OSDN Git Service

Merge remote branch 'origin/master' into nptl
authorAustin Foxley <austinf@cetoncorp.com>
Mon, 12 Apr 2010 13:18:10 +0000 (06:18 -0700)
committerAustin Foxley <austinf@cetoncorp.com>
Mon, 12 Apr 2010 13:18:10 +0000 (06:18 -0700)
Conflicts:
libc/unistd/confstr.c

Signed-off-by: Austin Foxley <austinf@cetoncorp.com>
1088 files changed:
.gitignore
Makefile.in
Rules.mak
extra/Configs/Config.in
extra/scripts/gen-as-const.awk
include/atomic.h
include/libc-symbols.h
ldso/include/ldso.h
ldso/ldso/arm/aeabi_read_tp.S
ldso/ldso/dl-tls.c
ldso/ldso/ldso.c
ldso/ldso/x86_64/dl-sysdep.h
ldso/ldso/x86_64/elfinterp.c
libc/Makefile.in
libc/inet/getaddrinfo.c
libc/inet/hostid.c
libc/inet/if_index.c
libc/inet/socketcalls.c
libc/misc/Makefile.in
libc/misc/dirent/closedir.c
libc/misc/dirent/opendir.c
libc/misc/internals/__uClibc_main.c
libc/misc/internals/tempname.c
libc/misc/internals/tempname.h
libc/misc/pthread/Makefile.in
libc/misc/pthread/tsd.c [new file with mode: 0644]
libc/misc/sysvipc/msgq.c
libc/misc/utmp/utent.c
libc/misc/utmp/wtent.c
libc/signal/Makefile.in
libc/signal/sigpause.c
libc/signal/sigwait.c
libc/stdio/_fopen.c
libc/stdio/_scanf.c
libc/stdio/_stdio.c
libc/stdio/_stdio.h
libc/stdio/fflush.c
libc/stdio/tempnam.c
libc/stdio/tmpfile.c
libc/stdio/tmpnam.c
libc/stdio/tmpnam_r.c
libc/stdio/vdprintf.c
libc/stdio/vsnprintf.c
libc/stdlib/Makefile.in
libc/stdlib/mkdtemp.c
libc/stdlib/mkstemp.c
libc/stdlib/mkstemp64.c
libc/stdlib/mktemp.c
libc/stdlib/system.c
libc/string/Makefile.in
libc/string/sh/memchr.S [new file with mode: 0644]
libc/string/sh/sh4/memmove.c [new file with mode: 0644]
libc/string/sh/sh4/memset.S [new file with mode: 0644]
libc/string/sh/sh4/strcpy.S [new file with mode: 0644]
libc/string/sh/sh4/strncpy.S [new file with mode: 0644]
libc/string/sh/strlen.S [new file with mode: 0644]
libc/sysdeps/linux/arm/Makefile.arch
libc/sysdeps/linux/arm/clone.S
libc/sysdeps/linux/arm/libc-aeabi_read_tp.S [new file with mode: 0644]
libc/sysdeps/linux/arm/libc-thumb_atomics.S [new file with mode: 0644]
libc/sysdeps/linux/arm/sysdep.h [new file with mode: 0644]
libc/sysdeps/linux/arm/vfork.S
libc/sysdeps/linux/common/Makefile.in
libc/sysdeps/linux/common/__rt_sigtimedwait.c
libc/sysdeps/linux/common/__rt_sigwaitinfo.c [new file with mode: 0644]
libc/sysdeps/linux/common/__syscall_fcntl.c
libc/sysdeps/linux/common/__syscall_rt_sigaction.c
libc/sysdeps/linux/common/_exit.c
libc/sysdeps/linux/common/bits/kernel_sigaction.h
libc/sysdeps/linux/common/bits/uClibc_mutex.h
libc/sysdeps/linux/common/bits/uClibc_stdio.h
libc/sysdeps/linux/common/fsync.c
libc/sysdeps/linux/common/ioctl.c
libc/sysdeps/linux/common/libgcc_s.h [new file with mode: 0644]
libc/sysdeps/linux/common/msync.c
libc/sysdeps/linux/common/nanosleep.c
libc/sysdeps/linux/common/not-cancel.h [new file with mode: 0644]
libc/sysdeps/linux/common/open64.c
libc/sysdeps/linux/common/pause.c
libc/sysdeps/linux/common/poll.c
libc/sysdeps/linux/common/pselect.c
libc/sysdeps/linux/common/readv.c
libc/sysdeps/linux/common/select.c
libc/sysdeps/linux/common/sigprocmask.c
libc/sysdeps/linux/common/sigsuspend.c
libc/sysdeps/linux/common/sysdep.h
libc/sysdeps/linux/common/wait.c
libc/sysdeps/linux/common/waitpid.c
libc/sysdeps/linux/common/writev.c
libc/sysdeps/linux/i386/Makefile.arch
libc/sysdeps/linux/i386/bits/syscalls.h
libc/sysdeps/linux/i386/bits/uClibc_arch_features.h
libc/sysdeps/linux/i386/clone.S
libc/sysdeps/linux/i386/sysdep.h [new file with mode: 0644]
libc/sysdeps/linux/i386/vfork.S
libc/sysdeps/linux/mips/Makefile.arch
libc/sysdeps/linux/mips/clone.S
libc/sysdeps/linux/mips/sys/asm.h
libc/sysdeps/linux/mips/sys/regdef.h
libc/sysdeps/linux/mips/syscall_error.S [new file with mode: 0644]
libc/sysdeps/linux/mips/sysdep.h [new file with mode: 0644]
libc/sysdeps/linux/mips/vfork.S [new file with mode: 0644]
libc/sysdeps/linux/sh/Makefile.arch
libc/sysdeps/linux/sh/bits/atomic.h
libc/sysdeps/linux/sh/clone.S
libc/sysdeps/linux/sh/longjmp.c [new file with mode: 0644]
libc/sysdeps/linux/sh/pread_write.c
libc/sysdeps/linux/sh/setjmp.S
libc/sysdeps/linux/sh/syscall_error.S
libc/sysdeps/linux/sh/sysdep.h
libc/sysdeps/linux/sparc/Makefile.arch
libc/sysdeps/linux/sparc/bits/atomic.h [new file with mode: 0644]
libc/sysdeps/linux/sparc/bits/uClibc_arch_features.h
libc/sysdeps/linux/sparc/clone.S
libc/sysdeps/linux/sparc/sigaction.c
libc/sysdeps/linux/sparc/sparcv9/clone.S [new file with mode: 0644]
libc/sysdeps/linux/sparc/sysdep.h [new file with mode: 0644]
libc/sysdeps/linux/x86_64/Makefile.arch
libc/sysdeps/linux/x86_64/bits/uClibc_arch_features.h
libc/sysdeps/linux/x86_64/clone.S
libc/sysdeps/linux/x86_64/sysdep.h [new file with mode: 0644]
libc/sysdeps/linux/x86_64/vfork.S
libc/termios/tcdrain.c
libc/unistd/daemon.c
libc/unistd/sysconf.c
libpthread/nptl/.gitignore [new file with mode: 0644]
libpthread/nptl/ChangeLog [new file with mode: 0644]
libpthread/nptl/DESIGN-barrier.txt [new file with mode: 0644]
libpthread/nptl/DESIGN-condvar.txt [new file with mode: 0644]
libpthread/nptl/DESIGN-rwlock.txt [new file with mode: 0644]
libpthread/nptl/DESIGN-sem.txt [new file with mode: 0644]
libpthread/nptl/Makefile [new file with mode: 0644]
libpthread/nptl/Makefile.in [new file with mode: 0644]
libpthread/nptl/README.NPTL [new file with mode: 0644]
libpthread/nptl/TODO [new file with mode: 0644]
libpthread/nptl/TODO-kernel [new file with mode: 0644]
libpthread/nptl/TODO-testing [new file with mode: 0644]
libpthread/nptl/alloca_cutoff.c [new file with mode: 0644]
libpthread/nptl/allocatestack.c [new file with mode: 0644]
libpthread/nptl/banner.h [new file with mode: 0644]
libpthread/nptl/cancellation.c [new file with mode: 0644]
libpthread/nptl/cleanup.c [new file with mode: 0644]
libpthread/nptl/cleanup_compat.c [new file with mode: 0644]
libpthread/nptl/cleanup_defer.c [new file with mode: 0644]
libpthread/nptl/cleanup_defer_compat.c [new file with mode: 0644]
libpthread/nptl/cleanup_routine.c [new file with mode: 0644]
libpthread/nptl/descr.h [new file with mode: 0644]
libpthread/nptl/eintr.c [new file with mode: 0644]
libpthread/nptl/events.c [new file with mode: 0644]
libpthread/nptl/forward.c [new file with mode: 0644]
libpthread/nptl/herrno.c [new file with mode: 0644]
libpthread/nptl/init.c [new file with mode: 0644]
libpthread/nptl/libc-cancellation.c [new file with mode: 0644]
libpthread/nptl/linux_fsinfo.h [new file with mode: 0644]
libpthread/nptl/pt-cleanup.c [new file with mode: 0644]
libpthread/nptl/pt-system.c [new file with mode: 0644]
libpthread/nptl/pthread-errnos.sym [new file with mode: 0644]
libpthread/nptl/pthreadP.h [new file with mode: 0644]
libpthread/nptl/pthread_atfork.c [new file with mode: 0644]
libpthread/nptl/pthread_attr_destroy.c [new file with mode: 0644]
libpthread/nptl/pthread_attr_getdetachstate.c [new file with mode: 0644]
libpthread/nptl/pthread_attr_getguardsize.c [new file with mode: 0644]
libpthread/nptl/pthread_attr_getinheritsched.c [new file with mode: 0644]
libpthread/nptl/pthread_attr_getschedparam.c [new file with mode: 0644]
libpthread/nptl/pthread_attr_getschedpolicy.c [new file with mode: 0644]
libpthread/nptl/pthread_attr_getscope.c [new file with mode: 0644]
libpthread/nptl/pthread_attr_getstack.c [new file with mode: 0644]
libpthread/nptl/pthread_attr_getstackaddr.c [new file with mode: 0644]
libpthread/nptl/pthread_attr_getstacksize.c [new file with mode: 0644]
libpthread/nptl/pthread_attr_init.c [new file with mode: 0644]
libpthread/nptl/pthread_attr_setdetachstate.c [new file with mode: 0644]
libpthread/nptl/pthread_attr_setguardsize.c [new file with mode: 0644]
libpthread/nptl/pthread_attr_setinheritsched.c [new file with mode: 0644]
libpthread/nptl/pthread_attr_setschedparam.c [new file with mode: 0644]
libpthread/nptl/pthread_attr_setschedpolicy.c [new file with mode: 0644]
libpthread/nptl/pthread_attr_setscope.c [new file with mode: 0644]
libpthread/nptl/pthread_attr_setstack.c [new file with mode: 0644]
libpthread/nptl/pthread_attr_setstackaddr.c [new file with mode: 0644]
libpthread/nptl/pthread_attr_setstacksize.c [new file with mode: 0644]
libpthread/nptl/pthread_barrierattr_destroy.c [new file with mode: 0644]
libpthread/nptl/pthread_barrierattr_getpshared.c [new file with mode: 0644]
libpthread/nptl/pthread_barrierattr_init.c [new file with mode: 0644]
libpthread/nptl/pthread_barrierattr_setpshared.c [new file with mode: 0644]
libpthread/nptl/pthread_cancel.c [new file with mode: 0644]
libpthread/nptl/pthread_clock_gettime.c [new file with mode: 0644]
libpthread/nptl/pthread_clock_settime.c [new file with mode: 0644]
libpthread/nptl/pthread_cond_destroy.c [new file with mode: 0644]
libpthread/nptl/pthread_cond_init.c [new file with mode: 0644]
libpthread/nptl/pthread_condattr_destroy.c [new file with mode: 0644]
libpthread/nptl/pthread_condattr_getclock.c [new file with mode: 0644]
libpthread/nptl/pthread_condattr_getpshared.c [new file with mode: 0644]
libpthread/nptl/pthread_condattr_init.c [new file with mode: 0644]
libpthread/nptl/pthread_condattr_setclock.c [new file with mode: 0644]
libpthread/nptl/pthread_condattr_setpshared.c [new file with mode: 0644]
libpthread/nptl/pthread_create.c [new file with mode: 0644]
libpthread/nptl/pthread_detach.c [new file with mode: 0644]
libpthread/nptl/pthread_equal.c [new file with mode: 0644]
libpthread/nptl/pthread_exit.c [new file with mode: 0644]
libpthread/nptl/pthread_getattr_np.c [new file with mode: 0644]
libpthread/nptl/pthread_getconcurrency.c [new file with mode: 0644]
libpthread/nptl/pthread_getschedparam.c [new file with mode: 0644]
libpthread/nptl/pthread_getspecific.c [new file with mode: 0644]
libpthread/nptl/pthread_join.c [new file with mode: 0644]
libpthread/nptl/pthread_key_create.c [new file with mode: 0644]
libpthread/nptl/pthread_key_delete.c [new file with mode: 0644]
libpthread/nptl/pthread_kill_other_threads.c [new file with mode: 0644]
libpthread/nptl/pthread_mutex_consistent.c [new file with mode: 0644]
libpthread/nptl/pthread_mutex_destroy.c [new file with mode: 0644]
libpthread/nptl/pthread_mutex_getprioceiling.c [new file with mode: 0644]
libpthread/nptl/pthread_mutex_init.c [new file with mode: 0644]
libpthread/nptl/pthread_mutex_lock.c [new file with mode: 0644]
libpthread/nptl/pthread_mutex_setprioceiling.c [new file with mode: 0644]
libpthread/nptl/pthread_mutex_timedlock.c [new file with mode: 0644]
libpthread/nptl/pthread_mutex_trylock.c [new file with mode: 0644]
libpthread/nptl/pthread_mutex_unlock.c [new file with mode: 0644]
libpthread/nptl/pthread_mutexattr_destroy.c [new file with mode: 0644]
libpthread/nptl/pthread_mutexattr_getprioceiling.c [new file with mode: 0644]
libpthread/nptl/pthread_mutexattr_getprotocol.c [new file with mode: 0644]
libpthread/nptl/pthread_mutexattr_getpshared.c [new file with mode: 0644]
libpthread/nptl/pthread_mutexattr_getrobust.c [new file with mode: 0644]
libpthread/nptl/pthread_mutexattr_gettype.c [new file with mode: 0644]
libpthread/nptl/pthread_mutexattr_init.c [new file with mode: 0644]
libpthread/nptl/pthread_mutexattr_setprioceiling.c [new file with mode: 0644]
libpthread/nptl/pthread_mutexattr_setprotocol.c [new file with mode: 0644]
libpthread/nptl/pthread_mutexattr_setpshared.c [new file with mode: 0644]
libpthread/nptl/pthread_mutexattr_setrobust.c [new file with mode: 0644]
libpthread/nptl/pthread_mutexattr_settype.c [new file with mode: 0644]
libpthread/nptl/pthread_rwlock_destroy.c [new file with mode: 0644]
libpthread/nptl/pthread_rwlock_init.c [new file with mode: 0644]
libpthread/nptl/pthread_rwlock_tryrdlock.c [new file with mode: 0644]
libpthread/nptl/pthread_rwlock_trywrlock.c [new file with mode: 0644]
libpthread/nptl/pthread_rwlockattr_destroy.c [new file with mode: 0644]
libpthread/nptl/pthread_rwlockattr_getkind_np.c [new file with mode: 0644]
libpthread/nptl/pthread_rwlockattr_getpshared.c [new file with mode: 0644]
libpthread/nptl/pthread_rwlockattr_init.c [new file with mode: 0644]
libpthread/nptl/pthread_rwlockattr_setkind_np.c [new file with mode: 0644]
libpthread/nptl/pthread_rwlockattr_setpshared.c [new file with mode: 0644]
libpthread/nptl/pthread_self.c [new file with mode: 0644]
libpthread/nptl/pthread_setcancelstate.c [new file with mode: 0644]
libpthread/nptl/pthread_setcanceltype.c [new file with mode: 0644]
libpthread/nptl/pthread_setconcurrency.c [new file with mode: 0644]
libpthread/nptl/pthread_setegid.c [new file with mode: 0644]
libpthread/nptl/pthread_seteuid.c [new file with mode: 0644]
libpthread/nptl/pthread_setgid.c [new file with mode: 0644]
libpthread/nptl/pthread_setregid.c [new file with mode: 0644]
libpthread/nptl/pthread_setresgid.c [new file with mode: 0644]
libpthread/nptl/pthread_setresuid.c [new file with mode: 0644]
libpthread/nptl/pthread_setreuid.c [new file with mode: 0644]
libpthread/nptl/pthread_setschedparam.c [new file with mode: 0644]
libpthread/nptl/pthread_setschedprio.c [new file with mode: 0644]
libpthread/nptl/pthread_setspecific.c [new file with mode: 0644]
libpthread/nptl/pthread_setuid.c [new file with mode: 0644]
libpthread/nptl/pthread_testcancel.c [new file with mode: 0644]
libpthread/nptl/pthread_timedjoin.c [new file with mode: 0644]
libpthread/nptl/pthread_tryjoin.c [new file with mode: 0644]
libpthread/nptl/res.c [new file with mode: 0644]
libpthread/nptl/sem_close.c [new file with mode: 0644]
libpthread/nptl/sem_destroy.c [new file with mode: 0644]
libpthread/nptl/sem_getvalue.c [new file with mode: 0644]
libpthread/nptl/sem_init.c [new file with mode: 0644]
libpthread/nptl/sem_open.c [new file with mode: 0644]
libpthread/nptl/sem_unlink.c [new file with mode: 0644]
libpthread/nptl/semaphore.h [new file with mode: 0644]
libpthread/nptl/semaphoreP.h [new file with mode: 0644]
libpthread/nptl/sysdeps/alpha/Makefile [new file with mode: 0644]
libpthread/nptl/sysdeps/alpha/dl-tls.h [new file with mode: 0644]
libpthread/nptl/sysdeps/alpha/elf/pt-initfini.c [new file with mode: 0644]
libpthread/nptl/sysdeps/alpha/jmpbuf-unwind.h [new file with mode: 0644]
libpthread/nptl/sysdeps/alpha/libc-tls.c [new file with mode: 0644]
libpthread/nptl/sysdeps/alpha/pthread_spin_lock.S [new file with mode: 0644]
libpthread/nptl/sysdeps/alpha/pthread_spin_trylock.S [new file with mode: 0644]
libpthread/nptl/sysdeps/alpha/pthreaddef.h [new file with mode: 0644]
libpthread/nptl/sysdeps/alpha/tcb-offsets.sym [new file with mode: 0644]
libpthread/nptl/sysdeps/alpha/tls.h [new file with mode: 0644]
libpthread/nptl/sysdeps/arm/Makefile.arch [new file with mode: 0644]
libpthread/nptl/sysdeps/arm/aeabi_read_tp.S [new file with mode: 0644]
libpthread/nptl/sysdeps/arm/aeabi_unwind_cpp_pr1.c [new file with mode: 0644]
libpthread/nptl/sysdeps/arm/dl-tls.h [new file with mode: 0644]
libpthread/nptl/sysdeps/arm/jmpbuf-unwind.h [new file with mode: 0644]
libpthread/nptl/sysdeps/arm/pthread_spin_lock.S [new file with mode: 0644]
libpthread/nptl/sysdeps/arm/pthread_spin_trylock.S [new file with mode: 0644]
libpthread/nptl/sysdeps/arm/pthreaddef.h [new file with mode: 0644]
libpthread/nptl/sysdeps/arm/tcb-offsets.sym [new file with mode: 0644]
libpthread/nptl/sysdeps/arm/thumb_atomics.S [new file with mode: 0644]
libpthread/nptl/sysdeps/arm/tls.h [new file with mode: 0644]
libpthread/nptl/sysdeps/generic/Makefile [new file with mode: 0644]
libpthread/nptl/sysdeps/generic/Makefile.in [new file with mode: 0644]
libpthread/nptl/sysdeps/generic/dl-tls.c [new file with mode: 0644]
libpthread/nptl/sysdeps/generic/dl-tls.h [new file with mode: 0644]
libpthread/nptl/sysdeps/generic/libc-tls.c [new file with mode: 0644]
libpthread/nptl/sysdeps/generic/lowlevellock.h [new file with mode: 0644]
libpthread/nptl/sysdeps/i386/Makefile [new file with mode: 0644]
libpthread/nptl/sysdeps/i386/Makefile.arch [new file with mode: 0644]
libpthread/nptl/sysdeps/i386/dl-tls.h [new file with mode: 0644]
libpthread/nptl/sysdeps/i386/i486/pthread_spin_trylock.S [new file with mode: 0644]
libpthread/nptl/sysdeps/i386/i586/pthread_spin_trylock.S [new file with mode: 0644]
libpthread/nptl/sysdeps/i386/i686/Makefile [new file with mode: 0644]
libpthread/nptl/sysdeps/i386/i686/pthread_spin_trylock.S [new file with mode: 0644]
libpthread/nptl/sysdeps/i386/i686/tls.h [new file with mode: 0644]
libpthread/nptl/sysdeps/i386/jmpbuf-unwind.h [new file with mode: 0644]
libpthread/nptl/sysdeps/i386/pthread_spin_init.c [new file with mode: 0644]
libpthread/nptl/sysdeps/i386/pthread_spin_lock.c [new file with mode: 0644]
libpthread/nptl/sysdeps/i386/pthread_spin_unlock.S [new file with mode: 0644]
libpthread/nptl/sysdeps/i386/pthreaddef.h [new file with mode: 0644]
libpthread/nptl/sysdeps/i386/tcb-offsets.sym [new file with mode: 0644]
libpthread/nptl/sysdeps/i386/tls.h [new file with mode: 0644]
libpthread/nptl/sysdeps/mips/Makefile [new file with mode: 0644]
libpthread/nptl/sysdeps/mips/Makefile.arch [new file with mode: 0644]
libpthread/nptl/sysdeps/mips/dl-tls.h [new file with mode: 0644]
libpthread/nptl/sysdeps/mips/jmpbuf-unwind.h [new file with mode: 0644]
libpthread/nptl/sysdeps/mips/libc-tls.c [new file with mode: 0644]
libpthread/nptl/sysdeps/mips/nptl-sysdep.S [new file with mode: 0644]
libpthread/nptl/sysdeps/mips/pthread_spin_lock.S [new file with mode: 0644]
libpthread/nptl/sysdeps/mips/pthread_spin_trylock.S [new file with mode: 0644]
libpthread/nptl/sysdeps/mips/pthreaddef.h [new file with mode: 0644]
libpthread/nptl/sysdeps/mips/regdef.h [new file with mode: 0644]
libpthread/nptl/sysdeps/mips/tcb-offsets.sym [new file with mode: 0644]
libpthread/nptl/sysdeps/mips/tls.h [new file with mode: 0644]
libpthread/nptl/sysdeps/powerpc/Makefile [new file with mode: 0644]
libpthread/nptl/sysdeps/powerpc/dl-tls.h [new file with mode: 0644]
libpthread/nptl/sysdeps/powerpc/jmpbuf-unwind.h [new file with mode: 0644]
libpthread/nptl/sysdeps/powerpc/pthread_spin_lock.c [new file with mode: 0644]
libpthread/nptl/sysdeps/powerpc/pthread_spin_trylock.c [new file with mode: 0644]
libpthread/nptl/sysdeps/powerpc/pthreaddef.h [new file with mode: 0644]
libpthread/nptl/sysdeps/powerpc/tcb-offsets.sym [new file with mode: 0644]
libpthread/nptl/sysdeps/powerpc/tls.h [new file with mode: 0644]
libpthread/nptl/sysdeps/pthread/Makefile [new file with mode: 0644]
libpthread/nptl/sysdeps/pthread/Makefile.in [new file with mode: 0644]
libpthread/nptl/sysdeps/pthread/allocalim.h [new file with mode: 0644]
libpthread/nptl/sysdeps/pthread/bits/libc-lock.h [new file with mode: 0644]
libpthread/nptl/sysdeps/pthread/bits/libc-tsd.h [new file with mode: 0644]
libpthread/nptl/sysdeps/pthread/bits/sigthread.h [new file with mode: 0644]
libpthread/nptl/sysdeps/pthread/bits/stdio-lock.h [new file with mode: 0644]
libpthread/nptl/sysdeps/pthread/createthread.c [new file with mode: 0644]
libpthread/nptl/sysdeps/pthread/defs.awk [new file with mode: 0644]
libpthread/nptl/sysdeps/pthread/librt-cancellation.c [new file with mode: 0644]
libpthread/nptl/sysdeps/pthread/list.h [new file with mode: 0644]
libpthread/nptl/sysdeps/pthread/malloc-machine.h [new file with mode: 0644]
libpthread/nptl/sysdeps/pthread/posix-timer.h [new file with mode: 0644]
libpthread/nptl/sysdeps/pthread/pt-initfini.c [new file with mode: 0644]
libpthread/nptl/sysdeps/pthread/pt-longjmp.c [new file with mode: 0644]
libpthread/nptl/sysdeps/pthread/pthread-functions.h [new file with mode: 0644]
libpthread/nptl/sysdeps/pthread/pthread.h [new file with mode: 0644]
libpthread/nptl/sysdeps/pthread/pthread_barrier_destroy.c [new file with mode: 0644]
libpthread/nptl/sysdeps/pthread/pthread_barrier_init.c [new file with mode: 0644]
libpthread/nptl/sysdeps/pthread/pthread_barrier_wait.c [new file with mode: 0644]
libpthread/nptl/sysdeps/pthread/pthread_cond_broadcast.c [new file with mode: 0644]
libpthread/nptl/sysdeps/pthread/pthread_cond_signal.c [new file with mode: 0644]
libpthread/nptl/sysdeps/pthread/pthread_cond_timedwait.c [new file with mode: 0644]
libpthread/nptl/sysdeps/pthread/pthread_cond_wait.c [new file with mode: 0644]
libpthread/nptl/sysdeps/pthread/pthread_once.c [new file with mode: 0644]
libpthread/nptl/sysdeps/pthread/pthread_rwlock_rdlock.c [new file with mode: 0644]
libpthread/nptl/sysdeps/pthread/pthread_rwlock_timedrdlock.c [new file with mode: 0644]
libpthread/nptl/sysdeps/pthread/pthread_rwlock_timedwrlock.c [new file with mode: 0644]
libpthread/nptl/sysdeps/pthread/pthread_rwlock_unlock.c [new file with mode: 0644]
libpthread/nptl/sysdeps/pthread/pthread_rwlock_wrlock.c [new file with mode: 0644]
libpthread/nptl/sysdeps/pthread/pthread_sigmask.c [new file with mode: 0644]
libpthread/nptl/sysdeps/pthread/pthread_spin_destroy.c [new file with mode: 0644]
libpthread/nptl/sysdeps/pthread/pthread_spin_init.c [new file with mode: 0644]
libpthread/nptl/sysdeps/pthread/pthread_spin_unlock.c [new file with mode: 0644]
libpthread/nptl/sysdeps/pthread/rt-unwind-resume.c [new file with mode: 0644]
libpthread/nptl/sysdeps/pthread/setxid.h [new file with mode: 0644]
libpthread/nptl/sysdeps/pthread/sigaction.c [new file with mode: 0644]
libpthread/nptl/sysdeps/pthread/sigfillset.c [new file with mode: 0644]
libpthread/nptl/sysdeps/pthread/sigprocmask.c [new file with mode: 0644]
libpthread/nptl/sysdeps/pthread/tcb-offsets.h [new file with mode: 0644]
libpthread/nptl/sysdeps/pthread/timer_create.c [new file with mode: 0644]
libpthread/nptl/sysdeps/pthread/timer_delete.c [new file with mode: 0644]
libpthread/nptl/sysdeps/pthread/timer_getoverr.c [new file with mode: 0644]
libpthread/nptl/sysdeps/pthread/timer_gettime.c [new file with mode: 0644]
libpthread/nptl/sysdeps/pthread/timer_routines.c [new file with mode: 0644]
libpthread/nptl/sysdeps/pthread/timer_settime.c [new file with mode: 0644]
libpthread/nptl/sysdeps/pthread/tpp.c [new file with mode: 0644]
libpthread/nptl/sysdeps/pthread/uClibc-glue.h [new file with mode: 0644]
libpthread/nptl/sysdeps/pthread/unwind-forcedunwind.c [new file with mode: 0644]
libpthread/nptl/sysdeps/pthread/unwind-resume.c [new file with mode: 0644]
libpthread/nptl/sysdeps/sh/Makefile [new file with mode: 0644]
libpthread/nptl/sysdeps/sh/Makefile.arch [new file with mode: 0644]
libpthread/nptl/sysdeps/sh/dl-tls.h [new file with mode: 0644]
libpthread/nptl/sysdeps/sh/jmpbuf-unwind.h [new file with mode: 0644]
libpthread/nptl/sysdeps/sh/pthread_spin_init.c [new file with mode: 0644]
libpthread/nptl/sysdeps/sh/pthread_spin_lock.c [new file with mode: 0644]
libpthread/nptl/sysdeps/sh/pthread_spin_trylock.S [new file with mode: 0644]
libpthread/nptl/sysdeps/sh/pthread_spin_unlock.S [new file with mode: 0644]
libpthread/nptl/sysdeps/sh/pthreaddef.h [new file with mode: 0644]
libpthread/nptl/sysdeps/sh/tcb-offsets.sym [new file with mode: 0644]
libpthread/nptl/sysdeps/sh/tls.h [new file with mode: 0644]
libpthread/nptl/sysdeps/sparc/Makefile [new file with mode: 0644]
libpthread/nptl/sysdeps/sparc/Makefile.arch [new file with mode: 0644]
libpthread/nptl/sysdeps/sparc/dl-tls.h [new file with mode: 0644]
libpthread/nptl/sysdeps/sparc/jmpbuf-unwind.h [new file with mode: 0644]
libpthread/nptl/sysdeps/sparc/pthreaddef.h [new file with mode: 0644]
libpthread/nptl/sysdeps/sparc/sparc32/jmpbuf-unwind.h [new file with mode: 0644]
libpthread/nptl/sysdeps/sparc/sparc32/pthread_spin_lock.c [new file with mode: 0644]
libpthread/nptl/sysdeps/sparc/sparc32/pthread_spin_trylock.c [new file with mode: 0644]
libpthread/nptl/sysdeps/sparc/sparc32/pthreaddef.h [new file with mode: 0644]
libpthread/nptl/sysdeps/sparc/sparc32/sparcv9/pthread_spin_lock.c [new file with mode: 0644]
libpthread/nptl/sysdeps/sparc/sparc32/sparcv9/pthread_spin_trylock.c [new file with mode: 0644]
libpthread/nptl/sysdeps/sparc/sparc32/sparcv9/pthread_spin_unlock.c [new file with mode: 0644]
libpthread/nptl/sysdeps/sparc/sparc64/jmpbuf-unwind.h [new file with mode: 0644]
libpthread/nptl/sysdeps/sparc/sparc64/pthread_spin_lock.c [new file with mode: 0644]
libpthread/nptl/sysdeps/sparc/sparc64/pthread_spin_trylock.c [new file with mode: 0644]
libpthread/nptl/sysdeps/sparc/sparc64/pthread_spin_unlock.c [new file with mode: 0644]
libpthread/nptl/sysdeps/sparc/sparc64/pthreaddef.h [new file with mode: 0644]
libpthread/nptl/sysdeps/sparc/tcb-offsets.sym [new file with mode: 0644]
libpthread/nptl/sysdeps/sparc/tls.h [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/Makefile [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/Makefile.in [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/__syscall_error.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/accept.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/alpha/Makefile [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/alpha/bits/local_lim.h [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/alpha/bits/semaphore.h [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/alpha/clone.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/alpha/createthread.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/alpha/fork.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/alpha/lowlevellock.h [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/alpha/pt-vfork.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/alpha/pthread_once.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/alpha/sem_post.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/alpha/sysdep-cancel.h [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_create.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_delete.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_getoverr.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_gettime.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_settime.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/alpha/vfork.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/arm/Makefile [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/arm/Makefile.arch [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/arm/bits/atomic.h [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/arm/bits/pthreadtypes.h [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/arm/bits/semaphore.h [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/arm/clone.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/arm/createthread.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/arm/fork.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/arm/lowlevellock.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/arm/lowlevellock.h [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/arm/nptl-aeabi_unwind_cpp_pr1.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-__syscall_error.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-__syscall_rt_sigaction.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-gettimeofday.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-vfork.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/arm/pthread_once.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/arm/sysdep-cancel.h [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind-forcedunwind.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind-resume.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind.h [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/arm/vfork.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/bits/local_lim.h [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/bits/posix_opt.h [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/close.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/connect.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/creat.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/createthread.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/exit-thread.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/fork.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/fork.h [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/getpid.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/Makefile [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/Makefile.arch [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/bits/semaphore.h [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/clone.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/createthread.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/fork.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevelrobustlock.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_barrier_wait.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_signal.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_rdlock.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedrdlock.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedwrlock.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_unlock.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_wrlock.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_post.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_timedwait.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_trywait.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_wait.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/libc-lowlevellock.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevellock.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevelrobustlock.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_barrier_wait.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_cond_broadcast.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_cond_signal.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_cond_timedwait.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_cond_wait.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_rdlock.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_timedrdlock.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_timedwrlock.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_unlock.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_wrlock.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/sem_post.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/sem_timedwait.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/sem_trywait.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/sem_wait.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/libc-lowlevellock.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevellock.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevelrobustlock.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_barrier_wait.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_cond_broadcast.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_cond_signal.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_cond_timedwait.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_cond_wait.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_rdlock.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_timedrdlock.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_timedwrlock.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_unlock.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_wrlock.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/sem_post.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/sem_timedwait.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/sem_trywait.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/sem_wait.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/pt-__syscall_error.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/pt-vfork.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/pthread_once.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/pthread_spin_init.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/pthread_spin_unlock.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/smp.h [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/sysdep-cancel.h [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/i386/vfork.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/internaltypes.h [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/jmp-unwind.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/kernel-posix-timers.h [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/libc-lowlevellock.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/libc_multiple_threads.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/libc_pthread_init.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/lowlevelbarrier.sym [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/lowlevelcond.sym [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/lowlevellock.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/lowlevelrobustlock.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/lowlevelrobustlock.sym [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/lowlevelrwlock.sym [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/lseek.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/mips/Makefile [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/mips/Makefile.arch [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/mips/bits/pthreadtypes.h [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/mips/bits/semaphore.h [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/mips/createthread.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/mips/fork.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/mips/lowlevellock.h [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/mips/pt-__syscall_rt_sigaction.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/mips/pt-clone.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/mips/pt-vfork.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/mips/pthread_once.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/mips/sysdep-cancel.h [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/mq_notify.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/msync.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/nanosleep.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/not-cancel.h [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/open.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/pause.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/Makefile [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/bits/semaphore.h [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/createthread.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/fork.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/lowlevellock.h [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/not-cancel.h [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc32/clone.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc32/pt-vfork.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc32/vfork.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/clone.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/pt-vfork.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_create.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_delete.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_getoverr.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_gettime.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_settime.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/vfork.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/pt-longjmp.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/pthread_once.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/pthread_spin_unlock.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/sem_post.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/pt-accept.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/pt-close.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/pt-connect.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/pt-fcntl.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/pt-fork.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/pt-fsync.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/pt-llseek.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/pt-lseek.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/pt-msgrcv.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/pt-msgsnd.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/pt-msync.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/pt-nanosleep.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/pt-open.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/pt-open64.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/pt-pause.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/pt-pread_pwrite.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/pt-raise.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/pt-read.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/pt-recv.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/pt-recvfrom.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/pt-recvmsg.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/pt-send.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/pt-sendmsg.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/pt-sendto.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/pt-sigwait.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/pt-sleep.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/pt-tcdrain.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/pt-wait.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/pt-waitpid.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/pt-write.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/pthread-pi-defines.sym [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/pthread_attr_getaffinity.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/pthread_attr_setaffinity.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/pthread_getaffinity.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/pthread_getcpuclockid.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/pthread_kill.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/pthread_mutex_cond_lock.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/pthread_setaffinity.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/pthread_sigqueue.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/pthread_yield.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/raise.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/read.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/recv.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/recvfrom.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/recvmsg.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/register-atfork.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sem_post.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sem_timedwait.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sem_trywait.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sem_wait.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/send.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sendmsg.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sendto.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sh/Makefile [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sh/Makefile.arch [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sh/bits/semaphore.h [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sh/clone.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sh/createthread.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sh/fork.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sh/libc-lowlevellock.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sh/lowlevel-atomic.h [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sh/lowlevellock.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sh/lowlevellock.h [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sh/lowlevelrobustlock.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sh/pt-initfini.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sh/pt-vfork.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_barrier_wait.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_cond_broadcast.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_cond_signal.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_cond_timedwait.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_cond_wait.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_once.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_rdlock.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedrdlock.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedwrlock.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_unlock.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_wrlock.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sh/sem_post.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sh/sem_timedwait.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sh/sem_trywait.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sh/sem_wait.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sh/sh4/lowlevellock.h [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sh/smp.h [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sh/sysdep-cancel.h [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sh/vfork.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sigtimedwait.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sigwait.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sigwaitinfo.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sleep.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/smp.h [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sparc/Makefile [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sparc/Makefile.arch [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sparc/bits/local_lim.h [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sparc/bits/pthreadtypes.h [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sparc/bits/semaphore.h [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sparc/clone.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sparc/fork.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sparc/internaltypes.h [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sparc/libc-lowlevellock.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sparc/lowlevellock.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sparc/lowlevellock.h [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sparc/pt-vfork.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sparc/pthread_barrier_destroy.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sparc/pthread_barrier_init.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sparc/pthread_barrier_wait.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sparc/pthread_once.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sem_init.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/clone.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/pt-vfork.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/pthread_barrier_wait.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sem_post.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sem_timedwait.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sem_trywait.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sem_wait.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sysdep-cancel.h [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/clone.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/pt-vfork.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/sysdep-cancel.h [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_create.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_delete.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_getoverr.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_gettime.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_settime.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sysdep-cancel.h [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/sparc/vfork.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/structsem.sym [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/timer_create.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/timer_delete.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/timer_getoverr.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/timer_gettime.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/timer_routines.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/timer_settime.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/unregister-atfork.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/unwindbuf.sym [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/waitpid.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/write.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/Makefile [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/Makefile.arch [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/bits/semaphore.h [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/cancellation.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/clone.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/compat-timer.h [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/fork.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/libc-cancellation.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/libc-lowlevellock.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/librt-cancellation.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.h [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevelrobustlock.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pt-__syscall_error.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pt-vfork.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_barrier_wait.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_signal.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_once.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_rdlock.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedrdlock.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedwrlock.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_unlock.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_wrlock.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_setaffinity.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_spin_init.c [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_spin_unlock.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sem_post.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sem_trywait.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sem_wait.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/vfork.S [new file with mode: 0644]
libpthread/nptl/sysdeps/x86_64/Makefile.arch [new file with mode: 0644]
libpthread/nptl/sysdeps/x86_64/dl-tls.h [new file with mode: 0644]
libpthread/nptl/sysdeps/x86_64/jmpbuf-unwind.h [new file with mode: 0644]
libpthread/nptl/sysdeps/x86_64/pthread_spin_init.c [new file with mode: 0644]
libpthread/nptl/sysdeps/x86_64/pthread_spin_lock.c [new file with mode: 0644]
libpthread/nptl/sysdeps/x86_64/pthread_spin_trylock.S [new file with mode: 0644]
libpthread/nptl/sysdeps/x86_64/pthread_spin_unlock.S [new file with mode: 0644]
libpthread/nptl/sysdeps/x86_64/pthreaddef.h [new file with mode: 0644]
libpthread/nptl/sysdeps/x86_64/tcb-offsets.sym [new file with mode: 0644]
libpthread/nptl/sysdeps/x86_64/tls.h [new file with mode: 0644]
libpthread/nptl/unwind.c [new file with mode: 0644]
libpthread/nptl/vars.c [new file with mode: 0644]
libpthread/nptl/version.c [new file with mode: 0644]
libpthread/nptl/version.h [new file with mode: 0644]
libpthread/nptl_db/ChangeLog [new file with mode: 0644]
libpthread/nptl_db/Makefile [new file with mode: 0644]
libpthread/nptl_db/Makefile.in [new file with mode: 0644]
libpthread/nptl_db/db_info.c [new file with mode: 0644]
libpthread/nptl_db/fetch-value.c [new file with mode: 0644]
libpthread/nptl_db/proc_service.h [new file with mode: 0644]
libpthread/nptl_db/structs.def [new file with mode: 0644]
libpthread/nptl_db/td_init.c [new file with mode: 0644]
libpthread/nptl_db/td_log.c [new file with mode: 0644]
libpthread/nptl_db/td_symbol_list.c [new file with mode: 0644]
libpthread/nptl_db/td_ta_clear_event.c [new file with mode: 0644]
libpthread/nptl_db/td_ta_delete.c [new file with mode: 0644]
libpthread/nptl_db/td_ta_enable_stats.c [new file with mode: 0644]
libpthread/nptl_db/td_ta_event_addr.c [new file with mode: 0644]
libpthread/nptl_db/td_ta_event_getmsg.c [new file with mode: 0644]
libpthread/nptl_db/td_ta_get_nthreads.c [new file with mode: 0644]
libpthread/nptl_db/td_ta_get_ph.c [new file with mode: 0644]
libpthread/nptl_db/td_ta_get_stats.c [new file with mode: 0644]
libpthread/nptl_db/td_ta_map_id2thr.c [new file with mode: 0644]
libpthread/nptl_db/td_ta_map_lwp2thr.c [new file with mode: 0644]
libpthread/nptl_db/td_ta_new.c [new file with mode: 0644]
libpthread/nptl_db/td_ta_reset_stats.c [new file with mode: 0644]
libpthread/nptl_db/td_ta_set_event.c [new file with mode: 0644]
libpthread/nptl_db/td_ta_setconcurrency.c [new file with mode: 0644]
libpthread/nptl_db/td_ta_thr_iter.c [new file with mode: 0644]
libpthread/nptl_db/td_ta_tsd_iter.c [new file with mode: 0644]
libpthread/nptl_db/td_thr_clear_event.c [new file with mode: 0644]
libpthread/nptl_db/td_thr_dbresume.c [new file with mode: 0644]
libpthread/nptl_db/td_thr_dbsuspend.c [new file with mode: 0644]
libpthread/nptl_db/td_thr_event_enable.c [new file with mode: 0644]
libpthread/nptl_db/td_thr_event_getmsg.c [new file with mode: 0644]
libpthread/nptl_db/td_thr_get_info.c [new file with mode: 0644]
libpthread/nptl_db/td_thr_getfpregs.c [new file with mode: 0644]
libpthread/nptl_db/td_thr_getgregs.c [new file with mode: 0644]
libpthread/nptl_db/td_thr_getxregs.c [new file with mode: 0644]
libpthread/nptl_db/td_thr_getxregsize.c [new file with mode: 0644]
libpthread/nptl_db/td_thr_set_event.c [new file with mode: 0644]
libpthread/nptl_db/td_thr_setfpregs.c [new file with mode: 0644]
libpthread/nptl_db/td_thr_setgregs.c [new file with mode: 0644]
libpthread/nptl_db/td_thr_setprio.c [new file with mode: 0644]
libpthread/nptl_db/td_thr_setsigpending.c [new file with mode: 0644]
libpthread/nptl_db/td_thr_setxregs.c [new file with mode: 0644]
libpthread/nptl_db/td_thr_sigsetmask.c [new file with mode: 0644]
libpthread/nptl_db/td_thr_tls_get_addr.c [new file with mode: 0644]
libpthread/nptl_db/td_thr_tlsbase.c [new file with mode: 0644]
libpthread/nptl_db/td_thr_tsd.c [new file with mode: 0644]
libpthread/nptl_db/td_thr_validate.c [new file with mode: 0644]
libpthread/nptl_db/thread_db.h [new file with mode: 0644]
libpthread/nptl_db/thread_dbP.h [new file with mode: 0644]
librt/Makefile.in
librt/clock_getcpuclockid.c [new file with mode: 0644]
librt/clock_gettime.c [new file with mode: 0644]
librt/clock_nanosleep.c [new file with mode: 0644]
librt/kernel-posix-cpu-timers.h [new file with mode: 0644]
librt/kernel-posix-timers.h
librt/mq_receive.c
librt/mq_send.c
librt/mq_timedreceive.S [new file with mode: 0644]
librt/mq_timedsend.S [new file with mode: 0644]
test/.gitignore
test/Makefile
test/Rules.mak
test/Test.mak
test/dlopen/Makefile
test/nptl/Makefile [new file with mode: 0644]
test/nptl/Makefile.in [new file with mode: 0644]
test/nptl/tst-align.c [new file with mode: 0644]
test/nptl/tst-align2.c [new file with mode: 0644]
test/nptl/tst-atfork1.c [new file with mode: 0644]
test/nptl/tst-attr1.c [new file with mode: 0644]
test/nptl/tst-attr2.c [new file with mode: 0644]
test/nptl/tst-attr3.c [new file with mode: 0644]
test/nptl/tst-barrier1.c [new file with mode: 0644]
test/nptl/tst-barrier2.c [new file with mode: 0644]
test/nptl/tst-barrier3.c [new file with mode: 0644]
test/nptl/tst-barrier4.c [new file with mode: 0644]
test/nptl/tst-basic1.c [new file with mode: 0644]
test/nptl/tst-basic2.c [new file with mode: 0644]
test/nptl/tst-basic3.c [new file with mode: 0644]
test/nptl/tst-basic4.c [new file with mode: 0644]
test/nptl/tst-basic5.c [new file with mode: 0644]
test/nptl/tst-basic6.c [new file with mode: 0644]
test/nptl/tst-cancel1.c [new file with mode: 0644]
test/nptl/tst-cancel10.c [new file with mode: 0644]
test/nptl/tst-cancel11.c [new file with mode: 0644]
test/nptl/tst-cancel12.c [new file with mode: 0644]
test/nptl/tst-cancel13.c [new file with mode: 0644]
test/nptl/tst-cancel14.c [new file with mode: 0644]
test/nptl/tst-cancel15.c [new file with mode: 0644]
test/nptl/tst-cancel16.c [new file with mode: 0644]
test/nptl/tst-cancel19.c [new file with mode: 0644]
test/nptl/tst-cancel2.c [new file with mode: 0644]
test/nptl/tst-cancel20.c [new file with mode: 0644]
test/nptl/tst-cancel21.c [new file with mode: 0644]
test/nptl/tst-cancel22.c [new file with mode: 0644]
test/nptl/tst-cancel3.c [new file with mode: 0644]
test/nptl/tst-cancel6.c [new file with mode: 0644]
test/nptl/tst-cancel7.c [new file with mode: 0644]
test/nptl/tst-cancel8.c [new file with mode: 0644]
test/nptl/tst-cancel9.c [new file with mode: 0644]
test/nptl/tst-cleanup0.c [new file with mode: 0644]
test/nptl/tst-cleanup1.c [new file with mode: 0644]
test/nptl/tst-cleanup2.c [new file with mode: 0644]
test/nptl/tst-cleanup3.c [new file with mode: 0644]
test/nptl/tst-cleanup4.c [new file with mode: 0644]
test/nptl/tst-cleanup4aux.c [new file with mode: 0644]
test/nptl/tst-clock.c [new file with mode: 0644]
test/nptl/tst-clock1.c [new file with mode: 0644]
test/nptl/tst-clock2.c [new file with mode: 0644]
test/nptl/tst-clock_nanosleep.c [new file with mode: 0644]
test/nptl/tst-cond1.c [new file with mode: 0644]
test/nptl/tst-cond10.c [new file with mode: 0644]
test/nptl/tst-cond11.c [new file with mode: 0644]
test/nptl/tst-cond12.c [new file with mode: 0644]
test/nptl/tst-cond13.c [new file with mode: 0644]
test/nptl/tst-cond14.c [new file with mode: 0644]
test/nptl/tst-cond15.c [new file with mode: 0644]
test/nptl/tst-cond16.c [new file with mode: 0644]
test/nptl/tst-cond17.c [new file with mode: 0644]
test/nptl/tst-cond18.c [new file with mode: 0644]
test/nptl/tst-cond19.c [new file with mode: 0644]
test/nptl/tst-cond2.c [new file with mode: 0644]
test/nptl/tst-cond20.c [new file with mode: 0644]
test/nptl/tst-cond21.c [new file with mode: 0644]
test/nptl/tst-cond3.c [new file with mode: 0644]
test/nptl/tst-cond4.c [new file with mode: 0644]
test/nptl/tst-cond5.c [new file with mode: 0644]
test/nptl/tst-cond6.c [new file with mode: 0644]
test/nptl/tst-cond7.c [new file with mode: 0644]
test/nptl/tst-cond8.c [new file with mode: 0644]
test/nptl/tst-cond9.c [new file with mode: 0644]
test/nptl/tst-cpuclock1.c [new file with mode: 0644]
test/nptl/tst-cpuclock2.c [new file with mode: 0644]
test/nptl/tst-cputimer1.c [new file with mode: 0644]
test/nptl/tst-cputimer2.c [new file with mode: 0644]
test/nptl/tst-cputimer3.c [new file with mode: 0644]
test/nptl/tst-detach1.c [new file with mode: 0644]
test/nptl/tst-eintr1.c [new file with mode: 0644]
test/nptl/tst-eintr2.c [new file with mode: 0644]
test/nptl/tst-eintr3.c [new file with mode: 0644]
test/nptl/tst-eintr4.c [new file with mode: 0644]
test/nptl/tst-eintr5.c [new file with mode: 0644]
test/nptl/tst-exec2.c [new file with mode: 0644]
test/nptl/tst-exec3.c [new file with mode: 0644]
test/nptl/tst-exec4.c [new file with mode: 0644]
test/nptl/tst-exit1.c [new file with mode: 0644]
test/nptl/tst-exit2.c [new file with mode: 0644]
test/nptl/tst-exit3.c [new file with mode: 0644]
test/nptl/tst-flock1.c [new file with mode: 0644]
test/nptl/tst-flock2.c [new file with mode: 0644]
test/nptl/tst-fork1.c [new file with mode: 0644]
test/nptl/tst-fork2.c [new file with mode: 0644]
test/nptl/tst-fork3.c [new file with mode: 0644]
test/nptl/tst-fork4.c [new file with mode: 0644]
test/nptl/tst-initializers1.c [new file with mode: 0644]
test/nptl/tst-join1.c [new file with mode: 0644]
test/nptl/tst-join2.c [new file with mode: 0644]
test/nptl/tst-join3.c [new file with mode: 0644]
test/nptl/tst-join4.c [new file with mode: 0644]
test/nptl/tst-join5.c [new file with mode: 0644]
test/nptl/tst-key1.c [new file with mode: 0644]
test/nptl/tst-key2.c [new file with mode: 0644]
test/nptl/tst-key3.c [new file with mode: 0644]
test/nptl/tst-key4.c [new file with mode: 0644]
test/nptl/tst-kill1.c [new file with mode: 0644]
test/nptl/tst-kill2.c [new file with mode: 0644]
test/nptl/tst-kill3.c [new file with mode: 0644]
test/nptl/tst-kill4.c [new file with mode: 0644]
test/nptl/tst-kill5.c [new file with mode: 0644]
test/nptl/tst-kill6.c [new file with mode: 0644]
test/nptl/tst-mqueue.h [new file with mode: 0644]
test/nptl/tst-mqueue1.c [new file with mode: 0644]
test/nptl/tst-mqueue2.c [new file with mode: 0644]
test/nptl/tst-mqueue3.c [new file with mode: 0644]
test/nptl/tst-mqueue4.c [new file with mode: 0644]
test/nptl/tst-mqueue5.c [new file with mode: 0644]
test/nptl/tst-mqueue6.c [new file with mode: 0644]
test/nptl/tst-mqueue7.c [new file with mode: 0644]
test/nptl/tst-mqueue8.c [new file with mode: 0644]
test/nptl/tst-mqueue9.c [new file with mode: 0644]
test/nptl/tst-mutex1.c [new file with mode: 0644]
test/nptl/tst-mutex2.c [new file with mode: 0644]
test/nptl/tst-mutex3.c [new file with mode: 0644]
test/nptl/tst-mutex4.c [new file with mode: 0644]
test/nptl/tst-mutex5.c [new file with mode: 0644]
test/nptl/tst-mutex5a.c [new file with mode: 0644]
test/nptl/tst-mutex6.c [new file with mode: 0644]
test/nptl/tst-mutex7.c [new file with mode: 0644]
test/nptl/tst-mutex7a.c [new file with mode: 0644]
test/nptl/tst-mutex8.c [new file with mode: 0644]
test/nptl/tst-mutex9.c [new file with mode: 0644]
test/nptl/tst-once1.c [new file with mode: 0644]
test/nptl/tst-once2.c [new file with mode: 0644]
test/nptl/tst-once3.c [new file with mode: 0644]
test/nptl/tst-once4.c [new file with mode: 0644]
test/nptl/tst-popen1.c [new file with mode: 0644]
test/nptl/tst-raise1.c [new file with mode: 0644]
test/nptl/tst-rwlock1.c [new file with mode: 0644]
test/nptl/tst-rwlock10.c [new file with mode: 0644]
test/nptl/tst-rwlock11.c [new file with mode: 0644]
test/nptl/tst-rwlock12.c [new file with mode: 0644]
test/nptl/tst-rwlock13.c [new file with mode: 0644]
test/nptl/tst-rwlock14.c [new file with mode: 0644]
test/nptl/tst-rwlock2.c [new file with mode: 0644]
test/nptl/tst-rwlock3.c [new file with mode: 0644]
test/nptl/tst-rwlock4.c [new file with mode: 0644]
test/nptl/tst-rwlock5.c [new file with mode: 0644]
test/nptl/tst-rwlock6.c [new file with mode: 0644]
test/nptl/tst-rwlock7.c [new file with mode: 0644]
test/nptl/tst-rwlock8.c [new file with mode: 0644]
test/nptl/tst-rwlock9.c [new file with mode: 0644]
test/nptl/tst-sched1.c [new file with mode: 0644]
test/nptl/tst-sem1.c [new file with mode: 0644]
test/nptl/tst-sem2.c [new file with mode: 0644]
test/nptl/tst-sem3.c [new file with mode: 0644]
test/nptl/tst-sem4.c [new file with mode: 0644]
test/nptl/tst-sem5.c [new file with mode: 0644]
test/nptl/tst-sem6.c [new file with mode: 0644]
test/nptl/tst-sem7.c [new file with mode: 0644]
test/nptl/tst-sem8.c [new file with mode: 0644]
test/nptl/tst-sem9.c [new file with mode: 0644]
test/nptl/tst-signal1.c [new file with mode: 0644]
test/nptl/tst-signal2.c [new file with mode: 0644]
test/nptl/tst-signal3.c [new file with mode: 0644]
test/nptl/tst-signal4.c [new file with mode: 0644]
test/nptl/tst-signal5.c [new file with mode: 0644]
test/nptl/tst-signal6.c [new file with mode: 0644]
test/nptl/tst-spin1.c [new file with mode: 0644]
test/nptl/tst-spin2.c [new file with mode: 0644]
test/nptl/tst-spin3.c [new file with mode: 0644]
test/nptl/tst-stack-align.h [new file with mode: 0644]
test/nptl/tst-stack1.c [new file with mode: 0644]
test/nptl/tst-stack2.c [new file with mode: 0644]
test/nptl/tst-stdio1.c [new file with mode: 0644]
test/nptl/tst-stdio2.c [new file with mode: 0644]
test/nptl/tst-sysconf.c [new file with mode: 0644]
test/nptl/tst-timer2.c [new file with mode: 0644]
test/nptl/tst-timer3.c [new file with mode: 0644]
test/nptl/tst-timer4.c [new file with mode: 0644]
test/nptl/tst-timer5.c [new file with mode: 0644]
test/nptl/tst-tls1.c [new file with mode: 0644]
test/nptl/tst-tls2.c [new file with mode: 0644]
test/nptl/tst-tls3.c [new file with mode: 0644]
test/nptl/tst-tls3mod.c [new file with mode: 0644]
test/nptl/tst-tls4.c [new file with mode: 0644]
test/nptl/tst-tls4moda.c [new file with mode: 0644]
test/nptl/tst-tls4modb.c [new file with mode: 0644]
test/nptl/tst-tls5.c [new file with mode: 0644]
test/nptl/tst-tls5.h [new file with mode: 0644]
test/nptl/tst-tls5mod.c [new file with mode: 0644]
test/nptl/tst-tls5moda.c [new file with mode: 0644]
test/nptl/tst-tls5modb.c [new file with mode: 0644]
test/nptl/tst-tls5modc.c [new file with mode: 0644]
test/nptl/tst-tls5modd.c [new file with mode: 0644]
test/nptl/tst-tls5mode.c [new file with mode: 0644]
test/nptl/tst-tls5modf.c [new file with mode: 0644]
test/nptl/tst-tsd1.c [new file with mode: 0644]
test/nptl/tst-tsd2.c [new file with mode: 0644]
test/nptl/tst-tsd3.c [new file with mode: 0644]
test/nptl/tst-tsd4.c [new file with mode: 0644]
test/nptl/tst-tsd5.c [new file with mode: 0644]
test/nptl/tst-umask1.c [new file with mode: 0644]
test/pthread/Makefile.in
test/tls/Makefile [new file with mode: 0644]
test/tls/Makefile.in [new file with mode: 0644]
test/tls/README [new file with mode: 0644]
test/tls/tls-macros-arm.h [new file with mode: 0644]
test/tls/tls-macros-mips.h [new file with mode: 0644]
test/tls/tls-macros-thumb.h [new file with mode: 0644]
test/tls/tls-macros.h [new file with mode: 0644]
test/tls/tst-tls-at-ctor.c [new file with mode: 0644]
test/tls/tst-tls1-static.c [new file with mode: 0644]
test/tls/tst-tls1.c [new file with mode: 0644]
test/tls/tst-tls10.c [new file with mode: 0644]
test/tls/tst-tls10.h [new file with mode: 0644]
test/tls/tst-tls11.c [new file with mode: 0644]
test/tls/tst-tls12.c [new file with mode: 0644]
test/tls/tst-tls13.c [new file with mode: 0644]
test/tls/tst-tls14.c [new file with mode: 0644]
test/tls/tst-tls15.c [new file with mode: 0644]
test/tls/tst-tls16.c [new file with mode: 0644]
test/tls/tst-tls17.c [new file with mode: 0644]
test/tls/tst-tls18.c [new file with mode: 0644]
test/tls/tst-tls2-static.c [new file with mode: 0644]
test/tls/tst-tls2.c [new file with mode: 0644]
test/tls/tst-tls3.c [new file with mode: 0644]
test/tls/tst-tls4.c [new file with mode: 0644]
test/tls/tst-tls5.c [new file with mode: 0644]
test/tls/tst-tls6.c [new file with mode: 0644]
test/tls/tst-tls7.c [new file with mode: 0644]
test/tls/tst-tls8.c [new file with mode: 0644]
test/tls/tst-tls9-static.c [new file with mode: 0644]
test/tls/tst-tls9.c [new file with mode: 0644]
test/tls/tst-tlsmod-at-ctor.c [new file with mode: 0644]
test/tls/tst-tlsmod1.c [new file with mode: 0644]
test/tls/tst-tlsmod10.c [new file with mode: 0644]
test/tls/tst-tlsmod11.c [new file with mode: 0644]
test/tls/tst-tlsmod12.c [new file with mode: 0644]
test/tls/tst-tlsmod13.c [new file with mode: 0644]
test/tls/tst-tlsmod13a.c [new file with mode: 0644]
test/tls/tst-tlsmod14a.c [new file with mode: 0644]
test/tls/tst-tlsmod14b.c [new file with mode: 0644]
test/tls/tst-tlsmod15a.c [new file with mode: 0644]
test/tls/tst-tlsmod15b.c [new file with mode: 0644]
test/tls/tst-tlsmod16a.c [new file with mode: 0644]
test/tls/tst-tlsmod16b.c [new file with mode: 0644]
test/tls/tst-tlsmod17a.c [new file with mode: 0644]
test/tls/tst-tlsmod17b.c [new file with mode: 0644]
test/tls/tst-tlsmod18a.c [new file with mode: 0644]
test/tls/tst-tlsmod2.c [new file with mode: 0644]
test/tls/tst-tlsmod3.c [new file with mode: 0644]
test/tls/tst-tlsmod4.c [new file with mode: 0644]
test/tls/tst-tlsmod5.c [new file with mode: 0644]
test/tls/tst-tlsmod6.c [new file with mode: 0644]
test/tls/tst-tlsmod7.c [new file with mode: 0644]
test/tls/tst-tlsmod8.c [new file with mode: 0644]
test/tls/tst-tlsmod9.c [new file with mode: 0644]
utils/.gitignore

index 5ceb817..c2603a0 100644 (file)
@@ -17,6 +17,7 @@ install_dir/
 .config*
 .*.dep
 /*.log
+cscope.*
 
 #
 # Debugging files
index 3716b94..691a597 100644 (file)
@@ -16,7 +16,6 @@ noconfig_targets := menuconfig config oldconfig silentoldconfig randconfig \
 
 include $(top_srcdir)Rules.mak
 sub_headers := headers
-
 ifndef KCONFIG_CONFIG
 KCONFIG_CONFIG := $(top_builddir).config
 endif
@@ -114,7 +113,8 @@ target-headers-sysdep := \
        $(ALL_HEADERS_BITS_ARCH) \
        $(ALL_HEADERS_BITS_SUBARCH) \
        $(ALL_HEADERS_SYS_COMMON) \
-       $(ALL_HEADERS_SYS_ARCH)
+       $(ALL_HEADERS_SYS_ARCH) \
+       $(ALL_HEADERS_BITS_PTHREAD)
 
 $(top_builddir)include/fpu_control.h:
        @$(disp_ln)
@@ -157,11 +157,14 @@ headers_clean-y += HEADERCLEAN_common
 # libc/sysdeps/linux/Makefile.commonarch to headers-y
 headers-y += $(target-headers-sysdep)
 
-headers: $(top_builddir)include/bits/uClibc_config.h
+headers: $(top_builddir)include/bits/uClibc_config.h $(top_builddir)include/bits/sysnum.h
 subdirs: $(addprefix $(top_builddir),$(subdirs))
-pregen: $(top_builddir)include/bits/sysnum.h headers subdirs
-
-$(top_builddir)include/bits/sysnum.h: $(top_srcdir)extra/scripts/gen_bits_syscall_h.sh | $(top_builddir)include/bits
+pregen-headers: headers
+       $(Q)$(MAKE) $(pregen-headers-y)
+pregen: pregen-headers subdirs
+       $(Q)$(if $(UCLIBC_HAS_LOCALE),$(MAKE) -C extra/locale locale_headers)
+$(top_builddir)include/bits/sysnum.h: $(top_srcdir)extra/scripts/gen_bits_syscall_h.sh
+       $(Q)$(INSTALL) -d $(@D)
        @$(disp_gen)
        $(Q)set -e; \
        tmp=`mktemp $(top_builddir)include/bits/sysnum.h.XXXXXX 2>/dev/null || true`; \
index 321f356..65b1105 100644 (file)
--- a/Rules.mak
+++ b/Rules.mak
@@ -128,6 +128,8 @@ UCLIBC_LDSO := $(UCLIBC_LDSO_NAME).so.$(MAJOR_VERSION)
 NONSHARED_LIBNAME := uclibc_nonshared.a
 libc := $(top_builddir)lib/$(SHARED_MAJORNAME)
 libc.depend := $(top_builddir)lib/$(SHARED_MAJORNAME:.$(MAJOR_VERSION)=)
+libdl.depend := $(top_builddir)lib/libdl.so
+libpthread.depend := $(top_builddir)lib/libpthread.so
 interp := $(top_builddir)lib/interp.os
 ldso := $(top_builddir)lib/$(UCLIBC_LDSO)
 headers_dep := $(top_builddir)include/bits/sysnum.h
@@ -527,6 +529,7 @@ XWARNINGS=$(call qstrip,$(WARNINGS)) -Wstrict-prototypes -fno-strict-aliasing
 ifeq ($(EXTRA_WARNINGS),y)
 XWARNINGS+=-Wnested-externs -Wshadow -Wmissing-noreturn -Wmissing-format-attribute -Wformat=2
 XWARNINGS+=-Wmissing-prototypes -Wmissing-declarations
+XWARNINGS+=-Wold-style-declaration -Wold-style-definition
 XWARNINGS+=-Wnonnull -Wundef
 # Works only w/ gcc-3.4 and up, can't be checked for gcc-3.x w/ check_gcc()
 #XWARNINGS+=-Wdeclaration-after-statement
@@ -589,7 +592,7 @@ endif
 
 LDFLAGS:=$(LDFLAGS_NOSTRIP) -Wl,-z,defs
 ifeq ($(DODEBUG),y)
-CFLAGS += -O0 -g3
+CFLAGS += -O0 -g3 -DDEBUG
 else
 CFLAGS += $(OPTIMIZATION)
 endif
@@ -632,12 +635,12 @@ PTDIR := libpthread/$(PTNAME)
 # set up system dependencies include dirs (NOTE: order matters!)
 ifeq ($(UCLIBC_HAS_THREADS_NATIVE),y)
 PTINC:=        -I$(top_srcdir)$(PTDIR)                                         \
+       -I$(top_srcdir)$(PTDIR)/sysdeps/unix/sysv/linux/$(TARGET_ARCH)/$(TARGET_SUBARCH)        \
        -I$(top_srcdir)$(PTDIR)/sysdeps/unix/sysv/linux/$(TARGET_ARCH)  \
        -I$(top_srcdir)$(PTDIR)/sysdeps/$(TARGET_ARCH)                  \
        -I$(top_srcdir)$(PTDIR)/sysdeps/unix/sysv/linux                 \
        -I$(top_srcdir)$(PTDIR)/sysdeps/pthread                         \
        -I$(top_srcdir)$(PTDIR)/sysdeps/pthread/bits                            \
-       -I$(top_srcdir)$(PTDIR)/sysdeps/generic                         \
        -I$(top_srcdir)ldso/ldso/$(TARGET_ARCH)                 \
        -I$(top_srcdir)ldso/include
 #
@@ -671,6 +674,7 @@ else
        PTNAME :=
        PTINC  :=
 endif
+CFLAGS += -I$(top_srcdir)libc/sysdeps/linux/common
 CFLAGS += -I$(KERNEL_HEADERS)
 
 #CFLAGS += -iwithprefix include-fixed -iwithprefix include
index 4ce4bb0..e430339 100644 (file)
@@ -401,6 +401,7 @@ config LDSO_GNU_HASH_SUPPORT
 
 choice
        prompt "Thread support"
+       #default UCLIBC_HAS_THREADS_NATIVE if (TARGET_alpha || TARGET_arm || TARGET_i386 || TARGET_mips || TARGET_powerpc || TARGET_sh || TARGET_sh64)
        default HAS_NO_THREADS
        help
          If you want to compile uClibc with pthread support, then answer Y.
@@ -431,11 +432,42 @@ config LINUXTHREADS_NEW
          the latest code from glibc, so it may be the only choice for the
          newer ports (like alpha/amd64/64bit arches and hppa).
 
+config UCLIBC_HAS_THREADS_NATIVE
+       bool "Native POSIX Threading (NPTL)"
+       select UCLIBC_HAS_TLS
+       select UCLIBC_HAS_STDIO_FUTEXES
+       help
+         If you want to compile uClibc with NPTL support, then answer Y.
+
+         IMPORTANT NOTE!  NPTL requires a Linux 2.6 kernel, binutils
+         at least version 2.16 and GCC with at least version 4.1.0. NPTL
+         will not work with older versions of any above sources. If you
+         ignore any of these guidelines, you do so at your own risk. Do
+         not ask for help on any of the development mailing lists.
+
+         !!!! WARNING !!!! BIG FAT WARNING !!!! REALLY BIG FAT WARNING !!!!
+
+         This is experimental code and at times it may not even build and
+         even if it does it might decide to do random damage. This code is
+         potentially hazardous to your health and sanity. It will remain
+         that way until further notice at which point this notice will
+         disappear. Thank you for your support and for not smoking.
+
 endchoice
 
 config UCLIBC_HAS_THREADS
        def_bool y if !HAS_NO_THREADS
 
+config UCLIBC_HAS_TLS
+       bool "Thread-Local Storage"
+       depends on UCLIBC_HAS_THREADS_NATIVE
+       default n
+       help
+         If you want to enable TLS support then answer Y.
+         This is fast an efficient way to store per-thread local data
+         which is not on stack. It needs __thread support enabled in
+         gcc.
+
 config PTHREADS_DEBUG_SUPPORT
        bool "Build pthreads debugging support"
        default n
@@ -1715,6 +1747,14 @@ config UCLIBC_HAS_GNU_GETOPT
 
          Most people will answer Y.
 
+config UCLIBC_HAS_STDIO_FUTEXES
+       bool "Use futexes for multithreaded I/O locking"
+       default n
+       depends on UCLIBC_HAS_THREADS_NATIVE
+       help
+         If you want to compile uClibc to use futexes for low-level
+         I/O locking, answer Y.  Otherwise, answer N.
+
 config UCLIBC_HAS_GETOPT_LONG
        bool "Support getopt_long/getopt_long_only"
        depends on !UCLIBC_HAS_GNU_GETOPT
index f9ec316..013bd6e 100644 (file)
@@ -26,7 +26,7 @@ NF == 1 { sub(/^.*$/, "& &"); }
 NF > 1 {
   name = $1;
   sub(/^[^     ]+[     ]+/, "");
-  printf "__asm__ (\"@@@name@@@%s@@@value@@@%%0@@@end@@@\" : : \"i\" (%s));\n",
+  printf "__asm__ (\"@@@name@@@%s@@@value@@@%%0@@@end@@@\" : : \"i\" ((long) %s));\n",
     name, $0;
 }
 
index aff4120..6383572 100644 (file)
@@ -1,5 +1,5 @@
 /* Internal macros for atomic operations for GNU C Library.
-   Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+   Copyright (C) 2002-2006, 2009 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
 
 #ifndef _ATOMIC_H
 #define _ATOMIC_H      1
 
+/* This header defines three types of macros:
+
+   - atomic arithmetic and logic operation on memory.  They all
+     have the prefix "atomic_".
+
+   - conditionally atomic operations of the same kinds.  These
+     always behave identical but can be faster when atomicity
+     is not really needed since only one thread has access to
+     the memory location.  In that case the code is slower in
+     the multi-thread case.  The interfaces have the prefix
+     "catomic_".
+
+   - support functions like barriers.  They also have the preifx
+     "atomic_".
+
+   Architectures must provide a few lowlevel macros (the compare
+   and exchange definitions).  All others are optional.  They
+   should only be provided if the architecture has specific
+   support for the operation.
+
+   As <atomic.h> macros are usually heavily nested and often use local
+   variables to make sure side-effects are evaluated properly, use for
+   macro local variables a per-macro unique prefix.  This file uses
+   __atgN_ prefix where N is different in each macro.  */
+
 #include <stdlib.h>
 
 #include <bits/atomic.h>
    and following args.  */
 #define __atomic_val_bysize(pre, post, mem, ...)                             \
   ({                                                                         \
-    __typeof (*mem) __result;                                                \
+    __typeof (*mem) __atg1_result;                                           \
     if (sizeof (*mem) == 1)                                                  \
-      __result = pre##_8_##post (mem, __VA_ARGS__);                          \
+      __atg1_result = pre##_8_##post (mem, __VA_ARGS__);                     \
     else if (sizeof (*mem) == 2)                                             \
-      __result = pre##_16_##post (mem, __VA_ARGS__);                         \
+      __atg1_result = pre##_16_##post (mem, __VA_ARGS__);                    \
     else if (sizeof (*mem) == 4)                                             \
-      __result = pre##_32_##post (mem, __VA_ARGS__);                         \
+      __atg1_result = pre##_32_##post (mem, __VA_ARGS__);                    \
     else if (sizeof (*mem) == 8)                                             \
-      __result = pre##_64_##post (mem, __VA_ARGS__);                         \
+      __atg1_result = pre##_64_##post (mem, __VA_ARGS__);                    \
     else                                                                     \
       abort ();                                                                      \
-    __result;                                                                \
+    __atg1_result;                                                           \
   })
 #define __atomic_bool_bysize(pre, post, mem, ...)                            \
   ({                                                                         \
-    int __result;                                                            \
+    int __atg2_result;                                                       \
     if (sizeof (*mem) == 1)                                                  \
-      __result = pre##_8_##post (mem, __VA_ARGS__);                          \
+      __atg2_result = pre##_8_##post (mem, __VA_ARGS__);                     \
     else if (sizeof (*mem) == 2)                                             \
-      __result = pre##_16_##post (mem, __VA_ARGS__);                         \
+      __atg2_result = pre##_16_##post (mem, __VA_ARGS__);                    \
     else if (sizeof (*mem) == 4)                                             \
-      __result = pre##_32_##post (mem, __VA_ARGS__);                         \
+      __atg2_result = pre##_32_##post (mem, __VA_ARGS__);                    \
     else if (sizeof (*mem) == 8)                                             \
-      __result = pre##_64_##post (mem, __VA_ARGS__);                         \
+      __atg2_result = pre##_64_##post (mem, __VA_ARGS__);                    \
     else                                                                     \
       abort ();                                                                      \
-    __result;                                                                \
+    __atg2_result;                                                           \
   })
 
 
 #endif
 
 
+#ifndef catomic_compare_and_exchange_val_acq
+# ifdef __arch_c_compare_and_exchange_val_32_acq
+#  define catomic_compare_and_exchange_val_acq(mem, newval, oldval) \
+  __atomic_val_bysize (__arch_c_compare_and_exchange_val,acq,                \
+                      mem, newval, oldval)
+# else
+#  define catomic_compare_and_exchange_val_acq(mem, newval, oldval) \
+  atomic_compare_and_exchange_val_acq (mem, newval, oldval)
+# endif
+#endif
+
+
+#ifndef catomic_compare_and_exchange_val_rel
+# ifndef atomic_compare_and_exchange_val_rel
+#  define catomic_compare_and_exchange_val_rel(mem, newval, oldval)          \
+  catomic_compare_and_exchange_val_acq (mem, newval, oldval)
+# else
+#  define catomic_compare_and_exchange_val_rel(mem, newval, oldval)          \
+  atomic_compare_and_exchange_val_rel (mem, newval, oldval)
+# endif
+#endif
+
+
 #ifndef atomic_compare_and_exchange_val_rel
 # define atomic_compare_and_exchange_val_rel(mem, newval, oldval)            \
   atomic_compare_and_exchange_val_acq (mem, newval, oldval)
 #  define atomic_compare_and_exchange_bool_acq(mem, newval, oldval) \
   __atomic_bool_bysize (__arch_compare_and_exchange_bool,acq,                \
                        mem, newval, oldval)
-#  else
-#   define atomic_compare_and_exchange_bool_acq(mem, newval, oldval) \
+# else
+#  define atomic_compare_and_exchange_bool_acq(mem, newval, oldval) \
+  ({ /* Cannot use __oldval here, because macros later in this file might     \
+       call this macro with __oldval argument.  */                           \
+     __typeof (oldval) __atg3_old = (oldval);                                \
+     atomic_compare_and_exchange_val_acq (mem, newval, __atg3_old)           \
+       != __atg3_old;                                                        \
+  })
+# endif
+#endif
+
+
+#ifndef catomic_compare_and_exchange_bool_acq
+# ifdef __arch_c_compare_and_exchange_bool_32_acq
+#  define catomic_compare_and_exchange_bool_acq(mem, newval, oldval) \
+  __atomic_bool_bysize (__arch_c_compare_and_exchange_bool,acq,                      \
+                       mem, newval, oldval)
+# else
+#  define catomic_compare_and_exchange_bool_acq(mem, newval, oldval) \
   ({ /* Cannot use __oldval here, because macros later in this file might     \
        call this macro with __oldval argument.  */                           \
-     __typeof (oldval) __old = (oldval);                                     \
-     atomic_compare_and_exchange_val_acq (mem, newval, __old) != __old;              \
+     __typeof (oldval) __atg4_old = (oldval);                                \
+     catomic_compare_and_exchange_val_acq (mem, newval, __atg4_old)          \
+       != __atg4_old;                                                        \
   })
 # endif
 #endif
 
 
+#ifndef catomic_compare_and_exchange_bool_rel
+# ifndef atomic_compare_and_exchange_bool_rel
+#  define catomic_compare_and_exchange_bool_rel(mem, newval, oldval)         \
+  catomic_compare_and_exchange_bool_acq (mem, newval, oldval)
+# else
+#  define catomic_compare_and_exchange_bool_rel(mem, newval, oldval)         \
+  atomic_compare_and_exchange_bool_rel (mem, newval, oldval)
+# endif
+#endif
+
+
 #ifndef atomic_compare_and_exchange_bool_rel
 # define atomic_compare_and_exchange_bool_rel(mem, newval, oldval) \
   atomic_compare_and_exchange_bool_acq (mem, newval, oldval)
 /* Store NEWVALUE in *MEM and return the old value.  */
 #ifndef atomic_exchange_acq
 # define atomic_exchange_acq(mem, newvalue) \
-  ({ __typeof (*(mem)) __oldval;                                             \
-     __typeof (mem) __memp = (mem);                                          \
-     __typeof (*(mem)) __value = (newvalue);                                 \
+  ({ __typeof (*(mem)) __atg5_oldval;                                        \
+     __typeof (mem) __atg5_memp = (mem);                                     \
+     __typeof (*(mem)) __atg5_value = (newvalue);                            \
                                                                              \
      do                                                                              \
-       __oldval = (*__memp);                                                 \
-     while (__builtin_expect (atomic_compare_and_exchange_bool_acq (__memp,   \
-                                                                   __value,  \
-                                                                   __oldval),\
-                             0));                                            \
+       __atg5_oldval = *__atg5_memp;                                         \
+     while (__builtin_expect                                                 \
+           (atomic_compare_and_exchange_bool_acq (__atg5_memp, __atg5_value, \
+                                                  __atg5_oldval), 0));       \
                                                                              \
-     __oldval; })
+     __atg5_oldval; })
 #endif
 
 #ifndef atomic_exchange_rel
 /* Add VALUE to *MEM and return the old value of *MEM.  */
 #ifndef atomic_exchange_and_add
 # define atomic_exchange_and_add(mem, value) \
-  ({ __typeof (*(mem)) __oldval;                                             \
-     __typeof (mem) __memp = (mem);                                          \
-     __typeof (*(mem)) __value = (value);                                    \
+  ({ __typeof (*(mem)) __atg6_oldval;                                        \
+     __typeof (mem) __atg6_memp = (mem);                                     \
+     __typeof (*(mem)) __atg6_value = (value);                               \
                                                                              \
      do                                                                              \
-       __oldval = (*__memp);                                                 \
-     while (__builtin_expect (atomic_compare_and_exchange_bool_acq (__memp,   \
-                                                                   __oldval  \
-                                                                   + __value,\
-                                                                   __oldval),\
-                             0));                                            \
+       __atg6_oldval = *__atg6_memp;                                         \
+     while (__builtin_expect                                                 \
+           (atomic_compare_and_exchange_bool_acq (__atg6_memp,               \
+                                                  __atg6_oldval              \
+                                                  + __atg6_value,            \
+                                                  __atg6_oldval), 0));       \
                                                                              \
-     __oldval; })
+     __atg6_oldval; })
+#endif
+
+
+#ifndef catomic_exchange_and_add
+# define catomic_exchange_and_add(mem, value) \
+  ({ __typeof (*(mem)) __atg7_oldv;                                          \
+     __typeof (mem) __atg7_memp = (mem);                                     \
+     __typeof (*(mem)) __atg7_value = (value);                               \
+                                                                             \
+     do                                                                              \
+       __atg7_oldv = *__atg7_memp;                                           \
+     while (__builtin_expect                                                 \
+           (catomic_compare_and_exchange_bool_acq (__atg7_memp,              \
+                                                   __atg7_oldv               \
+                                                   + __atg7_value,           \
+                                                   __atg7_oldv), 0));        \
+                                                                             \
+     __atg7_oldv; })
+#endif
+
+
+#ifndef atomic_max
+# define atomic_max(mem, value) \
+  do {                                                                       \
+    __typeof (*(mem)) __atg8_oldval;                                         \
+    __typeof (mem) __atg8_memp = (mem);                                              \
+    __typeof (*(mem)) __atg8_value = (value);                                \
+    do {                                                                     \
+      __atg8_oldval = *__atg8_memp;                                          \
+      if (__atg8_oldval >= __atg8_value)                                     \
+       break;                                                                \
+    } while (__builtin_expect                                                \
+            (atomic_compare_and_exchange_bool_acq (__atg8_memp, __atg8_value,\
+                                                   __atg8_oldval), 0));      \
+  } while (0)
+#endif
+
+
+#ifndef catomic_max
+# define catomic_max(mem, value) \
+  do {                                                                       \
+    __typeof (*(mem)) __atg9_oldv;                                           \
+    __typeof (mem) __atg9_memp = (mem);                                              \
+    __typeof (*(mem)) __atg9_value = (value);                                \
+    do {                                                                     \
+      __atg9_oldv = *__atg9_memp;                                            \
+      if (__atg9_oldv >= __atg9_value)                                       \
+       break;                                                                \
+    } while (__builtin_expect                                                \
+            (catomic_compare_and_exchange_bool_acq (__atg9_memp,             \
+                                                    __atg9_value,            \
+                                                    __atg9_oldv), 0));       \
+  } while (0)
+#endif
+
+
+#ifndef atomic_min
+# define atomic_min(mem, value) \
+  do {                                                                       \
+    __typeof (*(mem)) __atg10_oldval;                                        \
+    __typeof (mem) __atg10_memp = (mem);                                     \
+    __typeof (*(mem)) __atg10_value = (value);                               \
+    do {                                                                     \
+      __atg10_oldval = *__atg10_memp;                                        \
+      if (__atg10_oldval <= __atg10_value)                                   \
+       break;                                                                \
+    } while (__builtin_expect                                                \
+            (atomic_compare_and_exchange_bool_acq (__atg10_memp,             \
+                                                   __atg10_value,            \
+                                                   __atg10_oldval), 0));     \
+  } while (0)
 #endif
 
 
 #endif
 
 
+#ifndef catomic_add
+# define catomic_add(mem, value) \
+  (void) catomic_exchange_and_add ((mem), (value))
+#endif
+
+
 #ifndef atomic_increment
 # define atomic_increment(mem) atomic_add ((mem), 1)
 #endif
 
 
+#ifndef catomic_increment
+# define catomic_increment(mem) catomic_add ((mem), 1)
+#endif
+
+
 #ifndef atomic_increment_val
 # define atomic_increment_val(mem) (atomic_exchange_and_add ((mem), 1) + 1)
 #endif
 
 
+#ifndef catomic_increment_val
+# define catomic_increment_val(mem) (catomic_exchange_and_add ((mem), 1) + 1)
+#endif
+
+
 /* Add one to *MEM and return true iff it's now zero.  */
 #ifndef atomic_increment_and_test
 # define atomic_increment_and_test(mem) \
 #endif
 
 
+#ifndef catomic_decrement
+# define catomic_decrement(mem) catomic_add ((mem), -1)
+#endif
+
+
 #ifndef atomic_decrement_val
 # define atomic_decrement_val(mem) (atomic_exchange_and_add ((mem), -1) - 1)
 #endif
 
 
+#ifndef catomic_decrement_val
+# define catomic_decrement_val(mem) (catomic_exchange_and_add ((mem), -1) - 1)
+#endif
+
+
 /* Subtract 1 from *MEM and return true iff it's now zero.  */
 #ifndef atomic_decrement_and_test
 # define atomic_decrement_and_test(mem) \
 /* Decrement *MEM if it is > 0, and return the old value.  */
 #ifndef atomic_decrement_if_positive
 # define atomic_decrement_if_positive(mem) \
-  ({ __typeof (*(mem)) __oldval;                                             \
-     __typeof (mem) __memp = (mem);                                          \
+  ({ __typeof (*(mem)) __atg11_oldval;                                       \
+     __typeof (mem) __atg11_memp = (mem);                                    \
                                                                              \
      do                                                                              \
        {                                                                     \
-        __oldval = *__memp;                                                  \
-        if (__builtin_expect (__oldval <= 0, 0))                             \
+        __atg11_oldval = *__atg11_memp;                                      \
+        if (__builtin_expect (__atg11_oldval <= 0, 0))                       \
           break;                                                             \
        }                                                                     \
-     while (__builtin_expect (atomic_compare_and_exchange_bool_acq (__memp,   \
-                                                                   __oldval  \
-                                                                   - 1,      \
-                                                                   __oldval),\
-                             0));\
-     __oldval; })
+     while (__builtin_expect                                                 \
+           (atomic_compare_and_exchange_bool_acq (__atg11_memp,              \
+                                                  __atg11_oldval - 1,        \
+                                                  __atg11_oldval), 0));      \
+     __atg11_oldval; })
 #endif
 
 
 #ifndef atomic_add_negative
 # define atomic_add_negative(mem, value)                                     \
-  ({ __typeof (value) __aan_value = (value);                                 \
-     atomic_exchange_and_add (mem, __aan_value) < -__aan_value; })
+  ({ __typeof (value) __atg12_value = (value);                               \
+     atomic_exchange_and_add (mem, __atg12_value) < -__atg12_value; })
 #endif
 
 
 #ifndef atomic_add_zero
 # define atomic_add_zero(mem, value)                                         \
-  ({ __typeof (value) __aaz_value = (value);                                 \
-     atomic_exchange_and_add (mem, __aaz_value) == -__aaz_value; })
+  ({ __typeof (value) __atg13_value = (value);                               \
+     atomic_exchange_and_add (mem, __atg13_value) == -__atg13_value; })
 #endif
 
 
 
 #ifndef atomic_bit_test_set
 # define atomic_bit_test_set(mem, bit) \
-  ({ __typeof (*(mem)) __oldval;                                             \
-     __typeof (mem) __memp = (mem);                                          \
-     __typeof (*(mem)) __mask = ((__typeof (*(mem))) 1 << (bit));            \
+  ({ __typeof (*(mem)) __atg14_old;                                          \
+     __typeof (mem) __atg14_memp = (mem);                                    \
+     __typeof (*(mem)) __atg14_mask = ((__typeof (*(mem))) 1 << (bit));              \
                                                                              \
      do                                                                              \
-       __oldval = (*__memp);                                                 \
-     while (__builtin_expect (atomic_compare_and_exchange_bool_acq (__memp,   \
-                                                                   __oldval  \
-                                                                   | __mask, \
-                                                                   __oldval),\
-                             0));                                            \
+       __atg14_old = (*__atg14_memp);                                        \
+     while (__builtin_expect                                                 \
+           (atomic_compare_and_exchange_bool_acq (__atg14_memp,              \
+                                                  __atg14_old | __atg14_mask,\
+                                                  __atg14_old), 0));         \
                                                                              \
-     __oldval & __mask; })
+     __atg14_old & __atg14_mask; })
 #endif
 
+/* Atomically *mem &= mask.  */
+#ifndef atomic_and
+# define atomic_and(mem, mask) \
+  do {                                                                       \
+    __typeof (*(mem)) __atg15_old;                                           \
+    __typeof (mem) __atg15_memp = (mem);                                     \
+    __typeof (*(mem)) __atg15_mask = (mask);                                 \
+                                                                             \
+    do                                                                       \
+      __atg15_old = (*__atg15_memp);                                         \
+    while (__builtin_expect                                                  \
+          (atomic_compare_and_exchange_bool_acq (__atg15_memp,               \
+                                                 __atg15_old & __atg15_mask, \
+                                                 __atg15_old), 0));          \
+  } while (0)
+#endif
+
+#ifndef catomic_and
+# define catomic_and(mem, mask) \
+  do {                                                                       \
+    __typeof (*(mem)) __atg20_old;                                           \
+    __typeof (mem) __atg20_memp = (mem);                                     \
+    __typeof (*(mem)) __atg20_mask = (mask);                                 \
+                                                                             \
+    do                                                                       \
+      __atg20_old = (*__atg20_memp);                                         \
+    while (__builtin_expect                                                  \
+          (catomic_compare_and_exchange_bool_acq (__atg20_memp,              \
+                                                  __atg20_old & __atg20_mask,\
+                                                  __atg20_old), 0));         \
+  } while (0)
+#endif
+
+/* Atomically *mem &= mask and return the old value of *mem.  */
+#ifndef atomic_and_val
+# define atomic_and_val(mem, mask) \
+  ({ __typeof (*(mem)) __atg16_old;                                          \
+     __typeof (mem) __atg16_memp = (mem);                                    \
+     __typeof (*(mem)) __atg16_mask = (mask);                                \
+                                                                             \
+     do                                                                              \
+       __atg16_old = (*__atg16_memp);                                        \
+     while (__builtin_expect                                                 \
+           (atomic_compare_and_exchange_bool_acq (__atg16_memp,              \
+                                                  __atg16_old & __atg16_mask,\
+                                                  __atg16_old), 0));         \
+                                                                             \
+     __atg16_old; })
+#endif
+
+/* Atomically *mem |= mask and return the old value of *mem.  */
+#ifndef atomic_or
+# define atomic_or(mem, mask) \
+  do {                                                                       \
+    __typeof (*(mem)) __atg17_old;                                           \
+    __typeof (mem) __atg17_memp = (mem);                                     \
+    __typeof (*(mem)) __atg17_mask = (mask);                                 \
+                                                                             \
+    do                                                                       \
+      __atg17_old = (*__atg17_memp);                                         \
+    while (__builtin_expect                                                  \
+          (atomic_compare_and_exchange_bool_acq (__atg17_memp,               \
+                                                 __atg17_old | __atg17_mask, \
+                                                 __atg17_old), 0));          \
+  } while (0)
+#endif
+
+#ifndef catomic_or
+# define catomic_or(mem, mask) \
+  do {                                                                       \
+    __typeof (*(mem)) __atg18_old;                                           \
+    __typeof (mem) __atg18_memp = (mem);                                     \
+    __typeof (*(mem)) __atg18_mask = (mask);                                 \
+                                                                             \
+    do                                                                       \
+      __atg18_old = (*__atg18_memp);                                         \
+    while (__builtin_expect                                                  \
+          (catomic_compare_and_exchange_bool_acq (__atg18_memp,              \
+                                                  __atg18_old | __atg18_mask,\
+                                                  __atg18_old), 0));         \
+  } while (0)
+#endif
+
+/* Atomically *mem |= mask and return the old value of *mem.  */
+#ifndef atomic_or_val
+# define atomic_or_val(mem, mask) \
+  ({ __typeof (*(mem)) __atg19_old;                                          \
+     __typeof (mem) __atg19_memp = (mem);                                    \
+     __typeof (*(mem)) __atg19_mask = (mask);                                \
+                                                                             \
+     do                                                                              \
+       __atg19_old = (*__atg19_memp);                                        \
+     while (__builtin_expect                                                 \
+           (atomic_compare_and_exchange_bool_acq (__atg19_memp,              \
+                                                  __atg19_old | __atg19_mask,\
+                                                  __atg19_old), 0));         \
+                                                                             \
+     __atg19_old; })
+#endif
 
 #ifndef atomic_full_barrier
 # define atomic_full_barrier() __asm__ ("" ::: "memory")
 #endif
 
 
+#ifndef atomic_forced_read
+# define atomic_forced_read(x) \
+  ({ __typeof (x) __x; __asm__ ("" : "=r" (__x) : "0" (x)); __x; })
+#endif
+
+
 #ifndef atomic_delay
 # define atomic_delay() do { /* nothing */ } while (0)
 #endif
index 4615a6a..2800fe2 100644 (file)
 # define attribute_noreturn
 #endif
 
+#define libc_freeres_ptr(decl) \
+      __make_section_unallocated ("__libc_freeres_ptrs, \"aw\", %nobits") \
+  decl __attribute__ ((section ("__libc_freeres_ptrs" __sec_comment)))
+#define __libc_freeres_fn_section \
+      __attribute__ ((section ("__libc_freeres_fn")))
+
 #ifndef NOT_IN_libc
 # define IS_IN_libc 1
 #endif
index e566905..53bb5be 100644 (file)
@@ -72,7 +72,7 @@ extern char *_dl_ldsopath;             /* Where the shared lib loader was found
 extern const char *_dl_progname;       /* The name of the executable being run */
 extern size_t _dl_pagesize;            /* Store the page size for use later */
 
-#ifdef USE_TLS
+#if defined(USE_TLS) && USE_TLS
 extern void _dl_add_to_slotinfo (struct link_map  *l);
 extern void ** __attribute__ ((const)) _dl_initial_error_catch_tsd (void);
 #endif
index e906d07..564f593 100644 (file)
@@ -38,7 +38,6 @@
 #ifdef __UCLIBC_HAS_THREADS_NATIVE__
 
 #include <sysdep.h>
-#include <tls.h>
 
 /* GCC will emit calls to this routine under -mtp=soft.  Linux has an
    equivalent helper function (which clobbers fewer registers than
index 52b7aa5..d2808f9 100644 (file)
@@ -842,7 +842,10 @@ __tls_get_addr (GET_ADDR_ARGS)
   void *p;
 
   if (__builtin_expect (dtv[0].counter != _dl_tls_generation, 0))
-    the_map = _dl_update_slotinfo (GET_ADDR_MODULE);
+    {
+      the_map = _dl_update_slotinfo (GET_ADDR_MODULE);
+      dtv = THREAD_DTV ();
+    }
 
   p = dtv[GET_ADDR_MODULE].pointer.val;
 
index 0fbc8f1..74da588 100644 (file)
@@ -376,19 +376,6 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr,
        _dl_init_static_tls = &_dl_nothread_init_static_tls;
 #endif
 
-#ifdef __UCLIBC_HAS_SSP__
-       /* Set up the stack checker's canary.  */
-       stack_chk_guard = _dl_setup_stack_chk_guard ();
-# ifdef THREAD_SET_STACK_GUARD
-       THREAD_SET_STACK_GUARD (stack_chk_guard);
-#  ifdef __UCLIBC_HAS_SSP_COMPAT__
-       __guard = stack_chk_guard;
-#  endif
-# else
-       __stack_chk_guard = stack_chk_guard;
-# endif
-#endif
-
        /* At this point we are now free to examine the user application,
         * and figure out which libraries are supposed to be called.  Until
         * we have this list, we will not be completely ready for dynamic
@@ -944,6 +931,19 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr,
                tcbp = init_tls ();
        }
 #endif
+#ifdef __UCLIBC_HAS_SSP__
+       /* Set up the stack checker's canary.  */
+       stack_chk_guard = _dl_setup_stack_chk_guard ();
+# ifdef THREAD_SET_STACK_GUARD
+       THREAD_SET_STACK_GUARD (stack_chk_guard);
+#  ifdef __UCLIBC_HAS_SSP_COMPAT__
+       __guard = stack_chk_guard;
+#  endif
+# else
+       __stack_chk_guard = stack_chk_guard;
+# endif
+#endif
+
 
        _dl_debug_early("Beginning relocation fixups\n");
 
index 0eed657..ae3542a 100644 (file)
@@ -46,8 +46,12 @@ extern unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, int reloc_ent
    define the value.
    ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one
    of the main executable's symbols, as for a COPY reloc.  */
-#define elf_machine_type_class(type) \
-  ((((type) == R_X86_64_JUMP_SLOT) * ELF_RTYPE_CLASS_PLT) \
+#define elf_machine_type_class(type)                                         \
+  ((((type) == R_X86_64_JUMP_SLOT                                            \
+     || (type) == R_X86_64_DTPMOD64                                          \
+     || (type) == R_X86_64_DTPOFF64                                          \
+     || (type) == R_X86_64_TPOFF64)                                          \
+    * ELF_RTYPE_CLASS_PLT)                                                   \
    | (((type) == R_X86_64_COPY) * ELF_RTYPE_CLASS_COPY))
 
 /* Return the link-time address of _DYNAMIC.  Conveniently, this is the
index 92ac5ac..54528d3 100644 (file)
@@ -157,6 +157,7 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope,
        int reloc_type;
        int symtab_index;
        char *symname;
+       struct elf_resolve *tls_tpnt = 0;
        ElfW(Sym) *sym;
        ElfW(Addr) *reloc_addr;
        ElfW(Addr) symbol_addr;
@@ -173,18 +174,26 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope,
 
        if (symtab_index) {
                symbol_addr = (ElfW(Addr))_dl_find_hash(symname, scope, tpnt,
-                                                           elf_machine_type_class(reloc_type), NULL);
+                               elf_machine_type_class(reloc_type), &tls_tpnt);
                /*
                 * We want to allow undefined references to weak symbols - this
                 * might have been intentional.  We should not be linking local
                 * symbols here, so all bases should be covered.
                 */
-               if (unlikely(!symbol_addr && ELF_ST_BIND(sym->st_info) != STB_WEAK)) {
-                       _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", _dl_progname, symname);
-                       _dl_exit(1);
+               if (unlikely(!symbol_addr && (ELF_ST_TYPE(sym->st_info) != STT_TLS)
+                                       && (ELF_ST_BIND(sym->st_info) != STB_WEAK))) {
+                       /* This may be non-fatal if called from dlopen. */
+                       return 1;
                }
+       } else {
+               /* Relocs against STN_UNDEF are usually treated as using a
+                * symbol value of zero, and using the module containing the
+                * reloc itself. */
+               symbol_addr = sym->st_value;
+               tls_tpnt = tpnt;
        }
 
+
 #if defined (__SUPPORT_LD_DEBUG__)
        old_val = *reloc_addr;
 #endif
@@ -212,13 +221,20 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope,
                        break;
                */
                case R_X86_64_DTPMOD64:
-                       *reloc_addr = 1;
+                       *reloc_addr = tls_tpnt->l_tls_modid;
                        break;
                case R_X86_64_DTPOFF64:
+                       /* During relocation all TLS symbols are defined and used.
+                        * Therefore the offset is already correct.  */
                        *reloc_addr = sym->st_value + rpnt->r_addend;
                        break;
                case R_X86_64_TPOFF64:
-                       *reloc_addr = sym->st_value + rpnt->r_addend - symbol_addr;
+                       /* The offset is negative, forward from the thread pointer.
+                        * We know the offset of the object the symbol is contained in.
+                        * It is a negative value which will be added to the
+                        * thread pointer.  */
+                       CHECK_STATIC_TLS ((struct link_map *) tls_tpnt);
+                       *reloc_addr = sym->st_value - tls_tpnt->l_tls_offset + rpnt->r_addend;
                        break;
                case R_X86_64_32:
                        *(unsigned int *) reloc_addr = symbol_addr + rpnt->r_addend;
index 323c4e4..ff3e5c3 100644 (file)
@@ -16,7 +16,9 @@ VERSION_SCRIPT := -Wl,--version-script,$(VERSION_SCRIPT)
 endif
 
 LDFLAGS-libc.so := $(LDFLAGS) $(VERSION_SCRIPT) -Wl,-init,$(SYMBOL_PREFIX)__uClibc_init
-
+ifeq ($(UCLIBC_HAS_STDIO_FUTEXES),y)
+CFLAGS += -D__USE_STDIO_FUTEXES__
+endif
 LIBS-libc.so := $(interp) $(ldso) $(top_builddir)lib/$(NONSHARED_LIBNAME)
 
 # we have SHARED_MAJORNAME=libc.so.$(MAJOR_VERSION) defined in Rules.mak
index b91486f..8c7f7b9 100644 (file)
@@ -56,6 +56,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assert.h>
 #include <errno.h>
 #include <netdb.h>
+#include <tls.h>
 #include <resolv.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -307,7 +308,7 @@ gaih_local(const char *name, const struct gaih_service *service,
                char *buf = ((struct sockaddr_un *)ai->ai_addr)->sun_path;
 
                if (__path_search(buf, L_tmpnam, NULL, NULL, 0) != 0
-                || __gen_tempname(buf, __GT_NOCREATE) != 0
+                || __gen_tempname(buf, __GT_NOCREATE, 0) != 0
                ) {
                        return -EAI_SYSTEM;
                }
index ac4c56c..90b22ae 100644 (file)
@@ -14,6 +14,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <netdb.h>
+#include <not-cancel.h>
 
 #define HOSTID "/etc/hostid"
 
@@ -25,11 +26,11 @@ int sethostid(long int new_id)
 
        if (geteuid() || getuid())
                return __set_errno(EPERM);
-       fd = open(HOSTID, O_CREAT|O_WRONLY, 0644);
+       fd = open_not_cancel(HOSTID, O_CREAT|O_WRONLY, 0644);
        if (fd < 0)
                return fd;
-       ret = write(fd, &new_id, sizeof(new_id)) == sizeof(new_id) ? 0 : -1;
-       close(fd);
+       ret = write_not_cancel(fd, &new_id, sizeof(new_id)) == sizeof(new_id) ? 0 : -1;
+       close_not_cancel_no_status (fd);
        return ret;
 }
 #endif
@@ -44,10 +45,10 @@ long int gethostid(void)
         * It is not an error if we cannot read this file. It is not even an
         * error if we cannot read all the bytes, we just carry on trying...
         */
-       fd = open(HOSTID, O_RDONLY);
+       fd = open_not_cancel_2(HOSTID, O_RDONLY);
        if (fd >= 0) {
-               int i = read(fd, &id, sizeof(id));
-               close(fd);
+               int i = read_not_cancel(fd, &id, sizeof(id));
+               close_not_cancel_no_status(fd);
                if (i > 0)
                        return id;
        }
index 750a464..8efcd2a 100644 (file)
@@ -32,6 +32,7 @@
 #include <sys/socket.h>
 #include <sys/ioctl.h>
 #include <libc-internal.h>
+#include <not-cancel.h>
 
 #include "netlinkaccess.h"
 
@@ -55,13 +56,13 @@ if_nametoindex(const char* ifname)
     {
       /* close never fails here, fd is just a unconnected socket.
        *int saved_errno = errno; */
-      close(fd);
+      close_not_cancel_no_status(fd);
       /*if (saved_errno == EINVAL)
        *  __set_errno(ENOSYS); */
       return 0;
     }
 
-  close(fd);
+  close_not_cancel_no_status(fd);
   return ifr.ifr_ifindex;
 #endif
 }
@@ -112,7 +113,7 @@ if_nameindex (void)
 
       if (ioctl (fd, SIOCGIFCONF, &ifc) < 0)
        {
-         close (fd);
+         close_not_cancel_no_status (fd);
          return NULL;
        }
     }
@@ -123,7 +124,7 @@ if_nameindex (void)
   idx = malloc ((nifs + 1) * sizeof (struct if_nameindex));
   if (idx == NULL)
     {
-      close(fd);
+      close_not_cancel_no_status (fd);
       __set_errno(ENOBUFS);
       return NULL;
     }
@@ -141,7 +142,7 @@ if_nameindex (void)
          for (j =  0; j < i; ++j)
            free (idx[j].if_name);
          free(idx);
-         close(fd);
+         close_not_cancel_no_status (fd);
          if (saved_errno == EINVAL)
            saved_errno = ENOSYS;
          else if (saved_errno == ENOMEM)
@@ -155,7 +156,7 @@ if_nameindex (void)
   idx[i].if_index = 0;
   idx[i].if_name = NULL;
 
-  close(fd);
+  close_not_cancel_no_status (fd);
   return idx;
 #endif
 }
@@ -298,14 +299,14 @@ if_indextoname (unsigned int ifindex, char *ifname)
   if (ioctl (fd, SIOCGIFNAME, &ifr) < 0)
     {
       int serrno = errno;
-      close (fd);
+      close_not_cancel_no_status (fd);
       if (serrno == ENODEV)
        /* POSIX requires ENXIO.  */
        serrno = ENXIO;
       __set_errno (serrno);
       return NULL;
   }
-  close (fd);
+  close_not_cancel_no_status (fd);
 
   return strncpy (ifname, ifr.ifr_name, IFNAMSIZ);
 # else
index 8bb09ca..e4bdbcb 100644 (file)
@@ -33,27 +33,41 @@ extern int __socketcall(int call, unsigned long *args) attribute_hidden;
 #define SYS_RECVMSG     17
 #endif
 
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include <sysdep-cancel.h>
+#include <pthreadP.h>
+#else
+#define SINGLE_THREAD_P 1
+#endif
 
 #ifdef L_accept
-# ifdef __NR_accept
-_syscall3(int, accept, int, call, struct sockaddr *, addr, socklen_t *,addrlen)
-# elif defined(__NR_socketcall)
-int accept(int s, struct sockaddr *addr, socklen_t * addrlen)
+extern __typeof(accept) __libc_accept;
+#ifdef __NR_accept
+#define __NR___libc_accept  __NR_accept
+_syscall3(int, __libc_accept, int, call, struct sockaddr *, addr, socklen_t *,addrlen)
+#elif defined(__NR_socketcall)
+int __libc_accept(int s, struct sockaddr *addr, socklen_t * addrlen)
 {
        unsigned long args[3];
 
        args[0] = s;
        args[1] = (unsigned long) addr;
        args[2] = (unsigned long) addrlen;
-       return __socketcall(SYS_ACCEPT, args);
+
+       if (SINGLE_THREAD_P)
+               return __socketcall(SYS_ACCEPT, args);
+
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+       int oldtype = LIBC_CANCEL_ASYNC ();
+       int result = __socketcall(SYS_ACCEPT, args);
+       LIBC_CANCEL_RESET (oldtype);
+       return result;
+#endif
+
 }
-# endif
-# ifndef __LINUXTHREADS_OLD__
-libc_hidden_def(accept)
-# else
+#endif
+weak_alias(__libc_accept,accept)
 libc_hidden_weak(accept)
-strong_alias(accept,__libc_accept)
-# endif
 #endif
 
 #ifdef L_bind
@@ -74,25 +88,32 @@ libc_hidden_def(bind)
 #endif
 
 #ifdef L_connect
-# ifdef __NR_connect
-_syscall3(int, connect, int, sockfd, const struct sockaddr *, saddr, socklen_t, addrlen)
-# elif defined(__NR_socketcall)
-int connect(int sockfd, const struct sockaddr *saddr, socklen_t addrlen)
+extern __typeof(connect) __libc_connect;
+#ifdef __NR_connect
+#define __NR___libc_connect __NR_connect
+_syscall3(int, __libc_connect, int, sockfd, const struct sockaddr *, saddr, socklen_t, addrlen)
+#elif defined(__NR_socketcall)
+int __libc_connect(int sockfd, const struct sockaddr *saddr, socklen_t addrlen)
 {
        unsigned long args[3];
 
        args[0] = sockfd;
        args[1] = (unsigned long) saddr;
        args[2] = addrlen;
-       return __socketcall(SYS_CONNECT, args);
+
+       if (SINGLE_THREAD_P)
+               return __socketcall(SYS_CONNECT, args);
+
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+       int oldtype = LIBC_CANCEL_ASYNC ();
+       int result = __socketcall(SYS_CONNECT, args);
+       LIBC_CANCEL_RESET (oldtype);
+       return result;
+#endif
 }
-# endif
-# ifndef __LINUXTHREADS_OLD__
-libc_hidden_def(connect)
-# else
+#endif
+weak_alias(__libc_connect,connect)
 libc_hidden_weak(connect)
-strong_alias(connect,__libc_connect)
-# endif
 #endif
 
 #ifdef L_getpeername
@@ -164,12 +185,14 @@ libc_hidden_def(listen)
 #endif
 
 #ifdef L_recv
-# ifdef __NR_recv
-_syscall4(ssize_t, recv, int, sockfd, __ptr_t, buffer, size_t, len,
+extern __typeof(recv) __libc_recv;
+#ifdef __NR_recv
+#define __NR___libc_recv __NR_recv
+_syscall4(ssize_t, __libc_recv, int, sockfd, __ptr_t, buffer, size_t, len,
        int, flags)
-# elif defined(__NR_socketcall)
+#elif defined(__NR_socketcall)
 /* recv, recvfrom added by bir7@leland.stanford.edu */
-ssize_t recv(int sockfd, __ptr_t buffer, size_t len, int flags)
+ssize_t __libc_recv(int sockfd, __ptr_t buffer, size_t len, int flags)
 {
        unsigned long args[4];
 
@@ -177,29 +200,36 @@ ssize_t recv(int sockfd, __ptr_t buffer, size_t len, int flags)
        args[1] = (unsigned long) buffer;
        args[2] = len;
        args[3] = flags;
-       return (__socketcall(SYS_RECV, args));
+
+       if (SINGLE_THREAD_P)
+               return (__socketcall(SYS_RECV, args));
+
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+       int oldtype = LIBC_CANCEL_ASYNC ();
+       int result = __socketcall(SYS_RECV, args);
+       LIBC_CANCEL_RESET (oldtype);
+       return result;
+#endif
 }
-# elif defined(__NR_recvfrom)
-ssize_t recv(int sockfd, __ptr_t buffer, size_t len, int flags)
+#elif defined(__NR_recvfrom)
+ssize_t __libc_recv(int sockfd, __ptr_t buffer, size_t len, int flags)
 {
        return (recvfrom(sockfd, buffer, len, flags, NULL, NULL));
 }
-# endif
-# ifndef __LINUXTHREADS_OLD__
-libc_hidden_def(recv)
-# else
+#endif
+weak_alias(__libc_recv,recv)
 libc_hidden_weak(recv)
-strong_alias(recv,__libc_recv)
-# endif
 #endif
 
 #ifdef L_recvfrom
-# ifdef __NR_recvfrom
-_syscall6(ssize_t, recvfrom, int, sockfd, __ptr_t, buffer, size_t, len,
+extern __typeof(recvfrom) __libc_recvfrom;
+#ifdef __NR_recvfrom
+#define __NR___libc_recvfrom __NR_recvfrom
+_syscall6(ssize_t, __libc_recvfrom, int, sockfd, __ptr_t, buffer, size_t, len,
        int, flags, struct sockaddr *, to, socklen_t *, tolen)
-# elif defined(__NR_socketcall)
+#elif defined(__NR_socketcall)
 /* recv, recvfrom added by bir7@leland.stanford.edu */
-ssize_t recvfrom(int sockfd, __ptr_t buffer, size_t len, int flags,
+ssize_t __libc_recvfrom(int sockfd, __ptr_t buffer, size_t len, int flags,
                 struct sockaddr *to, socklen_t * tolen)
 {
        unsigned long args[6];
@@ -210,45 +240,59 @@ ssize_t recvfrom(int sockfd, __ptr_t buffer, size_t len, int flags,
        args[3] = flags;
        args[4] = (unsigned long) to;
        args[5] = (unsigned long) tolen;
-       return (__socketcall(SYS_RECVFROM, args));
+
+       if (SINGLE_THREAD_P)
+               return (__socketcall(SYS_RECVFROM, args));
+
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+       int oldtype = LIBC_CANCEL_ASYNC ();
+       int result = __socketcall(SYS_RECVFROM, args);
+       LIBC_CANCEL_RESET (oldtype);
+       return result;
+#endif
 }
-# endif
-# ifndef __LINUXTHREADS_OLD__
-libc_hidden_def(recvfrom)
-# else
+#endif
+weak_alias(__libc_recvfrom,recvfrom)
 libc_hidden_weak(recvfrom)
-strong_alias(recvfrom,__libc_recvfrom)
-# endif
 #endif
 
 #ifdef L_recvmsg
-# ifdef __NR_recvmsg
-_syscall3(ssize_t, recvmsg, int, sockfd, struct msghdr *, msg, int, flags)
-# elif defined(__NR_socketcall)
-ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags)
+extern __typeof(recvmsg) __libc_recvmsg;
+#ifdef __NR_recvmsg
+#define __NR___libc_recvmsg __NR_recvmsg
+_syscall3(ssize_t, __libc_recvmsg, int, sockfd, struct msghdr *, msg, int, flags)
+#elif defined(__NR_socketcall)
+ssize_t __libc_recvmsg(int sockfd, struct msghdr *msg, int flags)
 {
        unsigned long args[3];
 
        args[0] = sockfd;
        args[1] = (unsigned long) msg;
        args[2] = flags;
-       return (__socketcall(SYS_RECVMSG, args));
+
+       if (SINGLE_THREAD_P)
+               return (__socketcall(SYS_RECVMSG, args));
+
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+       int oldtype = LIBC_CANCEL_ASYNC ();
+       int result = __socketcall(SYS_RECVMSG, args);
+       LIBC_CANCEL_RESET (oldtype);
+       return result;
+#endif
 }
-# endif
-# ifndef __LINUXTHREADS_OLD__
-libc_hidden_def(recvmsg)
-# else
+#endif
+weak_alias(__libc_recvmsg,recvmsg)
 libc_hidden_weak(recvmsg)
-strong_alias(recvmsg,__libc_recvmsg)
-# endif
 #endif
 
 #ifdef L_send
-# ifdef __NR_send
-_syscall4(ssize_t, send, int, sockfd, const void *, buffer, size_t, len, int, flags)
-# elif defined(__NR_socketcall)
+extern __typeof(send) __libc_send;
+#ifdef __NR_send
+#define __NR___libc_send    __NR_send
+_syscall4(ssize_t, __libc_send, int, sockfd, const void *, buffer, size_t, len, int, flags)
+#elif defined(__NR_socketcall)
 /* send, sendto added by bir7@leland.stanford.edu */
-ssize_t send(int sockfd, const void *buffer, size_t len, int flags)
+ssize_t __libc_send(int sockfd, const void *buffer, size_t len, int flags)
 {
        unsigned long args[4];
 
@@ -256,51 +300,65 @@ ssize_t send(int sockfd, const void *buffer, size_t len, int flags)
        args[1] = (unsigned long) buffer;
        args[2] = len;
        args[3] = flags;
-       return (__socketcall(SYS_SEND, args));
+
+       if (SINGLE_THREAD_P)
+               return (__socketcall(SYS_SEND, args));
+
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+       int oldtype = LIBC_CANCEL_ASYNC ();
+       int result = __socketcall(SYS_SEND, args);
+       LIBC_CANCEL_RESET (oldtype);
+       return result;
+#endif
 }
-# elif defined(__NR_sendto)
-ssize_t send(int sockfd, const void *buffer, size_t len, int flags)
+#elif defined(__NR_sendto)
+ssize_t __libc_send(int sockfd, const void *buffer, size_t len, int flags)
 {
        return (sendto(sockfd, buffer, len, flags, NULL, 0));
 }
-# endif
-# ifndef __LINUXTHREADS_OLD__
-libc_hidden_def(send)
-# else
+#endif
+weak_alias(__libc_send,send)
 libc_hidden_weak(send)
-strong_alias(send,__libc_send)
-# endif
 #endif
 
 #ifdef L_sendmsg
-# ifdef __NR_sendmsg
-_syscall3(ssize_t, sendmsg, int, sockfd, const struct msghdr *, msg, int, flags)
-# elif defined(__NR_socketcall)
-ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags)
+extern __typeof(sendmsg) __libc_sendmsg;
+#ifdef __NR_sendmsg
+#define __NR___libc_sendmsg __NR_sendmsg
+_syscall3(ssize_t, __libc_sendmsg, int, sockfd, const struct msghdr *, msg, int, flags)
+#elif defined(__NR_socketcall)
+ssize_t __libc_sendmsg(int sockfd, const struct msghdr *msg, int flags)
 {
        unsigned long args[3];
 
        args[0] = sockfd;
        args[1] = (unsigned long) msg;
        args[2] = flags;
-       return (__socketcall(SYS_SENDMSG, args));
+
+       if (SINGLE_THREAD_P)
+               return (__socketcall(SYS_SENDMSG, args));
+
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+       int oldtype = LIBC_CANCEL_ASYNC ();
+       int result = __socketcall(SYS_SENDMSG, args);
+       LIBC_CANCEL_RESET (oldtype);
+       return result;
+#endif
 }
-# endif
-# ifndef __LINUXTHREADS_OLD__
-libc_hidden_def(sendmsg)
-# else
+#endif
+weak_alias(__libc_sendmsg,sendmsg)
 libc_hidden_weak(sendmsg)
-strong_alias(sendmsg,__libc_sendmsg)
-# endif
 #endif
 
 #ifdef L_sendto
-# ifdef __NR_sendto
-_syscall6(ssize_t, sendto, int, sockfd, const void *, buffer,
+extern __typeof(sendto) __libc_sendto;
+#ifdef __NR_sendto
+#define __NR___libc_sendto  __NR_sendto
+_syscall6(ssize_t, __libc_sendto, int, sockfd, const void *, buffer,
        size_t, len, int, flags, const struct sockaddr *, to, socklen_t, tolen)
-# elif defined(__NR_socketcall)
+#elif defined(__NR_socketcall)
 /* send, sendto added by bir7@leland.stanford.edu */
-ssize_t sendto(int sockfd, const void *buffer, size_t len, int flags,
+ssize_t __libc_sendto(int sockfd, const void *buffer, size_t len, int flags,
           const struct sockaddr *to, socklen_t tolen)
 {
        unsigned long args[6];
@@ -311,15 +369,20 @@ ssize_t sendto(int sockfd, const void *buffer, size_t len, int flags,
        args[3] = flags;
        args[4] = (unsigned long) to;
        args[5] = tolen;
-       return (__socketcall(SYS_SENDTO, args));
+
+       if (SINGLE_THREAD_P)
+               return (__socketcall(SYS_SENDTO, args));
+
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+       int oldtype = LIBC_CANCEL_ASYNC ();
+       int result = __socketcall(SYS_SENDTO, args);
+       LIBC_CANCEL_RESET (oldtype);
+       return result;
+#endif
 }
-# endif
-# ifndef __LINUXTHREADS_OLD__
-libc_hidden_def(sendto)
-# else
+#endif
+weak_alias(__libc_sendto,sendto)
 libc_hidden_weak(sendto)
-strong_alias(sendto,__libc_sendto)
-# endif
 #endif
 
 #ifdef L_setsockopt
index 838081d..6c09d31 100644 (file)
@@ -21,6 +21,7 @@ include $(top_srcdir)libc/misc/gnu/Makefile.in
 include $(top_srcdir)libc/misc/internals/Makefile.in
 include $(top_srcdir)libc/misc/locale/Makefile.in
 include $(top_srcdir)libc/misc/mntent/Makefile.in
+include $(top_srcdir)libc/misc/pthread/Makefile.in
 include $(top_srcdir)libc/misc/regex/Makefile.in
 include $(top_srcdir)libc/misc/search/Makefile.in
 include $(top_srcdir)libc/misc/statfs/Makefile.in
index cca03b8..dfb53f8 100644 (file)
@@ -9,6 +9,7 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include "dirstream.h"
+#include <not-cancel.h>
 
 
 int closedir(DIR * dir)
@@ -31,6 +32,6 @@ int closedir(DIR * dir)
        __UCLIBC_MUTEX_UNLOCK(dir->dd_lock);
        free(dir->dd_buf);
        free(dir);
-       return close(fd);
+       return close_not_cancel(fd);
 }
 libc_hidden_def(closedir)
index b43f608..4a23ab0 100644 (file)
@@ -12,6 +12,7 @@
 #include <unistd.h>
 #include <sys/dir.h>
 #include <sys/stat.h>
+#include <not-cancel.h>
 #include <dirent.h>
 #include "dirstream.h"
 
@@ -81,7 +82,7 @@ DIR *opendir(const char *name)
        }
 # define O_DIRECTORY 0
 #endif
-       fd = open(name, O_RDONLY|O_NDELAY|O_DIRECTORY|O_CLOEXEC);
+       fd = open_not_cancel_2(name, O_RDONLY|O_NDELAY|O_DIRECTORY|O_CLOEXEC);
        if (fd < 0)
                return NULL;
        /* Note: we should check to make sure that between the stat() and open()
@@ -93,7 +94,7 @@ DIR *opendir(const char *name)
                /* this close() never fails
                 *int saved_errno;
                 *saved_errno = errno; */
-               close(fd);
+               close_not_cancel_no_status(fd);
                /*__set_errno(saved_errno);*/
                return NULL;
        }
@@ -102,12 +103,13 @@ DIR *opendir(const char *name)
         * exec. From "Anna Pluzhnikov" <besp@midway.uchicago.edu>.
         */
 #ifndef __ASSUME_O_CLOEXEC
-       fcntl(fd, F_SETFD, FD_CLOEXEC);
+       fcntl_not_cancel(fd, F_SETFD, FD_CLOEXEC);
 #endif
 
        ptr = fd_to_DIR(fd, statbuf.st_blksize);
+
        if (!ptr) {
-               close(fd);
+               close_not_cancel_no_status(fd);
                __set_errno(ENOMEM);
        }
        return ptr;
index 6e520fa..f7e45c6 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (C) Feb 2001 Manuel Novoa III
+ * Copyright (C) 2006 by Steven J. Hill <sjhill@realitydiluted.com>
+ * Copyright (C) 2001 by Manuel Novoa III <mjn3@uclibc.org>
  * Copyright (C) 2000-2005 Erik Andersen <andersen@uclibc.org>
  *
  * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
  * avoided in the static library case.
  */
 
-#define        _ERRNO_H
 #include <features.h>
+#ifndef __UCLIBC_HAS_THREADS_NATIVE__
+#define        _ERRNO_H
+#endif
 #include <unistd.h>
 #include <stdlib.h>
 #include <string.h>
 #include <link.h>
 #include <bits/uClibc_page.h>
 #include <paths.h>
+#include <unistd.h>
 #include <asm/errno.h>
 #include <fcntl.h>
 #include <sys/stat.h>
 #include <sys/sysmacros.h>
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include <errno.h>
+#include <pthread-functions.h>
+#include <not-cancel.h>
+#include <atomic.h>
+#endif
 
 
 #ifndef SHARED
@@ -64,16 +74,17 @@ void internal_function _dl_aux_init (ElfW(auxv_t) *av);
  * Prototypes.
  */
 extern int *weak_const_function __errno_location(void);
-libc_hidden_proto(__errno_location)
 extern int *weak_const_function __h_errno_location(void);
-libc_hidden_proto(__h_errno_location)
-
 extern void weak_function _stdio_init(void) attribute_hidden;
 #ifdef __UCLIBC_HAS_LOCALE__
 extern void weak_function _locale_init(void) attribute_hidden;
 #endif
 #ifdef __UCLIBC_HAS_THREADS__
+#if !defined (__UCLIBC_HAS_THREADS_NATIVE__) || defined (SHARED)
 extern void weak_function __pthread_initialize_minimal(void);
+#else
+extern void __pthread_initialize_minimal(void);
+#endif
 #endif
 
 /* If __UCLIBC_FORMAT_SHARED_FLAT__, all array initialisation and finalisation
@@ -126,7 +137,7 @@ static void __check_one_fd(int fd, int mode)
        int nullfd = open(_PATH_DEVNULL, mode);
        /* /dev/null is major=1 minor=3.  Make absolutely certain
         * that is in fact the device that we have opened and not
-        * some other weird file... [removed in uclibc] */
+        * some other wierd file... [removed in uclibc] */
        if (nullfd!=fd)
        {
                abort();
@@ -181,17 +192,20 @@ void __uClibc_init(void)
      * __pthread_initialize_minimal so we can use pthread_locks
      * whenever they are needed.
      */
+#if !defined (__UCLIBC_HAS_THREADS_NATIVE__) || defined (SHARED)
     if (likely(__pthread_initialize_minimal!=NULL))
+#endif
        __pthread_initialize_minimal();
 #endif
 
 #ifndef SHARED
 # ifdef __UCLIBC_HAS_SSP__
     /* Set up the stack checker's canary.  */
-    stack_chk_guard = _dl_setup_stack_chk_guard();
 #  ifdef THREAD_SET_STACK_GUARD
+    uintptr_t stack_chk_guard = _dl_setup_stack_chk_guard();
     THREAD_SET_STACK_GUARD (stack_chk_guard);
 #   ifdef __UCLIBC_HAS_SSP_COMPAT__
+    stack_chk_guard = _dl_setup_stack_chk_guard();
     __guard = stack_chk_guard;
 #   endif
 #  else
@@ -266,6 +280,11 @@ void __uClibc_main(int (*main)(int, char **, char **), int argc,
     ElfW(auxv_t) auxvt[AT_EGID + 1];
 #endif
 
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+       /* Result of the 'main' function.  */
+       int result;
+#endif
+
 #ifndef SHARED
     __libc_stack_end = stack_end;
 #endif
@@ -385,34 +404,57 @@ void __uClibc_main(int (*main)(int, char **, char **), int argc,
     if (likely(__h_errno_location!=NULL))
        *(__h_errno_location()) = 0;
 
-    /*
-     * Finally, invoke application's main and then exit.
-     */
-    exit(main(argc, argv, __environ));
-}
+#if defined HAVE_CLEANUP_JMP_BUF && defined __UCLIBC_HAS_THREADS_NATIVE__
+       /* Memory for the cancellation buffer.  */
+       struct pthread_unwind_buf unwind_buf;
 
-#if defined(__UCLIBC_HAS_THREADS__) && !defined(SHARED)
-/* Weaks for internal library use only.
- *
- * We need to define weaks here to cover all the pthread functions that
- * libc itself will use so that we aren't forced to link libc against
- * libpthread.  This file is only used in libc.a and since we have
- * weaks here, they will be automatically overridden by libpthread.a
- * if it gets linked in.
- */
+       int not_first_call;
+       not_first_call =
+               setjmp ((struct __jmp_buf_tag *) unwind_buf.cancel_jmp_buf);
+       if (__builtin_expect (! not_first_call, 1))
+       {
+               struct pthread *self = THREAD_SELF;
+
+               /* Store old info.  */
+               unwind_buf.priv.data.prev = THREAD_GETMEM (self, cleanup_jmp_buf);
+               unwind_buf.priv.data.cleanup = THREAD_GETMEM (self, cleanup);
+
+               /* Store the new cleanup handler info.  */
+               THREAD_SETMEM (self, cleanup_jmp_buf, &unwind_buf);
 
-static int __pthread_return_0 (void) { return 0; }
-static void __pthread_return_void (void) { return; }
-
-weak_alias (__pthread_return_0, __pthread_mutex_init)
-weak_alias (__pthread_return_0, __pthread_mutex_lock)
-weak_alias (__pthread_return_0, __pthread_mutex_trylock)
-weak_alias (__pthread_return_0, __pthread_mutex_unlock)
-weak_alias (__pthread_return_void, _pthread_cleanup_push_defer)
-weak_alias (__pthread_return_void, _pthread_cleanup_pop_restore)
-# ifdef __UCLIBC_HAS_THREADS_NATIVE__
-weak_alias (__pthread_return_0, __pthread_mutexattr_init)
-weak_alias (__pthread_return_0, __pthread_mutexattr_destroy)
-weak_alias (__pthread_return_0, __pthread_mutexattr_settype)
+               /* Run the program.  */
+               result = main (argc, argv, __environ);
+       }
+       else
+       {
+               /* Remove the thread-local data.  */
+# ifdef SHARED
+               __libc_pthread_functions.ptr__nptl_deallocate_tsd ();
+# else
+               extern void __nptl_deallocate_tsd (void) __attribute ((weak));
+               __nptl_deallocate_tsd ();
 # endif
+
+               /* One less thread.  Decrement the counter.  If it is zero we
+                  terminate the entire process.  */
+               result = 0;
+# ifdef SHARED
+               unsigned int *const ptr = __libc_pthread_functions.ptr_nthreads;
+# else
+               extern unsigned int __nptl_nthreads __attribute ((weak));
+               unsigned int *const ptr = &__nptl_nthreads;
+# endif
+
+               if (! atomic_decrement_and_test (ptr))
+                       /* Not much left to do but to exit the thread, not the process.  */
+                       __exit_thread_inline (0);
+       }
+
+       exit (result);
+#else
+       /*
+        * Finally, invoke application's main and then exit.
+        */
+       exit (main (argc, argv, __environ));
 #endif
+}
index cbd4ced..4145c94 100644 (file)
@@ -168,14 +168,14 @@ static void brain_damaged_fillrand(unsigned char *buf, unsigned int len)
 
    KIND may be one of:
    __GT_NOCREATE:       simply verify that the name does not exist
-                        at the time of the call.
+                        at the time of the call. mode argument is ignored.
    __GT_FILE:           create the file using open(O_CREAT|O_EXCL)
-                        and return a read-write fd.  The file is mode 0600.
+                        and return a read-write fd with given mode.
    __GT_BIGFILE:        same as __GT_FILE but use open64().
-   __GT_DIR:            create a directory, which will be mode 0700.
+   __GT_DIR:            create a directory with given mode.
 
 */
-int attribute_hidden __gen_tempname (char *tmpl, int kind)
+int __gen_tempname (char *tmpl, int kind, mode_t mode)
 {
     char *XXXXXX;
     unsigned int i;
@@ -217,15 +217,15 @@ int attribute_hidden __gen_tempname (char *tmpl, int kind)
                        fd = 0;
                }
            case __GT_FILE:
-               fd = open (tmpl, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
+               fd = open (tmpl, O_RDWR | O_CREAT | O_EXCL, mode);
                break;
 #if defined __UCLIBC_HAS_LFS__
            case __GT_BIGFILE:
-               fd = open64 (tmpl, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
+               fd = open64 (tmpl, O_RDWR | O_CREAT | O_EXCL, mode);
                break;
 #endif
            case __GT_DIR:
-               fd = mkdir (tmpl, S_IRUSR | S_IWUSR | S_IXUSR);
+               fd = mkdir (tmpl, mode);
                break;
            default:
                fd = -1;
index ac40bef..017dc51 100644 (file)
@@ -3,13 +3,14 @@
 
 #define        __need_size_t
 #include <stddef.h>
+#include <sys/types.h>
 
 /* Disable support for $TMPDIR */
 extern int ___path_search (char *tmpl, size_t tmpl_len, const char *dir,
                const char *pfx /*, int try_tmpdir */) attribute_hidden;
 #define __path_search(tmpl, tmpl_len, dir, pfx, try_tmpdir) ___path_search(tmpl, tmpl_len, dir, pfx)
 
-extern int __gen_tempname (char *__tmpl, int __kind) attribute_hidden;
+extern int __gen_tempname (char *__tmpl, int __kind, mode_t mode);
 
 /* The __kind argument to __gen_tempname may be one of: */
 #define __GT_FILE     0       /* create a file */
index 3616123..504aa25 100644 (file)
@@ -10,6 +10,7 @@ subdirs += libc/misc/pthread
 MISC_PTHREAD_DIR := $(top_srcdir)libc/misc/pthread
 MISC_PTHREAD_OUT := $(top_builddir)libc/misc/pthread
 
+libc-shared-$(UCLIBC_HAS_TLS) += $(MISC_PTHREAD_OUT)/tsd.os
 libc-$(UCLIBC_HAS_THREADS) += $(MISC_PTHREAD_OUT)/unlock.o
 libc-$(UCLIBC_HAS_THREADS) += $(MISC_PTHREAD_OUT)/weaks.o
 
diff --git a/libc/misc/pthread/tsd.c b/libc/misc/pthread/tsd.c
new file mode 100644 (file)
index 0000000..835ee22
--- /dev/null
@@ -0,0 +1,10 @@
+/* libpthread sets _dl_error_catch_tsd to point to this function.
+   We define it here instead of in libpthread so t here instead of in libpthread so that it doesn't
+   need to have a TLS segment of its own just for this one pointer.  */
+
+void ** __attribute__ ((const))
+__libc_dl_error_tsd (void)
+{
+  static __thread void *data __attribute__ ((tls_model ("initial-exec")));
+  return &data;
+}
index dac886f..27eb1ff 100644 (file)
@@ -1,6 +1,11 @@
 #include <errno.h>
 #include <sys/msg.h>
 #include "ipc.h"
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include "sysdep-cancel.h"
+#else
+#define SINGLE_THREAD_P 1
+#endif
 
 
 #ifdef L_msgctl
@@ -43,31 +48,65 @@ struct new_msg_buf{
 
 #ifdef L_msgrcv
 #ifdef __NR_msgrcv
-_syscall5(ssize_t, msgrcv, int, msqid, void *, msgp, size_t, msgsz, long int, msgtyp, int, msgflg)
-#else
-ssize_t msgrcv (int msqid, void *msgp, size_t msgsz,
-       long int msgtyp, int msgflg)
+#define __NR___syscall_msgrcv __NR_msgrcv
+static inline _syscall5(ssize_t, __syscall_msgrcv, int, msqid, void *, msgp,
+                       size_t, msgsz, long int, msgtyp, int, msgflg)
+#endif
+static inline ssize_t do_msgrcv (int msqid, void *msgp, size_t msgsz,
+                           long int msgtyp, int msgflg)
 {
+#ifdef __NR_msgrcv
+    return __syscall_msgrcv(msqid, msgp, msgsz, msgtyp, msgflg);
+#else
     struct new_msg_buf temp;
 
     temp.r_msgtyp = msgtyp;
     temp.oldmsg = msgp;
     return __syscall_ipc(IPCOP_msgrcv ,msqid ,msgsz ,msgflg ,&temp, 0);
+#endif
 }
+ssize_t msgrcv (int msqid, void *msgp, size_t msgsz,
+           long int msgtyp, int msgflg)
+{
+    if (SINGLE_THREAD_P)
+       return do_msgrcv(msqid, msgp, msgsz, msgtyp, msgflg);
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+    int oldtype = LIBC_CANCEL_ASYNC ();
+    int result = do_msgrcv(msqid, msgp, msgsz, msgtyp, msgflg);
+    LIBC_CANCEL_RESET (oldtype);
+    return result;
 #endif
+}
 #endif
 
 
 
 #ifdef L_msgsnd
 #ifdef __NR_msgsnd
-_syscall4(int, msgsnd, int, msqid, const void *, msgp, size_t, msgsz, int, msgflg)
-#else
+#define __NR___syscall_msgsnd __NR_msgsnd
+static inline _syscall4(int, __syscall_msgsnd, int, msqid, const void *, msgp,
+                       size_t, msgsz, int, msgflg)
+#endif
 /* Send message to message queue.  */
-int msgsnd (int msqid, const void *msgp, size_t msgsz, int msgflg)
+static inline int do_msgsnd (int msqid, const void *msgp, size_t msgsz,
+                           int msgflg)
 {
+#ifdef __NR_msgsnd
+    return __syscall_msgsnd(msqid, msgp, msgsz, msgflg);
+#else
     return __syscall_ipc(IPCOP_msgsnd, msqid, msgsz, msgflg, (void *)msgp, 0);
+#endif
 }
+int msgsnd (int msqid, const void *msgp, size_t msgsz, int msgflg)
+{
+    if (SINGLE_THREAD_P)
+       return do_msgsnd(msqid, msgp, msgsz, msgflg);
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+    int oldtype = LIBC_CANCEL_ASYNC ();
+    int result = do_msgsnd(msqid, msgp, msgsz, msgflg);
+    LIBC_CANCEL_RESET (oldtype);
+    return result;
 #endif
+}
 #endif
 
index c83f45e..a678130 100644 (file)
@@ -19,6 +19,7 @@
 #include <errno.h>
 #include <string.h>
 #include <utmp.h>
+#include <not-cancel.h>
 
 #include <bits/uClibc_mutex.h>
 __UCLIBC_MUTEX_STATIC(utmplock, PTHREAD_MUTEX_INITIALIZER);
@@ -46,16 +47,16 @@ static const char *static_ut_name = default_file_name;
 static_if_threaded void __setutent(void)
 {
     if (static_fd < 0) {
-       static_fd = open(static_ut_name, O_RDWR | O_CLOEXEC);
+       static_fd = open_not_cancel_2(static_ut_name, O_RDWR | O_CLOEXEC);
        if (static_fd < 0) {
-           static_fd = open(static_ut_name, O_RDONLY | O_CLOEXEC);
+           static_fd = open_not_cancel_2(static_ut_name, O_RDONLY | O_CLOEXEC);
            if (static_fd < 0) {
                return; /* static_fd remains < 0 */
            }
        }
 #ifndef __ASSUME_O_CLOEXEC
        /* Make sure the file will be closed on exec()  */
-       fcntl(static_fd, F_SETFD, FD_CLOEXEC);
+       fcntl_not_cancel(static_fd, F_SETFD, FD_CLOEXEC);
 #endif
        return;
     }
@@ -81,7 +82,7 @@ static_if_threaded struct utmp *__getutent(void)
        }
     }
 
-    if (read(static_fd, &static_utmp, sizeof(static_utmp)) == sizeof(static_utmp)) {
+    if (read_not_cancel(static_fd, &static_utmp, sizeof(static_utmp)) == sizeof(static_utmp)) {
        return &static_utmp;
     }
 
@@ -103,7 +104,7 @@ void endutent(void)
 {
     __UCLIBC_MUTEX_LOCK(utmplock);
     if (static_fd >= 0)
-       close(static_fd);
+       close_not_cancel_no_status(static_fd);
     static_fd = -1;
     __UCLIBC_MUTEX_UNLOCK(utmplock);
 }
@@ -193,7 +194,7 @@ int utmpname(const char *new_ut_name)
     }
 
     if (static_fd >= 0) {
-       close(static_fd);
+       close_not_cancel_no_status(static_fd);
        static_fd = -1;
     }
     __UCLIBC_MUTEX_UNLOCK(utmplock);
index e73d99f..5ab743d 100644 (file)
@@ -13,6 +13,7 @@
 #include <utmp.h>
 #include <fcntl.h>
 #include <sys/file.h>
+#include <not-cancel.h>
 
 #if 0
 /* This is enabled in uClibc/libutil/logwtmp.c */
@@ -36,12 +37,12 @@ void updwtmp(const char *wtmp_file, const struct utmp *lutmp)
 {
     int fd;
 
-    fd = open(wtmp_file, O_APPEND | O_WRONLY);
+    fd = open_not_cancel(wtmp_file, O_APPEND | O_WRONLY, 0);
     if (fd >= 0) {
        if (lockf(fd, F_LOCK, 0) == 0) {
-           write(fd, lutmp, sizeof(*lutmp));
+           write_not_cancel(fd, lutmp, sizeof(struct utmp));
            lockf(fd, F_ULOCK, 0);
-           close(fd);
+           close_not_cancel_no_status(fd);
        }
     }
 }
index 3d989c4..a7e3078 100644 (file)
@@ -16,6 +16,10 @@ CSRC-$(UCLIBC_HAS_OBSOLETE_BSD_SIGNAL) += \
 CSRC-$(UCLIBC_HAS_OBSOLETE_SYSV_SIGNAL) += sysv_signal.c
 CSRC-$(UCLIBC_SUSV4_LEGACY) += sigintr.c
 
+ifeq ($(UCLIBC_HAS_THREADS_NATIVE),y)
+CSRC-y:=$(filter-out raise.c sigaction.c,$(CSRC-y))
+endif
+
 ifneq ($(strip $(ARCH_OBJS)),)
 CSRC-y := $(filter-out $(notdir $(ARCH_OBJS:.o=.c)),$(CSRC-y))
 endif
index 5f7ed69..0856ba2 100644 (file)
@@ -23,6 +23,9 @@
 #define __FAVOR_BSD
 #include <signal.h>
 #include <stddef.h>            /* For NULL.  */
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include <sysdep-cancel.h>
+#endif
 
 #include "sigset-cvt-mask.h"
 
@@ -43,6 +46,9 @@ int __sigpause (int sig_or_mask, int is_sig)
   else
     sigset_set_old_mask (&set, sig_or_mask);
 
+  /* Note the sigpause() is a cancellation point.  But since we call
+     sigsuspend() which itself is a cancellation point we do not have
+     to do anything here.  */
   return sigsuspend (&set);
 }
 libc_hidden_def(__sigpause)
@@ -54,5 +60,18 @@ libc_hidden_def(__sigpause)
    the BSD version.  So make this the default.  */
 int sigpause (int mask)
 {
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+  if (SINGLE_THREAD_P)
+    return __sigpause (mask, 0);
+
+  int oldtype = LIBC_CANCEL_ASYNC ();
+
+  int result = __sigpause (mask, 0);
+
+  LIBC_CANCEL_RESET (oldtype);
+
+  return result;
+#else
   return __sigpause (mask, 0);
+#endif
 }
index d0421f3..8fd7ea8 100644 (file)
@@ -1,7 +1,8 @@
 /* vi: set sw=4 ts=4: */
 /* sigwait
  *
- * Copyright (C) 2003 by Erik Andersen <andersen@uclibc.org>
+ * Copyright (C) 2006 by Steven J. Hill <sjhill@realitydiluted.com>
+ * Copyright (C) 2003-2005 by Erik Andersen <andersen@uclibc.org>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
 #include <string.h>
 #include <unistd.h>
 
-#if defined __UCLIBC_HAS_REALTIME__
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+# include <sysdep-cancel.h>
 
-int sigwait(const sigset_t *set, int *sig)
+# ifdef __NR_rt_sigtimedwait
+
+/* Return any pending signal or wait for one for the given time.  */
+static int do_sigwait(const sigset_t *set, int *sig)
+{
+       int ret;
+
+#  ifdef SIGCANCEL
+       sigset_t tmpset;
+       if (set != NULL
+               && (__builtin_expect (__sigismember (set, SIGCANCEL), 0)
+#   ifdef SIGSETXID
+               || __builtin_expect (__sigismember (set, SIGSETXID), 0)
+#   endif
+               ))
+       {
+               /* Create a temporary mask without the bit for SIGCANCEL set.  */
+               // We are not copying more than we have to.
+               memcpy(&tmpset, set, _NSIG / 8);
+               __sigdelset(&tmpset, SIGCANCEL);
+#   ifdef SIGSETXID
+               __sigdelset(&tmpset, SIGSETXID);
+#   endif
+               set = &tmpset;
+       }
+#  endif
+
+       /* XXX The size argument hopefully will have to be changed to the
+          real size of the user-level sigset_t.  */
+       INTERNAL_SYSCALL_DECL(err);
+       do
+               ret = INTERNAL_SYSCALL (rt_sigtimedwait, err, 4, set, NULL,
+                       NULL, _NSIG / 8);
+       while (INTERNAL_SYSCALL_ERROR_P (ret, err)
+               && INTERNAL_SYSCALL_ERRNO (ret, err) == EINTR);
+       if (! INTERNAL_SYSCALL_ERROR_P (ret, err))
+       {
+               *sig = ret;
+               ret = 0;
+       }
+else
+       ret = INTERNAL_SYSCALL_ERRNO (ret, err);
+
+       return ret;
+}
+
+int sigwait (const sigset_t *set, int *sig)
+{
+       if(SINGLE_THREAD_P)
+               return do_sigwait(set, sig);
+
+       int oldtype = LIBC_CANCEL_ASYNC();
+
+       int result = do_sigwait(set, sig);
+
+       LIBC_CANCEL_RESET(oldtype);
+
+       return result;
+}
+# else /* __NR_rt_sigtimedwait */
+#  error We must have rt_sigtimedwait defined!!!
+# endif
+#else /* __UCLIBC_HAS_THREADS_NATIVE__ */
+
+# if defined __UCLIBC_HAS_REALTIME__
+
+int sigwait (const sigset_t *set, int *sig)
 {
-       int ret = sigwaitinfo(set, NULL);
-       if (ret != -1) {
+       int ret = 1;
+       if ((ret = sigwaitinfo(set, NULL)) != -1) {
                *sig = ret;
                return 0;
        }
        return 1;
 }
 
-#else /* __UCLIBC_HAS_REALTIME__ */
+# else /* __UCLIBC_HAS_REALTIME__ */
 /* variant without REALTIME extensions */
 
 static smallint was_sig; /* obviously not thread-safe */
@@ -95,4 +163,5 @@ int sigwait (const sigset_t *set, int *sig)
   *sig = was_sig;
   return was_sig == -1 ? -1 : 0;
 }
-#endif /* __UCLIBC_HAS_REALTIME__ */
+# endif /* __UCLIBC_HAS_REALTIME__ */
+#endif /* __UCLIBC_HAS_THREADS_NATIVE__ */
index 96377ee..2db27a8 100644 (file)
@@ -99,7 +99,7 @@ FILE attribute_hidden *_stdio_fopen(intptr_t fname_or_mode,
 #ifdef __UCLIBC_HAS_THREADS__
                /* We only initialize the mutex in the non-freopen case. */
                /* stream->__user_locking = _stdio_user_locking; */
-               __stdio_init_mutex(&stream->__lock);
+               STDIO_INIT_MUTEX(stream->__lock);
 #endif
        }
 
@@ -197,7 +197,7 @@ FILE attribute_hidden *_stdio_fopen(intptr_t fname_or_mode,
 #ifdef __UCLIBC_HAS_THREADS__
        /* Even in the freopen case, we reset the user locking flag. */
        stream->__user_locking = _stdio_user_locking;
-       /* __stdio_init_mutex(&stream->__lock); */
+       /* STDIO_INIT_MUTEX(stream->__lock); */
 #endif
 
 #ifdef __STDIO_HAS_OPENLIST
index 9143118..34c1c9a 100644 (file)
@@ -235,7 +235,7 @@ int vsscanf(__const char *sp, __const char *fmt, va_list ap)
 
 #ifdef __UCLIBC_HAS_THREADS__
        f.__user_locking = 1;           /* Set user locking. */
-       __stdio_init_mutex(&f.__lock);
+       STDIO_INIT_MUTEX(f.__lock);
 #endif
        f.__nextopen = NULL;
 
@@ -283,7 +283,7 @@ int vsscanf(__const char *sp, __const char *fmt, va_list ap)
 
 #ifdef __UCLIBC_HAS_THREADS__
        f.f.__user_locking = 1;         /* Set user locking. */
-       __stdio_init_mutex(&f.f.__lock);
+       STDIO_INIT_MUTEX(f.f.__lock);
 #endif
        f.f.__nextopen = NULL;
 
@@ -388,8 +388,10 @@ int vswscanf(const wchar_t * __restrict str, const wchar_t * __restrict format,
 {
        FILE f;
 
-       f.__bufstart = f.__bufpos = (unsigned char *) str;
-       f.__bufread = f.__bufend = (unsigned char *) (str + wcslen(str));
+       f.__bufstart =
+       f.__bufpos = (char *) str;
+       f.__bufread =
+       f.__bufend = (char *)(str + wcslen(str));
        __STDIO_STREAM_DISABLE_GETC(&f);
        __STDIO_STREAM_DISABLE_PUTC(&f);
 
@@ -414,7 +416,7 @@ int vswscanf(const wchar_t * __restrict str, const wchar_t * __restrict format,
 
 #ifdef __UCLIBC_HAS_THREADS__
        f.__user_locking = 1;           /* Set user locking. */
-       __stdio_init_mutex(&f.__lock);
+       STDIO_INIT_MUTEX(f.__lock);
 #endif
        f.__nextopen = NULL;
 
index 3c8d667..6c11451 100644 (file)
 #endif
 
 #ifdef __UCLIBC_HAS_THREADS__
+#ifdef __USE_STDIO_FUTEXES__
+#define __STDIO_FILE_INIT_THREADSAFE \
+       2, _LIBC_LOCK_RECURSIVE_INITIALIZER,
+#else
 #define __STDIO_FILE_INIT_THREADSAFE \
        2, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP,
+#endif
 #else
 #define __STDIO_FILE_INIT_THREADSAFE
 #endif
@@ -152,14 +157,13 @@ FILE *__stdout = _stdio_streams + 1; /* For putchar() macro. */
 FILE *_stdio_openlist = _stdio_streams;
 
 # ifdef __UCLIBC_HAS_THREADS__
-__UCLIBC_MUTEX_INIT(_stdio_openlist_add_lock, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP);
-#ifdef __STDIO_BUFFERS
-__UCLIBC_MUTEX_INIT(_stdio_openlist_del_lock, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP);
+__UCLIBC_IO_MUTEX_INIT(_stdio_openlist_add_lock);
+#  ifdef __STDIO_BUFFERS
+__UCLIBC_IO_MUTEX_INIT(_stdio_openlist_del_lock);
 volatile int _stdio_openlist_use_count = 0;
 int _stdio_openlist_del_count = 0;
-#endif
+#  endif
 # endif
-
 #endif
 /**********************************************************************/
 #ifdef __UCLIBC_HAS_THREADS__
@@ -167,6 +171,7 @@ int _stdio_openlist_del_count = 0;
 /* 2 if threading not initialized and 0 otherwise; */
 int _stdio_user_locking = 2;
 
+#ifndef __USE_STDIO_FUTEXES__
 void attribute_hidden __stdio_init_mutex(__UCLIBC_MUTEX_TYPE *m)
 {
        const __UCLIBC_MUTEX_STATIC(__stdio_mutex_initializer,
@@ -174,6 +179,7 @@ void attribute_hidden __stdio_init_mutex(__UCLIBC_MUTEX_TYPE *m)
 
        memcpy(m, &__stdio_mutex_initializer, sizeof(__stdio_mutex_initializer));
 }
+#endif
 
 #endif
 /**********************************************************************/
@@ -189,10 +195,10 @@ void attribute_hidden _stdio_term(void)
         * locked, then I suppose there is a chance that a pointer in the
         * chain might be corrupt due to a partial store.
         */
-       __stdio_init_mutex(&_stdio_openlist_add_lock);
+       STDIO_INIT_MUTEX(_stdio_openlist_add_lock);
 #warning check
 #ifdef __STDIO_BUFFERS
-       __stdio_init_mutex(&_stdio_openlist_del_lock);
+       STDIO_INIT_MUTEX(_stdio_openlist_del_lock);
 #endif
 
        /* Next we need to worry about the streams themselves.  If a stream
@@ -214,7 +220,7 @@ void attribute_hidden _stdio_term(void)
                }
 
                ptr->__user_locking = 1; /* Set locking mode to "by caller". */
-               __stdio_init_mutex(&ptr->__lock); /* Shouldn't be necessary, but... */
+               STDIO_INIT_MUTEX(ptr->__lock); /* Shouldn't be necessary, but... */
        }
 #endif
 
index aaa3ad6..ec98f9e 100644 (file)
 #include <bits/uClibc_mutex.h>
 
 #define __STDIO_THREADLOCK_OPENLIST_ADD                        \
-        __UCLIBC_MUTEX_LOCK(_stdio_openlist_add_lock)
+        __UCLIBC_IO_MUTEX_LOCK(_stdio_openlist_add_lock)
 
 #define __STDIO_THREADUNLOCK_OPENLIST_ADD              \
-        __UCLIBC_MUTEX_UNLOCK(_stdio_openlist_add_lock)
+        __UCLIBC_IO_MUTEX_UNLOCK(_stdio_openlist_add_lock)
 
 #ifdef __STDIO_BUFFERS
 
 #define __STDIO_THREADLOCK_OPENLIST_DEL                        \
-        __UCLIBC_MUTEX_LOCK(_stdio_openlist_del_lock)
+        __UCLIBC_IO_MUTEX_LOCK(_stdio_openlist_del_lock)
 
 #define __STDIO_THREADUNLOCK_OPENLIST_DEL              \
-        __UCLIBC_MUTEX_UNLOCK(_stdio_openlist_del_lock)
+        __UCLIBC_IO_MUTEX_UNLOCK(_stdio_openlist_del_lock)
 
 
 #ifdef __UCLIBC_HAS_THREADS__
index 8b918d6..d9104a4 100644 (file)
  * when all (lbf) writing streams are flushed. */
 
 #define __MY_STDIO_THREADLOCK(__stream)                                        \
-        __UCLIBC_MUTEX_CONDITIONAL_LOCK((__stream)->__lock,            \
+        __UCLIBC_IO_MUTEX_CONDITIONAL_LOCK((__stream)->__lock,         \
        (_stdio_user_locking != 2))
 
 #define __MY_STDIO_THREADUNLOCK(__stream)                              \
-        __UCLIBC_MUTEX_CONDITIONAL_UNLOCK((__stream)->__lock,          \
+        __UCLIBC_IO_MUTEX_CONDITIONAL_UNLOCK((__stream)->__lock,               \
        (_stdio_user_locking != 2))
 
 #if defined(__UCLIBC_HAS_THREADS__) && defined(__STDIO_BUFFERS)
index faf7c5e..66c905d 100644 (file)
@@ -36,7 +36,7 @@ tempnam (const char *dir, const char *pfx)
   if (__path_search (buf, FILENAME_MAX, dir, pfx, 1))
     return NULL;
 
-  if (__gen_tempname (buf, __GT_NOCREATE))
+  if (__gen_tempname (buf, __GT_NOCREATE, 0))
     return NULL;
 
   return strdup (buf);
index 2f973c3..c6b2dc8 100644 (file)
 
 #include <features.h>
 #include <stdio.h>
+#include <sys/stat.h>
 #include <unistd.h>
 #include "../misc/internals/tempname.h"
+#include <not-cancel.h>
 
 
 /* This returns a new stream opened on a temporary file (generated
@@ -34,7 +36,7 @@ FILE * tmpfile (void)
 
     if (__path_search (buf, FILENAME_MAX, NULL, "tmpf", 0))
        return NULL;
-    fd = __gen_tempname (buf, __GT_FILE);
+    fd = __gen_tempname (buf, __GT_FILE, S_IRUSR | S_IWUSR);
     if (fd < 0)
        return NULL;
 
@@ -43,7 +45,7 @@ FILE * tmpfile (void)
     (void) remove (buf);
 
     if ((f = fdopen (fd, "w+b")) == NULL)
-       close (fd);
+       close_not_cancel (fd);
 
     return f;
 }
index 1f180e0..323105b 100644 (file)
@@ -41,7 +41,7 @@ tmpnam (char *s)
                        0))
     return NULL;
 
-  if (__builtin_expect (__gen_tempname (tmpbuf, __GT_NOCREATE), 0))
+  if (__builtin_expect (__gen_tempname (tmpbuf, __GT_NOCREATE, 0), 0))
     return NULL;
 
   if (s == NULL)
index eec589e..8f616b2 100644 (file)
@@ -28,7 +28,7 @@ char * tmpnam_r (char *s)
 
     if (__path_search (s, L_tmpnam, NULL, NULL, 0))
        return NULL;
-    if (__gen_tempname (s, __GT_NOCREATE))
+    if (__gen_tempname (s, __GT_NOCREATE, 0))
        return NULL;
 
     return s;
index e3405e4..457018b 100644 (file)
@@ -49,7 +49,7 @@ int vdprintf(int filedes, const char * __restrict format, va_list arg)
  * only because of fflush_unlocked. TODO? */
 #if (defined(__STDIO_BUFFERS) || defined(__USE_OLD_VFPRINTF__)) && defined(__UCLIBC_HAS_THREADS__)
        f.__user_locking = 1;           /* Set user locking. */
-       __stdio_init_mutex(&f.__lock);
+       STDIO_INIT_MUTEX(f.__lock);
 #endif
        f.__nextopen = NULL;
 
index 07cff34..31adc52 100644 (file)
@@ -43,7 +43,7 @@ int vsnprintf(char *__restrict buf, size_t size,
 
 #if (defined(__STDIO_BUFFERS) || defined(__USE_OLD_VFPRINTF__)) && defined(__UCLIBC_HAS_THREADS__)
        f.__user_locking = 1;           /* Set user locking. */
-       __stdio_init_mutex(&f.__lock);
+       STDIO_INIT_MUTEX(f.__lock);
 #endif
        f.__nextopen = NULL;
 
@@ -117,7 +117,7 @@ int vsnprintf(char *__restrict buf, size_t size,
 
 #ifdef __UCLIBC_HAS_THREADS__
        f.f.__user_locking = 1;         /* Set user locking. */
-       __stdio_init_mutex(&f.f.__lock);
+       STDIO_INIT_MUTEX(f.f.__lock);
 #endif
        f.f.__nextopen = NULL;
 
index 8317a81..0f174ee 100644 (file)
@@ -13,7 +13,7 @@ include $(top_srcdir)libc/stdlib/malloc-standard/Makefile.in
 
 CSRC-y := \
        abort.c getenv.c mkdtemp.c realpath.c mkstemp.c \
-       rand.c random.c random_r.c setenv.c system.c div.c ldiv.c lldiv.c \
+       rand.c random.c random_r.c setenv.c div.c ldiv.c lldiv.c \
        getpt.c drand48-iter.c jrand48.c \
        jrand48_r.c lrand48.c lrand48_r.c mrand48.c mrand48_r.c nrand48.c \
        nrand48_r.c rand_r.c srand48.c srand48_r.c seed48.c seed48_r.c \
@@ -65,7 +65,9 @@ STDLIB_SRC := $(patsubst %.c,$(STDLIB_DIR)/%.c,$(CSRC-y))
 STDLIB_OBJ := $(patsubst %.c,$(STDLIB_OUT)/%.o,$(CSRC-y))
 
 libc-y += $(STDLIB_OBJ)
-libc-static-y += $(STDLIB_OUT)/atexit.o
+libc-static-y += $(STDLIB_OUT)/atexit.o $(STDLIB_OUT)/system.o
+libc-shared-y += $(STDLIB_OUT)/system.oS
+
 # this should always be the PIC version, because it could be used in shared libs
 libc-nonshared-y += $(STDLIB_OUT)/atexit.os
 
index fa9ae3b..2bf15ae 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <sys/stat.h>
 #include "../misc/internals/tempname.h"
 
 #ifdef __USE_BSD
@@ -29,7 +30,7 @@
    (This function comes from OpenBSD.) */
 char * mkdtemp (char *template)
 {
-  if (__gen_tempname (template, __GT_DIR))
+  if (__gen_tempname (template, __GT_DIR, S_IRUSR | S_IWUSR | S_IXUSR))
     return NULL;
   else
     return template;
index c569cea..ce7d7db 100644 (file)
@@ -18,6 +18,7 @@
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <sys/stat.h>
 #include "../misc/internals/tempname.h"
 
 /* Generate a unique temporary file name from TEMPLATE.
@@ -26,5 +27,5 @@
    Then open the file and return a fd. */
 int mkstemp (char *template)
 {
-    return __gen_tempname (template, __GT_FILE);
+    return __gen_tempname (template, __GT_FILE, S_IRUSR | S_IWUSR);
 }
index 02a03f0..2cdee70 100644 (file)
@@ -18,6 +18,7 @@
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <sys/stat.h>
 #include "../misc/internals/tempname.h"
 
 /* Generate a unique temporary file name from TEMPLATE.
@@ -26,5 +27,5 @@
    Then open the file and return a fd. */
 int mkstemp64 (char *template)
 {
-    return __gen_tempname (template, __GT_BIGFILE);
+    return __gen_tempname (template, __GT_BIGFILE, S_IRUSR | S_IWUSR);
 }
index f3af1c1..3c922e3 100644 (file)
@@ -25,7 +25,7 @@
  * they are replaced with a string that makes the filename unique.  */
 char *mktemp(char *template)
 {
-       if (__gen_tempname (template, __GT_NOCREATE) < 0)
+       if (__gen_tempname (template, __GT_NOCREATE, 0) < 0)
                /* We return the null string if we can't find a unique file name.  */
                template[0] = '\0';
 
index 99f7970..4f54d1d 100644 (file)
 #include <unistd.h>
 #include <sys/wait.h>
 #include <stdlib.h>
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include <sched.h>
+#include <errno.h>
+#include <bits/libc-lock.h>
+#include <sysdep-cancel.h>
+#endif
 
 
+/* TODO: the cancellable version breaks on sparc currently,
+ * need to figure out why still
+ */
+#if !defined __UCLIBC_HAS_THREADS_NATIVE__ || defined __sparc__
 /* uClinux-2.0 has vfork, but Linux 2.0 doesn't */
 #include <sys/syscall.h>
 #ifndef __NR_vfork
@@ -61,4 +71,198 @@ int __libc_system(const char *command)
        signal(SIGCHLD, save_chld);
        return wait_val;
 }
+#else
+/* We have to and actually can handle cancelable system().  The big
+   problem: we have to kill the child process if necessary.  To do
+   this a cleanup handler has to be registered and is has to be able
+   to find the PID of the child.  The main problem is to reliable have
+   the PID when needed.  It is not necessary for the parent thread to
+   return.  It might still be in the kernel when the cancellation
+   request comes.  Therefore we have to use the clone() calls ability
+   to have the kernel write the PID into the user-level variable.  */
+
+libc_hidden_proto(sigaction)
+libc_hidden_proto(waitpid)
+
+#if defined __ia64__
+# define FORK() \
+  INLINE_SYSCALL (clone2, 6, CLONE_PARENT_SETTID | SIGCHLD, NULL, 0, \
+                 &pid, NULL, NULL)
+#elif defined __sparc__
+# define FORK() \
+  INLINE_CLONE_SYSCALL (CLONE_PARENT_SETTID | SIGCHLD, 0, &pid, NULL, NULL)
+#elif defined __s390__
+# define FORK() \
+  INLINE_SYSCALL (clone, 3, 0, CLONE_PARENT_SETTID | SIGCHLD, &pid)
+#else
+# define FORK() \
+  INLINE_SYSCALL (clone, 3, CLONE_PARENT_SETTID | SIGCHLD, 0, &pid)
+#endif
+
+static void cancel_handler (void *arg);
+
+# define CLEANUP_HANDLER \
+  __libc_cleanup_region_start (1, cancel_handler, &pid)
+
+# define CLEANUP_RESET \
+  __libc_cleanup_region_end (0)
+
+static struct sigaction intr, quit;
+static int sa_refcntr;
+__libc_lock_define_initialized (static, lock);
+
+# define DO_LOCK() __libc_lock_lock (lock)
+# define DO_UNLOCK() __libc_lock_unlock (lock)
+# define INIT_LOCK() ({ __libc_lock_init (lock); sa_refcntr = 0; })
+# define ADD_REF() sa_refcntr++
+# define SUB_REF() --sa_refcntr
+
+/* Execute LINE as a shell command, returning its status.  */
+static int
+do_system (const char *line)
+{
+  int status, save;
+  pid_t pid;
+  struct sigaction sa;
+  sigset_t omask;
+
+  sa.sa_handler = SIG_IGN;
+  sa.sa_flags = 0;
+  __sigemptyset (&sa.sa_mask);
+
+  DO_LOCK ();
+  if (ADD_REF () == 0)
+    {
+      if (sigaction (SIGINT, &sa, &intr) < 0)
+       {
+         SUB_REF ();
+         goto out;
+       }
+      if (sigaction (SIGQUIT, &sa, &quit) < 0)
+       {
+         save = errno;
+         SUB_REF ();
+         goto out_restore_sigint;
+       }
+    }
+  DO_UNLOCK ();
+
+  /* We reuse the bitmap in the 'sa' structure.  */
+  __sigaddset (&sa.sa_mask, SIGCHLD);
+  save = errno;
+  if (sigprocmask (SIG_BLOCK, &sa.sa_mask, &omask) < 0)
+    {
+       {
+         DO_LOCK ();
+         if (SUB_REF () == 0)
+           {
+             save = errno;
+             (void) sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
+           out_restore_sigint:
+             (void) sigaction (SIGINT, &intr, (struct sigaction *) NULL);
+             __set_errno (save);
+           }
+       out:
+         DO_UNLOCK ();
+         return -1;
+       }
+    }
+
+  CLEANUP_HANDLER;
+
+  pid = FORK ();
+  if (pid == (pid_t) 0)
+    {
+      /* Child side.  */
+      const char *new_argv[4];
+      new_argv[0] = "/bin/sh";
+      new_argv[1] = "-c";
+      new_argv[2] = line;
+      new_argv[3] = NULL;
+
+      /* Restore the signals.  */
+      (void) sigaction (SIGINT, &intr, (struct sigaction *) NULL);
+      (void) sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
+      (void) sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL);
+      INIT_LOCK ();
+
+      /* Exec the shell.  */
+      (void) execve ("/bin/sh", (char *const *) new_argv, __environ);
+      _exit (127);
+    }
+  else if (pid < (pid_t) 0)
+    /* The fork failed.  */
+    status = -1;
+  else
+    /* Parent side.  */
+    {
+      /* Note the system() is a cancellation point.  But since we call
+        waitpid() which itself is a cancellation point we do not
+        have to do anything here.  */
+      if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid)
+       status = -1;
+    }
+
+  CLEANUP_RESET;
+
+  save = errno;
+  DO_LOCK ();
+  if ((SUB_REF () == 0
+       && (sigaction (SIGINT, &intr, (struct sigaction *) NULL)
+          | sigaction (SIGQUIT, &quit, (struct sigaction *) NULL)) != 0)
+      || sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL) != 0)
+    {
+       status = -1;
+    }
+  DO_UNLOCK ();
+
+  return status;
+}
+
+
+int
+__libc_system (const char *line)
+{
+  if (line == NULL)
+    /* Check that we have a command processor available.  It might
+       not be available after a chroot(), for example.  */
+    return do_system ("exit 0") == 0;
+
+  if (SINGLE_THREAD_P)
+    return do_system (line);
+
+  int oldtype = LIBC_CANCEL_ASYNC ();
+
+  int result = do_system (line);
+
+  LIBC_CANCEL_RESET (oldtype);
+
+  return result;
+}
+
+
+/* The cancellation handler.  */
+static void
+cancel_handler (void *arg)
+{
+  pid_t child = *(pid_t *) arg;
+
+  INTERNAL_SYSCALL_DECL (err);
+  INTERNAL_SYSCALL (kill, err, 2, child, SIGKILL);
+
+  TEMP_FAILURE_RETRY (waitpid (child, NULL, 0));
+
+  DO_LOCK ();
+
+  if (SUB_REF () == 0)
+    {
+      (void) sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
+      (void) sigaction (SIGINT, &intr, (struct sigaction *) NULL);
+    }
+
+  DO_UNLOCK ();
+}
+#endif
+#ifdef IS_IN_libc
 weak_alias(__libc_system,system)
+#endif
index 9be083d..e7f2ccd 100644 (file)
@@ -18,7 +18,10 @@ STRING_SUBARCH_OUT := $(top_builddir)libc/string/$(TARGET_ARCH)/$(TARGET_SUBARCH
 STRING_SUBARCH_SSRC := $(wildcard $(STRING_SUBARCH_OUT)/*.S)
 STRING_SUBARCH_SOBJ := $(patsubst $(STRING_SUBARCH_DIR)/%.S,$(STRING_SUBARCH_OUT)/%.o,$(STRING_SUBARCH_SSRC))
 
-STRING_SUBARCH_OBJS := $(STRING_SUBARCH_SOBJ)
+STRING_SUBARCH_CSRC := $(wildcard $(STRING_SUBARCH_OUT)/*.c)
+STRING_SUBARCH_COBJ := $(patsubst $(STRING_SUBARCH_DIR)/%.c,$(STRING_SUBARCH_OUT)/%.o,$(STRING_SUBARCH_CSRC))
+
+STRING_SUBARCH_OBJS := $(STRING_SUBARCH_SOBJ) $(STRING_SUBARCH_COBJ)
 endif
 
 # Collect the arch specific implementation (asm, c files)
diff --git a/libc/string/sh/memchr.S b/libc/string/sh/memchr.S
new file mode 100644 (file)
index 0000000..6b7142f
--- /dev/null
@@ -0,0 +1,30 @@
+/* $Id: memchr.S,v 1.1 2000/04/14 16:49:01 mjd Exp $
+ *
+ * "memchr" implementation of SuperH
+ *
+ * Copyright (C) 1999  Niibe Yutaka
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+/*
+ * void *memchr(const void *s, int c, size_t n);
+ */
+
+#include <sysdep.h>
+
+ENTRY(memchr)
+       tst     r6,r6
+       bt/s    2f
+        exts.b r5,r5
+1:     mov.b   @r4,r1
+       cmp/eq  r1,r5
+       bt/s    3f
+        dt     r6
+       bf/s    1b
+        add    #1,r4
+2:     mov     #0,r4
+3:     rts
+        mov    r4,r0
+END(memchr)
+libc_hidden_def (memchr)
diff --git a/libc/string/sh/sh4/memmove.c b/libc/string/sh/sh4/memmove.c
new file mode 100644 (file)
index 0000000..4d52db2
--- /dev/null
@@ -0,0 +1,117 @@
+/* memmove implementation for SH4
+ *
+ * Copyright (C) 2009 STMicroelectronics Ltd.
+ *
+ * Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#include <string.h>
+
+
+#define FPSCR_SR       (1 << 20)
+#define STORE_FPSCR(x) __asm__ volatile("sts fpscr, %0" : "=r"(x))
+#define LOAD_FPSCR(x)  __asm__ volatile("lds %0, fpscr" : : "r"(x))
+
+static void fpu_optimised_copy_fwd(void *dest, const void *src, size_t len)
+{
+       char *d = (char *)dest;
+       char *s = (char *)src;
+
+       if (len >= 64) {
+               unsigned long fpscr;
+               int *s1;
+               int *d1;
+
+               /* Align the dest to 4 byte boundary. */
+               while ((unsigned)d & 0x7) {
+                       *d++ = *s++;
+                       len--;
+               }
+
+               s1 = (int *)s;
+               d1 = (int *)d;
+
+               /* check if s is well aligned to use FPU */
+               if (!((unsigned)s1 & 0x7)) {
+
+                       /* Align the dest to cache-line boundary */
+                       while ((unsigned)d1 & 0x1c) {
+                               *d1++ = *s1++;
+                               len -= 4;
+                       }
+
+                       /* Use paired single precision load or store mode for
+                        * 64-bit tranfering.*/
+                       STORE_FPSCR(fpscr);
+                       LOAD_FPSCR(FPSCR_SR);
+
+                       while (len >= 32) {
+                               __asm__ volatile ("fmov @%0+,dr0":"+r" (s1));
+                               __asm__ volatile ("fmov @%0+,dr2":"+r" (s1));
+                               __asm__ volatile ("fmov @%0+,dr4":"+r" (s1));
+                               __asm__ volatile ("fmov @%0+,dr6":"+r" (s1));
+                               __asm__
+                                   volatile ("fmov dr0,@%0"::"r"
+                                             (d1):"memory");
+                               d1 += 2;
+                               __asm__
+                                   volatile ("fmov dr2,@%0"::"r"
+                                             (d1):"memory");
+                               d1 += 2;
+                               __asm__
+                                   volatile ("fmov dr4,@%0"::"r"
+                                             (d1):"memory");
+                               d1 += 2;
+                               __asm__
+                                   volatile ("fmov dr6,@%0"::"r"
+                                             (d1):"memory");
+                               d1 += 2;
+                               len -= 32;
+                       }
+                       LOAD_FPSCR(fpscr);
+               }
+               s = (char *)s1;
+               d = (char *)d1;
+               /*TODO: other subcases could be covered here?!?*/
+       }
+       /* Go to per-byte copy */
+       while (len > 0) {
+               *d++ = *s++;
+               len--;
+       }
+       return;
+}
+
+void *memmove(void *dest, const void *src, size_t len)
+{
+       unsigned long int d = (long int)dest;
+       unsigned long int s = (long int)src;
+       unsigned long int res;
+
+       if (d >= s)
+               res = d - s;
+       else
+               res = s - d;
+       /*
+        * 1) dest and src are not overlap  ==> memcpy (BWD/FDW)
+        * 2) dest and src are 100% overlap ==> memcpy (BWD/FDW)
+        * 3) left-to-right overlap ==>  Copy from the beginning to the end
+        * 4) right-to-left overlap ==>  Copy from the end to the beginning
+        */
+
+       if (res == 0)           /* 100% overlap */
+               memcpy(dest, src, len); /* No overlap */
+       else if (res >= len)
+               memcpy(dest, src, len);
+       else {
+               if (d > s)      /* right-to-left overlap */
+                       memcpy(dest, src, len); /* memcpy is BWD */
+               else            /* cannot use SH4 memcpy for this case */
+                       fpu_optimised_copy_fwd(dest, src, len);
+       }
+       return (dest);
+}
+
+libc_hidden_def(memmove)
diff --git a/libc/string/sh/sh4/memset.S b/libc/string/sh/sh4/memset.S
new file mode 100644 (file)
index 0000000..1a57cb9
--- /dev/null
@@ -0,0 +1,146 @@
+/* $Id: memset.S,v 1.1 2000/04/14 16:49:01 mjd Exp $
+ *
+ * "memset" implementation of SuperH
+ *
+ * Copyright (C) 1999  Niibe Yutaka
+ *
+ * Copyright (c) 2009  STMicroelectronics Ltd
+ *   Optimised using 64bit data transfer via FPU
+ *   Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+/*
+ *            void *memset(void *s, int c, size_t n);
+ */
+
+#include <sysdep.h>
+
+#ifdef __LITTLE_ENDIAN__
+#define MEMSET_USES_FPU
+/* Use paired single precision load or store mode for 64-bit tranfering.
+ * FPSCR.SZ=1,FPSCR.SZ=0 is well defined on both SH4-200 and SH4-300.
+ * Currenlty it has been only implemented and tested for little endian mode. */
+.macro FPU_SET_PAIRED_PREC
+       sts     fpscr, r3
+       mov     #0x10, r0       ! PR=0 SZ=1
+       shll16  r0
+       lds     r0, fpscr
+.endm
+.macro RESTORE_FPSCR
+       lds     r3, fpscr
+.endm
+#endif
+
+ENTRY(memset)
+       tst     r6,r6
+       bt/s    5f              ! if n=0, do nothing
+        add    r6,r4
+       mov     #12,r0
+       cmp/gt  r6,r0
+       bt/s    4f              ! if it's too small, set a byte at once
+        mov    r4,r0
+       and     #3,r0
+       cmp/eq  #0,r0
+       bt/s    2f              ! It's aligned
+        sub    r0,r6
+1:
+       dt      r0
+       bf/s    1b
+        mov.b  r5,@-r4
+2:                             ! make VVVV
+       extu.b  r5,r5
+       swap.b  r5,r0           !   V0
+       or      r0,r5           !   VV
+       swap.w  r5,r0           ! VV00
+       or      r0,r5           ! VVVV
+
+       ! Enough bytes need to be copied
+       mov     #0x40, r0       ! (MT)
+       cmp/gt  r6,r0           ! (MT)  64 > len => slow loop
+
+       bt/s    22f
+        mov    r6,r0
+
+       ! align the dst to the cache block size if necessary
+       mov     r4, r3
+       mov     #~(0x1f), r1
+
+       and     r3, r1
+       cmp/eq  r3, r1
+
+       bt/s    11f             ! dst is already aligned
+        sub    r1, r3          ! r3-r1 -> r3
+       shlr2   r3              ! number of loops
+
+10:    mov.l   r5,@-r4
+       dt      r3
+       bf/s    10b
+        add    #-4, r6
+
+11:    ! dst is 32byte aligned
+       mov     r6,r2
+       mov     #-5,r0
+       shld    r0,r2           ! number of loops
+
+#ifdef MEMSET_USES_FPU
+       lds     r5, fpul        ! (CO)
+       fsts    fpul, fr0       ! Dr0 will be 'VVVVVVVV'
+       fsts    fpul, fr1
+
+       FPU_SET_PAIRED_PREC
+12:
+       add     #-0x20, r6      !(MT)
+       fmov    dr0, @-r4
+       fmov    dr0, @-r4
+       fmov    dr0, @-r4
+       dt      r2
+       bf/s    12b             !(BR)
+        fmov   dr0, @-r4
+
+       RESTORE_FPSCR
+#else
+12:
+       mov.l   r5,@-r4
+       mov.l   r5,@-r4
+       mov.l   r5,@-r4
+       mov.l   r5,@-r4
+       mov.l   r5,@-r4
+       mov.l   r5,@-r4
+       add     #-0x20, r6
+       mov.l   r5,@-r4
+       dt      r2
+       bf/s    12b
+        mov.l  r5,@-r4
+#endif
+       tst     r6,r6
+       bt/s    5f
+        mov    #8, r0
+
+       cmp/ge  r0, r6
+       bf/s    4f
+        mov    r6,r0
+22:
+       shlr2   r0
+       shlr    r0              ! r0 = r6 >> 3
+3:
+       dt      r0
+       mov.l   r5,@-r4         ! set 8-byte at once
+       bf/s    3b
+        mov.l  r5,@-r4
+       !
+       mov     #7,r0
+       and     r0,r6
+       tst     r6,r6
+       bt      5f
+       ! fill bytes
+4:
+       dt      r6
+       bf/s    4b
+        mov.b  r5,@-r4
+5:
+       rts
+        mov    r4,r0
+END(memset)
+libc_hidden_def (memset)
diff --git a/libc/string/sh/sh4/strcpy.S b/libc/string/sh/sh4/strcpy.S
new file mode 100644 (file)
index 0000000..0f82780
--- /dev/null
@@ -0,0 +1,28 @@
+/* strcpy implementation for SUPERH
+ *
+ * Copyright (C) 2009 STMicroelectronics Ltd.
+ *
+ * Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+/*
+       char *strcpy(char *dest, const char *src);
+ */
+
+#include <sysdep.h>
+
+ENTRY(strcpy)
+       mov     r4,r2
+1:
+       mov.b   @r5+,r1
+       tst     r1,r1
+       mov.b   r1,@r2
+       bf/s    1b
+        add    #1,r2
+
+       rts
+        mov    r4,r0
+END(strcpy)
+libc_hidden_def (strcpy)
diff --git a/libc/string/sh/sh4/strncpy.S b/libc/string/sh/sh4/strncpy.S
new file mode 100644 (file)
index 0000000..8a16f39
--- /dev/null
@@ -0,0 +1,43 @@
+/* strncpy implementation for SUPERH
+ *
+ * Copyright (C) 2009 STMicroelectronics Ltd.
+ *
+ * Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+/*
+       char *strncpy(char *dest, const char *src, size_t n);
+ */
+
+#include <sysdep.h>
+
+ENTRY(strncpy)
+       mov     #0,r0
+       bra     2f
+        mov    r4,r2
+1:
+       mov.b   r1,@(r0,r2)
+       add     #1,r0
+2:
+       cmp/hs  r6,r0
+       bt      5f
+       mov.b   @(r0,r5),r1
+       tst     r1,r1
+       bf/s    1b
+        cmp/hs r6,r0
+       bra     4f
+        nop
+3:
+       mov.b   r1,@(r0,r2)
+       add     #1,r0
+       cmp/hs  r6,r0
+4:
+       bf/s    3b
+        mov    #0,r1
+5:
+       rts
+        mov     r2,r0
+END(strncpy)
+libc_hidden_def(strncpy)
diff --git a/libc/string/sh/strlen.S b/libc/string/sh/strlen.S
new file mode 100644 (file)
index 0000000..1ccecc1
--- /dev/null
@@ -0,0 +1,75 @@
+/* $Id: strlen.S,v 1.2 2001/06/29 14:07:15 gniibe Exp $
+ *
+ * "strlen" implementation of SuperH
+ *
+ * Copyright (C) 1999  Kaz Kojima
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+/* size_t strlen (const char *s)  */
+
+#include <sysdep.h>
+#include <endian.h>
+
+ENTRY(strlen)
+       mov     r4,r0
+       and     #3,r0
+       tst     r0,r0
+       bt/s    1f
+        mov    #0,r2
+
+       add     #-1,r0
+       shll2   r0
+       shll    r0
+       braf    r0
+        nop
+
+       mov.b   @r4+,r1
+       tst     r1,r1
+       bt      8f
+       add     #1,r2
+
+       mov.b   @r4+,r1
+       tst     r1,r1
+       bt      8f
+       add     #1,r2
+
+       mov.b   @r4+,r1
+       tst     r1,r1
+       bt      8f
+       add     #1,r2
+
+1:
+       mov     #0,r3
+2:
+       mov.l   @r4+,r1
+       cmp/str r3,r1
+       bf/s    2b
+        add    #4,r2
+
+       add     #-4,r2
+#ifndef __LITTLE_ENDIAN__
+       swap.b  r1,r1
+       swap.w  r1,r1
+       swap.b  r1,r1
+#endif
+       extu.b  r1,r0
+       tst     r0,r0
+       bt/s    8f
+        shlr8  r1
+       add     #1,r2
+       extu.b  r1,r0
+       tst     r0,r0
+       bt/s    8f
+        shlr8  r1
+       add     #1,r2
+       extu.b  r1,r0
+       tst     r0,r0
+       bt      8f
+       add     #1,r2
+8:
+       rts
+        mov    r2,r0
+END(strlen)
+libc_hidden_def (strlen)
index c3c5525..bec06ff 100644 (file)
@@ -5,14 +5,24 @@
 # Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
 #
 
-CSRC := brk.c ioperm.c iopl.c mmap.c sigaction.c __syscall_error.c
+CSRC := brk.c ioperm.c iopl.c mmap.c __syscall_error.c
+
+ifneq ($(UCLIBC_HAS_THREADS_NATIVE),y)
+CSRC += sigaction.c
+endif
 
 SSRC := \
-       __longjmp.S vfork.S clone.S setjmp.S bsd-setjmp.S \
+       __longjmp.S setjmp.S bsd-setjmp.S \
        bsd-_setjmp.S sigrestorer.S mmap64.S
 
+ifeq ($(UCLIBC_HAS_THREADS_NATIVE),y)
+SSRC += libc-aeabi_read_tp.S libc-thumb_atomics.S
+else
+SSRC += vfork.S clone.S
+endif
+
 ifeq ($(UCLIBC_HAS_ADVANCED_REALTIME),y)
-        CSRC += posix_fadvise.c posix_fadvise64.c
+CSRC += posix_fadvise.c posix_fadvise64.c
 endif
 
 ifeq ($(CONFIG_ARM_EABI),y)
index d948373..fdc05b8 100644 (file)
 /* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg); */
 
 .text
-.global clone
-.type clone,%function
+.global __clone
+.type __clone,%function
 .align 2
 #if defined(THUMB1_ONLY)
 .thumb_func
-clone:
+__clone:
        @ sanity check args
        cmp     r0, #0
        beq     __einval
@@ -52,9 +52,15 @@ clone:
        @ get flags
        mov     r0, r2
        @ new sp is already in r1
+       @ load remaining arguments off the stack
+       stmfd   sp!, {r4}
+       ldr     r2, [sp, #4]
+       ldr     r3, [sp, #8]
+       ldr     r4, [sp, #12]
        DO_CALL (clone)
        movs    a1, a1
        blt     __error
+       ldmnefd sp!, {r4}
        beq     1f
        bx      lr
 1:
@@ -80,7 +86,7 @@ __error:
        POP_RET
 .pool
 #else
-clone:
+__clone:
        @ sanity check args
        cmp     r0, #0
        IT(te, ne)
@@ -98,9 +104,15 @@ clone:
        @ get flags
        mov     r0, r2
        @ new sp is already in r1
+       @ load remaining arguments off the stack
+       stmfd   sp!, {r4}
+       ldr     r2, [sp, #4]
+       ldr     r3, [sp, #8]
+       ldr     r4, [sp, #12]
        DO_CALL (clone)
        movs    a1, a1
        blt     __error
+       ldmnefd sp!, {r4}
        IT(t, ne)
 #if defined(__USE_BX__)
        bxne    lr
@@ -120,6 +132,7 @@ __error:
        b       __syscall_error
 #endif
 
-.size clone,.-clone
+.size __clone,.-__clone
+weak_alias(__clone, clone)
 
 #endif
diff --git a/libc/sysdeps/linux/arm/libc-aeabi_read_tp.S b/libc/sysdeps/linux/arm/libc-aeabi_read_tp.S
new file mode 100644 (file)
index 0000000..3aa135b
--- /dev/null
@@ -0,0 +1 @@
+#include <ldso/ldso/arm/aeabi_read_tp.S>
diff --git a/libc/sysdeps/linux/arm/libc-thumb_atomics.S b/libc/sysdeps/linux/arm/libc-thumb_atomics.S
new file mode 100644 (file)
index 0000000..e7bc895
--- /dev/null
@@ -0,0 +1 @@
+#include <ldso/ldso/arm/thumb_atomics.S>
diff --git a/libc/sysdeps/linux/arm/sysdep.h b/libc/sysdeps/linux/arm/sysdep.h
new file mode 100644 (file)
index 0000000..b1ae2fd
--- /dev/null
@@ -0,0 +1,367 @@
+/* Assembler macros for ARM.
+   Copyright (C) 1997, 1998, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _LINUX_ARM_SYSDEP_H
+#define _LINUX_ARM_SYSDEP_H 1
+
+#include <common/sysdep.h>
+
+#include <sys/syscall.h>
+/* For Linux we can use the system call table in the header file
+       /usr/include/asm/unistd.h
+   of the kernel.  But these symbols do not follow the SYS_* syntax
+   so we have to redefine the `SYS_ify' macro here.  */
+#undef SYS_ify
+#define SWI_BASE  (0x900000)
+#define SYS_ify(syscall_name)  (__NR_##syscall_name)
+
+#ifdef __ASSEMBLER__
+
+/* Syntactic details of assembler.  */
+
+#define ALIGNARG(log2) log2
+/* For ELF we need the `.type' directive to make shared libs work right.  */
+#define ASM_TYPE_DIRECTIVE(name,typearg) .type name,%##typearg;
+#define ASM_SIZE_DIRECTIVE(name) .size name,.-name
+
+/* In ELF C symbols are asm symbols.  */
+#undef NO_UNDERSCORES
+#define NO_UNDERSCORES
+
+#define PLTJMP(_x)     _x##(PLT)
+
+/* APCS-32 doesn't preserve the condition codes across function call. */
+#ifdef __APCS_32__
+#define LOADREGS(cond, base, reglist...)\
+       ldm##cond       base,reglist
+#ifdef __USE_BX__
+#define RETINSTR(cond, reg)    \
+       bx##cond        reg
+#define DO_RET(_reg)           \
+       bx _reg
+#else
+#define RETINSTR(cond, reg)    \
+       mov##cond       pc, reg
+#define DO_RET(_reg)           \
+       mov pc, _reg
+#endif
+#else  /* APCS-26 */
+#define LOADREGS(cond, base, reglist...)       \
+       ldm##cond       base,reglist^
+#define RETINSTR(cond, reg)    \
+       mov##cond##s    pc, reg
+#define DO_RET(_reg)           \
+       movs pc, _reg
+#endif
+
+/* Define an entry point visible from C.  */
+#define        ENTRY(name)                                             \
+  ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(name);                    \
+  ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name),function)            \
+  .align ALIGNARG(4);                                          \
+  name##:                                                      \
+  CALL_MCOUNT
+
+#undef END
+#define END(name)                                              \
+  ASM_SIZE_DIRECTIVE(name)
+
+/* If compiled for profiling, call `mcount' at the start of each function.  */
+#ifdef PROF
+#define CALL_MCOUNT                    \
+       str     lr,[sp, #-4]!   ;       \
+       bl      PLTJMP(mcount)  ;       \
+       ldr     lr, [sp], #4    ;
+#else
+#define CALL_MCOUNT            /* Do nothing.  */
+#endif
+
+#ifdef NO_UNDERSCORES
+/* Since C identifiers are not normally prefixed with an underscore
+   on this system, the asm identifier `syscall_error' intrudes on the
+   C name space.  Make sure we use an innocuous name.  */
+#define        syscall_error   __syscall_error
+#define mcount         _mcount
+#endif
+/* Linux uses a negative return value to indicate syscall errors,
+   unlike most Unices, which use the condition codes' carry flag.
+
+   Since version 2.1 the return value of a system call might be
+   negative even if the call succeeded.  E.g., the `lseek' system call
+   might return a large offset.  Therefore we must not anymore test
+   for < 0, but test for a real error by making sure the value in R0
+   is a real error number.  Linus said he will make sure the no syscall
+   returns a value in -1 .. -4095 as a valid result so we can safely
+   test with -4095.  */
+
+#undef PSEUDO
+#define        PSEUDO(name, syscall_name, args)                                \
+  .text;                                                               \
+  ENTRY (name);                                                                \
+    DO_CALL (syscall_name, args);                                      \
+    cmn r0, $4096;
+
+#define PSEUDO_RET                                                     \
+    RETINSTR(cc, lr);                                                  \
+    b PLTJMP(SYSCALL_ERROR)
+#undef ret
+#define ret PSEUDO_RET
+
+#undef PSEUDO_END
+#define        PSEUDO_END(name)                                                \
+  SYSCALL_ERROR_HANDLER                                                        \
+  END (name)
+
+#undef PSEUDO_NOERRNO
+#define        PSEUDO_NOERRNO(name, syscall_name, args)                        \
+  .text;                                                               \
+  ENTRY (name);                                                                \
+    DO_CALL (syscall_name, args);
+
+#define PSEUDO_RET_NOERRNO                                             \
+    DO_RET (lr);
+
+#undef ret_NOERRNO
+#define ret_NOERRNO PSEUDO_RET_NOERRNO
+
+#undef PSEUDO_END_NOERRNO
+#define        PSEUDO_END_NOERRNO(name)                                        \
+  END (name)
+
+/* The function has to return the error code.  */
+#undef PSEUDO_ERRVAL
+#define        PSEUDO_ERRVAL(name, syscall_name, args) \
+  .text;                                                               \
+  ENTRY (name)                                                         \
+    DO_CALL (syscall_name, args);                                      \
+    rsb r0, r0, #0
+
+#undef PSEUDO_END_ERRVAL
+#define        PSEUDO_END_ERRVAL(name) \
+  END (name)
+
+#define ret_ERRVAL PSEUDO_RET_NOERRNO
+
+#if NOT_IN_libc
+# define SYSCALL_ERROR __local_syscall_error
+# ifdef RTLD_PRIVATE_ERRNO
+#  define SYSCALL_ERROR_HANDLER                                        \
+__local_syscall_error:                                         \
+       ldr     r1, 1f;                                         \
+       rsb     r0, r0, #0;                                     \
+0:     str     r0, [pc, r1];                                   \
+       mvn     r0, #0;                                         \
+       DO_RET(lr);                                             \
+1:     .word C_SYMBOL_NAME(rtld_errno) - 0b - 8;
+# else
+#  define SYSCALL_ERROR_HANDLER                                        \
+__local_syscall_error:                                         \
+       str     lr, [sp, #-4]!;                                 \
+       str     r0, [sp, #-4]!;                                 \
+       bl      PLTJMP(C_SYMBOL_NAME(__errno_location));        \
+       ldr     r1, [sp], #4;                                   \
+       rsb     r1, r1, #0;                                     \
+       str     r1, [r0];                                       \
+       mvn     r0, #0;                                         \
+       ldr     pc, [sp], #4;
+# endif
+#else
+# define SYSCALL_ERROR_HANDLER /* Nothing here; code in sysdep.S is used.  */
+# define SYSCALL_ERROR __syscall_error
+#endif
+
+/* Linux takes system call args in registers:
+       syscall number  in the SWI instruction
+       arg 1           r0
+       arg 2           r1
+       arg 3           r2
+       arg 4           r3
+       arg 5           r4      (this is different from the APCS convention)
+       arg 6           r5
+       arg 7           r6
+
+   The compiler is going to form a call by coming here, through PSEUDO, with
+   arguments
+       syscall number  in the DO_CALL macro
+       arg 1           r0
+       arg 2           r1
+       arg 3           r2
+       arg 4           r3
+       arg 5           [sp]
+       arg 6           [sp+4]
+       arg 7           [sp+8]
+
+   We need to shuffle values between R4..R6 and the stack so that the
+   caller's v1..v3 and stack frame are not corrupted, and the kernel
+   sees the right arguments.
+
+*/
+
+#undef DO_CALL
+#if defined(__ARM_EABI__)
+#define DO_CALL(syscall_name, args)            \
+    DOARGS_##args                              \
+    mov ip, r7;                                        \
+    ldr r7, =SYS_ify (syscall_name);           \
+    swi 0x0;                                   \
+    mov r7, ip;                                        \
+    UNDOARGS_##args
+#else
+#define DO_CALL(syscall_name, args)            \
+    DOARGS_##args                              \
+    swi SYS_ify (syscall_name);                \
+    UNDOARGS_##args
+#endif
+
+#define DOARGS_0 /* nothing */
+#define DOARGS_1 /* nothing */
+#define DOARGS_2 /* nothing */
+#define DOARGS_3 /* nothing */
+#define DOARGS_4 /* nothing */
+#define DOARGS_5 str r4, [sp, $-4]!; ldr r4, [sp, $4];
+#define DOARGS_6 mov ip, sp; stmfd sp!, {r4, r5}; ldmia ip, {r4, r5};
+#define DOARGS_7 mov ip, sp; stmfd sp!, {r4, r5, r6}; ldmia ip, {r4, r5, r6};
+
+#define UNDOARGS_0 /* nothing */
+#define UNDOARGS_1 /* nothing */
+#define UNDOARGS_2 /* nothing */
+#define UNDOARGS_3 /* nothing */
+#define UNDOARGS_4 /* nothing */
+#define UNDOARGS_5 ldr r4, [sp], $4;
+#define UNDOARGS_6 ldmfd sp!, {r4, r5};
+#define UNDOARGS_7 ldmfd sp!, {r4, r5, r6};
+
+#else /* not __ASSEMBLER__ */
+/* Define a macro which expands into the inline wrapper code for a system
+   call.  */
+#undef INLINE_SYSCALL
+#define INLINE_SYSCALL(name, nr, args...)                              \
+  ({ unsigned int _sys_result = INTERNAL_SYSCALL (name, , nr, args);   \
+     if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (_sys_result, ), 0))       \
+       {                                                               \
+        __set_errno (INTERNAL_SYSCALL_ERRNO (_sys_result, ));          \
+        _sys_result = (unsigned int) -1;                               \
+       }                                                               \
+     (int) _sys_result; })
+
+#undef INTERNAL_SYSCALL_DECL
+#define INTERNAL_SYSCALL_DECL(err) do { } while (0)
+
+#undef INTERNAL_SYSCALL_RAW
+#if defined(__thumb__)
+/* Hide the use of r7 from the compiler, this would be a lot
+ * easier but for the fact that the syscalls can exceed 255.
+ * For the moment the LOAD_ARG_7 is sacrificed.
+ * We can't use push/pop inside the asm because that breaks
+ * unwinding (ie. thread cancellation).
+ */
+#define INTERNAL_SYSCALL_RAW(name, err, nr, args...)           \
+  ({ unsigned int _sys_result;                                 \
+    {                                                          \
+      int _sys_buf[2];                                         \
+      register int _a1 __asm__ ("a1");                         \
+      register int *_v3 __asm__ ("v3") = _sys_buf;             \
+      LOAD_ARGS_##nr (args)                                    \
+      *_v3 = (int) (name);                                     \
+      __asm__ __volatile__ ("str       r7, [v3, #4]\n"         \
+                    "\tldr      r7, [v3]\n"                    \
+                    "\tswi      0       @ syscall " #name "\n" \
+                    "\tldr      r7, [v3, #4]"                  \
+                   : "=r" (_a1)                                        \
+                    : "r" (_v3) ASM_ARGS_##nr                  \
+                    : "memory");                               \
+      _sys_result = _a1;                                       \
+    }                                                          \
+    (int) _sys_result; })
+#elif defined(__ARM_EABI__)
+#define INTERNAL_SYSCALL_RAW(name, err, nr, args...)           \
+  ({unsigned int _sys_result;                                  \
+     {                                                         \
+       register int _a1 __asm__ ("r0"), _nr __asm__ ("r7");    \
+       LOAD_ARGS_##nr (args)                                   \
+       _nr = name;                                             \
+       __asm__ __volatile__ ("swi      0x0 @ syscall " #name   \
+                    : "=r" (_a1)                               \
+                    : "r" (_nr) ASM_ARGS_##nr                  \
+                    : "memory");                               \
+       _sys_result = _a1;                                      \
+     }                                                         \
+     (int) _sys_result; })
+#else /* !defined(__ARM_EABI__) */
+#define INTERNAL_SYSCALL_RAW(name, err, nr, args...)           \
+  ({ unsigned int _sys_result;                                 \
+     {                                                         \
+       register int _a1 __asm__ ("a1");                                \
+       LOAD_ARGS_##nr (args)                                   \
+       __asm__ __volatile__ ("swi      %1 @ syscall " #name    \
+                    : "=r" (_a1)                               \
+                    : "i" (name) ASM_ARGS_##nr                 \
+                    : "memory");                               \
+       _sys_result = _a1;                                      \
+     }                                                         \
+     (int) _sys_result; })
+#endif
+
+#undef INTERNAL_SYSCALL
+#define INTERNAL_SYSCALL(name, err, nr, args...)               \
+       INTERNAL_SYSCALL_RAW(SYS_ify(name), err, nr, args)
+
+#undef INTERNAL_SYSCALL_ARM
+#define INTERNAL_SYSCALL_ARM(name, err, nr, args...)           \
+       INTERNAL_SYSCALL_RAW(__ARM_NR_##name, err, nr, args)
+
+#undef INTERNAL_SYSCALL_ERROR_P
+#define INTERNAL_SYSCALL_ERROR_P(val, err) \
+  ((unsigned int) (val) >= 0xfffff001u)
+
+#undef INTERNAL_SYSCALL_ERRNO
+#define INTERNAL_SYSCALL_ERRNO(val, err)       (-(val))
+
+#if defined(__ARM_EABI__)
+#undef INTERNAL_SYSCALL_NCS
+#define INTERNAL_SYSCALL_NCS(number, err, nr, args...)         \
+       INTERNAL_SYSCALL_RAW(number, err, nr, args)
+#else
+/* We can't implement non-constant syscalls directly since the syscall
+   number is normally encoded in the instruction.  So use SYS_syscall.  */
+#undef INTERNAL_SYSCALL_NCS
+#define INTERNAL_SYSCALL_NCS(number, err, nr, args...)         \
+       INTERNAL_SYSCALL_NCS_##nr (number, err, args)
+
+#define INTERNAL_SYSCALL_NCS_0(number, err, args...)           \
+       INTERNAL_SYSCALL (syscall, err, 1, number, args)
+#define INTERNAL_SYSCALL_NCS_1(number, err, args...)           \
+       INTERNAL_SYSCALL (syscall, err, 2, number, args)
+#define INTERNAL_SYSCALL_NCS_2(number, err, args...)           \
+       INTERNAL_SYSCALL (syscall, err, 3, number, args)
+#define INTERNAL_SYSCALL_NCS_3(number, err, args...)           \
+       INTERNAL_SYSCALL (syscall, err, 4, number, args)
+#define INTERNAL_SYSCALL_NCS_4(number, err, args...)           \
+       INTERNAL_SYSCALL (syscall, err, 5, number, args)
+#define INTERNAL_SYSCALL_NCS_5(number, err, args...)           \
+       INTERNAL_SYSCALL (syscall, err, 6, number, args)
+#endif
+
+#endif /* __ASSEMBLER__ */
+
+/* Pointer mangling is not yet supported for ARM.  */
+#define PTR_MANGLE(var) (void) (var)
+#define PTR_DEMANGLE(var) (void) (var)
+
+#endif /* linux/arm/sysdep.h */
index 42595b0..17d6a4d 100644 (file)
 #include <bits/errno.h>
 #include <sys/syscall.h>
 
+#ifndef SAVE_PID
+#define SAVE_PID
+#endif
+
+#ifndef RESTORE_PID
+#define RESTORE_PID
+#endif
+
+
 #ifdef __NR_fork
 .text
 .global        __vfork
@@ -23,7 +32,9 @@
 .thumb_func
 __vfork:
 #ifdef __NR_vfork
+       SAVE_PID
        DO_CALL (vfork)
+       RESTORE_PID
        ldr             r1, =0xfffff000
        cmp             r0, r1
        bcs             1f
@@ -57,7 +68,9 @@ __error:
 __vfork:
 
 #ifdef __NR_vfork
+       SAVE_PID
        DO_CALL (vfork)
+       RESTORE_PID
        cmn     r0, #4096
        IT(t, cc)
 #if defined(__USE_BX__)
index 172feb1..a6fa6d0 100644 (file)
@@ -34,6 +34,17 @@ CSRC := $(filter-out capget.c capset.c inotify.c ioperm.c iopl.c madvise.c \
        sync_file_range.c sysctl.c sysinfo.c timerfd.c uselib.c vhangup.c,$(CSRC))
 endif
 
+ifeq ($(UCLIBC_HAS_THREADS_NATIVE),y)
+CSRC := $(filter-out fork.c getpid.c raise.c open.c close.c read.c write.c, $(CSRC))
+ifeq ($(TARGET_ARCH),arm)
+CSRC := $(filter-out vfork.c, $(CSRC))
+else ifeq ($(TARGET_ARCH),x86_64)
+CSRC := $(filter-out vfork.c, $(CSRC))
+else
+CSRC := $(filter-out waitpid.c, $(CSRC))
+endif
+endif
+
 ifneq ($(UCLIBC_BSD_SPECIFIC),y)
 # we need these internally: getdomainname.c
 CSRC := $(filter-out mincore.c setdomainname.c,$(CSRC))
@@ -75,6 +86,18 @@ ifneq ($(UCLIBC_SV4_DEPRECATED),y)
 CSRC := $(filter-out ustat.c,$(CSRC))
 endif
 
+ifeq ($(TARGET_ARCH),sh)
+CSRC := $(filter-out longjmp.c vfork.c,$(CSRC))
+endif
+
+ifeq ($(TARGET_ARCH),sparc)
+CSRC := $(filter-out vfork.c,$(CSRC))
+endif
+
+ifeq ($(TARGET_ARCH),i386)
+CSRC := $(filter-out vfork.c,$(CSRC))
+endif
+
 # fails for some reason
 ifneq ($(strip $(ARCH_OBJS)),)
 CSRC := $(filter-out $(notdir $(ARCH_OBJS:.o=.c)) $(ARCH_OBJ_FILTEROUT),$(CSRC))
index f9ec0ea..554c6b9 100644 (file)
@@ -2,44 +2,97 @@
 /*
  * __rt_sigtimedwait() for uClibc
  *
- * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ * Copyright (C) 2006 by Steven Hill <sjhill@realitydiluted.com>
+ * Copyright (C) 2000-2004 by Erik Andersen <andersen@codepoet.org>
  *
- * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ * GNU Library General Public License (LGPL) version 2 or later.
  */
 
 #include <sys/syscall.h>
 #include <signal.h>
-#define __need_NULL
-#include <stddef.h>
+#include <string.h>
 
+libc_hidden_proto(memcpy)
 
 #ifdef __NR_rt_sigtimedwait
-#define __NR___rt_sigtimedwait __NR_rt_sigtimedwait
-static _syscall4(int, __rt_sigtimedwait, const sigset_t *, set, siginfo_t *, info,
-                 const struct timespec *, timeout, size_t, setsize)
+#include <string.h>
+libc_hidden_proto(memcpy)
 
-int sigwaitinfo(const sigset_t * set, siginfo_t * info)
+# ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#  include <sysdep-cancel.h>
+
+static int do_sigtimedwait(const sigset_t *set, siginfo_t *info,
+                                                  const struct timespec *timeout)
 {
-       return __rt_sigtimedwait(set, info, NULL, _NSIG / 8);
+#  ifdef SIGCANCEL
+       sigset_t tmpset;
+
+       if (set != NULL && (__builtin_expect (__sigismember (set, SIGCANCEL), 0)
+#   ifdef SIGSETXID
+               || __builtin_expect (__sigismember (set, SIGSETXID), 0)
+#   endif
+               ))
+       {
+               /* Create a temporary mask without the bit for SIGCANCEL set.  */
+               // We are not copying more than we have to.
+               memcpy (&tmpset, set, _NSIG / 8);
+               __sigdelset (&tmpset, SIGCANCEL);
+#   ifdef SIGSETXID
+               __sigdelset (&tmpset, SIGSETXID);
+#   endif
+               set = &tmpset;
+       }
+#  endif
+
+       /* XXX The size argument hopefully will have to be changed to the
+          real size of the user-level sigset_t.  */
+       int result = INLINE_SYSCALL (rt_sigtimedwait, 4, set, info,
+                                                                timeout, _NSIG / 8);
+
+       /* The kernel generates a SI_TKILL code in si_code in case tkill is
+          used.  tkill is transparently used in raise().  Since having
+          SI_TKILL as a code is useful in general we fold the results
+          here.  */
+       if (result != -1 && info != NULL && info->si_code == SI_TKILL)
+               info->si_code = SI_USER;
+
+       return result;
 }
 
-int sigtimedwait(const sigset_t * set, siginfo_t * info,
-                                const struct timespec *timeout)
+/* Return any pending signal or wait for one for the given time.  */
+int __sigtimedwait(const sigset_t *set, siginfo_t *info,
+                                  const struct timespec *timeout)
 {
-       return __rt_sigtimedwait(set, info, timeout, _NSIG / 8);
+       if(SINGLE_THREAD_P)
+               return do_sigtimedwait(set, info, timeout);
+
+       int oldtype = LIBC_CANCEL_ASYNC();
+
+       /* XXX The size argument hopefully will have to be changed to the
+          real size of the user-level sigset_t.  */
+       int result = do_sigtimedwait(set, info, timeout);
+
+       LIBC_CANCEL_RESET(oldtype);
+
+       return result;
 }
-#else
-int sigwaitinfo(const sigset_t * set, siginfo_t * info)
+# else
+#  define __need_NULL
+#  include <stddef.h>
+#  define __NR___rt_sigtimedwait __NR_rt_sigtimedwait
+static _syscall4(int, __rt_sigtimedwait, const sigset_t *, set,
+                                siginfo_t *, info, const struct timespec *, timeout,
+                                size_t, setsize);
+
+int attribute_hidden __sigtimedwait(const sigset_t * set, siginfo_t * info,
+                                                                       const struct timespec *timeout)
 {
-       if (set == NULL)
-               __set_errno(EINVAL);
-       else
-               __set_errno(ENOSYS);
-       return -1;
+       return __rt_sigtimedwait(set, info, timeout, _NSIG / 8);
 }
-
-int sigtimedwait(const sigset_t * set, siginfo_t * info,
-                                const struct timespec *timeout)
+# endif /* !__UCLIBC_HAS_THREADS_NATIVE__ */
+#else
+int attribute_hidden __sigtimedwait(const sigset_t * set, siginfo_t * info,
+                                                                       const struct timespec *timeout)
 {
        if (set == NULL)
                __set_errno(EINVAL);
@@ -48,5 +101,4 @@ int sigtimedwait(const sigset_t * set, siginfo_t * info,
        return -1;
 }
 #endif
-libc_hidden_def(sigwaitinfo)
-libc_hidden_def(sigtimedwait)
+weak_alias(__sigtimedwait,sigtimedwait)
diff --git a/libc/sysdeps/linux/common/__rt_sigwaitinfo.c b/libc/sysdeps/linux/common/__rt_sigwaitinfo.c
new file mode 100644 (file)
index 0000000..c8953bf
--- /dev/null
@@ -0,0 +1,102 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * __rt_sigwaitinfo() for uClibc
+ *
+ * Copyright (C) 2006 by Steven Hill <sjhill@realitydiluted.com>
+ * Copyright (C) 2000-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * GNU Library General Public License (LGPL) version 2 or later.
+ */
+
+#include <sys/syscall.h>
+#include <signal.h>
+#include <string.h>
+
+libc_hidden_proto(memcpy)
+
+#ifdef __NR_rt_sigtimedwait
+
+#include <string.h>
+
+# ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#  include <sysdep-cancel.h>
+
+static int do_sigwaitinfo(const sigset_t *set, siginfo_t *info)
+{
+#  ifdef SIGCANCEL
+       sigset_t tmpset;
+
+       if (set != NULL && (__builtin_expect (__sigismember (set, SIGCANCEL), 0)
+#   ifdef SIGSETXID
+               || __builtin_expect (__sigismember (set, SIGSETXID), 0)
+#   endif
+               ))
+       {
+               /* Create a temporary mask without the bit for SIGCANCEL set.  */
+               // We are not copying more than we have to.
+               memcpy (&tmpset, set, _NSIG / 8);
+               __sigdelset (&tmpset, SIGCANCEL);
+#   ifdef SIGSETXID
+               __sigdelset (&tmpset, SIGSETXID);
+#   endif
+               set = &tmpset;
+       }
+#  endif
+
+       /* XXX The size argument hopefully will have to be changed to the
+          real size of the user-level sigset_t.  */
+       int result = INLINE_SYSCALL (rt_sigtimedwait, 4, set, info,
+                                                                NULL, _NSIG / 8);
+
+       /* The kernel generates a SI_TKILL code in si_code in case tkill is
+          used.  tkill is transparently used in raise().  Since having
+          SI_TKILL as a code is useful in general we fold the results
+          here.  */
+       if (result != -1 && info != NULL && info->si_code == SI_TKILL)
+               info->si_code = SI_USER;
+
+       return result;
+}
+
+/* Return any pending signal or wait for one for the given time.  */
+int __sigwaitinfo(const sigset_t *set, siginfo_t *info)
+{
+       if(SINGLE_THREAD_P)
+               return do_sigwaitinfo(set, info);
+
+       int oldtype = LIBC_CANCEL_ASYNC();
+
+       /* XXX The size argument hopefully will have to be changed to the
+          real size of the user-level sigset_t.  */
+       int result = do_sigwaitinfo(set, info);
+
+       LIBC_CANCEL_RESET(oldtype);
+
+       return result;
+}
+# else
+#  define __need_NULL
+#  include <stddef.h>
+#  define __NR___rt_sigwaitinfo __NR_rt_sigtimedwait
+static _syscall4(int, __rt_sigwaitinfo, const sigset_t *, set,
+                                siginfo_t *, info, const struct timespec *, timeout,
+                                size_t, setsize);
+
+int attribute_hidden __sigwaitinfo(const sigset_t * set, siginfo_t * info)
+{
+       return __rt_sigwaitinfo(set, info, NULL, _NSIG / 8);
+}
+# endif
+#else
+int attribute_hidden __sigwaitinfo(const sigset_t * set, siginfo_t * info)
+{
+       if (set == NULL)
+               __set_errno(EINVAL);
+       else
+               __set_errno(ENOSYS);
+       return -1;
+}
+#endif
+libc_hidden_proto(sigwaitinfo)
+weak_alias (__sigwaitinfo, sigwaitinfo)
+libc_hidden_weak(sigwaitinfo)
index 355b22b..4e3bc23 100644 (file)
@@ -2,6 +2,7 @@
 /*
  * __syscall_fcntl() for uClibc
  *
+ * Copyright (C) 2006 Steven J. Hill <sjhill@realitydiluted.com>
  * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
  *
  * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
 
 #include <sys/syscall.h>
 #include <stdarg.h>
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include <sysdep-cancel.h>     /* Must come before <fcntl.h>.  */
+#endif
 #include <fcntl.h>
 #include <bits/wordsize.h>
 
-#define __NR___syscall_fcntl __NR_fcntl
-static __always_inline
-_syscall3(int, __syscall_fcntl, int, fd, int, cmd, long, arg)
+extern __typeof(fcntl) __libc_fcntl;
+libc_hidden_proto(__libc_fcntl)
 
-int fcntl(int fd, int cmd, ...)
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+int __fcntl_nocancel (int fd, int cmd, ...)
 {
-       long arg;
-       va_list list;
+       va_list ap;
+       void *arg;
 
-       va_start(list, cmd);
-       arg = va_arg(list, long);
-       va_end(list);
+       va_start (ap, cmd);
+       arg = va_arg (ap, void *);
+       va_end (ap);
 
-#if __WORDSIZE == 32
+# if __WORDSIZE == 32
        if (cmd == F_GETLK64 || cmd == F_SETLK64 || cmd == F_SETLKW64) {
-#if defined __UCLIBC_HAS_LFS__ && defined __NR_fcntl64
-               return fcntl64(fd, cmd, arg);
-#else
+#  if defined __UCLIBC_HAS_LFS__ && defined __NR_fcntl64
+               return INLINE_SYSCALL (fcntl64, 3, fd, cmd, arg);
+#  else
                __set_errno(ENOSYS);
                return -1;
-#endif
+#  endif
        }
+# endif
+       return INLINE_SYSCALL (fcntl, 3, fd, cmd, arg);
+}
 #endif
 
-       return (__syscall_fcntl(fd, cmd, arg));
-}
-#ifndef __LINUXTHREADS_OLD__
-libc_hidden_def(fcntl)
+int __libc_fcntl (int fd, int cmd, ...)
+{
+       va_list ap;
+       void *arg;
+
+       va_start (ap, cmd);
+       arg = va_arg (ap, void *);
+       va_end (ap);
+
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+       if (SINGLE_THREAD_P || (cmd != F_SETLKW && cmd != F_SETLKW64))
+# if defined __UCLIBC_HAS_LFS__ && defined __NR_fcntl64
+               return INLINE_SYSCALL (fcntl64, 3, fd, cmd, arg);
+# else
+               return INLINE_SYSCALL (fcntl, 3, fd, cmd, arg);
+# endif
+
+       int oldtype = LIBC_CANCEL_ASYNC ();
+
+# if defined __UCLIBC_HAS_LFS__ && defined __NR_fcntl64
+       int result = INLINE_SYSCALL (fcntl64, 3, fd, cmd, arg);
+# else
+       int result = INLINE_SYSCALL (fcntl, 3, fd, cmd, arg);
+# endif
+
+       LIBC_CANCEL_RESET (oldtype);
+
+       return result;
 #else
-libc_hidden_weak(fcntl)
-strong_alias(fcntl,__libc_fcntl)
+# if __WORDSIZE == 32
+       if (cmd == F_GETLK64 || cmd == F_SETLK64 || cmd == F_SETLKW64) {
+#  if defined __UCLIBC_HAS_LFS__ && defined __NR_fcntl64
+               return INLINE_SYSCALL (fcntl64, 3, fd, cmd, arg);
+#  else
+               __set_errno(ENOSYS);
+               return -1;
+#  endif
+       }
+# endif
+       return INLINE_SYSCALL (fcntl, 3, fd, cmd, arg);
 #endif
+}
+libc_hidden_def(__libc_fcntl)
 
-#if ! defined __NR_fcntl64 && defined __UCLIBC_HAS_LFS__
-strong_alias(fcntl,fcntl64)
-#endif
+libc_hidden_proto(fcntl)
+weak_alias(__libc_fcntl,fcntl)
+libc_hidden_weak(fcntl)
index b4b007d..006b38a 100644 (file)
@@ -12,7 +12,9 @@
 #ifdef __NR_rt_sigaction
 #include <signal.h>
 
-int __syscall_rt_sigaction (int __signum, const struct sigaction *__act, struct sigaction *__oldact, size_t __size) attribute_hidden;
+int __syscall_rt_sigaction (int __signum, const struct sigaction *__act,
+                                                       struct sigaction *__oldact, size_t __size);
+
 #define __NR___syscall_rt_sigaction __NR_rt_sigaction
 _syscall4(int, __syscall_rt_sigaction, int, signum,
                  const struct sigaction *, act, struct sigaction *, oldact,
index 6cece08..51117d1 100644 (file)
 #include <unistd.h>
 #include <sys/types.h>
 #include <sys/syscall.h>
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include <sysdep.h>
+#endif
 
 
 void attribute_noreturn _exit(int status)
 {
        /* The loop is added only to keep gcc happy. */
        while(1)
+       {
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+# ifdef __NR_exit_group
+               INLINE_SYSCALL(exit_group, 1, status);
+# endif
+#endif
                INLINE_SYSCALL(exit, 1, status);
+       }
 }
 libc_hidden_def(_exit)
 weak_alias(_exit,_Exit)
index f74e0a2..0a35ac8 100644 (file)
@@ -25,12 +25,12 @@ struct old_kernel_sigaction {
  */
 
 extern int __syscall_sigaction(int, const struct old_kernel_sigaction *,
-       struct old_kernel_sigaction *) attribute_hidden;
+       struct old_kernel_sigaction *);
 
 #endif
 
 
 extern int __syscall_rt_sigaction(int, const struct sigaction *,
-       struct sigaction *, size_t) attribute_hidden;
+       struct sigaction *, size_t);
 
 #endif /* _BITS_SIGACTION_STRUCT_H */
index 14aeb9c..c6094c3 100644 (file)
 #define __UCLIBC_MUTEX_UNLOCK(M)                                                                       \
         __UCLIBC_MUTEX_CONDITIONAL_UNLOCK(M, 1)
 
-#else
+#ifdef __USE_STDIO_FUTEXES__
+
+#include <bits/stdio-lock.h>
+
+#define __UCLIBC_IO_MUTEX(M)                   _IO_lock_t M
+#define __UCLIBC_IO_MUTEX_LOCK(M)              _IO_lock_lock(M)
+#define __UCLIBC_IO_MUTEX_UNLOCK(M)    _IO_lock_unlock(M)
+#define __UCLIBC_IO_MUTEX_TRYLOCK(M)   _IO_lock_trylock(M)
+#define __UCLIBC_IO_MUTEX_INIT(M)      _IO_lock_t M = _IO_lock_initializer
+#define __UCLIBC_IO_MUTEX_EXTERN(M)            extern _IO_lock_t M
+
+#define __UCLIBC_IO_MUTEX_CONDITIONAL_LOCK(M,C)                \
+       if (C) {                                                                                \
+               _IO_lock_lock(M);                                                       \
+       }
+
+#define __UCLIBC_IO_MUTEX_CONDITIONAL_UNLOCK(M,C)      \
+       if (C) {                                                                                \
+               _IO_lock_unlock(M);                                                     \
+       }
+
+#define __UCLIBC_IO_MUTEX_AUTO_LOCK(M,A,V)                     \
+               __UCLIBC_IO_MUTEX_CONDITIONAL_LOCK(M,((A=(V))) == 0)
+
+#define __UCLIBC_IO_MUTEX_AUTO_UNLOCK(M,A)                     \
+               __UCLIBC_IO_MUTEX_CONDITIONAL_UNLOCK(M,((A) == 0))
+
+#define __UCLIBC_IO_MUTEX_LOCK_CANCEL_UNSAFE(M)                _IO_lock_lock(M)
+#define __UCLIBC_IO_MUTEX_UNLOCK_CANCEL_UNSAFE(M)      _IO_lock_unlock(M)
+
+#else /* of __USE_STDIO_FUTEXES__ */
+
+#define __UCLIBC_IO_MUTEX(M)                        __UCLIBC_MUTEX(M)
+#define __UCLIBC_IO_MUTEX_LOCK(M)                   __UCLIBC_MUTEX_CONDITIONAL_LOCK(M, 1)
+#define __UCLIBC_IO_MUTEX_UNLOCK(M)                 __UCLIBC_MUTEX_CONDITIONAL_UNLOCK(M, 1)
+#define __UCLIBC_IO_MUTEX_TRYLOCK(M)                __UCLIBC_MUTEX_TRYLOCK_CANCEL_UNSAFE(M)
+#define __UCLIBC_IO_MUTEX_INIT(M)                   __UCLIBC_MUTEX_INIT(M, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP)
+#define __UCLIBC_IO_MUTEX_EXTERN(M)                 __UCLIBC_MUTEX_EXTERN(M)
+#define __UCLIBC_IO_MUTEX_AUTO_LOCK(M,A,V)          __UCLIBC_MUTEX_AUTO_LOCK(M,A,V)
+#define __UCLIBC_IO_MUTEX_AUTO_UNLOCK(M,A)          __UCLIBC_MUTEX_AUTO_UNLOCK(M,A)
+#define __UCLIBC_IO_MUTEX_LOCK_CANCEL_UNSAFE(M)     __UCLIBC_MUTEX_LOCK_CANCEL_UNSAFE(M)
+#define __UCLIBC_IO_MUTEX_UNLOCK_CANCEL_UNSAFE(M)   __UCLIBC_MUTEX_UNLOCK_CANCEL_UNSAFE(M)
+#define __UCLIBC_IO_MUTEX_CONDITIONAL_LOCK(M,C)     __UCLIBC_MUTEX_CONDITIONAL_LOCK(M, 1)
+#define __UCLIBC_IO_MUTEX_CONDITIONAL_UNLOCK(M,C)   __UCLIBC_MUTEX_CONDITIONAL_UNLOCK(M, 1)
+
+#endif /* of __USE_STDIO_FUTEXES__ */
+
+
+#else /* of __UCLIBC_HAS_THREADS__ */
 
 #define __UCLIBC_MUTEX(M)                              void *__UCLIBC_MUTEX_DUMMY_ ## M
 #define __UCLIBC_MUTEX_INIT(M,I)                       extern void *__UCLIBC_MUTEX_DUMMY_ ## M
 #define __UCLIBC_MUTEX_LOCK(M)                         ((void)0)
 #define __UCLIBC_MUTEX_UNLOCK(M)                       ((void)0)
 
-#endif
+#define __UCLIBC_IO_MUTEX(M)                        __UCLIBC_MUTEX(M)
+#define __UCLIBC_IO_MUTEX_LOCK(M)                   __UCLIBC_MUTEX_CONDITIONAL_LOCK(M, 1)
+#define __UCLIBC_IO_MUTEX_UNLOCK(M)                 __UCLIBC_MUTEX_CONDITIONAL_UNLOCK(M, 1)
+#define __UCLIBC_IO_MUTEX_TRYLOCK(M)                __UCLIBC_MUTEX_TRYLOCK_CANCEL_UNSAFE(M)
+#define __UCLIBC_IO_MUTEX_INIT(M)                   __UCLIBC_MUTEX_INIT(M, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP)
+#define __UCLIBC_IO_MUTEX_EXTERN(M)                 __UCLIBC_MUTEX_EXTERN(M)
+#define __UCLIBC_IO_MUTEX_AUTO_LOCK(M,A,V)          __UCLIBC_MUTEX_AUTO_LOCK(M,A,V)
+#define __UCLIBC_IO_MUTEX_AUTO_UNLOCK(M,A)          __UCLIBC_MUTEX_AUTO_UNLOCK(M,A)
+#define __UCLIBC_IO_MUTEX_LOCK_CANCEL_UNSAFE(M)     __UCLIBC_MUTEX_LOCK_CANCEL_UNSAFE(M)
+#define __UCLIBC_IO_MUTEX_UNLOCK_CANCEL_UNSAFE(M)   __UCLIBC_MUTEX_UNLOCK_CANCEL_UNSAFE(M)
+#define __UCLIBC_IO_MUTEX_CONDITIONAL_LOCK(M,C)     __UCLIBC_MUTEX_CONDITIONAL_LOCK(M, 1)
+#define __UCLIBC_IO_MUTEX_CONDITIONAL_UNLOCK(M,C)   __UCLIBC_MUTEX_CONDITIONAL_UNLOCK(M, 1)
+
+#endif /* of __UCLIBC_HAS_THREADS__ */
+
+#define __UCLIBC_IO_MUTEX_TRYLOCK_CANCEL_UNSAFE(M)     \
+               __UCLIBC_IO_MUTEX_TRYLOCK(M)
 
 #endif /* _UCLIBC_MUTEX_H */
index 3631ef7..a8cf4eb 100644 (file)
         __UCLIBC_MUTEX_AUTO_LOCK_VAR(__infunc_user_locking)
 
 #define __STDIO_AUTO_THREADLOCK(__stream)                                      \
-        __UCLIBC_MUTEX_AUTO_LOCK((__stream)->__lock, __infunc_user_locking,    \
+        __UCLIBC_IO_MUTEX_AUTO_LOCK((__stream)->__lock, __infunc_user_locking, \
        (__stream)->__user_locking)
 
 #define __STDIO_AUTO_THREADUNLOCK(__stream)                                    \
-        __UCLIBC_MUTEX_AUTO_UNLOCK((__stream)->__lock, __infunc_user_locking)
+        __UCLIBC_IO_MUTEX_AUTO_UNLOCK((__stream)->__lock, __infunc_user_locking)
 
 #define __STDIO_ALWAYS_THREADLOCK(__stream)                                    \
-        __UCLIBC_MUTEX_LOCK((__stream)->__lock)
+        __UCLIBC_IO_MUTEX_LOCK((__stream)->__lock)
 
 #define __STDIO_ALWAYS_THREADUNLOCK(__stream)                                  \
-        __UCLIBC_MUTEX_UNLOCK((__stream)->__lock)
+        __UCLIBC_IO_MUTEX_UNLOCK((__stream)->__lock)
 
 #define __STDIO_ALWAYS_THREADLOCK_CANCEL_UNSAFE(__stream)                      \
-        __UCLIBC_MUTEX_LOCK_CANCEL_UNSAFE((__stream)->__lock)
+        __UCLIBC_IO_MUTEX_LOCK_CANCEL_UNSAFE((__stream)->__lock)
 
 #define __STDIO_ALWAYS_THREADTRYLOCK_CANCEL_UNSAFE(__stream)                   \
-        __UCLIBC_MUTEX_TRYLOCK_CANCEL_UNSAFE((__stream)->__lock)
+        __UCLIBC_IO_MUTEX_TRYLOCK_CANCEL_UNSAFE((__stream)->__lock)
 
 #define __STDIO_ALWAYS_THREADUNLOCK_CANCEL_UNSAFE(__stream)                    \
-        __UCLIBC_MUTEX_UNLOCK_CANCEL_UNSAFE((__stream)->__lock)
+        __UCLIBC_IO_MUTEX_UNLOCK_CANCEL_UNSAFE((__stream)->__lock)
 
 #ifdef __UCLIBC_HAS_THREADS__
 #define __STDIO_SET_USER_LOCKING(__stream)     ((__stream)->__user_locking = 1)
 #define __STDIO_SET_USER_LOCKING(__stream)             ((void)0)
 #endif
 
+#ifdef __UCLIBC_HAS_THREADS__
+#ifdef __USE_STDIO_FUTEXES__
+#define STDIO_INIT_MUTEX(M) _IO_lock_init(M)
+#else
+#define STDIO_INIT_MUTEX(M) __stdio_init_mutex(& M)
+#endif
+#endif
+
 /**********************************************************************/
 
 #define __STDIO_IOFBF 0                /* Fully buffered.  */
@@ -275,7 +283,7 @@ struct __STDIO_FILE_STRUCT {
 #endif
 #ifdef __UCLIBC_HAS_THREADS__
        int __user_locking;
-       __UCLIBC_MUTEX(__lock);
+       __UCLIBC_IO_MUTEX(__lock);
 #endif
 /* Everything after this is unimplemented... and may be trashed. */
 #if __STDIO_BUILTIN_BUF_SIZE > 0
@@ -351,9 +359,9 @@ extern void _stdio_term(void) attribute_hidden;
 extern struct __STDIO_FILE_STRUCT *_stdio_openlist;
 
 #ifdef __UCLIBC_HAS_THREADS__
-__UCLIBC_MUTEX_EXTERN(_stdio_openlist_add_lock);
+__UCLIBC_IO_MUTEX_EXTERN(_stdio_openlist_add_lock);
 #ifdef __STDIO_BUFFERS
-__UCLIBC_MUTEX_EXTERN(_stdio_openlist_del_lock);
+__UCLIBC_IO_MUTEX_EXTERN(_stdio_openlist_del_lock);
 extern volatile int _stdio_openlist_use_count; /* _stdio_openlist_del_lock */
 extern int _stdio_openlist_del_count; /* _stdio_openlist_del_lock */
 #endif
index 774efc9..711811f 100644 (file)
 #include <sys/syscall.h>
 #include <unistd.h>
 
-#ifdef __LINUXTHREADS_OLD__
-extern __typeof(fsync) weak_function fsync;
-strong_alias(fsync,__libc_fsync)
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include "sysdep-cancel.h"
+#else
+#define SINGLE_THREAD_P 1
 #endif
 
-_syscall1(int, fsync, int, fd)
+#define __NR___syscall_fsync __NR_fsync
+static inline _syscall1(int, __syscall_fsync, int, fd)
+
+extern __typeof(fsync) __libc_fsync;
+
+int __libc_fsync(int fd)
+{
+       if (SINGLE_THREAD_P)
+               return __syscall_fsync(fd);
+
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+       int oldtype = LIBC_CANCEL_ASYNC ();
+       int result = __syscall_fsync(fd);
+       LIBC_CANCEL_RESET (oldtype);
+       return result;
+#endif
+}
+
+weak_alias(__libc_fsync, fsync)
index 7ac8f16..f2f0f53 100644 (file)
 #include <stdarg.h>
 #include <sys/ioctl.h>
 
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include <sysdep-cancel.h>
+#else
+#define SINGLE_THREAD_P 1
+#endif
+
+libc_hidden_proto(ioctl)
 
 #define __NR___syscall_ioctl __NR_ioctl
 static __always_inline
-_syscall3(int, __syscall_ioctl, int, fd, int, request, void *, arg)
+_syscall3(int, __syscall_ioctl, int, fd, unsigned long int, request, void *, arg)
 
 int ioctl(int fd, unsigned long int request, ...)
 {
-    void *arg;
-    va_list list;
+       void *arg;
+       va_list list;
+
+       va_start(list, request);
+       arg = va_arg(list, void *);
+
+       va_end(list);
 
-    va_start(list, request);
-    arg = va_arg(list, void *);
-    va_end(list);
+       if (SINGLE_THREAD_P)
+               return __syscall_ioctl(fd, request, arg);
 
-    return __syscall_ioctl(fd, request, arg);
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+       int oldtype = LIBC_CANCEL_ASYNC ();
+       int result = __syscall_ioctl(fd, request, arg);
+       LIBC_CANCEL_RESET (oldtype);
+       return result;
+#endif
 }
 libc_hidden_def(ioctl)
diff --git a/libc/sysdeps/linux/common/libgcc_s.h b/libc/sysdeps/linux/common/libgcc_s.h
new file mode 100644 (file)
index 0000000..e74a103
--- /dev/null
@@ -0,0 +1,2 @@
+/* Name of libgcc_s library provided by gcc.  */
+#define LIBGCC_S_SO "libgcc_s.so.1"
index 7a46f0c..2629bd4 100644 (file)
@@ -9,16 +9,33 @@
 
 #include <sys/syscall.h>
 #include <unistd.h>
+#include <sys/mman.h>
 
-#if defined __NR_msync && defined __ARCH_USE_MMU__
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include <sysdep-cancel.h>
+#else
+#define SINGLE_THREAD_P 1
+#endif
 
-#include <sys/mman.h>
+#define __NR___syscall_msync __NR_msync
+static __always_inline _syscall3(int, __syscall_msync, void *, addr, size_t, length,
+                                               int, flags)
 
-#ifdef __LINUXTHREADS_OLD__
-extern __typeof(msync) weak_function msync;
-strong_alias(msync,__libc_msync)
+extern __typeof(msync) __libc_msync;
+int __libc_msync(void * addr, size_t length, int flags)
+{
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+       int oldtype, result;
 #endif
 
-_syscall3(int, msync, void *, addr, size_t, length, int, flags)
+       if (SINGLE_THREAD_P)
+               return __syscall_msync(addr, length, flags);
 
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+       oldtype = LIBC_CANCEL_ASYNC ();
+       result = __syscall_msync(addr, length, flags);
+       LIBC_CANCEL_RESET (oldtype);
+       return result;
 #endif
+}
+weak_alias(__libc_msync,msync)
index 0849127..0be59c5 100644 (file)
 #include <sys/syscall.h>
 #include <time.h>
 
-#if defined __USE_POSIX199309 && defined __NR_nanosleep
-_syscall2(int, nanosleep, const struct timespec *, req,
-                 struct timespec *, rem)
-#ifndef __LINUXTHREADS_OLD__
-libc_hidden_def(nanosleep)
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include <sysdep-cancel.h>
+#include <pthreadP.h>
 #else
-libc_hidden_weak(nanosleep)
-strong_alias(nanosleep,__libc_nanosleep)
+#define SINGLE_THREAD_P 1
 #endif
+
+#define __NR___syscall_nanosleep __NR_nanosleep
+static inline _syscall2(int, __syscall_nanosleep, const struct timespec *, req,
+                                               struct timespec *, rem);
+
+extern __typeof(nanosleep) __libc_nanosleep;
+
+int __libc_nanosleep(const struct timespec *req, struct timespec *rem)
+{
+       if (SINGLE_THREAD_P)
+               return __syscall_nanosleep(req, rem);
+
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+       int oldtype = LIBC_CANCEL_ASYNC ();
+       int result = __syscall_nanosleep(req, rem);
+       LIBC_CANCEL_RESET (oldtype);
+       return result;
 #endif
+}
+
+libc_hidden_proto(nanosleep)
+weak_alias(__libc_nanosleep,nanosleep)
+libc_hidden_weak(nanosleep)
diff --git a/libc/sysdeps/linux/common/not-cancel.h b/libc/sysdeps/linux/common/not-cancel.h
new file mode 100644 (file)
index 0000000..9418417
--- /dev/null
@@ -0,0 +1,60 @@
+/* Uncancelable versions of cancelable interfaces.  Linux version.
+   Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+
+/* Uncancelable open.  */
+#define open_not_cancel(name, flags, mode) \
+   INLINE_SYSCALL (open, 3, (const char *) (name), (flags), (mode))
+#define open_not_cancel_2(name, flags) \
+   INLINE_SYSCALL (open, 2, (const char *) (name), (flags))
+
+/* Uncancelable close.  */
+#define close_not_cancel(fd) \
+  INLINE_SYSCALL (close, 1, fd)
+#define close_not_cancel_no_status(fd) \
+  (void) ({ INTERNAL_SYSCALL_DECL (err);                                     \
+           INTERNAL_SYSCALL (close, err, 1, (fd)); })
+
+/* Uncancelable read.  */
+#define read_not_cancel(fd, buf, n) \
+  INLINE_SYSCALL (read, 3, (fd), (buf), (n))
+
+/* Uncancelable write.  */
+#define write_not_cancel(fd, buf, n) \
+  INLINE_SYSCALL (write, 3, (fd), (buf), (n))
+
+/* Uncancelable writev.  */
+#define writev_not_cancel_no_status(fd, iov, n) \
+  (void) ({ INTERNAL_SYSCALL_DECL (err);                                     \
+           INTERNAL_SYSCALL (writev, err, 3, (fd), (iov), (n)); })
+
+/* Uncancelable fcntl.  */
+#define fcntl_not_cancel(fd, cmd, val) \
+  __fcntl_nocancel (fd, cmd, val)
+
+/* Uncancelable waitpid.  */
+#ifdef __NR_waitpid
+# define waitpid_not_cancel(pid, stat_loc, options) \
+  INLINE_SYSCALL (waitpid, 3, pid, stat_loc, options)
+#else
+# define waitpid_not_cancel(pid, stat_loc, options) \
+  INLINE_SYSCALL (wait4, 4, pid, stat_loc, options, NULL)
+#endif
index cfe471c..c1f5400 100644 (file)
@@ -7,6 +7,10 @@
 #include <features.h>
 #include <fcntl.h>
 #include <stdarg.h>
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include <errno.h>
+#include <sysdep-cancel.h>
+#endif
 
 #ifdef __UCLIBC_HAS_LFS__
 
@@ -28,7 +32,20 @@ int open64 (const char *file, int oflag, ...)
        va_end (arg);
     }
 
-    return open(file, oflag | O_LARGEFILE, mode);
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+  if (SINGLE_THREAD_P)
+    return INLINE_SYSCALL (open, 3, file, oflag | O_LARGEFILE, mode);
+
+  int oldtype = LIBC_CANCEL_ASYNC ();
+
+  int result = INLINE_SYSCALL (open, 3, file, oflag | O_LARGEFILE, mode);
+
+  LIBC_CANCEL_RESET (oldtype);
+
+  return result;
+#else
+  return open(file, oflag | O_LARGEFILE, mode);
+#endif
 }
 #ifndef __LINUXTHREADS_OLD__
 libc_hidden_def(open64)
index 19ba307..132ffa8 100644 (file)
 #define __UCLIBC_HIDE_DEPRECATED__
 #include <sys/syscall.h>
 #include <unistd.h>
-#include <signal.h>
 
-#ifdef __LINUXTHREADS_OLD__
-extern __typeof(pause) weak_function pause;
-strong_alias(pause, __libc_pause)
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include <sysdep-cancel.h>
 #endif
 
-#ifdef __NR_pause
-_syscall0(int, pause)
-#else
-int pause(void)
+#include <signal.h>
+
+/* Suspend the process until a signal arrives.
+   This always returns -1 and sets errno to EINTR.  */
+int
+__libc_pause (void)
 {
-       return __sigpause(sigblock(0), 0);
+  sigset_t set;
+
+  __sigemptyset (&set);
+  sigprocmask (SIG_BLOCK, NULL, &set);
+
+  /* pause is a cancellation point, but so is sigsuspend.
+     So no need for anything special here.  */
+
+  return sigsuspend (&set);
 }
+weak_alias (__libc_pause, pause)
+
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+LIBC_CANCEL_HANDLED ();                /* sigsuspend handles our cancellation.  */
 #endif
+
index 52f6c76..3895e0d 100644 (file)
 #include <sys/poll.h>
 #include <bits/kernel-features.h>
 
-#if defined __ASSUME_POLL_SYSCALL && defined __NR_poll
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include <sysdep-cancel.h>
+#else
+#define SINGLE_THREAD_P 1
+#endif
 
-_syscall3(int, poll, struct pollfd *, fds,
-       unsigned long int, nfds, int, timeout)
+libc_hidden_proto(poll)
 
-#elif defined(__NR_ppoll) && defined __UCLIBC_LINUX_SPECIFIC__
+#if defined __ASSUME_POLL_SYSCALL && defined __NR_poll
+
+#define __NR___syscall_poll __NR_poll
+static inline _syscall3(int, __syscall_poll, struct pollfd *, fds,
+                       unsigned long int, nfds, int, timeout);
 
 int poll(struct pollfd *fds, nfds_t nfds, int timeout)
 {
-       struct timespec *ts = NULL, tval;
-       if (timeout > 0) {
-               tval.tv_sec = timeout / 1000;
-               tval.tv_nsec = (timeout % 1000) * 1000000;
-               ts = &tval;
-       } else if (timeout == 0) {
-               tval.tv_sec = 0;
-               tval.tv_nsec = 0;
-               ts = &tval;
-       }
-       return ppoll(fds, nfds, ts, NULL);
+    if (SINGLE_THREAD_P)
+       return __syscall_poll(fds, nfds, timeout);
+
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+    int oldtype = LIBC_CANCEL_ASYNC ();
+    int result = __syscall_poll(fds, nfds, timeout);
+    LIBC_CANCEL_RESET (oldtype);
+    return result;
+#endif
 }
-
-#else
-/* ugh, this arch lacks poll, so we need to emulate this crap ... */
+#else /* !__NR_poll */
 
 #include <alloca.h>
 #include <sys/types.h>
@@ -54,6 +57,9 @@ int poll(struct pollfd *fds, nfds_t nfds, int timeout)
 #include <sys/param.h>
 #include <unistd.h>
 
+libc_hidden_proto(getdtablesize)
+libc_hidden_proto(select)
+
 /* uClinux 2.0 doesn't have poll, emulate it using select */
 
 /* Poll the file descriptors described by the NFDS structures starting at
@@ -221,10 +227,4 @@ int poll(struct pollfd *fds, nfds_t nfds, int timeout)
 }
 
 #endif
-
-#ifndef __LINUXTHREADS_OLD__
 libc_hidden_def(poll)
-#else
-libc_hidden_weak(poll)
-strong_alias(poll,__libc_poll)
-#endif
index 63ab0db..7e93537 100644 (file)
 #include <stddef.h>    /* For NULL.  */
 #include <sys/time.h>
 #include <sys/select.h>
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include <sysdep-cancel.h>
+#endif
 
-extern __typeof(pselect) __libc_pselect;
-
+libc_hidden_proto(sigprocmask)
+libc_hidden_proto(select)
 
 
 /* Check the first NFDS descriptors each in READFDS (if not NULL) for read
@@ -33,8 +36,13 @@ extern __typeof(pselect) __libc_pselect;
    after waiting the interval specified therein.  Additionally set the sigmask
    SIGMASK for this call.  Returns the number of ready descriptors, or -1 for
    errors.  */
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+static int
+__pselect (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+#else
 int
-__libc_pselect (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+pselect (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+#endif
           const struct timespec *timeout, const sigset_t *sigmask)
 {
   struct timeval tval;
@@ -64,4 +72,23 @@ __libc_pselect (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
 
   return retval;
 }
-weak_alias(__libc_pselect,pselect)
+
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+int
+pselect (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+          const struct timespec *timeout, const sigset_t *sigmask)
+{
+       if (SINGLE_THREAD_P)
+               return __pselect (nfds, readfds, writefds, exceptfds,
+                                 timeout, sigmask);
+
+       int oldtype = LIBC_CANCEL_ASYNC ();
+
+       int result = __pselect (nfds, readfds, writefds, exceptfds,
+                                timeout, sigmask);
+
+       LIBC_CANCEL_RESET (oldtype);
+
+       return result;
+}
+#endif
index 3c40a0d..fce396d 100644 (file)
@@ -2,7 +2,8 @@
 /*
  * readv() for uClibc
  *
- * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ * Copyright (C) 2006 by Steven J. Hill <sjhill@realitydiluted.com>
+ * Copyright (C) 2000-2004 by Erik Andersen <andersen@codepoet.org>
  *
  * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
  */
 #include <sys/syscall.h>
 #include <sys/uio.h>
 
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include <sysdep-cancel.h>
+
+/* We should deal with kernel which have a smaller UIO_FASTIOV as well
+   as a very big count.  */
+static ssize_t __readv (int fd, const struct iovec *vector, int count)
+{
+  ssize_t bytes_read;
+
+  bytes_read = INLINE_SYSCALL (readv, 3, fd, vector, count);
+
+  if (bytes_read >= 0 || errno != EINVAL || count <= UIO_FASTIOV)
+    return bytes_read;
+
+  /* glibc tries again, but we do not. */
+  //return __atomic_readv_replacement (fd, vector, count);
+
+  return -1;
+}
+
+ssize_t readv (int fd, const struct iovec *vector, int count)
+{
+  if (SINGLE_THREAD_P)
+    return __readv (fd, vector, count);
+
+  int oldtype = LIBC_CANCEL_ASYNC ();
+
+  int result = __readv (fd, vector, count);
+
+  LIBC_CANCEL_RESET (oldtype);
+
+  return result;
+}
+#else
 _syscall3(ssize_t, readv, int, filedes, const struct iovec *, vector,
                  int, count)
+#endif
index caff28d..0c2d919 100644 (file)
 #include <sys/select.h>
 #include <stdint.h>
 
-extern __typeof(select) __libc_select;
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include <sysdep-cancel.h>
+#else
+#define SINGLE_THREAD_P 1
+#endif
 
 #define USEC_PER_SEC 1000000L
 
+extern __typeof(select) __libc_select;
+
 #if !defined(__NR__newselect) && !defined(__NR_select) && defined __USE_XOPEN2K
 # define __NR___libc_pselect6 __NR_pselect6
 _syscall6(int, __libc_pselect6, int, n, fd_set *, readfds, fd_set *, writefds,
-       fd_set *, exceptfds, const struct timespec *, timeout,
-       const sigset_t *, sigmask)
+        fd_set *, exceptfds, const struct timespec *, timeout,
+        const sigset_t *, sigmask)
 
 int __libc_select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
                   struct timeval *timeout)
@@ -30,12 +36,12 @@ int __libc_select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
                _ts.tv_sec = timeout->tv_sec;
 
                /* GNU extension: allow for timespec values where the sub-sec
-                * field is equal to or more than 1 second.  The kernel will
-                * reject this on us, so take care of the time shift ourself.
-                * Some applications (like readline and linphone) do this.
-                * See 'clarification on select() type calls and invalid timeouts'
-                * on the POSIX general list for more information.
-                */
+               * field is equal to or more than 1 second.  The kernel will
+               * reject this on us, so take care of the time shift ourself.
+               * Some applications (like readline and linphone) do this.
+               * See 'clarification on select() type calls and invalid timeouts'
+               * on the POSIX general list for more information.
+               */
                usec = timeout->tv_usec;
                if (usec >= USEC_PER_SEC) {
                        _ts.tv_sec += usec / USEC_PER_SEC;
@@ -46,18 +52,41 @@ int __libc_select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
                ts = &_ts;
        }
 
-       return __libc_pselect6(n, readfds, writefds, exceptfds, ts, 0);
+       if (SINGLE_THREAD_P)
+               return __libc_pselect6(n, readfds, writefds, exceptfds, ts, 0);
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+       int oldtype = LIBC_CANCEL_ASYNC ();
+       int result = __libc_pselect6(n, readfds, writefds, exceptfds, ts, 0);
+       LIBC_CANCEL_RESET (oldtype);
+       return result;
+#endif
+
 }
 
 #else
 
 #ifdef __NR__newselect
-# define __NR___libc_select __NR__newselect
+# define __NR___syscall_select __NR__newselect
 #else
-# define __NR___libc_select __NR_select
+# define __NR___syscall_select __NR_select
 #endif
-_syscall5(int, __libc_select, int, n, fd_set *, readfds, fd_set *, writefds,
-                 fd_set *, exceptfds, struct timeval *, timeout)
+
+_syscall5(int, __syscall_select, int, n, fd_set *, readfds,
+               fd_set *, writefds, fd_set *, exceptfds, struct timeval *, timeout);
+
+int __libc_select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+                  struct timeval *timeout)
+{
+       if (SINGLE_THREAD_P)
+               return __syscall_select(n, readfds, writefds, exceptfds, timeout);
+
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+       int oldtype = LIBC_CANCEL_ASYNC ();
+       int result = __syscall_select(n, readfds, writefds, exceptfds, timeout);
+       LIBC_CANCEL_RESET (oldtype);
+       return result;
+#endif
+}
 
 #endif
 
index 13bb2be..011d7b3 100644 (file)
@@ -14,6 +14,7 @@
 
 #undef sigprocmask
 
+libc_hidden_proto(sigprocmask)
 
 #ifdef __NR_rt_sigprocmask
 
@@ -24,20 +25,28 @@ _syscall4(int, __rt_sigprocmask, int, how, const sigset_t *, set,
 
 int sigprocmask(int how, const sigset_t * set, sigset_t * oldset)
 {
-       if (set &&
-# if (SIG_BLOCK == 0) && (SIG_UNBLOCK == 1) && (SIG_SETMASK == 2)
-               (((unsigned int) how) > 2)
-# elif (SIG_BLOCK == 1) && (SIG_UNBLOCK == 2) && (SIG_SETMASK == 3)
-               (((unsigned int)(how-1)) > 2)
-# else
-#  warning "compile time assumption violated.. slow path..."
-               ((how != SIG_BLOCK) && (how != SIG_UNBLOCK)
-                && (how != SIG_SETMASK))
+#ifdef SIGCANCEL
+       sigset_t local_newmask;
+
+       /*
+        * The only thing we have to make sure here is that SIGCANCEL and
+        * SIGSETXID are not blocked.
+        */
+       if (set != NULL && (__builtin_expect (__sigismember (set, SIGCANCEL), 0)
+# ifdef SIGSETXID
+               || __builtin_expect (__sigismember (set, SIGSETXID), 0)
+# endif
+               ))
+       {
+               local_newmask = *set;
+               __sigdelset (&local_newmask, SIGCANCEL);
+# ifdef SIGSETXID
+               __sigdelset (&local_newmask, SIGSETXID);
 # endif
-               ) {
-               __set_errno(EINVAL);
-               return -1;
+               set = &local_newmask;
        }
+#endif
+
        return __rt_sigprocmask(how, set, oldset, _NSIG / 8);
 }
 
@@ -51,20 +60,28 @@ _syscall3(int, __syscall_sigprocmask, int, how, const sigset_t *, set,
 
 int sigprocmask(int how, const sigset_t * set, sigset_t * oldset)
 {
-       if (set &&
-# if (SIG_BLOCK == 0) && (SIG_UNBLOCK == 1) && (SIG_SETMASK == 2)
-               (((unsigned int) how) > 2)
-# elif (SIG_BLOCK == 1) && (SIG_UNBLOCK == 2) && (SIG_SETMASK == 3)
-               (((unsigned int)(how-1)) > 2)
-# else
-#  warning "compile time assumption violated.. slow path..."
-               ((how != SIG_BLOCK) && (how != SIG_UNBLOCK)
-                && (how != SIG_SETMASK))
+#ifdef SIGCANCEL
+       sigset_t local_newmask;
+
+       /*
+        * The only thing we have to make sure here is that SIGCANCEL and
+        * SIGSETXID are not blocked.
+        */
+       if (set != NULL && (__builtin_expect (__sigismember (set, SIGCANCEL), 0)
+# ifdef SIGSETXID
+               || __builtin_expect (__sigismember (set, SIGSETXID), 0)
+# endif
+               ))
+       {
+               local_newmask = *set;
+               __sigdelset (&local_newmask, SIGCANCEL);
+# ifdef SIGSETXID
+               __sigdelset (&local_newmask, SIGSETXID);
 # endif
-               ) {
-               __set_errno(EINVAL);
-               return -1;
+               set = &local_newmask;
        }
+#endif
+
        return (__syscall_sigprocmask(how, set, oldset));
 }
 #endif
index 3648e76..789eeda 100644 (file)
 
 #if defined __USE_POSIX
 #include <signal.h>
+#undef sigsuspend
 
-extern __typeof(sigsuspend) __libc_sigsuspend;
+libc_hidden_proto(sigsuspend)
 
 #ifdef __NR_rt_sigsuspend
 # define __NR___rt_sigsuspend __NR_rt_sigsuspend
-static __inline__ _syscall2(int, __rt_sigsuspend, const sigset_t *, mask, size_t, size)
 
-int __libc_sigsuspend(const sigset_t * mask)
+# ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#  include <errno.h>
+#  include <sysdep-cancel.h>
+
+/* Change the set of blocked signals to SET,
+   wait until a signal arrives, and restore the set of blocked signals.  */
+int sigsuspend (const sigset_t *set)
+{
+       if (SINGLE_THREAD_P)
+               return INLINE_SYSCALL (rt_sigsuspend, 2, set, _NSIG / 8);
+
+       int oldtype = LIBC_CANCEL_ASYNC ();
+
+       int result = INLINE_SYSCALL (rt_sigsuspend, 2, set, _NSIG / 8);
+
+       LIBC_CANCEL_RESET (oldtype);
+
+       return result;
+}
+# else
+static inline _syscall2(int, __rt_sigsuspend, const sigset_t *, mask, size_t, size);
+
+int sigsuspend(const sigset_t * mask)
 {
        return __rt_sigsuspend(mask, _NSIG / 8);
 }
+# endif
 #else
 # define __NR___syscall_sigsuspend __NR_sigsuspend
 static __inline__ _syscall3(int, __syscall_sigsuspend, int, a, unsigned long int, b,
                  unsigned long int, c)
 
-int __libc_sigsuspend(const sigset_t * set)
+int sigsuspend(const sigset_t * set)
 {
        return __syscall_sigsuspend(0, 0, set->__val[0]);
 }
 #endif
-weak_alias(__libc_sigsuspend,sigsuspend)
-libc_hidden_weak(sigsuspend)
+libc_hidden_def(sigsuspend)
 #endif
index cd5b2f1..dae74d7 100644 (file)
 # endif
 
 #endif /* __ASSEMBLER__ */
+
+/* Values used for encoding parameter of cfi_personality and cfi_lsda.  */
+#define DW_EH_PE_absptr                0x00
+#define DW_EH_PE_omit          0xff
+#define DW_EH_PE_uleb128       0x01
+#define DW_EH_PE_udata2                0x02
+#define DW_EH_PE_udata4                0x03
+#define DW_EH_PE_udata8                0x04
+#define DW_EH_PE_sleb128       0x09
+#define DW_EH_PE_sdata2                0x0a
+#define DW_EH_PE_sdata4                0x0b
+#define DW_EH_PE_sdata8                0x0c
+#define DW_EH_PE_signed                0x08
+#define DW_EH_PE_pcrel         0x10
+#define DW_EH_PE_textrel       0x20
+#define DW_EH_PE_datarel       0x30
+#define DW_EH_PE_funcrel       0x40
+#define DW_EH_PE_aligned       0x50
+#define DW_EH_PE_indirect      0x80
+
index b164953..d4b79bd 100644 (file)
@@ -1,23 +1,43 @@
 /*
+ * Copyright (C) 2006 Steven J. Hill <sjhill@realitydiluted.com>
  * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
  *
  * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
  */
-
 #include <stdlib.h>
 #include <syscall.h>
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <sys/resource.h>
 
-#ifdef __LINUXTHREADS_OLD__
-extern __typeof(wait) weak_function wait;
-strong_alias(wait,__libc_wait)
-#endif
+/* Wait for a child to die.  When one does, put its status in *STAT_LOC
+ * and return its process ID.  For errors, return (pid_t) -1.  */
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include <errno.h>
+#include <sysdep-cancel.h>
+
+pid_t attribute_hidden
+__libc_wait (__WAIT_STATUS_DEFN stat_loc)
+{
+  if (SINGLE_THREAD_P)
+    return INLINE_SYSCALL (wait4, 4, WAIT_ANY, stat_loc, 0,
+                          (struct rusage *) NULL);
 
+  int oldtype = LIBC_CANCEL_ASYNC ();
+
+  pid_t result = INLINE_SYSCALL (wait4, 4, WAIT_ANY, stat_loc, 0,
+                                (struct rusage *) NULL);
+
+  LIBC_CANCEL_RESET (oldtype);
+
+  return result;
+}
+#else
 /* Wait for a child to die.  When one does, put its status in *STAT_LOC
  * and return its process ID.  For errors, return (pid_t) -1.  */
-__pid_t wait(__WAIT_STATUS_DEFN stat_loc)
+__pid_t __libc_wait (__WAIT_STATUS_DEFN stat_loc)
 {
-       return wait4(WAIT_ANY, stat_loc, 0, NULL);
+      return wait4 (WAIT_ANY, stat_loc, 0, (struct rusage *) NULL);
 }
+#endif
+weak_alias(__libc_wait,wait)
index e464993..d043719 100644 (file)
@@ -1,5 +1,6 @@
 /* vi: set sw=4 ts=4: */
 /*
+ * Copyright (C) 2006 Steven J. Hill <sjhill@realitydiluted.com>
  * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
  *
  * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
 #include <sys/wait.h>
 #include <sys/resource.h>
 
-__pid_t waitpid(__pid_t pid, int *wait_stat, int options)
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include "sysdep-cancel.h"
+#else
+#define SINGLE_THREAD_P 1
+#endif
+
+libc_hidden_proto(wait4)
+
+extern __typeof(waitpid) __libc_waitpid;
+__pid_t __libc_waitpid(__pid_t pid, int *wait_stat, int options)
 {
-       return wait4(pid, wait_stat, options, NULL);
+       if (SINGLE_THREAD_P)
+               return wait4(pid, wait_stat, options, NULL);
+
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+       int oldtype = LIBC_CANCEL_ASYNC ();
+       int result = wait4(pid, wait_stat, options, NULL);
+       LIBC_CANCEL_RESET (oldtype);
+       return result;
+#endif
 }
-#ifndef __LINUXTHREADS_OLD__
-libc_hidden_def(waitpid)
-#else
+libc_hidden_proto(waitpid)
+weak_alias(__libc_waitpid,waitpid)
 libc_hidden_weak(waitpid)
-strong_alias(waitpid,__libc_waitpid)
-#endif
index 99de7e4..bd0e407 100644 (file)
 #include <sys/syscall.h>
 #include <sys/uio.h>
 
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include <errno.h>
+#include <sysdep-cancel.h>
+
+/* We should deal with kernel which have a smaller UIO_FASTIOV as well
+   as a very big count.  */
+static ssize_t __writev (int fd, const struct iovec *vector, int count)
+{
+  ssize_t bytes_written;
+
+  bytes_written = INLINE_SYSCALL (writev, 3, fd, vector, count);
+
+  if (bytes_written >= 0 || errno != EINVAL || count <= UIO_FASTIOV)
+    return bytes_written;
+
+  /* glibc tries again, but we do not. */
+  /* return __atomic_writev_replacement (fd, vector, count); */
+
+  return -1;
+}
+
+ssize_t writev (int fd, const struct iovec *vector, int count)
+{
+  if (SINGLE_THREAD_P)
+    return __writev (fd, vector, count);
+
+  int oldtype = LIBC_CANCEL_ASYNC ();
+
+  ssize_t result = __writev (fd, vector, count);
+
+  LIBC_CANCEL_RESET (oldtype);
+
+  return result;
+}
+#else
 _syscall3(ssize_t, writev, int, filedes, const struct iovec *, vector,
                  int, count)
+#endif
index 2bf2b76..668cca7 100644 (file)
@@ -5,8 +5,17 @@
 # Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
 #
 
-CSRC := brk.c sigaction.c __syscall_error.c
+CSRC := brk.c __syscall_error.c
+
+ifneq ($(UCLIBC_HAS_THREADS_NATIVE),y)
+CSRC += sigaction.c
+endif
 
 SSRC := \
-       __longjmp.S vfork.S clone.S setjmp.S bsd-setjmp.S bsd-_setjmp.S \
+       __longjmp.S setjmp.S bsd-setjmp.S bsd-_setjmp.S \
        sync_file_range.S syscall.S mmap.S mmap64.S posix_fadvise64.S
+
+
+ifneq ($(UCLIBC_HAS_THREADS_NATIVE),y)
+SSRC += vfork.S clone.S
+endif
index 0427d91..9184bd6 100644 (file)
@@ -23,7 +23,7 @@
                "int    $0x80\n\t"                              \
                RESTOREARGS_##nr                                \
                : "=a" (resultvar)                              \
-               : "i" (name) ASMFMT_##nr(args) : "memory", "cc" \
+               : "g" (name) ASMFMT_##nr(args) : "memory", "cc" \
        ); \
        (int) resultvar; \
 })
index deeec03..536e9c1 100644 (file)
@@ -37,7 +37,7 @@
 #undef __UCLIBC_HAVE_ASM_GLOBAL_DOT_NAME__
 
 /* define if target supports CFI pseudo ops */
-#undef __UCLIBC_HAVE_ASM_CFI_DIRECTIVES__
+#define __UCLIBC_HAVE_ASM_CFI_DIRECTIVES__
 
 /* define if target supports IEEE signed zero floats */
 #define __UCLIBC_HAVE_SIGNED_ZERO__
index 14fc25c..a7de3fe 100644 (file)
@@ -79,7 +79,10 @@ clone:
        movl    %eax,8(%ecx)
        /* Don't leak any information.  */
        movl    $0,4(%ecx)
+#ifndef RESET_PID
        movl    $0,(%ecx)
+#endif
+
 
        /* Do the system call */
        pushl   %ebx
@@ -90,6 +93,10 @@ clone:
        movl    FLAGS+12(%esp),%ebx
        movl    CTID+12(%esp),%edi
        movl    $__NR_clone,%eax
+#ifdef RESET_PID
+       /* Remember the flag value.  */
+       movl    %ebx, (%ecx)
+#endif
        int     $0x80
        popl    %edi
        popl    %esi
@@ -121,3 +128,4 @@ __error:
        jmp __syscall_error
 
 .size clone,.-clone
+weak_alias(clone, __clone)
diff --git a/libc/sysdeps/linux/i386/sysdep.h b/libc/sysdeps/linux/i386/sysdep.h
new file mode 100644 (file)
index 0000000..ff67e8a
--- /dev/null
@@ -0,0 +1,460 @@
+/* Copyright (C) 1992,1993,1995-2000,2002-2006,2007
+       Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper, <drepper@gnu.org>, August 1995.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along 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 _LINUX_I386_SYSDEP_H
+#define _LINUX_I386_SYSDEP_H 1
+
+#include <sys/syscall.h>
+#include <common/sysdep.h>
+
+#ifdef __ASSEMBLER__
+
+/* Syntactic details of assembler.  */
+
+/* ELF uses byte-counts for .align, most others use log2 of count of bytes.  */
+#define ALIGNARG(log2) 1<<log2
+/* For ELF we need the `.type' directive to make shared libs work right.  */
+#define ASM_TYPE_DIRECTIVE(name,typearg) .type name,typearg;
+#define ASM_SIZE_DIRECTIVE(name) .size name,.-name;
+
+/* In ELF C symbols are asm symbols.  */
+#undef NO_UNDERSCORES
+#define NO_UNDERSCORES
+
+/* Define an entry point visible from C.
+
+   There is currently a bug in gdb which prevents us from specifying
+   incomplete stabs information.  Fake some entries here which specify
+   the current source file.  */
+#define        ENTRY(name)                                                           \
+  STABS_CURRENT_FILE1("")                                                    \
+  STABS_CURRENT_FILE(name)                                                   \
+  ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(name);                                  \
+  ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name),@function)                         \
+  .align ALIGNARG(4);                                                        \
+  STABS_FUN(name)                                                            \
+  C_LABEL(name)                                                                      \
+  cfi_startproc;                                                             \
+  CALL_MCOUNT
+
+#undef END
+#define END(name)                                                            \
+  cfi_endproc;                                                               \
+  ASM_SIZE_DIRECTIVE(name)                                                   \
+  STABS_FUN_END(name)
+
+#ifdef HAVE_CPP_ASM_DEBUGINFO
+/* Disable that goop, because we just pass -g through to the assembler
+   and it generates proper line number information directly.  */
+# define STABS_CURRENT_FILE1(name)
+# define STABS_CURRENT_FILE(name)
+# define STABS_FUN(name)
+# define STABS_FUN_END(name)
+#else
+/* Remove the following two lines once the gdb bug is fixed.  */
+#define STABS_CURRENT_FILE(name)                                             \
+  STABS_CURRENT_FILE1 (#name)
+#define STABS_CURRENT_FILE1(name)                                            \
+  1: .stabs name,100,0,0,1b;
+/* Emit stabs definition lines.  We use F(0,1) and define t(0,1) as `int',
+   the same way gcc does it.  */
+#define STABS_FUN(name) STABS_FUN2(name, name##:F(0,1))
+#define STABS_FUN2(name, namestr)                                            \
+  .stabs "int:t(0,1)=r(0,1);-2147483648;2147483647;",128,0,0,0;                      \
+  .stabs #namestr,36,0,0,name;
+#define STABS_FUN_END(name)                                                  \
+  1: .stabs "",36,0,0,1b-name;
+#endif
+
+/* If compiled for profiling, call `mcount' at the start of each function.  */
+#ifdef PROF
+/* The mcount code relies on a normal frame pointer being on the stack
+   to locate our caller, so push one just for its benefit.  */
+#define CALL_MCOUNT \
+  pushl %ebp; cfi_adjust_cfa_offset (4); movl %esp, %ebp; \
+  cfi_def_cfa_register (ebp); call JUMPTARGET(mcount); \
+  popl %ebp; cfi_def_cfa (esp, 4);
+#else
+#define CALL_MCOUNT            /* Do nothing.  */
+#endif
+
+#ifdef NO_UNDERSCORES
+/* Since C identifiers are not normally prefixed with an underscore
+   on this system, the asm identifier `syscall_error' intrudes on the
+   C name space.  Make sure we use an innocuous name.  */
+#define        syscall_error   __syscall_error
+#define mcount         _mcount
+#endif
+
+#undef JUMPTARGET
+#ifdef __PIC__
+#define JUMPTARGET(name)       name##@PLT
+#define SYSCALL_PIC_SETUP \
+    pushl %ebx;                                                                      \
+    cfi_adjust_cfa_offset (4);                                               \
+    call 0f;                                                                 \
+0:  popl %ebx;                                                               \
+    cfi_adjust_cfa_offset (-4);                                                      \
+    addl $_GLOBAL_OFFSET_TABLE+[.-0b], %ebx;
+
+
+# define SETUP_PIC_REG(reg) \
+  .ifndef __x86.get_pc_thunk.reg;                                            \
+  .section .gnu.linkonce.t.__x86.get_pc_thunk.reg,"ax",@progbits;            \
+  .globl __x86.get_pc_thunk.reg;                                             \
+  .hidden __x86.get_pc_thunk.reg;                                            \
+  .type __x86.get_pc_thunk.reg,@function;                                    \
+__x86.get_pc_thunk.reg:                                                      \
+  movl (%esp), %e##reg;                                                              \
+  ret;                                                                       \
+  .size __x86.get_pc_thunk.reg, . - __x86.get_pc_thunk.reg;                  \
+  .previous;                                                                 \
+  .endif;                                                                    \
+  call __x86.get_pc_thunk.reg
+
+# define LOAD_PIC_REG(reg) \
+  SETUP_PIC_REG(reg); addl $_GLOBAL_OFFSET_TABLE_, %e##reg
+
+#else
+#define JUMPTARGET(name)       name
+#define SYSCALL_PIC_SETUP      /* Nothing.  */
+#endif
+
+/* Local label name for asm code. */
+#ifndef L
+#ifdef HAVE_ELF
+#define L(name)                .L##name
+#else
+#define L(name)                name
+#endif
+#endif
+
+#endif /* __ASSEMBLER__ */
+
+#ifndef offsetof
+# define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+
+/* For Linux we can use the system call table in the header file
+       /usr/include/asm/unistd.h
+   of the kernel.  But these symbols do not follow the SYS_* syntax
+   so we have to redefine the `SYS_ify' macro here.  */
+#undef SYS_ify
+#define SYS_ify(syscall_name)  __NR_##syscall_name
+
+#if defined USE_DL_SYSINFO \
+    && (!defined NOT_IN_libc || defined IS_IN_libpthread)
+# define I386_USE_SYSENTER     1
+#else
+# undef I386_USE_SYSENTER
+#endif
+
+#ifdef __ASSEMBLER__
+
+/* Linux uses a negative return value to indicate syscall errors,
+   unlike most Unices, which use the condition codes' carry flag.
+
+   Since version 2.1 the return value of a system call might be
+   negative even if the call succeeded.  E.g., the `lseek' system call
+   might return a large offset.  Therefore we must not anymore test
+   for < 0, but test for a real error by making sure the value in %eax
+   is a real error number.  Linus said he will make sure the no syscall
+   returns a value in -1 .. -4095 as a valid result so we can savely
+   test with -4095.  */
+
+/* We don't want the label for the error handle to be global when we define
+   it here.  */
+#ifdef __PIC__
+# define SYSCALL_ERROR_LABEL 0f
+#else
+# define SYSCALL_ERROR_LABEL syscall_error
+#endif
+
+#undef PSEUDO
+#define        PSEUDO(name, syscall_name, args)                                      \
+  .text;                                                                     \
+  ENTRY (name)                                                               \
+    DO_CALL (syscall_name, args);                                            \
+    cmpl $-4095, %eax;                                                       \
+    jae SYSCALL_ERROR_LABEL;                                                 \
+  L(pseudo_end):
+
+#undef PSEUDO_END
+#define        PSEUDO_END(name)                                                      \
+  SYSCALL_ERROR_HANDLER                                                              \
+  END (name)
+
+#undef PSEUDO_NOERRNO
+#define        PSEUDO_NOERRNO(name, syscall_name, args)                              \
+  .text;                                                                     \
+  ENTRY (name)                                                               \
+    DO_CALL (syscall_name, args)
+
+#undef PSEUDO_END_NOERRNO
+#define        PSEUDO_END_NOERRNO(name)                                              \
+  END (name)
+
+#define ret_NOERRNO ret
+
+/* The function has to return the error code.  */
+#undef PSEUDO_ERRVAL
+#define        PSEUDO_ERRVAL(name, syscall_name, args) \
+  .text;                                                                     \
+  ENTRY (name)                                                               \
+    DO_CALL (syscall_name, args);                                            \
+    negl %eax
+
+#undef PSEUDO_END_ERRVAL
+#define        PSEUDO_END_ERRVAL(name) \
+  END (name)
+
+#define ret_ERRVAL ret
+
+#ifndef __PIC__
+# define SYSCALL_ERROR_HANDLER /* Nothing here; code in sysdep.S is used.  */
+#else
+
+# ifdef RTLD_PRIVATE_ERRNO
+#  define SYSCALL_ERROR_HANDLER                                                      \
+0:SETUP_PIC_REG(cx);                                                         \
+  addl $_GLOBAL_OFFSET_TABLE_, %ecx;                                         \
+  xorl %edx, %edx;                                                           \
+  subl %eax, %edx;                                                           \
+  movl %edx, rtld_errno@GOTOFF(%ecx);                                        \
+  orl $-1, %eax;                                                             \
+  jmp L(pseudo_end);
+
+# elif defined _LIBC_REENTRANT
+
+#  if USE___THREAD
+#   ifndef NOT_IN_libc
+#    define SYSCALL_ERROR_ERRNO __libc_errno
+#   else
+#    define SYSCALL_ERROR_ERRNO errno
+#   endif
+#   define SYSCALL_ERROR_HANDLER                                             \
+0:SETUP_PIC_REG (cx);                                                        \
+  addl $_GLOBAL_OFFSET_TABLE_, %ecx;                                         \
+  movl SYSCALL_ERROR_ERRNO@GOTNTPOFF(%ecx), %ecx;                            \
+  xorl %edx, %edx;                                                           \
+  subl %eax, %edx;                                                           \
+  SYSCALL_ERROR_HANDLER_TLS_STORE (%edx, %ecx);                                      \
+  orl $-1, %eax;                                                             \
+  jmp L(pseudo_end);
+#   ifndef NO_TLS_DIRECT_SEG_REFS
+#    define SYSCALL_ERROR_HANDLER_TLS_STORE(src, destoff)                    \
+  movl src, %gs:(destoff)
+#   else
+#    define SYSCALL_ERROR_HANDLER_TLS_STORE(src, destoff)                    \
+  addl %gs:0, destoff;                                                       \
+  movl src, (destoff)
+#   endif
+#  else
+#   define SYSCALL_ERROR_HANDLER                                             \
+0:pushl %ebx;                                                                \
+  cfi_adjust_cfa_offset (4);                                                 \
+  cfi_rel_offset (ebx, 0);                                                   \
+  SETUP_PIC_REG (bx);                                                        \
+  addl $_GLOBAL_OFFSET_TABLE_, %ebx;                                         \
+  xorl %edx, %edx;                                                           \
+  subl %eax, %edx;                                                           \
+  pushl %edx;                                                                \
+  cfi_adjust_cfa_offset (4);                                                 \
+  call __errno_location@PLT;                                                 \
+  popl %ecx;                                                                 \
+  cfi_adjust_cfa_offset (-4);                                                \
+  popl %ebx;                                                                 \
+  cfi_adjust_cfa_offset (-4);                                                \
+  cfi_restore (ebx);                                                         \
+  movl %ecx, (%eax);                                                         \
+  orl $-1, %eax;                                                             \
+  jmp L(pseudo_end);
+/* A quick note: it is assumed that the call to `__errno_location' does
+   not modify the stack!  */
+#  endif
+# else
+/* Store (- %eax) into errno through the GOT.  */
+#  define SYSCALL_ERROR_HANDLER                                                      \
+0:SETUP_PIC_REG(cx);                                                         \
+  addl $_GLOBAL_OFFSET_TABLE_, %ecx;                                         \
+  xorl %edx, %edx;                                                           \
+  subl %eax, %edx;                                                           \
+  movl errno@GOT(%ecx), %ecx;                                                \
+  movl %edx, (%ecx);                                                         \
+  orl $-1, %eax;                                                             \
+  jmp L(pseudo_end);
+# endif        /* _LIBC_REENTRANT */
+#endif /* __PIC__ */
+
+
+/* The original calling convention for system calls on Linux/i386 is
+   to use int $0x80.  */
+#ifdef I386_USE_SYSENTER
+# ifdef SHARED
+#  define ENTER_KERNEL call *%gs:SYSINFO_OFFSET
+# else
+#  define ENTER_KERNEL call *_dl_sysinfo
+# endif
+#else
+# define ENTER_KERNEL int $0x80
+#endif
+
+/* Linux takes system call arguments in registers:
+
+       syscall number  %eax         call-clobbered
+       arg 1           %ebx         call-saved
+       arg 2           %ecx         call-clobbered
+       arg 3           %edx         call-clobbered
+       arg 4           %esi         call-saved
+       arg 5           %edi         call-saved
+       arg 6           %ebp         call-saved
+
+   The stack layout upon entering the function is:
+
+       24(%esp)        Arg# 6
+       20(%esp)        Arg# 5
+       16(%esp)        Arg# 4
+       12(%esp)        Arg# 3
+        8(%esp)        Arg# 2
+        4(%esp)        Arg# 1
+         (%esp)        Return address
+
+   (Of course a function with say 3 arguments does not have entries for
+   arguments 4, 5, and 6.)
+
+   The following code tries hard to be optimal.  A general assumption
+   (which is true according to the data books I have) is that
+
+       2 * xchg        is more expensive than  pushl + movl + popl
+
+   Beside this a neat trick is used.  The calling conventions for Linux
+   tell that among the registers used for parameters %ecx and %edx need
+   not be saved.  Beside this we may clobber this registers even when
+   they are not used for parameter passing.
+
+   As a result one can see below that we save the content of the %ebx
+   register in the %edx register when we have less than 3 arguments
+   (2 * movl is less expensive than pushl + popl).
+
+   Second unlike for the other registers we don't save the content of
+   %ecx and %edx when we have more than 1 and 2 registers resp.
+
+   The code below might look a bit long but we have to take care for
+   the pipelined processors (i586).  Here the `pushl' and `popl'
+   instructions are marked as NP (not pairable) but the exception is
+   two consecutive of these instruction.  This gives no penalty on
+   other processors though.  */
+
+#undef DO_CALL
+#define DO_CALL(syscall_name, args)                                          \
+    PUSHARGS_##args                                                          \
+    DOARGS_##args                                                            \
+    movl $SYS_ify (syscall_name), %eax;                                              \
+    ENTER_KERNEL                                                             \
+    POPARGS_##args
+
+#define PUSHARGS_0     /* No arguments to push.  */
+#define        DOARGS_0        /* No arguments to frob.  */
+#define        POPARGS_0       /* No arguments to pop.  */
+#define        _PUSHARGS_0     /* No arguments to push.  */
+#define _DOARGS_0(n)   /* No arguments to frob.  */
+#define        _POPARGS_0      /* No arguments to pop.  */
+
+#define PUSHARGS_1     movl %ebx, %edx; L(SAVEBX1): PUSHARGS_0
+#define        DOARGS_1        _DOARGS_1 (4)
+#define        POPARGS_1       POPARGS_0; movl %edx, %ebx; L(RESTBX1):
+#define        _PUSHARGS_1     pushl %ebx; cfi_adjust_cfa_offset (4); \
+                       cfi_rel_offset (ebx, 0); L(PUSHBX1): _PUSHARGS_0
+#define _DOARGS_1(n)   movl n(%esp), %ebx; _DOARGS_0(n-4)
+#define        _POPARGS_1      _POPARGS_0; popl %ebx; cfi_adjust_cfa_offset (-4); \
+                       cfi_restore (ebx); L(POPBX1):
+
+#define PUSHARGS_2     PUSHARGS_1
+#define        DOARGS_2        _DOARGS_2 (8)
+#define        POPARGS_2       POPARGS_1
+#define _PUSHARGS_2    _PUSHARGS_1
+#define        _DOARGS_2(n)    movl n(%esp), %ecx; _DOARGS_1 (n-4)
+#define        _POPARGS_2      _POPARGS_1
+
+#define PUSHARGS_3     _PUSHARGS_2
+#define DOARGS_3       _DOARGS_3 (16)
+#define POPARGS_3      _POPARGS_3
+#define _PUSHARGS_3    _PUSHARGS_2
+#define _DOARGS_3(n)   movl n(%esp), %edx; _DOARGS_2 (n-4)
+#define _POPARGS_3     _POPARGS_2
+
+#define PUSHARGS_4     _PUSHARGS_4
+#define DOARGS_4       _DOARGS_4 (24)
+#define POPARGS_4      _POPARGS_4
+#define _PUSHARGS_4    pushl %esi; cfi_adjust_cfa_offset (4); \
+                       cfi_rel_offset (esi, 0); L(PUSHSI1): _PUSHARGS_3
+#define _DOARGS_4(n)   movl n(%esp), %esi; _DOARGS_3 (n-4)
+#define _POPARGS_4     _POPARGS_3; popl %esi; cfi_adjust_cfa_offset (-4); \
+                       cfi_restore (esi); L(POPSI1):
+
+#define PUSHARGS_5     _PUSHARGS_5
+#define DOARGS_5       _DOARGS_5 (32)
+#define POPARGS_5      _POPARGS_5
+#define _PUSHARGS_5    pushl %edi; cfi_adjust_cfa_offset (4); \
+                       cfi_rel_offset (edi, 0); L(PUSHDI1): _PUSHARGS_4
+#define _DOARGS_5(n)   movl n(%esp), %edi; _DOARGS_4 (n-4)
+#define _POPARGS_5     _POPARGS_4; popl %edi; cfi_adjust_cfa_offset (-4); \
+                       cfi_restore (edi); L(POPDI1):
+
+#define PUSHARGS_6     _PUSHARGS_6
+#define DOARGS_6       _DOARGS_6 (40)
+#define POPARGS_6      _POPARGS_6
+#define _PUSHARGS_6    pushl %ebp; cfi_adjust_cfa_offset (4); \
+                       cfi_rel_offset (ebp, 0); L(PUSHBP1): _PUSHARGS_5
+#define _DOARGS_6(n)   movl n(%esp), %ebp; _DOARGS_5 (n-4)
+#define _POPARGS_6     _POPARGS_5; popl %ebp; cfi_adjust_cfa_offset (-4); \
+                       cfi_restore (ebp); L(POPBP1):
+
+#endif /* __ASSEMBLER__ */
+
+
+/* Pointer mangling support.  */
+#if defined NOT_IN_libc && defined IS_IN_rtld
+/* We cannot use the thread descriptor because in ld.so we use setjmp
+   earlier than the descriptor is initialized.  Using a global variable
+   is too complicated here since we have no PC-relative addressing mode.  */
+#else
+# ifdef __ASSEMBLER__
+#  define PTR_MANGLE(reg)      xorl %gs:POINTER_GUARD, reg;                  \
+                               roll $9, reg
+#  define PTR_DEMANGLE(reg)    rorl $9, reg;                                 \
+                               xorl %gs:POINTER_GUARD, reg
+# else
+#  define PTR_MANGLE(var)      __asm__ ("xorl %%gs:%c2, %0\n"                \
+                                    "roll $9, %0"                            \
+                                    : "=r" (var)                             \
+                                    : "0" (var),                             \
+                                      "i" (offsetof (tcbhead_t,              \
+                                                     pointer_guard)))
+#  define PTR_DEMANGLE(var)    __asm__ ("rorl $9, %0\n"                              \
+                                    "xorl %%gs:%c2, %0"                      \
+                                    : "=r" (var)                             \
+                                    : "0" (var),                             \
+                                      "i" (offsetof (tcbhead_t,              \
+                                                     pointer_guard)))
+# endif
+#endif
+
+#endif /* linux/i386/sysdep.h */
index 8005ff1..c9db2f4 100644 (file)
 
 __vfork:
        popl %ecx
+
+#ifdef SAVE_PID
+       SAVE_PID
+#endif
+
        movl $__NR_vfork,%eax
        int $0x80
        pushl %ecx
+
+#ifdef RESTORE_PID
+       RESTORE_PID
+#endif
+
        cmpl $-4095,%eax
        jae __syscall_error
        ret
index 2570a69..73e6499 100644 (file)
@@ -7,11 +7,15 @@
 
 CSRC := \
        __longjmp.c  brk.c setjmp_aux.c mmap.c __syscall_error.c \
-       cacheflush.c pread_write.c sysmips.c _test_and_set.c sigaction.c \
+       cacheflush.c pread_write.c sysmips.c _test_and_set.c \
        readahead.c
 
 ifeq ($(UCLIBC_HAS_ADVANCED_REALTIME),y)
-        CSRC += posix_fadvise.c posix_fadvise64.c
+CSRC += posix_fadvise.c posix_fadvise64.c
+endif
+
+ifneq ($(UCLIBC_HAS_THREADS_NATIVE),y)
+CSRC += sigaction.c
 endif
 
 SSRC := bsd-_setjmp.S bsd-setjmp.S setjmp.S clone.S syscall.S pipe.S
index 15fa295..a53d5c4 100644 (file)
@@ -132,3 +132,4 @@ L(__thread_start):
         jal             _exit
 #endif
        .end  __thread_start
+weak_alias(clone, __clone)
index 79d1439..d424ed3 100644 (file)
@@ -472,4 +472,20 @@ symbol             =       value
 # define MTC0  dmtc0
 #endif
 
+/* The MIPS archtectures do not have a uniform memory model.  Particular
+   platforms may provide additional guarantees - for instance, the R4000
+   LL and SC instructions implicitly perform a SYNC, and the 4K promises
+   strong ordering.
+
+   However, in the absence of those guarantees, we must assume weak ordering
+   and SYNC explicitly where necessary.
+
+   Some obsolete MIPS processors may not support the SYNC instruction.  This
+   applies to "true" MIPS I processors; most of the processors which compile
+   using MIPS I implement parts of MIPS II.  */
+
+#ifndef MIPS_SYNC
+# define MIPS_SYNC      sync
+#endif
+
 #endif /* sys/asm.h */
index 9d2c4c1..2d94130 100644 (file)
@@ -20,6 +20,8 @@
 #ifndef _SYS_REGDEF_H
 #define _SYS_REGDEF_H
 
+#include <sgidefs.h>
+
 /*
  * Symbolic register names for 32 bit ABI
  */
diff --git a/libc/sysdeps/linux/mips/syscall_error.S b/libc/sysdeps/linux/mips/syscall_error.S
new file mode 100644 (file)
index 0000000..1e348ad
--- /dev/null
@@ -0,0 +1,82 @@
+/* Copyright (C) 1992, 1993, 1994, 1997, 1998, 1999, 2000, 2002, 2003
+   Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Brendan Kehoe (brendan@zen.org).
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sys/asm.h>
+#include <sysdep.h>
+#include <bits/errno.h>
+
+#ifdef __UCLIBC_HAS_THREADS__
+
+LOCALSZ= 3
+FRAMESZ= (((NARGSAVE+LOCALSZ)*SZREG)+ALSZ)&ALMASK
+RAOFF= FRAMESZ-(1*SZREG)
+GPOFF= FRAMESZ-(2*SZREG)
+V0OFF= FRAMESZ-(3*SZREG)
+
+ENTRY(__syscall_error)
+#ifdef __PIC__
+       .set noat
+       SETUP_GPX (AT)
+       .set at
+#endif
+       PTR_SUBU sp, FRAMESZ
+       .set noat
+       SETUP_GPX64(GPOFF,AT)
+       .set at
+#ifdef __PIC__
+       SAVE_GP(GPOFF)
+#endif
+       REG_S   v0, V0OFF(sp)
+       REG_S   ra, RAOFF(sp)
+
+       /* Find our per-thread errno address  */
+       jal     __errno_location
+
+       /* Store the error value.  */
+       REG_L   t0, V0OFF(sp)
+       sw      t0, 0(v0)
+
+       /* And just kick back a -1.  */
+       REG_L   ra, RAOFF(sp)
+       RESTORE_GP64
+       PTR_ADDU sp, FRAMESZ
+       li      v0, -1
+       j       ra
+       END(__syscall_error)
+
+#else /* __UCLIBC_HAS_THREADS__ */
+
+
+ENTRY(__syscall_error)
+#ifdef __PIC__
+       SETUP_GPX (AT)
+#endif
+       SETUP_GPX64 (t9, AT)
+
+       /* Store it in errno... */
+       sw v0, errno
+
+       /* And just kick back a -1.  */
+       li v0, -1
+
+       RESTORE_GP64
+       j ra
+       END(__syscall_error)
+#endif  /* __UCLIBC_HAS_THREADS__ */
diff --git a/libc/sysdeps/linux/mips/sysdep.h b/libc/sysdeps/linux/mips/sysdep.h
new file mode 100644 (file)
index 0000000..56d1590
--- /dev/null
@@ -0,0 +1,391 @@
+/* Copyright (C) 1992, 1995, 1997, 1999, 2000, 2002, 2003, 2004
+   Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Brendan Kehoe (brendan@zen.org).
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _LINUX_MIPS_SYSDEP_H
+#define _LINUX_MIPS_SYSDEP_H 1
+
+#include <sgidefs.h>
+#include <common/sysdep.h>
+
+/* For Linux we can use the system call table in the header file
+   /usr/include/asm/unistd.h
+   of the kernel.  But these symbols do not follow the SYS_* syntax
+   so we have to redefine the `SYS_ify' macro here.  */
+
+#undef SYS_ify
+#ifdef __STDC__
+# define SYS_ify(syscall_name) __NR_##syscall_name
+#else
+# define SYS_ify(syscall_name) __NR_/**/syscall_name
+#endif
+
+#ifdef __ASSEMBLER__
+
+#include <regdef.h>
+
+#define ENTRY(name)                                    \
+  .globl name;                                         \
+  .align 2;                                            \
+  .ent name,0;                                         \
+  name##:
+
+#undef END
+#define        END(function)                                   \
+               .end    function;                       \
+               .size   function,.-function
+
+#define ret    j ra ; nop
+
+#undef PSEUDO_END
+#define PSEUDO_END(sym) .end sym; .size sym,.-sym
+
+#define PSEUDO_NOERRNO(name, syscall_name, args)       \
+  .align 2;                                            \
+  ENTRY(name)                                          \
+  .set noreorder;                                      \
+  li v0, SYS_ify(syscall_name);                                \
+  syscall
+
+#undef PSEUDO_END_NOERRNO
+#define PSEUDO_END_NOERRNO(sym) .end sym; .size sym,.-sym
+
+#define ret_NOERRNO ret
+
+#define PSEUDO_ERRVAL(name, syscall_name, args)                \
+  .align 2;                                            \
+  ENTRY(name)                                          \
+  .set noreorder;                                      \
+  li v0, SYS_ify(syscall_name);                                \
+  syscall
+
+#undef PSEUDO_END_ERRVAL
+#define PSEUDO_END_ERRVAL(sym) .end sym; .size sym,.-sym
+
+#define ret_ERRVAL ret
+
+#define r0     v0
+#define r1     v1
+/* The mips move insn is d,s.  */
+#define MOVE(x,y)      move y , x
+
+#if _MIPS_SIM == _ABIO32
+# define L(label) $L ## label
+#else
+# define L(label) .L ## label
+#endif
+
+/* Note that while it's better structurally, going back to call __syscall_error
+   can make things confusing if you're debugging---it looks like it's jumping
+   backwards into the previous fn.  */
+
+#ifdef __PIC__
+#define PSEUDO(name, syscall_name, args)               \
+  .align 2;                                            \
+  99: la t9,__syscall_error;                           \
+  jr t9;                                               \
+  ENTRY(name)                                          \
+  .set noreorder;                                      \
+  .cpload t9;                                          \
+  li v0, SYS_ify(syscall_name);                                \
+  syscall;                                             \
+  .set reorder;                                                \
+  bne a3, zero, 99b;                                   \
+L(syse1):
+#else
+#define PSEUDO(name, syscall_name, args)               \
+  .set noreorder;                                      \
+  .align 2;                                            \
+  99: j __syscall_error;                               \
+  nop;                                                 \
+  ENTRY(name)                                          \
+  .set noreorder;                                      \
+  li v0, SYS_ify(syscall_name);                                \
+  syscall;                                             \
+  .set reorder;                                                \
+  bne a3, zero, 99b;                                   \
+L(syse1):
+#endif
+
+/* We don't want the label for the error handler to be visible in the symbol
+   table when we define it here.  */
+#ifdef __PIC__
+# define SYSCALL_ERROR_LABEL 99b
+#endif
+
+#else   /* ! __ASSEMBLER__ */
+
+/* Define a macro which expands into the inline wrapper code for a system
+   call.  */
+#undef INLINE_SYSCALL
+#define INLINE_SYSCALL(name, nr, args...)                              \
+  ({ INTERNAL_SYSCALL_DECL(err);                                       \
+     long result_var = INTERNAL_SYSCALL (name, err, nr, args);         \
+     if ( INTERNAL_SYSCALL_ERROR_P (result_var, err) )                 \
+       {                                                               \
+        __set_errno (INTERNAL_SYSCALL_ERRNO (result_var, err));        \
+        result_var = -1L;                                              \
+       }                                                               \
+     result_var; })
+
+#undef INTERNAL_SYSCALL_DECL
+#define INTERNAL_SYSCALL_DECL(err) long err
+
+#undef INTERNAL_SYSCALL_ERROR_P
+#define INTERNAL_SYSCALL_ERROR_P(val, err)   ((long) (err))
+
+#undef INTERNAL_SYSCALL_ERRNO
+#define INTERNAL_SYSCALL_ERRNO(val, err)     (val)
+
+#undef INTERNAL_SYSCALL
+#define INTERNAL_SYSCALL(name, err, nr, args...) \
+       internal_syscall##nr (, "li\t$2, %2\t\t\t# " #name "\n\t",      \
+                             "i" (SYS_ify (name)), err, args)
+
+#undef INTERNAL_SYSCALL_NCS
+#define INTERNAL_SYSCALL_NCS(number, err, nr, args...) \
+       internal_syscall##nr (= number, , "r" (__v0), err, args)
+#undef internal_syscall0
+#define internal_syscall0(ncs_init, cs_init, input, err, dummy...)     \
+({                                                                     \
+       long _sys_result;                                               \
+                                                                       \
+       {                                                               \
+       register long __v0 __asm__("$2") ncs_init;                      \
+       register long __a3 __asm__("$7");                               \
+       __asm__ volatile (                                              \
+       ".set\tnoreorder\n\t"                                           \
+       cs_init                                                         \
+       "syscall\n\t"                                                   \
+       ".set reorder"                                                  \
+       : "=r" (__v0), "=r" (__a3)                                      \
+       : input                                                         \
+       : __SYSCALL_CLOBBERS);                                          \
+       err = __a3;                                                     \
+       _sys_result = __v0;                                             \
+       }                                                               \
+       _sys_result;                                                    \
+})
+
+#undef internal_syscall1
+#define internal_syscall1(ncs_init, cs_init, input, err, arg1)         \
+({                                                                     \
+       long _sys_result;                                               \
+                                                                       \
+       {                                                               \
+       register long __v0 __asm__("$2") ncs_init;                      \
+       register long __a0 __asm__("$4") = (long) arg1;                 \
+       register long __a3 __asm__("$7");                               \
+       __asm__ volatile (                                              \
+       ".set\tnoreorder\n\t"                                           \
+       cs_init                                                         \
+       "syscall\n\t"                                                   \
+       ".set reorder"                                                  \
+       : "=r" (__v0), "=r" (__a3)                                      \
+       : input, "r" (__a0)                                             \
+       : __SYSCALL_CLOBBERS);                                          \
+       err = __a3;                                                     \
+       _sys_result = __v0;                                             \
+       }                                                               \
+       _sys_result;                                                    \
+})
+
+#undef internal_syscall2
+#define internal_syscall2(ncs_init, cs_init, input, err, arg1, arg2)   \
+({                                                                     \
+       long _sys_result;                                               \
+                                                                       \
+       {                                                               \
+       register long __v0 __asm__("$2") ncs_init;                      \
+       register long __a0 __asm__("$4") = (long) arg1;                 \
+       register long __a1 __asm__("$5") = (long) arg2;                 \
+       register long __a3 __asm__("$7");                               \
+       __asm__ volatile (                                              \
+       ".set\tnoreorder\n\t"                                           \
+       cs_init                                                         \
+       "syscall\n\t"                                                   \
+       ".set\treorder"                                                 \
+       : "=r" (__v0), "=r" (__a3)                                      \
+       : input, "r" (__a0), "r" (__a1)                                 \
+       : __SYSCALL_CLOBBERS);                                          \
+       err = __a3;                                                     \
+       _sys_result = __v0;                                             \
+       }                                                               \
+       _sys_result;                                                    \
+})
+
+#undef internal_syscall3
+#define internal_syscall3(ncs_init, cs_init, input, err, arg1, arg2, arg3)\
+({                                                                     \
+       long _sys_result;                                               \
+                                                                       \
+       {                                                               \
+       register long __v0 __asm__("$2") ncs_init;                      \
+       register long __a0 __asm__("$4") = (long) arg1;                 \
+       register long __a1 __asm__("$5") = (long) arg2;                 \
+       register long __a2 __asm__("$6") = (long) arg3;                 \
+       register long __a3 __asm__("$7");                               \
+       __asm__ volatile (                                              \
+       ".set\tnoreorder\n\t"                                           \
+       cs_init                                                         \
+       "syscall\n\t"                                                   \
+       ".set\treorder"                                                 \
+       : "=r" (__v0), "=r" (__a3)                                      \
+       : input, "r" (__a0), "r" (__a1), "r" (__a2)                     \
+       : __SYSCALL_CLOBBERS);                                          \
+       err = __a3;                                                     \
+       _sys_result = __v0;                                             \
+       }                                                               \
+       _sys_result;                                                    \
+})
+
+#undef internal_syscall4
+#define internal_syscall4(ncs_init, cs_init, input, err, arg1, arg2, arg3, arg4)\
+({                                                                     \
+       long _sys_result;                                               \
+                                                                       \
+       {                                                               \
+       register long __v0 __asm__("$2") ncs_init;                      \
+       register long __a0 __asm__("$4") = (long) arg1;                 \
+       register long __a1 __asm__("$5") = (long) arg2;                 \
+       register long __a2 __asm__("$6") = (long) arg3;                 \
+       register long __a3 __asm__("$7") = (long) arg4;                 \
+       __asm__ volatile (                                              \
+       ".set\tnoreorder\n\t"                                           \
+       cs_init                                                         \
+       "syscall\n\t"                                                   \
+       ".set\treorder"                                                 \
+       : "=r" (__v0), "+r" (__a3)                                      \
+       : input, "r" (__a0), "r" (__a1), "r" (__a2)                     \
+       : __SYSCALL_CLOBBERS);                                          \
+       err = __a3;                                                     \
+       _sys_result = __v0;                                             \
+       }                                                               \
+       _sys_result;                                                    \
+})
+
+/* We need to use a frame pointer for the functions in which we
+   adjust $sp around the syscall, or debug information and unwind
+   information will be $sp relative and thus wrong during the syscall.  As
+   of GCC 3.4.3, this is sufficient.  */
+#define FORCE_FRAME_POINTER alloca (4)
+
+#undef internal_syscall5
+#define internal_syscall5(ncs_init, cs_init, input, err, arg1, arg2, arg3, arg4, arg5)\
+({                                                                     \
+       long _sys_result;                                               \
+                                                                       \
+       FORCE_FRAME_POINTER;                                            \
+       {                                                               \
+       register long __v0 __asm__("$2") ncs_init;                      \
+       register long __a0 __asm__("$4") = (long) arg1;                 \
+       register long __a1 __asm__("$5") = (long) arg2;                 \
+       register long __a2 __asm__("$6") = (long) arg3;                 \
+       register long __a3 __asm__("$7") = (long) arg4;                 \
+       __asm__ volatile (                                              \
+       ".set\tnoreorder\n\t"                                           \
+       "subu\t$29, 32\n\t"                                             \
+       "sw\t%6, 16($29)\n\t"                                           \
+       cs_init                                                         \
+       "syscall\n\t"                                                   \
+       "addiu\t$29, 32\n\t"                                            \
+       ".set\treorder"                                                 \
+       : "=r" (__v0), "+r" (__a3)                                      \
+       : input, "r" (__a0), "r" (__a1), "r" (__a2),                    \
+         "r" ((long)arg5)                                              \
+       : __SYSCALL_CLOBBERS);                                          \
+       err = __a3;                                                     \
+       _sys_result = __v0;                                             \
+       }                                                               \
+       _sys_result;                                                    \
+})
+
+#undef internal_syscall6
+#define internal_syscall6(ncs_init, cs_init, input, err, arg1, arg2, arg3, arg4, arg5, arg6)\
+({                                                                     \
+       long _sys_result;                                               \
+                                                                       \
+       FORCE_FRAME_POINTER;                                            \
+       {                                                               \
+       register long __v0 __asm__("$2") ncs_init;                      \
+       register long __a0 __asm__("$4") = (long) arg1;                 \
+       register long __a1 __asm__("$5") = (long) arg2;                 \
+       register long __a2 __asm__("$6") = (long) arg3;                 \
+       register long __a3 __asm__("$7") = (long) arg4;                 \
+       __asm__ volatile (                                              \
+       ".set\tnoreorder\n\t"                                           \
+       "subu\t$29, 32\n\t"                                             \
+       "sw\t%6, 16($29)\n\t"                                           \
+       "sw\t%7, 20($29)\n\t"                                           \
+       cs_init                                                         \
+       "syscall\n\t"                                                   \
+       "addiu\t$29, 32\n\t"                                            \
+       ".set\treorder"                                                 \
+       : "=r" (__v0), "+r" (__a3)                                      \
+       : input, "r" (__a0), "r" (__a1), "r" (__a2),                    \
+         "r" ((long)arg5), "r" ((long)arg6)                            \
+       : __SYSCALL_CLOBBERS);                                          \
+       err = __a3;                                                     \
+       _sys_result = __v0;                                             \
+       }                                                               \
+       _sys_result;                                                    \
+})
+
+#undef internal_syscall7
+#define internal_syscall7(ncs_init, cs_init, input, err, arg1, arg2, arg3, arg4, arg5, arg6, arg7)\
+({                                                                     \
+       long _sys_result;                                               \
+                                                                       \
+       FORCE_FRAME_POINTER;                                            \
+       {                                                               \
+       register long __v0 __asm__("$2") ncs_init;                      \
+       register long __a0 __asm__("$4") = (long) arg1;                 \
+       register long __a1 __asm__("$5") = (long) arg2;                 \
+       register long __a2 __asm__("$6") = (long) arg3;                 \
+       register long __a3 __asm__("$7") = (long) arg4;                 \
+       __asm__ volatile (                                              \
+       ".set\tnoreorder\n\t"                                           \
+       "subu\t$29, 32\n\t"                                             \
+       "sw\t%6, 16($29)\n\t"                                           \
+       "sw\t%7, 20($29)\n\t"                                           \
+       "sw\t%8, 24($29)\n\t"                                           \
+       cs_init                                                         \
+       "syscall\n\t"                                                   \
+       "addiu\t$29, 32\n\t"                                            \
+       ".set\treorder"                                                 \
+       : "=r" (__v0), "+r" (__a3)                                      \
+       : input, "r" (__a0), "r" (__a1), "r" (__a2),                    \
+         "r" ((long)arg5), "r" ((long)arg6), "r" ((long)arg7)          \
+       : __SYSCALL_CLOBBERS);                                          \
+       err = __a3;                                                     \
+       _sys_result = __v0;                                             \
+       }                                                               \
+       _sys_result;                                                    \
+})
+
+#undef __SYSCALL_CLOBBERS
+#define __SYSCALL_CLOBBERS "$1", "$3", "$8", "$9", "$10", "$11", "$12", "$13", \
+       "$14", "$15", "$24", "$25", "memory"
+
+/* Pointer mangling is not yet supported for MIPS.  */
+#define PTR_MANGLE(var) (void) (var)
+#define PTR_DEMANGLE(var) (void) (var)
+
+#endif  /* __ASSEMBLER__ */
+#endif /* _LINUX_MIPS_SYSDEP_H */
diff --git a/libc/sysdeps/linux/mips/vfork.S b/libc/sysdeps/linux/mips/vfork.S
new file mode 100644 (file)
index 0000000..8400df0
--- /dev/null
@@ -0,0 +1,97 @@
+/* Copyright (C) 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* vfork() is just a special case of clone().  */
+
+#include <sys/asm.h>
+#include <sysdep.h>
+
+#ifndef SAVE_PID
+#define SAVE_PID
+#endif
+
+#ifndef RESTORE_PID
+#define RESTORE_PID
+#endif
+
+
+/* int vfork() */
+
+       .text
+LOCALSZ= 1
+FRAMESZ= (((NARGSAVE+LOCALSZ)*SZREG)+ALSZ)&ALMASK
+GPOFF= FRAMESZ-(1*SZREG)
+NESTED(__vfork,FRAMESZ,sp)
+#ifdef __PIC__
+       SETUP_GP
+#endif
+       PTR_SUBU sp, FRAMESZ
+       SETUP_GP64 (a5, __vfork)
+#ifdef __PIC__
+       SAVE_GP (GPOFF)
+#endif
+#ifdef PROF
+# if (_MIPS_SIM != _ABIO32)
+       PTR_S           a5, GPOFF(sp)
+# endif
+       .set            noat
+       move            $1, ra
+# if (_MIPS_SIM == _ABIO32)
+       subu            sp,sp,8
+# endif
+       jal             _mcount
+       .set            at
+# if (_MIPS_SIM != _ABIO32)
+       PTR_L           a5, GPOFF(sp)
+# endif
+#endif
+
+       PTR_ADDU        sp, FRAMESZ
+
+       SAVE_PID
+
+       li              a0, 0x4112      /* CLONE_VM | CLONE_VFORK | SIGCHLD */
+       move            a1, sp
+
+       /* Do the system call */
+       li              v0,__NR_clone
+       syscall
+
+       RESTORE_PID
+
+       bnez            a3,L(error)
+
+       /* Successful return from the parent or child.  */
+       RESTORE_GP64
+       j               ra
+       nop
+
+       /* Something bad happened -- no child created.  */
+L(error):
+#ifdef __PIC__
+       PTR_LA          t9, __syscall_error
+       RESTORE_GP64
+       jr              t9
+#else
+       RESTORE_GP64
+       j               __syscall_error
+#endif
+       END(__vfork)
+
+.weak vfork;
+       vfork = __vfork
index 31beda1..3e32e10 100644 (file)
@@ -7,6 +7,6 @@
 #
 
 CSRC := \
-       mmap.c pipe.c __init_brk.c brk.c sbrk.c pread_write.c cacheflush.c
+       mmap.c pipe.c __init_brk.c brk.c sbrk.c pread_write.c longjmp.c cacheflush.c
 
-SSRC := setjmp.S __longjmp.S vfork.S clone.S ___fpscr_values.S
+SSRC := setjmp.S __longjmp.S ___fpscr_values.S
index 6bb7255..a099b43 100644 (file)
@@ -54,6 +54,10 @@ typedef uintmax_t uatomic_max_t;
     Japan. http://lc.linux.or.jp/lc2002/papers/niibe0919h.pdf (in
     Japanese).
 
+    Niibe Yutaka, "gUSA: User Space Atomicity with Little Kernel
+    Modification", LinuxTag 2003, Rome.
+    http://www.semmel.ch/Linuxtag-DVD/talks/170/paper.html (in English).
+
     B.N. Bershad, D. Redell, and J. Ellis, "Fast Mutual Exclusion for
     Uniprocessors",  Proceedings of the Fifth Architectural Support for
     Programming Languages and Operating Systems (ASPLOS), pp. 223-233,
@@ -65,56 +69,44 @@ typedef uintmax_t uatomic_max_t;
       r1:     saved stack pointer
 */
 
-#define __arch_compare_and_exchange_val_8_acq(mem, newval, oldval) \
-  ({ __typeof (*(mem)) __result; \
-     __asm__ __volatile__ ("\
+/* Avoid having lots of different versions of compare and exchange,
+   by having this one complicated version. Parameters:
+      bwl:     b, w or l for 8, 16 and 32 bit versions.
+      version: val or bool, depending on whether the result is the
+               previous value or a bool indicating whether the transfer
+               did happen (note this needs inverting before being
+               returned in atomic_compare_and_exchange_bool).
+*/
+
+#define __arch_compare_and_exchange_n(mem, newval, oldval, bwl, version) \
+  ({ signed long __result; \
+     __asm __volatile ("\
        .align 2\n\
        mova 1f,r0\n\
        nop\n\
        mov r15,r1\n\
        mov #-8,r15\n\
-     0: mov.b @%1,%0\n\
+     0: mov." #bwl " @%1,%0\n\
        cmp/eq %0,%3\n\
        bf 1f\n\
-       mov.b %2,@%1\n\
-     1: mov r1,r15"\
-       : "=&r" (__result) : "r" (mem), "r" (newval), "r" (oldval) \
-       : "r0", "r1", "t", "memory"); \
+       mov." #bwl " %2,@%1\n\
+     1: mov r1,r15\n\
+     .ifeqs \"bool\",\"" #version "\"\n\
+        movt %0\n\
+     .endif\n"                                 \
+       : "=&r" (__result)                      \
+       : "r" (mem), "r" (newval), "r" (oldval) \
+       : "r0", "r1", "t", "memory");           \
      __result; })
 
+#define __arch_compare_and_exchange_val_8_acq(mem, newval, oldval) \
+  __arch_compare_and_exchange_n(mem, newval, (int8_t)(oldval), b, val)
+
 #define __arch_compare_and_exchange_val_16_acq(mem, newval, oldval) \
-  ({ __typeof (*(mem)) __result; \
-     __asm__ __volatile__ ("\
-       .align 2\n\
-       mova 1f,r0\n\
-       nop\n\
-       mov r15,r1\n\
-       mov #-8,r15\n\
-     0: mov.w @%1,%0\n\
-       cmp/eq %0,%3\n\
-       bf 1f\n\
-       mov.w %2,@%1\n\
-     1: mov r1,r15"\
-       : "=&r" (__result) : "r" (mem), "r" (newval), "r" (oldval) \
-       : "r0", "r1", "t", "memory"); \
-     __result; })
+  __arch_compare_and_exchange_n(mem, newval, (int16_t)(oldval), w, val)
 
 #define __arch_compare_and_exchange_val_32_acq(mem, newval, oldval) \
-  ({ __typeof (*(mem)) __result; \
-     __asm__ __volatile__ ("\
-       .align 2\n\
-       mova 1f,r0\n\
-       nop\n\
-       mov r15,r1\n\
-       mov #-8,r15\n\
-     0: mov.l @%1,%0\n\
-       cmp/eq %0,%3\n\
-       bf 1f\n\
-       mov.l %2,@%1\n\
-     1: mov r1,r15"\
-       : "=&r" (__result) : "r" (mem), "r" (newval), "r" (oldval) \
-       : "r0", "r1", "t", "memory"); \
-     __result; })
+  __arch_compare_and_exchange_n(mem, newval, (int32_t)(oldval), l, val)
 
 /* XXX We do not really need 64-bit compare-and-exchange.  At least
    not in the moment.  Using it would mean causing portability
@@ -122,298 +114,180 @@ typedef uintmax_t uatomic_max_t;
    such an operation.  So don't define any code for now.  */
 
 # define __arch_compare_and_exchange_val_64_acq(mem, newval, oldval) \
-  (abort (), (__typeof (*mem)) 0)
+  (abort (), 0)
+
+/* For "bool" routines, return if the exchange did NOT occur */
+
+#define __arch_compare_and_exchange_bool_8_acq(mem, newval, oldval) \
+  (! __arch_compare_and_exchange_n(mem, newval, (int8_t)(oldval), b, bool))
+
+#define __arch_compare_and_exchange_bool_16_acq(mem, newval, oldval) \
+  (! __arch_compare_and_exchange_n(mem, newval, (int16_t)(oldval), w, bool))
+
+#define __arch_compare_and_exchange_bool_32_acq(mem, newval, oldval) \
+  (! __arch_compare_and_exchange_n(mem, newval, (int32_t)(oldval), l, bool))
+
+# define __arch_compare_and_exchange_bool_64_acq(mem, newval, oldval) \
+  (abort (), 0)
+
+/* Similar to the above, have one template which can be used in a
+   number of places. This version returns both the old and the new
+   values of the location. Parameters:
+      bwl:     b, w or l for 8, 16 and 32 bit versions.
+      oper:    The instruction to perform on the old value.
+   Note old is not sign extended, so should be an unsigned long.
+*/
+
+#define __arch_operate_old_new_n(mem, value, old, new, bwl, oper)      \
+  (void) ({ __asm __volatile ("\
+       .align 2\n\
+       mova 1f,r0\n\
+       mov r15,r1\n\
+       nop\n\
+       mov #-8,r15\n\
+     0: mov." #bwl " @%2,%0\n\
+       mov %0,%1\n\
+       " #oper " %3,%1\n\
+       mov." #bwl " %1,@%2\n\
+     1: mov r1,r15"                    \
+       : "=&r" (old), "=&r"(new)       \
+       : "r" (mem), "r" (value)        \
+       : "r0", "r1", "memory");        \
+    })
+
+#define __arch_exchange_and_add_8_int(mem, value)                      \
+  ({ int32_t __value = (value), __new, __old;                          \
+    __arch_operate_old_new_n((mem), __value, __old, __new, b, add);    \
+    __old; })
+
+#define __arch_exchange_and_add_16_int(mem, value)                     \
+  ({ int32_t __value = (value), __new, __old;                          \
+    __arch_operate_old_new_n((mem), __value, __old, __new, w, add);    \
+    __old; })
+
+#define __arch_exchange_and_add_32_int(mem, value)                     \
+  ({ int32_t __value = (value), __new, __old;                          \
+    __arch_operate_old_new_n((mem), __value, __old, __new, l, add);    \
+    __old; })
+
+#define __arch_exchange_and_add_64_int(mem, value)                     \
+  (abort (), 0)
 
 #define atomic_exchange_and_add(mem, value) \
-  ({ __typeof (*(mem)) __result, __tmp, __value = (value); \
-     if (sizeof (*(mem)) == 1) \
-       __asm__ __volatile__ ("\
-         .align 2\n\
-         mova 1f,r0\n\
-         mov r15,r1\n\
-         mov #-6,r15\n\
-       0: mov.b @%2,%0\n\
-         add %0,%1\n\
-         mov.b %1,@%2\n\
-       1: mov r1,r15"\
-       : "=&r" (__result), "=&r" (__tmp) : "r" (mem), "1" (__value) \
-       : "r0", "r1", "memory"); \
-     else if (sizeof (*(mem)) == 2) \
-       __asm__ __volatile__ ("\
-         .align 2\n\
-         mova 1f,r0\n\
-         mov r15,r1\n\
-         mov #-6,r15\n\
-       0: mov.w @%2,%0\n\
-         add %0,%1\n\
-         mov.w %1,@%2\n\
-       1: mov r1,r15"\
-       : "=&r" (__result), "=&r" (__tmp) : "r" (mem), "1" (__value) \
-       : "r0", "r1", "memory"); \
-     else if (sizeof (*(mem)) == 4) \
-       __asm__ __volatile__ ("\
-         .align 2\n\
-         mova 1f,r0\n\
-         mov r15,r1\n\
-         mov #-6,r15\n\
-       0: mov.l @%2,%0\n\
-         add %0,%1\n\
-         mov.l %1,@%2\n\
-       1: mov r1,r15"\
-       : "=&r" (__result), "=&r" (__tmp) : "r" (mem), "1" (__value) \
-       : "r0", "r1", "memory"); \
-     else \
-       { \
-        __typeof (mem) memp = (mem); \
-        do \
-          __result = *memp; \
-        while (__arch_compare_and_exchange_val_64_acq \
-                (memp, __result + __value, __result) == __result); \
-        (void) __value; \
-       } \
-     __result; })
+  __atomic_val_bysize (__arch_exchange_and_add, int, mem, value)
+
+
+/* Again, another template. We get a slight optimisation when the old value
+   does not need to be returned. Parameters:
+      bwl:     b, w or l for 8, 16 and 32 bit versions.
+      oper:    The instruction to perform on the old value.
+*/
+
+#define __arch_operate_new_n(mem, value, bwl, oper)     \
+  ({ int32_t __value = (value), __new; \
+     __asm __volatile ("\
+       .align 2\n\
+       mova 1f,r0\n\
+       mov r15,r1\n\
+       mov #-6,r15\n\
+     0: mov." #bwl " @%1,%0\n\
+       " #oper " %2,%0\n\
+       mov." #bwl " %0,@%1\n\
+     1: mov r1,r15"                    \
+       : "=&r" (__new)                 \
+       : "r" (mem), "r" (__value)      \
+       : "r0", "r1", "memory");        \
+     __new;                            \
+  })
+
+#define __arch_add_8_int(mem, value)           \
+  __arch_operate_new_n(mem, value, b, add)
+
+#define __arch_add_16_int(mem, value)          \
+  __arch_operate_new_n(mem, value, w, add)
+
+#define __arch_add_32_int(mem, value)          \
+  __arch_operate_new_n(mem, value, l, add)
+
+#define __arch_add_64_int(mem, value)          \
+  (abort (), 0)
 
 #define atomic_add(mem, value) \
-  (void) ({ __typeof (*(mem)) __tmp, __value = (value); \
-           if (sizeof (*(mem)) == 1) \
-             __asm__ __volatile__ ("\
-               .align 2\n\
-               mova 1f,r0\n\
-               mov r15,r1\n\
-               mov #-6,r15\n\
-            0: mov.b @%1,r2\n\
-               add r2,%0\n\
-               mov.b %0,@%1\n\
-            1: mov r1,r15"\
-               : "=&r" (__tmp) : "r" (mem), "0" (__value) \
-               : "r0", "r1", "r2", "memory"); \
-           else if (sizeof (*(mem)) == 2) \
-             __asm__ __volatile__ ("\
-               .align 2\n\
-               mova 1f,r0\n\
-               mov r15,r1\n\
-               mov #-6,r15\n\
-            0: mov.w @%1,r2\n\
-               add r2,%0\n\
-               mov.w %0,@%1\n\
-            1: mov r1,r15"\
-               : "=&r" (__tmp) : "r" (mem), "0" (__value) \
-               : "r0", "r1", "r2", "memory"); \
-           else if (sizeof (*(mem)) == 4) \
-             __asm__ __volatile__ ("\
-               .align 2\n\
-               mova 1f,r0\n\
-               mov r15,r1\n\
-               mov #-6,r15\n\
-            0: mov.l @%1,r2\n\
-               add r2,%0\n\
-               mov.l %0,@%1\n\
-            1: mov r1,r15"\
-               : "=&r" (__tmp) : "r" (mem), "0" (__value) \
-               : "r0", "r1", "r2", "memory"); \
-           else \
-             { \
-               __typeof (*(mem)) oldval; \
-               __typeof (mem) memp = (mem); \
-               do \
-                 oldval = *memp; \
-               while (__arch_compare_and_exchange_val_64_acq \
-                       (memp, oldval + __value, oldval) == oldval); \
-               (void) __value; \
-             } \
-           })
+  ((void) __atomic_val_bysize (__arch_add, int, mem, value))
+
+
+#define __arch_add_negative_8_int(mem, value)          \
+  (__arch_operate_new_n(mem, value, b, add) < 0)
+
+#define __arch_add_negative_16_int(mem, value)         \
+  (__arch_operate_new_n(mem, value, w, add) < 0)
+
+#define __arch_add_negative_32_int(mem, value)         \
+  (__arch_operate_new_n(mem, value, l, add) < 0)
+
+#define __arch_add_negative_64_int(mem, value)         \
+  (abort (), 0)
 
 #define atomic_add_negative(mem, value) \
-  ({ unsigned char __result; \
-     __typeof (*(mem)) __tmp, __value = (value); \
-     if (sizeof (*(mem)) == 1) \
-       __asm__ __volatile__ ("\
-         .align 2\n\
-         mova 1f,r0\n\
-         mov r15,r1\n\
-         mov #-6,r15\n\
-       0: mov.b @%2,r2\n\
-         add r2,%1\n\
-         mov.b %1,@%2\n\
-       1: mov r1,r15\n\
-         shal %1\n\
-         movt %0"\
-       : "=r" (__result), "=&r" (__tmp) : "r" (mem), "1" (__value) \
-       : "r0", "r1", "r2", "t", "memory"); \
-     else if (sizeof (*(mem)) == 2) \
-       __asm__ __volatile__ ("\
-         .align 2\n\
-         mova 1f,r0\n\
-         mov r15,r1\n\
-         mov #-6,r15\n\
-       0: mov.w @%2,r2\n\
-         add r2,%1\n\
-         mov.w %1,@%2\n\
-       1: mov r1,r15\n\
-         shal %1\n\
-         movt %0"\
-       : "=r" (__result), "=&r" (__tmp) : "r" (mem), "1" (__value) \
-       : "r0", "r1", "r2", "t", "memory"); \
-     else if (sizeof (*(mem)) == 4) \
-       __asm__ __volatile__ ("\
-         .align 2\n\
-         mova 1f,r0\n\
-         mov r15,r1\n\
-         mov #-6,r15\n\
-       0: mov.l @%2,r2\n\
-         add r2,%1\n\
-         mov.l %1,@%2\n\
-       1: mov r1,r15\n\
-         shal %1\n\
-         movt %0"\
-       : "=r" (__result), "=&r" (__tmp) : "r" (mem), "1" (__value) \
-       : "r0", "r1", "r2", "t", "memory"); \
-     else \
-       abort (); \
-     __result; })
+  __atomic_bool_bysize (__arch_add_negative, int, mem, value)
+
+
+#define __arch_add_zero_8_int(mem, value)              \
+  (__arch_operate_new_n(mem, value, b, add) == 0)
+
+#define __arch_add_zero_16_int(mem, value)             \
+  (__arch_operate_new_n(mem, value, w, add) == 0)
+
+#define __arch_add_zero_32_int(mem, value)             \
+  (__arch_operate_new_n(mem, value, l, add) == 0)
+
+#define __arch_add_zero_64_int(mem, value)             \
+  (abort (), 0)
 
 #define atomic_add_zero(mem, value) \
-  ({ unsigned char __result; \
-     __typeof (*(mem)) __tmp, __value = (value); \
-     if (sizeof (*(mem)) == 1) \
-       __asm__ __volatile__ ("\
-         .align 2\n\
-         mova 1f,r0\n\
-         mov r15,r1\n\
-         mov #-6,r15\n\
-       0: mov.b @%2,r2\n\
-         add r2,%1\n\
-         mov.b %1,@%2\n\
-       1: mov r1,r15\n\
-         tst %1,%1\n\
-         movt %0"\
-       : "=r" (__result), "=&r" (__tmp) : "r" (mem), "1" (__value) \
-       : "r0", "r1", "r2", "t", "memory"); \
-     else if (sizeof (*(mem)) == 2) \
-       __asm__ __volatile__ ("\
-         .align 2\n\
-         mova 1f,r0\n\
-         mov r15,r1\n\
-         mov #-6,r15\n\
-       0: mov.w @%2,r2\n\
-         add r2,%1\n\
-         mov.w %1,@%2\n\
-       1: mov r1,r15\n\
-         tst %1,%1\n\
-         movt %0"\
-       : "=r" (__result), "=&r" (__tmp) : "r" (mem), "1" (__value) \
-       : "r0", "r1", "r2", "t", "memory"); \
-     else if (sizeof (*(mem)) == 4) \
-       __asm__ __volatile__ ("\
-         .align 2\n\
-         mova 1f,r0\n\
-         mov r15,r1\n\
-         mov #-6,r15\n\
-       0: mov.l @%2,r2\n\
-         add r2,%1\n\
-         mov.l %1,@%2\n\
-       1: mov r1,r15\n\
-         tst %1,%1\n\
-         movt %0"\
-       : "=r" (__result), "=&r" (__tmp) : "r" (mem), "1" (__value) \
-       : "r0", "r1", "r2", "t", "memory"); \
-     else \
-       abort (); \
-     __result; })
+  __atomic_bool_bysize (__arch_add_zero, int, mem, value)
+
 
 #define atomic_increment_and_test(mem) atomic_add_zero((mem), 1)
 #define atomic_decrement_and_test(mem) atomic_add_zero((mem), -1)
 
-#define atomic_bit_set(mem, bit) \
-  (void) ({ unsigned int __mask = 1 << (bit); \
-           if (sizeof (*(mem)) == 1) \
-             __asm__ __volatile__ ("\
-               .align 2\n\
-               mova 1f,r0\n\
-               mov r15,r1\n\
-               mov #-6,r15\n\
-            0: mov.b @%0,r2\n\
-               or %1,r2\n\
-               mov.b r2,@%0\n\
-            1: mov r1,r15"\
-               : : "r" (mem), "r" (__mask) \
-               : "r0", "r1", "r2", "memory"); \
-           else if (sizeof (*(mem)) == 2) \
-             __asm__ __volatile__ ("\
-               .align 2\n\
-               mova 1f,r0\n\
-               mov r15,r1\n\
-               mov #-6,r15\n\
-            0: mov.w @%0,r2\n\
-               or %1,r2\n\
-               mov.w r2,@%0\n\
-            1: mov r1,r15"\
-               : : "r" (mem), "r" (__mask) \
-               : "r0", "r1", "r2", "memory"); \
-           else if (sizeof (*(mem)) == 4) \
-             __asm__ __volatile__ ("\
-               .align 2\n\
-               mova 1f,r0\n\
-               mov r15,r1\n\
-               mov #-6,r15\n\
-            0: mov.l @%0,r2\n\
-               or %1,r2\n\
-               mov.l r2,@%0\n\
-            1: mov r1,r15"\
-               : : "r" (mem), "r" (__mask) \
-               : "r0", "r1", "r2", "memory"); \
-           else \
-             abort (); \
-           })
-
-#define atomic_bit_test_set(mem, bit) \
-  ({ unsigned int __mask = 1 << (bit); \
-     unsigned int __result = __mask; \
-     if (sizeof (*(mem)) == 1) \
-       __asm__ __volatile__ ("\
-         .align 2\n\
-         mova 1f,r0\n\
-         nop\n\
-         mov r15,r1\n\
-         mov #-8,r15\n\
-       0: mov.b @%2,r2\n\
-         or r2,%1\n\
-         and r2,%0\n\
-         mov.b %1,@%2\n\
-       1: mov r1,r15"\
-       : "=&r" (__result), "=&r" (__mask) \
-       : "r" (mem), "0" (__result), "1" (__mask) \
-       : "r0", "r1", "r2", "memory"); \
-     else if (sizeof (*(mem)) == 2) \
-       __asm__ __volatile__ ("\
-         .align 2\n\
-         mova 1f,r0\n\
-         nop\n\
-         mov r15,r1\n\
-         mov #-8,r15\n\
-       0: mov.w @%2,r2\n\
-         or r2,%1\n\
-         and r2,%0\n\
-         mov.w %1,@%2\n\
-       1: mov r1,r15"\
-       : "=&r" (__result), "=&r" (__mask) \
-       : "r" (mem), "0" (__result), "1" (__mask) \
-       : "r0", "r1", "r2", "memory"); \
-     else if (sizeof (*(mem)) == 4) \
-       __asm__ __volatile__ ("\
-         .align 2\n\
-         mova 1f,r0\n\
-         nop\n\
-         mov r15,r1\n\
-         mov #-8,r15\n\
-       0: mov.l @%2,r2\n\
-         or r2,%1\n\
-         and r2,%0\n\
-         mov.l %1,@%2\n\
-       1: mov r1,r15"\
-       : "=&r" (__result), "=&r" (__mask) \
-       : "r" (mem), "0" (__result), "1" (__mask) \
-       : "r0", "r1", "r2", "memory"); \
-     else \
-       abort (); \
-     __result; })
+
+#define __arch_bit_set_8_int(mem, value)               \
+  __arch_operate_new_n(mem, 1<<(value), b, or)
+
+#define __arch_bit_set_16_int(mem, value)              \
+  __arch_operate_new_n(mem, 1<<(value), w, or)
+
+#define __arch_bit_set_32_int(mem, value)              \
+  __arch_operate_new_n(mem, 1<<(value), l, or)
+
+#define __arch_bit_set_64_int(mem, value)              \
+  (abort (), 0)
+
+#define __arch_add_64_int(mem, value)                  \
+  (abort (), 0)
+
+#define atomic_bit_set(mem, value) \
+  ((void) __atomic_val_bysize (__arch_bit_set, int, mem, value))
+
+
+#define __arch_bit_test_set_8_int(mem, value)                          \
+  ({ int32_t __value = 1<<(value), __new, __old;                       \
+    __arch_operate_old_new_n((mem), __value, __old, __new, b, or);     \
+    __old & __value; })
+
+#define __arch_bit_test_set_16_int(mem, value)                         \
+  ({ int32_t __value = 1<<(value), __new, __old;                       \
+    __arch_operate_old_new_n((mem), __value, __old, __new, w, or);     \
+    __old & __value; })
+
+#define __arch_bit_test_set_32_int(mem, value)                         \
+  ({ int32_t __value = 1<<(value), __new, __old;                       \
+    __arch_operate_old_new_n((mem), __value, __old, __new, l, or);     \
+    __old & __value; })
+
+#define __arch_bit_test_set_64_int(mem, value) \
+  (abort (), 0)
+
+#define atomic_bit_test_set(mem, value) \
+  __atomic_val_bysize (__arch_bit_test_set, int, mem, value)
index 3d18b6d..423a6c2 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+/* Copyright (C) 1999, 2000, 2003, 2004, 2007 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
    and invokes a function in the right context after its all over.  */
 
 #include <features.h>
-#include <sys/syscall.h>
-#define _ERRNO_H
+#include <asm/unistd.h>
+#include <sysdep.h>
+#define _ERRNO_H       1
 #include <bits/errno.h>
-#include <bits/sysnum.h>
-
-
-#ifdef __PIC__
-#define PLTJMP(_x)     _x@PLT
-#else
-#define PLTJMP(_x)     _x
+#ifdef RESET_PID
+#include <tcb-offsets.h>
 #endif
+/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg,
+            pid_t *ptid, void *tls, pid_t *ctid); */
 
-
-/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg); */
-
-        .text
-
-.text
-.align 4
-.type  clone,@function
-.globl clone;
-clone:
+       .text
+ENTRY(__clone)
        /* sanity check arguments.  */
        tst     r4, r4
-       bt      0f
-       tst     r5, r5
-       bf/s    1f
-        mov    #+__NR_clone, r3
-0:             
-       bra __syscall_error
-        mov    #-EINVAL, r4
-
+       bt/s    0f
+        tst    r5, r5
+       bf      1f
+0:
+       bra     .Lsyscall_error
+        mov    #-EINVAL,r0
 1:
        /* insert the args onto the new stack */
        mov.l   r7, @-r5
        /* save the function pointer as the 0th element */
        mov.l   r4, @-r5
-       
+
        /* do the system call */
        mov     r6, r4
-       trapa   #(__SH_SYSCALL_TRAP_BASE + 2)
+       mov.l   @r15, r6
+       mov.l   @(8,r15), r7
+       mov.l   @(4,r15), r0
+       mov     #+SYS_ify(clone), r3
+       trapa   #0x15
        mov     r0, r1
-#ifdef __sh2__
-/* 12 arithmetic shifts for the crappy sh2, because shad doesn't exist!         */
-       shar    r1
-       shar    r1
-       shar    r1
-       shar    r1
-       shar    r1
-       shar    r1
-       shar    r1
-       shar    r1
-       shar    r1
-       shar    r1
-       shar    r1
-       shar    r1
-#else          
        mov     #-12, r2
        shad    r2, r1
-#endif
-       not     r1, r1                  /* r1=0 means r0 = -1 to -4095 */
-       tst     r1, r1                  /* i.e. error in linux */
-       bf/s    2f
-        tst    r0, r0
-        bra __syscall_error
-        mov    r0, r4
-
-2:
-       bt      3f
+       not     r1, r1                  // r1=0 means r0 = -1 to -4095
+       tst     r1, r1                  // i.e. error in linux
+       bf      .Lclone_end
+.Lsyscall_error:
+       SYSCALL_ERROR_HANDLER
+.Lclone_end:
+       tst     r0, r0
+       bt      2f
+.Lpseudo_end:
        rts
         nop
+2:
+       /* terminate the stack frame */
+       mov     #0, r14
+#ifdef RESET_PID
+       mov     r4, r0
+       shlr16  r0
+       tst     #1, r0                  // CLONE_THREAD = (1 << 16)
+       bf/s    4f
+        mov    r4, r0
+       /* new pid */
+       shlr8   r0
+       tst     #1, r0                  // CLONE_VM = (1 << 8)
+       bf/s    3f
+        mov    #-1, r0
+       mov     #+SYS_ify(getpid), r3
+       trapa   #0x15
 3:
+       stc     gbr, r1
+       mov.w   .Lpidoff, r2
+       add     r1, r2
+       mov.l   r0, @r2
+       mov.w   .Ltidoff, r2
+       add     r1, r2
+       mov.l   r0, @r2
+4:
+#endif
        /* thread starts */
        mov.l   @r15, r1
        jsr     @r1
         mov.l  @(4,r15), r4
 
        /* we are done, passing the return value through r0  */
-       mov.l   .L1, r1
-#ifdef __PIC__
+       mov.l   .L3, r1
+#ifdef SHARED
        mov.l   r12, @-r15
        sts.l   pr, @-r15
        mov     r0, r4
-       mova    .LG, r0  /* .LG from syscall_error.S */
+       mova    .LG, r0
        mov.l   .LG, r12
        add     r0, r12
-       mova    .L1, r0
+       mova    .L3, r0
        add     r0, r1
        jsr     @r1
         nop
@@ -118,8 +119,16 @@ clone:
         mov    r0, r4
 #endif
        .align  2
-.L1:
-       .long   PLTJMP( HIDDEN_JUMPTARGET(_exit))
-.size clone,.-clone;
+.LG:
+       .long   _GLOBAL_OFFSET_TABLE_
+.L3:
+       .long   PLTJMP(C_SYMBOL_NAME(_exit))
+#ifdef RESET_PID
+.Lpidoff:
+       .word   PID - TLS_PRE_TCB_SIZE
+.Ltidoff:
+       .word   TID - TLS_PRE_TCB_SIZE
+#endif
+PSEUDO_END (__clone)
 
-#include "syscall_error.S"
+weak_alias (__clone, clone)
diff --git a/libc/sysdeps/linux/sh/longjmp.c b/libc/sysdeps/linux/sh/longjmp.c
new file mode 100644 (file)
index 0000000..dd0616d
--- /dev/null
@@ -0,0 +1,56 @@
+/* Copyright (C) 1991, 92, 94, 95, 97, 98, 2000 Free Software Foundation, Inc.
+   Copyright (C) 2001 Hewlett-Packard Australia
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Library General Public License as published by the Free
+ Software Foundation; either version 2 of the License, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more
+ details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this program; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Derived in part from the Linux-8086 C library, the GNU C Library, and several
+ other sundry sources.  Files within this library are copyright by their
+ respective copyright holders.
+*/
+
+#include <stddef.h>
+#include <setjmp.h>
+#include <signal.h>
+
+libc_hidden_proto(sigprocmask)
+
+extern int __longjmp(char *env, int val);
+libc_hidden_proto(__longjmp)
+
+extern void _longjmp_unwind (jmp_buf env, int val);
+
+
+/* Set the signal mask to the one specified in ENV, and jump
+   to the position specified in ENV, causing the setjmp
+   call there to return VAL, or 1 if VAL is 0.  */
+void __libc_siglongjmp (sigjmp_buf env, int val)
+{
+  /* Perform any cleanups needed by the frames being unwound.  */
+
+  _longjmp_unwind (env, val);
+
+  if (env[0].__mask_was_saved)
+    /* Restore the saved signal mask.  */
+    (void) sigprocmask (SIG_SETMASK, &env[0].__saved_mask,
+                         (sigset_t *) NULL);
+
+  /* Call the machine-dependent function to restore machine state.  */
+  __longjmp ((char *) env[0].__jmpbuf, val ?: 1);
+}
+
+__asm__(".weak longjmp; longjmp = __libc_siglongjmp");
+__asm__(".weak _longjmp; _longjmp = __libc_siglongjmp");
+__asm__(".weak siglongjmp; siglongjmp = __libc_siglongjmp");
+strong_alias(__libc_siglongjmp, __libc_longjmp)
index 84a28e7..86feb9c 100644 (file)
 #include <stdint.h>
 #include <endian.h>
 
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include <sysdep-cancel.h>
+#else
+#define SINGLE_THREAD_P 1
+#endif
+
+
 #ifdef __NR_pread64             /* Newer kernels renamed but it's the same.  */
 # ifdef __NR_pread
 #  error "__NR_pread and __NR_pread64 both defined???"
@@ -33,7 +40,15 @@ static __inline__ _syscall6(ssize_t, __syscall_pread, int, fd, void *, buf,
 
 ssize_t __libc_pread(int fd, void *buf, size_t count, off_t offset)
 {
-       return(__syscall_pread(fd,buf,count,0,__LONG_LONG_PAIR(offset >> 31,offset)));
+       if (SINGLE_THREAD_P)
+               return(__syscall_pread(fd,buf,count,0,__LONG_LONG_PAIR(offset >> 31,offset)));
+
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+       int oldtype = LIBC_CANCEL_ASYNC ();
+       ssize_t result = __syscall_pread(fd,buf,count,0,__LONG_LONG_PAIR(offset >> 31,offset));
+       LIBC_CANCEL_RESET (oldtype);
+       return result;
+#endif
 }
 weak_alias(__libc_pread,pread)
 
@@ -43,7 +58,16 @@ ssize_t __libc_pread64(int fd, void *buf, size_t count, off64_t offset)
 {
        uint32_t low = offset & 0xffffffff;
        uint32_t high = offset >> 32;
-       return(__syscall_pread(fd, buf, count, 0, __LONG_LONG_PAIR (high, low)));
+
+       if (SINGLE_THREAD_P)
+               return __syscall_pread(fd, buf, count, 0, __LONG_LONG_PAIR (high, low));
+
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+       int oldtype = LIBC_CANCEL_ASYNC ();
+       ssize_t result = __syscall_pread(fd, buf, count, 0, __LONG_LONG_PAIR (high, low));
+       LIBC_CANCEL_RESET (oldtype);
+       return result;
+#endif
 }
 weak_alias(__libc_pread64,pread64)
 # endif /* __UCLIBC_HAS_LFS__  */
@@ -66,7 +90,16 @@ static __inline__ _syscall6(ssize_t, __syscall_pwrite, int, fd, const void *, bu
 
 ssize_t __libc_pwrite(int fd, const void *buf, size_t count, off_t offset)
 {
-       return(__syscall_pwrite(fd,buf,count,0,__LONG_LONG_PAIR(offset >> 31,offset)));
+       if (SINGLE_THREAD_P)
+               return __syscall_pwrite(fd,buf,count,0,__LONG_LONG_PAIR(offset >> 31,offset));
+
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+       int oldtype = LIBC_CANCEL_ASYNC ();
+       ssize_t result = __syscall_pwrite(fd,buf,count,0,__LONG_LONG_PAIR(offset >> 31,offset));
+       LIBC_CANCEL_RESET (oldtype);
+       return result;
+#endif
+
 }
 weak_alias(__libc_pwrite,pwrite)
 
@@ -76,7 +109,16 @@ ssize_t __libc_pwrite64(int fd, const void *buf, size_t count, off64_t offset)
 {
        uint32_t low = offset & 0xffffffff;
        uint32_t high = offset >> 32;
-       return(__syscall_pwrite(fd, buf, count, 0, __LONG_LONG_PAIR (high, low)));
+
+       if (SINGLE_THREAD_P)
+               return __syscall_pwrite(fd, buf, count, 0, __LONG_LONG_PAIR (high, low));
+
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+       int oldtype = LIBC_CANCEL_ASYNC ();
+       ssize_t result = __syscall_pwrite(fd, buf, count, 0, __LONG_LONG_PAIR (high, low));
+       LIBC_CANCEL_RESET (oldtype);
+       return result;
+#endif
 }
 weak_alias(__libc_pwrite64,pwrite64)
 # endif /* __UCLIBC_HAS_LFS__  */
index 00475a0..0a81424 100644 (file)
@@ -77,7 +77,7 @@ __sigsetjmp_intern:
        mov.l   r9, @-r4
        mov.l   r8, @-r4
 
-#ifdef __PIC__
+#ifdef __HAVE_SHARED__
        mov.l   .LG, r2
        mova    .LG, r0
        add     r0, r2
index f55dd53..7379503 100644 (file)
@@ -3,7 +3,7 @@ __syscall_error:
        /* Call errno_location, store '-r4' in errno and return -1 */
        mov.l   r12, @-r15
        sts.l   pr, @-r15
-#ifdef __PIC__
+#ifdef SHARED
        mova    .LG, r0
        mov.l   .LG, r12
        add     r0, r12
@@ -27,7 +27,7 @@ __syscall_error:
 
        .align  4
 
-#ifdef __PIC__
+#ifdef SHARED
 1:     .long   __errno_location@GOT
 .LG:   .long   _GLOBAL_OFFSET_TABLE_
 #else
index 6f182cd..bd62342 100644 (file)
 
 #define ret_ERRVAL ret
 
-#ifndef PIC
+#ifndef __PIC__
 # define SYSCALL_ERROR_HANDLER \
        mov.l 0f,r1; \
        jmp @r1; \
      0: .long _GLOBAL_OFFSET_TABLE_; \
      1: .long errno@GOT
 # endif        /* _LIBC_REENTRANT */
-#endif /* PIC */
+#endif /* __PIC__ */
 
 # ifdef __SH4__
 #  define SYSCALL_INST_PAD \
     .align 2;                          \
  1: .long SYS_ify (syscall_name);      \
  2:
-
 #endif /* __ASSEMBLER__ */
+
+/* Pointer mangling support.  */
+#if defined NOT_IN_libc && defined IS_IN_rtld
+/* We cannot use the thread descriptor because in ld.so we use setjmp
+   earlier than the descriptor is initialized.  Using a global variable
+   is too complicated here since we have no PC-relative addressing mode.  */
+#else
+# ifdef __ASSEMBLER__
+#  define PTR_MANGLE(reg, tmp) \
+     stc gbr,tmp; mov.l @(POINTER_GUARD,tmp),tmp; xor tmp,reg
+#  define PTR_MANGLE2(reg, tmp)        xor tmp,reg
+#  define PTR_DEMANGLE(reg, tmp)       PTR_MANGLE (reg, tmp)
+#  define PTR_DEMANGLE2(reg, tmp)      PTR_MANGLE2 (reg, tmp)
+# else
+#  define PTR_MANGLE(var) \
+     (var) = (void *) ((uintptr_t) (var) ^ THREAD_GET_POINTER_GUARD ())
+#  define PTR_DEMANGLE(var)    PTR_MANGLE (var)
+# endif
+#endif
+
index ffae27b..8a62420 100644 (file)
@@ -5,8 +5,15 @@
 # Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
 #
 
-CSRC := brk.c __syscall_error.c qp_ops.c sigaction.c
+CSRC := brk.c __syscall_error.c qp_ops.c
 
 SSRC := \
-       __longjmp.S fork.S vfork.S clone.S setjmp.S bsd-setjmp.S bsd-_setjmp.S \
+       __longjmp.S setjmp.S bsd-setjmp.S bsd-_setjmp.S \
        syscall.S urem.S udiv.S umul.S sdiv.S rem.S pipe.S
+
+ifneq ($(UCLIBC_HAS_THREADS_NATIVE),y)
+CSRC += sigaction.c
+SSRC += fork.S vfork.S
+endif
+
+
diff --git a/libc/sysdeps/linux/sparc/bits/atomic.h b/libc/sysdeps/linux/sparc/bits/atomic.h
new file mode 100644 (file)
index 0000000..f625eb9
--- /dev/null
@@ -0,0 +1,329 @@
+/* Atomic operations.  sparc32 version.
+   Copyright (C) 2003, 2004, 2006 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _BITS_ATOMIC_H
+#define _BITS_ATOMIC_H 1
+
+#include <stdint.h>
+
+typedef int8_t atomic8_t;
+typedef uint8_t uatomic8_t;
+typedef int_fast8_t atomic_fast8_t;
+typedef uint_fast8_t uatomic_fast8_t;
+
+typedef int16_t atomic16_t;
+typedef uint16_t uatomic16_t;
+typedef int_fast16_t atomic_fast16_t;
+typedef uint_fast16_t uatomic_fast16_t;
+
+typedef int32_t atomic32_t;
+typedef uint32_t uatomic32_t;
+typedef int_fast32_t atomic_fast32_t;
+typedef uint_fast32_t uatomic_fast32_t;
+
+typedef int64_t atomic64_t;
+typedef uint64_t uatomic64_t;
+typedef int_fast64_t atomic_fast64_t;
+typedef uint_fast64_t uatomic_fast64_t;
+
+typedef intptr_t atomicptr_t;
+typedef uintptr_t uatomicptr_t;
+typedef intmax_t atomic_max_t;
+typedef uintmax_t uatomic_max_t;
+
+
+/* We have no compare and swap, just test and set.
+   The following implementation contends on 64 global locks
+   per library and assumes no variable will be accessed using atomic.h
+   macros from two different libraries.  */
+
+__make_section_unallocated
+  (".gnu.linkonce.b.__sparc32_atomic_locks, \"aw\", %nobits");
+
+volatile unsigned char __sparc32_atomic_locks[64]
+  __attribute__ ((nocommon, section (".gnu.linkonce.b.__sparc32_atomic_locks"
+                                    __sec_comment),
+                 visibility ("hidden")));
+
+#define __sparc32_atomic_do_lock(addr) \
+  do                                                                 \
+    {                                                                \
+      unsigned int __old_lock;                                       \
+      unsigned int __idx = (((long) addr >> 2) ^ ((long) addr >> 12)) \
+                          & 63;                                      \
+      do                                                             \
+       __asm __volatile ("ldstub %1, %0"                             \
+                         : "=r" (__old_lock),                        \
+                           "=m" (__sparc32_atomic_locks[__idx])      \
+                         : "m" (__sparc32_atomic_locks[__idx])       \
+                         : "memory");                                \
+      while (__old_lock);                                            \
+    }                                                                \
+  while (0)
+
+#define __sparc32_atomic_do_unlock(addr) \
+  do                                                                 \
+    {                                                                \
+      __sparc32_atomic_locks[(((long) addr >> 2)                     \
+                             ^ ((long) addr >> 12)) & 63] = 0;       \
+      __asm __volatile ("" ::: "memory");                            \
+    }                                                                \
+  while (0)
+
+#define __sparc32_atomic_do_lock24(addr) \
+  do                                                                 \
+    {                                                                \
+      unsigned int __old_lock;                                       \
+      do                                                             \
+       __asm __volatile ("ldstub %1, %0"                             \
+                         : "=r" (__old_lock), "=m" (*(addr))         \
+                         : "m" (*(addr))                             \
+                         : "memory");                                \
+      while (__old_lock);                                            \
+    }                                                                \
+  while (0)
+
+#define __sparc32_atomic_do_unlock24(addr) \
+  do                                                                 \
+    {                                                                \
+      *(char *) (addr) = 0;                                          \
+      __asm __volatile ("" ::: "memory");                            \
+    }                                                                \
+  while (0)
+
+
+#ifndef SHARED
+# define __v9_compare_and_exchange_val_32_acq(mem, newval, oldval) \
+({                                                                           \
+  register __typeof (*(mem)) __acev_tmp __asm ("%g6");                       \
+  register __typeof (mem) __acev_mem __asm ("%g1") = (mem);                  \
+  register __typeof (*(mem)) __acev_oldval __asm ("%g5");                    \
+  __acev_tmp = (newval);                                                     \
+  __acev_oldval = (oldval);                                                  \
+  /* .word 0xcde05005 is cas [%g1], %g5, %g6.  Can't use cas here though,     \
+     because as will then mark the object file as V8+ arch.  */                      \
+  __asm __volatile (".word 0xcde05005"                                       \
+                   : "+r" (__acev_tmp), "=m" (*__acev_mem)                   \
+                   : "r" (__acev_oldval), "m" (*__acev_mem),                 \
+                     "r" (__acev_mem) : "memory");                           \
+  __acev_tmp; })
+#endif
+
+/* The only basic operation needed is compare and exchange.  */
+#define __v7_compare_and_exchange_val_acq(mem, newval, oldval) \
+  ({ __typeof (mem) __acev_memp = (mem);                             \
+     __typeof (*mem) __acev_ret;                                     \
+     __typeof (*mem) __acev_newval = (newval);                       \
+                                                                     \
+     __sparc32_atomic_do_lock (__acev_memp);                         \
+     __acev_ret = *__acev_memp;                                              \
+     if (__acev_ret == (oldval))                                     \
+       *__acev_memp = __acev_newval;                                 \
+     __sparc32_atomic_do_unlock (__acev_memp);                       \
+     __acev_ret; })
+
+#define __v7_compare_and_exchange_bool_acq(mem, newval, oldval) \
+  ({ __typeof (mem) __aceb_memp = (mem);                             \
+     int __aceb_ret;                                                 \
+     __typeof (*mem) __aceb_newval = (newval);                       \
+                                                                     \
+     __sparc32_atomic_do_lock (__aceb_memp);                         \
+     __aceb_ret = 0;                                                 \
+     if (*__aceb_memp == (oldval))                                   \
+       *__aceb_memp = __aceb_newval;                                 \
+     else                                                            \
+       __aceb_ret = 1;                                               \
+     __sparc32_atomic_do_unlock (__aceb_memp);                       \
+     __aceb_ret; })
+
+#define __v7_exchange_acq(mem, newval) \
+  ({ __typeof (mem) __acev_memp = (mem);                             \
+     __typeof (*mem) __acev_ret;                                     \
+     __typeof (*mem) __acev_newval = (newval);                       \
+                                                                     \
+     __sparc32_atomic_do_lock (__acev_memp);                         \
+     __acev_ret = *__acev_memp;                                              \
+     *__acev_memp = __acev_newval;                                   \
+     __sparc32_atomic_do_unlock (__acev_memp);                       \
+     __acev_ret; })
+
+#define __v7_exchange_and_add(mem, value) \
+  ({ __typeof (mem) __acev_memp = (mem);                             \
+     __typeof (*mem) __acev_ret;                                     \
+                                                                     \
+     __sparc32_atomic_do_lock (__acev_memp);                         \
+     __acev_ret = *__acev_memp;                                              \
+     *__acev_memp = __acev_ret + (value);                            \
+     __sparc32_atomic_do_unlock (__acev_memp);                       \
+     __acev_ret; })
+
+/* Special versions, which guarantee that top 8 bits of all values
+   are cleared and use those bits as the ldstub lock.  */
+#define __v7_compare_and_exchange_val_24_acq(mem, newval, oldval) \
+  ({ __typeof (mem) __acev_memp = (mem);                             \
+     __typeof (*mem) __acev_ret;                                     \
+     __typeof (*mem) __acev_newval = (newval);                       \
+                                                                     \
+     __sparc32_atomic_do_lock24 (__acev_memp);                       \
+     __acev_ret = *__acev_memp & 0xffffff;                           \
+     if (__acev_ret == (oldval))                                     \
+       *__acev_memp = __acev_newval;                                 \
+     else                                                            \
+       __sparc32_atomic_do_unlock24 (__acev_memp);                   \
+     __asm __volatile ("" ::: "memory");                             \
+     __acev_ret; })
+
+#define __v7_exchange_24_rel(mem, newval) \
+  ({ __typeof (mem) __acev_memp = (mem);                             \
+     __typeof (*mem) __acev_ret;                                     \
+     __typeof (*mem) __acev_newval = (newval);                       \
+                                                                     \
+     __sparc32_atomic_do_lock24 (__acev_memp);                       \
+     __acev_ret = *__acev_memp & 0xffffff;                           \
+     *__acev_memp = __acev_newval;                                   \
+     __asm __volatile ("" ::: "memory");                             \
+     __acev_ret; })
+
+#ifdef SHARED
+
+/* When dynamically linked, we assume pre-v9 libraries are only ever
+   used on pre-v9 CPU.  */
+# define __atomic_is_v9 0
+
+# define atomic_compare_and_exchange_val_acq(mem, newval, oldval) \
+  __v7_compare_and_exchange_val_acq (mem, newval, oldval)
+
+# define atomic_compare_and_exchange_bool_acq(mem, newval, oldval) \
+  __v7_compare_and_exchange_bool_acq (mem, newval, oldval)
+
+# define atomic_exchange_acq(mem, newval) \
+  __v7_exchange_acq (mem, newval)
+
+# define atomic_exchange_and_add(mem, value) \
+  __v7_exchange_and_add (mem, value)
+
+# define atomic_compare_and_exchange_val_24_acq(mem, newval, oldval) \
+  ({                                                                 \
+     if (sizeof (*mem) != 4)                                         \
+       abort ();                                                     \
+     __v7_compare_and_exchange_val_24_acq (mem, newval, oldval); })
+
+# define atomic_exchange_24_rel(mem, newval) \
+  ({                                                                 \
+     if (sizeof (*mem) != 4)                                         \
+       abort ();                                                     \
+     __v7_exchange_24_rel (mem, newval); })
+
+#else
+
+
+
+/*
+   Here's what we'd like to do:
+
+   In libc.a/libpthread.a etc. we don't know if we'll be run on
+   pre-v9 or v9 CPU.  To be interoperable with dynamically linked
+   apps on v9 CPUs e.g. with process shared primitives, use cas insn
+   on v9 CPUs and ldstub on pre-v9.
+
+   However, we have no good way to test at run time that I know of,
+   so resort to the lowest common denominator (v7 ops) -austinf
+ */
+#define __atomic_is_v9 0
+
+# define atomic_compare_and_exchange_val_acq(mem, newval, oldval) \
+  ({                                                                 \
+     __typeof (*mem) __acev_wret;                                    \
+     if (sizeof (*mem) != 4)                                         \
+       abort ();                                                     \
+     if (__atomic_is_v9)                                             \
+       __acev_wret                                                   \
+        = __v9_compare_and_exchange_val_32_acq (mem, newval, oldval);\
+     else                                                            \
+       __acev_wret                                                   \
+        = __v7_compare_and_exchange_val_acq (mem, newval, oldval);   \
+     __acev_wret; })
+
+# define atomic_compare_and_exchange_bool_acq(mem, newval, oldval) \
+  ({                                                                 \
+     int __acev_wret;                                                \
+     if (sizeof (*mem) != 4)                                         \
+       abort ();                                                     \
+     if (__atomic_is_v9)                                             \
+       {                                                             \
+        __typeof (oldval) __acev_woldval = (oldval);                 \
+        __acev_wret                                                  \
+          = __v9_compare_and_exchange_val_32_acq (mem, newval,       \
+                                                  __acev_woldval)    \
+            != __acev_woldval;                                       \
+       }                                                             \
+     else                                                            \
+       __acev_wret                                                   \
+        = __v7_compare_and_exchange_bool_acq (mem, newval, oldval);  \
+     __acev_wret; })
+
+# define atomic_exchange_rel(mem, newval) \
+  ({                                                                 \
+     __typeof (*mem) __acev_wret;                                    \
+     if (sizeof (*mem) != 4)                                         \
+       abort ();                                                     \
+     if (__atomic_is_v9)                                             \
+       {                                                             \
+        __typeof (mem) __acev_wmemp = (mem);                         \
+        __typeof (*(mem)) __acev_wval = (newval);                    \
+        do                                                           \
+          __acev_wret = *__acev_wmemp;                               \
+        while (__builtin_expect                                      \
+                 (__v9_compare_and_exchange_val_32_acq (__acev_wmemp,\
+                                                        __acev_wval, \
+                                                        __acev_wret) \
+                  != __acev_wret, 0));                               \
+       }                                                             \
+     else                                                            \
+       __acev_wret = __v7_exchange_acq (mem, newval);                \
+     __acev_wret; })
+
+# define atomic_compare_and_exchange_val_24_acq(mem, newval, oldval) \
+  ({                                                                 \
+     __typeof (*mem) __acev_wret;                                    \
+     if (sizeof (*mem) != 4)                                         \
+       abort ();                                                     \
+     if (__atomic_is_v9)                                             \
+       __acev_wret                                                   \
+        = __v9_compare_and_exchange_val_32_acq (mem, newval, oldval);\
+     else                                                            \
+       __acev_wret                                                   \
+        = __v7_compare_and_exchange_val_24_acq (mem, newval, oldval);\
+     __acev_wret; })
+
+# define atomic_exchange_24_rel(mem, newval) \
+  ({                                                                 \
+     __typeof (*mem) __acev_w24ret;                                  \
+     if (sizeof (*mem) != 4)                                         \
+       abort ();                                                     \
+     if (__atomic_is_v9)                                             \
+       __acev_w24ret = atomic_exchange_rel (mem, newval);            \
+     else                                                            \
+       __acev_w24ret = __v7_exchange_24_rel (mem, newval);           \
+     __acev_w24ret; })
+
+#endif
+
+#endif /* bits/atomic.h */
index 1dbfa2b..2d8cdd7 100644 (file)
@@ -36,7 +36,7 @@
 #undef __UCLIBC_HAVE_ASM_GLOBAL_DOT_NAME__
 
 /* define if target supports CFI pseudo ops */
-#undef __UCLIBC_HAVE_ASM_CFI_DIRECTIVES__
+#define __UCLIBC_HAVE_ASM_CFI_DIRECTIVES__
 
 /* define if target supports IEEE signed zero floats */
 #define __UCLIBC_HAVE_SIGNED_ZERO__
index 0e41ee0..2b66095 100644 (file)
@@ -1,4 +1,5 @@
-/* Copyright (C) 1996, 1997, 1998, 2000 Free Software Foundation, Inc.
+/* Copyright (C) 1996, 1997, 1998, 2000, 2003, 2004, 2007
+   Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Richard Henderson (rth@tamu.edu).
 
 /* clone() is even more special than fork() as it mucks with stacks
    and invokes a function in the right context after its all over.  */
 
-#include <features.h>
+#include <asm/errno.h>
 #include <asm/unistd.h>
+#include <tcb-offsets.h>
+#include <sysdep.h>
 
-/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg); */
+#define CLONE_VM       0x00000100
+#define CLONE_THREAD   0x00010000
 
-.text
-.global clone
-.type   clone,%function
-.align 4
+/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg,
+            pid_t *ptid, void *tls, pid_t *ctid); */
 
-clone:
+       .text
+ENTRY (__clone)
        save    %sp,-96,%sp
+       cfi_def_cfa_register(%fp)
+       cfi_window_save
+       cfi_register(%o7, %i7)
 
        /* sanity check arguments */
-       tst     %i0
-       be      __error
-       orcc    %i1,%g0,%o1
-       be      __error
-       mov     %i2,%o0
+       orcc    %i0,%g0,%g2
+       be      .Leinval
+        orcc   %i1,%g0,%o1
+       be      .Leinval
+        mov    %i2,%o0
+
+       /* The child_stack is the top of the stack, allocate one
+          whole stack frame from that as this is what the kernel
+          expects.  */
+       sub     %o1, 96, %o1
+       mov     %i3, %g3
+       mov     %i2, %g4
+
+       /* ptid */
+       mov     %i4,%o2
+       /* tls */
+       mov     %i5,%o3
+       /* ctid */
+       ld      [%fp+92],%o4
 
        /* Do the system call */
        set     __NR_clone,%g1
        ta      0x10
-       bcs     __error
-       tst     %o1
+       bcs     .Lerror
+        tst    %o1
        bne     __thread_start
-       nop
-       ret
-       restore %o0,%g0,%o0
-
-__error:
-       jmp __syscall_error
+        nop
+       jmpl    %i7 + 8, %g0
+        restore %o0,%g0,%o0
 
-.size clone,.-clone
-
-.type __thread_start,%function
+.Leinval:
+       mov     EINVAL, %o0
+.Lerror:
+       call    __errno_location
+        mov    %o0, %i0
+       st      %i0,[%o0]
+       jmpl    %i7 + 8, %g0
+        restore %g0,-1,%o0
+END(__clone)
 
+       .type   __thread_start,@function
 __thread_start:
-       call    %i0
-       mov     %i3,%o0
-       call    HIDDEN_JUMPTARGET(_exit),0
-       nop
+#ifdef RESET_PID
+       sethi   %hi(CLONE_THREAD), %l0
+       andcc   %g4, %l0, %g0
+       bne     1f
+        andcc  %g4, CLONE_VM, %g0
+       bne,a   2f
+        mov    -1,%o0
+       set     __NR_getpid,%g1
+       ta      0x10
+2:
+       st      %o0,[%g7 + PID]
+       st      %o0,[%g7 + TID]
+1:
+#endif
+       mov     %g0, %fp        /* terminate backtrace */
+       call    %g2
+        mov    %g3,%o0
+       call    exit,0
+        nop
+
+       .size   __thread_start, .-__thread_start
 
-.size __thread_start,.-__thread_start
+weak_alias (__clone, clone)
index 7140fd3..a22ac40 100644 (file)
@@ -34,8 +34,7 @@ _syscall5(int, rt_sigaction, int, a, int, b, int, c, int, d, int, e);
 static void __rt_sigreturn_stub(void);
 static void __sigreturn_stub(void);
 
-libc_hidden_proto(sigaction)
-int sigaction(int sig, const struct sigaction *act, struct sigaction *oact)
+int __libc_sigaction(int sig, const struct sigaction *act, struct sigaction *oact)
 {
        int ret;
        struct sigaction kact, koact;
@@ -66,8 +65,10 @@ int sigaction(int sig, const struct sigaction *act, struct sigaction *oact)
        return ret;
 }
 
-libc_hidden_def(sigaction)
-weak_alias(sigaction,__libc_sigaction)
+#ifndef LIBC_SIGACTION
+weak_alias(__libc_sigaction,sigaction)
+libc_hidden_weak(sigaction)
+#endif
 
 static void
 __rt_sigreturn_stub(void)
diff --git a/libc/sysdeps/linux/sparc/sparcv9/clone.S b/libc/sysdeps/linux/sparc/sparcv9/clone.S
new file mode 100644 (file)
index 0000000..9d101e2
--- /dev/null
@@ -0,0 +1,102 @@
+/* Copyright (C) 1997, 2000, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Richard Henderson (rth@tamu.edu).
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* clone() is even more special than fork() as it mucks with stacks
+   and invokes a function in the right context after its all over.  */
+
+#include <asm/errno.h>
+#include <asm/unistd.h>
+#include <tcb-offsets.h>
+#include <sysdep.h>
+
+#define CLONE_VM       0x00000100
+#define CLONE_THREAD   0x00010000
+
+/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg,
+            pid_t *ptid, void *tls, pid_t *ctid); */
+
+       .register       %g2,#scratch
+       .register       %g3,#scratch
+
+       .text
+
+ENTRY (__clone)
+       save    %sp, -192, %sp
+       cfi_def_cfa_register(%fp)
+       cfi_window_save
+       cfi_register(%o7, %i7)
+
+       /* sanity check arguments */
+       brz,pn  %i0, 99f                /* fn non-NULL? */
+        mov    %i0, %g2
+       brz,pn  %i1, 99f                /* child_stack non-NULL? */
+        mov    %i2, %o0                /* clone flags */
+
+       /* The child_stack is the top of the stack, allocate one
+          whole stack frame from that as this is what the kernel
+          expects.  Also, subtract STACK_BIAS.  */
+       sub     %i1, 192 + 0x7ff, %o1
+       mov     %i3, %g3
+       mov     %i2, %g4
+
+       mov     %i4,%o2                 /* PTID */
+       mov     %i5,%o3                 /* TLS */
+       ldx     [%fp+0x7ff+176],%o4     /* CTID */
+
+       /* Do the system call */
+       set     __NR_clone, %g1
+       ta      0x6d
+       bcs,pn  %xcc, 98f
+        nop
+       brnz,pn %o1, __thread_start
+        nop
+       jmpl    %i7 + 8, %g0
+        restore %o0, %g0, %o0
+99:    mov     EINVAL, %o0
+98:    call    HIDDEN_JUMPTARGET(__errno_location)
+        mov    %o0, %i0
+       st      %i0, [%o0]
+       jmpl    %i7 + 8, %g0
+        restore %g0,-1,%o0
+END(__clone)
+
+       .type __thread_start,@function
+__thread_start:
+#ifdef RESET_PID
+       sethi   %hi(CLONE_THREAD), %l0
+       andcc   %g4, %l0, %g0
+       bne,pt  %icc, 1f
+        andcc  %g4, CLONE_VM, %g0
+       bne,a,pn %icc, 2f
+        mov    -1,%o0
+       set     __NR_getpid,%g1
+       ta      0x6d
+2:     st      %o0,[%g7 + PID]
+       st      %o0,[%g7 + TID]
+1:
+#endif
+       mov     %g0, %fp        /* terminate backtrace */
+       call    %g2
+        mov    %g3,%o0
+       call    HIDDEN_JUMPTARGET(_exit),0
+        nop
+
+       .size   __thread_start, .-__thread_start
+
+weak_alias (__clone, clone)
diff --git a/libc/sysdeps/linux/sparc/sysdep.h b/libc/sysdeps/linux/sparc/sysdep.h
new file mode 100644 (file)
index 0000000..cf3e3af
--- /dev/null
@@ -0,0 +1,69 @@
+#ifndef _LINUX_SPARC_SYSDEP_H
+#define _LINUX_SPARC_SYSDEP_H 1
+
+#include <common/sysdep.h>
+
+#undef ENTRY
+#undef END
+
+#ifdef __ASSEMBLER__
+
+#define LOADSYSCALL(x) mov __NR_##x, %g1
+
+#define ENTRY(name)                 \
+    .align 4;                       \
+    .global C_SYMBOL_NAME(name);    \
+    .type   name, @function;        \
+C_LABEL(name)                       \
+    cfi_startproc;
+
+#define END(name)                   \
+    cfi_endproc;                    \
+    .size name, . - name
+
+#define LOC(name) .L##name
+
+       /* If the offset to __syscall_error fits into a signed 22-bit
+        * immediate branch offset, the linker will relax the call into
+        * a normal branch.
+        */
+#undef PSEUDO
+#undef PSEUDO_END
+#undef PSEUDO_NOERRNO
+#undef PSEUDO_ERRVAL
+
+#define PSEUDO(name, syscall_name, args)       \
+       .text;                                  \
+       .globl          __syscall_error;        \
+ENTRY(name);                                   \
+       LOADSYSCALL(syscall_name);              \
+       ta              0x10;                   \
+       bcc             1f;                     \
+        mov            %o7, %g1;               \
+       call            __syscall_error;        \
+        mov            %g1, %o7;               \
+1:
+
+#define PSEUDO_NOERRNO(name, syscall_name, args)\
+       .text;                                  \
+ENTRY(name);                                   \
+       LOADSYSCALL(syscall_name);              \
+       ta              0x10;
+
+#define PSEUDO_ERRVAL(name, syscall_name, args)        \
+       .text;                                  \
+ENTRY(name);                                   \
+       LOADSYSCALL(syscall_name);              \
+       ta              0x10;
+
+#define PSEUDO_END(name)                       \
+       END(name)
+
+
+#endif /* __ASSEMBLER__ */
+
+/* Pointer mangling is not yet supported for SPARC.  */
+#define PTR_MANGLE(var) (void) (var)
+#define PTR_DEMANGLE(var) (void) (var)
+
+#endif
index 044f97f..de7ce72 100644 (file)
@@ -5,7 +5,15 @@
 # Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
 #
 
-CSRC := brk.c sigaction.c __syscall_error.c mmap.c
+CSRC := brk.c __syscall_error.c mmap.c
+
+ifneq ($(UCLIBC_HAS_THREADS_NATIVE),y)
+CSRC += sigaction.c
+endif
 
 SSRC := \
-       __longjmp.S vfork.S setjmp.S syscall.S bsd-setjmp.S bsd-_setjmp.S clone.S
+       __longjmp.S setjmp.S syscall.S bsd-setjmp.S bsd-_setjmp.S
+
+ifneq ($(UCLIBC_HAS_THREADS_NATIVE),y)
+SSRC += vfork.S clone.S
+endif
index 748e544..1d966ae 100644 (file)
@@ -36,7 +36,7 @@
 #undef __UCLIBC_HAVE_ASM_GLOBAL_DOT_NAME__
 
 /* define if target supports CFI pseudo ops */
-#undef __UCLIBC_HAVE_ASM_CFI_DIRECTIVES__
+#define __UCLIBC_HAVE_ASM_CFI_DIRECTIVES__
 
 /* define if target supports IEEE signed zero floats */
 #define __UCLIBC_HAVE_SIGNED_ZERO__
index dc5eeb0..8c66ce5 100644 (file)
@@ -109,6 +109,8 @@ clone:
        call    *%rax
        /* Call exit with return value from function call. */
        movq    %rax, %rdi
-       call    HIDDEN_JUMPTARGET(_exit)
+       movl    $__NR_exit, %eax
+       syscall
 
 .size clone,.-clone
+weak_alias(clone, __clone)
diff --git a/libc/sysdeps/linux/x86_64/sysdep.h b/libc/sysdeps/linux/x86_64/sysdep.h
new file mode 100644 (file)
index 0000000..09bb926
--- /dev/null
@@ -0,0 +1,349 @@
+/* Copyright (C) 2001-2005, 2007 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 _LINUX_X86_64_SYSDEP_H
+#define _LINUX_X86_64_SYSDEP_H 1
+
+/* There is some commonality.  */
+#include <sys/syscall.h>
+#include <common/sysdep.h>
+
+#ifdef __ASSEMBLER__
+
+/* Syntactic details of assembler.  */
+
+#ifdef HAVE_ELF
+
+/* ELF uses byte-counts for .align, most others use log2 of count of bytes.  */
+#define ALIGNARG(log2) 1<<log2
+/* For ELF we need the `.type' directive to make shared libs work right.  */
+#define ASM_TYPE_DIRECTIVE(name,typearg) .type name,typearg;
+#define ASM_SIZE_DIRECTIVE(name) .size name,.-name;
+
+/* In ELF C symbols are asm symbols.  */
+#undef NO_UNDERSCORES
+#define NO_UNDERSCORES
+
+#else
+
+#define ALIGNARG(log2) log2
+#define ASM_TYPE_DIRECTIVE(name,type)  /* Nothing is specified.  */
+#define ASM_SIZE_DIRECTIVE(name)       /* Nothing is specified.  */
+
+#endif
+
+
+/* Define an entry point visible from C.  */
+#define        ENTRY(name)                                                           \
+  ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(name);                                  \
+  ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name),@function)                         \
+  .align ALIGNARG(4);                                                        \
+  C_LABEL(name)                                                                      \
+  cfi_startproc;                                                             \
+  CALL_MCOUNT
+
+#undef END
+#define END(name)                                                            \
+  cfi_endproc;                                                               \
+  ASM_SIZE_DIRECTIVE(name)
+
+/* If compiled for profiling, call `mcount' at the start of each function.  */
+#ifdef PROF
+/* The mcount code relies on a normal frame pointer being on the stack
+   to locate our caller, so push one just for its benefit.  */
+#define CALL_MCOUNT                                                          \
+  pushq %rbp;                                                                \
+  cfi_adjust_cfa_offset(8);                                                  \
+  movq %rsp, %rbp;                                                           \
+  cfi_def_cfa_register(%rbp);                                                \
+  call JUMPTARGET(mcount);                                                   \
+  popq %rbp;                                                                 \
+  cfi_def_cfa(rsp,8);
+#else
+#define CALL_MCOUNT            /* Do nothing.  */
+#endif
+
+#ifdef NO_UNDERSCORES
+/* Since C identifiers are not normally prefixed with an underscore
+   on this system, the asm identifier `syscall_error' intrudes on the
+   C name space.  Make sure we use an innocuous name.  */
+#define        syscall_error   __syscall_error
+#define mcount         _mcount
+#endif
+
+#define        PSEUDO(name, syscall_name, args)                                      \
+lose:                                                                        \
+  jmp JUMPTARGET(syscall_error)                                                      \
+  .globl syscall_error;                                                              \
+  ENTRY (name)                                                               \
+  DO_CALL (syscall_name, args);                                                      \
+  jb lose
+
+#undef PSEUDO_END
+#define        PSEUDO_END(name)                                                      \
+  END (name)
+
+#undef JUMPTARGET
+#ifdef __PIC__
+#define JUMPTARGET(name)       name##@PLT
+#else
+#define JUMPTARGET(name)       name
+#endif
+
+/* Local label name for asm code. */
+#ifndef L
+# ifdef HAVE_ELF
+/* ELF-like local names start with `.L'.  */
+#  define L(name)      .L##name
+# else
+#  define L(name)      name
+# endif
+#endif
+
+#endif /* __ASSEMBLER__ */
+
+/* For Linux we can use the system call table in the header file
+       /usr/include/asm/unistd.h
+   of the kernel.  But these symbols do not follow the SYS_* syntax
+   so we have to redefine the `SYS_ify' macro here.  */
+#undef SYS_ify
+#define SYS_ify(syscall_name)  __NR_##syscall_name
+
+/* This is a kludge to make syscalls.list find these under the names
+   pread and pwrite, since some kernel headers define those names
+   and some define the *64 names for the same system calls.  */
+#if !defined __NR_pread && defined __NR_pread64
+# define __NR_pread __NR_pread64
+#endif
+#if !defined __NR_pwrite && defined __NR_pwrite64
+# define __NR_pwrite __NR_pwrite64
+#endif
+
+/* This is to help the old kernel headers where __NR_semtimedop is not
+   available.  */
+#ifndef __NR_semtimedop
+# define __NR_semtimedop 220
+#endif
+
+
+#ifdef __ASSEMBLER__
+
+/* Linux uses a negative return value to indicate syscall errors,
+   unlike most Unices, which use the condition codes' carry flag.
+
+   Since version 2.1 the return value of a system call might be
+   negative even if the call succeeded.         E.g., the `lseek' system call
+   might return a large offset.         Therefore we must not anymore test
+   for < 0, but test for a real error by making sure the value in %eax
+   is a real error number.  Linus said he will make sure the no syscall
+   returns a value in -1 .. -4095 as a valid result so we can savely
+   test with -4095.  */
+
+/* We don't want the label for the error handle to be global when we define
+   it here.  */
+# ifdef __PIC__
+#  define SYSCALL_ERROR_LABEL 0f
+# else
+#  define SYSCALL_ERROR_LABEL syscall_error
+# endif
+
+# undef        PSEUDO
+# define PSEUDO(name, syscall_name, args)                                    \
+  .text;                                                                     \
+  ENTRY (name)                                                               \
+    DO_CALL (syscall_name, args);                                            \
+    cmpq $-4095, %rax;                                                       \
+    jae SYSCALL_ERROR_LABEL;                                                 \
+  L(pseudo_end):
+
+# undef        PSEUDO_END
+# define PSEUDO_END(name)                                                    \
+  SYSCALL_ERROR_HANDLER                                                              \
+  END (name)
+
+# undef        PSEUDO_NOERRNO
+# define PSEUDO_NOERRNO(name, syscall_name, args) \
+  .text;                                                                     \
+  ENTRY (name)                                                               \
+    DO_CALL (syscall_name, args)
+
+# undef        PSEUDO_END_NOERRNO
+# define PSEUDO_END_NOERRNO(name) \
+  END (name)
+
+# define ret_NOERRNO ret
+
+# undef        PSEUDO_ERRVAL
+# define PSEUDO_ERRVAL(name, syscall_name, args) \
+  .text;                                                                     \
+  ENTRY (name)                                                               \
+    DO_CALL (syscall_name, args);                                            \
+    negq %rax
+
+# undef        PSEUDO_END_ERRVAL
+# define PSEUDO_END_ERRVAL(name) \
+  END (name)
+
+# define ret_ERRVAL ret
+
+# ifndef __PIC__
+#  define SYSCALL_ERROR_HANDLER        /* Nothing here; code in sysdep.S is used.  */
+# elif defined(RTLD_PRIVATE_ERRNO)
+#  define SYSCALL_ERROR_HANDLER                        \
+0:                                             \
+  leaq rtld_errno(%rip), %rcx;                 \
+  xorl %edx, %edx;                             \
+  subq %rax, %rdx;                             \
+  movl %edx, (%rcx);                           \
+  orq $-1, %rax;                               \
+  jmp L(pseudo_end);
+# elif USE___THREAD
+#  ifndef NOT_IN_libc
+#   define SYSCALL_ERROR_ERRNO __libc_errno
+#  else
+#   define SYSCALL_ERROR_ERRNO errno
+#  endif
+#  define SYSCALL_ERROR_HANDLER                        \
+0:                                             \
+  movq SYSCALL_ERROR_ERRNO@GOTTPOFF(%rip), %rcx;\
+  xorl %edx, %edx;                             \
+  subq %rax, %rdx;                             \
+  movl %edx, %fs:(%rcx);                       \
+  orq $-1, %rax;                               \
+  jmp L(pseudo_end);
+# elif defined _LIBC_REENTRANT
+/* Store (- %rax) into errno through the GOT.
+   Note that errno occupies only 4 bytes.  */
+#  define SYSCALL_ERROR_HANDLER                        \
+0:                                             \
+  xorl %edx, %edx;                             \
+  subq %rax, %rdx;                             \
+  pushq %rdx;                                  \
+  cfi_adjust_cfa_offset(8);                    \
+  call __errno_location@PLT;           \
+  popq %rdx;                                   \
+  cfi_adjust_cfa_offset(-8);                   \
+  movl %edx, (%rax);                           \
+  orq $-1, %rax;                               \
+  jmp L(pseudo_end);
+
+/* A quick note: it is assumed that the call to `__errno_location' does
+   not modify the stack!  */
+# else /* Not _LIBC_REENTRANT.  */
+#  define SYSCALL_ERROR_HANDLER                        \
+0:movq errno@GOTPCREL(%RIP), %rcx;             \
+  xorl %edx, %edx;                             \
+  subq %rax, %rdx;                             \
+  movl %edx, (%rcx);                           \
+  orq $-1, %rax;                               \
+  jmp L(pseudo_end);
+# endif        /* __PIC__ */
+
+/* The Linux/x86-64 kernel expects the system call parameters in
+   registers according to the following table:
+
+    syscall number     rax
+    arg 1              rdi
+    arg 2              rsi
+    arg 3              rdx
+    arg 4              r10
+    arg 5              r8
+    arg 6              r9
+
+    The Linux kernel uses and destroys internally these registers:
+    return address from
+    syscall            rcx
+    eflags from syscall        r11
+
+    Normal function call, including calls to the system call stub
+    functions in the libc, get the first six parameters passed in
+    registers and the seventh parameter and later on the stack.  The
+    register use is as follows:
+
+     system call number        in the DO_CALL macro
+     arg 1             rdi
+     arg 2             rsi
+     arg 3             rdx
+     arg 4             rcx
+     arg 5             r8
+     arg 6             r9
+
+    We have to take care that the stack is aligned to 16 bytes.  When
+    called the stack is not aligned since the return address has just
+    been pushed.
+
+
+    Syscalls of more than 6 arguments are not supported.  */
+
+# undef        DO_CALL
+# define DO_CALL(syscall_name, args)           \
+    DOARGS_##args                              \
+    movl $SYS_ify (syscall_name), %eax;                \
+    syscall;
+
+# define DOARGS_0 /* nothing */
+# define DOARGS_1 /* nothing */
+# define DOARGS_2 /* nothing */
+# define DOARGS_3 /* nothing */
+# define DOARGS_4 movq %rcx, %r10;
+# define DOARGS_5 DOARGS_4
+# define DOARGS_6 DOARGS_5
+
+#endif /* __ASSEMBLER__ */
+
+
+/* Pointer mangling support.  */
+#if defined NOT_IN_libc && defined IS_IN_rtld
+/* We cannot use the thread descriptor because in ld.so we use setjmp
+   earlier than the descriptor is initialized.  */
+# ifdef __ASSEMBLER__
+#  define PTR_MANGLE(reg)      xorq __pointer_chk_guard_local(%rip), reg;    \
+                               rolq $17, reg
+#  define PTR_DEMANGLE(reg)    rorq $17, reg;                                \
+                               xorq __pointer_chk_guard_local(%rip), reg
+# else
+#  define PTR_MANGLE(reg)      __asm__ ("xorq __pointer_chk_guard_local(%%rip), %0\n" \
+                                    "rolq $17, %0"                           \
+                                    : "=r" (reg) : "0" (reg))
+#  define PTR_DEMANGLE(reg)    __asm__ ("rorq $17, %0\n"                             \
+                                    "xorq __pointer_chk_guard_local(%%rip), %0" \
+                                    : "=r" (reg) : "0" (reg))
+# endif
+#else
+# ifdef __ASSEMBLER__
+#  define PTR_MANGLE(reg)      xorq %fs:POINTER_GUARD, reg;                  \
+                               rolq $17, reg
+#  define PTR_DEMANGLE(reg)    rorq $17, reg;                                \
+                               xorq %fs:POINTER_GUARD, reg
+# else
+#  define PTR_MANGLE(var)      __asm__ ("xorq %%fs:%c2, %0\n"                \
+                                    "rolq $17, %0"                           \
+                                    : "=r" (var)                             \
+                                    : "0" (var),                             \
+                                      "i" (offsetof (tcbhead_t,              \
+                                                     pointer_guard)))
+#  define PTR_DEMANGLE(var)    __asm__ ("rorq $17, %0\n"                             \
+                                    "xorq %%fs:%c2, %0"                      \
+                                    : "=r" (var)                             \
+                                    : "0" (var),                             \
+                                      "i" (offsetof (tcbhead_t,              \
+                                                     pointer_guard)))
+# endif
+#endif
+
+#endif /* linux/x86_64/sysdep.h */
index 2dadbbf..97c9c5b 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2002, 2004 Free Software Foundation, Inc.
+/* Copyright (C) 2001, 2002, 2004, 2008 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
@@ -31,7 +31,7 @@
 .text
 .global __vfork
 .hidden __vfork
-.type  __vfork,%function
+.type   __vfork,%function
 
 __vfork:
 
@@ -39,6 +39,10 @@ __vfork:
           is preserved by the syscall and that we're allowed to destroy. */
        popq    %rdi
 
+#ifdef SAVE_PID
+       SAVE_PID
+#endif
+
        /* Stuff the syscall number in RAX and enter into the kernel.  */
        movl    $__NR_vfork, %eax
        syscall
@@ -46,6 +50,10 @@ __vfork:
        /* Push back the return PC.  */
        pushq   %rdi
 
+#ifdef RESTORE_PID
+       RESTORE_PID
+#endif
+
        cmpl    $-4095, %eax
        jae __syscall_error             /* Branch forward if it failed.  */
 
index ad94803..e0f4231 100644 (file)
 #include <errno.h>
 #include <termios.h>
 #include <sys/ioctl.h>
-
-#ifdef __LINUXTHREADS_OLD__
-extern __typeof(tcdrain) weak_function tcdrain;
-strong_alias(tcdrain,__libc_tcdrain)
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include <sysdep-cancel.h>
 #endif
 
+libc_hidden_proto(ioctl)
+
+extern __typeof(tcdrain) __libc_tcdrain;
 /* Wait for pending output to be written on FD.  */
-int tcdrain(int fd)
+int __libc_tcdrain (int fd)
 {
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+       if (SINGLE_THREAD_P)
+               /* With an argument of 1, TCSBRK for output to be drain.  */
+               return INLINE_SYSCALL (ioctl, 3, fd, TCSBRK, 1);
+
+       int oldtype = LIBC_CANCEL_ASYNC ();
+
+       /* With an argument of 1, TCSBRK for output to be drain.  */
+       int result = INLINE_SYSCALL (ioctl, 3, fd, TCSBRK, 1);
+
+       LIBC_CANCEL_RESET (oldtype);
+
+       return result;
+#else
        return ioctl(fd, TCSBRK, 1);
+#endif
 }
+weak_alias(__libc_tcdrain,tcdrain)
index 741672e..c3b5631 100644 (file)
 #include <paths.h>
 #include <signal.h>
 #include <unistd.h>
+#include <not-cancel.h>
+#include <errno.h>
+
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include <sys/stat.h>
+#endif
+
+#ifdef __UCLIBC_HAS_LFS__
+#define STAT stat64
+#define FSTAT fstat64
+#else
+#define STAT stat
+#define FSTAT fstat
+#endif
 
 #if defined __USE_BSD || (defined __USE_XOPEN && !defined __USE_UNIX98)
 
@@ -97,15 +111,40 @@ int daemon(int nochdir, int noclose)
        if (setsid() == -1)
                return -1;
 
+#ifndef __UCLIBC_HAS_THREADS_NATIVE__
+       /* Make certain we are not a session leader, or else we
+        * might reacquire a controlling terminal */
+       if (fork())
+               _exit(0);
+#endif
+
        if (!nochdir)
                chdir("/");
 
-       if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR)) != -1) {
-               dup2(fd, STDIN_FILENO);
-               dup2(fd, STDOUT_FILENO);
-               dup2(fd, STDERR_FILENO);
-               if (fd > 2)
-                       close(fd);
+       if (!noclose)
+       {
+               struct STAT st;
+
+               if ((fd = open_not_cancel(_PATH_DEVNULL, O_RDWR, 0)) != -1
+                       && (__builtin_expect (FSTAT (fd, &st), 0) == 0))
+               {
+                       if (__builtin_expect (S_ISCHR (st.st_mode), 1) != 0) {
+                               dup2(fd, STDIN_FILENO);
+                               dup2(fd, STDOUT_FILENO);
+                               dup2(fd, STDERR_FILENO);
+                               if (fd > 2)
+                                       close(fd);
+                       } else {
+                               /* We must set an errno value since no
+                                  function call actually failed.  */
+                               close_not_cancel_no_status (fd);
+                               __set_errno (ENODEV);
+                               return -1;
+                       }
+               } else {
+                       close_not_cancel_no_status (fd);
+                       return -1;
+               }
        }
        return 0;
 }
index af4389b..b7cb494 100644 (file)
 #ifdef __UCLIBC_HAS_REGEX__
 #include <regex.h>
 #endif
-
-#ifdef HAVE_LINUX_CPUMASK_H
-# include <linux/cpumask.h>
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include <sysdep.h>
 #endif
+
 #ifndef num_present_cpus
 # define num_present_cpus() (1)
 #endif
@@ -906,13 +906,32 @@ long int sysconf(int name)
 #endif
 
     case _SC_MONOTONIC_CLOCK:
-#if defined __UCLIBC_HAS_REALTIME__ && defined __NR_clock_getres
-      /* Check using the clock_getres system call.  */
+#ifdef __NR_clock_getres
+    /* Check using the clock_getres system call.  */
+# ifdef __UCLIBC_HAS_THREADS_NATIVE__
+    {
+      struct timespec ts;
+      INTERNAL_SYSCALL_DECL (err);
+      int r;
+      r = INTERNAL_SYSCALL (clock_getres, err, 2, CLOCK_MONOTONIC, &ts);
+      return INTERNAL_SYSCALL_ERROR_P (r, err) ? -1 : _POSIX_VERSION;
+    }
+# else
       if (clock_getres(CLOCK_MONOTONIC, NULL) >= 0)
         return _POSIX_VERSION;
+
+      RETURN_NEG_1;
+# endif
 #endif
 
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+    case _SC_THREAD_CPUTIME:
+# if _POSIX_THREAD_CPUTIME > 0
+      return _POSIX_THREAD_CPUTIME;
+# else
       RETURN_NEG_1;
+# endif
+#endif
     }
 }
 libc_hidden_def(sysconf)
diff --git a/libpthread/nptl/.gitignore b/libpthread/nptl/.gitignore
new file mode 100644 (file)
index 0000000..c7ded8e
--- /dev/null
@@ -0,0 +1,21 @@
+#
+# Never ignore these
+#
+!.gitignore
+
+#
+# Generated files
+#
+gen_l*
+pthread-errnos.[hcs]
+tcb-offsets.[hcs]
+lowlevelbarrier.h
+lowlevelcond.h
+lowlevelrwlock.h
+lowlevelrobustlock.h
+unwindbuf.h
+structsem.h
+pthread-pi-defines.h
+sysdeps/pthread/pt-sigaction.c
+sysdeps/pthread/pt-sigfillset.c
+sysdeps/pthread/pt-sigprocmask.c
diff --git a/libpthread/nptl/ChangeLog b/libpthread/nptl/ChangeLog
new file mode 100644 (file)
index 0000000..c81eb03
--- /dev/null
@@ -0,0 +1,11100 @@
+2010-01-15  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S:
+       Fix unwind info.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Likewise.
+
+2010-01-15  Michal Schmidt  <mschmidt@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S:
+       Fix pthread_cond_timedwait with requeue-PI.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S:
+       Fix pthread_cond_wait with requeue-PI.
+
+2010-01-14  Ulrich Drepper  <drepper@redhat.com>
+
+       * Versions: Add pthread_mutex_consistent, pthread_mutexattr_getrobust,
+       and pthread_mutexattr_setrobust for GLIBC_2.12.
+       * pthread_mutex_consistent.c: Define alias pthread_mutex_consistent.
+       * pthread_mutexattr_getrobust.c: Define alias
+       pthread_mutexattr_getrobust.
+       * pthread_mutexattr_setrobust.c: Define alias
+       pthread_mutexattr_setrobust.
+
+2010-01-12  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/pthread.h: Cleanup.  Fix up for XPG7.
+
+2010-01-08  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/pthread.h: Fix pthread_mutex_consistent declaration.
+
+2009-12-18  Thomas Schwinge  <thomas@codesourcery.com>
+
+       * sysdeps/unix/sysv/linux/s390/s390-32/pt-initfini.c (_init): Don't
+       call __gmon_start__.
+       * sysdeps/unix/sysv/linux/s390/s390-64/pt-initfini.c (_init): Likewise.
+
+2009-12-17  Ulrich Drepper  <drepper@redhat.com>
+
+       * pthread_rwlock_init.c (__pthread_rwlock_init): Simplify code by
+       using memset.
+
+2009-12-01  Dinakar Guniguntala  <dino@in.ibm.com>
+
+       * sysdeps/unix/sysv/linux/i386/i486/lowlevellock.h: Define
+       FUTEX_WAIT_REQUEUE_PI and FUTEX_CMP_REQUEUE_PI.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S: If mutex
+       is a non robust PI mutex, then use FUTEX_CMP_REQUEUE_PI.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_signal.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: If mutex
+       is a non robust PI mutex, then use FUTEX_WAIT_REQUEUE_PI.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Likewise.
+
+2009-12-12  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/i486/sem_timedwait.S (sem_timedwait):
+       Don't update nwaiters after invalid timeout is recognized.
+
+2009-11-27  Thomas Schwinge  <thomas@codesourcery.com>
+
+       * sysdeps/unix/sysv/linux/sh/pt-initfini.c (_init): Don't call
+       __gmon_start__.
+
+2009-11-27  Andreas Schwab  <schwab@redhat.com>
+
+       * sysdeps/unix/sysv/linux/x86_64/cancellation.S: Reload
+       THREAD_SELF->cancelhandling after returning from futex call.
+
+2009-11-24  Ulrich Drepper  <drepper@redhat.com>
+
+       * tst-sem13.c: New file.
+       * Makefile (tests): Add tst-sem13.
+
+2009-11-22  Roland McGrath  <roland@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/dl-sysdep.h: # include "i686/dl-sysdep.h"
+       instead of recapitulating its contents.
+
+2009-11-18  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S: Minor
+       optimizations and cleanups.
+
+2009-11-18  Dinakar Guniguntala  <dino@in.ibm.com>
+
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S:
+       Remove redundant code. Fix cfi offsets.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_signal.S:
+       Fix cfi offsets.
+
+2009-11-17  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: Minimally
+       reduce size of unwind info.
+
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Convert to use
+       cfi directives.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Likewise.
+       Based on a patch by Dinakar Guniguntala <dino@in.ibm.com>.
+
+2009-11-03  Andreas Schwab  <schwab@linux-m68k.org>
+
+       [BZ #4457]
+       * sysdeps/pthread/unwind-resume.c: Include <libgcc_s.h> and use
+       LIBGCC_S_SO.
+       * sysdeps/pthread/unwind-forcedunwind.c: Likewise.
+
+2009-10-30  Ulrich Drepper  <drepper@redhat.com>
+
+       * tst-sem11.c (main): Rewrite to avoid aliasing problems.
+
+       [BZ #3270]
+       * allocatestack.c (__nptl_setxid): Perform the operation in multiple
+       steps to avoid races with creation and terminations.
+       * nptl-init.c (sighandler_setxid): Adjust.
+       Patch by Daniel Jacobowitz.
+
+2009-09-07  Andreas Schwab  <schwab@redhat.com>
+
+       * sysdeps/pthread/bits/libc-lock.h (BP_SYM): Remove space before paren.
+
+2009-09-02  Suzuki K P  <suzuki@in.ibm.com>
+           Joseph Myers  <joseph@codesourcery.com>
+
+       [BZ #7094]
+       * sysdeps/unix/sysv/linux/timer_create.c (timer_create):
+       Initialize the sigev_notify field for newly created timer to make sure
+       the timer gets deleted from the active timer's list upon timer_delete.
+
+2009-08-27  Andrew Stubbs  <ams@codesourcery.com>
+
+       * sysdeps/unix/sysv/linux/sh/lowlevellock.S (__lll_timedlock_wait):
+       Correct a logic error.
+
+2009-08-25  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/x86_64/tls.h (RTLD_ENABLE_FOREIGN_CALL): Store old value
+       of the field in local variables.
+       (RTLD_FINALIZE_FOREIGN_CALL): Restore rtld_must_xmm_save from local
+       variable and don't unconditionally clear it.
+
+2009-08-24  Ulrich Drepper  <drepper@redhat.com>
+
+       * pthread_create.c (start_thread): Hint to the kernel that memory for
+       the stack can be reused.  We do not mark all the memory.  The part
+       still in use and some reserve are kept.
+
+2009-08-23  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/bits/posix_opt.h: Clean up namespace.
+
+2009-08-11  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_unlock.S: Add CFI
+       directives.
+
+2009-08-10  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_rdlock.S: Add CFI
+       directives.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_wrlock.S: Likewise.
+
+2009-08-10  Andreas Schwab  <schwab@redhat.com>
+
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_signal.S
+       (__pthread_cond_signal): Don't clobber register used for syscall
+       number.
+
+2009-08-08  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S (sem_timedwait):
+       Optimize code path used when FUTEX_CLOCK_REALTIME is supported.
+
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S
+       (__pthread_cond_wait): Optimize by avoiding use of callee-safe
+       register.
+
+2009-08-07  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/x86_64/sem_wait.S: Little optimizations
+       enabled by the special *_asynccancel functions.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S: Likewise.
+
+       * sysdeps/unix/sysv/linux/x86_64/cancellation.S: Include lowlevellock.h.
+
+2009-08-04  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/x86_64/cancellation.S: New file.
+       * sysdeps/unix/sysv/linux/x86_64/libc-cancellation.S: New file.
+       * sysdeps/unix/sysv/linux/x86_64/librt-cancellation.S: New file.
+       * sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h (PSEUDO): Optimize
+       since we can assume the special __*_{en,dis}able_asynccancel
+       functions.
+       (PUSHARGS_*, POPARGS_*, SAVESTK_*, RESTSTK_*): Removed.
+       * sysdeps/x86_64/tcb-offsets.sym: Add cancellation-related bits
+       and PTHREAD_CANCELED.
+
+2009-07-31  Ulrich Drepper  <drepper@redhat.com>
+
+       * descr.h: Better definition of *_BITMASK macros for cancellation.
+
+2009-07-29  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/x86_64/tls.h (TLS_TCB_ALIGN): Define explicitly to 32.
+
+       * sysdeps/x86_64/tls.h (tcbhead_t): Add room for SSE registers the
+       dynamic linker might have to save.
+       Define RTLD_CHECK_FOREIGN_CALL, RTLD_ENABLE_FOREIGN_CALL,
+       RTLD_PREPARE_FOREIGN_CALL, and RTLD_FINALIZE_FOREIGN_CALL.  Pretty
+       printing.
+
+       * sysdeps/x86_64/tcb-offsets.sym: Add RTLD_SAVESPACE_SSE.
+
+2009-07-28  Ulrich Drepper  <drepper@redhat.com>
+
+       * pthread_mutex_lock.c [NO_INCR] (__pthread_mutex_cond_lock_adjust):
+       New function.
+       * pthreadP.h: Declare __pthread_mutex_cond_lock_adjust.
+       * sysdeps/unix/sysv/linux/pthread-pi-defines.sym: Add ROBUST_BIT.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S: Don't use
+       requeue_pi for robust mutexes.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_signal.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S: Likewise.
+       Don't only skip __pthread_mutex_cond_lock.  Call instead
+       __pthread_mutex_cond_lock_adjust.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: Likewise.
+
+       * pthread_mutex_unlock.c (__pthread_mutex_unlock_full): Minor
+       optimization of PI mutex handling.
+
+2009-07-27  Ulrich Drepper  <drepper@redhat.com>
+
+       [BZ #10418]
+       * pthread_mutex_unlock.c (__pthread_mutex_unlock_full): Use _rel
+       instead of of _acq variants of cmpxchg.
+
+2009-07-23  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/x86_64/configure.in: New file.
+
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: Fix error
+       path when not using absolute timeout futex.
+
+2009-07-20  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S: Minor
+       optimizations of last changes.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: Likewise.
+
+2009-07-19  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h: Define
+       FUTEX_WAIT_REQUEUE_PI and FUTEX_CMP_REQUEUE_PI.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S: If mutex
+       is a PI mutex, then use FUTEX_CMP_REQUEUE_PI.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_signal.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: If mutex
+       is a PI mutex, then use FUTEX_WAIT_REQUEUE_PI.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S: Likewise.
+
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S
+       (__pthread_cond_timedwait): Make more robust.
+
+2009-07-18  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/x86_64/lowlevelrobustlock.S
+       (__lll_robust_timedlock_wait): If possible use FUTEX_WAIT_BITSET to
+       directly use absolute timeout.
+
+       * tst-sem5.c (do_test): Add test for premature timeout.
+       * Makefile: Linu tst-sem5 with librt.
+
+       * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedwrlock.S
+       (pthread_rwlock_timedwrlock): If possible use FUTEX_WAIT_BITSET to
+       directly use absolute timeout.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedrdlock.S
+       (pthread_rwlock_timedrdlock): Likewise.
+
+       * tst-cond11.c (run_test): Add test to check that the timeout is
+       long enough.
+
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S
+       (__pthread_cond_timedwait): If possible use FUTEX_WAIT_BITSET to
+       directly use absolute timeout.
+
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S
+       (__pthread_cond_wait): Convert to using exception handler instead of
+       registered unwind buffer.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S
+       (__pthread_cond_timedwait): Likewise.
+
+2009-07-17  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S (sem_timedwait):
+       If possible use FUTEX_WAIT_BITSET|FUTEX_CLOCK_REALTIME to directly
+       use absolute timeout.
+
+       * sysdeps/unix/sysv/linux/x86_64/sem_wait.S (sem_wait): Optimize
+       handling of uncontested semaphore.
+
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S
+       (__condvar_cleanup): Rewrite to use cfi directives instead of
+       hand-coded unwind tables.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_once.S (__pthread_once):
+       Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/sem_wait.S (sem_wait): Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S (sem_timedwait):
+       Likewise.
+
+2009-06-12  Ulrich Drepper  <drepper@redhat.com>
+
+       * Makefile (libpthread-routines): Add pthread_sigqueue.
+       * Versions: Add pthread_sigqueue for GLIBC_2.11.
+       * sysdeps/pthread/bits/sigthread.h: Declare pthread_sigqueue.
+       * sysdeps/unix/sysv/linux/pthread_sigqueue.c: New file.
+
+2009-06-11  Ulrich Drepper  <drepper@redhat.com>
+
+       [BZ #10262]
+       * sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S
+       (LOAD_FUTEX_WAIT_ABS): Fix futex parameter in case private futexes
+       cannot be assumed.
+       Patch by Bryan Kadzban <bz-glibc@kdzbn.homelinux.net>.
+
+2009-05-16  Ulrich Drepper  <drepper@redhat.com>
+
+       * libc-cancellation.c: Move __libc_cleanup_routine to...
+       * libc-cleanup.c: ...here.  New file.
+       * Makefile (routines): Add libc-cleanup.
+
+       * cancellation.c (__pthread_disable_asynccancel): Remove unnecessary
+       test.
+       * libc-cancellation.c: Use <nptl/cancellation.c: to define the code.
+       * sysdeps/pthread/librt-cancellation.c: Likewise.
+
+       [BZ #9924]
+       * nptl-init.c: Renamed from init.c.
+       * Makefile: Change all occurences of init.c to nptl-init.c.
+
+2009-05-15  Ulrich Drepper  <drepper@redhat.com>
+
+       * cancellation.c (__pthread_disable_asynccancel): Correct the bits
+       to test when deciding on the delay.
+       * libc-cancellation.c (__libc_disable_asynccancel): Likewise.
+       * pthread_cancel.c: Close race between deciding on sending a signal
+       and setting the CANCELING_BIT bit.
+
+       * cancellation.c (__pthread_disable_asynccancel): Don't return if
+       thread is canceled.
+       * libc-cancellation.c (__libc_disable_asynccancel): Likewise.
+
+2009-04-27  Ulrich Drepper  <drepper@redhat.com>
+
+       * cancellation.c (__pthread_disable_asynccancel): Use THREAD_ATOMIC_AND
+       is available.
+       * libc-cancellation.c (__libc_disable_asynccancel): Likewise.
+       * sysdeps/x86_64/tls.h: Define THREAD_ATOMIC_AND.
+       * sysdeps/i386/tls.h: Likewise.
+       (tcbhead_t): Add __private_tm member.
+
+2009-04-26  Ulrich Drepper  <drepper@redhat.com>
+
+       * sem_open.c (sem_open): Rewrite initialization of initsem to
+       avoid warnings.
+
+       * sysdeps/unix/sysv/linux/libc_pthread_init.c (__libc_pthread_init):
+       Avoid warning by using may_alias attribute on ptrhack.
+
+2009-04-22  Ulrich Drepper  <drepper@redhat.com>
+
+       [BZ #10090]
+       * pthread_attr_setschedparam.c (__pthread_attr_setschedparam):
+       Check policy and priority for validity.
+       Patch mostly by Zhang Xiliang <zhangxiliang@cn.fujitsu.com>.
+
+2009-03-15  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S
+       (__pthread_cond_timedwait): Change to use cfi directives instead of
+       hand-coded unwind sections.
+
+2009-03-10  Ulrich Drepper  <drepper@redhat.com>
+
+       * init.c (nptl_freeres): Compile only for SHARED.
+
+2009-03-09  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/sparc/lowlevellock.h: Define
+       FUTEX_WAIT_BITSET, FUTEX_WAKE_BITSET, FUTEX_CLOCK_REALTIME and
+       FUTEX_BITSET_MATCH_ANY.
+
+2009-02-27  Roland McGrath  <roland@redhat.com>
+
+       * init.c (__nptl_initial_report_events): Mark __attribute_used__.
+       * pthread_create.c (__nptl_threads_events, __nptl_last_event): Likewise.
+
+2009-02-26  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/bits/posix_opt.h: Define
+       _POSIX_THREAD_ROBUST_PRIO_INHERIT and
+       _POSIX_THREAD_ROBUST_PRIO_PROTECT.  Reset value of macros from
+       200112L to 200809L.
+
+2009-02-25  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/pthread.h: The robust mutex functions are in
+       POSIX 2008.
+
+2009-02-24  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/bits/posix_opt.h (_BITS_POSIX_OPT_H):
+       Unify name of include protector macro.
+
+2009-02-14  SUGIOKA Toshinobu  <sugioka@itonet.co.jp>
+
+       * sysdeps/unix/sysv/linux/sh/lowlevellock.S: Define
+       LOAD_FUTEX_WAIT_ABS even if (FUTEX_WAIT == 0).
+
+2009-01-29  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/unwind-forcedunwind.c: Encrypt all function
+       pointer variables.
+
+       * allocatestack.c (__free_stacks): Renamed from free_stacks.
+       (__free_stack_cache): Removed.  Change callers to call __free_stacks.
+       * init.c (nptl_freeres): New function.
+       (pthread_functions): Initialize ptr_freeres to nptl_freeres.
+       * pthreadP.h: Don't declare __free_stack_cache.  Declare __free_stacks.
+       * sysdeps/pthread/unwind-forcedunwind.c (libgcc_s_handle): New
+       variable.
+       (pthread_cancel_init): Depend in libgcc_s_handle for decision to
+       load DSO.  Assign last.
+       (__unwind_freeres): New function.
+
+       * allocatestack.c (__reclaim_stacks): Reset in_flight_stack later
+       for better debugging.  No need to use stack_list_add here.
+
+2009-01-14  Kaz Kojima  <kkojima@rr.iij4u.or.jp>
+
+       * sysdeps/unix/sysv/linux/sh/lowlevellock.S
+       (__lll_timedlock_wait): Use FUTEX_WAIT_BITSET|FUTEX_CLOCK_REALTIME
+       instead of computing relative timeout.
+       * sysdeps/unix/sysv/linux/sh/lowlevellock.h: Define
+       FUTEX_CLOCK_REALTIME and FUTEX_BITSET_MATCH_ANY.
+
+2009-01-25  Ulrich Drepper  <drepper@redhat.com>
+
+       * pthread_mutex_lock.c (__pthread_mutex_lock): Remove unused label out.
+
+2009-01-08  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/list.h (list_add): Initialize new element first.
+       (list_add_tail): Removed.
+
+2009-01-07  Ulrich Drepper  <drepper@redhat.com>
+
+       * (in_flight_stack): New variable.
+       (stack_list_del): New function.  Use instead of list_del.
+       (stack_list_add): New function.  Use instead of list_add when adding to
+       stack_cache and stack_used lists.
+       (__reclaim_stacks): Complete operations on stack_cache and stack_used lists
+       when the fork call interrupted another thread.
+
+2009-01-04  Ulrich Drepper  <drepper@redhat.com>
+
+       * init.c (__pthread_initialize_minimal_internal): Optimize test
+       FUTEX_CLOCK_REALTIME a bit.
+
+2009-01-03  Ulrich Drepper  <drepper@redhat.com>
+
+       * init.c (__pthread_initialize_minimal_internal): Cheat a bit by
+       only passing five parameters to FUTEX_WAIT_BITSET call.
+
+       * sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S
+       (__lll_timedlock_wait): Use FUTEX_WAIT_BITSET|FUTEX_CLOCK_REALTIME
+       instead of computing relative timeout.
+
+2009-01-02  Ulrich Drepper  <drepper@redhat.com>
+
+       * init.c (__pthread_initialize_minimal_internal): Check for
+       FUTEX_CLOCK_REALTIME flag.
+       * sysdeps/unix/sysv/linux/x86_64/lowlevellock.S (__lll_timedlock_wait):
+       Use FUTEX_WAIT_BITSET|FUTEX_CLOCK_REALTIME instead of computing
+       relative timeout.
+
+       * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h: Define
+       FUTEX_CLOCK_REALTIME and FUTEX_BITSET_MATCH_ANY.
+       * sysdeps/unix/sysv/linux/i386/lowlevellock.h: Likewise.
+       * sysdeps/unix/sysv/linux/ia64/lowlevellock.h: Likewise.
+       * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h: Likewise.
+       * sysdeps/unix/sysv/linux/s390/lowlevellock.h: Likewise.
+
+2008-12-09  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/pthread.h (pthread_cleanup_pop): Use { } as empty
+       loop body instead of ; to avoid gcc warnings.
+       (pthread_cleanup_pop_restore_np): Likewise.
+       Patch by Caolán McNamara <caolanm@redhat.com>.
+
+2008-12-09  Jakub Jelinek  <jakub@redhat.com>
+
+       * pthread_mutex_lock.c (__pthread_mutex_lock): Handle only the
+       fast path here, for robust/PI/PP mutexes call
+       __pthread_mutex_lock_full.  Don't use switch, instead use a series
+       of ifs according to their probability.
+       (__pthread_mutex_lock_full): New function.
+       * pthread_mutex_unlock.c: Include assert.h.
+       (__pthread_mutex_unlock_usercnt): Handle only the
+       fast path here, for robust/PI/PP mutexes call
+       __pthread_mutex_unlock_full.  Don't use switch, instead use a series
+       of ifs according to their probability.
+       (__pthread_mutex_unlock_full): New function.
+       * sysdeps/unix/sysv/linux/pthread_mutex_cond_lock.c
+       (__pthread_mutex_lock_full): Define.
+
+2008-12-08  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/x86_64/tls.h (tcbhead_t): Add fields reserved for TM
+       implementation.  Add necessary padding and.
+       * descr.h (struct pthread): Increase padding for tcbhead_t to 24
+       words.
+
+2008-12-04  Kaz Kojima  <kkojima@rr.iij4u.or.jp>
+
+       * sysdeps/unix/sysv/linux/sh/lowlevellock.h: Define FUTEX_WAIT_BITSET
+       and FUTEX_WAKE_BITSET.
+
+2008-12-02  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/lowlevellock.h: Define FUTEX_WAIT_BITSET
+       and FUTEX_WAKE_BITSET.
+       * sysdeps/unix/sysv/linux/ia64/lowlevellock.h: Likewise.
+       * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h: Likewise.
+       * sysdeps/unix/sysv/linux/s390/lowlevellock.h: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h: Likewise.
+
+2008-11-25  Roland McGrath  <roland@redhat.com>
+
+       * sysdeps/alpha, sysdeps/unix/sysv/linux/alpha:
+       Subdirectories moved to ports repository as
+       sysdeps/.../nptl subdirectories.
+
+2008-11-12  Jakub Jelinek  <jakub@redhat.com>
+
+       [BZ #7008]
+       * pthread_condattr_setclock.c (pthread_condattr_setclock): Fix masking
+       of old value.
+       * pthread_cond_init.c (__pthread_cond_init): Fix
+       cond->__data.__nwaiters initialization.
+       * Makefile (tests): Add tst-cond23.
+       * tst-cond23.c: New test.
+
+2008-11-07  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/pthread/malloc-machine.h (MALLOC): Adjust __libc_tsd_define
+       arguments.
+       (tsd_setspecific, tsd_getspecific): Adjust __libc_tsd_{set,get}
+       arguments.
+
+2008-11-01  Ulrich Drepper  <drepper@redhat.com>
+
+       [BZ #6955]
+       * pthread_mutex_lock.c: Add support for private PI mutexes.
+       * pthread_mutex_timedlock.c: Likewise.
+       * pthread_mutex_trylock.c: Likewise.
+       * pthread_mutex_unlock.c: Likewise.
+       Patch mostly by Ben Jackson <ben@ben.com>.
+
+2008-10-31  Ulrich Drepper  <drepper@redhat.com>
+
+       [BZ #6843]
+       * sysdeps/pthread/gai_misc.h (__gai_create_helper_thread):
+       Increase stack size for helper thread.
+
+2008-10-06  Martin Schwidefsky  <schwidefsky@de.ibm.com>
+
+       * sysdeps/s390/tls.h (THREAD_SET_STACK_GUARD): Add empty inline
+       assembly with a clobber list for access registers a0 and a1.
+
+2008-09-11  Martin Schwidefsky  <schwidefsky@de.ibm.com>
+
+       * sysdeps/unix/sysv/linux/fork.c (__libc_fork): Add memory barrier
+       to force runp->refcntr to be read from memory.
+
+2008-09-08  Richard Guenther  <rguenther@suse.de>
+
+       * sysdeps/unix/sysv/linux/i386/lowlevellock.h (lll_lock,
+       lll_robust_lock, lll_cond_lock, lll_robust_cond_lock,
+       lll_timedlock, lll_robust_timedlock, lll_unlock,
+       lll_robust_unlock): Promote private to int.
+
+2008-08-15  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/x86_64/pthreaddef.h: Remove ARCH_MAP_FLAGS and
+       ARCH_RETRY_MMAP definitions.
+       * allocatestack.c: Remove definition of ARCH_MAP_FLAGS.
+       Define MAP_STACK when not defined.
+       (allocate_stack): Use MAP_STACK instead of ARCH_MAP_FLAGS.  Remove
+       handling of ARCH_RETRY_MMAP.
+
+2008-07-30  Ulrich Drepper  <drepper@redhat.com>
+
+       * tst-align2.c (f): Print message that f is reached.
+
+2008-04-28  Hiroki Kaminaga  <kaminaga@sm.sony.co.jp>
+
+       [BZ #6740]
+       * sysdeps/powerpc/tcb-offsets.sym (PRIVATE_FUTEX_OFFSET): Guard symbol
+       definition with #ifndef __ASSUME_PRIVATE_FUTEX.
+
+2008-07-25  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/mq_notify.c (init_mq_netlink): Use
+       SOCK_CLOEXEC if possible.
+
+2008-05-29  Ulrich Drepper  <drepper@redhat.com>
+
+       * Makefile (tests): Add tst-rwlock2a.
+       * tst-rwlock2.c: Use TYPE macro to decide what rwlock type to use.
+       * tst-rwlock2a.c: New file.
+
+2008-06-12  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/pthread.h: Remove inadvertant checkin.
+
+2008-05-17  Samuel Thibault  <samuel.thibault@ens-lyon.org>
+
+       * sysdeps/pthread/pthread.h: Fix typo in comment.
+
+2008-05-28  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/createthread.c (do_clone): Pass accurate length
+       of CPU set to the kernel.
+
+2008-05-23  Paul Pluzhnikov  <ppluzhnikov@google.com>
+
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_barrier_wait.S: Add
+       cfi directives.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_signal.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_rdlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_unlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_wrlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/sem_post.S: Likewise.
+
+2008-05-22  Paul Pluzhnikov  <ppluzhnikov@google.com>
+
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedrdlock.S: Add
+       cfi directives.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedwrlock.S:
+       Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedrdlock.S:
+       Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedwrlock.S:
+       Likewise.
+
+2008-05-26  Ulrich Drepper  <drepper@redhat.com>
+
+       * tst-typesizes.c: Explicitly check __SIZEOF_PTHREAD_* constants.
+
+2008-05-20  Jakub Jelinek  <jakub@redhat.com>
+
+       David S. Miller  <davem@davemloft.net>
+
+       * sysdeps/unix/sysv/linux/sparc/sparc64/Makefile: New file.
+
+2008-05-10  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_rdlock.S: Access
+       __pshared correctly.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedrdlock.S:
+       Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedwrlock.S:
+       Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_unlock.S:
+       Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_wrlock.S:
+       Likewise.
+       Reported by Clemens Kolbitsch <clemens.kol@gmx.at>.
+
+2008-04-14  David S. Miller  <davem@davemloft.net>
+
+       * sysdeps/unix/sysv/linux/sparc/sparc32/sem_wait.c
+       (__old_sem_wait): Fix argument to lll_futex_wait().
+
+2007-11-26  Daniel Jacobowitz  <dan@codesourcery.com>
+
+       * pthread_create.c: Require pthread_mutex_trylock and
+       pthread_key_delete for libgcc.
+
+2008-04-08  Jakub Jelinek  <jakub@redhat.com>
+
+       [BZ #6020]
+       * sysdeps/unix/sysv/linux/sparc/lowlevellock.h
+       (lll_futex_wake_unlock): Add private argument to the pre-v9 macro.
+       Patch by Sunil Amitkumar Janki <devel.sjanki@gmail.com>.
+
+2008-03-27  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/bits/local_lim.h: Undefine ARG_MAX if
+       <linux/limits.h> has defined it.
+       * sysdeps/unix/sysv/linux/alpha/bits/local_lim.h: Likewise.
+       * sysdeps/unix/sysv/linux/ia64/bits/local_lim.h: Likewise.
+       * sysdeps/unix/sysv/linux/powerpc/bits/local_lim.h: Likewise.
+       * sysdeps/unix/sysv/linux/sparc/bits/local_lim.h: Likewise.
+
+2008-03-18  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/ia64/dl-sysdep.h: Use __ASSEMBLER__ instead
+       of ASSEMBLER.
+       * sysdeps/unix/sysv/linux/i386/i686/dl-sysdep.h: Likewise.
+       * sysdeps/unix/sysv/linux/i386/dl-sysdep.h: Likewise.
+
+2008-03-14  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/dl-sysdep.h: Define
+       HAVE_DL_DISCOVER_OSVERSION.
+       * sysdeps/unix/sysv/linux/i386/i686/dl-sysdep.h: Likewise.
+       * sysdeps/unix/sysv/linux/ia64/dl-sysdep.h: Likewise.
+
+2008-03-07  Ulrich Drepper  <drepper@redhat.com>
+
+       [BZ #5778]
+       * sysdeps/unix/sysv/linux/bits/posix_opt.h: Change
+       _POSIX_CHOWN_RESTRICTED value to zero.
+
+2008-01-31  Roland McGrath  <roland@redhat.com>
+
+       * Makefile (omit-deps): Variable removed.
+
+2008-01-30  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/x86_64/sem_post.S (sem_post): Avoid
+       unnecessary addr32 prefix.
+
+2008-01-29  Roland McGrath  <roland@redhat.com>
+
+       * Makeconfig (ptw-CPPFLAGS, sysd-rules-patterns): New variables.
+
+2008-01-22  Kaz Kojima  <kkojima@rr.iij4u.or.jp>
+
+       * sysdeps/unix/sysv/linux/sh/sem_post.S: Don't overflow value field.
+
+2008-01-21  Kaz Kojima  <kkojima@rr.iij4u.or.jp>
+
+       * sysdeps/unix/sysv/linux/sh/lowlevel-atomic.h (XADD): Use
+       a scratch register.
+       * sysdeps/unix/sysv/linux/sh/lowlevellock.S
+       (__lll_lock_wait_private): Fix typo.
+       * sysdeps/unix/sysv/linux/sh/pthread_barrier_wait.S
+       (pthread_barrier_wait): Likewise.  Adjust XADD use.
+       * sysdeps/unix/sysv/linux/sh/sem_post.S (__new_sem_post):
+       Adjust XADD use.
+       * sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedrdlock.S
+       (pthread_rwlock_timedrdlock): Return correct return value.
+       * sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedwrlock.S
+       (pthread_rwlock_timedwrlock): Likewise.
+
+2008-01-15  Ulrich Drepper  <drepper@redhat.com>
+
+       * tst-eintr2.c (do_test): make sure that if mutex_lock in main
+       thread returns the program exits with an error code.
+
+2008-01-10  Ulrich Drepper  <drepper@redhat.com>
+
+       * pthread-errnos.sym: Add EOVERFLOW.
+       * sysdeps/unix/sysv/linux/structsem.sym: Add SEM_VALUE_MAX.
+       * sysdeps/unix/sysv/linux/sem_post.c: Don't overflow value field.
+       * sysdeps/unix/sysv/linux/i386/i486/sem_post.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/sem_post.S: Likewise.
+
+2007-12-14  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/x86_64/pthreaddef.h (ARCH_RETRY_MMAP): Take additional
+       parameter.  Passed it as permission to mmap.
+       * allocatestack.c (allocate_stack): Pass prot as second parameter
+       to ARCH_RETRY_MMAP.
+
+2007-12-12  Ulrich Drepper  <drepper@redhat.com>
+
+       * tst-basic7.c: Allocate memory for the stack.
+
+       [BZ #5465]
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S [!SHARED]
+       (__pthread_cond_timedwait): Don't use VDSO.
+       Patch by Michal Januszewski.
+
+2007-12-07  Ulrich Drepper  <drepper@redhat.com>
+
+       [BZ #5455]
+       * sysdeps/pthread/pthread.h [!__EXCEPTIONS] (pthread_cleanup_pop):
+       Allow label before pthread_cleanup_pop.
+       (pthread_cleanup_pop_restore_np): Likewise.
+
+2007-12-04  Kaz Kojima  <kkojima@rr.iij4u.or.jp>
+
+       * sysdeps/unix/sysv/linux/sh/lowlevellock.S (__lll_timedlock_wait):
+       Store 2 before returning ETIMEDOUT.
+
+2007-11-23  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/x86_64/lowlevellock.S (__lll_timedlock_wait):
+       Store 2 before returning ETIMEDOUT.
+       * sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S: Likewise
+       * sysdeps/unix/sysv/linux/lowlevellock.c: Likewise.
+       (__lll_lock_wait_private): Optimize.
+       (__lll_lock_wait): Likewise.
+
+2007-11-20  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/pthread/pthread.h (pthread_cleanup_push,
+       pthread_cleanup_push_defer_np): Add extra (void *) cast to shut up
+       g++ 4.1 and 4.2 -Wstrict-aliasing warnings.
+
+2007-11-08  Ulrich Drepper  <drepper@redhat.com>
+
+       [BZ #5240]
+       * sysdeps/unix/sysv/linux/lowlevellock.c (__lll_timedlock_wait):
+       If we time out, try one last time to lock the futex to avoid
+       losing a wakeup signal.
+       * sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/lowlevellock.S: Likewise.
+
+       [BZ #5245]
+       * sysdeps/pthread/createthread.c (do_clone): Translate clone error
+       if necessary.
+
+2007-11-07  Ulrich Drepper  <drepper@redhat.com>
+
+       [BZ #5245]
+       * allocatestack.c (allocate_stack): Change ENOMEM error in case
+       mmap failed to EAGAIN.
+       * Makefile (tests): Add tst-basic7.
+       * tst-basic7.c: New file.
+
+2007-11-05  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/register-atfork.c (__register_atfork):
+       Use __linkin_atfork.
+
+2007-11-03  Mike Frysinger  <vapier@gentoo.org>
+
+       * sysdeps/unix/sysv/linux/sh/lowlevellock.S (LOAD_FUTEX_WAIT): Add
+       missing line continuations.
+       * sysdeps/unix/sysv/linux/sh/lowlevelrobustlock.S (LOAD_FUTEX_WAIT,
+       LOAD_FUTEX_WAKE): Likewise.  Also add missing 3rd parameter.
+
+2007-10-28  Ulrich Drepper  <drepper@redhat.com>
+
+       [BZ #5220]
+       * sysdeps/unix/sysv/linux/kernel-posix-timers.h: Declare
+       __active_timer_sigev_thread and __active_timer_sigev_thread_lock.
+       (struct timer): Add next element.
+       * sysdeps/unix/sysv/linux/timer_create.c: For SIGEV_THREAD timers,
+       enqueue timer structure into __active_timer_sigev_thread list.
+       * sysdeps/unix/sysv/linux/timer_delete.c: For SIGEV_THREAD timers,
+       remove timer struct from __active_timer_sigev_thread.
+       * sysdeps/unix/sysv/linux/timer_routines.c (timer_helper_thread):
+       Before using timer structure make sure it is still on the
+       __active_timer_sigev_thread list.  Keep lock until done.
+       Define __active_timer_sigev_thread and
+       __active_timer_sigev_thread_lock.
+
+2007-10-27  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/malloc-machine.h: Define ATFORK_MEM.
+       Redefine thread_atfork for use of ATFORK_MEM.
+       * sysdeps/unix/sysv/linux/fork.h: Define __linkin_atfork.
+       * sysdeps/unix/sysv/linux/register-atfork.c (__linkin_atfork): New
+       function.
+       * sysdeps/unix/sysv/linux/unregister-atfork.c (__unregister_atfork):
+       Use atomic operation when removing first element of list.
+
+2007-10-17  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/i486/sem_post.S (__old_sem_post): New
+       routine instead of an alias to __new_sem_post.
+
+2007-10-15  Jakub Jelinek  <jakub@redhat.com>
+
+       * init.c (__pthread_initialize_minimal): Initialize word to appease
+       valgrind.
+
+2007-10-10  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/pthread/bits/libc-lock.h (__libc_rwlock_init): Inside of
+       libc.so just clear NAME.
+       (__libc_rwlock_fini): Nop inside of libc.so.
+       * tst-initializers1.c (main): Test if PTHREAD_RWLOCK_INITIALIZER is
+       all zeros.
+
+2007-09-02  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S
+       (__pthread_cond_wait): Fix unlocking of internal lock after mutex
+       unlocking failed.
+       Patch by Luca Barbieri <luca.barbieri@gmail.com>.
+
+2007-08-21  Ulrich Drepper  <drepper@redhat.com>
+
+       [BZ #4938]
+       * allocatestack.c (__reclaim_stacks): Clear the TSD in the
+       reclaimed stack if necessary.
+       * Makefile (tests): Add tst-tsd6.
+       * tst-tsd6.c: New file.
+
+2007-08-21  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/alpha/lowlevellock.h (lll_robust_dead):
+       Add private argument.
+
+2007-08-20  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S
+       (__pthread_cond_timedwait): Use clock_gettime from VDSO if possible.
+
+2007-08-16  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/alpha/lowlevellock.h
+       (__lll_robust_timedlock): Pass private as last argument to
+       __lll_robust_timedlock_wait.
+       (__lll_unlock): Fix a pasto.
+
+2007-08-15  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/sparc/internaltypes.h (sparc_new_sem,
+       sparc_old_sem): New structs.
+       * sysdeps/unix/sysv/linux/sparc/sparc32/sem_wait.c
+       (__sem_wait_cleanup): New function.
+       (__new_sem_wait): Use sparc_new_sem structure.  Bump and afterwards
+       decrease nwaiters.  Register __sem_wait_cleanup as cleanup handler.
+       Pass isem->private ^ FUTEX_PRIVATE_FLAG as last argument to
+       lll_futex_wait.
+       (__old_sem_wait): New function.
+       * sysdeps/unix/sysv/linux/sparc/sparc32/sparcv9/sem_wait.c: Include
+       nptl/sysdeps/unix/sysv/linux/sparc version.
+       * sysdeps/unix/sysv/linux/sparc/sparc32/sparcv9/sem_timedwait.c:
+       Likewise.
+       * sysdeps/unix/sysv/linux/sparc/sparc32/sparcv9/sem_post.c: Likewise.
+       * sysdeps/unix/sysv/linux/sparc/sparc32/sem_trywait.c
+       (__new_sem_trywait): Use sparc_old_sem structure.
+       * sysdeps/unix/sysv/linux/sparc/sparc32/sem_timedwait.c
+       (sem_timedwait): Use sparc_new_sem structure.  Bump and afterwards
+       decrease nwaiters.  Register __sem_wait_cleanup as cleanup handler.
+       Pass isem->private ^ FUTEX_PRIVATE_FLAG as last argument to
+       lll_futex_timed_wait.
+       * sysdeps/unix/sysv/linux/sparc/sparc32/sem_post.c (__new_sem_post):
+       Use sparc_new_sem structure.  Only wake if nwaiters > 0.  Pass
+       isem->private ^ FUTEX_PRIVATE_FLAG as last argument to
+       lll_futex_wake.
+       (__old_sem_post): New function.
+       * sysdeps/unix/sysv/linux/sparc/sem_wait.c: New file.
+       * sysdeps/unix/sysv/linux/sparc/sem_init.c: New file.
+       * sysdeps/unix/sysv/linux/sparc/sem_timedwait.c: New file.
+       * sysdeps/unix/sysv/linux/sparc/sem_post.c: New file.
+       * sysdeps/unix/sysv/linux/sparc/sparc32/sparcv9/sem_init.c: Remove.
+       * sysdeps/unix/sysv/linux/sparc/sparc32/sem_init.c: Remove.
+
+2007-08-14  Kaz Kojima  <kkojima@rr.iij4u.or.jp>
+
+       * sysdeps/unix/sysv/linux/sh/pthread_cond_broadcast.S
+       (__pthread_cond_broadcast): Pass LLL_PRIVATE to lll_* and or
+       FUTEX_PRIVATE_FLAG into SYS_futex op if cv is process private.
+       Don't use FUTEX_CMP_REQUEUE if dep_mutex is not process private.
+       * sysdeps/unix/sysv/linux/shpthread_cond_signal.S
+       (__pthread_cond_signal): Pass LLL_PRIVATE to lll_* and or
+       FUTEX_PRIVATE_FLAG into SYS_futex op if cv is process private.
+       Use FUTEX_WAKE_OP.
+       * sysdeps/unix/sysv/linux/sh/pthread_cond_wait.S: Include
+       kernel-features.h and tcb-offsets.h.
+       (__pthread_cond_wait, __condvar_w_cleanup): Pass LLL_PRIVATE to
+       lll_* and or FUTEX_PRIVATE_FLAG into SYS_futex op if cv is
+       process private.
+       * sysdeps/unix/sysv/linux/sh/pthread_cond_timedwait.S: Include
+       tcb-offsets.h.
+       (__pthread_cond_timedwait, __condvar_tw_cleanup): Pass LLL_PRIVATE
+       to lll_* and or FUTEX_PRIVATE_FLAG into SYS_futex op if cv is
+       process private.
+       * sysdeps/unix/sysv/linux/sh/pthread_once.S: Use #ifdef
+       __ASSUME_PRIVATE_FUTEX instead of #if __ASSUME_PRIVATE_FUTEX.
+       * sysdeps/unix/sysv/linux/sh/pthread_rwlock_rdlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedrdlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedwrlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/sh/pthread_rwlock_unlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/sh/pthread_rwlock_wrlock.S: Likewise.
+
+2007-08-14  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/lowlevellock.c: Comment fix.
+       * sysdeps/unix/sysv/linux/sparc/sparc32/lowlevellock.c
+       (__lll_timedwait_tid): Pass LLL_SHARED as 4th argument to
+       lll_futex_timed_wait.
+
+       * sysdeps/unix/sysv/linux/alpha/lowlevellock.h (__lll_unlock,
+       __lll_robust_unlock): Rewrite as macros instead of inline functions.
+       * sysdeps/unix/sysv/linux/s390/lowlevellock.h (__lll_unlock,
+       __lll_robust_unlock, __lll_wait_tid): Likewise.
+
+2007-08-13  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/lowlevellock.h (__lll_private_flag):
+       Fix a pasto.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S
+       (__pthread_cond_broadcast): Pass LLL_PRIVATE to lll_* and or
+       FUTEX_PRIVATE_FLAG into SYS_futex op if cv is process private.
+       Don't use FUTEX_CMP_REQUEUE if dep_mutex is not process private.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_signal.S
+       (__pthread_cond_signal): Pass LLL_PRIVATE to lll_* and or
+       FUTEX_PRIVATE_FLAG into SYS_futex op if cv is process private.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Include
+       kernel-features.h.
+       (__pthread_cond_wait, __condvar_w_cleanup): Pass LLL_PRIVATE to
+       lll_* and or FUTEX_PRIVATE_FLAG into SYS_futex op if cv is
+       process private.  Switch DW_CFA_advance_loc1 and some
+       DW_CFA_advance_loc .eh_frame opcodes to DW_CFA_advance_loc4.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S
+       (__pthread_cond_timedwait, __condvar_tw_cleanup): Pass LLL_PRIVATE to
+       lll_* and or FUTEX_PRIVATE_FLAG into SYS_futex op if cv is
+       process private.  Switch DW_CFA_advance_loc{1,2} and some
+       DW_CFA_advance_loc .eh_frame opcodes to DW_CFA_advance_loc4.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_rdlock.S: Use
+       #ifdef __ASSUME_PRIVATE_FUTEX instead of #if __ASSUME_PRIVATE_FUTEX.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedwrlock.S:
+       Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_unlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_wrlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedrdlock.S:
+       Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S
+       (__pthread_cond_broadcast): Compare %r8 instead of
+       dep_mutex-cond_*(%rdi) with $-1.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_signal.S
+       (__pthread_cond_signal): Xor FUTEX_WAKE_OP with FUTEX_WAKE instead
+       of oring.
+
+2007-08-13  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/i786/Implies: New file.
+
+2007-08-13  Jakub Jelinek  <jakub@redhat.com>
+
+       * allocatestack.c: Include kernel-features.h.
+       * pthread_create.c: Likewise.
+       * pthread_mutex_init.c: Likewise.
+       * init.c: Likewise.
+       * pthread_cond_timedwait.c: Likewise.
+       * sysdeps/unix/sysv/linux/alpha/lowlevellock.h: Likewise.
+       * sysdeps/unix/sysv/linux/ia64/lowlevellock.h: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_wrlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_rdlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_unlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedwrlock.S:
+       Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedrdlock.S:
+       Likewise.
+       * sysdeps/unix/sysv/linux/s390/lowlevellock.h: Likewise.
+       * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h: Likewise.
+       * sysdeps/unix/sysv/linux/sparc/lowlevellock.h: Likewise.
+       * sysdeps/unix/sysv/linux/sh/pthread_cond_timedwait.S: Likewise.
+
+2007-08-12  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/sparc/bits/pthreadtypes.h
+       [__WORDSIZE=32] (pthread_rwlock_t): Split __flags element into four
+       byte elements.  One of them is the new __shared element.
+       [__WORDSIZE=64] (pthread_rwlock_t): Renamed __pad1 element to __shared,
+       adjust names of other padding elements.
+       * sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h
+       [__WORDSIZE=32] (pthread_rwlock_t): Split __flags element into four
+       byte elements.  One of them is the new __shared element.
+       [__WORDSIZE=64] (pthread_rwlock_t): Renamed __pad1 element to __shared,
+       adjust names of other padding elements.
+       * sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h (pthread_rwlock_t):
+       Renamed __pad1 element to __shared, adjust names of other padding
+       elements.
+       * sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h
+       (pthread_rwlock_t): Likewise.
+       * sysdeps/unix/sysv/linux/ia64/lowlevellock.h (__lll_lock): Fix a
+       typo.
+
+2007-08-09  Anton Blanchard  <anton@samba.org>
+
+       * sysdeps/unix/sysv/linux/powerpc/pthread_spin_unlock.c: New file.
+
+2007-08-12  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S: Include
+       <kernel-features.h>.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: Likewise.
+
+2007-08-11  Ulrich Drepper  <drepper@redhat.com>
+
+       * pthreadP.h (PTHREAD_ROBUST_MUTEX_PSHARED): Define.
+       * pthread_mutex_lock.c: Use it instead of PTHREAD_MUTEX_PSHARED when
+       dealing with robust mutexes.
+       * pthread_mutex_timedlock.c: Likewise.
+       * pthread_mutex_trylock.c: Likewise.
+       * pthread_mutex_unlock.c: Likewise.
+       * sysdeps/unix/sysv/linux/pthread_mutex_cond_lock.c: Likewise.
+
+2007-08-06  Jakub Jelinek  <jakub@redhat.com>
+
+       * pthreadP.h (PTHREAD_MUTEX_PSHARED_BIT): Define.
+       (PTHREAD_MUTEX_TYPE): Mask __kind with 127.
+       (PTHREAD_MUTEX_PSHARED): Define.
+       * pthread_mutex_init.c (__pthread_mutex_init): Set
+       PTHREAD_MUTEX_PSHARED_BIT for pshared or robust
+       mutexes.
+       * pthread_mutex_lock.c (LLL_MUTEX_LOCK): Take mutex as argument
+       instead of its __data.__lock field, pass PTHREAD_MUTEX_PSHARED
+       as second argument to lll_lock.
+       (LLL_MUTEX_TRYLOCK): Take mutex as argument
+       instead of its __data.__lock field.
+       (LLL_ROBUST_MUTEX_LOCK): Take mutex as argument instead of its
+       __data.__lock field, pass PTHREAD_MUTEX_PSHARED as second argument
+       to lll_robust_lock.
+       (__pthread_mutex_lock): Update LLL_MUTEX_LOCK, LLL_MUTEX_TRYLOCK,
+       LLL_ROBUST_MUTEX_LOCK users, use PTHREAD_MUTEX_TYPE (mutex)
+       instead of mutex->__data.__kind directly, pass
+       PTHREAD_MUTEX_PSHARED (mutex) to lll_unlock and lll_futex_wait.
+       * pthread_mutex_trylock.c (__pthread_mutex_trylock): Use
+       PTHREAD_MUTEX_TYPE (mutex) instead of mutex->__data.__kind
+       directly, pass PTHREAD_MUTEX_PSHARED (mutex) to lll_unlock.
+       (pthread_mutex_timedlock): Pass PTHREAD_MUTEX_PSHARED (mutex)
+       to lll_timedlock, lll_robust_timedlock, lll_unlock and
+       lll_futex_timed_wait.  Use PTHREAD_MUTEX_TYPE (mutex) instead
+       of mutex->__data.__kind directly.
+       * pthread_mutex_timedlock.c (pthread_mutex_timedlock): Pass
+       PTHREAD_MUTEX_PSHARED (mutex) to lll_timedlock,
+       lll_robust_timedlock, lll_unlock and lll_futex_timed_wait.  Use
+       PTHREAD_MUTEX_TYPE (mutex) instead of mutex->__data.__kind directly.
+       * pthread_mutex_unlock.c (__pthread_mutex_unlock_usercnt): Pass
+       PTHREAD_MUTEX_PSHARED (mutex) to lll_unlock, lll_robust_unlock
+       and lll_futex_wake.
+       * pthread_mutex_setprioceiling.c (pthread_mutex_setprioceiling): Pass
+       PTHREAD_MUTEX_PSHARED (mutex) to lll_futex_wait and lll_futex_wake.
+       Use PTHREAD_MUTEX_TYPE (mutex) instead of mutex->__data.__kind
+       directly.
+       * sysdeps/unix/sysv/linux/pthread_mutex_cond_lock.c (LLL_MUTEX_LOCK):
+       Take mutex as argument instead of its __data.__lock field, pass
+       PTHREAD_MUTEX_PSHARED as second argument to lll_cond_lock.
+       (LLL_MUTEX_TRYLOCK): Take mutex as argument instead of its
+       __data.__lock field.
+       (LLL_ROBUST_MUTEX_LOCK): Take mutex as argument instead of its
+       __data.__lock field, pass PTHREAD_MUTEX_PSHARED as second argument
+       to lll_robust_cond_lock.
+       * pthread_cond_broadcast.c (__pthread_cond_broadcast): Add pshared
+       variable, pass it to lll_lock, lll_unlock, lll_futex_requeue and
+       lll_futex_wake.  Don't use lll_futex_requeue if dependent mutex
+       has PTHREAD_MUTEX_PSHARED_BIT bit set in its __data.__kind.
+       * pthread_cond_destroy.c (__pthread_cond_destroy): Add pshared
+       variable, pass it to lll_lock, lll_unlock, lll_futex_wake and
+       lll_futex_wait.
+       * pthread_cond_signal.c (__pthread_cond_signal): Add pshared
+       variable, pass it to lll_lock, lll_unlock, lll_futex_wake_unlock and
+       lll_futex_wake.
+       * pthread_cond_timedwait.c (__pthread_cond_wait): Add
+       pshared variable, pass it to lll_lock, lll_unlock,
+       lll_futex_timedwait and lll_futex_wake.
+       * pthread_cond_wait.c (__condvar_cleanup, __pthread_cond_wait): Add
+       pshared variable, pass it to lll_lock, lll_unlock, lll_futex_wait
+       and lll_futex_wake.
+       * sysdeps/unix/sysv/linux/alpha/lowlevellock.h (lll_futex_requeue,
+       lll_futex_wake_unlock): Add private argument, use __lll_private_flag
+       macro.
+       * sysdeps/unix/sysv/linux/ia64/lowlevellock.h (lll_futex_requeue,
+       lll_futex_wake_unlock): Likewise.
+       * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h (lll_futex_requeue):
+       Likewise.
+       * sysdeps/unix/sysv/linux/sparc/lowlevellock.h (lll_futex_requeue,
+       lll_futex_wake_unlock): Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h (lll_futex_requeue):
+       Likewise.
+       * sysdeps/unix/sysv/linux/s390/lowlevellock.h (lll_futex_requeue,
+       lll_futex_wake_unlock): Likewise.
+       (lll_futex_wake): Fix a typo.
+       * sysdeps/unix/sysv/linux/pthread-pi-defines.sym (PS_BIT): Add.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S
+       (__pthread_cond_broadcast): Pass LLL_PRIVATE to lll_* and or
+       FUTEX_PRIVATE_FLAG into SYS_futex op if cv is process private.
+       Don't use FUTEX_CMP_REQUEUE if dep_mutex is not process private.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_signal.S
+       (__pthread_cond_signal): Pass LLL_PRIVATE to lll_* and or
+       FUTEX_PRIVATE_FLAG into SYS_futex op if cv is process private.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S
+       (__pthread_cond_timedwait): Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:
+       (__condvar_cleanup, __pthread_cond_wait): Likewise.
+
+2007-08-05  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h (PSEUDO):
+       Don't use CGOTSETUP and CGOTRESTORE macros.
+       (CGOTSETUP, CGOTRESTORE): Remove.
+       <IS_IN_rtld> (CENABLE, CDISABLE): Don't use JUMPTARGET, branch to
+       @local symbol.
+
+2007-08-01  Kaz Kojima  <kkojima@rr.iij4u.or.jp>
+
+       * sysdeps/unix/sysv/linux/sh/libc-lowlevellock.S: Remove
+       definitions for private futexes.
+       * sysdeps/unix/sysv/linux/sh/lowlevellock.S: Include
+       kernel-features.h and lowlevellock.h.  Use private futexes if
+       they are available.
+       (__lll_lock_wait_private, __lll_unlock_wake_private): New.
+       (__lll_mutex_lock_wait): Rename to
+       (__lll_lock_wait): ... this.  Don't compile in for libc.so.
+       (__lll_mutex_timedlock_wait): Rename to ...
+       (__lll_timedlock_wait): ... this.  Use __NR_gettimeofday.
+       Don't compile in for libc.so.
+       (__lll_mutex_unlock_wake): Rename to ...
+       (__lll_unlock_wake): ... this.  Don't compile in for libc.so.
+       (__lll_timedwait_tid): Use __NR_gettimeofday.
+       * sysdeps/unix/sysv/linux/sh/lowlevellock.h: Allow including
+       the header from assembler.  Renamed all lll_mutex_* resp.
+       lll_robust_mutex_* macros to lll_* resp. lll_robust_*.
+       Renamed all LLL_MUTEX_LOCK_* macros to LLL_LOCK_*.
+       (FUTEX_CMP_REQUEUE, FUTEX_WAKE_OP, FUTEX_OP_CLEAR_WAKE_IF_GT_ONE):
+       Define.
+       (__lll_lock_wait_private): Add prototype.
+       (__lll_lock_wait, __lll_timedlock_wait, __lll_robust_lock_wait,
+       __lll_robust_timedlock_wait, __lll_unlock_wake_private,
+       __lll_unlock_wake): Likewise.
+       (lll_lock): Add private argument.  Call __lll_lock_wait_private
+       if private is constant LLL_PRIVATE.
+       (lll_robust_lock, lll_cond_lock, lll_robust_cond_lock,
+       lll_timedlock, lll_robust_timedlock): Add private argument.
+       (lll_unlock): Add private argument.  Call __lll_unlock_wake_private
+       if private is constant LLL_PRIVATE.
+       (lll_robust_unlock, lll_robust_dead): Add private argument.
+       (lll_lock_t): Remove.
+       (__lll_cond_wait, __lll_cond_timedwait, __lll_cond_wake,
+       __lll_cond_broadcast, lll_cond_wait, lll_cond_timedwait,
+       lll_cond_wake, lll_cond_broadcast): Remove.
+       * sysdeps/unix/sysv/linux/sh/lowlevelrobustlock.S: Include
+       kernel-features.h and lowlevellock.h.
+       (SYS_gettimeofday, SYS_futex, FUTEX_WAIT, FUTEX_WAKE): Remove.
+       (LOAD_FUTEX_WAIT): Define.
+       (__lll_robust_mutex_lock_wait): Rename to ...
+       (__lll_robust_lock_wait): ... this.  Add private argument.
+       Use LOAD_FUTEX_WAIT macro.
+       (__lll_robust_mutex_timedlock_wait): Rename to ...
+       (__lll_robust_timedlock_wait): ... this.    Add private argument.
+       Use __NR_gettimeofday.  Use LOAD_FUTEX_WAIT macro.
+       * sysdeps/unix/sysv/linux/sh/pthread_barrier_wait.S: Include
+       lowlevellock.h.
+       (SYS_futex, FUTEX_WAIT, FUTEX_WAKE): Remove.
+       (pthread_barrier_wait): Use __lll_{lock,unlock}_* instead of
+       __lll_mutex_{lock,unlock}_*.
+       * sysdeps/unix/sysv/linux/sh/pthread_cond_broadcast.S: Include
+       lowlevellock.h and pthread-errnos.h.
+       (SYS_futex, FUTEX_WAIT, FUTEX_WAKE, FUTEX_REQUEUE,
+       FUTEX_CMP_REQUEUE, EINVAL): Remove.
+       (__pthread_cond_broadcast): Use __lll_{lock,unlock}_* instead of
+       __lll_mutex_{lock,unlock}_*.
+       * sysdeps/unix/sysv/linux/sh/pthread_cond_signal.S: Include
+       lowlevellock.h and pthread-errnos.h.
+       (SYS_futex, FUTEX_WAIT, FUTEX_WAKE, FUTEX_REQUEUE, EINVAL): Remove.
+       (__pthread_cond_signal): Use __lll_{lock,unlock}_* instead of
+       __lll_mutex_{lock,unlock}_*.
+       * sysdeps/unix/sysv/linux/sh/pthread_cond_timedwait.S: Include
+       lowlevellock.h.
+       (SYS_futex, SYS_gettimeofday, FUTEX_WAIT, FUTEX_WAKE): Remove.
+       (__pthread_cond_timedwait): Use __lll_{lock,unlock}_* instead of
+       __lll_mutex_{lock,unlock}_*.  Use __NR_gettimeofday.
+       (__condvar_tw_cleanup): Likewise.
+       * sysdeps/unix/sysv/linux/sh/pthread_cond_wait.S: Include
+       lowlevellock.h.
+       (SYS_futex, FUTEX_WAIT, FUTEX_WAKE): Remove.
+       (__pthread_cond_wait): Use __lll_{lock,unlock}_* instead of
+       __lll_mutex_{lock,unlock}_*.
+       ( __condvar_w_cleanup): Likewise.
+       * sysdeps/unix/sysv/linux/sh/pthread_once.S: Include lowlevellock.h.
+       (SYS_futex, FUTEX_WAIT, FUTEX_WAKE, FUTEX_PRIVATE_FLAG): Remove.
+       * sysdeps/unix/sysv/linux/sh/pthread_rwlock_rdlock.S: Include
+       lowlevellock.h.
+       (SYS_futex, FUTEX_WAIT, FUTEX_WAKE, FUTEX_PRIVATE_FLAG): Remove.
+       (__pthread_rwlock_rdlock): Use __lll_{lock,unlock}_* instead of
+       __lll_mutex_{lock,unlock}_*.
+       * sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedrdlock.S: Include
+       lowlevellock.h.
+       (SYS_gettimeofday, SYS_futex, FUTEX_WAIT, FUTEX_WAKE,
+       FUTEX_PRIVATE_FLAG): Remove.
+       (pthread_rwlock_timedrdlock): Use __lll_{lock,unlock}_* instead of
+       __lll_mutex_{lock,unlock}_*.  Use __NR_gettimeofday.
+       * sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedwrlock.S: Include
+       lowlevellock.h.
+       (SYS_gettimeofday, SYS_futex, FUTEX_WAIT, FUTEX_WAKE,
+       FUTEX_PRIVATE_FLAG): Remove.
+       (pthread_rwlock_timedwrlock): Use __lll_{lock,unlock}_* instead of
+       __lll_mutex_{lock,unlock}_*.  Use __NR_gettimeofday.
+       * sysdeps/unix/sysv/linux/sh/pthread_rwlock_unlock.S: Include
+       lowlevellock.h.
+       (SYS_futex, FUTEX_WAIT, FUTEX_WAKE, FUTEX_PRIVATE_FLAG): Remove.
+       (__pthread_rwlock_unlock): Use __lll_{lock,unlock}_* instead of
+       __lll_mutex_{lock,unlock}_*.
+       * sysdeps/unix/sysv/linux/sh/pthread_rwlock_wrlock.S: Include
+       lowlevellock.h.
+       (SYS_futex, FUTEX_WAIT, FUTEX_WAKE, FUTEX_PRIVATE_FLAG): Remove.
+       (__pthread_rwlock_wrlock): Use __lll_{lock,unlock}_* instead of
+       __lll_mutex_{lock,unlock}_*.
+       * sysdeps/unix/sysv/linux/sh/sem_post.S: Include lowlevellock.h.
+       (SYS_futex, FUTEX_WAIT, FUTEX_WAKE, FUTEX_PRIVATE_FLAG): Remove.
+       (__new_sem_post): Use standard initial exec code sequences.
+       * sysdeps/unix/sysv/linux/sh/sem_timedwait.S: Include
+       lowlevellock.h.
+       (SYS_gettimeofday, SYS_futex, FUTEX_WAIT, FUTEX_WAKE,
+       FUTEX_PRIVATE_FLAG): Remove.
+       (sem_timedwait): Use __NR_gettimeofday.  Use standard initial
+       exec code sequences.
+       * sysdeps/unix/sysv/linux/sh/sem_trywait.S: Include lowlevellock.h.
+       (__new_sem_trywait): Use standard initial exec code sequences.
+       * sysdeps/unix/sysv/linux/sh/sem_wait.S: Include lowlevellock.h.
+       (__new_sem_wait): Use standard initial exec code sequences.
+
+2007-07-31  Anton Blanchard  <anton@samba.org>
+
+       * sysdeps/unix/sysv/linux/powerpc/sem_post.c (__new_sem_post):
+       Use __asm __volatile (__lll_acq_instr ::: "memory") instead of
+       atomic_full_barrier.
+
+2007-07-31  Jakub Jelinek  <jakub@redhat.com>
+
+       * allocatestack.c (stack_cache_lock): Change type to int.
+       (get_cached_stack, allocate_stack, __deallocate_stack,
+       __make_stacks_executable, __find_thread_by_id, __nptl_setxid,
+       __pthread_init_static_tls, __wait_lookup_done): Add LLL_PRIVATE
+       as second argument to lll_lock and lll_unlock macros on
+       stack_cache_lock.
+       * pthread_create.c (__find_in_stack_list): Likewise.
+       (start_thread): Similarly with pd->lock.  Use lll_robust_dead
+       macro instead of lll_robust_mutex_dead, pass LLL_SHARED to it
+       as second argument.
+       * descr.h (struct pthread): Change lock and setxid_futex field
+       type to int.
+       * old_pthread_cond_broadcast.c (__pthread_cond_broadcast_2_0): Use
+       LLL_LOCK_INITIALIZER instead of LLL_MUTEX_LOCK_INITIALIZER.
+       * old_pthread_cond_signal.c (__pthread_cond_signal_2_0): Likewise.
+       * old_pthread_cond_timedwait.c (__pthread_cond_timedwait_2_0):
+       Likewise.
+       * old_pthread_cond_wait.c (__pthread_cond_wait_2_0): Likewise.
+       * pthread_cond_init.c (__pthread_cond_init): Likewise.
+       * pthreadP.h (__attr_list_lock): Change type to int.
+       * pthread_attr_init.c (__attr_list_lock): Likewise.
+       * pthread_barrier_destroy.c (pthread_barrier_destroy): Pass
+       ibarrier->private ^ FUTEX_PRIVATE_FLAG as second argument to
+       lll_{,un}lock.
+       * pthread_barrier_wait.c (pthread_barrier_wait): Likewise and
+       also for lll_futex_{wake,wait}.
+       * pthread_barrier_init.c (pthread_barrier_init): Make iattr
+       a pointer to const.
+       * pthread_cond_broadcast.c (__pthread_cond_broadcast): Pass
+       LLL_SHARED as second argument to lll_{,un}lock.
+       * pthread_cond_destroy.c (__pthread_cond_destroy): Likewise.
+       * pthread_cond_signal.c (__pthread_cond_singal): Likewise.
+       * pthread_cond_timedwait.c (__pthread_cond_timedwait): Likewise.
+       * pthread_cond_wait.c (__condvar_cleanup, __pthread_cond_wait):
+       Likewise.
+       * pthread_getattr_np.c (pthread_getattr_np): Add LLL_PRIVATE
+       as second argument to lll_{,un}lock macros on pd->lock.
+       * pthread_getschedparam.c (__pthread_getschedparam): Likewise.
+       * pthread_setschedparam.c (__pthread_setschedparam): Likewise.
+       * pthread_setschedprio.c (pthread_setschedprio): Likewise.
+       * tpp.c (__pthread_tpp_change_priority, __pthread_current_priority):
+       Likewise.
+       * sysdeps/pthread/createthread.c (do_clone, create_thread):
+       Likewise.
+       * pthread_once.c (once_lock): Change type to int.
+       (__pthread_once): Pass LLL_PRIVATE as second argument to
+       lll_{,un}lock macros on once_lock.
+       * pthread_rwlock_rdlock.c (__pthread_rwlock_rdlock): Use
+       lll_{,un}lock macros instead of lll_mutex_{,un}lock, pass
+       rwlock->__data.__shared as second argument to them and similarly
+       for lll_futex_w*.
+       * pthread_rwlock_timedrdlock.c (pthread_rwlock_timedrdlock):
+       Likewise.
+       * pthread_rwlock_timedwrlock.c (pthread_rwlock_timedwrlock):
+       Likewise.
+       * pthread_rwlock_tryrdlock.c (__pthread_rwlock_tryrdlock): Likewise.
+       * pthread_rwlock_trywrlock.c (__pthread_rwlock_trywrlock): Likewise.
+       * pthread_rwlock_unlock.c (__pthread_rwlock_unlock): Likewise.
+       * pthread_rwlock_wrlock.c (__pthread_rwlock_wrlock): Likewise.
+       * sem_close.c (sem_close): Pass LLL_PRIVATE as second argument
+       to lll_{,un}lock macros on __sem_mappings_lock.
+       * sem_open.c (check_add_mapping): Likewise.
+       (__sem_mappings_lock): Change type to int.
+       * semaphoreP.h (__sem_mappings_lock): Likewise.
+       * pthread_mutex_lock.c (LLL_MUTEX_LOCK, LLL_MUTEX_TRYLOCK,
+       LLL_ROBUST_MUTEX_LOCK): Use lll_{,try,robust_}lock macros
+       instead of lll_*mutex_*, pass LLL_SHARED as last
+       argument.
+       (__pthread_mutex_lock): Use lll_unlock instead of lll_mutex_unlock,
+       pass LLL_SHARED as last argument.
+       * sysdeps/unix/sysv/linux/pthread_mutex_cond_lock.c (LLL_MUTEX_LOCK,
+       LLL_MUTEX_TRYLOCK, LLL_ROBUST_MUTEX_LOCK): Use
+       lll_{cond_,cond_try,robust_cond}lock macros instead of lll_*mutex_*,
+       pass LLL_SHARED as last argument.
+       * pthread_mutex_timedlock.c (pthread_mutex_timedlock): Use
+       lll_{timed,try,robust_timed,un}lock instead of lll_*mutex*, pass
+       LLL_SHARED as last argument.
+       * pthread_mutex_trylock.c (__pthread_mutex_trylock): Similarly.
+       * pthread_mutex_unlock.c (__pthread_mutex_unlock_usercnt):
+       Similarly.
+       * sysdeps/pthread/bits/libc-lock.h (__libc_lock_lock,
+       __libc_lock_lock_recursive, __libc_lock_unlock,
+       __libc_lock_unlock_recursive): Pass LLL_PRIVATE as second
+       argument to lll_{,un}lock.
+       * sysdeps/pthread/bits/stdio-lock.h (_IO_lock_lock,
+       _IO_lock_unlock): Likewise.
+       * sysdeps/unix/sysv/linux/fork.c (__libc_fork): Don't use
+       compound literal.
+       * sysdeps/unix/sysv/linux/unregister-atfork.c (__unregister_atfork):
+       Pass LLL_PRIVATE as second argument to lll_{,un}lock macros on
+       __fork_lock.
+       * sysdeps/unix/sysv/linux/register-atfork.c (__register_atfork,
+       free_mem): Likewise.
+       (__fork_lock): Change type to int.
+       * sysdeps/unix/sysv/linux/fork.h (__fork_lock): Likewise.
+       * sysdeps/unix/sysv/linux/sem_post.c (__new_sem_post): Pass
+       isem->private ^ FUTEX_PRIVATE_FLAG as second argument to
+       lll_futex_wake.
+       * sysdeps/unix/sysv/linux/sem_timedwait.c (sem_timedwait): Likewise.
+       * sysdeps/unix/sysv/linux/sem_wait.c (__new_sem_wait): Likewise.
+       * sysdeps/unix/sysv/linux/lowlevellock.c (__lll_lock_wait_private):
+       New function.
+       (__lll_lock_wait, __lll_timedlock_wait): Add private argument and
+       pass it through to lll_futex_*wait, only compile in when
+       IS_IN_libpthread.
+       * sysdeps/unix/sysv/linux/lowlevelrobustlock.c
+       (__lll_robust_lock_wait, __lll_robust_timedlock_wait): Add private
+       argument and pass it through to lll_futex_*wait.
+       * sysdeps/unix/sysv/linux/alpha/lowlevellock.h: Renamed all
+       lll_mutex_* resp. lll_robust_mutex_* macros to lll_* resp.
+       lll_robust_*.  Renamed all __lll_mutex_* resp. __lll_robust_mutex_*
+       inline functions to __lll_* resp. __lll_robust_*.
+       (LLL_MUTEX_LOCK_INITIALIZER): Remove.
+       (lll_mutex_dead): Add private argument.
+       (__lll_lock_wait_private): New prototype.
+       (__lll_lock_wait, __lll_robust_lock_wait, __lll_lock_timedwait,
+       __lll_robust_lock_timedwait): Add private argument to prototypes.
+       (__lll_lock): Add private argument, if it is constant LLL_PRIVATE,
+       call __lll_lock_wait_private, otherwise pass private to
+       __lll_lock_wait.
+       (__lll_robust_lock, __lll_cond_lock, __lll_timedlock,
+       __lll_robust_timedlock): Add private argument, pass it to
+       __lll_*wait functions.
+       (__lll_unlock): Add private argument, if it is constant LLL_PRIVATE,
+       call __lll_unlock_wake_private, otherwise pass private to
+       __lll_unlock_wake.
+       (__lll_robust_unlock): Add private argument, pass it to
+       __lll_robust_unlock_wake.
+       (lll_lock, lll_robust_lock, lll_cond_lock, lll_timedlock,
+       lll_robust_timedlock, lll_unlock, lll_robust_unlock): Add private
+       argument, pass it through to __lll_* inline function.
+       (__lll_mutex_unlock_force, lll_mutex_unlock_force): Remove.
+       (lll_lock_t): Remove.
+       (__lll_cond_wait, __lll_cond_timedwait, __lll_cond_wake,
+       __lll_cond_broadcast, lll_cond_wait, lll_cond_timedwait,
+       lll_cond_wake, lll_cond_broadcast): Remove.
+       * sysdeps/unix/sysv/linux/ia64/lowlevellock.h: Likewise.
+       * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h: Likewise.
+       * sysdeps/unix/sysv/linux/s390/lowlevellock.h: Likewise.
+       * sysdeps/unix/sysv/linux/sparc/lowlevellock.h: Likewise.
+       * sysdeps/unix/sysv/linux/i386/lowlevellock.h: Allow including
+       the header from assembler.  Renamed all lll_mutex_* resp.
+       lll_robust_mutex_* macros to lll_* resp. lll_robust_*.
+       (LOCK, FUTEX_CMP_REQUEUE, FUTEX_WAKE_OP,
+       FUTEX_OP_CLEAR_WAKE_IF_GT_ONE): Define.
+       (LLL_MUTEX_LOCK_INITIALIZER, LLL_MUTEX_LOCK_INITIALIZER_LOCKED,
+       LLL_MUTEX_LOCK_INITIALIZER_WAITERS): Remove.
+       (__lll_mutex_lock_wait, __lll_mutex_timedlock_wait,
+       __lll_mutex_unlock_wake, __lll_lock_wait, __lll_unlock_wake):
+       Remove prototype.
+       (__lll_trylock_asm, __lll_lock_asm_start, __lll_unlock_asm): Define.
+       (lll_robust_trylock, lll_cond_trylock): Use LLL_LOCK_INITIALIZER*
+       rather than LLL_MUTEX_LOCK_INITIALIZER* macros.
+       (lll_trylock): Likewise, use __lll_trylock_asm, pass
+       MULTIPLE_THREADS_OFFSET as another asm operand.
+       (lll_lock): Add private argument, use __lll_lock_asm_start, pass
+       MULTIPLE_THREADS_OFFSET as last asm operand, call
+       __lll_lock_wait_private if private is constant LLL_PRIVATE,
+       otherwise pass private as another argument to __lll_lock_wait.
+       (lll_robust_lock, lll_cond_lock, lll_robust_cond_lock,
+       lll_timedlock, lll_robust_timedlock): Add private argument, pass
+       private as another argument to __lll_*lock_wait call.
+       (lll_unlock): Add private argument, use __lll_unlock_asm, pass
+       MULTIPLE_THREADS_OFFSET as another asm operand, call
+       __lll_unlock_wake_private if private is constant LLL_PRIVATE,
+       otherwise pass private as another argument to __lll_unlock_wake.
+       (lll_robust_unlock): Add private argument, pass private as another
+       argument to __lll_unlock_wake.
+       (lll_robust_dead): Add private argument, use __lll_private_flag
+       macro.
+       (lll_islocked): Use LLL_LOCK_INITIALIZER instead of
+       LLL_MUTEX_LOCK_INITIALIZER.
+       (lll_lock_t): Remove.
+       (LLL_LOCK_INITIALIZER_WAITERS): Define.
+       (__lll_cond_wait, __lll_cond_timedwait, __lll_cond_wake,
+       __lll_cond_broadcast, lll_cond_wait, lll_cond_timedwait,
+       lll_cond_wake, lll_cond_broadcast): Remove.
+       * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S: Revert
+       2007-05-2{3,9} changes.
+       * sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S: Include
+       kernel-features.h and lowlevellock.h.
+       (LOAD_PRIVATE_FUTEX_WAIT): Define.
+       (LOAD_FUTEX_WAIT): Rewritten.
+       (LOCK, SYS_gettimeofday, SYS_futex, FUTEX_WAIT, FUTEX_WAKE): Don't
+       define.
+       (__lll_lock_wait_private, __lll_unlock_wake_private): New functions.
+       (__lll_mutex_lock_wait): Rename to ...
+       (__lll_lock_wait): ... this.  Take futex addr from %edx instead of
+       %ecx, %ecx is now private argument.  Don't compile in for libc.so.
+       (__lll_mutex_timedlock_wait): Rename to ...
+       (__lll_timedlock_wait): ... this.  Use __NR_gettimeofday.  %esi
+       contains private argument.  Don't compile in for libc.so.
+       (__lll_mutex_unlock_wake): Rename to ...
+       (__lll_unlock_wake): ... this.  %ecx contains private argument.
+       Don't compile in for libc.so.
+       (__lll_timedwait_tid): Use __NR_gettimeofday.
+       * sysdeps/unix/sysv/linux/i386/i486/lowlevelrobustlock.S: Include
+       kernel-features.h and lowlevellock.h.
+       (LOAD_FUTEX_WAIT): Define.
+       (LOCK, SYS_gettimeofday, SYS_futex, FUTEX_WAIT, FUTEX_WAKE): Don't
+       define.
+       (__lll_robust_mutex_lock_wait): Rename to ...
+       (__lll_robust_lock_wait): ... this.  Futex addr is now in %edx
+       argument, %ecx argument contains private.  Use LOAD_FUTEX_WAIT
+       macro.
+       (__lll_robust_mutex_timedlock_wait): Rename to ...
+       (__lll_robust_timedlock_wait): ... this.  Use __NR_gettimeofday.
+       %esi argument contains private, use LOAD_FUTEX_WAIT macro.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_barrier_wait.S: Include
+       lowlevellock.h.
+       (SYS_futex, FUTEX_WAIT, FUTEX_WAKE, LOCK): Don't define.
+       (pthread_barrier_wait): Rename __lll_mutex_* to __lll_*, pass
+       PRIVATE(%ebx) ^ LLL_SHARED as private argument in %ecx to
+       __lll_lock_wait and __lll_unlock_wake, pass MUTEX(%ebx) address
+       to __lll_lock_wait in %edx.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S:
+       Include lowlevellock.h and pthread-errnos.h.
+       (SYS_futex, FUTEX_WAIT, FUTEX_WAKE, FUTEX_REQUEUE,
+       FUTEX_CMP_REQUEUE, EINVAL, LOCK): Don't define.
+       (__pthread_cond_broadcast): Rename __lll_mutex_* to __lll_*, pass
+       cond_lock address in %edx rather than %ecx to __lll_lock_wait,
+       pass LLL_SHARED in %ecx to both __lll_lock_wait and
+       __lll_unlock_wake.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_signal.S:
+       Include lowlevellock.h and pthread-errnos.h.
+       (SYS_futex, FUTEX_WAIT, FUTEX_WAKE, FUTEX_WAKE_OP,
+       FUTEX_OP_CLEAR_WAKE_IF_GT_ONE, EINVAL, LOCK): Don't define.
+       (__pthread_cond_signal): Rename __lll_mutex_* to __lll_*, pass
+       cond_lock address in %edx rather than %ecx to __lll_lock_wait,
+       pass LLL_SHARED in %ecx to both __lll_lock_wait and
+       __lll_unlock_wake.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S:
+       Include lowlevellock.h.
+       (SYS_futex, SYS_gettimeofday, FUTEX_WAIT, FUTEX_WAKE, LOCK):
+       Don't define.
+       (__pthread_cond_timedwait): Rename __lll_mutex_* to __lll_*, pass
+       cond_lock address in %edx rather than %ecx to __lll_lock_wait,
+       pass LLL_SHARED in %ecx to both __lll_lock_wait and
+       __lll_unlock_wake.  Use __NR_gettimeofday.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S:
+       Include lowlevellock.h.
+       (SYS_futex, FUTEX_WAIT, FUTEX_WAKE, LOCK): Don't define.
+       (__pthread_cond_wait, __condvar_w_cleanup): Rename __lll_mutex_*
+       to __lll_*, pass cond_lock address in %edx rather than %ecx to
+       __lll_lock_wait, pass LLL_SHARED in %ecx to both __lll_lock_wait
+       and __lll_unlock_wake.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_rdlock.S:
+       Include lowlevellock.h.
+       (SYS_futex, FUTEX_WAIT, FUTEX_WAKE, LOCK): Don't define.
+       (__pthread_rwlock_rdlock): Rename __lll_mutex_* to __lll_*, pass
+       MUTEX(%ebx) address in %edx rather than %ecx to
+       __lll_lock_wait, pass PSHARED(%ebx) in %ecx to both __lll_lock_wait
+       and __lll_unlock_wake.  Move return value from %ecx to %edx
+       register.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedrdlock.S:
+       Include lowlevellock.h.
+       (SYS_futex, SYS_gettimeofday, FUTEX_WAIT, FUTEX_WAKE, LOCK):
+       Don't define.
+       (__pthread_rwlock_wrlock): Rename __lll_mutex_* to __lll_*, pass
+       MUTEX(%ebp) address in %edx rather than %ecx to
+       __lll_lock_wait, pass PSHARED(%ebp) in %ecx to both __lll_lock_wait
+       and __lll_unlock_wake.  Move return value from %ecx to %edx
+       register.  Use __NR_gettimeofday.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedwrlock.S:
+       Include lowlevellock.h.
+       (SYS_futex, SYS_gettimeofday, FUTEX_WAIT, FUTEX_WAKE, LOCK):
+       Don't define.
+       (__pthread_rwlock_wrlock): Rename __lll_mutex_* to __lll_*, pass
+       MUTEX(%ebp) address in %edx rather than %ecx to
+       __lll_lock_wait, pass PSHARED(%ebp) in %ecx to both __lll_lock_wait
+       and __lll_unlock_wake.  Move return value from %ecx to %edx
+       register.  Use __NR_gettimeofday.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_unlock.S:
+       Include lowlevellock.h.
+       (SYS_futex, FUTEX_WAIT, FUTEX_WAKE, LOCK): Don't define.
+       (__pthread_rwlock_unlock): Rename __lll_mutex_* to __lll_*, pass
+       MUTEX(%edi) address in %edx rather than %ecx to
+       __lll_lock_wait, pass PSHARED(%edi) in %ecx to both __lll_lock_wait
+       and __lll_unlock_wake.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_wrlock.S:
+       Include lowlevellock.h.
+       (SYS_futex, FUTEX_WAIT, FUTEX_WAKE, LOCK): Don't define.
+       (__pthread_rwlock_wrlock): Rename __lll_mutex_* to __lll_*, pass
+       MUTEX(%ebx) address in %edx rather than %ecx to
+       __lll_lock_wait, pass PSHARED(%ebx) in %ecx to both __lll_lock_wait
+       and __lll_unlock_wake.  Move return value from %ecx to %edx
+       register.
+       * sysdeps/unix/sysv/linux/i386/pthread_once.S: Include
+       lowlevellock.h.
+       (LOCK, SYS_futex, FUTEX_WAIT, FUTEX_WAKE, FUTEX_PRIVATE_FLAG): Don't
+       define.
+       * sysdeps/unix/sysv/linux/i386/i486/sem_post.S: Include lowlevellock.h.
+       (LOCK, SYS_futex, FUTEX_WAKE): Don't define.
+       * sysdeps/unix/sysv/linux/i386/i486/sem_timedwait.S: Include
+       lowlevellock.h.
+       (LOCK, SYS_futex, SYS_gettimeofday, FUTEX_WAIT): Don't define.
+       (sem_timedwait): Use __NR_gettimeofday.
+       * sysdeps/unix/sysv/linux/i386/i486/sem_trywait.S: Include
+       lowlevellock.h.
+       (LOCK): Don't define.
+       * sysdeps/unix/sysv/linux/i386/i486/sem_wait.S: Include
+       lowlevellock.h.
+       (LOCK, SYS_futex, FUTEX_WAIT): Don't define.
+       * sysdeps/unix/sysv/linux/powerpc/sem_post.c: Wake only when there
+       are waiters.
+       * sysdeps/unix/sysv/linux/x86_64/libc-lowlevellock.S: Revert
+       2007-05-2{3,9} changes.
+       * sysdeps/unix/sysv/linux/x86_64/lowlevellock.S: Include
+       kernel-features.h and lowlevellock.h.
+       (LOAD_PRIVATE_FUTEX_WAIT): Define.
+       (LOAD_FUTEX_WAIT): Rewritten.
+       (LOCK, SYS_futex, FUTEX_WAIT, FUTEX_WAKE): Don't define.
+       (__lll_lock_wait_private, __lll_unlock_wake_private): New functions.
+       (__lll_mutex_lock_wait): Rename to ...
+       (__lll_lock_wait): ... this.  %esi is now private argument.
+       Don't compile in for libc.so.
+       (__lll_mutex_timedlock_wait): Rename to ...
+       (__lll_timedlock_wait): ... this.  %esi contains private argument.
+       Don't compile in for libc.so.
+       (__lll_mutex_unlock_wake): Rename to ...
+       (__lll_unlock_wake): ... this.  %esi contains private argument.
+       Don't compile in for libc.so.
+       * sysdeps/unix/sysv/linux/x86_64/lowlevelrobustlock.S: Include
+       kernel-features.h and lowlevellock.h.
+       (LOAD_FUTEX_WAIT): Define.
+       (LOCK, SYS_futex, FUTEX_WAIT, FUTEX_WAKE): Don't define.
+       (__lll_robust_mutex_lock_wait): Rename to ...
+       (__lll_robust_lock_wait): ... this.  %esi argument contains private.
+       Use LOAD_FUTEX_WAIT macro.
+       (__lll_robust_mutex_timedlock_wait): Rename to ...
+       (__lll_robust_timedlock_wait): ... this. %esi argument contains
+       private, use LOAD_FUTEX_WAIT macro.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_barrier_wait.S: Include
+       lowlevellock.h.
+       (SYS_futex, FUTEX_WAIT, FUTEX_WAKE, LOCK): Don't define.
+       (pthread_barrier_wait): Rename __lll_mutex_* to __lll_*, pass
+       PRIVATE(%rdi) ^ LLL_SHARED as private argument in %esi to
+       __lll_lock_wait and __lll_unlock_wake.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S:
+       Include lowlevellock.h and pthread-errnos.h.
+       (SYS_futex, FUTEX_WAIT, FUTEX_WAKE, FUTEX_REQUEUE,
+       FUTEX_CMP_REQUEUE, EINVAL, LOCK): Don't define.
+       (__pthread_cond_broadcast): Rename __lll_mutex_* to __lll_*,
+       pass LLL_SHARED in %esi to both __lll_lock_wait and
+       __lll_unlock_wake.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_signal.S:
+       Include lowlevellock.h and pthread-errnos.h.
+       (SYS_futex, FUTEX_WAIT, FUTEX_WAKE, FUTEX_WAKE_OP,
+       FUTEX_OP_CLEAR_WAKE_IF_GT_ONE, EINVAL, LOCK): Don't define.
+       (__pthread_cond_signal): Rename __lll_mutex_* to __lll_*,
+       pass LLL_SHARED in %esi to both __lll_lock_wait and
+       __lll_unlock_wake.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S:
+       Include lowlevellock.h.
+       (SYS_futex, FUTEX_WAIT, FUTEX_WAKE, LOCK): Don't define.
+       (__pthread_cond_timedwait): Rename __lll_mutex_* to __lll_*,
+       pass LLL_SHARED in %esi to both __lll_lock_wait and
+       __lll_unlock_wake.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:
+       Include lowlevellock.h.
+       (SYS_futex, FUTEX_WAIT, FUTEX_WAKE, LOCK): Don't define.
+       (__pthread_cond_wait, __condvar_cleanup): Rename __lll_mutex_*
+       to __lll_*, pass LLL_SHARED in %esi to both __lll_lock_wait
+       and __lll_unlock_wake.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_rdlock.S:
+       Include lowlevellock.h.
+       (SYS_futex, FUTEX_WAIT, FUTEX_WAKE, FUTEX_PRIVATE_FLAG, LOCK):
+       Don't define.
+       (__pthread_rwlock_rdlock): Rename __lll_mutex_* to __lll_*,
+       pass PSHARED(%rdi) in %esi to both __lll_lock_wait
+       and __lll_unlock_wake.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedrdlock.S:
+       Include lowlevellock.h.
+       (SYS_futex, FUTEX_WAIT, FUTEX_WAKE, FUTEX_PRIVATE_FLAG, LOCK):
+       Don't define.
+       (__pthread_rwlock_wrlock): Rename __lll_mutex_* to __lll_*,
+       pass PSHARED(%rdi) in %esi to both __lll_lock_wait
+       and __lll_unlock_wake.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedwrlock.S:
+       Include lowlevellock.h.
+       (SYS_futex, FUTEX_WAIT, FUTEX_WAKE, FUTEX_PRIVATE_FLAG, LOCK):
+       Don't define.
+       (__pthread_rwlock_wrlock): Rename __lll_mutex_* to __lll_*,
+       pass PSHARED(%rdi) in %esi to both __lll_lock_wait
+       and __lll_unlock_wake.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_unlock.S:
+       Include lowlevellock.h.
+       (SYS_futex, FUTEX_WAIT, FUTEX_WAKE, FUTEX_PRIVATE_FLAG, LOCK):
+       Don't define.
+       (__pthread_rwlock_unlock): Rename __lll_mutex_* to __lll_*,
+       pass PSHARED(%rdi) in %esi to both __lll_lock_wait
+       and __lll_unlock_wake.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_wrlock.S:
+       Include lowlevellock.h.
+       (SYS_futex, FUTEX_WAIT, FUTEX_WAKE, FUTEX_PRIVATE_FLAG, LOCK):
+       Don't define.
+       (__pthread_rwlock_wrlock): Rename __lll_mutex_* to __lll_*,
+       pass PSHARED(%rdi) in %ecx to both __lll_lock_wait
+       and __lll_unlock_wake.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_once.S: Include
+       lowlevellock.h.
+       (LOCK, SYS_futex, FUTEX_WAIT, FUTEX_WAKE, FUTEX_PRIVATE_FLAG): Don't
+       define.
+       * sysdeps/unix/sysv/linux/x86_64/sem_post.S: Include lowlevellock.h.
+       (LOCK, SYS_futex, FUTEX_WAKE): Don't define.
+       * sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S: Include
+       lowlevellock.h.
+       (LOCK, SYS_futex, FUTEX_WAIT): Don't define.
+       * sysdeps/unix/sysv/linux/x86_64/sem_trywait.S: Include
+       lowlevellock.h.
+       (LOCK): Don't define.
+       * sysdeps/unix/sysv/linux/x86_64/sem_wait.S: Include
+       lowlevellock.h.
+       (LOCK, SYS_futex, FUTEX_WAIT): Don't define.
+       * sysdeps/unix/sysv/linux/sparc/internaltypes.h: New file.
+       * sysdeps/unix/sysv/linux/sparc/pthread_barrier_destroy.c: New file.
+       * sysdeps/unix/sysv/linux/sparc/pthread_barrier_init.c: New file.
+       * sysdeps/unix/sysv/linux/sparc/pthread_barrier_wait.c: New file.
+       * sysdeps/unix/sysv/linux/sparc/sparc32/lowlevellock.c
+       (__lll_lock_wait_private): New function.
+       (__lll_lock_wait, __lll_timedlock_wait): Add private argument, pass
+       it to lll_futex_*wait.  Don't compile in for libc.so.
+       * sysdeps/unix/sysv/linux/sparc/sparc32/pthread_barrier_init.c:
+       Remove.
+       * sysdeps/unix/sysv/linux/sparc/sparc32/pthread_barrier_wait.c
+       (struct sparc_pthread_barrier): Remove.
+       (pthread_barrier_wait): Use union sparc_pthread_barrier instead of
+       struct sparc_pthread_barrier.  Pass
+       ibarrier->s.pshared ? LLL_SHARED : LLL_PRIVATE to lll_{,un}lock
+       and lll_futex_wait macros.
+       * sysdeps/unix/sysv/linux/sparc/sparc32/sparcv9/pthread_barrier_init.c:
+       Remove.
+       * sysdeps/unix/sysv/linux/sparc/sparc32/sparcv9/pthread_barrier_wait.c:
+       Include sparc pthread_barrier_wait.c instead of generic one.
+
+2007-07-30  Jakub Jelinek  <jakub@redhat.com>
+
+       * tst-rwlock14.c (do_test): Avoid warnings on 32-bit arches.
+
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedrdlock.S
+       (pthread_rwlock_timedrdlock): Copy futex retval to %esi rather than
+       %ecx.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedwrlock.S
+       (pthread_rwlock_timedwrlock): Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_unlock.S
+       (__pthread_rwlock_unlock): Fix MUTEX != 0 args to __lll_*.
+
+2007-07-31  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/sparc/tls.h (tcbhead_t): Add private_futex field.
+
+2007-07-26  Jakub Jelinek  <jakub@redhat.com>
+
+       * tst-locale2.c (useless): Add return statement.
+
+2007-07-24  Jakub Jelinek  <jakub@redhat.com>
+
+       * allocatestack.c (__nptl_setxid, __wait_lookup_done): Replace
+       lll_private_futex_* (*) with lll_futex_* (*, LLL_PRIVATE).
+       * pthread_create.c (start_thread): Likewise.
+       * init.c (sighandler_setxid): Likewise.
+       * sysdeps/alpha/tls.h (THREAD_GSCOPE_RESET_FLAG): Likewise.
+       * sysdeps/ia64/tls.h (THREAD_GSCOPE_RESET_FLAG): Likewise.
+       * sysdeps/i386/tls.h (THREAD_GSCOPE_RESET_FLAG): Likewise.
+       * sysdeps/s390/tls.h (THREAD_GSCOPE_RESET_FLAG): Likewise.
+       * sysdeps/powerpc/tls.h (THREAD_GSCOPE_RESET_FLAG): Likewise.
+       * sysdeps/x86_64/tls.h (THREAD_GSCOPE_RESET_FLAG): Likewise.
+       * sysdeps/sparc/tls.h (THREAD_GSCOPE_RESET_FLAG): Likewise.
+       * sysdeps/sh/tls.h (THREAD_GSCOPE_RESET_FLAG): Likewise.
+       * sysdeps/pthread/aio_misc.h (AIO_MISC_NOTIFY, AIO_MISC_WAIT):
+       Likewise.
+       * sysdeps/pthread/gai_misc.h (GAI_MISC_NOTIFY, GAI_MISC_WAIT):
+       Likewise.
+       * sysdeps/unix/sysv/linux/unregister-atfork.c (__unregister_atfork):
+       Likewise.
+       * sysdeps/unix/sysv/linux/rtld-lowlevel.h (__rtld_waitzero,
+       __rtld_notify): Likewise.
+       * sysdeps/unix/sysv/linux/fork.c (__libc_fork): Likewise.
+       * sysdeps/unix/sysv/linux/powerpc/pthread_once.c (clear_once_control,
+       __pthread_once): Likewise.
+       * sysdeps/unix/sysv/linux/alpha/pthread_once.c (clear_once_control,
+       __pthread_once): Add LLL_PRIVATE as last argument to lll_futex_*.
+       * sysdeps/unix/sysv/linux/alpha/lowlevellock.h (FUTEX_PRIVATE_FLAG,
+       LLL_PRIVATE, LLL_SHARED, __lll_private_flag): Define.
+       (lll_futex_wait): Add private argument, define as wrapper around
+       lll_futex_timed_wait.
+       (lll_futex_timed_wait, lll_futex_wake): Add private argument,
+       use __lll_private_flag macro.
+       (lll_robust_mutex_dead, __lll_mutex_unlock, __lll_robust_mutex_unlock,
+       __lll_mutex_unlock_force): Pass LLL_SHARED as last arg to lll_futex_*.
+       * sysdeps/unix/sysv/linux/ia64/pthread_once.c (clear_once_control,
+       __pthread_once): Add LLL_PRIVATE as last argument to lll_futex_*.
+       * sysdeps/unix/sysv/linux/ia64/lowlevellock.h (FUTEX_PRIVATE_FLAG,
+       LLL_PRIVATE, LLL_SHARED, __lll_private_flag): Define.
+       (lll_futex_wait): Add private argument, define as wrapper around
+       lll_futex_timed_wait.
+       (lll_futex_timed_wait, lll_futex_wake): Add private argument,
+       use __lll_private_flag macro.
+       (__lll_mutex_unlock, __lll_robust_mutex_unlock, lll_wait_tid,
+       __lll_mutex_unlock_force): Pass LLL_SHARED as last arg to lll_futex_*.
+       * sysdeps/unix/sysv/linux/i386/lowlevellock.h (__lll_private_flag):
+       Define.
+       (lll_futex_timed_wait, lll_futex_wake): Use it.
+       (lll_private_futex_wait, lll_private_futex_timed_wait,
+       lll_private_futex_wake): Removed.
+       * sysdeps/unix/sysv/linux/s390/pthread_once.c (clear_once_control,
+       __pthread_once): Add LLL_PRIVATE as last argument to lll_futex_*.
+       * sysdeps/unix/sysv/linux/s390/lowlevellock.h (FUTEX_PRIVATE_FLAG,
+       LLL_PRIVATE, LLL_SHARED, __lll_private_flag): Define.
+       (lll_futex_wait): Add private argument, define as wrapper around
+       lll_futex_timed_wait.
+       (lll_futex_timed_wait, lll_futex_wake): Add private argument,
+       use __lll_private_flag macro.
+       (lll_robust_mutex_dead, __lll_mutex_unlock, __lll_robust_mutex_unlock,
+       lll_wait_tid, __lll_mutex_unlock_force): Pass LLL_SHARED as last arg
+       to lll_futex_*.
+       * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h
+       (lll_private_futex_wait, lll_private_futex_timed_wait,
+       lll_private_futex_wake): Removed.
+       * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h (__lll_private_flag):
+       Fix !__ASSUME_PRIVATE_FUTEX non-constant private case.
+       (lll_private_futex_wait, lll_private_futex_timed_wait,
+       lll_private_futex_wake): Removed.
+       * sysdeps/unix/sysv/linux/sparc/pthread_once.c (clear_once_control,
+       __pthread_once): Add LLL_PRIVATE as last argument to lll_futex_*.
+       * sysdeps/unix/sysv/linux/sparc/lowlevellock.h (FUTEX_PRIVATE_FLAG,
+       LLL_PRIVATE, LLL_SHARED, __lll_private_flag): Define.
+       (lll_futex_wait): Add private argument, define as wrapper around
+       lll_futex_timed_wait.
+       (lll_futex_timed_wait, lll_futex_wake): Add private argument,
+       use __lll_private_flag macro.
+       (lll_robust_mutex_dead, __lll_mutex_unlock, __lll_robust_mutex_unlock,
+       lll_wait_tid, __lll_mutex_unlock_force): Pass LLL_SHARED as last arg
+       to lll_futex_*.
+       * sysdeps/unix/sysv/linux/sh/lowlevellock.h (__lll_private_flag):
+       Define.
+       (lll_futex_timed_wait, lll_futex_wake): Use it.
+       (lll_private_futex_wait, lll_private_futex_timed_wait,
+       lll_private_futex_wake): Removed.
+
+2007-07-27  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/sparc/tls.h (tcbhead_t): Move gscope_flag to the end
+       of the structure for sparc32.
+
+2007-07-26  Aurelien Jarno  <aurelien@aurel32.net>
+
+       * sysdeps/sparc/tls.h (tcbhead_t): Add gscope_flag.
+
+2007-07-23  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedrdlock.S: Fix
+       code used when private futexes are assumed.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedwrlock.S:
+       Likewise.
+
+2007-07-23  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h
+       (__lll_private_flag): Define.
+       (lll_futex_wait): Define as a wrapper around lll_futex_timed_wait.
+       (lll_futex_timed_wait, lll_futex_wake, lll_futex_wake_unlock): Use
+       __lll_private_flag.
+       (lll_private_futex_wait, lll_private_futex_timedwait,
+       lll_private_futex_wake): Define as wrapper around non-_private
+       macros.
+       * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h
+       (__lll_private_flag): Define.
+       (lll_futex_timed_wait, lll_futex_wake): Use __lll_private_flag.
+       (lll_private_futex_wait, lll_private_futex_timedwait,
+       lll_private_futex_wake): Define as wrapper around non-_private
+       macros.
+
+2007-07-10  Steven Munroe  <sjmunroe@us.ibm.com>
+
+       * pthread_rwlock_rdlock.c (__pthread_rwlock_rdlock): Add LLL_SHARED
+       parameter to lll_futex_wait call.
+       * pthread_rwlock_wrlock.c (__pthread_rwlock_wrlock): Likewise.
+
+       * sysdeps/unix/sysv/linux/powerpc/pthread_once.c (__pthread_once):
+       Replace lll_futex_wait with lll_private_futex_wait.
+       * sysdeps/unix/sysv/linux/powerpc/sem_post.c (__new_sem_post):
+       Add LLL_SHARED parameter to lll_futex_wake().
+
+       * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h: Define LLL_PRIVATE
+       LLL_SHARED, lll_private_futex_wait, lll_private_futex_timed_wait and
+       lll_private_futex_wake.
+       (lll_futex_wait): Add private parameter. Adjust FUTEX_PRIVATE_FLAG
+       bit from private parm before syscall.
+       (lll_futex_timed_wait): Likewise.
+       (lll_futex_wake): Likewise.
+       (lll_futex_wake_unlock): Likewise.
+       (lll_mutex_unlock): Add LLL_SHARED parm to lll_futex_wake call.
+       (lll_robust_mutex_unlock): Likewise.
+       (lll_mutex_unlock_force): Likewise.
+       (lll_wait_tid): Add LLL_SHARED parm to lll_futex_wait call.
+
+2007-07-23  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedrdlock.S: Fix
+       compilation when unconditionally using private futexes.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_rdlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedwrlock.S:
+       Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_unlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_wrlock.S: Likewise.
+
+2007-07-17  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/pthread/bits/stdio-lock.h (_IO_acquire_lock_clear_flags2):
+       Define.
+
+2007-07-06  Kaz Kojima  <kkojima@rr.iij4u.or.jp>
+
+       * sysdeps/sh/tls.h: Include stdlib.h, list.h, sysdep.h and
+       kernel-features.h.
+
+2007-05-16  Roland McGrath  <roland@redhat.com>
+
+       * init.c (__nptl_initial_report_events): New variable.
+       (__pthread_initialize_minimal_internal): Initialize pd->report_events
+       to that.
+
+2007-06-22  Jakub Jelinek  <jakub@redhat.com>
+
+       * pthread_getattr_np.c (pthread_getattr_np): Clear cpuset and
+       cpusetsize if pthread_getaffinity_np failed with ENOSYS.
+
+2007-06-19  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/rtld-lowlevel.h: Remove mrlock
+       implementation.
+
+2007-06-18  Ulrich Drepper  <drepper@redhat.com>
+
+       * pthreadP.h: Define PTHREAD_MUTEX_TYPE.
+       * phtread_mutex_lock.c: Use PTHREAD_MUTEX_TYPE.
+       * pthread_mutex_timedlock.c: Likewise.
+       * pthread_mutex_trylock.c: Likewise.
+       * pthread_mutex_unlock.c: Likewise.
+
+2007-06-17  Andreas Schwab  <schwab@suse.de>
+
+       * sysdeps/pthread/pt-initfini.c: Tell gcc about the nonstandard
+       sections.
+
+2007-06-17  Ulrich Drepper  <drepper@redhat.com>
+
+       * allocatestack.c (allocate_stack): Make code compile if
+       __ASSUME_PRIVATE_FUTEX is set.
+
+2007-06-17  Kaz Kojima  <kkojima@rr.iij4u.or.jp>
+
+       * sysdeps/unix/sysv/linux/sh/pthread_rwlock_rdlock.S:
+       (__pthread_rwlock_rdlock): Don't use non SH-3/4 instruction.
+       * sysdeps/unix/sysv/linux/sh/pthread_rwlock_wrlock.S:
+       (__pthread_rwlock_wrlock): Likewise.
+       * sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedrdlock.S:
+       (pthread_rwlock_timedrdlock): Likewise.
+       * sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedwrlock.S:
+       (pthread_rwlock_timedwrlock): Likewise.
+       * sysdeps/unix/sysv/linux/sh/pthread_rwlock_unlock.S:
+       (__pthread_rwlock_unlock): Likewise.
+
+2007-06-10  Kaz Kojima  <kkojima@rr.iij4u.or.jp>
+
+       * sysdeps/sh/tcb-offsets.sym: Add PRIVATE_FUTEX.
+       * sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h: Include endian.h.
+       Split __flags into __flags, __shared, __pad1 and __pad2.
+       * sysdeps/unix/sysv/linux/sh/libc-lowlevellock.S: Use private
+       futexes if they are available.
+       * sysdeps/unix/sysv/linux/sh/lowlevellock.S: Adjust so that change
+       in libc-lowlevellock.S allow using private futexes.
+       * sysdeps/unix/sysv/linux/sh/lowlevellock.h: Define
+       FUTEX_PRIVATE_FLAG.  Add additional parameter to lll_futex_wait,
+       lll_futex_timed_wait and lll_futex_wake.  Change lll_futex_wait
+       to call lll_futex_timed_wait.  Add lll_private_futex_wait,
+       lll_private_futex_timed_wait and lll_private_futex_wake.
+       (lll_robust_mutex_unlock): Fix typo.
+       * sysdeps/unix/sysv/linux/sh/pthread_barrier_wait.S: Use private
+       field in futex command setup.
+       * sysdeps/unix/sysv/linux/sh/pthread_cond_timedwait.S: Use
+       COND_NWAITERS_SHIFT instead of COND_CLOCK_BITS.
+       * sysdeps/unix/sysv/linux/sh/pthread_cond_wait.S: Likewise.
+       * sysdeps/unix/sysv/linux/sh/pthread_once.S: Use private futexes
+       if they are available.  Remove clear_once_control.
+       * sysdeps/unix/sysv/linux/sh/pthread_rwlock_rdlock.S: Use private
+       futexes if they are available.
+       * sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedrdlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedwrlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/sh/pthread_rwlock_unlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/sh/pthread_rwlock_wrlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/sh/sem_post.S: Add private futex support.
+       Wake only when there are waiters.
+       * sysdeps/unix/sysv/linux/sh/sem_wait.S: Add private futex
+       support.  Indicate that there are waiters.  Remove unnecessary
+       extra cancellation test.
+       * sysdeps/unix/sysv/linux/sh/sem_timedwait.S: Likewise.  Removed
+       left-over duplication of __sem_wait_cleanup.
+
+2007-06-07  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h: Add additional
+       parameter to lll_futex_wait, lll_futex_timed_wait, and
+       lll_futex_wake.  Change lll_futex_wait to call lll_futex_timed_wait.
+       Add lll_private_futex_wait, lll_private_futex_timed_wait, and
+       lll_private_futex_wake.
+       * sysdeps/unix/sysv/linux/i386/lowlevellock.h: Likewise.
+       * allocatestack.c: Adjust use of lll_futex_* macros.
+       * init.c: Likewise.
+       * lowlevellock.h: Likewise.
+       * pthread_barrier_wait.c: Likewise.
+       * pthread_cond_broadcast.c: Likewise.
+       * pthread_cond_destroy.c: Likewise.
+       * pthread_cond_signal.c: Likewise.
+       * pthread_cond_timedwait.c: Likewise.
+       * pthread_cond_wait.c: Likewise.
+       * pthread_create.c: Likewise.
+       * pthread_mutex_lock.c: Likewise.
+       * pthread_mutex_setprioceiling.c: Likewise.
+       * pthread_mutex_timedlock.c: Likewise.
+       * pthread_mutex_unlock.c: Likewise.
+       * pthread_rwlock_timedrdlock.c: Likewise.
+       * pthread_rwlock_timedwrlock.c: Likewise.
+       * pthread_rwlock_unlock.c: Likewise.
+       * sysdeps/alpha/tls.h: Likewise.
+       * sysdeps/i386/tls.h: Likewise.
+       * sysdeps/ia64/tls.h: Likewise.
+       * sysdeps/powerpc/tls.h: Likewise.
+       * sysdeps/pthread/aio_misc.h: Likewise.
+       * sysdeps/pthread/gai_misc.h: Likewise.
+       * sysdeps/s390/tls.h: Likewise.
+       * sysdeps/sh/tls.h: Likewise.
+       * sysdeps/sparc/tls.h: Likewise.
+       * sysdeps/unix/sysv/linux/fork.c: Likewise.
+       * sysdeps/unix/sysv/linux/lowlevellock.c: Likewise.
+       * sysdeps/unix/sysv/linux/lowlevelrobustlock.c: Likewise.
+       * sysdeps/unix/sysv/linux/rtld-lowlevel.h: Likewise.
+       * sysdeps/unix/sysv/linux/sem_post.c: Likewise.
+       * sysdeps/unix/sysv/linux/sem_timedwait.c: Likewise.
+       * sysdeps/unix/sysv/linux/sem_wait.c: Likewise.
+       * sysdeps/unix/sysv/linux/unregister-atfork.c: Likewise.
+       * sysdeps/unix/sysv/linux/sparc/pthread_once.c: Likewise.
+       * sysdeps/unix/sysv/linux/sparc/sparc32/pthread_barrier_wait.c:
+       Likewise.
+       * sysdeps/unix/sysv/linux/sparc/sparc32/sem_post.c: Likewise.
+       * sysdeps/x86_64/tls.h: Likewise.
+
+2007-05-29  Ulrich Drepper  <drepper@redhat.com>
+
+       * pthread_getattr_np.c: No need to install a cancellation handler,
+       this is no cancellation point.
+       * pthread_getschedparam.c: Likewise.
+       * pthread_setschedparam.c: Likewise.
+       * pthread_setschedprio.c: Likewise.
+       * sysdeps/unix/sysv/linux/lowlevellock.c: Remove all traces of
+       lll_unlock_wake_cb.
+       * sysdeps/unix/sysv/linux/alpha/lowlevellock.h: Likewise.
+       * sysdeps/unix/sysv/linux/i386/lowlevellock.h: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S: Likewise.
+       * sysdeps/unix/sysv/linux/ia64/lowlevellock.h: Likewise.
+       * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h: Likewise.
+       * sysdeps/unix/sysv/linux/s390/lowlevellock.h: Likewise.
+       * sysdeps/unix/sysv/linux/sh/lowlevellock.S: Likewise.
+       * sysdeps/unix/sysv/linux/sh/lowlevellock.h: Likewise.
+       * sysdeps/unix/sysv/linux/sparc/lowlevellock.h: Likewise.
+       * sysdeps/unix/sysv/linux/sparc/sparc32/lowlevellock.c: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/lowlevellock.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h: Likewise.
+
+       * sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S: Checking
+       whether there are more than one thread makes no sense here since
+       we only call the slow path if the locks are taken.
+       * sysdeps/unix/sysv/linux/x86_64/libc-lowlevellock.S: Likewise.
+
+       * sysdeps/unix/sysv/linux/internaltypes.h: Introduce
+       COND_NWAITERS_SHIFT.
+       * pthread_cond_destroy.c: Use COND_NWAITERS_SHIFT instead of
+       COND_CLOCK_BITS.
+       * pthread_cond_init.c: Likewise.
+       * pthread_cond_timedwait.c: Likewise.
+       * pthread_cond_wait.c: Likewise.
+       * pthread_condattr_getclock.c: Likewise.
+       * pthread_condattr_setclock.c: Likewise.
+       * sysdeps/unix/sysv/linux/lowlevelcond.sym: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S: Likewise.
+
+2007-05-28  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/powerpc/pthread_attr_setstacksize.c: Include
+       unistd.h.
+
+       * sysdeps/i386/tls.h (THREAD_GSCOPE_RESET_FLAG): Use explicit
+       insn suffix.
+       (THREAD_GSCOPE_GET_FLAG): Remove.
+       * sysdeps/x86_64/tls.h (THREAD_GSCOPE_GET_FLAG): Remove.
+       * allocatestack.c (__wait_lookup_done): Revert 2007-05-24
+       changes.
+       * sysdeps/powerpc/tls.h (tcbhead_t): Remove gscope_flag.
+       (THREAD_GSCOPE_GET_FLAG): Remove.
+       (THREAD_GSCOPE_RESET_FLAG): Use THREAD_SELF->header.gscope_flag
+       instead of THREAD_GSCOPE_GET_FLAG.
+       (THREAD_GSCOPE_SET_FLAG): Likewise.  Add atomic_write_barrier after
+       it.
+       * sysdeps/s390/tls.h (THREAD_GSCOPE_FLAG_UNUSED,
+       THREAD_GSCOPE_FLAG_USED, THREAD_GSCOPE_FLAG_WAIT,
+       THREAD_GSCOPE_RESET_FLAG, THREAD_GSCOPE_SET_FLAG,
+       THREAD_GSCOPE_WAIT): Define.
+       * sysdeps/sparc/tls.h (THREAD_GSCOPE_FLAG_UNUSED,
+       THREAD_GSCOPE_FLAG_USED, THREAD_GSCOPE_FLAG_WAIT,
+       THREAD_GSCOPE_RESET_FLAG, THREAD_GSCOPE_SET_FLAG,
+       THREAD_GSCOPE_WAIT): Define.
+       * sysdeps/sh/tls.h (THREAD_GSCOPE_FLAG_UNUSED,
+       THREAD_GSCOPE_FLAG_USED, THREAD_GSCOPE_FLAG_WAIT,
+       THREAD_GSCOPE_RESET_FLAG, THREAD_GSCOPE_SET_FLAG,
+       THREAD_GSCOPE_WAIT): Define.
+       * sysdeps/ia64/tls.h (THREAD_GSCOPE_FLAG_UNUSED,
+       THREAD_GSCOPE_FLAG_USED, THREAD_GSCOPE_FLAG_WAIT,
+       THREAD_GSCOPE_RESET_FLAG, THREAD_GSCOPE_SET_FLAG,
+       THREAD_GSCOPE_WAIT): Define.
+
+2007-05-24  Richard Henderson  <rth@redhat.com>
+
+       * descr.h (struct pthread): Add header.gscope_flag.
+       * sysdeps/alpha/tls.h (THREAD_GSCOPE_FLAG_UNUSED,
+       THREAD_GSCOPE_FLAG_USED, THREAD_GSCOPE_FLAG_WAIT,
+       THREAD_GSCOPE_RESET_FLAG, THREAD_GSCOPE_SET_FLAG,
+       THREAD_GSCOPE_WAIT): Define.
+
+2007-05-27  Ulrich Drepper  <drepper@redhat.com>
+
+       * init.c: Make it compile with older kernel headers.
+
+       * tst-initializers1.c: Show through exit code which test failed.
+
+       * pthread_rwlock_init.c: Also initialize __shared field.
+       * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h: Split __flags
+       element in rwlock structure into four byte elements.  One of them is
+       the new __shared element.
+       * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h [__WORDSIZE=32]:
+       Likewise.
+       [__WORDSIZE=64]: Renamed __pad1 element int rwlock structure to
+       __shared, adjust names of other padding elements.
+       * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h: Likewise.
+       * sysdeps/pthread/pthread.h: Adjust rwlock initializers.
+       * sysdeps/unix/sysv/linux/lowlevelrwlock.sym: Add PSHARED.
+       * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h: Define
+       FUTEX_PRIVATE_FLAG.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_rdlock.S: Change main
+       futex to use private operations if possible.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedrdlock.S:
+       Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedwrlock.S:
+       Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_unlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_wrlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_rdlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedrdlock.S:
+       Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedwrlock.S:
+       Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_unlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_wrlock.S: Likewise.
+
+2007-05-26  Ulrich Drepper  <drepper@redhat.com>
+
+       * pthreadP.h (PTHREAD_RWLOCK_PREFER_READER_P): Define.
+       * pthread_rwlock_rdlock.c: Use PTHREAD_RWLOCK_PREFER_READER_P.
+       * pthread_rwlock_timedrdlock.c: Likewise.
+       * pthread_rwlock_tryrdlock.c: Likewise.
+
+       * sysdeps/unix/sysv/linux/x86_64/sem_trywait.S (sem_trywait): Tiny
+       optimization.
+
+       * sysdeps/unix/sysv/linux/sem_wait.c: Add missing break.
+       * sysdeps/unix/sysv/linux/sem_timedwait.c: Removed left-over
+       duplication of __sem_wait_cleanup.
+
+       * allocatestack.c: Revert last change.
+       * init.c: Likewise.
+       * sysdeps/i386/tls.h: Likewise.
+       * sysdeps/x86_64/tls.h: Likewise.
+       * descr.h [TLS_DTV_AT_TP] (struct pthread): Add private_futex field to
+       header structure.
+       * sysdeps/powerpc/tcb-offsets.sym: Add PRIVATE_FUTEX_OFFSET.
+
+       * sysdeps/unix/sysv/linux/internaltypes.h (struct pthread_barrier):
+       Add private field.
+       * sysdeps/unix/sysv/linux/lowlevelbarrier.sym: Add PRIVATE definition.
+       * pthread_barrier_init.c: Set private flag if pshared and private
+       futexes are supported.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_barrier_wait.S: Use
+       private field in futex command setup.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_barrier_wait.S: Likewise.
+
+2007-05-25  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/i486/sem_post.S: Add private futex
+       support.
+       * sysdeps/unix/sysv/linux/i386/i486/sem_timedwait.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/sem_wait.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/sem_post.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/sem_wait.S: Likewise.
+
+       * semaphoreP.h: Declare __old_sem_init and __old_sem_wait.
+       * sem_init.c (__new_sem_init): Rewrite to initialize all three
+       fields in the structure.
+       (__old_sem_init): New function.
+       * sem_open.c: Initialize all fields of the structure.
+       * sem_getvalue.c: Adjust for renamed element.
+       * sysdeps/unix/sysv/linux/Makefile [subdir=nptl]
+       (gen-as-const-headers): Add structsem.sym.
+       * sysdeps/unix/sysv/linux/structsem.sym: New file.
+       * sysdeps/unix/sysv/linux/internaltypes.h: Rename struct sem to
+       struct new_sem.  Add struct old_sem.
+       * sysdeps/unix/sysv/linux/sem_post.c: Wake only when there are waiters.
+       * sysdeps/unix/sysv/linux/i386/i486/sem_post.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/sem_post.S: Likewise.
+       * sysdeps/unix/sysv/linux/sem_wait.c: Indicate that there are waiters.
+       * sysdeps/unix/sysv/linux/i386/i486/sem_wait.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/sem_wait.S: Likewise.
+       * sysdeps/unix/sysv/linux/sem_timedwait.c: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/sem_timedwait.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S: Likewise.
+       * Makefile (tests): Add tst-sem10, tst-sem11, tst-sem12.
+       * tst-sem10.c: New file.
+       * tst-sem11.c: New file.
+       * tst-sem12.c: New file.
+       * tst-typesizes.c: Test struct new_sem and struct old_sem instead
+       of struct sem.
+
+2007-05-25  Ulrich Drepper  <drepper@redhat.com>
+           Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/i486/sem_timedwait.S (sem_timedwait):
+       Move __pthread_enable_asynccancel right before futex syscall.
+       * sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S (sem_timedwait):
+       Likewise.
+
+2007-05-24  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/i386/tls.h (THREAD_SET_PRIVATE_FUTEX,
+       THREAD_COPY_PRIVATE_FUTEX): Define.
+       * sysdeps/x86_64/tls.h (THREAD_SET_PRIVATE_FUTEX,
+       THREAD_COPY_PRIVATE_FUTEX): Define.
+       * allocatestack.c (allocate_stack): Use THREAD_COPY_PRIVATE_FUTEX.
+       * init.c (__pthread_initialize_minimal_internal): Use
+       THREAD_SET_PRIVATE_FUTEX.
+
+       * sysdeps/powerpc/tls.h (tcbhead_t): Add gscope_flag.
+       (THREAD_GSCOPE_FLAG_UNUSED, THREAD_GSCOPE_FLAG_USED,
+       THREAD_GSCOPE_FLAG_WAIT): Define.
+       (THREAD_GSCOPE_GET_FLAG, THREAD_GSCOPE_SET_FLAG,
+       THREAD_GSCOPE_RESET_FLAG, THREAD_GSCOPE_WAIT): Define.
+       * sysdeps/i386/tls.h (THREAD_GSCOPE_WAIT): Don't use
+       PTR_DEMANGLE.
+       (THREAD_GSCOPE_GET_FLAG): Define.
+       * sysdeps/x86_64/tls.h (THREAD_GSCOPE_GET_FLAG): Define.
+       * allocatestack.c (__wait_lookup_done): Use THREAD_GSCOPE_GET_FLAG
+       instead of ->header.gscope_flag directly.
+
+2007-05-23  Ulrich Drepper  <drepper@redhat.com>
+
+       * init.c (__pthread_initialize_minimal_internal): Check whether
+       private futexes are available.
+       * allocatestack.c (allocate_stack): Copy private_futex field from
+       current thread into the new stack.
+       * sysdeps/unix/sysv/linux/x86_64/libc-lowlevellock.S: Use private
+       futexes if they are available.
+       * sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S: Likewise
+       * sysdeps/unix/sysv/linux/x86_64/lowlevellock.S: Adjust so that change
+       in libc-lowlevellock.S allow using private futexes.
+       * sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h: Define
+       FUTEX_PRIVATE_FLAG.
+       * sysdeps/unix/sysv/linux/i386/lowlevellock.h: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_once.S: Use private futexes
+       if they are available.
+       * sysdeps/unix/sysv/linux/i386/pthread_once.S: Likewise.
+       * sysdeps/x86_64/tcb-offsets.sym: Add PRIVATE_FUTEX.
+       * sysdeps/i386/tcb-offsets.sym: Likewise.
+       * sysdeps/x86_64/tls.h (tcbhead_t): Add private_futex field.
+       * sysdeps/i386/tls.h (tcbhead_t): Likewise.
+
+2007-05-21  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/pthread-functions.h (struct pthread_functions):
+       Remove ptr_wait_lookup_done again.
+       * init.c (pthread_functions): Don't add .ptr_wait_lookup_done here.
+       (__pthread_initialize_minimal_internal): Initialize
+       _dl_wait_lookup_done pointer in _rtld_global directly.
+       * sysdeps/unix/sysv/linux/libc_pthread_init.c (__libc_pthread_init):
+       Remove code to code _dl_wait_lookup_done.
+       * sysdeps/x86_64/tls.h (THREAD_GSCOPE_WAIT): The pointer is not
+       encrypted for now.
+
+2007-05-21  Jakub Jelinek  <jakub@redhat.com>
+
+       * tst-robust9.c (do_test): Don't fail if ENABLE_PI and
+       pthread_mutex_init failed with ENOTSUP.
+
+2007-05-19  Ulrich Drepper  <drepper@redhat.com>
+
+       * allocatestack.c (__wait_lookup_done): New function.
+       * sysdeps/pthread/pthread-functions.h (struct pthread_functions):
+       Add ptr_wait_lookup_done.
+       * init.c (pthread_functions): Initialize .ptr_wait_lookup_done.
+       * pthreadP.h: Declare __wait_lookup_done.
+       * sysdeps/i386/tls.h (tcbhead_t): Add gscope_flag.
+       Define macros to implement reference handling of global scope.
+       * sysdeps/x86_64/tls.h: Likewise.
+       * sysdeps/unix/sysv/linux/libc_pthread_init.c (__libc_pthread_init):
+       Initialize GL(dl_wait_lookup_done).
+
+2007-05-17  Ulrich Drepper  <drepper@redhat.com>
+
+       [BZ #4512]
+       * pthread_mutex_lock.c: Preserve FUTEX_WAITERS bit when dead owner
+       is detected.
+       * pthread_mutex_timedlock.c: Likewise.
+       * pthread_mutex_trylock.c: Likewise.
+       Patch in part by Atsushi Nemoto <anemo@mba.ocn.ne.jp>.
+
+       * Makefile (tests): Add tst-robust9 and tst-robustpi9.
+       * tst-robust9.c: New file.
+       * tst-robustpi9.c: New file.
+
+       * sysdeps/unix/sysv/linux/sem_wait.c (__new_sem_wait): Remove
+       unnecessary extra cancellation test.
+
+2007-05-14  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/x86_64/sem_wait.S: Remove unnecessary
+       extra cancellation test.
+       * sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S: Likewise.
+
+2007-05-10  Ulrich Drepper  <drepper@redhat.com>
+
+       * descr.h (struct pthread): Rearrange members to fill hole in
+       64-bit layout.
+
+       * sysdeps/unix/sysv/linux/pthread_setaffinity.c
+       (__pthread_setaffinity_new): If syscall was successful and
+       RESET_VGETCPU_CACHE is defined, use it before returning.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_setaffinity.c: New file.
+
+2007-05-10  Jakub Jelinek  <jakub@redhat.com>
+
+       [BZ #4455]
+       * tst-align2.c: Include stackinfo.h.
+       * tst-getpid1.c: Likewise.
+
+2007-05-02  Carlos O'Donell  <carlos@systemhalted.org>
+
+       [BZ #4455]
+       * tst-align2.c (do_test): Add _STACK_GROWS_UP case.
+       * tst-getpid1.c (do_test): Likewise.
+
+       [BZ #4456]
+       * allocatestack.c (change_stack_perm): Add _STACK_GROWS_UP case.
+       (allocate_stack): Likewise.
+
+2007-05-07  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/lowlevelrobustlock.c
+       (__lll_robust_lock_wait): Fix race caused by reloading of futex value.
+       (__lll_robust_timedlock_wait): Likewise.
+       Reported by Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>.
+
+2007-05-06  Mike Frysinger  <vapier@gentoo.org>
+
+       [BZ #4465]
+       * tst-cancel-wrappers.sh: Set C["fdatasync"] to 1.
+       * tst-cancel4.c (tf_fdatasync): New test.
+
+2007-04-27  Ulrich Drepper  <drepper@redhat.com>
+
+       [BZ #4392]
+       * pthread_mutex_trylock.c (__pthread_mutex_trylock): Treat error
+       check mutexes like normal mutexes.
+
+       [BZ #4306]
+       * sysdeps/unix/sysv/linux/timer_create.c (timer_create):
+       Initialize the whole sigevent structure to appease valgrind.
+
+2007-04-25  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/x86_64/tls.h (tcbhead_t): Add vgetcpu_cache.
+       * sysdeps/x86_64/tcb-offsets.sym: Add VGETCPU_CACHE_OFFSET.
+
+2007-04-06  Ulrich Drepper  <drepper@redhat.com>
+
+       * tst-locale1.c: Avoid warnings.
+       * tst-locale2.c: Likewise.
+
+2007-03-19  Steven Munroe  <sjmunroe@us.ibm.com>
+
+       * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h
+       (__lll_robust_trylock): Add MUTEX_HINT_ACQ to lwarx instruction.
+
+2007-03-16  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/pthread/bits/libc-lock.h: Use __extern_inline and
+       __extern_always_inline where appropriate.
+       * sysdeps/pthread/pthread.h: Likewise.
+
+2007-03-13  Richard Henderson  <rth@redhat.com>
+
+       * sysdeps/unix/sysv/linux/alpha/sysdep-cancel.h (PSEUDO): Use two
+       separate cfi regions for the two subsections.
+
+2007-02-25  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/fork.c (__libc_fork): Reset refcntr in
+       new thread, don't just decrement it.
+       Patch by Suzuki K P <suzuki@in.ibm.com>.
+
+2007-02-21  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/pthread-functions.h: Correct last patch, correct
+       PTHFCT_CALL definition.
+
+2007-02-18  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/pthread-functions.h: If PTR_DEMANGLE is not
+       available, don't use it.
+
+2007-02-09  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/x86_64/lowlevellock.S
+       (__lll_mutex_timedlock_wait): Use correct pointer when we don't
+       call into the kernel to delay.
+
+2007-01-18  Ulrich Drepper  <drepper@redhat.com>
+
+       * tst-initializers1.c: We want to test the initializers as seen
+       outside of libc, so undefined _LIBC.
+
+       * pthread_join.c (cleanup): Avoid warning.
+
+2007-01-17  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/x86_64/lowlevellock.S
+       (__lll_timedwait_tid): Add unwind info.
+
+       * sysdeps/unix/sysv/linux/libc_pthread_init.c: Don't just copy the
+       function table, mangle the pointers.
+       * sysdeps/pthread/pthread-functions.h: Define PTHFCT_CALL.
+       * forward.c: Use PTHFCT_CALL and __libc_pthread_functions_init.
+       * sysdeps/pthread/bits/libc-lock.h: When using __libc_pthread_functions
+       demangle pointers before use.
+       * sysdeps/unix/sysv/linux/s390/jmp-unwind.c: Use PTHFCT_CALL to
+       demangle pointer.
+       * sysdeps/unix/sysv/linux/jmp-unwind.c: Likewise.
+       * sysdeps/pthread/setxid.h: Likewise.
+
+2007-01-12  Ulrich Drepper  <drepper@redhat.com>
+
+       * tst-rwlock7.c: Show some more information in case of correct
+       behavior.
+
+2007-01-11  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h
+       (lll_futex_timed_wait): Undo part of last change, don't negate
+       return value.
+
+2007-01-10  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h: Cleanups.  Define
+       FUTEX_CMP_REQUEUE and lll_futex_requeue.
+
+2006-12-28  David S. Miller  <davem@davemloft.net>
+
+       * shlib-versions: Fix sparc64 linux target specification.
+
+2007-01-10  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/sparc/sparc32/sparcv9/pthread_barrier_wait.c:
+       Adjust include path for pthread_barrier_wait.c move.
+
+2006-12-21  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/pthread_kill.c (pthread_kill): Make sure
+       tid isn't reread from pd->tid in between ESRCH test and the syscall.
+
+2006-12-06  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h (PSEUDO): Handle
+       6 argument cancellable syscalls.
+       (STM_6, LM_6, LR7_0, LR7_1, LR7_2, LR7_3, LR7_4, LR7_5, LR7_6): Define.
+       * sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h (PSEUDO): Handle
+       6 argument cancellable syscalls.
+       (STM_6, LM_6, LR7_0, LR7_1, LR7_2, LR7_3, LR7_4, LR7_5, LR7_6): Define.
+
+2006-12-09  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/rtld-lowlevel.h
+       (__rtld_mrlock_initialize): Add missing closing parenthesis.
+
+2006-10-30  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/ia64/pthread_spin_unlock.c (pthread_spin_unlock): Use
+       __sync_lock_release instead of __sync_lock_release_si.
+
+2006-10-29  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h (RTLD_SINGLE_THREAD_P):
+       Define.
+       (SINGLE_THREAD_P): Define to 1 if IS_IN_rtld.
+       * sysdeps/unix/sysv/linux/alpha/sysdep-cancel.h: Likewise.
+       * sysdeps/unix/sysv/linux/ia64/sysdep-cancel.h: Likewise.
+       * sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h: Likewise.
+       * sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h: Likewise.
+       * sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h: Likewise.
+       * sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h: Likewise.
+       * sysdeps/unix/sysv/linux/sparc/sparc32/sysdep-cancel.h: Likewise.
+       * sysdeps/unix/sysv/linux/sparc/sparc64/sysdep-cancel.h: Likewise.
+       * sysdeps/unix/sysv/linux/sh/sysdep-cancel.h: Likewise.
+
+2006-10-27  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/pthread_barrier_wait.c: Move to...
+       * pthread_barrier_wait.c: ...here.
+       * sysdeps/pthread/pthread_cond_broadcast.c: Move to...
+       * pthread_cond_broadcast.c: ...here.
+       * sysdeps/pthread/pthread_cond_signal.c: Move to...
+       * pthread_cond_signal.c: ...here.
+       * sysdeps/pthread/pthread_cond_timedwait.c: Move to...
+       * pthread_cond_timedwait.c: ...here.
+       * sysdeps/pthread/pthread_cond_wait.c: Move to...
+       * pthread_cond_wait.c: ...here.
+       * sysdeps/pthread/pthread_once.c: Move to...
+       * pthread_once.c: ...here.
+       * sysdeps/pthread/pthread_rwlock_rdlock.c: Move to...
+       * pthread_rwlock_rdlock.c: ...here.
+       * sysdeps/pthread/pthread_rwlock_timedrdlock.c: Move to...
+       * pthread_rwlock_timedrdlock.c: ...here.
+       * sysdeps/pthread/pthread_rwlock_timedwrlock.c: Move to...
+       * pthread_rwlock_timedwrlock.c: ...here.
+       * sysdeps/pthread/pthread_rwlock_unlock.c: Move to...
+       * pthread_rwlock_unlock.c: ...here.
+       * sysdeps/pthread/pthread_rwlock_wrlock.c: Move to...
+       * pthread_rwlock_wrlock.c: ...here.
+       * sysdeps/pthread/pthread_spin_destroy.c: Move to...
+       * pthread_spin_destroy.c: ...here.
+       * sysdeps/pthread/pthread_spin_init.c: Move to...
+       * pthread_spin_init.c: ...here.
+       * sysdeps/pthread/pthread_spin_unlock.c: Move to...
+       * pthread_spin_unlock.c: ...here.
+       * sysdeps/pthread/pthread_getcpuclockid.c: Move to...
+       * pthread_getcpuclockid.c: ...here.
+
+       * init.c: USE_TLS support is now always enabled.
+       * tst-tls5.h: Likewise.
+       * sysdeps/alpha/tls.h: Likewise.
+       * sysdeps/i386/tls.h: Likewise.
+       * sysdeps/ia64/tls.h: Likewise.
+       * sysdeps/powerpc/tls.h: Likewise.
+       * sysdeps/s390/tls.h: Likewise.
+       * sysdeps/sh/tls.h: Likewise.
+       * sysdeps/sparc/tls.h: Likewise.
+       * sysdeps/x86_64/tls.h: Likewise.
+
+2006-10-27  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/rtld-lowlevel.h (__rtld_mrlock_lock,
+       __rtld_mrlock_change): Update oldval if atomic compare and exchange
+       failed.
+
+       * sysdeps/unix/sysv/linux/alpha/sysdep-cancel.h (SINGLE_THREAD_P):
+       Define to THREAD_SELF->header.multiple_threads.
+       * sysdeps/unix/sysv/linux/ia64/sysdep-cancel.h (SINGLE_THREAD_P):
+       Likewise.
+       * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h (SINGLE_THREAD_P):
+       Likewise.
+       * sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h
+       (SINGLE_THREAD_P): Likewise.
+       * sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h
+       (SINGLE_THREAD_P): Likewise.
+       * sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h
+       (SINGLE_THREAD_P): Likewise.
+       * sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h
+       (SINGLE_THREAD_P): Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h (SINGLE_THREAD_P):
+       Likewise.
+       * sysdeps/unix/sysv/linux/sparc/sparc32/sysdep-cancel.h
+       (SINGLE_THREAD_P): Likewise.
+       * sysdeps/unix/sysv/linux/sparc/sparc64/sysdep-cancel.h
+       (SINGLE_THREAD_P): Likewise.
+       * sysdeps/unix/sysv/linux/sh/sysdep-cancel.h (SINGLE_THREAD_P):
+       Likewise.
+
+2006-10-26  Jakub Jelinek  <jakub@redhat.com>
+
+       * pthread_attr_setstacksize.c (NEW_VERNUM): Define to GLIBC_2_3_3
+       by default rather than 2_3_3.
+
+2006-10-17  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/rtld-lowlevel.h (__rtld_mrlock_lock,
+       __rtld_mrlock_unlock, __rtld_mrlock_change, __rtld_mrlock_done): Use
+       atomic_* instead of catomic_* macros.
+
+2006-10-12  Ulrich Drepper  <drepper@redhat.com>
+
+       [BZ #3285]
+       * sysdeps/unix/sysv/linux/bits/local_lim.h: Add SEM_VALUE_MAX.
+       * sysdeps/unix/sysv/linux/powerpc/bits/local_lim.h: Likewise.
+       * sysdeps/unix/sysv/linux/sparc/bits/local_lim.h: Likewise.
+       * sysdeps/unix/sysv/linux/alpha/bits/local_lim.h: Likewise.
+       * sysdeps/unix/sysv/linux/ia64/bits/local_lim.h: Likewise.
+       * sysdeps/unix/sysv/linux/i386/bits/semaphore.h: Remove SEM_VALUE_MAX.
+       * sysdeps/unix/sysv/linux/powerpc/bits/semaphore.h: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/bits/semaphore.h: Likewise.
+       * sysdeps/unix/sysv/linux/sparc/bits/semaphore.h: Likewise.
+       * sysdeps/unix/sysv/linux/alpha/bits/semaphore.h: Likewise.
+       * sysdeps/unix/sysv/linux/sh/bits/semaphore.h: Likewise.
+       * sysdeps/unix/sysv/linux/ia64/bits/semaphore.h: Likewise.
+       * sysdeps/unix/sysv/linux/s390/bits/semaphore.h: Likewise.
+
+2006-10-11  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h: Add support for
+       cancelable syscalls with six parameters.
+
+       * sysdeps/unix/sysv/linux/rtld-lowlevel.h: Use catomic_*
+       operations instead of atomic_*.
+
+2006-10-09  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/rtld-lowlevel.h: New file..
+
+2006-10-07  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/powerpc/bits/local_lim.h: New file.
+       * sysdeps/unix/sysv/linux/powerpc/pthread_attr_setstack.c: New file.
+       * sysdeps/unix/sysv/linux/powerpc/pthread_attr_setstacksize.c:
+       New file.
+       * pthread_attr_setstack.c: Allow overwriting the version number of the
+       new symbol.
+       * pthread_attr_setstacksize.c: Likewise.
+       (__old_pthread_attr_setstacksize): If STACKSIZE_ADJUST is defined use
+       it.
+       * sysdeps/unix/sysv/linux/powerpc/Versions (libpthread): Add
+       pthread_attr_setstack and pthread_attr_setstacksize to GLIBC_2.6.
+
+2006-09-24  Ulrich Drepper  <drepper@redhat.com>
+
+       [BZ #3251]
+       * descr.h (ENQUEUE_MUTEX_BOTH): Add cast to avoid warning.
+       Patch by Petr Baudis.
+
+2006-09-18  Jakub Jelinek  <jakub@redhat.com>
+
+       * tst-kill4.c (do_test): Explicitly set tf thread's stack size.
+
+       * tst-cancel2.c (tf): Loop as long as something was written.
+
+2006-09-12  Kaz Kojima  <kkojima@rr.iij4u.or.jp>
+
+       * sysdeps/unix/sysv/linux/sh/pthread_cond_broadcast.S: For PI
+       mutexes wake all mutexes.
+       * sysdeps/unix/sysv/linux/sh/pthread_cond_wait.S: Don't increment
+       WAKEUP_SEQ if this would increase the value beyond TOTAL_SEQ.
+       * sysdeps/unix/sysv/linux/sh/pthread_cond_timedwait.S: Likewise.
+
+2006-09-12  Ulrich Drepper  <drepper@redhat.com>
+
+       * tst-cond22.c (tf): Slight changes to the pthread_cond_wait use
+       to guarantee the thread is always canceled.
+
+2006-09-08  Jakub Jelinek  <jakub@redhat.com>
+
+       * tst-cond22.c: Include pthread.h instead of pthreadP.h.
+       Include stdlib.h.
+       * sysdeps/pthread/pthread_cond_wait.c (__condvar_cleanup): Only
+       increase FUTEX if increasing WAKEUP_SEQ.  Fix comment typo.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S: Likewise.
+
+2006-09-08  Ulrich Drepper  <drepper@redhat.com>
+
+       [BZ #3123]
+       * sysdeps/pthread/pthread_cond_wait.c (__condvar_cleanup): Don't
+       increment WAKEUP_SEQ if this would increase the value beyond TOTAL_SEQ.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S: Likewise.
+       * Makefile (tests): Add tst-cond22.
+       * tst-cond22.c: New file.
+
+2006-09-05  Ulrich Drepper  <drepper@redhat.com>
+
+       [BZ #3124]
+       * descr.h (struct pthread): Add parent_cancelhandling.
+       * sysdeps/pthread/createthread.c (create_thread): Pass parent
+       cancelhandling value to child.
+       * pthread_create.c (start_thread): If parent thread was canceled
+       reset the SIGCANCEL mask.
+       * Makefile (tests): Add tst-cancel25.
+       * tst-cancel25.c: New file.
+
+2006-09-05  Jakub Jelinek  <jakub@redhat.com>
+           Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/gai_misc.h (GAI_MISC_NOTIFY): Don't decrement
+       counterp if it is already zero.
+       * sysdeps/pthread/aio_misc.h (AIO_MISC_NOTIFY): Likewise..
+
+2006-03-04  Jakub Jelinek  <jakub@redhat.com>
+           Roland McGrath  <roland@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/lowlevellock.h
+       (LLL_STUB_UNWIND_INFO_START, LLL_STUB_UNWIND_INFO_END,
+       LLL_STUB_UNWIND_INFO_3, LLL_STUB_UNWIND_INFO_4): Define.
+       (lll_mutex_lock, lll_robust_mutex_lock, lll_mutex_cond_lock,
+       lll_robust_mutex_cond_lock, lll_mutex_timedlock,
+       lll_robust_mutex_timedlock, lll_mutex_unlock,
+       lll_robust_mutex_unlock, lll_lock, lll_unlock): Use them.
+       Add _L_*_ symbols around the subsection.
+       * sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S: Add unwind info.
+       * sysdeps/unix/sysv/linux/i386/i486/lowlevelrobustlock.S: Likewise.
+
+2006-03-03  Jakub Jelinek  <jakub@redhat.com>
+           Roland McGrath  <roland@redhat.com>
+
+       * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h
+       (LLL_STUB_UNWIND_INFO_START, LLL_STUB_UNWIND_INFO_END,
+       LLL_STUB_UNWIND_INFO_5, LLL_STUB_UNWIND_INFO_6): Define.
+       (lll_mutex_lock, lll_robust_mutex_lock, lll_mutex_cond_lock,
+       lll_robust_mutex_cond_lock, lll_mutex_timedlock,
+       lll_robust_mutex_timedlock, lll_mutex_unlock,
+       lll_robust_mutex_unlock, lll_lock, lll_unlock): Use them.
+       Add _L_*_ symbols around the subsection.
+       * sysdeps/unix/sysv/linux/x86_64/lowlevellock.S: Add unwind info.
+       * sysdeps/unix/sysv/linux/x86_64/lowlevelrobustlock.S: Likewise.
+
+2006-08-31  Ulrich Drepper  <drepper@redhat.com>
+
+       * pthread_rwlock_trywrlock.c (__pthread_rwlock_trywrlock): Undo last
+       change because it can disturb too much existing code.  If real hard
+       reader preference is needed we'll introduce another type.
+       * sysdeps/pthread/pthread_rwlock_timedwrlock.c
+       (pthread_rwlock_timedwrlock): Likewise.
+       * sysdeps/pthread/pthread_rwlock_wrlock.c (__pthread_rwlock_wrlock):
+       Likewise.
+
+2006-08-30  Ulrich Drepper  <drepper@redhat.com>
+
+       * pthread_rwlock_trywrlock.c (__pthread_rwlock_trywrlock): Respect
+       reader preference.
+       * sysdeps/pthread/pthread_rwlock_timedwrlock.c
+       (pthread_rwlock_timedwrlock): Likewise.
+       * sysdeps/pthread/pthread_rwlock_wrlock.c (__pthread_rwlock_wrlock):
+       Likewise.
+
+2006-08-25  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/libc_pthread_init.c (freeres_libpthread):
+       Only define ifdef SHARED.
+
+2006-08-23  Ulrich Drepper  <drepper@redhat.com>
+
+       * allocatestack.c (queue_stack): Move freeing of surplus stacks to...
+       (free_stacks): ...here.
+       (__free_stack_cache): New function.
+       * pthreadP.h: Declare __free_stack_cache.
+       * sysdeps/pthread/pthread-functions.h (pthread_functions): Add
+       ptr_freeres.
+       * init.c (pthread_functions): Initialize ptr_freeres.
+       * sysdeps/unix/sysv/linux/libc_pthread_init.c (freeres_libptread):
+       New freeres function.
+
+2006-07-30  Joseph S. Myers  <joseph@codesourcery.com>
+
+       [BZ #3018]
+       * Makefile (extra-objs): Add modules to extra-test-objs instead.
+
+2006-08-20  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/bits/posix_opt.h: Define
+       _XOPEN_REALTIME_THREADS.
+
+2006-08-15  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/clock_settime.c (INTERNAL_VSYSCALL): Use
+       HAVE_CLOCK_GETRES_VSYSCALL as guard macro rather than
+       HAVE_CLOCK_GETTIME_VSYSCALL.
+       (maybe_syscall_settime_cpu): Use plain INTERNAL_VSYSCALL here.
+
+2006-08-14  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/bits/posix_opt.h
+       (_POSIX_THREAD_PRIO_PROTECT): Define to 200112L.
+       * descr.h (struct priority_protection_data): New type.
+       (struct pthread): Add tpp field.
+       * pthreadP.h (PTHREAD_MUTEX_PP_NORMAL_NP,
+       PTHREAD_MUTEX_PP_RECURSIVE_NP, PTHREAD_MUTEX_PP_ERRORCHECK_NP,
+       PTHREAD_MUTEX_PP_ADAPTIVE_NP): New enum values.
+       * pthread_mutex_init.c (__pthread_mutex_init): Handle non-robust
+       TPP mutexes.
+       * pthread_mutex_lock.c (__pthread_mutex_lock): Handle TPP mutexes.
+       * pthread_mutex_trylock.c (__pthread_mutex_trylock): Likewise.
+       * pthread_mutex_timedlock.c (pthread_mutex_timedlock): Likewise.
+       * pthread_mutex_unlock.c (__pthread_mutex_unlock_usercnt): Likewise.
+       * tpp.c: New file.
+       * pthread_setschedparam.c (__pthread_setschedparam): Handle priority
+       boosted by TPP.
+       * pthread_setschedprio.c (pthread_setschedprio): Likewise.
+       * pthread_mutexattr_getprioceiling.c
+       (pthread_mutexattr_getprioceiling): If ceiling is 0, ensure it is
+       in the SCHED_FIFO priority range.
+       * pthread_mutexattr_setprioceiling.c
+       (pthread_mutexattr_setprioceiling): Fix prioceiling validation.
+       * pthread_mutex_getprioceiling.c (pthread_mutex_getprioceiling): Fail
+       if mutex is not TPP.  Ceiling is now in __data.__lock.
+       * pthread_mutex_setprioceiling.c: Include stdbool.h.
+       (pthread_mutex_setprioceiling): Fix prioceiling validation.  Ceiling
+       is now in __data.__lock.  Add locking.
+       * pthread_create.c (__free_tcb): Free pd->tpp structure.
+       * Makefile (libpthread-routines): Add tpp.
+       (xtests): Add tst-mutexpp1, tst-mutexpp6 and tst-mutexpp10.
+       * tst-tpp.h: New file.
+       * tst-mutexpp1.c: New file.
+       * tst-mutexpp6.c: New file.
+       * tst-mutexpp10.c: New file.
+       * tst-mutex1.c (TEST_FUNCTION): Don't redefine if already defined.
+       * tst-mutex6.c (TEST_FUNCTION): Likewise.
+
+2006-08-12  Ulrich Drepper  <drepper@redhat.com>
+
+       [BZ #2843]
+       * pthread_join.c (pthread_join): Account for self being canceled
+       when checking for deadlocks.
+       * tst-join5.c: Cleanups.  Allow to be used in tst-join6.
+       (tf1): Don't print anything after pthread_join returns, this would be
+       another cancellation point.
+       (tf2): Likewise.
+       * tst-join6.c: New file.
+       * Makefile (tests): Add tst-join6.
+
+2006-08-03  Ulrich Drepper  <drepper@redhat.com>
+
+       [BZ #2892]
+       * pthread_setspecific.c (__pthread_setspecific): Check
+       out-of-range index before checking for unused key.
+
+       * sysdeps/pthread/gai_misc.h: New file.
+
+2006-08-01  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/smp.h: New file.  Old Linux-specific
+       file.  Don't use sysctl.
+       * sysdeps/unix/sysv/linux/smp.h: Always assume SMP.  Archs can
+       overwrite the file if this is likely not true.
+
+2006-07-31  Daniel Jacobowitz  <dan@codesourcery.com>
+
+       * allocatestack.c (__reclaim_stacks): Reset the PID on cached stacks.
+       * Makefile (tests): Add tst-getpid3.
+       * tst-getpid3.c: New file.
+
+2006-07-30  Roland McGrath  <roland@redhat.com>
+
+       * Makefile (libpthread-routines): Add ptw-sigsuspend.
+
+       * sysdeps/unix/sysv/linux/i386/not-cancel.h
+       (pause_not_cancel): New macro.
+       (nanosleep_not_cancel): New macro.
+       (sigsuspend_not_cancel): New macro.
+       * pthread_mutex_timedlock.c (pthread_mutex_timedlock): Use
+       nanosleep_not_cancel macro from <not-cancel.h>.
+       * pthread_mutex_lock.c (__pthread_mutex_lock): Use pause_not_cancel
+       macro from <not-cancel.h>.
+
+2006-07-28  Ulrich Drepper  <drepper@redhat.com>
+           Jakub Jelinek  <jakub@redhat.com>
+
+       * descr.h: Change ENQUEUE_MUTEX and DEQUEUE_MUTEX for bit 0
+       notification of PI mutex.  Add ENQUEUE_MUTEX_PI.
+       * pthreadP.h: Define PTHREAD_MUTEX_PI_* macros for PI mutex types.
+       * pthread_mutex_setprioceilining.c: Adjust for mutex type name change.
+       * pthread_mutex_init.c: Add support for priority inheritance mutex.
+       * pthread_mutex_lock.c: Likewise.
+       * pthread_mutex_timedlock.c: Likewise.
+       * pthread_mutex_trylock.c: Likewise.
+       * pthread_mutex_unlock.c: Likewise.
+       * sysdeps/pthread/pthread_cond_broadcast.c: For PI mutexes wake
+       all mutexes.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.c: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.c: Likewise.
+       * sysdeps/unix/sysv/linux/pthread-pi-defines.sym: New file.
+       * sysdeps/unix/sysv/linux/Makefile (gen-as-const-header): Add
+       pthread-pi-defines.sym.
+       * sysdeps/unix/sysv/linux/i386/lowlevellock.h: Define FUTEX_LOCK_PI,
+       FUTEX_UNLOCK_PI, and FUTEX_TRYLOCK_PI.
+       * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h: Likewise.
+       * sysdeps/unix/sysv/linux/alpha/lowlevellock.h: Likewise.
+       * sysdeps/unix/sysv/linux/ia64/lowlevellock.h: Likewise.
+       * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h: Likewise.
+       * sysdeps/unix/sysv/linux/s390/lowlevellock.h: Likewise.
+       * sysdeps/unix/sysv/linux/sh/lowlevellock.h: Likewise.
+       * sysdeps/unix/sysv/linux/sparc/lowlevellock.h: Likewise.
+       * sysdeps/unix/sysv/linux/bits/posix_opt.h: Define
+       _POSIX_THREAD_PRIO_INHERIT to 200112L.
+       * tst-mutex1.c: Adjust to allow use in PI mutex test.
+       * tst-mutex2.c: Likewise.
+       * tst-mutex3.c: Likewise.
+       * tst-mutex4.c: Likewise.
+       * tst-mutex5.c: Likewise.
+       * tst-mutex6.c: Likewise.
+       * tst-mutex7.c: Likewise.
+       * tst-mutex7a.c: Likewise.
+       * tst-mutex8.c: Likewise.
+       * tst-mutex9.c: Likewise.
+       * tst-robust1.c: Likewise.
+       * tst-robust7.c: Likewise.
+       * tst-robust8.c: Likewise.
+       * tst-mutexpi1.c: New file.
+       * tst-mutexpi2.c: New file.
+       * tst-mutexpi3.c: New file.
+       * tst-mutexpi4.c: New file.
+       * tst-mutexpi5.c: New file.
+       * tst-mutexpi6.c: New file.
+       * tst-mutexpi7.c: New file.
+       * tst-mutexpi7a.c: New file.
+       * tst-mutexpi8.c: New file.
+       * tst-mutexpi9.c: New file.
+       * tst-robust1.c: New file.
+       * tst-robust2.c: New file.
+       * tst-robust3.c: New file.
+       * tst-robust4.c: New file.
+       * tst-robust5.c: New file.
+       * tst-robust6.c: New file.
+       * tst-robust7.c: New file.
+       * tst-robust8.c: New file.
+       * Makefile (tests): Add the new tests.
+
+       * pthread_create.c (start_thread): Add some casts to avoid warnings.
+       * pthread_mutex_destroy.c: Remove unneeded label.
+
+2006-07-01  Ulrich Drepper  <drepper@redhat.com>
+
+       * pthread_mutex_init.c (__pthread_mutex_init): Move some
+       computations to compile time.
+
+2006-06-04  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/pthread.h: Add pthread_equal inline version.
+
+2006-05-15  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/fork.h: Mark __fork_handlers as hidden.
+
+2006-05-11  Ulrich Drepper  <drepper@redhat.com>
+
+       * pthread_key_create.c (__pthread_key_create): Do away with
+       __pthread_keys_lock.
+
+       * sysdeps/unix/sysv/linux/pthread_setaffinity.c
+       (__kernel_cpumask_size): Mark as hidden.
+       * sysdeps/unix/sysv/linux/pthread_attr_setaffinity.c: Likewise.
+
+       * sem_open.c (__sem_mappings_lock): Mark as hidden.
+       * semaphoreP.h (__sem_mappings_lock): Likewise.
+
+2006-05-10  Ulrich Drepper  <drepper@redhat.com>
+
+       * pthread_atfork.c: Mark __dso_handle as hidden.
+
+2006-05-09  Ulrich Drepper  <drepper@redhat.com>
+
+       [BZ #2644]
+       * sysdeps/pthread/unwind-forcedunwind.c: Different solution for
+       the reload problem.  Change the one path in pthread_cancel_init
+       which causes the problem.  Force gcc to reload.  Simplify callers.
+       * sysdeps/unix/sysv/linux/ia64/unwind-forcedunwind.c
+       (_Unwind_GetBSP): Undo last patch.
+
+2006-05-07  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/ia64/unwind-forcedunwind.c: Make sure the
+       function pointer is reloaded after pthread_cancel_init calls.
+
+       [BZ #2644]
+       * sysdeps/pthread/unwind-forcedunwind.c: Make sure functions
+       pointers are reloaded after pthread_cancel_init calls.
+
+2006-05-01  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/allocalim.h (__libc_use_alloca): Mark with
+       __always_inline.
+
+2006-04-27  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/timer_routines.c (timer_helper_thread):
+       Allocate new object which is passed to timer_sigev_thread so that
+       the timer can be deleted before the new thread is scheduled.
+
+2006-04-26  Roland McGrath  <roland@redhat.com>
+
+       * sysdeps/x86_64/tls.h: Include <asm/prctl.h> inside [! __ASSEMBLER__].
+
+2006-04-08  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/lowlevellock.h: Remove branch predicion
+       suffix for conditional jumps.
+       * sysdeps/unix/sysv/linux/i386/i486/sem_trywait.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_barrier_wait.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/sem_timedwait.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/sem_wait.S: Likewise.
+
+       * init.c (sigcancel_handler): Compare with correct PID even if the
+       thread is in the middle of a fork call.
+       (sighandler_setxid): Likewise.
+       Reported by Suzuki K P <suzuki@in.ibm.com> .
+
+2006-04-07  Jakub Jelinek  <jakub@redhat.com>
+
+       * pthreadP.h (FUTEX_TID_MASK): Sync with kernel.
+
+2006-04-06  Ulrich Drepper  <drepper@redhat.com>
+
+       * pthread_getattr_np.c (pthread_getattr_np): Close fp if getrlimit
+       fails [Coverity CID 105].
+
+2006-04-05  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/pthread.h: Add nonnull attributes.
+
+2006-04-03  Steven Munroe  <sjmunroe@us.ibm.com>
+
+       [BZ #2505]
+       * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h [_ARCH_PWR4]:
+       Define __lll_rel_instr using lwsync.
+
+2006-03-27  Ulrich Drepper  <drepper@redhat.com>
+
+       * allocatestack.c (allocate_stack): Always initialize robust_head.
+       * descr.h: Define struct robust_list_head.
+       (struct pthread): Use robust_list_head in robust mutex list definition.
+       Adjust ENQUEUE_MUTEX and DEQUEUE_MUTEX.
+       * init.c [!__ASSUME_SET_ROBUST_LIST] (__set_robust_list_avail): Define.
+       (__pthread_initialize_minimal_internal): Register robust_list with
+       the kernel.
+       * pthreadP.h: Remove PRIVATE_ from PTHREAD_MUTEX_ROBUST_* names.
+       Declare __set_robust_list_avail.
+       * pthread_create.c (start_thread): Register robust_list of new thread.
+       [!__ASSUME_SET_ROBUST_LIST]: If robust_list is not empty wake up
+       waiters.
+       * pthread_mutex_destroy.c: For robust mutexes don't look at the
+       number of users, it's unreliable.
+       * pthread_mutex_init.c: Allow use of pshared robust mutexes if
+       set_robust_list syscall is available.
+       * pthread_mutex_consistent.c: Adjust for PTHREAD_MUTEX_ROBUST_* rename.
+       * pthread_mutex_lock.c: Simplify robust mutex code a bit.
+       Set robust_head.list_op_pending before trying to lock a robust mutex.
+       * pthread_mutex_timedlock.c: Likewise.
+       * pthread_mutex_trylock.c: Likewise.
+       * pthread_mutex_unlock.c: Likewise for unlocking.
+       * Makefile (tests): Add tst-robust8.
+       * tst-robust8.c: New file.
+
+2006-03-08  Andreas Schwab  <schwab@suse.de>
+
+       * sysdeps/unix/sysv/linux/ia64/dl-sysdep.h
+       (DL_SYSINFO_IMPLEMENTATION): Add missing newline.
+
+2006-03-05  Roland McGrath  <roland@redhat.com>
+
+       * configure (libc_add_on): Disable add-on when $add_ons_automatic = yes
+       and $config_os doesn't match *linux*.
+
+2006-03-05  David S. Miller  <davem@sunset.davemloft.net>
+
+       * sysdeps/unix/sysv/linux/sparc/sparc32/pt-vfork.S:
+       Use __syscall_error.
+       * sysdeps/unix/sysv/linux/sparc/sparc32/sysdep-cancel.h: Likewise.
+       * sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S: Likewise.
+       * sysdeps/unix/sysv/linux/sparc/sparc64/pt-vfork.S: Likewise.
+       * sysdeps/unix/sysv/linux/sparc/sparc64/sysdep-cancel.h: Likewise.
+       * sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S: Likewise.
+       * sysdeps/unix/sysv/linux/sparc/Makefile: New file.
+
+2006-03-02  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/aio_misc.h: Various cleanups.
+
+2006-03-01  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/x86_64/lowlevelrobustlock.S
+       (__lll_robust_lock_wait): Also set FUTEX_WAITERS bit if we got the
+       mutex.
+       (__lll_robust_timedlock_wait): Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/lowlevelrobustlock.S
+       (__lll_robust_lock_wait): Likewise.
+       (__lll_robust_timedlock_wait): Likewise.
+       * sysdeps/unix/sysv/linux/lowlevelrobustlock.c
+       (__lll_robust_lock_wait): Likewise.
+       (__lll_robust_timedlock_wait): Likewise.
+
+2006-03-01  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/sparc/lowlevellock.h (lll_robust_mutex_dead,
+       lll_robust_mutex_trylock, lll_robust_mutex_lock,
+       lll_robust_mutex_cond_lock, lll_robust_mutex_timedlock,
+       lll_robust_mutex_unlock): Define.
+       (__lll_robust_lock_wait, __lll_robust_timedlock_wait): New prototypes.
+
+2006-02-28  H.J. Lu  <hongjiu.lu@intel.com>
+
+       * sysdeps/unix/sysv/linux/ia64/clone2.S: Include <clone2.S>
+       instead of <clone.S>.
+
+2006-02-27  Jakub Jelinek  <jakub@redhat.com>
+
+       * Makefile (libpthread-routines): Add
+       pthread_mutexattr_[sg]etprotocol, pthread_mutexattr_[sg]etprioceiling
+       and pthread_mutex_[sg]etprioceiling.
+       * Versions (GLIBC_2.4): Export pthread_mutexattr_getprotocol,
+       pthread_mutexattr_setprotocol, pthread_mutexattr_getprioceiling,
+       pthread_mutexattr_setprioceiling, pthread_mutex_getprioceiling and
+       pthread_mutex_setprioceiling.
+       * sysdeps/pthread/pthread.h (PTHREAD_PRIO_NONE, PTHREAD_PRIO_INHERIT,
+       PTHREAD_PRIO_PROTECT): New enum values.
+       (pthread_mutexattr_getprotocol, pthread_mutexattr_setprotocol,
+       pthread_mutexattr_getprioceiling, pthread_mutexattr_setprioceiling,
+       pthread_mutex_getprioceiling, pthread_mutex_setprioceiling): New
+       prototypes.
+       * pthreadP.h (PTHREAD_MUTEX_PRIO_INHERIT_PRIVATE_NP,
+       PTHREAD_MUTEX_PRIO_PROTECT_PRIVATE_NP): New enum values.
+       (PTHREAD_MUTEX_PRIO_CEILING_SHIFT, PTHREAD_MUTEX_PRIO_CEILING_MASK):
+       Define.
+       (PTHREAD_MUTEXATTR_PROTOCOL_SHIFT, PTHREAD_MUTEXATTR_PROTOCOL_MASK,
+       PTHREAD_MUTEXATTR_PRIO_CEILING_SHIFT,
+       PTHREAD_MUTEXATTR_PRIO_CEILING_MASK): Define.
+       (PTHREAD_MUTEXATTR_FLAG_BITS): Or in PTHREAD_MUTEXATTR_PROTOCOL_MASK
+       and PTHREAD_MUTEXATTR_PRIO_CEILING_MASK.
+       * pthread_mutex_init.c (__pthread_mutex_init): For the time being
+       return ENOTSUP for PTHREAD_PRIO_INHERIT or PTHREAD_PRIO_PROTECT
+       protocol mutexes.
+       * pthread_mutex_getprioceiling.c: New file.
+       * pthread_mutex_setprioceiling.c: New file.
+       * pthread_mutexattr_getprioceiling.c: New file.
+       * pthread_mutexattr_setprioceiling.c: New file.
+       * pthread_mutexattr_getprotocol.c: New file.
+       * pthread_mutexattr_setprotocol.c: New file.
+
+2006-02-27  Daniel Jacobowitz  <dan@codesourcery.com>
+
+       * sysdeps/unix/sysv/linux/aio_misc.h: Include <limits.h>.
+
+2006-02-27  Roland McGrath  <roland@redhat.com>
+
+       * sysdeps/pthread/Subdirs: List nptl here too.
+       * configure (libc_add_on_canonical): New variable.
+
+       * sysdeps/unix/sysv/linux/sh/sh4/lowlevellock.h: Use #include_next.
+
+       * sysdeps/unix/sysv/linux/sleep.c: Use #include_next after #include of
+       self to get main source tree's file.
+       * sysdeps/unix/sysv/linux/alpha/clone.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/clone.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/vfork.S: Likewise.
+       * sysdeps/unix/sysv/linux/ia64/clone2.S: Likewise.
+       * sysdeps/unix/sysv/linux/powerpc/powerpc32/clone.S: Likewise.
+       * sysdeps/unix/sysv/linux/powerpc/powerpc64/clone.S: Likewise.
+       * sysdeps/unix/sysv/linux/s390/s390-32/clone.S: Likewise.
+       * sysdeps/unix/sysv/linux/s390/s390-64/clone.S: Likewise.
+       * sysdeps/unix/sysv/linux/sh/clone.S: Likewise.
+       * sysdeps/unix/sysv/linux/sparc/sparc32/clone.S: Likewise.
+       * sysdeps/unix/sysv/linux/sparc/sparc64/clone.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/clone.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/vfork.S: Likewise.
+
+       * Makefile: Use $(sysdirs) in vpath directive.
+
+       * sysdeps/pthread/Makefile (CFLAGS-libc-start.c): Variable removed.
+       (CPPFLAGS-timer_routines.c): Likewise.
+
+       * Makeconfig (includes): Variable removed.
+
+2006-02-26  Roland McGrath  <roland@redhat.com>
+
+       * sysdeps/generic/pt-raise.c: Moved to ...
+       * pt-raise.c: ... here.
+       * sysdeps/generic/lowlevellock.h: Moved to ...
+       * lowlevellock.h: ... here.
+
+2006-02-23  Roland McGrath  <roland@redhat.com>
+
+       * descr.h (struct pthread): Add final member `end_padding'.
+       (PTHREAD_STRUCT_END_PADDING): Use it.
+
+2006-02-20  Roland McGrath  <roland@redhat.com>
+
+       * sysdeps/mips: Directory removed, saved in ports repository.
+       * sysdeps/unix/sysv/linux/mips: Likewise.
+
+2006-02-18  Ulrich Drepper  <drepper@redhat.com>
+
+       * tst-robust1.c: Add second mutex to check that the mutex list is
+       handled correctly.
+
+2006-02-17  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/alpha/lowlevellock.h (lll_robust_mutex_dead,
+       lll_robust_mutex_trylock, lll_robust_mutex_lock,
+       lll_robust_mutex_cond_lock, lll_robust_mutex_timedlock,
+       lll_robust_mutex_unlock): New macros.
+       (__lll_robust_lock_wait, __lll_robust_timedlock_wait): New prototypes.
+       * sysdeps/unix/sysv/linux/s390/lowlevellock.h: Likewise.
+       * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h: Likewise.
+       * sysdeps/unix/sysv/linux/ia64/lowlevellock.h: Likewise.
+       * sysdeps/unix/sysv/linux/lowlevelrobustlock.c: New file.
+
+2006-02-17  Kaz Kojima  <kkojima@rr.iij4u.or.jp>
+
+       * sysdeps/unix/sysv/linux/sh/lowlevellock.h: Add lll_robust_mutex_*
+       definitions.
+       * sysdeps/unix/sysv/linux/sh/lowlevelrobustlock.S: New file.
+
+2006-02-17  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h
+       (lll_robust_mutex_unlock): Avoid unnecessary wakeups.
+       * sysdeps/unix/sysv/linux/i386/lowlevellock.h
+       (lll_robust_mutex_unlock): Likewise.
+
+2006-02-13  Jakub Jelinek  <jakub@redhat.com>
+
+       * descr.h [!__PTHREAD_MUTEX_HAVE_PREV] (DEQUEUE_MUTEX):
+       Set robust_list.__next rather than robust_list.
+       * sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h
+       (__pthread_list_t): New typedef.
+       (pthread_mutex_t): Replace __next and __prev fields with __list.
+       * sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h
+       (__pthread_list_t): New typedef.
+       (pthread_mutex_t): Replace __next and __prev fields with __list.
+       * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h
+       (__pthread_list_t, __pthread_slist_t): New typedefs.
+       (pthread_mutex_t): Replace __next and __prev fields with __list.
+       * sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h
+       (__pthread_list_t, __pthread_slist_t): New typedefs.
+       (pthread_mutex_t): Replace __next and __prev fields with __list.
+       * sysdeps/unix/sysv/linux/sparc/bits/pthreadtypes.h
+       (__pthread_list_t, __pthread_slist_t): New typedefs.
+       (pthread_mutex_t): Replace __next and __prev fields with __list.
+       * sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h
+       (__pthread_slist_t): New typedef.
+       (pthread_mutex_t): Replace __next field with __list.
+
+2006-02-15  Ulrich Drepper  <drepper@redhat.com>
+
+       * pthreadP.h: Define PTHREAD_MUTEX_INCONSISTENT instead of
+       PTHREAD_MUTEX_OWNERDEAD.
+       (PTHREAD_MUTEX_ROBUST_PRIVATE_NP): Define as 16, not 256.
+       Define FUTEX_WAITERS, FUTEX_OWNER_DIED, FUTEX_TID_MASK.
+       * Makefile (libpthread-routines): Add lowlevelrobustlock.
+       * pthread_create.c (start_thread): Very much simplify robust_list loop.
+       * pthread_mutex_consistent.c: Inconsistent mutex have __owner now set
+       to PTHREAD_MUTEX_INCONSISTENT.
+       * pthread_mutex_destroy.c: Allow destroying of inconsistent mutexes.
+       * pthread_mutex_lock.c: Reimplement robust mutex handling.
+       * pthread_mutex_trylock.c: Likewise.
+       * pthread_mutex_timedlock.c: Likewise.
+       * pthread_mutex_unlock.c: Likewise.
+       * sysdeps/unix/sysv/linux/pthread_mutex_cond_lock.c: Likewise.
+       * sysdeps/unix/sysv/linux/Makefile (gen-as-const-headers): Add
+       lowlevelrobustlock.sym.
+       * sysdeps/unix/sysv/linux/lowlevelrobustlock.sym: New file.
+       * sysdeps/unix/sysv/linux/i386/lowlevellock.h: Add lll_robust_mutex_*
+       definitions.
+       * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/lowlevelrobustlock.S: New file.
+       * sysdeps/unix/sysv/linux/i386/i586/lowlevelrobustlock.S: New file.
+       * sysdeps/unix/sysv/linux/i386/i686/lowlevelrobustlock.S: New file.
+       * sysdeps/unix/sysv/linux/x86_64/lowlevelrobustlock.S: New file.
+
+2006-02-12  Ulrich Drepper  <drepper@redhat.com>
+
+       * allocatestack.c (allocate_stack): Initialize robust_list.
+       * init.c (__pthread_initialize_minimal_internal): Likewise.
+       * descr.h (struct xid_command): Pretty printing.
+       (struct pthread): Use __pthread_list_t or __pthread_slist_t for
+       robust_list.  Adjust macros.
+       * pthread_create.c (start_thread): Adjust robust_list handling.
+       * phtread_mutex_unlock.c: Don't allow unlocking from any thread
+       but the owner for all robust mutex types.
+       * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h: Define
+       __pthread_list_t and __pthread_slist_t.  Use them in pthread_mutex_t.
+       * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: Likewise.
+       * sysdeps/pthread/pthread.h: Adjust mutex initializers.
+
+       * sysdeps/unix/sysv/linux/i386/not-cancel.h: Define openat_not_cancel,
+       openat_not_cancel_3, openat64_not_cancel, and openat64_not_cancel_3.
+
+2006-02-08  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/lowlevellock.h (lll_futex_wait,
+       lll_futex_timedwait, lll_wait_tid): Add "memory" clobber.
+
+2006-01-20  Kaz Kojima  <kkojima@rr.iij4u.or.jp>
+
+       * sysdeps/unix/sysv/linux/sh/lowlevellock.h (lll_futex_wait):
+       Return status.
+       (lll_futex_timed_wait): Define.
+
+2006-01-19  Ulrich Drepper  <drepper@redhat.com>
+
+       * tst-cancel4.c: Test ppoll.
+
+2006-01-18  Andreas Jaeger  <aj@suse.de>
+
+       [BZ #2167]
+       * sysdeps/unix/sysv/linux/mips/bits/pthreadtypes.h
+       (pthread_mutex_t): Follow changes for other archs.  Based on patch
+       by Jim Gifford <patches@jg555.com>.
+
+2006-01-13  Richard Henderson  <rth@redhat.com>
+
+       * sysdeps/alpha/tls.h (tcbhead_t): Rename member to __private.
+
+2006-01-10  Roland McGrath  <roland@redhat.com>
+
+       * sysdeps/alpha/jmpbuf-unwind.h: File moved to main source tree.
+       * sysdeps/i386/jmpbuf-unwind.h: Likewise.
+       * sysdeps/mips/jmpbuf-unwind.h: Likewise.
+       * sysdeps/powerpc/jmpbuf-unwind.h: Likewise.
+       * sysdeps/s390/jmpbuf-unwind.h: Likewise.
+       * sysdeps/sh/jmpbuf-unwind.h: Likewise.
+       * sysdeps/sparc/sparc32/jmpbuf-unwind.h: Likewise.
+       * sysdeps/sparc/sparc64/jmpbuf-unwind.h: Likewise.
+       * sysdeps/x86_64/jmpbuf-unwind.h: Likewise.
+       * sysdeps/unix/sysv/linux/ia64/jmpbuf-unwind.h: Likewise.
+
+2006-01-09  Roland McGrath  <roland@redhat.com>
+
+       * tst-initializers1-c89.c: New file.
+       * tst-initializers1-c99.c: New file.
+       * tst-initializers1-gnu89.c: New file.
+       * tst-initializers1-gnu99.c: New file.
+       * Makefile (tests): Add them.
+       (CFLAGS-tst-initializers1-c89.c): New variable.
+       (CFLAGS-tst-initializers1-c99.c): New variable.
+       (CFLAGS-tst-initializers1-gnu89.c): New variable.
+       (CFLAGS-tst-initializers1-gnu99.c): New variable.
+
+       * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h (pthread_mutex_t):
+       Use __extension__ on anonymous union definition.
+       * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/sparc/bits/pthreadtypes.h: Likewise.
+
+2006-01-08  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h (pthread_mutex_t):
+       Don't give the union a name because it changes the mangled name.
+       Instead name the struct for __data.
+       * sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h (pthread_mutex_t):
+       Likewise.
+       * sysdeps/unix/sysv/linux/sparc/bits/pthreadtypes.h (pthread_mutex_t):
+       Likewise.
+
+2006-01-09  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/sparc/sparc64/jmpbuf-unwind.h (_JMPBUF_UNWINDS_ADJ): Add
+       stack bias to mc_ftp field.
+
+2006-01-07  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/aio_misc.h (AIO_MISC_WAIT): Work around gcc
+       being too clever and reloading the futex value where it shouldn't.
+
+2006-01-06  Ulrich Drepper  <drepper@redhat.com>
+
+       * descr.h [!__PTHREAD_MUTEX_HAVE_PREV] (DEQUEUE_MUTEX): Use
+       correct type.
+
+2006-01-06  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/sparc/sparc64/sysdep-cancel.h (PSEUDO):
+       Add cfi directives.
+
+2006-01-06  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/ia64/tls.h (tcbhead_t): Rename private member to __private.
+       * sysdeps/ia64/tcb-offsets.sym: Adjust for private->__private
+       rename in tcbhead_t.
+
+       * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h (pthread_mutex_t):
+       Don't give the union a name because it changes the mangled name.
+       Instead name the struct for __data.
+       * sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: Likewise.
+       * pthread_create.c (start_thread): Adjust robust mutex free loop.
+       * descr.h (ENQUEUE_MUTEX, DEQUEUE_MUTEX): Adjust.
+
+2006-01-05  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/lowlevellock.h (lll_futex_wait):
+       Return status.
+       (lll_futex_timed_wait): Define.
+       * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h: Likewise.
+       * sysdeps/pthread/aio_misc.h: New file.
+
+2006-01-03  Joseph S. Myers  <joseph@codesourcery.com>
+
+       * Makefile ($(objpfx)$(multidir)): Use mkdir -p.
+
+2006-01-03  Steven Munroe  <sjmunroe@us.ibm.com>
+
+       * sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h
+       (PSEUDO): Remove redundant cfi_startproc and cfi_endproc directives.
+       * sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h: Likewise.
+
+2006-01-04  Ulrich Drepper  <drepper@redhat.com>
+
+       * tst-cancel24.cc: Use C headers instead of C++ headers.
+
+2006-01-03  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/sparc/lowlevellock.h: Remove #error for
+       sparc-linux configured glibc.
+       (lll_futex_wake_unlock): Define to 1 for sparc-linux configured glibc.
+       (__lll_mutex_trylock, __lll_mutex_cond_trylock, __lll_mutex_lock,
+       __lll_mutex_cond_lock, __lll_mutex_timedlock): Use
+       atomic_compare_and_exchange_val_24_acq instead of
+       atomic_compare_and_exchange_val_acq.
+       (lll_mutex_unlock, lll_mutex_unlock_force): Use atomic_exchange_24_rel
+       instead of atomic_exchange_rel.
+       * sysdeps/unix/sysv/linux/sparc/sparc32/lowlevellock.c: New file.
+       * sysdeps/unix/sysv/linux/sparc/sparc32/pthread_barrier_init.c: New
+       file.
+       * sysdeps/unix/sysv/linux/sparc/sparc32/pthread_barrier_wait.c: New
+       file.
+       * sysdeps/unix/sysv/linux/sparc/sparc32/sem_init.c: New file.
+       * sysdeps/unix/sysv/linux/sparc/sparc32/sem_post.c: New file.
+       * sysdeps/unix/sysv/linux/sparc/sparc32/sem_timedwait.c: New file.
+       * sysdeps/unix/sysv/linux/sparc/sparc32/sem_trywait.c: New file.
+       * sysdeps/unix/sysv/linux/sparc/sparc32/sem_wait.c: New file.
+       * sysdeps/unix/sysv/linux/sparc/sparc32/sparcv9/pthread_barrier_init.c:
+       New file.
+       * sysdeps/unix/sysv/linux/sparc/sparc32/sparcv9/pthread_barrier_wait.c:
+       New file.
+       * sysdeps/unix/sysv/linux/sparc/sparc32/sparcv9/sem_init.c: New file.
+       * sysdeps/unix/sysv/linux/sparc/sparc32/sparcv9/sem_post.c: New file.
+       * sysdeps/unix/sysv/linux/sparc/sparc32/sparcv9/sem_timedwait.c: New
+       file.
+       * sysdeps/unix/sysv/linux/sparc/sparc32/sparcv9/sem_trywait.c: New
+       file.
+       * sysdeps/unix/sysv/linux/sparc/sparc32/sparcv9/sem_wait.c: New file.
+
+2006-01-03  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/pthread.h [__WORDSIZE==64]: Don't use cast in
+       mutex initializers.
+
+2006-01-02  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/sparc/tls.h (tcbhead_t): Add pointer_guard field.
+       (THREAD_GET_POINTER_GUARD, THREAD_SET_POINTER_GUARD,
+       THREAD_COPY_POINTER_GUARD): Define.
+       * sysdeps/sparc/tcb-offsets.sym (POINTER_GUARD): Define.
+       * sysdeps/sparc/sparc64/jmpbuf-unwind.h: Revert 2005-12-27 changes.
+
+2006-01-01  Ulrich Drepper  <drepper@redhat.com>
+
+       * version.c: Update copyright year.
+
+2005-12-29  Kaz Kojima  <kkojima@rr.iij4u.or.jp>
+
+       * sysdeps/unix/sysv/linux/sh/sysdep-cancel.h: Remove explicit
+       .eh_frame section, use cfi_* directives.
+       * sysdeps/unix/sysv/linux/sh/lowlevellock.S: Add cfi instrumentation.
+
+2005-12-30  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/ia64/jmpbuf-unwind.h: Undo last change for
+       now.
+
+2005-12-29  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/sigaction.c: Removed.
+       * sigaction.c: New file.
+       * sysdeps/unix/sysv/linux/Makefile: Define CFLAGS-sigaction.c.
+
+2005-12-28  Ulrich Drepper  <drepper@redhat.com>
+
+       * Makefile (tests): Add tst-signal7.
+       * tst-signal7.c: New file.
+
+2005-12-27  Roland McGrath  <roland@redhat.com>
+
+       * sysdeps/x86_64/jmpbuf-unwind.h (_jmpbuf_sp): New inline function.
+       (_JMPBUF_UNWINDS_ADJ): Use it, to PTR_DEMANGLE before comparison.
+       * sysdeps/alpha/jmpbuf-unwind.h: Likewise.
+       * sysdeps/i386/jmpbuf-unwind.h: Likewise.
+       * sysdeps/mips/jmpbuf-unwind.h: Likewise.
+       * sysdeps/powerpc/jmpbuf-unwind.h: Likewise.
+       * sysdeps/s390/jmpbuf-unwind.h: Likewise.
+       * sysdeps/sh/jmpbuf-unwind.h: Likewise.
+       * sysdeps/sparc/sparc32/jmpbuf-unwind.h: Likewise.
+       * sysdeps/sparc/sparc64/jmpbuf-unwind.h: Likewise.
+       * sysdeps/unix/sysv/linux/ia64/jmpbuf-unwind.h: Likewise.
+
+2005-12-27  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h: Add __next
+       and __prev field to pthread_mutex_t.
+       * sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/sparc/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h: Add __next field
+       to pthread_mutex_t.
+
+2005-12-26  Ulrich Drepper  <drepper@redhat.com>
+
+       * pthreadP.h: Define PTHREAD_MUTEX_ROBUST_PRIVATE_NP,
+       PTHREAD_MUTEX_ROBUST_PRIVATE_RECURSIVE_NP,
+       PTHREAD_MUTEX_ROBUST_PRIVATE_ERRORCHECK_NP,
+       PTHREAD_MUTEX_ROBUST_PRIVATE_ADAPTIVE_NP,
+       PTHREAD_MUTEXATTR_FLAG_ROBUST, PTHREAD_MUTEXATTR_FLAG_PSHARED,
+       and PTHREAD_MUTEXATTR_FLAG_BITS.
+       * descr.h (struct pthread): Add robust_list field and define
+       ENQUEUE_MUTEX and DEQUEUE_MUTEX macros.
+       * pthread_mutexattr_getrobust.c: New file.
+       * pthread_mutexattr_setrobust.c: New file.
+       * pthread_mutex_consistent.c: New file.
+       * sysdeps/pthread/pthread.h: Declare pthread_mutexattr_getrobust,
+       pthread_mutexattr_setrobust, and pthread_mutex_consistent.
+       Define PTHREAD_MUTEX_STALLED_NP and PTHREAD_MUTEX_ROBUST_NP.
+       Adjust pthread_mutex_t initializers.
+       * nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h: Add __next
+       field to pthread_mutex_t.
+       * nptl/sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: Add __next
+       and __prev field to pthread_mutex_t.
+       * Versions [GLIBC_2.4]: Export pthread_mutexattr_getrobust_np,
+       pthread_mutexattr_setrobust_np, and pthread_mutex_consistent_np.
+       * pthread_mutexattr_getpshared.c: Use PTHREAD_MUTEXATTR_FLAG_PSHARED
+       and PTHREAD_MUTEXATTR_FLAG_BITS macros instead of magic numbers.
+       * pthread_mutexattr_gettype.c: Likewise.
+       * pthread_mutexattr_setpshared.c: Likewise.
+       * pthread_mutexattr_settype.c: Likewise.
+       * pthread_mutex_init.c: Reject robust+pshared attribute for now.
+       Initialize mutex kind according to robust flag.
+       * pthread_mutex_lock.c: Implement local robust mutex.
+       * pthread_mutex_timedlock.c: Likewise.
+       * pthread_mutex_trylock.c: Likewise.
+       * pthread_mutex_unlock.c: Likewise.
+       * pthread_create.c (start_thread): Mark robust mutexes which remained
+       locked as dead.
+       * tst-robust1.c: New file.
+       * tst-robust2.c: New file.
+       * tst-robust3.c: New file.
+       * tst-robust4.c: New file.
+       * tst-robust5.c: New file.
+       * tst-robust6.c: New file.
+       * tst-robust7.c: New file.
+       * Makefile (libpthread-routines): Add pthread_mutexattr_getrobust,
+       pthread_mutexattr_setrobust, and pthread_mutex_consistent.
+       (tests): Add tst-robust1, tst-robust2, tst-robust3, tst-robust4,
+       tst-robust5, tst-robust6, and tst-robust7.
+
+       * tst-typesizes.c: New file.
+       * Makefile (tests): Add tst-typesizes.
+
+       * tst-once3.c: More debug output.
+
+2005-12-24  Ulrich Drepper  <drepper@redhat.com>
+
+       * pthread_mutex_trylock.c (__pthread_mutex_trylock): Add break
+       missing after last change.
+
+       * version.c: Update copyright year.
+
+2005-12-23  Ulrich Drepper  <drepper@redhat.com>
+
+       * pthread_mutex_destroy.c: Set mutex type to an invalid value.
+       * pthread_mutex_lock.c: Return EINVAL for invalid mutex type.
+       * pthread_mutex_trylock.c: Likewise.
+       * pthread_mutex_timedlock.c: Likewise.
+       * pthread_mutex_unlock.c: Likewise.
+
+2005-12-22  Roland McGrath  <roland@redhat.com>
+
+       * sysdeps/pthread/sigaction.c: Use "" instead of <> to include self,
+       so that #include_next's search location is not reset to the -I..
+       directory where <nptl/...> can be found.
+
+2005-12-22  Ulrich Drepper  <drepper@redhat.com>
+
+       [BZ #1913]
+       * sysdeps/unix/sysv/linux/i386/i486/sem_wait.S (__new_sem_wait):
+       Fix unwind info.  Remove useless branch prediction prefix.
+       * tst-cancel24.cc: New file.
+       * Makefile: Add rules to build and run tst-cancel24.
+
+2005-12-21  Roland McGrath  <roland@redhat.com>
+
+       * libc-cancellation.c: Use <> rather than "" #includes.
+       * pt-cleanup.c: Likewise.
+       * pthread_create.c: Likewise.
+       * pthread_join.c: Likewise.
+       * pthread_timedjoin.c: Likewise.
+       * pthread_tryjoin.c: Likewise.
+       * sysdeps/unix/sysv/linux/libc_pthread_init.c: Likewise.
+       * sysdeps/unix/sysv/linux/register-atfork.c: Likewise.
+       * sysdeps/unix/sysv/linux/unregister-atfork.c: Likewise.
+       * unwind.c: Likewise.
+
+2005-12-19  Kaz Kojima  <kkojima@rr.iij4u.or.jp>
+
+       * sysdeps/sh/tcb-offsets.sym: Add POINTER_GUARD.
+       * sysdeps/sh/tls.h (tcbhead_t): Remove private and add pointer_guard.
+       (THREAD_GET_POINTER_GUARD, THREAD_SET_POINTER_GUARD,
+       THREAD_COPY_POINTER_GUARD): Define.
+
+2005-12-19  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/ia64/tls.h (TLS_PRE_TCB_SIZE): Make room for 2 uintptr_t's
+       rather than one.
+       (THREAD_GET_POINTER_GUARD, THREAD_SET_POINTER_GUARD,
+       THREAD_COPY_POINTER_GUARD): Define.
+       * sysdeps/powerpc/tcb-offsets.sym (POINTER_GUARD): Add.
+       * sysdeps/powerpc/tls.h (tcbhead_t): Add pointer_guard field.
+       (THREAD_GET_POINTER_GUARD, THREAD_SET_POINTER_GUARD,
+       THREAD_COPY_POINTER_GUARD): Define.
+       * sysdeps/s390/tcb-offsets.sym (STACK_GUARD): Add.
+       * sysdeps/s390/tls.h (THREAD_GET_POINTER_GUARD,
+       THREAD_SET_POINTER_GUARD, THREAD_COPY_POINTER_GUARD): Define.
+       * sysdeps/unix/sysv/linux/ia64/__ia64_longjmp.S (__ia64_longjmp):
+       Use PTR_DEMANGLE for B0 if defined.
+
+2005-12-17  Ulrich Drepper  <drepper@redhat.com>
+
+       * pthread_create.c (__pthread_create_2_1): Use
+       THREAD_COPY_POINTER_GUARD if available.
+       * sysdeps/i386/tcb-offsets.sym: Add POINTER_GUARD.
+       * sysdeps/x86_64/tcb-offsets.sym: Likewise.
+       * sysdeps/i386/tls.h (tcbhead_t): Add pointer_guard.
+       Define THREAD_SET_POINTER_GUARD and THREAD_COPY_POINTER_GUARD.
+       * sysdeps/x86_64/tls.h: Likewise.
+
+2005-12-15  Roland McGrath  <roland@redhat.com>
+
+       * sysdeps/unix/sysv/linux/mq_notify.c: Don't use sysdeps/generic.
+
+2005-12-13  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/sigfillset.c: Adjust for files moved out of
+       sysdeps/generic.
+       * errno-loc.c: New file.
+
+2005-12-12  Roland McGrath  <roland@redhat.com>
+
+       * init.c (__pthread_initialize_minimal_internal): Do __static_tls_size
+       adjustments before choosing stack size.  Update minimum stack size
+       calculation to match allocate_stack change.
+
+2005-12-12  Ulrich Drepper  <drepper@redhat.com>
+
+       * allocatestack.c (allocate_stack): Don't demand that there is an
+       additional full page available on the stack beside guard, TLS, the
+       minimum stack.
+
+2005-11-24  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h
+       (__cleanup_fct_attribute): Use __regparm__ not regparm.
+
+       * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: When
+       compiling 32-bit code we must define __cleanup_fct_attribute.
+
+005-11-24  Jakub Jelinek  <jakub@redhat.com>
+
+       [BZ #1920]
+       * sysdeps/pthread/pthread.h (__pthread_unwind_next): Use
+       __attribute__ instead of __attribute.
+       * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h
+       (__cleanup_fct_attribute): Likewise.
+
+2005-11-17  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/pthread/unwind-forcedunwind.c (pthread_cancel_init): Put
+       a write barrier before writing libgcc_s_getcfa.
+
+2005-11-06  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/configure: Removed.
+
+2005-11-05  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/ia64/pt-initfini.c: Remove trace of
+       optional init_array/fini_array support.
+
+2005-10-24  Roland McGrath  <roland@redhat.com>
+
+       * sysdeps/unix/sysv/linux/x86_64/sem_trywait.S: Remove unnecessary
+       versioned_symbol use.
+
+2005-10-16  Roland McGrath  <roland@redhat.com>
+
+       * init.c (__pthread_initialize_minimal_internal): Even when using a
+       compile-time default stack size, apply the minimum that allocate_stack
+       will require, and round up to page size.
+
+2005-10-10  Daniel Jacobowitz  <dan@codesourcery.com>
+
+       * Makefile ($(test-modules)): Remove static pattern rule.
+
+2005-10-14  Jakub Jelinek  <jakub@redhat.com>
+           Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/x86_64/pthread_once.S: Fix stack
+       alignment in callback function.
+       * Makefile: Add rules to build and run tst-align3.
+       * tst-align3.c: New file.
+
+2005-10-03  Jakub Jelinek  <jakub@redhat.com>
+
+       * allocatestack.c (setxid_signal_thread): Add
+       INTERNAL_SYSCALL_DECL (err).
+
+2005-10-02  Jakub Jelinek  <jakub@redhat.com>
+
+       * allocatestack.c (setxid_signal_thread): Need to use
+       atomic_compare_and_exchange_bool_acq.
+
+2005-10-01  Ulrich Drepper  <drepper@redhat.com>
+           Jakub Jelinek  <jakub@redhat.com>
+
+       * descr.h: Define SETXID_BIT and SETXID_BITMASK.  Adjust
+       CANCEL_RESTMASK.
+       (struct pthread): Move specific_used field to avoid padding.
+       Add setxid_futex field.
+       * init.c (sighandler_setxid): Reset setxid flag and release the
+       setxid futex.
+       * allocatestack.c (setxid_signal_thread): New function.  Broken
+       out of the bodies of the two loops in __nptl_setxid.  For undetached
+       threads check whether they are exiting and if yes, don't send a signal.
+       (__nptl_setxid): Simplify loops by using setxid_signal_thread.
+       * pthread_create.c (start_thread): For undetached threads, check
+       whether setxid bit is set.  If yes, wait until signal has been
+       processed.
+
+       * allocatestack.c (STACK_VARIABLES): Initialize them.
+       * pthread_create.c (__pthread_create_2_1): Initialize pd.
+
+2004-09-02  Jakub Jelinek  <jakub@redhat.com>
+
+       * pthread_cond_destroy.c (__pthread_cond_destroy): If there are
+       waiters, awake all waiters on the associated mutex.
+
+2005-09-22  Roland McGrath  <roland@redhat.com>
+
+       * perf.c [__x86_64__] (HP_TIMING_NOW): New macro (copied from
+       ../sysdeps/x86_64/hp-timing.h).
+
+2005-08-29  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h (FUTEX_WAKE_OP,
+       FUTEX_OP_CLEAR_WAKE_IF_GT_ONE): Define.
+       (lll_futex_wake_unlock): Define.
+       * sysdeps/unix/sysv/linux/alpha/lowlevellock.h (FUTEX_WAKE_OP,
+       FUTEX_OP_CLEAR_WAKE_IF_GT_ONE): Define.
+       (lll_futex_wake_unlock): Define.
+       * sysdeps/unix/sysv/linux/ia64/lowlevellock.h (FUTEX_WAKE_OP,
+       FUTEX_OP_CLEAR_WAKE_IF_GT_ONE): Define.
+       (lll_futex_wake_unlock): Define.
+       * sysdeps/unix/sysv/linux/s390/lowlevellock.h (FUTEX_WAKE_OP,
+       FUTEX_OP_CLEAR_WAKE_IF_GT_ONE): Define.
+       (lll_futex_wake_unlock): Define.
+       * sysdeps/unix/sysv/linux/sparc/lowlevellock.h (FUTEX_WAKE_OP,
+       FUTEX_OP_CLEAR_WAKE_IF_GT_ONE): Define.
+       (lll_futex_wake_unlock): Define.
+       * sysdeps/pthread/pthread_cond_signal.c (__pthread_cond_signal): Use
+       lll_futex_wake_unlock.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_signal.S
+       (FUTEX_WAKE_OP, FUTEX_OP_CLEAR_WAKE_IF_GT_ONE): Define.
+       (__pthread_cond_signal): Use FUTEX_WAKE_OP.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_signal.S
+       (FUTEX_WAKE_OP, FUTEX_OP_CLEAR_WAKE_IF_GT_ONE): Define.
+       (__pthread_cond_signal): Use FUTEX_WAKE_OP.
+
+2005-09-05  Kaz Kojima  <kkojima@rr.iij4u.or.jp>
+
+       * sysdeps/unix/sysv/linux/sh/lowlevellock.S (__lll_mutex_lock_wait):
+       Fix typo in register name.
+
+2005-08-23  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/timer_routines.c (timer_helper_thread):
+       Use __sigfillset.  Document that sigfillset does the right thing wrt
+       to SIGSETXID.
+
+2005-07-11  Jakub Jelinek  <jakub@redhat.com>
+
+       [BZ #1102]
+       * sysdeps/pthread/pthread.h (PTHREAD_MUTEX_INITIALIZER,
+       PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP,
+       PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP,
+       PTHREAD_MUTEX_ADAPTIVE_NP, PTHREAD_RWLOCK_INITIALIZER,
+       PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
+       PTHREAD_COND_INITIALIZER): Supply zeros for all fields
+       in the structure.
+       * Makefile (tests): Add tst-initializers1.
+       (CFLAGS-tst-initializers1.c): Set.
+       * tst-initializers1.c: New test.
+
+2005-07-11  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h (pthread_rwlock_t):
+       Make sure __flags are located at offset 48 from the start of the
+       structure.
+
+2005-07-02  Roland McGrath  <roland@redhat.com>
+
+       * Makeconfig: Comment fix.
+
+2005-07-05  Jakub Jelinek  <jakub@redhat.com>
+
+       * descr.h (PTHREAD_STRUCT_END_PADDING): Define.
+       * sysdeps/ia64/tls.h (TLS_PRE_TCB_SIZE): If PTHREAD_STRUCT_END_PADDING
+       is smaller than 8 bytes, increase TLS_PRE_TCB_SIZE by 16 bytes.
+       (THREAD_SYSINFO, THREAD_SELF, DB_THREAD_SELF): Don't assume
+       TLS_PRE_TCB_SIZE is sizeof (struct pthread).
+       (THREAD_SET_STACK_GUARD, THREAD_COPY_STACK_GUARD): Define.
+       * sysdeps/ia64/tcb-offsets.sym (PID, TID, MULTIPLE_THREADS_OFFSET):
+       Use TLS_PRE_TCB_SIZE instead of sizeof (struct pthread).
+       * sysdeps/unix/sysv/linux/ia64/createthread.c (TLS_VALUE): Don't
+       assume TLS_PRE_TCB_SIZE is sizeof (struct pthread).
+
+2005-06-25  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/i386/tls.h (tcbhead_t): Add stack_guard field.
+       (THREAD_SET_STACK_GUARD, THREAD_COPY_STACK_GUARD): Define.
+       * sysdeps/x86_64/tls.h (tcbhead_t): Add sysinfo and stack_guard
+       fields.
+       (THREAD_SET_STACK_GUARD, THREAD_COPY_STACK_GUARD): Define.
+       * sysdeps/s390/tls.h (tcbhead_t): Add stack_guard
+       field.  Put in sysinfo field unconditionally.
+       (THREAD_SET_STACK_GUARD, THREAD_COPY_STACK_GUARD): Define.
+       * sysdeps/powerpc/tls.h (tcbhead_t): Add stack_guard field.
+       (THREAD_SET_STACK_GUARD, THREAD_COPY_STACK_GUARD): Define.
+       * sysdeps/sparc/tls.h (tcbhead_t): Add sysinfo and stack_guard
+       fields.
+       (THREAD_SET_STACK_GUARD, THREAD_COPY_STACK_GUARD): Define.
+       * pthread_create.c (__pthread_create_2_1): Use
+       THREAD_COPY_STACK_GUARD macro.
+       * Makefile: Add rules to build and run tst-stackguard1{,-static}
+       tests.
+       * tst-stackguard1.c: New file.
+       * tst-stackguard1-static.c: New file.
+
+2005-06-14  Alan Modra  <amodra@bigpond.net.au>
+
+       * sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h (PSEUDO):
+       Invoke CGOTSETUP and CGOTRESTORE.
+       (CGOTSETUP, CGOTRESTORE): Define.
+
+2005-05-29  Richard Henderson  <rth@redhat.com>
+
+       * tst-cancel4.c (WRITE_BUFFER_SIZE): New.
+       (tf_write, tf_writev): Use it.
+       (do_test): Use socketpair instead of pipe.  Set SO_SNDBUF to
+       the system minimum.
+
+2005-05-23  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h
+       [IS_IN_librt] (CENABLE, CDISABLE): Use JUMPTARGET instead of
+       __librt_*_asynccancel@local.
+
+2005-05-17  Alan Modra  <amodra@bigpond.net.au>
+
+       * sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h: Delete
+       all occurrences of JUMPTARGET.  Instead append @local to labels.
+
+2005-05-20  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/i386/tls.h (TLS_INIT_TCB_SIZE, TLS_INIT_TCB_ALIGN): Define to
+       size/alignment of struct pthread rather than tcbhead_t.
+       * sysdeps/x86_64/tls.h (TLS_INIT_TCB_SIZE, TLS_INIT_TCB_ALIGN):
+       Likewise.
+       * sysdeps/s390/tls.h (TLS_INIT_TCB_SIZE, TLS_INIT_TCB_ALIGN):
+       Likewise.
+       * sysdeps/sparc/tls.h (TLS_INIT_TCB_SIZE, TLS_INIT_TCB_ALIGN):
+       Likewise.
+
+2005-05-19  Richard Henderson  <rth@redhat.com>
+
+       * sysdeps/ia64/pthread_spin_lock.c (pthread_spin_lock): Use
+       __sync_val_compare_and_swap, not explicit _si variant.
+       * sysdeps/ia64/pthread_spin_trylock.c (pthread_spin_trylock): Likewise.
+
+2005-05-03  Ulrich Drepper  <drepper@redhat.com>
+
+       [BZ #915]
+       * sysdeps/pthread/pthread.h: Avoid empty initializers.
+
+2005-05-03  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h: Remove explicit
+       .eh_frame section, use cfi_* directives.
+
+2005-04-27  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/pthread_getcpuclockid.c: Use <> instead
+       of "" includes.
+
+2005-04-27  Ulrich Drepper  <drepper@redhat.com>
+
+       [BZ #1075]
+       * tst-cancel17.c (do_test): Add arbitrary factor to make sure
+       aio_write blocks.
+
+2005-04-27  Roland McGrath  <roland@redhat.com>
+
+       * Makefile (tests): Remove tst-clock2.
+
+       * sysdeps/unix/sysv/linux/timer_create.c (timer_create): Handle
+       CLOCK_PROCESS_CPUTIME_ID and CLOCK_PROCESS_THREAD_ID specially,
+       translating to the kernel clockid_t for our own process/thread clock.
+
+       * sysdeps/unix/sysv/linux/pthread_getcpuclockid.c: New file.
+
+2005-04-15  Jakub Jelinek  <jakub@redhat.com>
+
+       * old_pthread_cond_init.c: Include <errno.h>.
+       (__pthread_cond_init_2_0): Fail with EINVAL if COND_ATTR is
+       process shared or uses clock other than CLOCK_REALTIME.
+       * pthread_cond_init.c (__pthread_cond_init): Remove bogus comment.
+
+2005-04-13  David S. Miller  <davem@davemloft.net>
+
+       * sysdeps/sparc/sparc64/jmpbuf-unwind.h: New file.
+       * sysdeps/sparc/sparc64/clone.S: New file.
+
+2005-04-05  Jakub Jelinek  <jakub@redhat.com>
+
+       [BZ #1102]
+       * sysdeps/pthread/pthread.h (__pthread_cleanup_routine): Use
+       __inline instead of inline.
+       * sysdeps/pthread/bits/libc-lock.h (__libc_cleanup_routine): Likewise.
+
+2005-03-31  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_unlock.S: Use
+       functionally equivalent, but shorter instructions.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedrdlock.S:
+       Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_barrier_wait.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_rdlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/sem_wait.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_wrlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_once.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedwrlock.S:
+       Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_signal.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/lowlevellock.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/sem_post.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S: Likewise.
+
+2005-03-28  Daniel Jacobowitz  <dan@codesourcery.com>
+
+       * sysdeps/mips/Makefile: New file.
+       * sysdeps/mips/nptl-sysdep.S: New file.
+       * sysdeps/mips/tcb-offsets.sym: New file.
+       * sysdeps/mips/pthread_spin_lock.S: New file.
+       * sysdeps/mips/pthread_spin_trylock.S: New file.
+       * sysdeps/mips/pthreaddef.h: New file.
+       * sysdeps/mips/tls.h: New file.
+       * sysdeps/mips/jmpbuf-unwind.h: New file.
+       * sysdeps/unix/sysv/linux/mips/lowlevellock.h: New file.
+       * sysdeps/unix/sysv/linux/mips/bits/pthreadtypes.h: New file.
+       * sysdeps/unix/sysv/linux/mips/bits/semaphore.h: New file.
+       * sysdeps/unix/sysv/linux/mips/pthread_once.c: New file.
+       * sysdeps/unix/sysv/linux/mips/fork.c: New file.
+       * sysdeps/unix/sysv/linux/mips/pt-vfork.S: New file.
+       * sysdeps/unix/sysv/linux/mips/vfork.S: New file.
+       * sysdeps/unix/sysv/linux/mips/clone.S: New file.
+       * sysdeps/unix/sysv/linux/mips/createthread.c: New file.
+       * sysdeps/unix/sysv/linux/mips/sysdep-cancel.h: New file.
+
+2005-03-23  Ulrich Drepper  <drepper@redhat.com>
+
+       [BZ #1112]
+       * pthread_create.c (__pthread_create_2_1): Rename syscall error
+       variable to scerr.
+
+2005-03-10  Jakub Jelinek  <jakub@redhat.com>
+
+       * tst-getpid1.c (do_test): Align stack passed to clone{2,}.
+
+2005-02-25  Roland McGrath  <roland@redhat.com>
+
+       * alloca_cutoff.c: Correct license text.
+       * tst-unload.c: Likewise.
+       * sysdeps/pthread/allocalim.h: Likewise.
+       * sysdeps/pthread/pt-initfini.c: Likewise.
+       * sysdeps/pthread/bits/libc-lock.h: Likewise.
+       * sysdeps/pthread/bits/sigthread.h: Likewise.
+       * sysdeps/unix/sysv/linux/bits/local_lim.h: Likewise.
+       * sysdeps/unix/sysv/linux/bits/posix_opt.h: Likewise.
+
+2005-02-16  Roland McGrath  <roland@redhat.com>
+
+       * sysdeps/pthread/pthread-functions.h (struct pthread_functions):
+       Use unsigned int * for ptr_nthreads.
+
+2005-02-14  Alan Modra  <amodra@bigpond.net.au>
+
+       [BZ #721]
+       * sysdeps/powerpc/tcb-offsets.sym (thread_offsetof): Redefine to suit
+       gcc4.
+
+2005-02-07  Richard Henderson  <rth@redhat.com>
+
+       [BZ #787]
+       * sysdeps/pthread/pthread.h (__sigsetjmp): Use pointer as first
+       argument.
+
+2004-11-03  Marcus Brinkmann  <marcus@gnu.org>
+
+       * sysdeps/generic/lowlevellock.h (__generic_mutex_unlock): Fix
+       order of arguments in invocation of atomic_add_zero.
+
+2005-01-26  Jakub Jelinek  <jakub@redhat.com>
+
+       [BZ #737]
+       * sysdeps/unix/sysv/linux/i386/i486/sem_trywait.S (__new_sem_trywait):
+       Use direct %gs segment access or, if NO_TLS_DIRECT_SEG_REFS,
+       at least gotntpoff relocation and addition.
+       * sysdeps/unix/sysv/linux/i386/i486/sem_timedwait.S (sem_timedwait):
+       Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/sem_post.S (__new_sem_post):
+       Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/sem_wait.S (__new_sem_wait):
+       Likewise.
+
+2005-01-06  Ulrich Drepper  <drepper@redhat.com>
+
+       * allocatestack.c (init_one_static_tls): Adjust initialization of DTV
+       entry for static tls deallocation fix.
+       * sysdeps/alpha/tls.h (dtv_t): Change pointer type to be struct which
+       also contains information whether the memory pointed to is static
+       TLS or not.
+       * sysdeps/i386/tls.h: Likewise.
+       * sysdeps/ia64/tls.h: Likewise.
+       * sysdeps/powerpc/tls.h: Likewise.
+       * sysdeps/s390/tls.h: Likewise.
+       * sysdeps/sh/tls.h: Likewise.
+       * sysdeps/sparc/tls.h: Likewise.
+       * sysdeps/x86_64/tls.h: Likewise.
+
+2004-12-27  Ulrich Drepper  <drepper@redhat.com>
+
+       * init.c (__pthread_initialize_minimal_internal): Use __sigemptyset.
+
+2004-12-21  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/i386/tls.h (CALL_THREAD_FCT): Maintain 16 byte alignment of
+       %esp.
+       * Makefile (tests): Add tst-align2.
+       * tst-align2.c: New test.
+       * sysdeps/i386/Makefile (CFLAGS-tst-align{,2}.c): Add
+       -mpreferred-stack-boundary=4.
+
+2004-12-18  Roland McGrath  <roland@redhat.com>
+
+       * sysdeps/unix/sysv/linux/powerpc/powerpc64/bits/local_lim.h:
+       New file removed withdrawn for the moment.
+
+2004-12-17  Richard Henderson  <rth@redhat.com>
+
+       * sysdeps/unix/sysv/linux/alpha/clone.S: New file.
+       * sysdeps/alpha/tcb-offsets.sym (TID_OFFSET): New.
+
+2004-12-16  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/powerpc/powerpc64/bits/local_lim.h: New file.
+       Increased PTHREAD_STACK_MIN.
+
+       * tst-context1.c (stacks): Use bigger stack size.
+
+2004-12-16  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/sparc/sparc32/clone.S: New file.
+       * sysdeps/sparc/tcb-offsets.sym: Add TID.
+
+2004-12-15  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/s390/s390-32/clone.S: New file.
+       * sysdeps/unix/sysv/linux/s390/s390-64/clone.S: New file.
+       * sysdeps/s390/tcb-offsets.sym (TID): Add.
+
+2004-12-15  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/powerpc/powerpc32/clone.S: New file.
+
+2004-12-14  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/powerpc/tcb-offsets.sym: Add TID.
+       * sysdeps/unix/sysv/linux/powerpc/powerpc64/clone.S: New file.
+
+       * tst-getpid1.c: If child crashes, report this first.  Print which
+       signal.
+
+2004-12-09  Ulrich Drepper  <drepper@redhat.com>
+
+       * init.c (__pthread_initialize_minimal_internal): Also unblock
+       SIGSETXID.
+
+2004-12-01  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/bits/posix_opt.h (_POSIX_CPUTIME,
+       _POSIX_THREAD_CPUTIME): Define to 0.
+       * sysdeps/pthread/timer_create.c (timer_create): Remove unused code
+       handling CLOCK_PROCESS_CPUTIME_ID and CLOCK_THREAD_CPUTIME_ID.
+       * sysdeps/pthread/timer_routines.c (__timer_signal_thread_pclk,
+       __timer_signal_thread_tclk): Remove.
+       (init_module): Remove their initialization.
+       (thread_cleanup): Remove their cleanup assertions.
+       * sysdeps/pthread/posix-timer.h (__timer_signal_thread_pclk,
+       __timer_signal_thread_tclk): Remove.
+       * sysdeps/unix/sysv/linux/i386/bits/posix_opt.h: Removed.
+       * sysdeps/unix/sysv/linux/ia64/bits/posix_opt.h: Removed.
+       * sysdeps/unix/sysv/linux/x86_64/bits/posix_opt.h: Removed.
+
+2004-12-07  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/ia64/tcb-offsets.sym (TID): Add.
+       * sysdeps/unix/sysv/linux/ia64/clone2.S: New file.
+
+       * Makefile (tests): Add tst-getpid2.
+       * tst-getpid1.c (TEST_CLONE_FLAGS): Define.
+       (do_test): Use it.  Use __clone2 instead of clone on ia64.
+       * tst-getpid2.c: New test.
+
+2004-12-07  Kaz Kojima  <kkojima@rr.iij4u.or.jp>
+
+       * sysdeps/unix/sysv/linux/sh/clone.S: New file.
+
+2004-12-04  Ulrich Drepper  <drepper@redhat.com>
+
+       * Makefile (tests): Add tst-getpid1.
+       * tst-getpid1.c: New file.
+       * sysdeps/unix/sysv/linux/i386/clone.S: New file.
+       * sysdeps/unix/sysv/linux/x86_64/clone.S: New file.
+
+2004-12-02  Roland McGrath  <roland@redhat.com>
+
+       * Makefile (libpthread-nonshared): Variable removed.
+       ($(objpfx)libpthread_nonshared.a): Target removed.
+       ($(inst_libdir)/libpthread_nonshared.a): Likewise.
+       These are now handled by generic magic from
+       libpthread-static-only-routines being set.
+
+2004-11-27  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/bits/posix_opt.h (_POSIX_PRIORITIZED_IO,
+       _POSIX2_CHAR_TERM, _POSIX_THREAD_PRIO_INHERIT,
+       _POSIX_THREAD_PRIO_PROTECT): Define.
+       * sysdeps/unix/sysv/linux/i386/bits/posix_opt.h: Likewise.
+       * sysdeps/unix/sysv/linux/ia64/bits/posix_opt.h: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/bits/posix_opt.h: Likewise.
+
+2004-11-26  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/bits/posix_opt.h (_POSIX_ADVISORY_INFO,
+       _POSIX_SPORADIC_SERVER, _POSIX_THREAD_SPORADIC_SERVER, _POSIX_TRACE,
+       _POSIX_TRACE_EVENT_FILTER, _POSIX_TRACE_INHERIT, _POSIX_TRACE_LOG,
+       _POSIX_TYPED_MEMORY_OBJECTS, _POSIX_IPV6, _POSIX_RAW_SOCKETS): Define.
+       * sysdeps/unix/sysv/linux/i386/bits/posix_opt.h: Likewise.
+       * sysdeps/unix/sysv/linux/ia64/bits/posix_opt.h: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/bits/posix_opt.h: Likewise.
+
+2004-11-24  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/x86_64/Makefile [nptl]: Define CFLAGS-pthread_create.c.
+
+       * Makefile (libpthread-routines): Add pthread_setschedprio.
+       * Versions [libpthread, GLIBC_2.3.4]: Add pthread_setschedprio.
+       * sysdeps/pthread/pthread.h: Declare pthread_setschedprio.
+       * pthread_setschedprio.c: New file.
+
+2004-11-20  Jakub Jelinek  <jakub@redhat.com>
+
+       * pthread_create.c (pthread_cancel): Add PTHREAD_STATIC_FN_REQUIRE.
+       * pthread_cancel.c (pthread_create): Likewise.
+
+       * Makefile (libpthread-routines): Add vars.
+       * sysdeps/pthread/createthread.c (__pthread_multiple_threads): Remove.
+       * init.c (__default_stacksize, __is_smp): Remove.
+       * vars.c: New file.
+       * pthreadP.h (__find_thread_by_id): If !SHARED, add weak_function
+       and define a wrapper macro.
+       (PTHREAD_STATIC_FN_REQUIRE): Define.
+       * allocatestack.c (__find_thread_by_id): Undefine.
+       * pthread_create (__pthread_keys): Remove.
+       (pthread_mutex_lock, pthread_mutex_unlock, pthread_once,
+       pthread_key_create, pthread_setspecific, pthread_getspecific): Add
+       PTHREAD_STATIC_FN_REQUIRE.
+
+2004-11-18  Kaz Kojima  <kkojima@rr.iij4u.or.jp>
+
+       * sysdeps/sh/tls.h (DB_THREAD_SELF): Set the correct bias
+       parameter to REGISTER macro.
+
+2004-11-17  Roland McGrath  <roland@redhat.com>
+
+       * sysdeps/unix/sysv/linux/timer_routines.c (__start_helper_thread):
+       Make sure SIGCANCEL is blocked as well.
+
+2004-11-10  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/pthread/setxid.h: New file.
+       * sysdeps/pthread/pthread-functions.h (HAVE_PTR__NPTL_SETXID): Remove.
+       (struct xid_command): Add forward decl.
+       (struct pthread_functions): Change return type of __nptl_setxid hook
+       to int.
+       * pthreadP.h (__nptl_setxid): Change return type to int.
+       * allocatestack.c (__nptl_setxid): Call INTERNAL_SYSCALL_NCS in the
+       calling thread, return its return value and set errno on failure.
+       * descr.h (struct xid_command): Change id type to long array.
+
+       * Makefile: Add rules to build and test tst-setuid1 and
+       tst-setuid1-static.
+       * tst-setuid1.c: New test.
+       * tst-setuid1-static.c: New test.
+
+2004-11-10  Jakub Jelinek  <jakub@redhat.com>
+
+       * Makefile (tests): Add tst-exit3.
+       * tst-exit3.c: New test.
+
+2004-11-09  Ulrich Drepper  <drepper@redhat.com>
+
+       * Makefile (tests): Add tst-exit2.
+       * tst-exit2.c: New file.
+
+2004-11-09  Roland McGrath  <roland@redhat.com>
+
+       [BZ #530]
+       * sysdeps/pthread/createthread.c (do_clone): Increment __nptl_nthreads
+       here, before calling clone.
+       * pthread_create.c (start_thread): Don't do it here.
+
+2004-11-02  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/smp.h: Include <errno.h>.
+
+2004-10-29  Kaz  Kojima  <kkojima@rr.iij4u.or.jp>
+
+       * sysdeps/unix/sysv/linux/sh/sem_timedwait.S (sem_timedwait):
+       Set ETIMEDOUT to errno when time is up.  Tweak to avoid
+       assembler warning.
+
+2004-10-28  Jakub Jelinek  <jakub@redhat.com>
+
+       * pthread_create.c (__pthread_create_2_1): Avoid leaking stacks
+       if sched_priority is not between minprio and maxprio.
+
+2004-10-25  Kaz Kojima  <kkojima@rr.iij4u.or.jp>
+
+       * sysdeps/unix/sysv/linux/sh/pthread_cond_timedwait.S
+       (__pthread_cond_timedwait): Use clock_gettime syscall if exists.
+
+       * sysdeps/unix/sysv/linux/sh/lowlevellock.S
+       (__lll_mutex_timedlock_wait): Fix a bad branch condition.
+
+2004-10-24  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/smp.h (is_smp_system): Use
+       not-cancelable I/O functions.
+
+2004-10-21  Kaz Kojima  <kkojima@rr.iij4u.or.jp>
+
+       * sysdeps/unix/sysv/linux/sh/lowlevellock.S
+       (__lll_mutex_timedlock_wait): If woken but cannot get the lock,
+       make sure 2 is stored in the futex and we looked at the old value.
+       Fix a few other problems to return the correct value.
+
+2004-10-14  Richard Henderson  <rth@redhat.com>
+
+       * sysdeps/alpha/tcb-offsets.sym (thread_offsetof): Redefine to
+       make gcc4 happy.
+
+2004-10-06  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/jmp-unwind.c: Include pthreadP.h instead
+       of pthread-functions.h and pthreaddef.h.
+       * sysdeps/unix/sysv/linux/s390/jmp-unwind.c: Likewise.
+
+       * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h (pthread_cond_t):
+       Change __data.__nwaiters from int to unsigned int.
+
+       * tst-clock2.c (do_test): Don't fail if _POSIX_THREAD_CPUTIME == 0 and
+       sysconf (_SC_THREAD_CPUTIME) returns negative value.
+
+       * allocatestack.c (__find_thread_by_id): Move attribute_hidden
+       before return type.
+
+       * sysdeps/s390/jmpbuf-unwind.h: Include bits/wordsize.h.
+       (JMPBUF_CFA_UNWINDS_ADJ): Subtract 96 resp. 160 bytes from CFA.
+
+2004-10-06  Ulrich Drepper  <drepper@redhat.com>
+
+       * tst-cancel4.c (tf_msgrcv): Check for failure in msgget.  If the
+       test fails, remove message queue.
+       (tf_msgsnd): Likewise.
+
+2004-10-05  Jakub Jelinek  <jakub@redhat.com>
+
+       * tst-clock1.c: Change #ifdef to #if defined.
+       * tst-clock2.c: Likewise.
+       * tst-cond11.c: Likewise.
+
+       * sysdeps/pthread/timer_create.c (timer_create): Use
+       defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0 instead of
+       defined CLOCK_PROCESS_CPUTIME_ID #ifs and similarly for
+       THREAD_CPUTIME.
+
+2004-10-05  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/x86_64/bits/posix_opt.h (_POSIX_CPUTIME,
+       _POSIX_THREAD_CPUTIME): Define to 0.
+
+2004-10-04  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/bits/posix_opt.h: Define _POSIX_CPUTIME
+       and _POSIX_THREAD_CPUTIME to zero.
+       * sysdeps/unix/sysv/linux/ia64/bits/posix_opt.h: Likewise.
+       * tst-barrier2.c: Fix testing for POSIX feature.
+       * tst-clock1.c: Likewise.
+       * tst-clock2.c: Likewise.
+       * tst-cond11.c: Likewise.
+       * tst-cond4.c: Likewise.
+       * tst-cond6.c: Likewise.
+       * tst-flock2.c: Likewise.
+       * tst-mutex4.c: Likewise.
+       * tst-mutex9.c: Likewise.
+       * tst-rwlock12.c: Likewise.
+       * tst-rwlock4.c: Likewise.
+       * tst-signal1.c: Likewise.
+       * tst-spin2.c: Likewise.
+       * sysdeps/pthread/posix-timer.h: Likewise.
+       * sysdeps/pthread/timer_create.c: Likewise.
+       * sysdeps/pthread/timer_routines.c: Likewise.
+
+2004-10-01  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/x86_64/lowlevellock.S
+       (__lll_mutex_timedlock_wait): Address futex correctly.
+
+       * sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S
+       (__lll_mutex_timedlock_wait): If woken but cannot get the lock,
+       make sure 2 is stored in the futex and we looked at the old value.
+       * sysdeps/unix/sysv/linux/x86_64/lowlevellock.S
+       (__lll_mutex_timedlock_wait): Likewise.  Fix a few other problems
+       which might very well made the code not working at all before.
+       [BZ #417]
+
+2004-09-28  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/pthread_kill.c (__pthread_kill): Don't
+       allow SIGSETXID to be sent.
+       * sysdeps/pthread/sigaction.c (__sigaction): Don't allow action
+       for SIGSETXID to be defined.
+       * sysdeps/pthread/pthread_sigmask.c (pthread_sigmask): Make sure
+       SIGSETXID cannot be blocked.
+
+       * sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h (pthread_cond_t):
+       Add __extension__ to long long types.
+       * sysdeps/unix/sysv/linux/sparc/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: Likewise.
+
+2004-09-25  Ulrich Drepper  <drepper@redhat.com>
+
+       * descr.h (struct pthread): Add stopped_start field.
+       * sysdeps/pthread/createthread.c (create_thread): Set
+       start_stopped flag in descriptor for new thread appropriately.
+       * pthread_create.c (start_thread): Only take lock to be stopped on
+       startup if stopped_start flag says so.
+
+2004-09-24  Ulrich Drepper  <drepper@redhat.com>
+
+       * pthread_create.c (__pthread_create_2_1): Remember whether thread
+       is created detached and if yes, do not try to free the stack in case
+       the thread creation failed.
+       * sysdeps/pthread/createthread.c (do_clone): Free stack here if clone
+       call fails.  Don't depend on INTERNAL_SYSCALL_ERRNO return zero in
+       case there has been no error.  [BZ #405]
+
+       * pthread_create.c (start_thread): Don't wait for scheduler data
+       etc to be set at the beginning of the function.  The cancellation
+       infrastructure must have been set up.  And enable async
+       cancellation before potentially going to sleep.  [BZ #401]
+
+2004-09-20  Ulrich Drepper  <drepper@redhat.com>
+
+       * Versions: Remove exports for pthread_set*id_np functions.
+       * sysdeps/pthread/pthread.h: Remove pthread_set*id_np prototypes
+       for now.
+       * Makefile: Don't build pthread_set*id code for now.
+
+2004-09-19  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/allocrtsig.c: Allocate second signal for
+       internal use.
+       * allocatestack.c (__nptl_setxid): New function.
+       * descr.h (struct xid_command): Define type.
+       * init.c (pthread_functions): Add ptr__nptl_setxid initialization.
+       (sighandler_setxid): New function.
+       (__pthread_initialize_minimal): Register sighandler_setxid for
+       SIGCANCEL.
+       * pt-allocrtsig.c: Update comment.
+       * pthreadP.h: Define SIGSETXID.  Declare __xidcmd variable.
+       Declare __nptl_setxid.
+       * sysdeps/pthread/pthread-functions.h: Add ptr__nptl_setxid.
+       * sysdeps/pthread/pthread.h: Declare pthread_setgid_np,
+       pthread_setuid_np, pthread_setegid_np, pthread_seteuid_np,
+       pthread_setregid_np, pthread_setreuid_np, pthread_setresgid_np,
+       and pthread_setresuid_np.
+       * pthread_setgid_np.c: New file.
+       * pthread_setuid_np.c: New file.
+       * pthread_setegid_np.c: New file.
+       * pthread_seteuid_np.c: New file.
+       * pthread_setregid_np.c: New file.
+       * pthread_setreuid_np.c: New file.
+       * pthread_setresgid_np.c: New file.
+       * pthread_setresuid_np.c: New file.
+       * Versions [libpthread, GLIBC_2.3.4]: Add pthread_setgid_np,
+       pthread_setuid_np, pthread_setegid_np, pthread_seteuid_np,
+       pthread_setregid_np, pthread_setreuid_np, pthread_setresgid_np,
+       and pthread_setresuid_np.
+       * Makefile (libpthread-routines): Add pthread_setuid, pthread_seteuid,
+       pthread_setreuid, pthread_setresuid, pthread_setgid, pthread_setegid,
+       pthread_setregid, and pthread_setresgid.
+
+2004-09-18  Ulrich Drepper  <drepper@redhat.com>
+
+       * allocatestack.c (allocate_stack): Return EAGAIN instead of
+       ENOMEM when out of memory.
+
+2004-09-10  Roland McGrath  <roland@redhat.com>
+
+       [BZ #379]
+       * allocatestack.c (allocate_stack): Remove [__ASSUME_CLONE_STOPPED]
+       code, since we don't try to use the broken CLONE_STOPPED any more.
+       * pthread_create.c (start_thread): Likewise.
+
+2004-09-15  Richard Henderson  <rth@redhat.com>
+
+       * sysdeps/unix/sysv/linux/alpha/vfork.S: Use libc_hidden_def.
+
+2004-09-01  David Mosberger  <davidm@hpl.hp.com>
+
+       * sysdeps/unix/sysv/linux/ia64/jmpbuf-unwind.h
+       (__libc_unwind_longjmp): Delete macro and declare as function.
+       * sysdeps/unix/sysv/linux/ia64/Makefile (sysdep_routines): Mention
+       __ia64_longjmp, sigstack_longjmp, and __sigstack_longjmp for
+       nptl directory.
+       * sysdeps/unix/sysv/linux/ia64/__ia64_longjmp.S: New file.
+       * sysdeps/unix/sysv/linux/ia64/__sigstack_longjmp.c: New file.
+       * sysdeps/unix/sysv/linux/ia64/unwind_longjmp.c: New file.
+
+2004-09-12  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/pthread.h: Make rwlock prototypes available also
+       for __USE_XOPEN2K.
+       * sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h: Define rwlock
+       types also for __USE_XOPEN2K.
+       * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/sparc/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: Likewise.
+       [BZ #320]
+
+2004-09-08  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/pthread.h
+       (PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP): Make safe for C++.
+       (PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP): Likewise.
+       (PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP): Likewise.
+       (PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP): Likewise.
+       [BZ #375]
+
+2004-09-07  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h: Allow
+       PSEUDO to be used with . prefix.
+
+       * sysdeps/unix/sysv/linux/alpha/pthread_once.c (__pthread_once):
+       Use atomic_increment instead of atomic_exchange_and_add.
+       * sysdeps/unix/sysv/linux/sparc/pthread_once.c (__pthread_once):
+       Likewise.
+       * sysdeps/unix/sysv/linux/ia64/pthread_once.c (__pthread_once):
+       Likewise.
+       * sysdeps/unix/sysv/linux/powerpc/pthread_once.c (__pthread_once):
+       Likewise.
+
+       * allocatestack.c (allocate_stack): Use atomic_increment_val
+       instead of atomic_exchange_and_add.
+       * sysdeps/unix/sysv/linux/sem_post.c (__new_sem_post): Likewise.
+       * sysdeps/unix/sysv/linux/powerpc/sem_post.c (__new_sem_post):
+       Likewise.
+       * sysdeps/pthread/pthread_barrier_wait.c (pthread_barrier_wait):
+       Likewise.
+
+       * sysdeps/pthread/pthread.h (pthread_once): Remove __THROW since
+       the initialization function might throw.
+
+2005-09-05  Richard Henderson  <rth@redhat.com>
+
+       * sysdeps/unix/sysv/linux/alpha/sysdep-cancel.h (SINGLE_THREAD_P):
+       Move definition inside libpthread, libc, librt check.  Provide
+       definition for rtld.
+
+2004-09-02  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/alpha/jmpbuf-unwind.h: Define __libc_unwind_longjmp.
+       * sysdeps/i386/jmpbuf-unwind.h: Likewise
+       * sysdeps/powerpc/jmpbuf-unwind.h: Likewise.
+       * sysdeps/s390/jmpbuf-unwind.h: Likewise.
+       * sysdeps/sh/jmpbuf-unwind.h: Likewise.
+       * sysdeps/sparc/sparc32/jmpbuf-unwind.h: Likewise.
+       * sysdeps/unix/sysv/linux/ia64/jmpbuf-unwind.h: Likewise.
+       * sysdeps/x86_64/jmpbuf-unwind.h: Likewise.
+       * unwind.c: Use it.
+
+       * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h (pthread_cond_t):
+       Rename __data.__clock to __data.__nwaiters, make it unsigned int.
+       * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h (pthread_cond_t):
+       Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S:
+       Decrement __nwaiters.  If pthread_cond_destroy has been called and
+       this is the last waiter, signal pthread_cond_destroy caller and
+       avoid using the pthread_cond_t structure after unlock.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Likewise.
+       Read clock type from the least significant bits of __nwaiters instead
+       of __clock.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: Likewise.
+       * sysdeps/unix/sysv/linux/internaltypes.h: Define COND_CLOCK_BITS.
+
+2004-08-31  Jakub Jelinek  <jakub@redhat.com>
+
+       [BZ #342]
+       * Makefile (tests): Add tst-cond20 and tst-cond21.
+       * tst-cond20.c: New test.
+       * tst-cond21.c: New test.
+       * sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h
+       (pthread_cond_t): Rename __data.__clock to __data.__nwaiters, make
+       it unsigned int.
+       * sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h (pthread_cond_t):
+       Likewise.
+       * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h
+       (pthread_cond_t): Likewise.
+       * sysdeps/unix/sysv/linux/sparc/bits/pthreadtypes.h (pthread_cond_t):
+       Likewise.
+       * sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h (pthread_cond_t):
+       Likewise.
+       * sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h (pthread_cond_t):
+       Likewise.
+       * sysdeps/unix/sysv/linux/lowlevelcond.sym (cond_clock): Remove.
+       (cond_nwaiters): New.
+       (clock_bits): New.
+       * pthread_cond_destroy.c (__pthread_cond_destroy): Return EBUSY
+       if there are waiters not signalled yet.
+       Wait until all already signalled waiters wake up.
+       * sysdeps/pthread/pthread_cond_wait.c (__condvar_cleanup): Decrement
+       __nwaiters.  If pthread_cond_destroy has been called and this is the
+       last waiter, signal pthread_cond_destroy caller and avoid using
+       the pthread_cond_t structure after unlock.
+       (__pthread_cond_wait): Increment __nwaiters in the beginning,
+       decrement it when leaving.  If pthread_cond_destroy has been called
+       and this is the last waiter, signal pthread_cond_destroy caller.
+       * sysdeps/pthread/pthread_cond_timedwait.c (__pthread_cond_timedwait):
+       Likewise.  Read clock type from the least significant bits of
+       __nwaiters instead of __clock.
+       * pthread_condattr_setclock.c (pthread_condattr_setclock): Check
+       whether clock ID can be encoded in COND_CLOCK_BITS bits.
+       * pthread_condattr_getclock.c (pthread_condattr_getclock): Decode
+       clock type just from the last COND_CLOCK_BITS bits of value.
+       * pthread_cond_init.c (__pthread_cond_init): Initialize __nwaiters
+       instead of __clock, just from second bit of condattr's value.
+
+2004-08-30  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: Include
+       bits/wordsize.h.  Make the header match i386 header when __WORDSIZE
+       != 64.
+       * sysdeps/unix/sysv/linux/x86_64/bits/semaphore.h: Likewise.
+
+2004-08-15  Roland McGrath  <roland@frob.com>
+
+       * pthread_atfork.c: Update copyright terms including special exception
+       for these trivial files, which are statically linked into executables
+       that use dynamic linking for the significant library code.
+
+2004-08-09  Jakub Jelinek  <jakub@redhat.com>
+
+       * DESIGN-rwlock.txt: Add decreasing of nr_readers_queued to
+       pthread_rwlock_rdlock.
+       * sysdeps/pthread/pthread_rwlock_rdlock (__pthread_rwlock_rdlock):
+       Decrease __nr_readers_queued after reacquiring lock.
+       * sysdeps/pthread/pthread_rwlock_timedrdlock
+       (pthread_rwlock_timedrdlock): Likewise.
+       Reported by Bob Cook <bobcook47@hotmail.com>.
+
+2004-08-11  Jakub Jelinek  <jakub@redhat.com>
+
+       * tst-rwlock14.c (tf): Read main thread handle from *ARG
+       before pthread_barrier_wait.
+
+2004-08-07  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S:
+       Remove unnecessary exception handling data.
+
+2004-07-23  Jakub Jelinek  <jakub@redhat.com>
+
+       [BZ #284]
+       * sysdeps/pthread/pthread.h (pthread_getcpuclockid): Use __clockid_t
+       instead of clockid_t.
+
+2004-07-21  Roland McGrath  <roland@redhat.com>
+
+       * Makefile ($(objpfx)multidir.mk): Use $(make-target-directory).
+
+2004-07-19  Roland McGrath  <roland@redhat.com>
+
+       * tst-cancel4.c (tf_waitid): Use WEXITED flag bit if available.
+
+2004-07-02  Roland McGrath  <roland@redhat.com>
+
+       * configure: Don't exit.
+
+2004-07-14  Kaz Kojima  <kkojima@rr.iij4u.or.jp>
+
+       * sysdeps/unix/sysv/linux/sh/pthread_cond_timedwait.S
+       (__pthread_cond_timedwait): Check for invalid nanosecond in
+       timeout value.
+
+2004-07-07  Ulrich Drepper  <drepper@redhat.com>
+
+       * Makefile: Add rules to build and run tst-fini1.
+       * tst-fini1.c: New file.
+       * tst-fini1mod.c: New file.
+
+2004-07-05  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h: Define NO_CANCELLATION
+       if no cancellation support is needed.
+       * sysdeps/unix/sysv/linux/ia64/sysdep-cancel.h: Likewise.
+       * sysdeps/unix/sysv/linux/sh/sysdep-cancel.h: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h: Likewise.
+       * sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h: Likewise.
+       * sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h: Likewise.
+       * sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h: Likewise.
+       * sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h: Likewise.
+       * sysdeps/unix/sysv/linux/sparc/sparc32/sysdep-cancel.h: Likewise.
+       * sysdeps/unix/sysv/linux/sparc/sparc64/sysdep-cancel.h: Likewise.
+
+       * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h: Define __NR_futex
+       only if not already defined.
+
+2004-07-05  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h (lll_unlock): Use
+       constraint "m" instead of "0" for futex.
+
+       * shlib-versions: Add powerpc64-.*-linux.*.
+
+2004-07-04  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedrdlock.S
+       (pthread_rwlock_timedrdlock): Use cmpq instead of cmpl to check
+       for valid tv_nsec.
+       * tst-rwlock14.c (do_test): Test for invalid tv_nsec equal to
+       1 billion and 64-bit tv_nsec which is valid when truncated to 32
+       bits.
+
+2004-06-29  Roland McGrath  <roland@redhat.com>
+
+       * Banner: NPTL no longer has its own version number.
+       * Makefile (nptl-version): Variable removed.
+       * sysdeps/pthread/Makefile (CFLAGS-confstr.c): Set LIBPTHREAD_VERSION
+       using $(version), the glibc version number.
+
+2004-06-29  Kaz Kojima  <kkojima@rr.iij4u.or.jp>
+
+       * sysdeps/unix/sysv/linux/sh/pthread_once.S (__pthread_once):
+       Fix branch offset for a PLT entry.
+       * sysdeps/unix/sysv/linux/sh/sem_post.S (__new_sem_post):
+       Likewise.
+       * sysdeps/unix/sysv/linux/sh/sem_timedwait.S (sem_timedwait):
+       Likewise.
+       * sysdeps/unix/sysv/linux/sh/sem_trywait.S (__new_sem_trywait):
+       Likewise.
+       * sysdeps/unix/sysv/linux/sh/sem_wait.S (__new_sem_wait):
+       Likewise.
+
+2004-06-28  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/alpha/tcb-offsets.sym (MULTIPLE_THREADS_OFFSET): Define
+       unconditionally.
+
+2004-06-28  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/pthread/pthread_rwlock_timedwrlock.c
+       (pthread_rwlock_timedwrlock): Return EINVAL if tv_nsec is negative,
+       instead of tv_sec.
+       * sysdeps/pthread/pthread_rwlock_timedrdlock.c
+       (pthread_rwlock_timedrdlock): Likewise.
+
+2004-06-22  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/s390/lowlevellock.h (lll_futex_requeue):
+       Set __r7 to val, not mutex.
+
+2004-06-27  Ulrich Drepper  <drepper@redhat.com>
+
+       * Makefile: Add rules to build tst-rwlock14.
+       * tst-rwlock14.c: New file.
+
+2004-06-24  Boris Hu  <boris.hu@intel.com>
+
+       * sysdeps/pthread/pthread_rwlock_timedrdlock.c: Add timeout validation
+       check.
+       * sysdeps/pthread/pthread_rwlock_timedwrlock.c: Likewise.
+
+2004-06-19  Andreas Jaeger  <aj@suse.de>
+
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: Fix
+       assembler in last patch.
+
+2004-06-17  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/pthread_cond_timedwait.c
+       (__pthread_cond_timedwait): Also check for negativ nanoseconds.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S
+       (__pthread_cond_timedwait): Check for invalid nanosecond in
+       timeout value.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: Likewise.
+       * tst-cond19.c: New file.
+       * Makefile: Add rules to build and run tst-cond19.
+
+2004-06-15  Steven Munroe  <sjmunroe@us.ibm.com>
+
+       * tst-context1.c (GUARD_PATTERN): Defined.
+       (tst_context_t): Define struct containing ucontext_t & guard words.
+       (ctx): Declare as an array of tst_context_t.
+       (fct): Verify uc_link & guard words are still valid.
+       (tf): Initialize guard words in ctx.  Adjust ctx refs for new struct.
+
+2004-06-13  Kaz Kojima  <kkojima@rr.iij4u.or.jp>
+
+       * sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h (pthread_cond_t):
+       Add __data.__futex field, reshuffle __data.__clock.
+       * sysdeps/unix/sysv/linux/sh/pthread_cond_signal.S
+       (__pthread_cond_signal): Increment __futex at the same time as
+       __wakeup_seq or __total_seq.  Pass address of __futex instead of
+       address of low 32-bits of __wakeup_seq to futex syscall.
+       * sysdeps/unix/sysv/linux/sh/pthread_cond_wait.S
+       (__pthread_cond_wait): Likewise.  Pass __futex value from before
+       releasing internal lock to FUTEX_WAIT.
+       * sysdeps/unix/sysv/linux/sh/pthread_cond_timedwait.S
+       (__pthread_cond_timedwait): Likewise.
+       * sysdeps/unix/sysv/linux/sh/pthread_cond_broadcast.S
+       (FUTEX_CMP_REQUEUE): Define.
+       (__pthread_cond_broadcast): Set __futex to 2 * __total_seq.
+       Use FUTEX_CMP_REQUEUE operation instead of FUTEX_REQUEUE.
+       Pass __futex value from before the unlock and __futex address instead
+       of address of low 32-bits of __wakeup_seq to futex syscall.
+       Fallback to FUTEX_WAKE all on any errors.
+
+2004-06-08  Jakub Jelinek  <jakub@redhat.com>
+
+       * pthread_mutexattr_getpshared.c (pthread_mutex_getpshared): Fix
+       comment typo.
+       * pthread_mutexattr_gettype.c (pthread_mutexattr_gettype): Likewise.
+       * pthread_mutexattr_init.c (__pthread_mutexattr_init): Likewise.
+       * pthread_mutexattr_settype.c (__pthread_mutexattr_settype): Likewise.
+       * pthread_mutexattr_setpshared.c (pthread_mutexattr_setpshared):
+       Likewise.  Reported by Bob Cook <bobcook47@hotmail.com>.
+
+2004-06-11  Martin Schwidefsky  <schwidefsky@de.ibm.com>
+
+       * sysdeps/unix/sysv/linux/s390/lowlevellock.h (lll_compare_and_swap):
+       Add memory clobber to inline assembly.
+       (__lll_mutex_trylock): Likewise.
+       (__lll_mutex_cond_trylock): Likewise.
+
+2004-06-07  Martin Schwidefsky  <schwidefsky@de.ibm.com>
+
+       * sysdeps/unix/sysv/linux/s390/lowlevellock.h (lll_futex_requeue):
+       Pass val argument as 6th system call argument in %r7.
+
+2004-05-21  Jakub Jelinek  <jakub@redhat.com>
+
+       * Makefile (tests): Add tst-cond16.
+       * sysdeps/unix/sysv/linux/lowlevelcond.sym (cond_futex): Add.
+       * pthread_cond_init.c (__pthread_cond_init): Clear __data.__futex.
+       * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h (pthread_cond_t):
+       Add __data.__futex field, reshuffle __data.__clock.
+       * sysdeps/unix/sysv/linux/i386/pthread_cond_signal.S
+       (__pthread_cond_signal): Increment __futex at the same time as
+       __wakeup_seq or __total_seq.  Pass address of __futex instead of
+       address of low 32-bits of __wakeup_seq to futex syscall.
+       * sysdeps/unix/sysv/linux/i386/pthread_cond_wait.S
+       (__pthread_cond_wait): Likewise.  Pass __futex value from before
+       releasing internal lock to FUTEX_WAIT.
+       * sysdeps/unix/sysv/linux/i386/pthread_cond_timedwait.S
+       (__pthread_cond_timedwait): Likewise.
+       * sysdeps/unix/sysv/linux/i386/pthread_cond_broadcast.S
+       (FUTEX_CMP_REQUEUE): Define.
+       (__pthread_cond_broadcast): Set __futex to 2 * __total_seq.
+       Use FUTEX_CMP_REQUEUE operation instead of FUTEX_REQUEUE.
+       Pass __futex value from before the unlock and __futex address instead
+       of address of low 32-bits of __wakeup_seq to futex syscall.
+       Fallback to FUTEX_WAKE all on any errors.
+       * sysdeps/unix/sysv/linux/alpha/lowlevellock.h (FUTEX_CMP_REQUEUE):
+       Define.
+       (lll_futex_requeue): Add val argument, use FUTEX_CMP_REQUEUE
+       internally.  Return non-zero if error, zero if success.
+       * sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h (pthread_cond_t):
+       Add __data.__futex field, reshuffle __data.__clock.
+       * sysdeps/unix/sysv/linux/s390/lowlevellock.h (FUTEX_CMP_REQUEUE):
+       Define.
+       (lll_futex_requeue): Add val argument, return 1 unconditionally
+       for the time being.
+       * sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h (pthread_cond_t):
+       Add __data.__futex field, reshuffle __data.__clock.
+       * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h (FUTEX_CMP_REQUEUE):
+       Define.
+       (lll_futex_requeue): Add val argument, use FUTEX_CMP_REQUEUE
+       internally.  Return non-zero if error, zero if success.
+       * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h
+       (pthread_cond_t): Add __data.__futex field, reshuffle __data.__clock.
+       * sysdeps/unix/sysv/linux/sparc/lowlevellock.h (FUTEX_CMP_REQUEUE):
+       Define.
+       (lll_futex_requeue): Add val argument, use FUTEX_CMP_REQUEUE
+       internally.  Return non-zero if error, zero if success.
+       * sysdeps/unix/sysv/linux/sparc/bits/pthreadtypes.h (pthread_cond_t):
+       Add __data.__futex field, reshuffle __data.__clock.
+       * sysdeps/unix/sysv/linux/ia64/lowlevellock.h (FUTEX_CMP_REQUEUE):
+       Define.
+       (lll_futex_requeue): Add val argument, use FUTEX_CMP_REQUEUE
+       internally.  Return non-zero if error, zero if success.
+       * sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h (pthread_cond_t):
+       Add __data.__futex field, reshuffle __data.__clock.
+       * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h (pthread_cond_t):
+       Add __data.__futex field, reshuffle __data.__clock.
+       * sysdeps/pthread/pthread_cond_signal.c (__pthread_cond_signal):
+       Increment __futex at the same time as __wakeup_seq or __total_seq.
+       Pass address of __futex instead of address of low 32-bits of
+       __wakeup_seq to futex syscall.
+       * sysdeps/pthread/pthread_cond_wait.c (__pthread_cond_wait): Likewise.
+       Pass __futex value from before releasing internal lock
+       to FUTEX_WAIT.
+       * sysdeps/pthread/pthread_cond_timedwait.c (__pthread_cond_timedwait):
+       Likewise.  Avoid unnecessary shadowing of variables.
+       * sysdeps/pthread/pthread_cond_broadcast.c (__pthread_cond_broadcast):
+       Set __futex to 2 * __total_seq.  Pass __futex value from before the
+       unlock and __futex address instead of address of low 32-bits of
+       __wakeup_seq to futex_requeue macro, adjust for new return value
+       meaning.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_signal.S
+       (__pthread_cond_signal): Increment __futex at the same time as
+       __wakeup_seq or __total_seq.  Pass address of __futex instead of
+       address of low 32-bits of __wakeup_seq to futex syscall.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S
+       (__pthread_cond_wait): Likewise.  Pass __futex value from before
+       releasing internal lock to FUTEX_WAIT.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S
+       (__pthread_cond_timedwait): Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S
+       (FUTEX_CMP_REQUEUE): Define.
+       (__pthread_cond_broadcast): Set __futex to 2 * __total_seq.
+       Use FUTEX_CMP_REQUEUE operation instead of FUTEX_REQUEUE.
+       Pass __futex value from before the unlock and __futex address instead
+       of address of low 32-bits of __wakeup_seq to futex syscall.
+       Fallback to FUTEX_WAKE all on any errors.
+
+2004-06-03  Kaz Kojima  <kkojima@rr.iij4u.or.jp>
+
+       * sysdeps/unix/sysv/linux/sh/lowlevellock.h (lll_mutex_lock):
+       Add nop to align the end of critical section.
+       (lll_mutex_cond_lock, lll_mutex_timedlock): Likewise.
+
+2004-06-01  Kaz Kojima  <kkojima@rr.iij4u.or.jp>
+
+       * sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h (pthread_cond_t):
+       Add __broadcast_seq field.
+       * sysdeps/unix/sysv/linux/sh/pthread_cond_broadcast.S: Mark
+       all waiters as woken with woken_seq and bump broadcast counter.
+       * sysdeps/unix/sysv/linux/sh/pthread_cond_wait.S: Use new
+       __broadcast_seq.  Increment __woken_seq correctly when cleanuped.
+       * sysdeps/unix/sysv/linux/sh/pthread_cond_timedwait.S: Likewise.
+       Comment typo fixes.  Avoid returning -ETIMEDOUT.
+
+2004-06-01  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S
+       (__condvar_tw_cleanup): Fix access to saved broadcast_seq value.
+       Reported by Kaz Kojima.
+
+2004-05-25  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/aio_misc.h: New file.
+
+2004-05-21  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/pthread/pthread_cond_wait.c (__pthread_cond_wait): Compare
+       __broadcast_seq with bc_seq after acquiring internal lock instead of
+       before it.
+
+2004-05-18  Jakub Jelinek  <jakub@redhat.com>
+
+       * Makefile (.NOTPARALLEL): Only serialize make check/xcheck, not
+       compilation.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S
+       (__pthread_cond_timedwait): Avoid returning -ETIMEDOUT.
+       * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h
+       (pthread_cond_t): Add __data.__broadcast_seq field.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S
+       (FRAME_SIZE): Define.
+       (__pthread_cond_timedwait): Use it.  Store/check broadcast_seq.
+       Comment typo fixes.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S (FRAME_SIZE):
+       Define.
+       (__pthread_cond_wait): Use it.  Store/check broadcast_seq.  Comment
+       typo fixes.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S
+       (__pthread_cond_broadcast): Increment broadcast_seq.  Comment typo
+       fixes.
+
+2004-05-18  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/lowlevelcond.sym: Add broadcast_seq entry.
+       * sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h (pthread_cond_t):
+       Add __broadcast_seq field.
+       * sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/sparc/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S: Mark
+       all waiters as woken with woken_seq and bump broadcast counter.
+       * sysdeps/pthread/pthread_cond_broadcast.c: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Use new
+       __broadcast_seq field.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Likewise.
+       * sysdeps/pthread/pthread_cond_wait.c: Likewise.
+       * sysdeps/pthread/pthread_cond_timedwait.c: Likewise.
+       * pthread_cond_init.c: Initialize __broadcast_seq field.
+       * Makefile (tests): Add tst-cond17 and tst-cond18.
+       Add .NOTPARALLEL goal.
+       * tst-cond16.c: New file.  From Jakub.
+       * tst-cond17.c: New file.  From Jakub.
+       * tst-cond18.c: New file.  From Jakub.
+
+2004-05-16  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/i486/sem_timedwait.S: Correct some
+       unwind info.
+
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S:
+       Parametrize frame size.  Correct some unwind info.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Likewise.
+
+2004-05-04  Jakub Jelinek  <jakub@redhat.com>
+
+       * tst-stack3.c: Note testing functionality beyond POSIX.
+
+2004-05-04  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/ia64/sysdep-cancel.h (USE___THREAD):
+       Change conditional from ifdef to if.
+
+2004-04-23  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/ia64/sysdep-cancel.h (SYSDEP_CANCEL_ERRNO,
+       SYSDEP_CANCEL_ERROR): Define.
+       (PSEUDO): Use it.
+
+2004-05-01  Jakub Jelinek  <jakub@redhat.com>
+
+       * Versions (libpthread): Remove __pthread_cleanup_upto@@GLIBC_PRIVATE.
+
+2004-04-20  Jakub Jelinek  <jakub@redhat.com>
+
+       * sem_unlink.c (sem_unlink): Change EPERM into EACCES.
+
+2004-04-19  Kaz Kojima  <kkojima@rr.iij4u.or.jp>
+
+       * sysdeps/unix/sysv/linux/sh/sem_timedwait.S: Add frame info.
+       Use HIDDEN_JUMPTARGET to jump to __pthread_unwind.
+       * sysdeps/unix/sysv/linux/sh/sem_wait.S: Remove unneeded frame
+       info.  Use HIDDEN_JUMPTARGET to jump to __pthread_unwind.
+
+2004-04-19  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/timer_routines.c: Make sure helper
+       thread has all signals blocked.
+
+2004-04-18  Andreas Jaeger  <aj@suse.de>
+
+       * sysdeps/unix/sysv/linux/x86_64/bits/semaphore.h
+       (SEM_VALUE_MAX): Add missing brace.
+
+2004-04-17  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/pthread/Makefile (tests): Add tst-mqueue8x
+       in rt subdir.
+       (CFLAGS-tst-mqueue8x.c): Add -fexceptions.
+       * sysdeps/pthread/tst-mqueue8x.c: New test.
+       * tst-cancel4.c: Update comment about message queues.
+
+       * sysdeps/pthread/timer_gettime.c (timer_gettime): For expired timer
+       return it_value { 0, 0 }.
+       * sysdeps/pthread/timer_create.c (timer_create): Handle SIGEV_NONE
+       like SIGEV_SIGNAL.
+       * sysdeps/pthread/timer_routines.c (thread_expire_timer): Remove
+       assertion for SIGEV_NONE.
+       (thread_attr_compare): Compare all attributes, not just a partial
+       subset.
+
+2004-04-17  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/mq_notify.c: Include stdlib.h.
+
+2004-04-17  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/alpha/bits/semaphore.h (SEM_VALUE_MAX):
+       Just use a plain number.
+       * sysdeps/unix/sysv/linux/i386/bits/semaphore.h: Likewise.
+       * sysdeps/unix/sysv/linux/ia64/bits/semaphore.h: Likewise.
+       * sysdeps/unix/sysv/linux/powerpc/bits/semaphore.h: Likewise.
+       * sysdeps/unix/sysv/linux/s390/bits/semaphore.h: Likewise.
+       * sysdeps/unix/sysv/linux/sh/bits/semaphore.h: Likewise.
+       * sysdeps/unix/sysv/linux/sparc/bits/semaphore.h: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/bits/semaphore.h: Likewise.
+
+2004-04-16  Kaz Kojima  <kkojima@rr.iij4u.or.jp>
+
+       * sysdeps/unix/sysv/linux/sh/pthread_cond_wait.S: Remove unneeded
+       frame info.
+       * sysdeps/unix/sysv/linux/sh/pthread_cond_timedwait.S: Likewise.
+
+2004-04-15  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/timer_routines.c: Include errno.h.
+       (timer_helper_thread): Use inline rt_sigtimedwait syscall instead
+       of calling sigwaitinfo.
+
+2004-04-16  Ulrich Drepper  <drepper@redhat.com>
+
+       * allocatestack.c (allocate_stack): Set reported_guardsize
+       unconditionally.
+       * pthread_getattr_np.c (pthread_getattr_np): Use
+       reported_guardsize instead of guardsize.
+       * descr.h (struct pthread): Add reported_guardsize field.
+
+2004-04-13  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/mq_notify.c: Shut up GCC warning.
+
+2004-04-12  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/mq-notify.c: New file.
+
+2004-04-08  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/bits/local_lim.h (MQ_PRIO_MAX): Define.
+       * sysdeps/unix/sysv/linux/alpha/bits/local_lim.h (MQ_PRIO_MAX): Define.
+       * sysdeps/unix/sysv/linux/ia64/bits/local_lim.h (MQ_PRIO_MAX): Define.
+       * sysdeps/unix/sysv/linux/sparc/bits/local_lim.h (MQ_PRIO_MAX): Define.
+       * sysdeps/unix/sysv/linux/bits/posix_opt.h (_POSIX_MESSAGE_PASSING):
+       Define.
+       * sysdeps/unix/sysv/linux/i386/bits/posix_opt.h
+       (_POSIX_MESSAGE_PASSING): Define.
+       * sysdeps/unix/sysv/linux/ia64/bits/posix_opt.h
+       (_POSIX_MESSAGE_PASSING): Define.
+       * sysdeps/unix/sysv/linux/x86_64/bits/posix_opt.h
+       (_POSIX_MESSAGE_PASSING): Define.
+
+2004-04-04  Ulrich Drepper  <drepper@redhat.com>
+
+       * tst-context1.c (fct): Check whether correct stack is used.
+
+2004-04-03  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h: Never use
+       matching constraints for asm mem parameters.
+
+       * tst-clock2.c (tf): Don't define unless needed.
+
+2004-03-30  H.J. Lu  <hongjiu.lu@intel.com>
+
+       * Makefile (link-libc-static): Use $(static-gnulib) instead of
+       $(gnulib).
+
+2004-03-30  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/pthread-functions.h: Add ptr__nptl_deallocate_tsd.
+       * init.c (pthread_functions): Add ptr__nptl_deallocate_tsd.
+       * pthreadP.h: Declare __nptl_deallocate_tsd.
+       * pthread_create.c (deallocate_tsd): Remove to __nptl_deallocate_tsd.
+       Adjust caller.
+
+       * Makefile (tests): Add tst-tsd5.
+       * tst-tsd5.c: New file.
+
+2004-03-29  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/pthread_attr_setaffinity.c
+       (__pthread_attr_setaffinity_old): Prepend GLIBC_ to version names
+       is SHLIB_COMPAT check.
+       * sysdeps/unix/sysv/linux/pthread_attr_getaffinity.c
+       (__pthread_attr_getaffinity_old): Likewise.
+       * sysdeps/unix/sysv/linux/pthread_getaffinity.c
+       (__pthread_getaffinity_old): Likewise.
+       * sysdeps/unix/sysv/linux/pthread_setaffinity.c
+       (__pthread_setaffinity_old): Likewise.
+
+2004-03-26  Ulrich Drepper  <drepper@redhat.com>
+
+       * allocatestack.c (_make_stacks_executable): Call
+       _dl_make_stack_executable first.
+
+2004-03-24  Roland McGrath  <roland@redhat.com>
+
+       * sysdeps/i386/pthread_spin_lock.c (pthread_spin_lock): Use "m"
+       constraint instead of "0".
+
+2004-03-24  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h
+       (lll_mutex_cond_trylock): Define as wrapper around __lll_cond_trylock.
+
+       * sysdeps/unix/sysv/linux/getpid.c (really_getpid): Reorganize
+       code to avoid warning.
+
+2004-03-24  Andreas Jaeger  <aj@suse.de>
+
+       * sysdeps/unix/sysv/linux/pthread_attr_setaffinity.c
+       (__pthread_attr_setaffinity_old): Remove const.
+
+2004-03-23  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/smp.h: New file.
+       * sysdeps/unix/sysv/linux/sh/smp.h: New file.
+       * init.c: Define __is_smp.
+       (__pthread_initialize_minimal_internal): Call is_smp_system to
+       initialize __is_smp.
+       * pthreadP.h: Declare __is_smp.
+       Define MAX_ADAPTIVE_COUNT is necessary.
+       * pthread_mutex_init.c: Add comment regarding __spins field.
+       * pthread_mutex_lock.c: Implement adaptive mutex type.
+       * pthread_mutex_timedlock.c: Likewise.
+       * sysdeps/unix/sysv/linux/pthread_mutex_cond_lock.c: Likewise.
+       * sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h (pthread_mutex_t):
+       Add __spins field.
+       * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/sparc/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h: Define
+       lll_mutex_cond_trylock.
+       * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/sparc/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h: Likewise.
+       Define BUSY_WAIT_NOP.
+       * sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: Likewise.
+
+       * tst-mutex5.c: Add support for testing adaptive mutexes.
+       * tst-mutex7.c: Likewise.
+       * tst-mutex5a.c: New file.
+       * tst-mutex7a.c: New file.
+       * Makefile (tests): Add tst-mutex5a and tst-mutex7a.
+
+       * sysdeps/unix/sysv/linux/x86_64/lowlevellock.S
+       (__lll_mutex_timedlock_wait): Preserve r8 and r9 since the
+       vgettimeofday call might destroy the content.
+
+       * sysdeps/ia64/pthread_spin_lock.c (pthread_spin_lock): Use hint
+       @pause in the loop.
+
+       * sysdeps/unix/sysv/linux/i386/lowlevellock.h (lll_mutex_trylock):
+       No need to restrict type of ret.  Make it int.  Add comment.
+
+       * sysdeps/unix/sysv/linux/i386/lowlevellock.h (lll_mutex_trylock):
+       Remove unnecessary setne instruction.
+
+2004-03-22  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/pthread_getaffinity.c
+       (__pthread_getaffinity_new): Use INT_MAX instead of UINT_MAX.
+       * pthread_getattr_np.c (pthread_getattr_np): Double size every cycle.
+       If realloc fails, break out of the loop.
+
+2004-03-20  Andreas Jaeger  <aj@suse.de>
+
+       * sysdeps/unix/sysv/linux/pthread_setaffinity.c
+       (__pthread_setaffinity_old): Fix interface.
+       * sysdeps/unix/sysv/linux/pthread_getaffinity.c
+       (__pthread_getaffinity_old): Likewise.
+
+       * sysdeps/unix/sysv/linux/pthread_setaffinity.c
+       (__pthread_setaffinity_new): Remove duplicate declaration.
+
+2004-03-20  Kaz Kojima  <kkojima@rr.iij4u.or.jp>
+
+       * sysdeps/unix/sysv/linux/sh/sysdep-cancel.h (CENABLE): Save
+       the return value to a safe register.
+       (CDISABLE): Set the function argument correctly.
+
+2004-03-17  Kaz Kojima  <kkojima@rr.iij4u.or.jp>
+
+       * sysdeps/unix/sysv/linux/sh/lowlevel-atomic.h (XCHG): Define.
+       * sysdeps/unix/sysv/linux/sh/lowlevellock.S (__lll_mutex_lock_wait):
+       Rewrite so that only one locked memory operation per round is needed.
+       * sysdeps/unix/sysv/linux/sh/pthread_barrier_wait.S
+       (pthread_barrier_wait): After wakeup, release lock only when the
+       last thread stopped using the barrier object.
+       * sysdeps/unix/sysv/linux/sh/pthread_cond_wait.S
+       (__pthread_cond_wait): Don't store mutex address if the current
+       value is ~0l.  Add correct cleanup support and unwind info.
+       * sysdeps/unix/sysv/linux/sh/pthread_cond_timedwait.S: Likewise.
+       * sysdeps/unix/sysv/linux/sh/pthread_cond_broadcast.S
+       (__pthread_cond_broadcast): Don't use requeue for pshared condvars.
+       * sysdeps/unix/sysv/linux/sh/pthread_cond_signal.S: Update comment.
+       * sysdeps/unix/sysv/linux/sh/pthread_once.S (__pthread_once):
+       Add correct cleanup support and unwind info.
+       * sysdeps/unix/sysv/linux/sh/sem_wait.S (__new_sem_wait): Likewise.
+       * sysdeps/unix/sysv/linux/sh/sysdep-cancel.h: Add unwind
+       information for syscall wrappers.
+
+2004-03-18  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/internaltypes.h (struct pthread_attr): Add
+       cpusetsize field, remove next.
+       * sysdeps/pthread/pthread.h (pthread_getaffinity_np): Add new second
+       parameter for size of the CPU set.
+       (pthread_setaffinity_np): Likewise.
+       (pthread_attr_getaffinity_np): Likewise.
+       (pthread_attr_setaffinity_np): Likewise.
+       * sysdeps/unix/sysv/linux/pthread_attr_getaffinity.c: Implement
+       interface change, keep compatibility code.
+       * sysdeps/unix/sysv/linux/pthread_attr_setaffinity.c: Likewise.
+       * sysdeps/unix/sysv/linux/pthread_getaffinity.c: Likewise.
+       * sysdeps/unix/sysv/linux/pthread_setaffinity.c: Likewise.
+       * pthreadP.h: Remove hidden_proto for pthread_getaffinity_np.  Declare
+       __pthread_getaffinity_np.
+       * Versions: Add version for changed interfaces.
+       * tst-attr3.c: Adjust test for interface change.
+       * pthread_getattr_np.c: Query the kernel about the affinity mask with
+       increasing buffer sizes.
+       * pthread_attr_destroy.c: Remove unused list handling.
+       * pthread_attr_init.c: Likewise.
+
+2004-03-17  Roland McGrath  <roland@redhat.com>
+
+       * sysdeps/unix/sysv/linux/timer_create.c (timer_create): Pass missing
+       first argument to clock_getres so we ever enable kernel timers.
+
+2004-03-15  Ulrich Weigand  <uweigand@de.ibm.com>
+
+       * init.c (nptl_version): Add __attribute_used__ to nptl_version.
+
+2004-03-12  Richard Henderson  <rth@redhat.com>
+
+       * sysdeps/unix/sysv/linux/alpha/sysdep-cancel.h: Propagate
+       oldvalue from CENABLE to CDISABLE.
+
+2004-03-12  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/bits/local_lim.h: Define HOST_NAME_MAX.
+       * sysdeps/unix/sysv/linux/alpha/bits/local_lim.h: Likewise.
+       * sysdeps/unix/sysv/linux/ia64/bits/local_lim.h: Likewise.
+       * sysdeps/unix/sysv/linux/sparc/bits/local_lim.h: Likewise.
+
+2004-03-11  Richard Henderson  <rth@redhat.com>
+
+       * sysdeps/alpha/tcb-offsets.sym (PID_OFFSET): New.
+       * sysdeps/unix/sysv/linux/alpha/pt-vfork.S: Save/restore PID.
+       * sysdeps/unix/sysv/linux/alpha/vfork.S: New file.
+
+2004-03-11  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/s390/s390-64/vfork.S (__vfork): Use jgnl
+       instead of jnl instruction to jump to SYSCALL_ERROR_LABEL.
+       * sysdeps/unix/sysv/linux/s390/s390-64/pt-vfork.S (__vfork): Likewise.
+
+2004-03-11  Jakub Jelinek  <jakub@redhat.com>
+
+       * forward.c (__pthread_cond_broadcast_2_0,
+       __pthread_cond_destroy_2_0, __pthread_cond_init_2_0,
+       __pthread_cond_signal_2_0, __pthread_cond_wait_2_0,
+       __pthread_cond_timedwait_2_0): Use return 0 as defaction instead of 0.
+
+2004-03-11  Kaz Kojima  <kkojima@rr.iij4u.or.jp>
+
+       * sysdeps/sh/tcb-offsets.sym: Add PID.
+       * sysdeps/unix/sysv/linux/sh/pt-vfork.S: Properly handle PID cache.
+       * sysdeps/unix/sysv/linux/sh/vfork.S: New file.
+
+2004-03-10  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/powerpc/powerpc32/vfork.S: No need to
+       include <sysdep-cancel.h>, vfork is no cancellation point.
+       * sysdeps/unix/sysv/linux/powerpc/powerpc64/vfork.S: Likewise.
+       * sysdeps/unix/sysv/linux/powerpc/powerpc64/pt-vfork.S: Likewise.
+       * sysdeps/unix/sysv/linux/powerpc/powerpc32/pt-vfork.S: Likewise.
+
+2004-03-10  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/s390/s390-32/vfork.S (__vfork): Add
+       libc_hidden_def.
+       * sysdeps/unix/sysv/linux/s390/s390-64/vfork.S (__vfork): Likewise.
+       * sysdeps/unix/sysv/linux/powerpc/powerpc32/vfork.S (__vfork):
+       Likewise.
+       * sysdeps/unix/sysv/linux/powerpc/powerpc64/vfork.S (__vfork):
+       Likewise.
+       * sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S (__vfork): Likewise.
+       * sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S (__vfork): Likewise.
+       * sysdeps/unix/sysv/linux/ia64/pt-vfork.S: Include tcb-offsets.h.
+       * sysdeps/unix/sysv/linux/ia64/vfork.S (__vfork): Use DO_CALL instead
+       of DO_CALL_VIA_BREAK.  Work around a gas problem.
+
+       * sysdeps/unix/sysv/linux/powerpc/pt-vfork.S: Remove.
+       * sysdeps/unix/sysv/linux/powerpc/powerpc32/vfork.S: New file.
+       * sysdeps/unix/sysv/linux/powerpc/powerpc32/pt-vfork.S: New file.
+       * sysdeps/unix/sysv/linux/powerpc/powerpc64/vfork.S: New file.
+       * sysdeps/unix/sysv/linux/powerpc/powerpc64/pt-vfork.S: New file.
+       * sysdeps/powerpc/tcb-offsets.sym: Add PID.
+
+       * sysdeps/unix/sysv/linux/ia64/pt-vfork.S (__vfork): Don't use
+       a local register for saving old PID.  Negate PID in parent upon exit.
+
+       * sysdeps/unix/sysv/linux/s390/s390-32/pt-vfork.S: Include
+       tcb-offsets.h.
+       (__vfork): Negate PID if non-zero and set to INT_MIN if zero
+       before syscall, set to the old value in the parent afterwards.
+       * sysdeps/unix/sysv/linux/s390/s390-32/vfork.S: New file.
+       * sysdeps/unix/sysv/linux/s390/s390-64/pt-vfork.S: Include
+       tcb-offsets.h.
+       (__vfork): Negate PID if non-zero and set to INT_MIN if zero
+       before syscall, set to the old value in the parent afterwards.
+       * sysdeps/unix/sysv/linux/s390/s390-64/vfork.S: New file.
+       * sysdeps/s390/tcb-offsets.sym: Add PID.
+
+       * sysdeps/unix/sysv/linux/sparc/pt-vfork.S: Remove.
+       * sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S: New file.
+       * sysdeps/unix/sysv/linux/sparc/sparc32/pt-vfork.S: New file.
+       * sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S: New file.
+       * sysdeps/unix/sysv/linux/sparc/sparc64/pt-vfork.S: New file.
+       * sysdeps/sparc/tcb-offsets.sym: Add PID.
+
+2004-03-10  Andreas Schwab  <schwab@suse.de>
+
+       * sysdeps/ia64/tcb-offsets.sym: Add PID.
+       * sysdeps/unix/sysv/linux/ia64/vfork.S: New file.
+       * sysdeps/unix/sysv/linux/ia64/pt-vfork.S: Properly handle PID cache.
+
+2004-03-09  Jakub Jelinek  <jakub@redhat.com>
+
+       * tst-cancel20.c (do_one_test): Clear in_sh_body first.
+       * tst-cancel21.c (do_one_test): Likewise.
+       Reported by Gordon Jin <gordon.jin@intel.com>.
+
+2004-02-09  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/vfork.S (SAVE_PID): Negate PID
+       if non-zero and set to INT_MIN if zero.
+       * sysdeps/unix/sysv/linux/x86_64/vfork.S (SAVE_PID): Likewise.
+       * sysdeps/unix/sysv/linux/i386/pt-vfork.S: Include tcb-offsets.h.
+       (SAVE_PID, RESTORE_PID): Define.
+       (__vfork): Use it.
+       * sysdeps/unix/sysv/linux/x86_64/pt-vfork.S: Include tcb-offsets.h.
+       Use relative path to avoid including NPTL i386/vfork.S.
+       (SAVE_PID, RESTORE_PID): Define.
+       * sysdeps/unix/sysv/linux/raise.c: Include limits.h.
+       (raise): Handle THREAD_SELF->pid INT_MIN the same as 0.
+       * Makefile (tests): Add tst-vfork1, tst-vfork2, tst-vfork1x and
+       tst-vfork2x.
+       (tests-reverse): Add tst-vfork1x and tst-vfork2x.
+       * tst-vfork1.c: New test.
+       * tst-vfork2.c: New test.
+       * tst-vfork1x.c: New test.
+       * tst-vfork2x.c: New test.
+
+2004-03-08  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/i386/tcb-offsets.sym: Add PID.
+       * sysdeps/x86_64/tcb-offsets.sym: Likewise.
+       * sysdeps/unix/sysv/linux/i386/vfork.S: New file.
+       * sysdeps/unix/sysv/linux/x86_64/vfork.S: New file.
+
+2004-03-08  Steven Munroe  <sjmunroe@us.ibm.com>
+
+       * sysdeps/unix/sysv/linux/powerpc/Versions: Remove leading tabs.
+
+2004-03-08  H.J. Lu  <hongjiu.lu@intel.com>
+
+       * sysdeps/s390/tls.h (INIT_SYSINFO): _dl_sysinfo is now in
+       _rtld_global_ro.
+
+2004-03-07  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/ia64/tls.h (INIT_SYSINFO): _dl_sysinfo is now in
+       _rtld_global_ro.
+
+       * tst-once4.c: Remove unnecessary macro definition.
+
+       * tst-mutex7.c (do_test): Limit thread stack size.
+       * tst-once2.c (do_test): Likewise.
+       * tst-tls3.c (do_test): Likewise.
+       * tst-tls1.c (do_test): Likewise.
+       * tst-signal3.c (do_test): Likewise.
+       * tst-kill6.c (do_test): Likewise.
+       * tst-key4.c (do_test): Likewise.
+       * tst-join4.c (do_test): Likewise.
+       * tst-fork1.c (do_test): Likewise.
+       * tst-context1.c (do_test): Likewise.
+       * tst-cond2.c (do_test): Likewise.
+       * tst-cond10.c (do_test): Likewise.
+       * tst-clock2.c (do_test): Likewise.
+       * tst-cancel10.c (do_test): Likewise.
+       * tst-basic2.c (do_test): Likewise.
+       * tst-barrier4.c (do_test): Likewise.
+
+2004-03-05  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/i386/tls.h: Use GLRO instead of GL where appropriate.
+
+2004-03-01  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S
+       (__pthread_cond_timedwait): Optimize wakeup test.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S
+       (__pthread_cond_wait): Likewise.
+       * sysdeps/pthread/pthread_cond_wait.c (__pthread_cond_wait): Likewise.
+       * sysdeps/pthread/pthread_cond_timedwait.c (__pthread_cond_timedwait):
+       Likewise.
+
+2004-02-29  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S
+       (__lll_mutex_lock_wait): Optimize a bit more.  Just one copy of
+       the atomic instruction needed.
+       * sysdeps/unix/sysv/linux/x86_64/lowlevellock.S
+       (__lll_mutex_lock_wait): Likewise.
+
+2004-02-28  Ulrich Drepper  <drepper@redhat.com>
+
+       * Makefile (tests): Add tst-cond14 and tst-cond15.
+       * tst-cond14.c: New file.
+       * tst-cond15.c: New file.
+
+2004-02-27  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/createthread.c (create_thread): Remove use of
+       CLONE_STOPPED.  We cannot use SIGCONT which means CLONE_STOPPED
+       needs to be implemented differently to be useful.
+
+2004-02-26  Ulrich Drepper  <drepper@redhat.com>
+
+       * pthread_attr_setschedparam.c: Don't test priority against limits
+       here.  Set ATTR_FLAG_SCHED_SET flag.
+       * pthread_attr_setschedpolicy.c: Set ATTR_FLAG_POLICY_SET flag.
+       * pthread_create.c (__pthread_create_2_1): Copy scheduling attributes
+       from parent thread to child.  If attribute is used and scheduling
+       parameters are not inherited, copy parameters from attribute or
+       compute them.  Check priority value.
+       * pthread_getschedparam.c: If the parameters aren't known yet get
+       them from the kernel.
+       * pthread_setschedparam.c: Set ATTR_FLAG_SCHED_SET and
+       ATTR_FLAG_POLICY_SET flag for thread.
+       * sysdeps/unix/sysv/linux/internaltypes.h: Define ATTR_FLAG_SCHED_SET
+       and ATTR_FLAG_POLICY_SET.
+
+       * sysdeps/pthread/createthread.c: Use tgkill if possible.
+
+       * pthread_attr_getstackaddr.c (__pthread_attr_getstackaddr): Don't
+       fail if stack address hasn't been set.  Just return 0.
+
+2004-02-25  Ulrich Drepper  <drepper@redhat.com>
+
+       * Makefile (tests-nolibpthread): Add tst-unload.  Don't link with
+       libpthread for the files in this list.
+       (CFLAGS-tst-unload): Removed.
+       * tst-unload.c (do_test): Don't use complete path for
+       LIBPHREAD_SO.
+
+       * Makefile: Define sonames for tst-tls5mod, tst-_res1mod1, and
+       tst-_res1mod2.
+
+2004-02-22  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S
+       (__lll_mutex_lock_wait): Rewrite so that only one locked memory
+       operation per round is needed.
+       * sysdeps/unix/sysv/linux/x86_64/lowlevellock.S
+       (__lll_mutex_lock_wait): Likewise.
+
+2004-02-20  Ulrich Drepper  <drepper@redhat.com>
+
+       * tst-cancel9.c (cleanup): Don't print to stderr.
+
+2004-02-20  Kaz Kojima  <kkojima@rr.iij4u.or.jp>
+
+       * sysdeps/sh/jmpbuf-unwind.h (_JMPBUF_UNWINDS_ADJ): Fix variable name.
+
+2004-02-20  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/sparc/sparc32/sysdep-cancel.h
+       (__syscall_error_handler2): Call CDISABLE.
+       * sysdeps/unix/sysv/linux/sparc/sparc64/sysdep-cancel.h
+       (__syscall_error_handler2): Call CDISABLE.
+
+       * sysdeps/pthread/pthread_barrier_wait.c (pthread_barrier_wait):
+       Release lock before the loop, don't reacquire it.
+
+       * sysdeps/unix/sysv/linux/ia64/dl-sysdep.h (DL_ARGV_NOT_RELRO): Define.
+
+2004-02-19  Andreas Schwab  <schwab@suse.de>
+
+       * sysdeps/pthread/pthread_barrier_wait.c (pthread_barrier_wait):
+       Fix last change.
+
+2004-02-18  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_barrier_wait.S
+       (pthread_barrier_wait): After wakeup, release lock only when the
+       last thread stopped using the barrier object.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_barrier_wait.S
+       (pthread_barrier_wait): Likewise.
+       * sysdeps/pthread/pthread_barrier_wait.c (pthread_barrier_wait):
+       Likewise.
+       * Makefile (tests): Add tst-barrier4.
+       * tst-barrier4.c: New file.
+
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S
+       (__pthread_cond_timedwait): Perform timeout test while holding
+       internal lock to prevent wakeup race.
+       Patch by Dinakar Guniguntala <dgunigun@in.ibm.com>.
+       * sysdeps/pthread/pthread_cond_timedwait.c
+       (__pthread_cond_timedwait): Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S
+       (__pthread_cond_timedwait): Likewise.
+
+2004-02-18  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_unlock.S
+       (__pthread_rwlock_unlock): Access WRITER as 32-bit value.
+       * Makefile (tests): Add tst-rwlock13.
+       * tst-rwlock13.c: New test.
+
+2004-02-16  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S
+       (__condvar_tw_cleanup): Little optimization.
+       Patch by Dinakar Guniguntala <dgunigun@in.ibm.com>.
+
+2004-02-16  Steven Munroe  <sjmunroe@us.ibm.com>
+
+       * sysdeps/unix/sysv/linux/powerpc/pt-longjmp.c: Replace libc with
+       libpthread as "lib" parameter to SHLIB_COMPAT.
+       (__novmx_siglongjmp): Fix typo in function name.
+       (__novmx_longjmp): Fix typo in function name.
+
+2004-02-13  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/pthread_cond_wait.c (__pthread_cond_wait): Add a
+       __builtin_expect.
+
+       * sysdeps/generic/pt-longjmp.c: Moved to...
+       * sysdeps/pthread/pt-longjmp.c: ...here.  New file.
+
+2004-01-29  Steven Munroe  <sjmunroe@us.ibm.com>
+
+       * Makefile (libpthread-routines): Add pt-cleanup.
+       * pt-longjmp.c: Removed.
+       * pt-cleanup.c: Copied __pthread_cleanup_upto to here. New file.
+       * sysdeps/generic/pt-longjmp.c: Copied longjmp to here. New file.
+       * sysdeps/unix/sysv/linux/powerpc/Versions: New file.
+       Version longjmp, siglongjmp for GLIBC_2.3.4.
+       * sysdeps/unix/sysv/linux/powerpc/pt-longjmp.c: New File.
+
+2004-02-13  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/pthread_cond_timedwait.c
+       (__pthread_cond_timedwait): Optimize.  Drop internal lock earlier.
+       Reuse code.  Add __builtin_expects.
+
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S
+       (__pthread_cond_timedwait): Get internal lock in case timeout has
+       passed before the futex syscall.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: Likewise.
+
+2004-01-20  Ulrich Drepper  <drepper@redhat.com>
+
+       * allocatestack.c: Pretty printing.
+
+       * sysdeps/pthread/createthread.c (create_thread): Don't add
+       CLONE_DETACHED bit if it is not necessary.
+
+2004-01-16  Ulrich Drepper  <drepper@redhat.com>
+
+       * pthread_getattr_np.c: Include ldsodefs.h.
+
+2004-01-16  Richard Henderson  <rth@redhat.com>
+
+       * allocatestack.c: Don't declare __libc_stack_end.
+       * init.c (__pthread_initialize_minimal_internal): Likewise.
+       * pthread_getattr_np.c (pthread_getattr_np): Likewise.
+
+2004-01-15  Richard Henderson  <rth@redhat.com>
+
+       * sysdeps/alpha/tls.h (tcbhead_t): Add private.
+       (TLS_INIT_TCB_SIZE, TLS_INIT_TCB_ALIGN, TLS_TCB_SIZE,
+       TLS_PRE_TCB_SIZE, TLS_TCB_ALIGN, INSTALL_DTV, INSTALL_NEW_DTV,
+       GET_DTV, THREAD_DTV, THREAD_SELF, DB_THREAD_SELF): Match ia64.
+       (TLS_TCB_OFFSET, THREAD_ID, NO_TLS_OFFSET): Remove.
+       (THREAD_GETMEM, THREAD_GETMEM_NC): Simplify.
+       (THREAD_SETMEM, THREAD_SETMEM_NC): Likewise.
+       * sysdeps/unix/sysv/linux/alpha/createthread.c (TLS_VALUE): Match ia64.
+
+2004-01-14  Ulrich Drepper  <drepper@redhat.com>
+
+       * init.c (pthread_functions): Make array const.
+
+2004-01-13  Ulrich Drepper  <drepper@redhat.com>
+
+       * allocatestack.c (__make_stacks_executable): Change interface.
+       Check parameters.  Pass parameter on to libc counterpart.
+       * pthreadP.h: Change declaration.
+
+2004-01-13  Richard Henderson  <rth@redhat.com>
+
+       * pthread_attr_setstack.c (__old_pthread_attr_setstack): Use
+       prototype form.
+       * pthread_attr_setstacksize.c (__old_pthread_attr_setstacksize):
+       Likewise.
+
+       * sysdeps/alpha/Makefile: New file.
+       * sysdeps/alpha/tcb-offsets.sym: New file.
+       * sysdeps/unix/sysv/linux/alpha/sysdep-cancel.h (SINGLE_THREAD_P):
+       Use MULTIPLE_THREADS_OFFSET to implement !libpthread !libc version.
+
+       * sysdeps/unix/sysv/linux/alpha/lowlevellock.h: Rewrite based
+       on powerpc version.
+
+2004-01-08  Jakub Jelinek  <jakub@redhat.com>
+
+       * Makefile (tests): Add tst-backtrace1.
+       * tst-backtrace1.c: New test.
+
+2003-12-11  Ulrich Weigand  <uweigand@de.ibm.com>
+
+       * sysdeps/alpha/tls.h (DB_THREAD_SELF): Pass bit size of thread
+       register as second parameter to the REGISTER macro.
+       * sysdeps/ia64/tls.h (DB_THREAD_SELF): Likewise.
+       * sysdeps/powerpc/tls.h (DB_THREAD_SELF): Likewise.
+       * sysdeps/sh/tls.h (DB_THREAD_SELF): Likewise.
+       * sysdeps/sparc/tls.h (DB_THREAD_SELF): Likewise.
+       * sysdeps/s390/tls.h (DB_THREAD_SELF): Pass __WORDSIZE as bit size
+       of thread register as second parameter to REGISTER macro in 64 case.
+
+2004-01-03  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/Makefile (CFLAGS-getpid.c): Removed.
+       (CFLAGS-getpid.o): Defined.
+       (CFLAGS-getpid.os): Defined.
+
+2003-12-31  Ulrich Drepper  <drepper@redhat.com>
+
+       * pthread_getattr_np.c (pthread_getattr_np): Make sure stack info
+       returned for main thread does not overlap with any other VMA.
+       Patch by Jakub Jelinek.
+
+2003-12-29  Jakub Jelinek  <jakub@redhat.com>
+
+       * tst-raise1.c: Include stdio.h.
+
+2003-12-23  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/raise.c (raise): Protect pid = selftid
+       setting with __ASSUME_TGKILL || defined __NR_tgkill.
+       If pid is 0, set it to selftid.
+       * sysdeps/unix/sysv/linux/getpid.c (really_getpid): Make inline.
+       Don't set self->pid but self->tid.  If self->pid == 0 and self->tid
+       != 0, return self->tid without doing a syscall.
+       * descr.h (struct pthread): Move pid field after tid.
+
+       * Makefile (tests): Add tst-raise1.
+       * tst-raise1.c: New file.
+
+2003-12-23  Roland McGrath  <roland@redhat.com>
+
+       * tst-oddstacklimit.c: New file.
+       * Makefile (tests): Add it.
+       (tst-oddstacklimit-ENV): New variable.
+
+       * init.c (__pthread_initialize_minimal_internal): Round stack rlimit
+       value up to page size for __default_stacksize.
+
+2003-12-21  Ulrich Drepper  <drepper@redhat.com>
+
+       * Makefile (tests): Add tst-eintr5.
+       * tst-eintr5.c: New file.
+
+       * eintr.c (eintr_source): Prevent sending signal to self.
+
+       * tst-eintr2.c (tf1): Improve error message.
+
+2003-12-20  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/Makefile (CFLAGS-getpid.c): Define.
+       * sysdeps/unix/sysv/linux/getpid.c: New file.
+       * pthread_cancel.c: Add comment explaining use of PID field.
+       * sysdeps/unix/sysv/linux/pthread_kill.c: Likewise.
+       * pthread_getattr_np.c: Use abs() when comparing PID and TID fields.
+       * sysdeps/unix/sysv/linux/fork.c: Negate PID field of parent
+       temporarily to signal the field must not be relied on and updated
+       by getpid().
+       * sysdeps/unix/sysv/linux/pt-raise.c: Handle case where PID is
+       temporarily negative.
+       * sysdeps/unix/sysv/linux/raise.c: Likewise.
+
+2003-12-19  Ulrich Drepper  <drepper@redhat.com>
+
+       * eintr.c (setup_eintr): Add new parameter.  Pass to thread function.
+       (eintr_source): If ARG != NULL, use pthread_kill.
+       * tst-eintr1.c: Adjust for this change.
+       * tst-eintr2.c: Likewise.
+       * Makefile (tests): Add tst-eintr3 and tst-eintr4.
+       * tst-eintr3.c: New file.
+       * tst-eintr4.c: New file.
+
+2003-12-19  Jakub Jelinek  <jakub@redhat.com>
+
+       * libc-cancellation.c (__libc_enable_asynccancel): Don't cancel
+       if CANCELSTATE_BITMASK is set.
+       * sysdeps/pthread/librt-cancellation.c (__librt_enable_asynccancel):
+       Likewise.
+
+       * Makefile (tests): Add tst-cancel22 and tst-cancel23.
+       (tests-reverse): Add tst-cancel23.
+       * tst-cancel22.c: New test.
+       * tst-cancel23.c: New test.
+
+2003-12-18  Ulrich Drepper  <drepper@redhat.com>
+
+       * tst-eintr1.c: Better error messages.
+
+       * Makefile (tests): Add tst-eintr2.
+       * tst-eintr2.c: New file.
+
+2003-12-18  Jakub Jelinek  <jakub@redhat.com>
+
+       * Makefile (tests): Add tst-cancel21 and tst-cancelx21.
+       (CFLAGS-tst-cancelx21.c): Set.
+       * tst-cancel21.c: New test.
+       * tst-cancelx21.c: New test.
+
+       * unwind.c (FRAME_LEFT): Add adj argument.  Subtract it from each
+       comparison operand.
+       (unwind_stop): Use _JMPBUF_CFA_UNWINDS_ADJ macro instead of
+       _JMPBUF_CFA_UNWINDS.  Adjust FRAME_LEFT invocations.
+       * pt-longjmp.c: Include jmpbuf-unwind.h.
+       (__pthread_cleanup_upto): Use _JMPBUF_UNWINDS_ADJ macro instead of
+       _JMPBUF_UNWINDS.  Adjust compared pointers.
+       * init.c (__pthread_initialize_minimal_internal): Initialize
+       pd->stackblock_size.
+       * sysdeps/pthread/jmpbuf-unwind.h: Removed.
+       * sysdeps/alpha/jmpbuf-unwind.h: New file.
+       * sysdeps/i386/jmpbuf-unwind.h: New file.
+       * sysdeps/powerpc/jmpbuf-unwind.h: New file.
+       * sysdeps/s390/jmpbuf-unwind.h: New file.
+       * sysdeps/sh/jmpbuf-unwind.h: New file.
+       * sysdeps/sparc/sparc32/jmpbuf-unwind.h: New file.
+       * sysdeps/x86_64/jmpbuf-unwind.h: New file.
+       * sysdeps/unix/sysv/linux/ia64/jmpbuf-unwind.h: Include stdint.h.
+       (_JMPBUF_CFA_UNWINDS): Remove.
+       (_JMPBUF_CFA_UNWINDS_ADJ, _JMPBUF_UNWINDS_ADJ): Define.
+
+2003-12-12  Jakub Jelinek  <jakub@redhat.com>
+
+       * Makefile (tests): Add tst-cancel20 and tst-cancelx20.
+       (CFLAGS-tst-cancelx20.c): Set.
+       * tst-cancel20.c: New test.
+       * tst-cancelx20.c: New test.
+
+2003-12-17  Ulrich Drepper  <drepper@redhat.com>
+
+       * init.c (__pthread_initialize_minimal_internal): Don't treat
+       architectures with separate register stack special here when
+       computing default stack size.
+
+2003-12-17  Roland McGrath  <roland@redhat.com>
+
+       * Makefile (tst-cancelx7-ARGS): New variable.
+       Reportd by Greg Schafer <gschafer@zip.com.au>.
+
+2003-12-17  Jakub Jelinek  <jakub@redhat.com>
+
+       * Makefile (tests): Add tst-stack3.  Depend on $(objpfx)tst-stack3-mem.
+       (generated): Add tst-stack3.mtrace and tst-stack3-mem.
+       (tst-stack3-ENV): Set.
+       ($(objpfx)tst-stack3-mem): New.
+       * tst-stack3.c: New test.
+
+2003-12-10  David Mosberger  <davidm@hpl.hp.com>
+
+       * sysdeps/unix/sysv/linux/ia64/pt-initfini.c (_init_EPILOG_BEGINS):
+       Add unwind directives.  Drop unused .regstk directive.
+       (_fini_EPILOG_BEGINS): Add unwind directives.
+
+2003-12-11  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/lowlevellock.h (lll_futex_wait):
+       Assume parameter is a pointer.
+       (lll_futex_wake): Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h (lll_futex_wait):
+       Likewise.
+       (lll_futex_wake): Likewise.
+       Reported by Boris Hu.
+       * sysdeps/unix/sysv/linux/unregister-atfork.c
+       (__unregister_atfork): Pass pointer to refcntr to lll_futex_wait.
+
+       * sysdeps/unix/sysv/linux/sem_wait.c (__new_sem_wait): Simplify a bit.
+
+2003-12-10  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/bits/libc-lock.h (__rtld_lock_initialize): Define.
+       * sysdeps/unix/sysv/linux/fork.c (__libc_fork): Call
+       __rtld_lock_initialize for ld.so lock.
+       Patch in part by Adam Li <adam.li@intel.com>.
+
+2003-12-02  David Mosberger  <davidm@hpl.hp.com>
+
+       * Makefile (link-libc-static): Remove -lgcc_eh---it's already mentioned
+       in $(gnulib).  Also, remove stale comment.
+
+2003-11-12  David Mosberger  <davidm@hpl.hp.com>
+
+       * sysdeps/unix/sysv/linux/ia64/sysdep-cancel.h (PSEUDO): Take
+       advantage of new syscall stub and optimize accordingly.
+
+       * sysdeps/unix/sysv/linux/ia64/lowlevellock.h (__NR_futex): Rename
+       from SYS_futex, to match expectations of
+       sysdep.h:DO_INLINE_SYSCALL.
+       (lll_futex_clobbers): Remove.
+       (lll_futex_timed_wait): Rewrite in terms of DO_INLINE_SYSCALL.
+       (lll_futex_wake): Likewise.
+       (lll_futex_requeue): Likewise.
+       (__lll_mutex_trylock): Rewrite to a macro, so we can include this
+       file before DO_INLINE_SYSCALL is defined (proposed by Jakub
+       Jelinek).
+       (__lll_mutex_lock): Likewise.
+       (__lll_mutex_cond_lock): Likewise.
+       (__lll_mutex_timed_lock): Likewise.
+       (__lll_mutex_unlock): Likewise.
+       (__lll_mutex_unlock_force): Likewise.
+
+       * sysdeps/ia64/tls.h: Move declaration of __thread_self up so it
+       comes before the include of <sysdep.h>.
+       (THREAD_SELF_SYSINFO): New macro.
+       (THREAD_SYSINFO): Likewise.
+       (INIT_SYSINFO): New macro.
+       (TLS_INIT_TP): Call INIT_SYSINFO.
+
+       * sysdeps/ia64/tcb-offsets.sym: Add SYSINFO_OFFSET.
+
+       * sysdeps/pthread/createthread.c (create_thread): Use
+       THREAD_SELF_SYSINFO and THREAD_SYSINFO instead of open code.
+       * allocatestack.c (allocate_stack): Use THREAD_SYSINFO and
+       THREAD_SELF_SYSINFO instead of open code.
+       * sysdeps/i386/tls.h (THREAD_SELF_SYSINFO): New macro.
+       (THREAD_SYSINFO): Likewise.
+
+       * sysdeps/unix/sysv/linux/ia64/dl-sysdep.h: New file.
+
+       * sysdeps/unix/sysv/linux/ia64/pt-vfork.S: Work around gas problem.
+
+2003-12-06  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/ia64/pt-initfini.c: Use .init_array
+       instead of .init.  Patch by David Mosberger.
+
+2003-11-30  Thorsten Kukuk  <kukuk@suse.de>
+
+       * sysdeps/pthread/configure.in: Remove broken declaration in C
+       cleanup handling check.
+
+2003-11-30  Andreas Jaeger  <aj@suse.de>
+
+       * Makefile (CFLAGS-pt-initfini.s): Add $(fno_unit_at_a_time).
+       * sysdeps/unix/sysv/linux/x86_64/Makefile (CFLAGS-pt-initfini.s):
+       Likewise.
+
+2003-11-27  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/internaltypes.h (ATTR_FLAG_OLDATTR): Define.
+       * pthread_attr_destroy.c: Include shlib-compat.h.
+       (__pthread_attr_destroy): Return immediately if ATTR_FLAG_OLDATTR
+       is set in iattr->flags.
+       * pthread_attr_init.c (__pthread_attr_init_2_0): Set ATTR_FLAG_OLDATTR.
+
+2003-11-21  Jakub Jelinek  <jakub@redhat.com>
+
+       * Makefile (distribute): Add tst-cleanup4aux.c.
+
+       * tst-cond12.c (prepare): Add prototype.  Move after test-skeleton.c
+       include.
+
+2003-11-21  Ulrich Drepper  <drepper@redhat.com>
+
+       * tst-cond12.c (do_test): If USE_COND_SIGNAL is defined, use
+       pthread_cond_signal.
+
+       * sysdeps/pthread/pthread_cond_wait.c (__pthread_cond_wait): Don't
+       store mutex address if the current value is ~0l.
+       * sysdeps/pthread/pthread_cond_timedwait.c
+       (__pthread_cond_timedwait): Likewise.
+       * sysdeps/pthread/pthread_cond_broadcast.c
+       (__pthread_cond_broadcast): Don't use requeue for pshared
+       condvars.
+
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S
+       (__pthread_cond_wait): Don't store mutex address if the current
+       value is ~0l.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S
+       (__pthread_cond_timedwait): Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S
+       (__pthread_cond_broadcast): Don't use requeue for pshared
+       condvars.
+
+       * pthread_cond_init.c (__pthread_cond_init): Initialize __mutex
+       element with ~0l for pshared condvars, with NULL otherwise.
+
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S
+       (__pthread_cond_wait): Don't store mutex address if the current
+       value is ~0l.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S
+       (__pthread_cond_timedwait): Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S
+       (__pthread_cond_broadcast): Don't use requeue for pshared
+       condvars.
+
+       * Makefile: Add rules to build and run tst-cond12 and tst-cond13.
+       * tst-cond12.c: New file.
+       * tst-cond13.c: New file.
+
+2003-11-17  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/configure.in: Make missing forced unwind support
+       fatal.
+
+2003-11-11  Ulrich Drepper  <drepper@redhat.com>
+
+       * pthreadP.h: Don't declare __pthread_unwind as weak inside libpthread.
+
+2003-11-06  Ulrich Drepper  <drepper@redhat.com>
+
+       * Makefile: Add magic to clean up correctly.
+
+2003-11-05  Jakub Jelinek  <jakub@redhat.com>
+
+       * unwind.c (FRAME_LEFT): Define.
+       (unwind_stop): Handle old style cleanups here.
+       (__pthread_unwind): Handle old style cleanups only if
+       !HAVE_FORCED_UNWIND.
+       * Makefile (tests): Add tst-cleanup4 and tst-cleanupx4.
+       (CFLAGS-tst-cleanupx4.c): Add -fexceptions.
+       ($(objpfx)tst-cleanup4): Depend on $(objpfx)tst-cleanup4aux.o.
+       ($(objpfx)tst-cleanupx4): Likewise.
+       * tst-cleanup4.c: New test.
+       * tst-cleanup4aux.c: New.
+       * tst-cleanupx4.c: New test.
+
+2003-11-04  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/bits/stdio-lock.h: Use lll_*lock instead of
+       lll_mutex_*lock macros to skip atomic operations on some archs.
+
+2003-11-03  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/tst-timer.c (main): Initialize
+       sigev2.sigev_value as well.
+
+2003-10-15  Roland McGrath  <roland@redhat.com>
+
+       * sysdeps/pthread/configure.in: Barf if visibility attribute support
+       is missing.
+       * sysdeps/pthread/configure: Regenerated.
+
+2003-10-09  Kaz Kojima  <kkojima@rr.iij4u.or.jp>
+
+       * sysdeps/unix/sysv/linux/sh/lowlevellock.h: Completely revamp the
+       locking macros.  No distinction between normal and mutex locking
+       anymore.
+       * sysdeps/unix/sysv/linux/sh/lowlevellock.S: Rewrite mutex locking.
+       Merge bits from lowlevelmutex.S we still need.
+       * sysdeps/unix/sysv/linux/sh/libc-lowlevelmutex.S: Remove.
+       * sysdeps/unix/sysv/linux/sh/lowlevelmutex.S: Likewise.
+       * sysdeps/unix/sysv/linux/sh/not-cancel.h: New file.
+       * sysdeps/unix/sysv/linux/sh/pthread_barrier_wait.S: Adjust for
+       new mutex implementation.
+       * sysdeps/unix/sysv/linux/sh/pthread_cond_broadcast.S: Likewise.
+       * sysdeps/unix/sysv/linux/sh/pthread_cond_signal.S: Likewise.
+       * sysdeps/unix/sysv/linux/sh/pthread_cond_timedwait.S: Likewise.
+       * sysdeps/unix/sysv/linux/sh/pthread_cond_wait.S: Likewise.
+       * sysdeps/unix/sysv/linux/sh/pthread_rwlock_rdlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedrdlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedwrlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/sh/pthread_rwlock_unlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/sh/pthread_rwlock_wrlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/sh/sysdep-cancel.h (PSEUDO): Also defined
+       symbol for entry point to avoid cancellation.
+
+2003-10-07  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h: Backout 2003-10-02
+       changes.
+       (SAVE_OLDTYPE_0): Fix a typo.
+
+2003-10-03  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/pthread_once.S (__pthread_once):
+       Check __sigsetjmp return value.  Reported by Daniel Jacobowitz.
+
+2003-10-02  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h (DOCARGS_1): Use
+       correct offset.
+
+2003-10-02  Jakub Jelinek  <jakub@redhat.com>
+
+       * Makefile (tests): Add tst-cancel19.
+       * tst-cancel19.c: New test.
+
+2003-10-02  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h: Fix saving and
+       restoring of the old cancellation type.
+
+2003-09-30  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/pthread/malloc-machine.h: Remove misleading comment.
+
+2003-09-27  Wolfram Gloger  <wg@malloc.de>
+
+       * sysdeps/pthread/malloc-machine.h: New file
+
+2003-09-24  Roland McGrath  <roland@redhat.com>
+
+       * allocatestack.c (__make_stacks_executable): Don't ignore return
+       value from _dl_make_stack_executable.
+
+2003-09-24  Ulrich Drepper  <drepper@redhat.com>
+
+       * allocatestack.c (__make_stacks_executable): Also change
+       permission of the currently unused stacks.
+
+       * allocatestack.c (change_stack_perm): Split out from
+       __make_stacks_executable.
+       (allocate_stack): If the required permission changed between the time
+       we started preparing the stack and queueing it, change the permission.
+       (__make_stacks_executable): Call change_stack_perm.
+
+       * Makefile: Build tst-execstack-mod locally.
+       * tst-execstack-mod.c: New file.
+
+2003-09-23  Jakub Jelinek  <jakub@redhat.com>
+
+       * Makefile (tests): Only add tst-execstack if have-z-execstack is yes.
+
+2003-09-23  Roland McGrath  <roland@redhat.com>
+
+       * tst-execstack.c: New file.
+       * Makefile (tests): Add it.
+       ($(objpfx)tst-execstack, $(objpfx)tst-execstack.out): New targets.
+       (LDFLAGS-tst-execstack): New variable.
+
+       * allocatestack.c (allocate_stack): Use GL(dl_stack_flags) to decide
+       whether to use PROT_EXEC for stack mmap.
+       (__make_stacks_executable): New function.
+       * pthreadP.h: Declare it.
+       * init.c (__pthread_initialize_minimal_internal): Set
+       GL(dl_make_stack_executable_hook) to that.
+
+2003-09-22  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h: Adjust for latest
+       recommendation from AMD re avoidance of lock prefix.
+
+2003-09-22  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/lowlevellock.c (__lll_timedlock_wait): Use
+       lll_futex_timed_wait instead of lll_futex_wait.
+       * sysdeps/unix/sysv/linux/s390/lowlevellock.c: Removed.
+       * sysdeps/unix/sysv/linux/s390/lowlevelmutex.c: Removed.
+       * sysdeps/unix/sysv/linux/s390/libc-lowlevellock.c: Removed.
+       * sysdeps/unix/sysv/linux/s390/libc-lowlevelmutex.c: Removed.
+       * sysdeps/unix/sysv/linux/s390/sem_trywait.c: Removed.
+       * sysdeps/unix/sysv/linux/s390/sem_wait.c: Removed.
+       * sysdeps/unix/sysv/linux/s390/sem_post.c: Removed.
+       * sysdeps/unix/sysv/linux/s390/sem_timedwait.c: Removed.
+       * sysdeps/unix/sysv/linux/s390/lowlevellock.h: Include atomic.h.
+       Completely revamp the locking macros.  No distinction between
+       normal and mutex locking anymore.
+       * sysdeps/unix/sysv/linux/sparc/lowlevellock.h: Likewise.
+       * sysdeps/unix/sysv/linux/ia64/lowlevellock.h (__lll_lock_wait,
+       __lll_lock_timedwait): Fix prototypes.
+       * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h (__lll_lock_wait,
+       __lll_lock_timedwait): Likewise.
+       (lll_mutex_lock, lll_mutex_cond_lock): Use _val instead of _bool
+       macros, add __builtin_expect.
+       (lll_mutex_timedlock): Likewise.  Fix return value.
+       * sysdeps/unix/sysv/linux/i386/i486/libc-lowlevelmutex.S: Removed.
+       * sysdeps/unix/sysv/linux/i386/i586/libc-lowlevelmutex.S: Removed.
+       * sysdeps/unix/sysv/linux/i386/i586/lowlevelmutex.S: Removed.
+       * sysdeps/unix/sysv/linux/i386/i686/libc-lowlevelmutex.S: Removed.
+       * sysdeps/unix/sysv/linux/i386/i686/lowlevelmutex.S: Removed.
+       * sysdeps/unix/sysv/linux/x86_64/libc-lowlevelmutex.S: Removed.
+       * sysdeps/unix/sysv/linux/lowlevelmutex.c: Removed.
+       * sysdeps/unix/sysv/linux/libc-lowlevelmutex.c: Removed.
+
+2003-09-22  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S
+       (__lll_mutex_lock_wait): Minor optimization to avoid one atomic
+       operation if possible.
+
+       * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h: Don't play tricks
+       like jumping over the lock prefix.
+
+2003-09-21  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/lowlevellock.h: Completely revamp the
+       locking macros.  No distinction between normal and mutex locking
+       anymore.
+       * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h: Likewise.
+       * sysdeps/unix/sysv/linux/ia64/lowlevellock.h: Likewise.
+       * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S: Rewrite mutex
+       locking.  Merge bits from lowlevelmutex.S we still need.
+       * sysdeps/unix/sysv/linux/x86_64/lowlevellock.S: Likewise.
+       * sysdeps/unix/sysv/linux/lowlevellock.c: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/lowlevelmutex.S: Removed.
+       * sysdeps/unix/sysv/linux/x86_64/lowlevelmutex.S: Removed.
+       * Makefile (routines): Remove libc-lowlevelmutex.
+       (libpthread-rountines): Remove lowlevelmutex.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_barrier_wait.S: Adjust
+       for new mutex implementation.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_rdlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedrdlock.S:
+       Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedwrlock.S:
+       Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_unlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_wrlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_barrier_wait.S: Likewise
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_rdlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedrdlock.S:
+       Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedwrlock.S:
+       Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_unlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_wrlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_signal.S: Likewise.
+       Don't use requeue.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_signal.S: Likewise.
+       * sysdeps/pthread/pthread_cond_signal.c: Don't use requeue.
+
+2003-09-20  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/lowlevellock.h: Don't match memory
+       in parameters of asm with output parameters.
+
+       * pthread_mutex_unlock.c (__pthread_mutex_unlock_usercnt): Change
+       type of DECR parameter to int.
+       * pthreadP.h: Adjust prototype of __pthread_mutex_unlock_usercnt.
+
+2003-09-18  Jakub Jelinek  <jakub@redhat.com>
+
+       * tst-attr3.c (tf, do_test): Print stack start/end/size and
+       guardsize for each thread.
+
+2003-09-17  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/pthread/pthread.h (pthread_getattr_np): Clarify usage.
+       * sysdeps/unix/sysv/linux/pthread_attr_setaffinity.c
+       (pthread_attr_setaffinity_np): Handle cpuset == NULL.
+
+       * sysdeps/unix/sysv/linux/pthread_attr_getaffinity.c
+       (pthread_attr_getaffinity_np): Don't segfault if iattr->cpuset is
+       NULL.
+       * pthread_getattr_np.c: Set cpuset using pthread_getaffinity_np.
+       * pthreadP.h (pthread_getaffinity_np): Add hidden_proto.
+       * sysdeps/unix/sysv/linux/pthread_getaffinity.c
+       (pthread_getaffinity_np): Add hidden_def.
+
+       * Makefile (tests): Add tst-attr3.
+       * tst-attr3.c: New test.
+
+       * sysdeps/i386/Makefile (CFLAGS-tst-align.c): Remove.
+
+2003-09-15  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/i386/Makefile (CFLAGS-pthread_create.c,
+       CFLAGS-tst-align.c): Add -mpreferred-stack-boundary=4.
+
+2003-09-17  Jakub Jelinek  <jakub@redhat.com>
+
+       * Makefile (CFLAGS-tst-align.c): Add $(stack-align-test-flags).
+       * tst-align.c: Include tst-stack-align.h.
+       (tf, do_test): Use TEST_STACK_ALIGN macro.
+
+2003-09-17  Ulrich Drepper  <drepper@redhat.com>
+
+       * pthread_attr_init.c (__pthread_attr_init_2_0): Remove unused
+       variable.
+
+2003-09-16  Ulrich Drepper  <drepper@redhat.com>
+
+       * pthread_getattr_np.c (pthread_getattr_np): Correctly fill in the
+       stack-related values for the initial thread.
+
+2003-09-15  Jakub Jelinek  <jakub@redhat.com>
+
+       * Makefile (CFLAGS-pthread_once.c): Add $(uses-callbacks).
+
+2003-09-11  Ulrich Drepper  <drepper@redhat.com>
+
+       * pthread_mutex_lock.c: Minor code rearrangements.
+
+2003-09-05  Roland McGrath  <roland@redhat.com>
+
+       * pthread_create.c (__pthread_pthread_sizeof_descr): Removed.
+       Instead, include ../nptl_db/db_info.c to do its magic.
+       * pthread_key_create.c (__pthread_pthread_keys_max): Removed.
+       (__pthread_pthread_key_2ndlevel_size): Likewise.
+       * sysdeps/alpha/tls.h (DB_THREAD_SELF): New macro.
+       * sysdeps/i386/tls.h (DB_THREAD_SELF): New macro.
+       * sysdeps/ia64/tls.h (DB_THREAD_SELF): New macro.
+       * sysdeps/powerpc/tls.h (DB_THREAD_SELF): New macro.
+       * sysdeps/s390/tls.h (DB_THREAD_SELF): New macro.
+       * sysdeps/sh/tls.h (DB_THREAD_SELF): New macro.
+       * sysdeps/sparc/tls.h (DB_THREAD_SELF): New macro.
+       * sysdeps/x86_64/tls.h (DB_THREAD_SELF): New macro.
+       * sysdeps/alpha/td_ta_map_lwp2thr.c: File removed.
+       * sysdeps/generic/td_ta_map_lwp2thr.c: File removed.
+       * sysdeps/i386/td_ta_map_lwp2thr.c: File removed.
+       * sysdeps/ia64/td_ta_map_lwp2thr.c: File removed.
+       * sysdeps/powerpc/td_ta_map_lwp2thr.c: File removed.
+       * sysdeps/s390/td_ta_map_lwp2thr.c: File removed.
+       * sysdeps/sh/td_ta_map_lwp2thr.c: File removed.
+       * sysdeps/sparc/td_ta_map_lwp2thr.c: File removed.
+       * sysdeps/x86_64/td_ta_map_lwp2thr.c: File removed.
+
+2003-09-08  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: Change type
+       of pthread_t to be compatible with LT.
+       * sysdeps/unix/sysv/linux/sparc/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h: Likewise.
+
+2003-09-04  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/not-cancel.h (fcntl_not_cancel): Define.
+
+2003-09-04  Jakub Jelinek  <jakub@redhat.com>
+
+       * unwind-forcedunwind.c: Move to...
+       * sysdeps/pthread/unwind-forcedunwind.c: ...here.
+       (pthread_cancel_init): Use ARCH_CANCEL_INIT if defined.
+       * sysdeps/pthread/jmpbuf-unwind.h: New file.
+       * sysdeps/unix/sysv/linux/ia64/unwind-forcedunwind.c: New file.
+       * sysdeps/unix/sysv/linux/ia64/jmpbuf-unwind.h: New file.
+       * unwind.c: Include jmpbuf-unwind.h.
+       (unwind_stop): Use _JMPBUF_CFA_UNWINDS macro.
+
+2003-09-02  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/ia64/bits/local_lim.h: New file.
+       * sysdeps/unix/sysv/linux/ia64/Versions (libpthread): Export
+       pthread_attr_setstack and pthread_attr_setstacksize @@GLIBC_2.3.3.
+       * sysdeps/unix/sysv/linux/alpha/bits/local_lim.h: New file.
+       * sysdeps/unix/sysv/linux/alpha/Versions: New file.
+       * sysdeps/unix/sysv/linux/sparc/bits/local_lim.h: New file.
+       * sysdeps/unix/sysv/linux/sparc/Versions: New file.
+       * pthread_attr_setstack.c (__old_pthread_attr_setstack): New function.
+       (pthread_attr_setstack): If PTHREAD_STACK_MIN != 16384, export
+       as @@GLIBC_2.3.2 and also export compatibility @GLIBC_2.2.
+       * pthread_attr_setstacksize.c (__old_pthread_attr_setstacksize): New
+       function.
+       (pthread_attr_setstacksize): If PTHREAD_STACK_MIN != 16384, export
+       as @@GLIBC_2.3.2 and also export compatibility @GLIBC_2.1.
+       * Makefile (tests): Add tst-stack2.
+       * tst-stack2.c: New test.
+       * tst-stack1.c: Include limits.h and sys/param.h.
+       (do_test): Set size to MAX (4 * getpagesize (), PTHREAD_STACK_MIN).
+
+       * pthread_condattr_setpshared.c: Include errno.h.
+       (pthread_condattr_setpshared): Return EINVAL if pshared
+       is neither PTHREAD_PROCESS_PRIVATE nor PTHREAD_PROCESS_SHARED.
+
+       * sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h (PSEUDO): Also
+       defined symbol for entry point to avoid cancellation.
+       * sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h (PSEUDO):
+       Likewise.
+       * sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h (PSEUDO):
+       Likewise.
+       * sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h (PSEUDO):
+       Likewise.
+       * sysdeps/unix/sysv/linux/sparc/sparc32/sysdep-cancel.h (PSEUDO):
+       Likewise.
+       * sysdeps/unix/sysv/linux/sparc/sparc64/sysdep-cancel.h (PSEUDO):
+       Likewise.
+       * sysdeps/unix/sysv/linux/i386/not-cancel.h (__open_nocancel,
+       __close_nocancel, __read_nocancel, __write_nocancel,
+       __waitpid_nocancel): Add attribute_hidden.  If not in libc.so,
+       libpthread.so or librt.so, define to corresponding function
+       without _nocancel suffix.
+       * sysdeps/unix/sysv/linux/s390/not-cancel.h: New file.
+       * sysdeps/unix/sysv/linux/powerpc/not-cancel.h: New file.
+       * sysdeps/unix/sysv/linux/sparc/not-cancel.h: New file.
+
+       * sysdeps/unix/sysv/linux/x86_64/not-cancel.h: Fix a typo.
+
+2003-09-02  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/not-cancel.h: New file.
+       * sysdeps/unix/sysv/linux/x86_64/not-cancel.h: New file.
+
+       * sysdeps/unix/sysv/linux/i386/lowlevellock.h: Make sure the code
+       in subsections has a symbol associated with it.
+
+       * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h (PSEUDO): Also
+       defined symbol for entry point to avoid cancellation.
+       * sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h (PSEUDO): Likewise.
+
+2003-09-01  Jakub Jelinek  <jakub@redhat.com>
+
+       * Makefile (tests): Add tst-tls5.
+       (module-names): Add tst-tls5mod{,a,b,c,d,e,f}.
+       ($(objpfx)tst-tls5mod{,a,b,c,d,e,f}.so-no-z-defs): Set to yes.
+       ($(objpfx)tst-tls5): New.
+       ($(objpfx)tst-tls6.out): Likewise.
+       (tests): Depend on $(objpfx)tst-tls6.out.
+       * tst-tls3.c: Include stdint.h and pthreaddef.h.
+       (do_test): Check pthread_self () return value alignment.
+       * tst-tls3mod.c: Include stdint.h and pthreaddef.h.
+       (tf): Check pthread_self () return value alignment.
+       * tst-tls5.c: New test.
+       * tst-tls5.h: New.
+       * tst-tls5mod.c: New.
+       * tst-tls5moda.c: New.
+       * tst-tls5modb.c: New.
+       * tst-tls5modc.c: New.
+       * tst-tls5modd.c: New.
+       * tst-tls5mode.c: New.
+       * tst-tls5modf.c: New.
+       * tst-tls6.sh: New test.
+
+       * sysdeps/pthread/pthread-functions.h (struct pthread_functions): Add
+       ptr___pthread_cond_timedwait and ptr___pthread_cond_timedwait_2_0.
+       * init.c (pthread_functions): Initialize them.
+       * forward.c (pthread_cond_timedwait@GLIBC_2.0,
+       pthread_cond_timedwait@@GLIBC_2.3.2): New forwards.
+       * Versions (libc): Export pthread_cond_timedwait@GLIBC_2.0,
+       pthread_cond_timedwait@@GLIBC_2.3.2.
+
+2003-09-01  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/alpha/timer_create.c: New file.
+       * sysdeps/unix/sysv/linux/alpha/timer_delete.c: New file.
+       * sysdeps/unix/sysv/linux/alpha/timer_getoverr.c: New file.
+       * sysdeps/unix/sysv/linux/alpha/timer_gettime.c: New file.
+       * sysdeps/unix/sysv/linux/alpha/timer_settime.c: New file.
+       * sysdeps/unix/sysv/linux/alpha/Versions: New file.
+
+       * sysdeps/unix/sysv/linux/alpha/aio_cancel.c: New file.
+
+       * sysdeps/unix/sysv/linux/ia64/bits/posix_opt.h: Define
+       _POSIX_THREAD_PRIORITY_SCHEDULING.
+       * sysdeps/unix/sysv/linux/x86_64/bits/posix_opt.h: Likewise.
+
+2003-08-31  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/bits/stdio-lock.h (_IO_acquire_lock): Avoid
+       nested function, use static inline function from libio.h.
+       Code by Richard Henderson.
+
+       * sysdeps/pthread/bits/libc-lock.h: Mark pthread_setcancelstate as
+       weak.
+
+2003-08-30  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/sparc/sparc64/Versions: New file.
+       * sysdeps/unix/sysv/linux/sparc/sparc64/timer_create.c: New file.
+       * sysdeps/unix/sysv/linux/sparc/sparc64/timer_delete.c: New file.
+       * sysdeps/unix/sysv/linux/sparc/sparc64/timer_getoverr.c: New file.
+       * sysdeps/unix/sysv/linux/sparc/sparc64/timer_gettime.c: New file.
+       * sysdeps/unix/sysv/linux/sparc/sparc64/timer_settime.c: New file.
+       * sysdeps/unix/sysv/linux/sparc/sparc64/sysdep-cancel.h: New file.
+       * sysdeps/unix/sysv/linux/sparc/sparc32/sysdep-cancel.h: New file.
+       * sysdeps/unix/sysv/linux/sparc/bits/pthreadtypes.h: New file.
+       * sysdeps/unix/sysv/linux/sparc/bits/semaphore.h: New file.
+       * sysdeps/unix/sysv/linux/sparc/lowlevellock.h: New file.
+       * sysdeps/unix/sysv/linux/sparc/pthread_once.c: New file.
+       * sysdeps/unix/sysv/linux/sparc/pt-vfork.S: New file.
+       * sysdeps/unix/sysv/linux/sparc/fork.c: New file.
+       * sysdeps/unix/sysv/linux/sparc/aio_cancel.c: New file.
+       * sysdeps/sparc/sparc32/sparcv9/pthread_spin_lock.c: New file.
+       * sysdeps/sparc/sparc32/sparcv9/pthread_spin_trylock.c: New file.
+       * sysdeps/sparc/sparc32/sparcv9/pthread_spin_unlock.c: New file.
+       * sysdeps/sparc/sparc32/pthread_spin_lock.c: New file.
+       * sysdeps/sparc/sparc32/pthread_spin_trylock.c: New file.
+       * sysdeps/sparc/sparc32/pthreaddef.h: New file.
+       * sysdeps/sparc/sparc64/pthread_spin_lock.c: New file.
+       * sysdeps/sparc/sparc64/pthread_spin_trylock.c: New file.
+       * sysdeps/sparc/sparc64/pthread_spin_unlock.c: New file.
+       * sysdeps/sparc/sparc64/pthreaddef.h: New file.
+       * sysdeps/sparc/tls.h: New file.
+       * sysdeps/sparc/tcb-offsets.sym: New file.
+       * sysdeps/sparc/Makefile: New file.
+       * sysdeps/sparc/td_ta_map_lwp2thr.c: New file.
+       * init.c [__sparc__] (__NR_set_tid_address): Define.
+
+2003-08-29  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/pthread/bits/stdio-lock.h (_IO_acquire_lock,
+       _IO_release_lock): Define.
+
+2003-08-29  Jakub Jelinek  <jakuB@redhat.com>
+
+       * tst-cancel4.c (tf_sigwait, tf_sigwaitinfo, tf_sigtimedwait): Add
+       sigemptyset before sigaddset.  Reported by jreiser@BitWagon.com.
+
+2003-08-27  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/pthread.h (pthread_exit): Remove __THROW.
+       (__pthread_cleanup_class): Add missing return types of member
+       functions.
+
+2003-08-26  Steven Munroe <sjmunroe@us.ibm.com>
+
+       * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h
+       (lll_mutex_unlock_force): Add memory barrier between store and futex
+       syscall.
+
+2003-08-25  Ulrich Drepper  <drepper@redhat.com>
+
+       * tst-cancel4.c (do_test): Also unlink tempfname and remove
+       tempmsg in first loop.
+
+2003-08-18  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/bits/posix_opt.h: Define
+       _POSIX_THREAD_PRIORITY_SCHEDULING.
+       * sysdeps/unix/sysv/linux/i386/bits/posix_opt.h: Likewise.
+
+2003-08-07  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/pthread/bits/libc-lock.h [_LIBC && SHARED]
+       (__rtld_lock_default_lock_recursive,
+       __rtld_lock_default_unlock_recursive): Define.
+       [_LIBC && SHARED] (__rtld_lock_lock_recursive,
+       __rtld_lock_unlock_recursive): Define using
+       GL(_dl_rtld_*lock_recursive).
+       * init.c (__pthread_initialize_minimal_internal): Initialize
+       _dl_rtld_lock_recursive and _dl_rtld_unlock_recursive.
+       Lock GL(_dl_load_lock) the same number of times as
+       GL(_dl_load_lock) using non-mt implementation was nested.
+
+       * pthreadP.h (__pthread_cleanup_upto): Add hidden_proto.
+       * pt-longjmp.c (__pthread_cleanup_upto): Add hidden_def.
+
+2003-08-06  Jakub Jelinek  <jakub@redhat.com>
+
+       * tst-cancel17.c (do_test): Make len2 maximum of page size and
+       PIPE_BUF.
+
+2003-08-07  Jakub Jelinek  <jakub@redhat.com>
+
+       * pthread_create.c (__pthread_create_2_0): Clear new_attr.cpuset.
+
+2003-08-03  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/pthread/createthread.c (do_clone): Move error handling
+       to first syscall error check.  Move syscall error check for tkill
+       into __ASSUME_CLONE_STOPPED #ifdef.
+
+2003-08-02  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/createthread.c (do_clone): If __ASSUME_CLONE_STOPPED
+       is not defined, do explicit synchronization.
+       (create_thread): Do not lock pd->lock here.  If __ASSUME_CLONE_STOPPED
+       is not defined also unlock pd->lock for non-debugging case in case
+       it is necessary.
+       * pthread_create.c (start_thread): Always get and release pd->lock
+       if __ASSUME_CLONE_STOPPED is not defined.
+       (start_thread_debug): Removed.  Adjust users.
+       * allocatestack.c (allocate_stack): Always initialize lock if
+       __ASSUME_CLONE_STOPPED is not defined.
+       * Makefile (tests): Add tst-sched1.
+       * tst-sched1.c: New file.
+
+       * sysdeps/pthread/createthread.c (do_clone): Only use
+       sched_setschduler and pass correct parameters.
+
+2003-07-31  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/pthread/pthread.h (pthread_attr_setstackaddr,
+       pthread_attr_setstacksize): Change PTHREAD_STACK_SIZE to
+       PTHREAD_STACK_MIN in comments.
+
+2003-07-31  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/pthread/pthread_cond_timedwait.c (__pthread_cond_timedwait):
+       Shut up warnings if INTERNAL_SYSCALL_ERROR_P does not use its first
+       argument.
+       * sysdeps/unix/sysv/linux/timer_create.c (timer_create): Likewise.
+       * pthread_condattr_setclock.c (pthread_condattr_setclock): Likewise.
+       * sysdeps/unix/sysv/linux/s390/jmp-unwind.c: Include pthreaddef.h.
+       (__pthread_cleanup_upto): Fix prototype.
+       (_longjmp_unwind): Adjust caller.
+       * sysdeps/unix/sysv/linux/s390/lowlevellock.h (__lll_mutex_timedlock):
+       Change second argument to const struct pointer.
+       * tst-sem8.c (main): Remove unused s2 and s3 variables.
+       * tst-sem9.c (main): Likewise.
+       * unwind.c: Include string.h for strlen prototype.
+
+2003-07-31  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S
+       (__pthread_cond_timedwait): Don't use cmov unless HAVE_CMOV is defined.
+       * sysdeps/unix/sysv/linux/i386/i686/pthread_cond_timedwait.S:
+       Define HAVE_CMOV.
+       Patch by Nicholas Miell <nmiell@attbi.com>.
+
+2003-07-30  Jakub Jelinek  <jakub@redhat.com>
+
+       * init.c (__pthread_initialize_minimal_internal): Initialize
+       GL(dl_init_static_tls).
+       * pthreadP.h (__pthread_init_static_tls): New prototype.
+       * allocatestack.c (init_one_static_tls, __pthread_init_static_tls):
+       New functions.
+       * Makefile (tests): Add tst-tls4.
+       (modules-names): Add tst-tls4moda and tst-tls4modb.
+       ($(objpfx)tst-tls4): Link against libdl and libpthread.
+       ($(objpfx)tst-tls4.out): Depend on tst-tls4moda.so and
+       tst-tls4modb.so.
+       * tst-tls4.c: New file.
+       * tst-tls4moda.c: New file.
+       * tst-tls4modb.c: New file.
+
+2003-06-19  Daniel Jacobowitz  <drow@mvista.com>
+
+       * sysdeps/pthread/timer_create.c (timer_create): Call timer_delref
+       before __timer_dealloc.
+       * sysdeps/pthread/timer_routines.c (__timer_thread_find_matching):
+       Don't call list_unlink.
+
+2003-07-29  Roland McGrath  <roland@redhat.com>
+
+       * Makefile [$(build-shared) = yes] (tests): Depend on $(test-modules).
+
+2003-07-25  Jakub Jelinek  <jakub@redhat.com>
+
+       * tst-cancel17.c (do_test): Check if aio_cancel failed.
+       Don't reuse struct aiocb A if it failed.
+       Write fpathconf (fds[1], _PC_PIPE_BUF) + 2 bytes using aio_write,
+       not just one byte, as that does not block.
+
+2003-07-22  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/pthread/unwind-resume.c: New file.
+       * sysdeps/pthread/Makefile (routines, shared-only-routines): Add
+       unwind-resume in csu subdir.
+       (CFLAGS-unwind-resume.c, CFLAGS-rt-unwind-resume.c): Compile with
+       exceptions.
+       (librt-sysdep_routines, librt-shared-only-routines): Add
+       rt-unwind-resume.
+       * sysdeps/pthread/rt-unwind-resume.c: New file.
+       * unwind-forcedunwind.c: New file.
+       * Makefile (libpthread-routines): Add unwind-forcedunwind.
+       (libpthread-shared-only-routines): Likewise.
+       (CFLAGS-unwind-forcedunwind.c): Compile with exceptions.
+       * pthreadP.h (pthread_cancel_init): New prototype.
+       * pthread_cancel.c (pthread_cancel): Call pthread_cancel_init.
+
+       * sysdeps/pthread/createthread.c (do_thread, create_thread): Make
+       attr argument const struct pthread_attr *.
+
+       * res.c (__res_state): Return __resp.
+       * descr.h: Include resolv.h.
+       (struct pthread): Add res field.
+       * pthread_create.c: Include resolv.h.
+       (start_thread): Initialize __resp.
+       * Makefile (tests): Add tst-_res1.
+       (module-names): Add tst-_res1mod1, tst-_res1mod2.
+       ($(objpfx)tst-_res1mod2.so): Depend on $(objpfx)tst-_res1mod1.so.
+       ($(objpfx)tst-_res1): Depend on $(objpfx)tst-_res1mod2.so and
+       libpthread.
+       * tst-_res1.c: New file.
+       * tst-_res1mod1.c: New file.
+       * tst-_res1mod2.c: New file.
+
+2003-07-21  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/createthread.c: Don't define CLONE_STOPPED.
+
+       * Makefile: Define various *-no-z-defs variables for test DSOs
+       which has undefined symbols.
+
+2003-07-21  Steven Munroe  <sjmunroe@us.ibm.com>
+
+       * sysdeps/unix/sysv/linux/powerpc/pthread_once.c (__pthread_once):
+       Retry if the stwcx fails to store once_control.
+
+2003-07-20  Ulrich Drepper  <drepper@redhat.com>
+
+       * Makefile (libpthread-routines): Add pthread_attr_getaffinity and
+       pthread_attr_setaffinity.
+       * Versions [libpthread] (GLIBC_2.3.3): Likewise.
+       * sysdeps/unix/sysv/linux/pthread_attr_getaffinity.c: New file.
+       * sysdeps/unix/sysv/linux/pthread_attr_setaffinity.c: New file.
+       * pthread_attr_destroy.c: Free cpuset element if allocated.
+       * pthread_create.c: Pass iattr as additional parameter to
+       create_thread.
+       * sysdeps/pthread/createthread.c: If attribute is provided and
+       a new thread is created with affinity set or scheduling parameters,
+       start thread with CLONE_STOPPED.
+       * sysdeps/pthread/pthread.h: Declare pthread_attr_getaffinity and
+       pthread_attr_setaffinity.
+       * sysdeps/unix/sysv/linux/internaltypes.h (struct pthread_attr): Add
+       cpuset element.
+
+2003-07-15  Ulrich Drepper  <drepper@redhat.com>
+
+       * tst-tcancel-wrappers.sh: lseek and llseek are not cancelation points.
+
+2003-07-14  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/configure.in: Require CFI directives also for
+       ppc and s390.
+
+2003-07-15  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h (PSEUDO):
+       Add cfi directives.
+
+2003-07-12  Kaz Kojima  <kkojima@rr.iij4u.or.jp>
+
+       * sysdeps/sh/tcb-offsets.sym: Add RESULT, TID, CANCELHANDLING and
+       CLEANUP_JMP_BUF.
+       * sysdeps/unix/sysv/linux/sh/pthread_cond_wait.S: Use more
+       registers as variables.  Call __pthread_mutex_unlock_usercnt.
+       * sysdeps/unix/sysv/linux/sh/pthread_cond_timedwait.S: Likewise.
+       * sysdeps/unix/sysv/linux/sh/pthread_rwlock_rdlock.S: Store TID
+       not self pointer in __writer.  Compare with TID to determine
+       deadlocks.
+       * sysdeps/unix/sysv/linux/sh/pthread_rwlock_wrlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedrdlock.S:
+       Likewise.
+       * sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedwrlock.S:
+       Likewise.
+       * sysdeps/unix/sysv/linux/sh/sem_wait.S: Add cancellation support.
+       * sysdeps/unix/sysv/linux/sh/sem_timedwait.S: Likewise.
+       * sysdeps/unix/sysv/linux/sh/sysdep-cancel.h: Define all the nice
+       macros also when compiling librt.
+
+2003-07-11  Jakub Jelinek  <jakub@redhat.com>
+
+       * Makefile (CFLAGS-pthread_once.c): Add -fexceptions
+       -fasynchronous-unwind-tables.
+       * sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h
+       (PSEUDO): Add cfi directives.
+       * sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h (PSEUDO):
+       Likewise.
+       * sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h (PSEUDO):
+       Likewise.
+
+2003-07-08  Jakub Jelinek  <jakub@redhat.com>
+
+       * pthreadP.h (__pthread_unwind_next, __pthread_register_cancel,
+       __pthread_unregister_cancel): Add prototypes and hidden_proto.
+       * unwind.c (__pthread_unwind_next): Add hidden_def.
+       * cleanup.c (__pthread_register_cancel, __pthread_unregister_cancel):
+       Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/sem_wait.S (__new_sem_wait):
+       Use HIDDEN_JUMPTARGET to jump to __pthread_unwind.
+       * sysdeps/unix/sysv/linux/i386/i486/sem_timedwait.S (sem_timedwait):
+       Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/sem_wait.S (sem_wait): Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S (sem_timedwait):
+       Likewise.
+       * sysdeps/unix/sysv/linux/i386/pthread_once.S (__pthread_once): Use
+       HIDDEN_JUMPTARGET to call __pthread_register_cancel,
+       __pthread_unregister_cancel and __pthread_unwind_next.
+
+2003-07-04  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/ia64/sysdep-cancel.h (PSEUDO): Use
+       different symbol for the cancellation syscall wrapper and
+       non-cancellation syscall wrapper.
+       (PSEUDO_END): Define.
+
+2003-07-05  Richard Henderson  <rth@redhat.com>
+
+       * sysdeps/alpha/elf/pt-initfini.c: Avoid .ent/.end.
+       * sysdeps/unix/sysv/linux/alpha/lowlevellock.h (lll_futex_wait,
+       lll_futex_timed_wait, lll_futex_wake, lll_futex_requeue): On success
+       return actual return value from the syscall, not 0.
+
+2003-07-07  Ulrich Drepper  <drepper@redhat.com>
+
+       * descr.h (struct pthread): Add pid field.
+       * allocatestack.c (allocate_stack): Initialize pid field in descriptor.
+       (__reclaim_stacks): Likewise.
+       * init.c (sigcancel_handler): If __ASSUME_CORRECT_SI_PID is defined
+       also check for PID of the signal source.
+       (__pthread_initialize_minimal_internal): Also initialize pid field
+       of initial thread's descriptor.
+       * pthread_cancel.c: Use tgkill instead of tkill if possible.
+       * sysdeps/unix/sysv/linux/fork.c: Likewise.
+       * sysdeps/unix/sysv/linux/pt-raise.c: Likewise.
+       * sysdeps/unix/sysv/linux/pthread_kill.c: Likewise.
+       * sysdeps/unix/sysv/linux/raise.c: Likewise.
+
+2003-07-05  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/bits/libc-lock.h (__libc_cleanup_push): Renamed.
+       Fix use of parameter.
+       (__libc_cleanup_pop): Likewise.
+
+2003-07-04  Ulrich Drepper  <drepper@redhat.com>
+
+       * init.c (sigcancel_handler): Change parameters to match handler
+       for SA_SIGACTION.  Check signal number and code to recognize
+       invalid invocations.
+
+2003-07-03  Roland McGrath  <roland@redhat.com>
+
+       * sysdeps/ia64/td_ta_map_lwp2thr.c (td_ta_map_lwp2thr):
+       Apply sizeof (struct pthread) bias to r13 value.
+
+2003-07-03  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/configure.in: Require CFI directives.
+
+       * sysdeps/pthread/librt-cancellation.c (__pthread_unwind): Remove
+       definition.
+       * pthreadP.h (__pthread_unwind): Add hidden_proto if used in
+       libpthread compilation.
+       * unwind.c (__pthread_unwind): Add hidden_def.
+       * Versions (libpthread) [GLIBC_PRIVATE]: Add __pthread_unwind.
+
+2003-07-01  Ulrich Drepper  <drepper@redhat.com>
+
+       * libc-cancellation.c (__libc_cleanup_routine): Define.
+       * sysdeps/pthread/bits/libc-lock.h (__pthread_cleanup_push): Define.
+       (__pthread_cleanup_pop): Define.
+
+2003-07-01  Richard Henderson  <rth@redhat.com>
+
+       * sysdeps/alpha/elf/pt-initfini.c: New file.
+       * sysdeps/alpha/pthread_spin_lock.S: New file.
+       * sysdeps/alpha/pthread_spin_trylock.S: New file.
+       * sysdeps/alpha/pthreaddef.h: New file.
+       * sysdeps/alpha/td_ta_map_lwp2thr.c: New file.
+       * sysdeps/alpha/tls.h: New file.
+       * sysdeps/unix/sysv/linux/alpha/Makefile: New file.
+       * sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h: New file.
+       * sysdeps/unix/sysv/linux/alpha/bits/semaphore.h: New file.
+       * sysdeps/unix/sysv/linux/alpha/createthread.c: New file.
+       * sysdeps/unix/sysv/linux/alpha/fork.c: New file.
+       * sysdeps/unix/sysv/linux/alpha/lowlevellock.h: New file.
+       * sysdeps/unix/sysv/linux/alpha/pt-vfork.S: New file.
+       * sysdeps/unix/sysv/linux/alpha/pthread_once.c: New file.
+       * sysdeps/unix/sysv/linux/alpha/sem_post.c: New file.
+       * sysdeps/unix/sysv/linux/alpha/sysdep-cancel.h: New file.
+
+2003-07-01  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/x86_64/pthread_once.S: Add correct
+       cleanup support and unwind info.
+
+2003-06-30  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/pthread_once.S (__pthread_once):
+       Use correct cleanup handler registration.  Add unwind info.
+       * sysdeps/unix/sysv/linux/unwindbuf.sym: New file.
+       * sysdeps/unix/sysv/linux/Makefile: Add rule to build unwindbuf.h.
+       * tst-once3.c: Add cleanup handler and check it is called.
+       * tst-once4.c: Likewise.
+       * tst-oncex3.c: New file.
+       * tst-oncex4.c: New file.
+       * Makefile: Add rules to build and run tst-oncex3 and tst-oncex4.
+
+2003-06-29  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/configure.in: Check for C cleanup handling in gcc.
+
+2003-06-27  Ulrich Drepper  <drepper@redhat.com>
+
+       * tst-cancel4.c (tf_msgrcv): Use IPC_PRIVATE in msgget call.
+       (tf_msgsnd): Likewise.
+
+       * tst-cancel4.c (tf_msgrcv): Strengthen test against valid
+       premature returns a bit more.
+
+2003-06-26  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/librt-cancellation.c: Move __pthread_unwind
+       definition to the front.
+
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Rename
+       the cleanup functions to make the names unique.  Fix dwarf opcode
+       un unwind table.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Rename cleanup
+       functions to make the names unique.  Fix CFA offset for two blocks.
+
+2003-06-25  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/pthread.h (class __pthread_cleanup_class): Add
+       missing closing braces.
+       Patch by Christophe Saout <christophe@saout.de>.
+
+2003-06-24  Roland McGrath  <roland@redhat.com>
+
+       * pthread_mutex_trylock.c (__pthread_mutex_trylock): Typo fix.
+
+2003-06-24  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/ia64/bits/posix_opt.h: New file.
+       * sysdeps/unix/sysv/linux/x86_64/bits/posix_opt.h: New file.
+
+       * pthreadP.h: Declare __find_thread_by_id.
+       * allocatestack.c [HP_TIMING_AVAIL]: Define __find_thread_by_id.
+       * pthread_clock_gettime.c: Allow using other thread's clock.
+       * pthread_clock_settime.c: Likewise.
+       * sysdeps/pthread/pthread_getcpuclockid.c: Likewise.
+       * Makefile: Add rules to build and run tst-clock2.
+       * tst-clock2.c: New file.
+
+2003-06-23  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Rewrite
+       to use exception-based cleanup handler.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Likewise.
+
+       * tst-cond8.c (ch): Announce that we are done.
+
+       * pthreadP.h (__pthread_mutex_cond_lock): Mark with internal_function.
+
+       * tst-cancel17.c (tf): Retry aio_suspend in case of EINTR.
+       Also test aio_suspend with timeout value.
+
+2003-06-22  Ulrich Drepper  <drepper@redhat.com>
+
+       * pthreadP.h: Mark __pthread_mutex_unlock_usercnt also hidden.
+       * pthread_mutex_unlock.c (__pthread_mutex_unlock_usercnt): Add
+       attribute_hidden.
+
+       * pthreadP.h (__pthread_mutex_init_internal): Mark hidden.
+       (__pthread_mutex_lock_internal): Likewise.
+       (__pthread_mutex_unlock_internal): Likewise.
+       (__pthread_mutex_unlock_usercnt): Declare.
+       * pthread_mutex_destroy.c: Always fail if used in any way.
+       * pthread_mutex_init.c: Update comment.
+       * pthread_mutex_lock.c: If NO_INCR is not defined adjust __nusers.
+       * pthread_mutex_timedlock.c: Adjust __nusers.
+       * pthread_mutex_trylock.c: Adjust __nusers.
+       * pthread_mutex_unlock.c: Old code is in __pthread_mutex_unlock_usercnt
+       and public interfaces are wrapper with pass additional parameter.
+       __pthread_mutex_unlock_usercnt does not adjust __nusers if second
+       parameter zero.
+       * tst-mutex8.c: New file.
+       * Makefile (tests): Add tst-mutex8.
+       * sysdeps/pthread/pthread_cond_timedwait.c: Call
+       __pthread_mutex_unlock_usercnt.
+       * sysdeps/pthread/pthread_cond_wait.c: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S: Likewise.
+       * sysdeps/unix/sysv/linux/pthread_mutex_cond_lock.c: Define NO_INCR.
+       * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h (pthread_mutex_t):
+       Add __nusers.
+       * sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: Likewise.
+
+       * pthread_mutex_lock.c: Don't store THREAD_ID in __owner, use TID.
+       * pthread_mutex_timedlock.c: Likewise.
+       * pthread_mutex_trylock.c: Adjust __nusers.
+       * pthread_mutex_unlock.c: Compare with TID not THREAD_ID.
+       * tst-mutex9.c: New file.
+       * Makefile (tests): Add tst-mutex9.
+       * sysdeps/i386/tls.h: Remove THREAD_ID definition.
+       * sysdeps/ia64/tls.h: Likewise.
+       * sysdeps/powerpc/tls.h: Likewise.
+       * sysdeps/s390/tls.h: Likewise.
+       * sysdeps/sh/tls.h: Likewise.
+       * sysdeps/x86_64/tls.h: Likewise.
+       * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h (pthread_mutex_t):
+       Change type of __owner.
+       * sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: Likewise.
+
+2003-06-19  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/ia64/sem_post.c: Move to...
+       * sysdeps/unix/sysv/linux/sem_post.c: ...here.
+
+       * sysdeps/unix/sysv/linux/sem_post.c: Move to...
+       * sysdeps/unix/sysv/linux/powerpc/sem_post.c: ... here.  Pass nr + 1
+       instead of nr to lll_futex_wake.  Only set errno and return -1
+       if err < 0.
+
+       * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h (lll_futex_wait,
+       lll_futex_timed_wait, lll_futex_wake, lll_futex_requeue): On success
+       return actual return value from the syscall, not 0.
+
+2003-06-18  Ulrich Drepper  <drepper@redhat.com>
+
+       * tst-cancel4.c (tf_msgsnd): Don't always use 100 as the type,
+       find a random value.
+       (tf_msgrcv): Likewise.  Also don't report msgrcv returns if
+       errno==EIDRM.
+
+       * sysdeps/unix/sysv/linux/timer_settime.c: Add prototype for
+       compat_timer_settime.
+       * sysdeps/unix/sysv/linux/timer_gettime.c: Add prototype for
+       compat_timer_gettime.
+       * sysdeps/unix/sysv/linux/timer_getoverr.c: Add prototype for
+       compat_timer_getoverrun.
+       * sysdeps/unix/sysv/linux/timer_delete.c: Add prototype for
+       compat_timer_delete.
+
+       * pthread_mutex_destroy.c (__pthread_mutex_destroy): For
+       error-checking mutex detect busy mutexes.
+
+2003-06-17  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h (lll_mutex_lock):
+       Add ax to clobber list.
+       (lll_mutex_cond_lock): Likewise.
+       (lll_mutex_unlock): Likewise.
+       (lll_lock): Likewise.
+       (lll_unlock): Likewise.
+
+       * Makefile: Add rules to build and run tst-cancel18 and tst-cancelx18.
+       * tst-cancel18.c: New file.
+       * tst-cancelx18.c: New file.
+
+       * tst-cancel4.c: Test connect, creat, msgrcv, msgsnd, sendmsg, sendto,
+       and tcdrain.
+
+       * Makefile: Add rules to build and run tst-cancel17 and tst-cancel17x.
+       * tst-cancel17.c: New file.
+       * tst-cancelx17.c: New file.
+
+       * sysdeps/unix/sysv/linux/sigtimedwait.c: New file.
+       * sysdeps/unix/sysv/linux/sigwait.c: New file.
+       * sysdeps/unix/sysv/linux/sigwaitinfo.c: New file.
+
+       * tst-cancel4.c: Test open, close, pread, pwrite, fsync, and msync.
+
+2003-06-16  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/pthread/createthread.c (create_thread): Set
+       header.multiple_threads unconditionally.
+       * allocatestack.c (allocate_stack): Likewise.
+       * descr.h (struct pthread): Add header.multiple_threads
+       unconditionally.
+       * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h (CENABLE, CDISABLE):
+       Define for librt.  #error if neither libpthread, libc nor librt.
+       * sysdeps/unix/sysv/linux/ia64/sysdep-cancel.h (CENABLE, CDISABLE):
+       Likewise.
+       * sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h (CENABLE,
+       CDISABLE): Likewise.
+       * sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h (CENABLE,
+       CDISABLE): Likewise.
+       * sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h (CENABLE,
+       CDISABLE): Likewise.
+       * sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h (CENABLE,
+       CDISABLE): Likewise.  Access header.multiple_threads outside of
+       libc and libpthread.
+       * sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h (CENABLE, CDISABLE):
+       Likewise.
+       * sysdeps/x86_64/tls.h (tcbhead_t): Add multiple_threads.
+       * sysdeps/x86_64/tcb-offsets.sym (MULTIPLE_THREADS_OFFSET): Define.
+
+2003-06-17  Ulrich Drepper  <drepper@redhat.com>
+
+       * tst-cancel4.c: Add tests for the socket and signal functions, pause.
+       Also test early cancellation before the thread reaches the cancellation
+       point.
+
+       * Makefile: Compile forward.c with exceptions.
+
+       * sysdeps/unix/sysv/linux/sleep.c: New file.
+
+2003-06-16  Ulrich Drepper  <drepper@redhat.com>
+
+       * Makefile: Add CFLAGS definition to compile function wrappers
+       duplicated from libc with exceptions.
+       * tst-cancel4.c: Also check cancellation handlers.
+
+       * Makefile: Add rules to build and run tst-cancel16 and
+       tst-cancelx16.  Add missing CFLAGS definitions.
+       * tst-cancel16.c: New file.
+       * tst-cancelx16.c: New file.
+
+2003-06-15  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/dl-sysdep.h
+       (DL_SYSINFO_IMPLEMENTATION): Use CFI opcodes.
+       * sysdeps/unix/sysv/linux/i386/i686/dl-sysdep.h
+       (DL_SYSINFO_IMPLEMENTATION): Likewise.
+
+       * pthreadP.h (LIBC_CANCEL_ASYNC): Also define for librt.
+       (LIBC_CANCEL_RESET): Likewise.
+       Declare __librt_enable_asynccancel and __librt_disable_asynccancel.
+       * sysdeps/pthread/Makefile (librt-sysdep_routines): Add
+       librt-cancellation.
+       (CFLAGS-libcrt-cancellation.c): Define.
+       * sysdeps/pthread/librt-cancellation.c: New file.
+       * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h: Define all the nice
+       macros also when compiling librt.
+       * sysdeps/unix/sysv/linux/ia64/sysdep-cancel.h: Likewise.
+       * sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h: Likewise.
+       * sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h: Likewise.
+       * sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h: Likewise.
+       * sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h: Likewise.
+       * sysdeps/unix/sysv/linux/sh/sysdep-cancel.h: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h: Likewise.
+
+       * sysdeps/unix/sysv/linux/timer_create.c: Add prototype for
+       compat_timer_create.
+
+2003-06-14  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/posix-timer.h (timespec_compare): Always inline.
+
+       * sysdeps/unix/sysv/linux/fork.h: Add libc_hidden_proto for
+       __register_atfork.
+       * sysdeps/unix/sysv/linux/register-atfork.c (__register_atfork):
+       Add libc_hidden_def.
+
+2003-06-13  Roland McGrath  <roland@redhat.com>
+
+       * sysdeps/x86_64/td_ta_map_lwp2thr.c (td_ta_map_lwp2thr): Pass FS
+       constant from <sys/reg.h> to ps_get_thread_area, not register contents.
+
+2003-06-11  Ulrich Drepper  <drepper@redhat.com>
+
+       * allocatestack.c (queue_stack): Always inline.
+       * ptreadhP.h (__do_cancel): Likewise.
+
+2003-06-10  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/s390/sem_timedwait.c (sem_timedwait): Fix
+       a typo.
+
+2003-06-10  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_signal.S
+       (__pthread_cond_signal): Remove incorrect second addition for
+       cond_lock!=0.
+
+2003-06-09  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_signal.S
+       (__pthread_cond_signal): Use correct futex pointer in
+       __lll_mutex_lock_wait call.
+
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_signal.S
+       (__pthread_cond_signal): Some more tweaks to handle cond_lock!=0.
+
+2003-06-08  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/s390/sem_wait.c (__new_sem_wait): Make
+       cancelable.
+       * sysdeps/unix/sysv/linux/s390/sem_timedwait.c (sem_timedwait):
+       Likewise.
+
+       * sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h: Remove
+       hand-written CFI generation code.  Since ENTRY/END also initiated
+       CFI frames this caused two CFI sets to be generated.
+
+2003-06-07  Ulrich Drepper  <drepper@redhat.com>
+
+       * cleanup_routine.c: New file.
+       * Versions (libpthread) [GLIBC_2.3.3]: Add __pthread_cleanup_routine.
+       * sysdeps/pthread/pthread.h: Add support for fully exception-based
+       cleanup handling.
+       * Makefile (libpthread-routines): Add cleanup_routine.
+       Add more CFLAGS variables to compile with exceptions.  Add comments
+       why which file needs unwind tables.
+       (tests) [have-forced-unwind==yes]: Add tst-cancelx* and tst-cleanupx*
+       tests.
+       * tst-cancelx1.c: New file.
+       * tst-cancelx2.c: New file.
+       * tst-cancelx3.c: New file.
+       * tst-cancelx4.c: New file.
+       * tst-cancelx5.c: New file.
+       * tst-cancelx6.c: New file.
+       * tst-cancelx7.c: New file.
+       * tst-cancelx8.c: New file.
+       * tst-cancelx9.c: New file.
+       * tst-cancelx10.c: New file.
+       * tst-cancelx11.c: New file.
+       * tst-cancelx12.c: New file.
+       * tst-cancelx13.c: New file.
+       * tst-cancelx14.c: New file.
+       * tst-cancelx15.c: New file.
+       * tst-cleanupx0.c: New file.
+       * tst-cleanupx0.expect: New file.
+       * tst-cleanupx1.c: New file.
+       * tst-cleanupx2.c: New file.
+       * tst-cleanupx3.c: New file.
+
+       * tst-cleanup0.c: Make standard compliant.
+       * tst-cleanup1.c: Likewise.
+
+       * sysdeps/unix/sysv/linux/sem_timedwait.c: Add cancellation support.
+       * sysdeps/unix/sysv/linux/sem_wait.c: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/sem_timedwait.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/sem_wait.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/sem_wait.S: Likewise.
+       * sysdeps/i386/tcb-offsets.sym: Add RESULT, CANCELHANDLING, and
+       CLEANUP_JMP_BUF.
+       * sysdeps/x86_64/tcb-offsets.sym: Likewise.
+       * tst-cancel12.c: New file.
+       * tst-cancel13.c: New file.
+       * tst-cancel14.c: New file.
+       * tst-cancel15.c: New file.
+       * Makefile (tests): Add tst-cancel12, tst-cancel13, tst-cancel14,
+       and tst-cancel15.
+
+       * tst-cancel1.c: Add some comments.
+
+       * sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S: Compute relative
+       timeout correctly.
+
+2003-06-06  Ulrich Drepper  <drepper@redhat.com>
+
+       * Makefile (CFLAGS-pthread_cancel.c): Define.
+
+2003-06-05  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h (pthread_rwlock_t):
+       Change type of __writer element to int.
+       * sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: Likewise.
+       * sysdeps/i386/tcb-offsets.sym: Replace SELF entry with TID entry.
+       * sysdeps/x86_64/tcb-offsets.sym: Likewise.
+       * pthread_rwlock_trywrlock.c: Store TID not self pointer in __writer.
+       Compare with TID to determine deadlocks.
+       * sysdeps/pthread/pthread_rwlock_rdlock.c: Likewise.
+       * sysdeps/pthread/pthread_rwlock_timedrdlock.c: Likewise.
+       * sysdeps/pthread/pthread_rwlock_timedwrlock.: Likewise.
+       * sysdeps/pthread/pthread_rwlock_wrlock.c: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_rdlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedrdlock.S:
+       Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedwrlock.S:
+       Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_wrlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_rdlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedrdlock.S:
+       Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedwrlock.S:
+       Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_wrlock.S: Likewise.
+       * Makefile (tests): Add tst-rwlock12.
+       * tst-rwlock12.c: New file.
+
+2003-06-05  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/lowlevellock.c (__lll_lock_wait,
+       __lll_timedlock_wait, lll_unlock_wake_cb, __lll_timedwait_tid):
+       Remove bogus hidden_proto.
+       * sysdeps/unix/sysv/linux/s390/libc-lowlevellock.c (___lll_lock):
+       Likewise.
+       * sysdeps/unix/sysv/linux/s390/lowlevellock.c (___lll_lock,
+       lll_unlock_wake_cb, ___lll_timedwait_tid): Likewise.
+       * sysdeps/unix/sysv/linux/s390/lowlevelmutex.c (___lll_mutex_lock,
+       ___lll_mutex_timedlock): Likewise.
+
+2003-06-04  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_signal.S
+       (__pthread_cond_signal): Add some code to eventually handle
+       cond_lock!=0.
+
+2003-06-01  Ulrich Drepper  <drepper@redhat.com>
+
+       * Makefile (tests): Add tst-exec4.
+       (tst-exec4-ARGS): Define.
+       * tst-exec4.c: New file.
+
+2003-05-31  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/lowlevellock.c (__lll_timedlock_wait):
+       Also fail if tv_nsec < 0.
+       (__lll_timedwait_tid): Likewise.
+       * sysdeps/unix/sysv/linux/sem_timedwait.c (sem_timedwait): Likewise.
+       * sysdeps/unix/sysv/linux/i386/lowlevellock.h (lll_timedwait_tid):
+       Likewise.
+       * sysdeps/unix/sysv/linux/s390/lowlevellock.c (___lll_timedwait_tid):
+       Likewise.
+       * sysdeps/unix/sysv/linux/s390/lowlevelmutex.c (__lll_mutex_timedlock):
+       Likewise.
+       * sysdeps/unix/sysv/linux/s390/sem_timedwait.c (sem_timedwait):
+       Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h (lll_timedwait_tid):
+       Likewise.
+       * sysdeps/unix/sysv/linux/sh/lowlevellock.h (lll_timedwait_tid):
+       Likewise.
+
+       * Makefile (tests): Add tst-sem8 and tst-sem9.
+       * tst-sem8.c: New file.
+       * tst-sem9.c: New file.
+       * sem_open.c: Fix creation of in_use record if the file exists but
+       no internal record.
+
+       * posix-timer.h: Remove old, unused timer_id2ptr and timer_ptr2id
+       definitions.
+
+       * sysdeps/pthread/timer_create.c (timer_create): In case
+       evp==NULL, assign timer ID to sival_ptr.
+
+       * descr.h (struct pthread_unwind_buf): Change type of prev element to
+       struct pthread_unwind_buf *.
+       (struct pthread): Likewise for cleanup_jmp_buf element.
+
+       * cleanup.c (__pthread_register_cancel): Add cast to avoid warning.
+       * cleanup_defer.c (__pthread_register_cancel_defer): Likewise.
+       * unwind.c (__pthread_unwind_next): Likewise.
+
+2003-05-30  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/ia64/lowlevellock.h
+       (lll_futex_timed_wait): Use int for futex value parameter.
+       (lll_futex_wake): Likewise.
+       (lll_futex_requeue): Likewise.
+
+       * sysdeps/unix/sysv/linux/lowlevellock.c (__lll_lock_wait):
+       Replace one memory operation with one register operation.
+
+       * tst-join4.c (do_test): Fix error message.
+
+       * tst-rwlock6.c (do_test): Use correct format specifier.
+
+       * sysdeps/unix/sysv/linux/i386/i486/lowlevelmutex.S
+       (__lll_mutex_lock_wait): Replace one memory operation with one
+       register operation.
+       * sysdeps/unix/sysv/linux/x86_64/lowlevelmutex.S
+       (__lll_mutex_lock_wait): Likewise.
+
+       * sysdeps/unix/sysv/linux/ia64/lowlevellock.h
+       (__lll_mutex_cond_lock): Add one to value parameter of
+       __lll_lock_wait to reflect reality in the futex syscall.
+       * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h
+       (lll_mutex_cond_lock): Likewise.
+
+2003-05-30  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/s390/lowlevellock.h (__lll_mutex_cond_lock):
+       New function.
+       (lll_mutex_cond_lock): Define.
+
+2003-05-29  Ulrich Drepper  <drepper@redhat.com>
+
+       * Makefile (tests): Add tst-signal6.
+       * tst-signal6.c: New file.
+
+       * sysdeps/unix/sysv/linux/s390/lowlevellock.h
+       (__lll_mutex_unlock_force): New function
+       (lll_mutex_unlock_force): Use __lll_mutex_unlock_force.
+
+       * sysdeps/unix/sysv/linux/ia64/lowlevellock.h
+       (__lll_mutex_unlock_force): New function.
+       (lll_mutex_unlock_force): Use __lll_mutex_unlock_force.
+
+       * tst-rwlock7.c (do_test): Use correct format specifier.
+
+       * sysdeps/unix/sysv/linux/ia64/lowlevellock.h (lll_futex_requeue):
+       Find break parameter in correct asm argument.
+
+2003-05-27  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/ia64/lowlevellock.h (lll_futex_clobbers):
+       Remove out4.
+       (lll_futex_requeue): Fix __o3 constraint, return negative errno if
+       error occured.
+       * sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h (pthread_cond_t):
+       Add __mutex.
+       * sysdeps/unix/sysv/linux/s390/lowlevellock.h (FUTEX_REQUEUE,
+       lll_futex_requeue, lll_mutex_unlock_force): Define.
+
+2003-05-30  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h
+       (pthread_cond_t): Add __mutex.
+       * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h (FUTEX_REQUEUE,
+       lll_futex_requeue, lll_mutex_unlock_force): Define.
+
+2003-05-28  Kaz Kojima  <kkojima@rr.iij4u.or.jp>
+
+       * sysdeps/sh/tcb-offsets.sym: Define MUTEX_FUTEX.
+       * sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h (pthread_cond_t):
+       Add __mutex field.
+       * sysdeps/unix/sysv/linux/sh/lowlevellock.h (SYSCALL_WITH_INST_PAD):
+       Define.
+       (lll_futex_wait, lll_futex_wake): Define.
+       * sysdeps/unix/sysv/linux/sh/sh4/lowlevellock.h: New file.
+       * sysdeps/unix/sysv/linux/sh/pthread_cond_broadcast.S: Try using
+       FUTEX_REQUEUE instead of FUTEX_WAIT.
+       * sysdeps/unix/sysv/linux/sh/pthread_cond_signal.S: Likewise.
+       * sysdeps/unix/sysv/linux/sh/pthread_cond_timedwait.S: Remember
+       mutex which was used in condvar structure.  Call
+       __pthread_mutex_cond_lock instead of __pthread_mutex_lock_internal.
+       * sysdeps/unix/sysv/linux/sh/pthread_cond_wait.S: Likewise.
+
+       * sysdeps/unix/sysv/linux/sh/pthread_rwlock_rdlock.S: Don't
+       include tcb-offsets.h.  Read wakeup value in locked region.
+       Use the value of gbr register as THREAD_ID.
+       * sysdeps/unix/sysv/linux/sh/pthread_rwlock_wrlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedrdlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedwrlock.S: Likewise.
+
+       * sysdeps/unix/sysv/linux/sh/sem_trywait.S: Remove futex related
+       macros.
+
+2003-05-28  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/pthread_cond_broadcast.c
+       (__pthread_cond_broadcast): Fix typo: MAX_INT -> INT_MAX.
+
+2003-05-26  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S: Fix
+       typo in register name.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_signal.S: Use parameters
+       correctly.  Actually use requeue.  Little optimization.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: Store
+       mutex address early.  Handle cancellation state as 32-bit value.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S: Likewise.
+       Remove unnecessary label.
+
+2003-05-25  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/pthread_cond_broadcast.c: Try using FUTEX_REQUEUE
+       instead of FUTEX_WAIT.
+       * sysdeps/pthread/pthread_cond_signal.c: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_signal.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_signal.S: Likewise.
+       * sysdeps/pthread/pthread_cond_timedwait.c: Remember mutex which was
+       used in condvar structure.  Call __pthread_mutex_cond_lock instead
+       of __pthread_mutex_lock_internal.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: Likewise.
+       * sysdeps/pthread/pthread_cond_wait.c: Likewise.
+       (__condvar_cleanup): Always call __pthread_mutex_cond_lock.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S: Likewise.
+       * sysdeps/unix/sysv/linux/Makefile (libpthread-sysdep_routines):
+       Add pthread_mutex_cond_lock.
+       * sysdeps/unix/sysv/linux/lowlevelcond.sym: Add dep_mutex.
+       * sysdeps/unix/sysv/linux/pthread_cond_mutex_lock.c: New file.
+       * sysdeps/unix/sysv/linux/i386/lowlevellock.h: Define
+       lll_mutex_cond_lock.
+       * sysdeps/unix/sysv/linux/ia64/lowlevellock.h: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h: Likewise.
+       * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h (pthread_cond_t):
+       Add __mutex field.
+       * sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: Likewise.
+
+       * sysdeps/i386/tcb-offsets.sym: Define MUTEX_FUTEX.
+       * sysdeps/x86_64/tcb-offsets.sym: Likewise.
+
+       * pthreadP.h: Declare __pthread_mutex_cond_lock.
+       * pthread_mutex_lock.c: Define LLL_MUTEX_LOCK if not already defined.
+       Use it instead of lll_mutex_lock.  If __pthread_mutex_lock is a
+       macro don't define aliases.
+
+       * cancellation.c: Remove __pthread_enable_asynccancel_2.
+       * pthreadP.h: Remove declaration of __pthread_enable_asynccancel_2.
+       * sysdeps/pthread/pthread_cond_timedwait.c: Use
+       __pthread_enable_asynccancel instead of __pthread_enable_asynccancel_2.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: Likewise.
+       * sysdeps/pthread/pthread_cond_wait.c: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S: Likewise.
+
+2003-05-17  Ulrich Drepper  <drepper@redhat.com>
+
+       * sem_open.c: Fix one endless loop.  Implement correct semantics
+       wrt opening the same semaphore more then once.
+       * sem_close.c: Adjust for sem_open change.
+       * semaphoreP.h: Include <semaphore.h>.  Define struct inuse_sem.
+       Declare __sem_mappings, __sem_mappings_lock, __sem_search.
+       * Makefile (tests): Add tst-sem7.
+       * tst-sem7.c: New file.
+
+2003-05-16  Roland McGrath  <roland@redhat.com>
+
+       * sysdeps/unix/sysv/linux/register-atfork.c (libc_freeres_fn): Fix
+       uninitialized variable braino.
+
+2003-05-16  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/timer_gettime.c (timer_gettime): Correct
+       test for syscall availability.
+
+       * sysdeps/unix/sysv/linux/timer_settime.c (timer_settime): Set
+       __no_posix_timers to -1 if the syscalls don't exist.
+
+       * pthread_join.c (pthread_join): Set tid field of the joined
+       thread to -1.  This isn't necessary but helps to recognize some
+       error conditions with almost no cost.
+
+       * allocatestack.c (FREE_P): Also negative values indicate an
+       unused stack.
+
+       * unwind.c: Include <unistd.h>.
+
+2003-05-14  Ulrich Drepper  <drepper@redhat.com>
+
+       * Makefile ($(objpfx)$(multidir)): Add rule to create the directory.
+
+2003-05-14  Jakub Jelinek  <jakub@redhat.com>
+
+       * Makefile (crti-objs, crtn-objs): New variables.
+       (omit-deps, extra-objs): Add crtn.
+       ($(objpfx)libpthread.so): Depend on both crti and crtn
+       and links to them in multidir.
+       ($(objpfx)crtn.S, $(objpfx)crtn.o): New rules.
+
+2003-05-12  Steven Munroe  <sjmunroe@us.ibm.com>
+
+       * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h
+       (lll_mutex_unlock): Use atomic_exchange_rel.
+
+2003-05-11  Ulrich Drepper  <drepper@redhat.com>
+
+       * cond-perf.c (cons): Add missing locking around setting of alldone.
+
+2003-05-10  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/i486/sem_trywait.S: Remove futex
+       related macros.
+       * sysdeps/unix/sysv/linux/x86_64/sem_trywait.S: Likewise.
+
+2003-05-09  Ulrich Drepper  <drepper@redhat.com>
+
+       * tst-sem6.c: New file.
+       * Makefile (tests): Add tst-sem6.
+
+       * sysdeps/unix/sysv/linux/ia64/lowlevellock.h (___lll_mutex_unlock):
+       Use atomic_exchange_rel instead of atomic_exchange.
+       * sysdeps/unix/sysv/linux/lowlevellock.c (lll_unlock_wake_cb):
+       Likewise.
+
+       * sysdeps/unix/sysv/linux/i386/lowlevellock.h: Improve quality of
+       code for lll_futex_wait and lll_futex_wake in static apps.  Use
+       vsyscall is possible.
+
+       * sysdeps/unix/sysv/linux/pthread_getaffinity.c: New file.
+       * sysdeps/unix/sysv/linux/pthread_setaffinity.c: New file.
+       * sysdeps/pthread/pthread.h: Declare pthread_getaffinity_np and
+       pthread_setaffinity_np.
+       * Versions [libpthread] (GLIBC_2.3.3): Add pthread_getaffinity_np
+       and pthread_setaffinity_np.
+       * Makefile (libpthread-routines): Add pthread_getaffinity and
+       pthread_setaffinity.
+
+       * allocatestack.c (allocate_stack): If ARCH_RETRY_MMAP is defined,
+       use it in case mmap to allocate the stack fails.
+       * sysdeps/unix/sysv/linux/x86_64/Makefile: Don't define
+       ARCH_MAP_FLAGS here.
+       * sysdeps/x86_64/pthreaddef.h: Define ARCH_MAP_FLAGS and
+       ARCH_RETRY_MMAP.
+
+2003-05-08  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/fork.c: Complete rewrite of the atfork
+       handler implementation.  It is now lockless in fork().
+       * sysdeps/unix/sysv/linux/register-atfork.c: Likewise.
+       * sysdeps/unix/sysv/linux/unregister-atfork.c: Likewise.
+       * sysdeps/unix/sysv/linux/fork.h: Don't include <link.h>.  Don't
+       declare the __fork_*_lists.
+       (struct fork_handler): Include pointers to all three functions.
+       Add next, refcntr and need_signal elements.
+       (__fork_handlers): New declaration.
+       (__register_atfork_malloc): Remove declaration.
+       (HAVE_register_atfork_malloc): Remove definition.
+       * sysdeps/unix/sysv/linux/libc_pthread_init.c: Remove
+       __pthread_child_handler variable.
+       (__libc_pthread_init): Use __register_atfork instead of explicitly
+       adding to the list.
+       * sysdeps/unix/sysv/linux/i386/lowlevellock.h: Define lll_futex_wait
+       and lll_futex_wake.
+       * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h: Likewise.
+
+       * unwind.c (unwind_cleanup): Print error message and then abort.  This
+       function must never be reached.
+
+       * cond-perf.c: New file.
+
+2003-05-05  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/i386/tls.h (TLS_INIT_TP): Include \n in error message.
+
+2003-05-04  Roland McGrath  <roland@redhat.com>
+
+       * Makefile ($(objpfx)../libc.so): New target.
+
+2003-05-02  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h
+       (pthread_condattr_t): Size is only an int, don't use long for
+       alignment.
+       (pthread_mutexattr_t): Likewise.
+       * sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h: Likewise.
+
+2003-05-01  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/i386/tls.h: Define THREAD_ID.
+       * sysdeps/ia64/tls.h: Likewise.
+       * sysdeps/powerpc/tls.h: Likewise.
+       * sysdeps/s390/tls.h: Likewise.
+       * sysdeps/sh/tls.h: Likewise.
+       * sysdeps/x86_64/tls.h: Likewise.
+       * pthread_mutex_lock.c: Use THREAD_ID instead of THREAD_SELF to
+       record ownership.
+       * pthread_mutex_timedlock.c: Likewise.
+       * pthread_mutex_trylock.c: Likewise.
+       * pthread_mutex_unlock.c: Likewise.
+       * pthread_rwlock_trywrlock.c: Likewise.
+       * sysdeps/pthread/pthread_rwlocklock_rdlock.c: Likewise.
+       * sysdeps/pthread/pthread_rwlock_timedrdlock.c: Likewise.
+       * sysdeps/pthread/pthread_rwlock_timedwrlock.c: Likewise.
+       * sysdeps/pthread/pthread_rwlock_wrlock.c: Likewise.
+
+       * sysdeps/pthread/createthread.c (create_thread): Use CLONE_SYSVSEM
+       flag.
+
+2003-04-29  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h
+       (__SIZEOF_PTHREAD_COND_T): Define to 48.
+       (pthread_rwlock_t): Add 16 bytes of pad instead of 8 before __flags.
+       * sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h (pthread_cond_t):
+       Make __align long long instead of long.
+       (pthread_rwlock_t): Formatting.
+       * sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h
+       (pthread_rwlock_t): Formatting.
+       * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h
+       (pthread_cond_t): Make __align long long instead of long.
+       (pthread_rwlock_t): Move __flags field to the same position as in
+       linuxthreads.
+
+2003-04-30  Ulrich Drepper  <drepper@redhat.com>
+
+       * tst-rwlock6.c (do_test): Use correct printf format specifiers.
+       * tst-rwlock7.c (do_test): Likewise.
+
+2003-04-26  Roland McGrath  <roland@redhat.com>
+
+       * Makefile ($(test-modules)): Depend on $(common-objpfx)shlib.lds.
+
+2003-04-22  Jakub Jelinek  <jakub@redhat.com>
+
+       * allocatestack.c (TLS_TPADJ): Add TLS_PRE_TCB_SIZE instead of
+       sizeof (struct pthread).
+       (allocate_stack): Subtract TLS_PRE_TCB_SIZE bytes instead of
+       1 struct pthread.
+       * sysdeps/powerpc/tls.h (TLS_INIT_TCB_SIZE, TLS_TCB_SIZE): Define
+       to 0.
+       (TLS_INIT_TCB_ALIGN, TLS_TCB_ALIGN): Define to alignment of
+       struct pthread.
+       (TLS_PRE_TCB_SIZE): Increase to cover tcbhead_t preceeded by pad
+       to 32-bit bytes.
+       (INSTALL_DTV, GET_DTV, THREAD_DTV): tcbhead_t is immediately before
+       tcbp.
+       (TLS_INIT_TP, THREAD_SELF, INIT_THREAD_SELF): Don't add TLS_TCB_SIZE
+       unneccessarily.
+       (NO_TLS_OFFSET): Define.
+       * sysdeps/unix/sysv/linux/powerpc/createthread.c (TLS_VALUE): Don't
+       add TLS_TCB_SIZE unnecessarily.
+
+2003-04-22  Roland McGrath  <roland@redhat.com>
+
+       * Makeconfig (shared-thread-library): Reverse link order to work
+       around linker bug.
+
+2003-04-22  Ulrich Drepper  <drepper@redhat.com>
+
+       * semaphore.h: Fix typo in comment.
+
+2003-04-21  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/sigfillset.c: New file.
+
+       * init.c (__pthread_initialize_minimal): Don't block SIGTIMER.
+       * pthreadP.h: Make SIGTIMER and SIGCANCEL the same.
+       * sysdeps/pthread/pthread_sigmask.c: Remove handling of SIGTIMER.
+       * sysdeps/pthread/sigaction.c: Likewise.
+       * sysdeps/pthread/sigprocmask.c: New file.
+       * sysdeps/unix/sysv/linux/allocrtsig.c (current_rtmin): Define as
+       __SIGRTMIN+1.
+       * sysdeps/unix/sysv/linux/timer_routines.c (timer_helper_thread):
+       Block SIGTIMER.  Also handle SI_TKILL events and terminate thread
+       in this case.
+
+2003-04-19  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/dl-sysdep.h
+       (DL_SYSINFO_IMPLEMENTATION): Add .eh_frame information.
+
+       * sysdeps/unix/sysv/linux/unregister-atfork.c
+       (__unregister_atfork): Don't free memory not allocated dynamically.
+
+       * semaphore.h: Remove __THROW marker from cancellation points.
+       * nptl/sysdeps/pthread/pthread.h: Likewise.
+
+2003-04-18  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/pthread.h: Don't mark pthread_testcancel,
+       pthread_cancel, pthread_setcancelstate, and pthread_setcanceltype with
+       __THROW.
+
+2003-04-16  Jakub Jelinek  <jakub@redhat.com>
+
+       * tst-cancel4.c (do_test): Use %zd instead of %d when printing cnt.
+
+2003-04-15  Roland McGrath  <roland@redhat.com>
+
+       * forward.c (__pthread_unwind): Tweak to avoid warning.
+
+2003-04-15  Ulrich Drepper  <drepper@redhat.com>
+
+       * pthreadP.h: Move THREAD_ATOMIC_* replacements to the top.
+
+2003-04-14  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S: Don't
+       overflow CFA advance instructions.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: Likewise.
+
+2003-04-14  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/i386/tls.h: Rename LOCK to LOCK_PREFIX.
+       * sysdeps/i386/pthread_spin_lock.c: Likewise.
+       * sysdeps/x86_64/tls.h: Likewise.  Define LOCK_PREFIX if not already
+       defined.
+
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Use
+       DW_CFA_advance_loc2 for .Laddl-.Lsubl.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Use
+       DW_CFA_advance_loc for .Laddl-.Lsubl.
+
+2003-04-13  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h: Don't use
+       position-independent unwind data for static libraries.
+       Add missing unwind info.  Add comments.
+
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S: Add unwind info.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Likewise.
+
+2003-04-12  Ulrich Drepper  <drepper@redhat.com>
+
+       * Makefile: Make sure all cancellation points are compiled with
+       exception and asynchronous unwind tables.
+
+       * sysdeps/x86_64/tls.h (THREAD_SETMEM): Word around compiler bug
+       which mishandles loading of global object addresses in PIC.
+       (THREAD_SETMEM_NC): Likewise.
+
+2003-04-11  Ulrich Drepper  <drepper@redhat.com>
+
+       * pthread.h: Define new data structure for cleanup buffer.  Declare
+       new cleanup handler interfaces.
+       * descr.h: Include <unwind.h> if necessary.  Define pthread_unwind_buf.
+       (struct pthread): Add cleanup_jmp_buf pointer.  Define
+       HAVE_CLEANUP_JMP_BUF and not HAVE_CANCELBUF.
+       * pthreadP.h: Declare __pthread_unwind.  Define __do_cancel to use
+       it.  Declare old cleanup handler installation functions.
+       * cleanup.c: Rewrite.  Install handler for unwind-based cleanup
+       handling.
+       * cleanup_defer.c: Likewise.
+       * cleanup_compat.c: New file.  Old cleanup code.
+       * cleanup_def_compat.c: New file.  Old cleanup code.
+       * pthread_create.c (start_thread): Initialize cleanup_jmp_buf element
+       if own thread descriptor.
+       * unwind.c: New file.
+       * forward.c: Add __pthread_unwind.
+       * init.c (pthread_functions): Add __pthread_unwind.
+       * sysdeps/pthread/pthread-functions.s (struct pthread_functions):
+       Add ptr___pthread_unwind.
+       * Versions [GLIBC_2.3.3] (libpthread): Export new cleanup handling
+       and unwind function.
+       * Makefile (libpthread-routines): Add cleanup_compat,
+       cleanup_def_compat, and unwind.  Define CFLAGS to enable unwind
+       table generation if necessary.
+       * version.c: Record whether unwind support is compiled in.
+       * sysdeps/pthread/configure.in: Add checks for unwind unterfaces.
+       * sysdeps/pthread/bits/libc-lock.h: Add prototypes of the old cleanup
+       handler interfaces.
+       * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h: Add quite a bit of
+       complication to generate unwind information for syscall wrappers.
+       * sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h: Likewise.
+       * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h: Define
+       __cleanup_fct_attribute.
+
+       * Makefile: Add rules to build and run tst-cleanup0.
+       * tst-cleanup0.c: New file.
+       * tst-cleanup0.expect: New file.
+
+       * pthread_create.c (deallocate_tsd): Don't take parameter.  Adjust
+       caller.  Optimize to avoid often unecessary local variable.
+
+2003-04-11  Roland McGrath  <roland@redhat.com>
+
+       * Makefile ($(objpfx)multidir.mk): New target, generated makefile that
+       sets variable `multidir'; include that.
+       (generated): Add it.
+       ($(objpfx)$(multidir)/crti.o): New target.
+       [$(multidir) != .] (generated-dirs, extra-objs, omit-deps): Add it.
+
+2003-04-11  Ulrich Drepper  <drepper@redhat.com>
+
+       * tst-attr2.c (do_test): Add cast to avoid warning.
+       * tst-mutex4.c (do_test): Likewise.
+
+2003-04-10  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/fork.c (__libc_fork): Reset CPU clocks
+       in child.
+
+2003-04-09  Ulrich Drepper  <drepper@redhat.com>
+
+       * Makefile (tests): Add tst-detach1.
+       * tst-detach1.c: New file.
+
+2003-04-08  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/pthread.h: Remove duplicate
+       pthread_cleanup_{push,pop} definitions.
+
+       * tst-barrier2.c: Eliminate warnings.
+       * tst-cancel4.c: Likewise.
+       * tst-cond4.c: Likewise.
+       * tst-cond6.c: Likewise.
+       * tst-detach1.c: Likewise.
+       * tst-rwlock4.c: Likewise.
+       * tst-rwlock6.c: Likewise.
+       * tst-rwlock7.c: Likewise.
+       * tst-sem3.c: Likewise.
+       * tst-spin2.c: Likewise.
+       * tst-umask1.c: Likewise.
+
+2003-04-07  Ulrich Drepper  <drepper@redhat.com>
+
+       * pthread_detach.c (pthread_detach): Fix test for invalid TID.
+
+2003-04-06  Ulrich Drepper  <drepper@redhat.com>
+
+       * descr.h (struct pthread): Move cancelhandling member to the front.
+
+2003-04-05  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/register-atfork.c: Define malloc_prepare,
+       malloc_parent, and malloc_child statically.
+       (__register_atfork_malloc): New function.
+       (free_mem): Don't free any of the malloc_* variables on the list.
+       * sysdeps/unix/sysv/linux/fork.h: Declare __register_atfork_malloc.
+       Define HAVE_register_atfork_malloc.
+
+2003-04-04  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/createthread.c (create_thread): Add some more
+       comments explaining when to set multiple_threads and when not.
+
+       * pthreadP.h: Define THREAD_ATOMIC_CMPXCHG_VAL and
+       THREAD_ATOMIC_BIT_SET if not already defined.
+       * sysdeps/i386/tls.h: Define THREAD_ATOMIC_CMPXCHG_VAL and
+       THREAD_ATOMIC_BIT_SET:
+       * sysdeps/x86_64/tls.h: Likewise.
+       * cleanup_defer.c (_pthread_cleanup_push_defer): Rewrite to use
+       THREAD_ATOMIC_CMPXCHG_VAL.
+       (_pthread_cleanup_pop_restore): Likewise.
+       * cancellation.c (__pthread_enable_asynccancel): Likewise.
+       (__pthread_enable_asynccancel_2): Likewise.
+       (__pthread_disable_asynccancel): Likewise.
+       * libc-cancellation.c (__libc_enable_asynccancel): Likewise.
+       (__libc_disable_asynccancel): Likewise.
+       * init.c (sigcancel_handler): Likewise.
+       * pthread_setcancelstate.c (__pthread_setcancelstate): Likewise.
+       * pthread_setcanceltype.c (__pthread_setcanceltype): Likewise.
+
+2003-04-03  Ulrich Drepper  <drepper@redhat.com>
+
+       * init.c (sigcancel_handler): Don't set EXITING_BIT here.
+       * libc-cancellation.c (__libc_enable_asynccancel): Likewise.
+       * pthreadP.h (__do_cancel): Set EXITING_BIT here.
+       * Makefile (tests): Add tst-cancel11.
+       * tst-cancel11.c: New file.
+
+2003-04-01  Ulrich Drepper  <drepper@redhat.com>
+
+       * pthread_create.c (deallocate_tsd): Clear/free memory after the last
+       round, not the first.  Use specific_used flag instead of local
+       found_nonzero variable.  Use THREAD_[SG]ETMEM where possible.
+       (__free_tcb): Don't call deallocate_tsd here.
+       (start_thread): Call deallocate_tsd here.
+       * pthread_setspecific.c: Set specific_used flag really only when
+       needed.
+       * Makefile (tests): Add tst-tsd3.c and tst-tsd4.
+       * tst-tsd3.c: New file.
+       * tst-tsd4.c: New file.
+
+2003-03-31  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/ia64/lowlevellock.h (__lll_mutex_lock):
+       Use atomic_exchange_and_add instead of __lll_add.
+       (__lll_mutex_timedlock): Likewise.
+       Patch by Ian Wienand.
+
+2003-03-24  Steven Munroe  <sjmunroe@us.ibm.com>
+
+       * sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h
+       (SINGLE_THREAD_P): Fix typo.
+       * tst-cancel-wrappers.sh: Handle '.'ed symbols.
+
+2003-03-31  Ulrich Drepper  <drepper@redhat.com>
+
+       * Makefile (tests): Add tst-align.
+       * tst-align.c: New file.
+       * sysdeps/i386/Makefile: Define CFLAGS-tst-align.
+
+       * sysdeps/i386/tls.h (CALL_THREAD_FCT): Align stack of called
+       function correctly.
+
+       * tst-tsd2.c: Add casts to avoid warnings.
+
+2003-03-30  Ulrich Drepper  <drepper@redhat.com>
+
+       * descr.h (struct pthread): Move most often used elements to the front.
+
+2003-03-29  Ulrich Drepper  <drepper@redhat.com>
+
+       * Makefile (libpthread-routines): Add pthread_atfork.
+       (libpthread-static-only-routines): Add pthread_atfork.
+
+2003-03-28  Kaz Kojima  <kkojima@rr.iij4u.or.jp>
+
+       * sysdeps/sh/tls.h: Include nptl/descr.h after the definition
+       of TLS_DTV_AT_TP.
+       (INSTALL_DTV): Add parens.
+       (THREAD_GETMEM, THREAD_GETMEM_NC, THREAD_SETMEM, THREAD_SETMEM_NC):
+       Use passed descr instead of THREAD_SELF.
+       * sysdeps/unix/sysv/linux/sh/lowlevelmutex.S
+       (__lll_mutex_timedlock_wait): Correct expected value after
+       spurious wakeup.
+       * sysdeps/unix/sysv/linux/sh/pthread_cond_broadcast.S:
+       Release lock before waking up the waiters.
+       * sysdeps/unix/sysv/linux/sh/pthread_cond_wait.S: Correct exit
+       criteria.  Reorderstruct passed to cleanup handler.  Fix
+       handling of cancellation and failung pthread_mutex_unlock call.
+       Use __pthread_enable_asynccancel_2 instead of
+       __pthread_enable_asynccancel.
+       * sysdeps/unix/sysv/linux/sh/pthread_cond_timedwait.S: Likewise.
+       Return result of lock re-get if it fails.
+       * sysdeps/unix/sysv/linux/sh/pthread_once.S: Fix wrong argument
+       for __pthread_cleanup_push.
+       * sysdeps/unix/sysv/linux/sh/pthread_rwlock_rdlock.S: Fix
+       completely broken rwlock implementation.
+       * sysdeps/unix/sysv/linux/sh/pthread_rwlock_wrlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedrdlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedwrlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/sh/pthread_rwlock_unlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/sh/pthread_rwlock_wrlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/sh/sem_post.S: Fix error value.  Use
+       versioned_symbol macro.
+       * sysdeps/unix/sysv/linux/sh/sem_trywait.S: Use versioned_symbol macro.
+       * sysdeps/unix/sysv/linux/sh/sem_wait.S: Likewise.
+
+2003-03-27  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/kernel-posix-timers.h: Don't declare
+       __timer_helper_thread.  Declare __start_helper_thread, __helper_once,
+       and __helper_tid.
+       (struct timer): Remove th and bar field.
+       * sysdeps/unix/sysv/linux/timer_create.c (timer_create): Remove
+       debugging code.  Create only one helper thread.
+       * sysdeps/unix/sysv/linux/timer_delete.c (timer_delete): Don't kill
+       helper thread.
+       * sysdeps/unix/sysv/linux/timer_routines.c (timer_helper_thread):
+       Renamed.  Define statically.  Use thread info from siginfo.
+       (__helper_once): New variable.
+       (__helper_tid): New variable.
+       (__reset_helper_control): New function.
+       (__start_helper_thread): New function.
+
+       * pthread_create.c (start_thread): Don't use setjmp inside
+       __builtin_expect to work around gcc bug.
+
+       * sysdeps/unix/sysv/linux/timer_delete.c (timer_delete): Even if
+       timer_delete syscall fails, but not with ENOSYS, set
+       __no_posix_timers.
+
+       * sysdeps/unix/sysv/linux/timer_settime.c [!__ASSUME_POSIX_TIMERS]
+       (timer_settime): Fix typo.
+       * sysdeps/unix/sysv/linux/timer_getoverr.c
+       [!__ASSUME_POSIX_TIMERS] (timer_getoverrun): Likewise.
+
+2003-03-27  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Fix
+       offset of cleanupbuf.__prev.
+
+2003-03-26  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/timer_getoverr.c: Fix typo in name
+       of included file.
+
+2003-03-26  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/timer_create.c (timer_create): If EVP ==
+       NULL provide default definition to syscall.
+
+2003-03-25  Roland McGrath  <roland@redhat.com>
+
+       * sysdeps/pthread/posix-timer.h (TIMER_MAX): Define if not defined.
+       (timer_id2ptr): Fix typo.
+
+2003-03-25  Ulrich Drepper  <drepper@redhat.com>
+
+       * pthreadP.h: Define SIGCANCEL and SIGTIMER.
+       * sysdeps/i386/pthreaddef.h: Remove SIGCANCEL definition.
+       * sysdeps/ia64/pthreaddef.h: Likewise.
+       * sysdeps/powerpc/pthreaddef.h: Likewise.
+       * sysdeps/s390/pthreaddef.h: Likewise.
+       * sysdeps/sh/pthreaddef.h: Likewise.
+       * sysdeps/x86_64/pthreaddef.h: Likewise.
+       * init.c (__pthread_initialize_minimal): Block SIGTIMER.
+       * sysdeps/pthread/sigaction.c: Also prevent SIGTIMER handler from
+       being changed.
+       * sysdeps/pthread/pthread_sigmask.c (pthread_sigmask): Make sure
+       SIGTIMER is not unblocked.
+       * sysdeps/unix/sysv/linux/allocrtsig.c (current_rtmin): One more
+       RT signal taken.
+       * sysdeps/unix/sysv/linux/pthread_kill.c: Do not allow SIGTIMER to
+       be send.
+       * sysdeps/pthread/posix-timer.h (timer_id2ptr, timer_ptr2id): Just
+       pass pointer through as ID.
+       * sysdeps/unix/sysv/linux/bits/local_lim.h (TIMER_MAX): Removed.
+       * sysdeps/unix/sysv/linux/kernel-posix-timers.h: New file.
+       * sysdeps/unix/sysv/linux/timer_create.c: New file.
+       * sysdeps/unix/sysv/linux/timer_delete.c: New file.
+       * sysdeps/unix/sysv/linux/timer_getoverr.c: New file.
+       * sysdeps/unix/sysv/linux/timer_gettime.c: New file.
+       * sysdeps/unix/sysv/linux/timer_routines.c: New file.
+       * sysdeps/unix/sysv/linux/timer_settime.c: New file.
+       * sysdeps/unix/sysv/linux/ia64/Versions: New file.
+       * sysdeps/unix/sysv/linux/ia64/timer_create.c: New file.
+       * sysdeps/unix/sysv/linux/ia64/timer_delete.c: New file.
+       * sysdeps/unix/sysv/linux/ia64/timer_getoverr.c: New file.
+       * sysdeps/unix/sysv/linux/ia64/timer_gettime.c: New file.
+       * sysdeps/unix/sysv/linux/ia64/timer_settime.c: New file.
+       * sysdeps/unix/sysv/linux/powerpc/powerpc64/Versions: New file.
+       * sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_create.c: New file.
+       * sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_delete.c: New file.
+       * sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_getoverr.c: New file.
+       * sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_gettime.c: New file.
+       * sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_settime.c: New file.
+       * sysdeps/unix/sysv/linux/s390/s390-64/Versions: New file.
+       * sysdeps/unix/sysv/linux/s390/s390-64/timer_create.c: New file.
+       * sysdeps/unix/sysv/linux/s390/s390-64/timer_delete.c: New file.
+       * sysdeps/unix/sysv/linux/s390/s390-64/timer_getoverr.c: New file.
+       * sysdeps/unix/sysv/linux/s390/s390-64/timer_gettime.c: New file.
+       * sysdeps/unix/sysv/linux/s390/s390-64/timer_settime.c: New file.
+       * sysdeps/unix/sysv/linux/x86_64/Versions: New file.
+       * sysdeps/unix/sysv/linux/x86_64/compat-timer.h: New file.
+       * sysdeps/unix/sysv/linux/x86_64/timer_create.c: New file.
+       * sysdeps/unix/sysv/linux/x86_64/timer_delete.c: New file.
+       * sysdeps/unix/sysv/linux/x86_64/timer_getoverr.c: New file.
+       * sysdeps/unix/sysv/linux/x86_64/timer_gettime.c: New file.
+       * sysdeps/unix/sysv/linux/x86_64/timer_settime.c: New file.
+
+       * pthreadP.h: Remove FRAME_LEFT definition.
+       * cleanup.c (_pthread_cleanup_push): Don't check for reference to
+       already left frame.  Programs which have this problem are not POSIX
+       compliant.
+       * cleanup_defer.c (_pthread_cleanup_push_defer): Likewise.
+
+2003-03-24  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/tst-timer.c: Check return values of the
+       functions we test.
+
+2003-03-23  Roland McGrath  <roland@redhat.com>
+
+       * tst-tls3.c (do_test) [! HAVE___THREAD]: Don't test anything.
+       * tst-tls3mod.c: Likewise.
+       * tst-tls1.c: Likewise.
+       * tst-tls2.c: Likewise.
+
+       * tst-mutex5.c (do_test): Unlock before destroy, otherwise we invoke
+       undefined behavior.
+
+       * tst-join5.c (tf1, tf2): Add a cast.
+
+       * Makeconfig (includes): Append -I$(..)nptl to this variable.
+
+       * tst-barrier2.c (do_test) [! _POSIX_THREAD_PROCESS_SHARED]:
+       Don't test anything.
+       * tst-cond4.c: Likewise.
+       * tst-cond6.c: Likewise.
+       * tst-flock2.c: Likewise.
+       * tst-mutex4.c: Likewise.
+       * tst-rwlock4.c: Likewise.
+       * tst-signal1.c: Likewise.
+       * tst-spin2.c: Likewise.
+       * tst-cond11.c [! _POSIX_CLOCK_SELECTION]: Likewise.
+
+       * tst-mutex4.c: Use test-skeleton.c.
+       * tst-spin2.c: Likewise.
+       * tst-sysconf.c: Likewise.
+       * tst-barrier2.c: Likewise.
+       * tst-cond4.c: Likewise.
+       * tst-cond6.c: Likewise.
+       * tst-rwlock4.c: Likewise.
+       * tst-unload.c: Likewise.
+       * tst-flock2.c (do_test): Use return instead of exit.
+
+2003-03-22  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/fork.c (__fork): Add libc_hidden_def.
+
+2003-03-21  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/ia64/lowlevellock.h
+       (__lll_mutex_trylock): Use atomic_compare_and_exchange_val_acq
+       instead of __lll_compare_and_swap.
+       * sysdeps/unix/sysv/linux/ia64/pthread_once.c (__pthread_once):
+       Likewise.
+       Removed definition if __lll_compare_and_swap.
+
+       * cancellation.c: Adjust for new form of compare&exchange macros.
+       * cleanup_defer.c: Likewise.
+       * init.c: Likewise.
+       * libc-cancellation.c: Likewise.
+       * old_pthread_cond_broadcast.c: Likewise.
+       * old_pthread_cond_signal.c: Likewise.
+       * old_pthread_cond_timedwait.c: Likewise.
+       * old_pthread_cond_wait.c: Likewise.
+       * pthread_cancel.c: Likewise.
+       * pthread_create.c: Likewise.
+       * pthread_detach.c: Likewise.
+       * pthread_join.c: Likewise.
+       * pthread_key_delete.c: Likewise.
+       * pthread_setcancelstate.c: Likewise.
+       * pthread_setcanceltype.c: Likewise.
+       * pthread_timedjoin.c: Likewise.
+       * pthread_tryjoin.c: Likewise.
+       * sysdeps/pthread/createthread.c: Likewise.
+
+2003-03-20  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/ia64/lowlevellock.h: Include <atomic.h>.
+       Remove __lll_add, __lll_dec_if_positive, and __lll_test_and_set
+       definitions.  Replace uses with calls to atomic_* functions.
+       * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h: Likewise.
+       * sysdeps/unix/sysv/linux/lowlevellock.c: Replace __lll_add and
+       __lll_test_and_set calls with atomic_exchange_and_add and
+       atomic_exchange calls respectively.
+       * sysdeps/unix/sysv/linux/sem_post.c: Likewise.
+       * sysdeps/unix/sysv/linux/sem_timedwait.c: Likewise.
+       * sysdeps/unix/sysv/linux/sem_trywait.c: Likewise.
+       * sysdeps/unix/sysv/linux/sem_wait.c: Likewise.
+       * sysdeps/unix/sysv/linux/ia64/pthread_once.c: Likewise.
+       * sysdeps/unix/sysv/linux/ia64/sem_port.c: Likewise.
+       * sysdeps/unix/sysv/linux/powerpc/pthread_once.c: Likewise.
+
+       * allocatestack.c (allocate_stack): Assume atomic_exchange_and_add
+       returns the old value.
+
+2003-03-20  Martin Schwidefsky  <sky@mschwid3.boeblingen.de.ibm.com>
+
+       * sysdeps/s390/pthread_spin_lock.c (pthread_spin_lock): Use type
+       int for variable OLDVAL and correct inline assembler contraint.
+       * sysdeps/s390/pthread_spin_trylock.c (pthread_spin_trylock): Use
+       type int for variable OLD.
+
+       * sysdeps/s390/tls.h (TLS_MULTIPLE_THREADS_IN_TCB): Define it
+       only for s390-32.
+       * sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h
+       (SINGLE_THREAD_P): Use global variable __local_multiple_threads
+       instead of multiple_threads field in the TCB.
+
+2003-03-19  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/i386/i686/bits/atomic.h: Removed.
+       * sysdeps/i386/i586/bits/atomic.h: Removed.
+       * sysdeps/i386/i486/bits/atomic.h: Removed.  Moved to glibc.
+       * sysdeps/x86_64/bits/atomic.h: Removed.  Moved to glibc.
+       * sysdeps/s390/bits/atomic.h: Removed.  Moved to glibc.
+       * sysdeps/sh/bits/atomic.h: Removed.  Moved to glibc.
+       * sysdeps/ia64/bits/atomic.h: Removed.  Moved to glibc.
+       * sysdeps/powerpc/bits/atomic.h: Removed.  Moved to glibc.
+       * atomic.h: Removed.  Moved to glibc.
+
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: Add
+       support for clock selection.
+
+       * sysdeps/pthread/pthread_cond_broadcast.c: Release lock before
+       signalling waiters.
+
+2003-03-18  Roland McGrath  <roland@redhat.com>
+
+       * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h (__lll_test_and_set):
+       Add __lll_rel_instr first.  Add memory clobber.
+       (lll_mutex_unlock): Use __lll_test_and_set.
+       From Paul Mackerras <paulus@samba.org>.
+
+       * sysdeps/powerpc/tls.h (TLS_MULTIPLE_THREADS_IN_TCB): Define
+       unconditionally.
+       * sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h
+       (SINGLE_THREAD_P):  Add `header.' prefix.
+       From Paul Mackerras <paulus@samba.org>.
+
+       * Versions (libpthread: GLIBC_2.3.2): Move pthread_tryjoin_np and
+       pthread_timedjoin_np to ...
+       (libpthread: GLIBC_2.3.3): ... here.
+       (libpthread: GLIBC_2.2): Move pthread_barrierattr_getpshared there too.
+
+       * sysdeps/pthread/pthread_cond_timedwait.c (__pthread_cond_timedwait):
+       Avoid shadowing VAL variable.
+
+       * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h (__lll_test_and_set):
+       New macro.
+
+2003-03-18  Ulrich Drepper  <drepper@redhat.com>
+
+       * Makefile (tests): Add tst-cond11.
+       * tst-cond11.c: New file.
+
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Reorder
+       struct passed to cleanup handler to eliminate one more
+       instruction.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Likewise.
+
+       * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h
+       (pthrad_cond_t): Replace __unused field with __clock.
+
+       * sysdeps/pthread/pthread_cond_wait.c: Release condvar lock before
+       waken all waiters in cleanup handler.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Likewise.
+
+       * pthread_condattr_getclock.c: New file.
+       * pthread_condattr_setclock.c: New file.
+       * sysdeps/pthread/pthread.h: Declare these new functions.
+       * Versions [GLIBC_2.3.3] (libpthread): Add the new functions.
+       * Makefile (libpthread-routines): Add the new functions.
+       * sysdeps/unix/sysv/linux/internaltypes.h (struct pthread_condattr):
+       Renamed field to value.  Document use of the bits.
+       * pthread_condattr_getpshared.c: Adjust for struct pthread_condattr
+       change.
+       * pthread_condattr_setpshared.c: Likewise.
+       * pthread_cond_init.c (__pthread_cond_init): Initialized __clock field.
+       * sysdeps/unix/sysv/linux/lowlevelcond.sym: Add cond_clock symbol.
+       * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h (pthread_cond_t):
+       Add __clock field.
+       * sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S:
+       Implement clock selection.
+       * sysdeps/pthread/pthread_cond_timedwait.c: Likewise.
+       * pthread-errnos.sym: Add ENOSYS.
+       * sysdeps/unix/sysv/linux/bits/posix_opt.h: Define
+       _POSIX_CLOCK_SELECTION.
+       * sysdeps/unix/sysv/linux/i386/bits/posix_opt.h: Likewise.
+
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: Remove
+       invalid .size directive.
+
+2003-03-17  Roland McGrath  <roland@redhat.com>
+
+       * sysdeps/unix/sysv/linux/lowlevellock.c (__lll_lock_wait):
+       Formatting tweaks.
+
+2003-03-17  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/ia64/pthread_once.c: Use __builtin_expect.
+       Use __lll_add instead of spelling it out.  Use protected symbol names.
+       * sysdeps/unix/sysv/linux/ia64/sem_post.c: Use __builtin_expect.
+       Use __lll_add.
+       * sysdeps/unix/sysv/linux/ia64/lowlevellock.h (__lll_compare_and_swap):
+       Renamed from lll_compare_and_swap.  Use new name where necessary.
+       (__lll_add): Defined.
+       (__lll_dec_if_positive): Defined.
+       (__lll_test_and_set): Defined.
+       * sysdeps/ia64/pthread_spin_init.c: Removed.
+       * sysdeps/unix/sysv/linux/ia64/lowlevelmutex.c: Removed.
+       * sysdeps/unix/sysv/linux/ia64/sem_trywait.c: Removed.
+       * sysdeps/unix/sysv/linux/ia64/sem_wait.c: Removed.
+       * sysdeps/unix/sysv/linux/ia64/lowlevellock.c: Removed.
+       * sysdeps/unix/sysv/linux/ia64/libc-lowlevellock.c: Removed.
+       * sysdeps/unix/sysv/linux/ia64/libc-lowlevelmutex.c: Removed.
+       * sysdeps/unix/sysv/linux/ia64/sem_timedwait.c: Removed.
+       * sysdeps/ia64/bits/atomic.h: Add __builtin_expect where appropriate.
+       * sysdeps/ia64/pthread_spin_unlock.c (pthread_spin_unlock): Use
+       __sync_lock_release_si.
+       Patch by Jakub Jelinek.
+
+       * sysdeps/unix/sysv/linux/lowlevellock.c (__lll_timedlock_wait):
+       Fix timeout handling.
+       (__lll_timedwait_tid): Likewise.
+       (lll_unlock_wake_cb): Wake up other waiters if necessary.
+       Patch by Jakub Jelinek.
+
+       * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h: Pretty printing.
+
+2003-03-17  Roland McGrath  <roland@redhat.com>
+
+       PowerPC port contributed by Paul Mackerras <paulus@samba.org>.
+       * sysdeps/pthread/pthread_spin_init.c: New file.
+       * sysdeps/pthread/pthread_spin_unlock.c: New file.
+       * sysdeps/powerpc/Makefile: New file.
+       * sysdeps/powerpc/pthread_spin_lock.c: New file.
+       * sysdeps/powerpc/pthread_spin_trylock.c: New file.
+       * sysdeps/powerpc/pthreaddef.h: New file.
+       * sysdeps/powerpc/tcb-offsets.sym: New file.
+       * sysdeps/powerpc/td_ta_map_lwp2thr.c: New file.
+       * sysdeps/powerpc/tls.h: New file.
+       * sysdeps/powerpc/bits/atomic.h: New file.
+       * sysdeps/unix/sysv/linux/libc-lowlevelmutex.c: New file.
+       * sysdeps/unix/sysv/linux/libc-lowlevellock.c: New file.
+       * sysdeps/unix/sysv/linux/lowlevellock.c: New file.
+
+       * sysdeps/unix/sysv/linux/lowlevelmutex.c: New file.
+       * sysdeps/unix/sysv/linux/sem_post.c: New file.
+       * sysdeps/unix/sysv/linux/sem_timedwait.c: New file.
+       * sysdeps/unix/sysv/linux/sem_trywait.c: New file.
+       * sysdeps/unix/sysv/linux/sem_wait.c: New file.
+       * sysdeps/unix/sysv/linux/powerpc/Makefile: New file.
+       * sysdeps/unix/sysv/linux/powerpc/createthread.c: New file.
+       * sysdeps/unix/sysv/linux/powerpc/fork.c: New file.
+       * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h: New file.
+       * sysdeps/unix/sysv/linux/powerpc/pt-vfork.S: New file.
+       * sysdeps/unix/sysv/linux/powerpc/pthread_once.c: New file.
+       * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h: New file.
+       * sysdeps/unix/sysv/linux/powerpc/bits/semaphore.h: New file.
+       * sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h: New file.
+       * sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h: New file.
+
+       * sysdeps/unix/sysv/linux/ia64/lowlevellock.c: Use __gettimeofday,
+       not gettimeofday.
+       * sysdeps/unix/sysv/linux/ia64/lowlevelmutex.c: Likewise.
+       * sysdeps/unix/sysv/linux/ia64/sem_timedwait.c: Likewise.
+       * sysdeps/unix/sysv/linux/s390/lowlevellock.c: Likewise.
+       * sysdeps/unix/sysv/linux/s390/lowlevelmutex.c: Likewise.
+       * sysdeps/unix/sysv/linux/s390/sem_timedwait.c: Likewise.
+
+2003-03-17  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/pthread_cond_wait.c: Correct exit criteria.
+       * sysdeps/pthread/pthread_cond_timedwait.c: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Likewise.
+       Patch by Ewald Snel <ewald@rambo.its.tudelft.nl>.
+
+2003-03-16  Roland McGrath  <roland@redhat.com>
+
+       * tst-fork4.c: Include <string.h>.
+       * tst-signal2.c: Likewise.
+       * tst-mutex5.c (do_test): exit -> return.
+       * tst-mutex2.c: Include <stdlib.h>.
+
+2003-03-16  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/i486/lowlevelmutex.S
+       (__lll_mutex_timedlock_wait): Correct expected value after
+       spurious wakeup.  Otherwise we would never wait again.
+
+       * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h: Work around red
+       zone versus inline asm stupidity.  Use correct instructions.
+
+       * tst-rwlock6.c: Add some more status output.
+
+2003-03-15  Roland McGrath  <roland@redhat.com>
+
+       * sysdeps/pthread/configure.in: New file.
+       * sysdeps/pthread/configure: New file (generated).
+
+2003-03-15  Ulrich Drepper  <drepper@redhat.com>
+
+       * allocatestack.c (allocate_stack): Store the exact stack size of
+       user allocated stacks.
+
+2003-03-15  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h
+       (SINGLE_THREAD): Use `header' prefix instead of `header.data'.
+       * sysdeps/sh/tcb-offsets.sym (MULTIPLE_THREADS_OFFSET): Likewise.
+       * sysdeps/sh/tls.h (TLS_MULTIPLE_THREADS_IN_TCB): Define.
+       * sysdeps/unix/sysv/linux/ia64/sysdep-cancel.h (SINGLE_THREAD_P):
+       Use `header.' prefix.
+       * sysdeps/ia64/tcb-offsets.sym (MULTIPLE_THREADS_OFFSET): Likewise.
+
+2003-03-15  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/x86_64/pthreaddef.h (CURRENT_STACK_FRAME): Don't use
+       __builtin_frame_address, use stack pointer.
+
+       * sysdeps/unix/sysv/linux/jmp-unwind.c: Use CURRENT_STACK_FRAME
+       instead of __builtin_frame_pointer.
+
+2003-03-14  Ulrich Drepper  <drepper@redhat.com>
+
+       * tst-basic1.c (do_test): Add cast to avoid warning.
+       * tst-basic2.c (do_test): Likewise.
+
+       * sysdeps/unix/sysv/linux/x86_64/pthread_once.S: Use correct
+       amount of stack correction.
+
+       * tst-fork4.c: Use test-skeleton.c.
+
+2003-03-14  Roland McGrath  <roland@redhat.com>
+
+       * init.c: Fix typo "#eli" for "#else".
+
+2003-03-14  Steven Munroe  <sjmunroe@us.ibm.com>
+
+       * allocatestack.c (__stack_user): Use hidden_data_def.
+       * pthread_create.c (__pthread_keys): Likewise.
+
+       * init.c [__powerpc__] (__NR_set_tid_address): Define it.
+
+2003-03-14  Roland McGrath  <roland@redhat.com>
+
+       * tst-fork4.c: New file.
+       * Makefile (tests): Add it.
+
+       * descr.h (struct pthread): Move the union out of [!TLS_DTV_AT_TP], so
+       we always define the padding space.
+       [!TLS_DTV_AT_TP]: Give tcbhead_t field a name, `header', since GCC
+       stopped supporting its own extensions fully.
+       [TLS_MULTIPLE_THREADS_IN_TCB]: Put `multiple_threads' inside a wrapper
+       struct also called `header', so `header.multiple_threads' is the field
+       name to use on all machines.
+       * allocatestack.c (allocate_stack): Use `header.' prefix.
+       * sysdeps/pthread/createthread.c (create_thread): Likewise.
+       * pthread_create.c (__pthread_create_2_1): Likewise.
+       * sysdeps/i386/tls.h (INSTALL_NEW_DTV, THREAD_DTV): Likewise.
+       (THREAD_SELF): Likewise.
+       * sysdeps/x86_64/tls.h: Likewise.
+       * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h
+       (SINGLE_THREAD_P): Likewise.
+       * sysdeps/unix/sysv/linux/sh/sysdep-cancel.h
+       (SINGLE_THREAD_P): Likewise.
+       * sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h
+       (SINGLE_THREAD_P): Likewise.
+
+       * sysdeps/s390/td_ta_map_lwp2thr.c (td_ta_map_lwp2thr): Use REGS[18]
+       value directly.
+
+2003-03-14  Ulrich Drepper  <drepper@redhat.com>
+
+       * pthread_create.c (start_thread): Use CALL_THREAD_FCT if defined.
+       * sysdeps/i386/tls.h: Define CALL_THREAD_FCT.
+
+       * pthread_create.c (start_thread): setjmp is expected to return 0.
+
+       * sysdeps/x86_64/tls.h (THREAD_GETMEM): Mark asms volatile.
+       (THREAD_GETMEM_NC): Likewise.
+
+2003-03-13  Ulrich Drepper  <drepper@redhat.com>
+
+       * allocatestack.c (allocate_stack): If MULTI_PAGE_ALIASING is defined
+       and the size of the stack which must be allocated is a multiple,
+       allocate one more page.
+       * sysdeps/i386/i686/Makefile: Don't define COLORING_INCREMENT, but
+       MULTI_PAGE_ALIASING.
+
+2003-03-13  Roland McGrath  <roland@redhat.com>
+
+       * pthread_create.c (start_thread): Set EXITING_BIT after the
+       event-reporting (and destructors), not before.
+
+2003-03-13  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/ia64/lowlevellock.h (lll_futex_timed_wait,
+       lll_futex_wake): Declare register variables as long int instead of
+       unsigned long int.  Patch by Ian Wienand <ianw@gelato.unsw.edu.au>.
+       Make syscall arguments clobbered by the syscall.
+       (lll_futex_wait): Define using lll_futex_timed_wait.
+
+       * sysdeps/ia64/td_ta_map_lwp2thr.c (td_ta_map_lwp2thr): Cast regs[13]
+       to void *.
+
+       * sysdeps/unix/sysv/linux/fork.c (__libc_fork): Only declare and set
+       PPID if [! NDEBUG].
+
+       * allocatestack.c (nptl_ncreated): Only declare if
+       COLORING_INCREMENT != 0.
+
+       * pthreadP.h (__pthread_enable_asynccancel_2): New prototype.
+       (__libc_enable_asynccancel_2): Remove prototype.
+
+       * sysdeps/unix/sysv/linux/ia64/fork.c (ARCH_FORK): Swap ptid and
+       ctid to match kernel.
+
+2003-03-12  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/Makefile (sysdep_routines): Add
+       libc_multiple_threads.
+       * sysdeps/unix/sysv/linux/libc_pthread_init.c: Move definition of
+       __libc_multiple_threads to...
+       * sysdeps/unix/sysv/linux/libc_multiple_threads.c: ...here.  New file.
+
+       * sysdeps/unix/sysv/linux/x86_64/sem_post.S: Remove unnecessary
+       versioning.
+       * sysdeps/unix/sysv/linux/x86_64/sem_trywait.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/sem_wait.S: Likewise.
+
+       * sysdeps/unix/sysv/linux/x86_64/pthread_once.S
+       (__pthread_once_internal): Define.
+
+       * sysdeps/unix/sysv/linux/i386/i486/sem_post.S: Use shlib-compat.h
+       macros instead of .symver directly.
+       * sysdeps/unix/sysv/linux/i386/i486/sem_trywait.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/sem_wait.S: Likewise.
+
+       * sysdeps/x86_64/tls.h [__ASSEMBLER__]: Include tcb-offsets.h.
+       * sysdeps/x86_64/tcb-offsets.sym: New file.
+       * sysdeps/x86_64/Makefile: New file.
+
+       * sysdeps/i386/tcb-offsets.sym: Add SELF.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_rdlock.S: Use SELF
+       to access own pthread_t in TCB.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedrdlock.S:
+       Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedwrlock.S:
+       Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_wrlock.S: Likewise.
+
+2003-03-12  Roland McGrath  <roland@redhat.com>
+
+       * pthread-errnos.sym: New file.
+       * Makefile (gen-as-const-headers): New variable, list that file.
+       * sysdeps/unix/sysv/linux/i386/i486/sem_wait.S: Include generated
+       header <pthread-errnos.h> instead of defining errno values here.
+       * sysdeps/unix/sysv/linux/i386/i486/sem_trywait.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/sem_timedwait.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/sem_post.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_wrlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedwrlock.S:
+       Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedrdlock.S:
+       Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_rdlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/lowlevelmutex.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/sem_wait.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/sem_trywait.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/sem_post.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/lowlevelmutex.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/lowlevellock.S: Likewise.
+       * sysdeps/unix/sysv/linux/sh/sem_trywait.S: Likewise.
+       * sysdeps/unix/sysv/linux/sh/sem_timedwait.S: Likewise.
+       * sysdeps/unix/sysv/linux/sh/sem_post.S: Likewise.
+       * sysdeps/unix/sysv/linux/sh/sem_wait.S: Likewise.
+       * sysdeps/unix/sysv/linux/sh/pthread_rwlock_wrlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedwrlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedrdlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/sh/pthread_cond_timedwait.S: Likewise.
+       * sysdeps/unix/sysv/linux/sh/pthread_rwlock_rdlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/sh/lowlevellock.S: Likewise.
+       * sysdeps/unix/sysv/linux/sh/lowlevelmutex.S: Likewise.
+       * sysdeps/i386/i486/pthread_spin_trylock.S: Likewise.
+       * sysdeps/x86_64/pthread_spin_trylock.S: Likewise.
+       * sysdeps/sh/pthread_spin_trylock.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_rdlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_wrlock.S: Likewise.
+
+       * sysdeps/unix/sysv/linux/fork.c: Add an assert to check that
+       CLONE_CHILD_SETTID worked.
+
+2003-03-12  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedrdlock.S: New
+       file.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedwrlock.S: New
+       file.
+
+       * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h
+       (pthread_cond_t): Add padding.
+
+       * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_rdlock.S: New file.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_wrlock.S: New file.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_unlock.S: New file.
+
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedwrlock.S
+       (__pthread_rwlock_timedwrlock): Add missing opcode suffix.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedrdlock.S
+       (__pthread_rwlock_timedrdlock): Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_wrlock.S
+       (__pthread_rwlock_wrlock): Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_rdlock.S
+       (__pthread_rwlock_rdlock): Likewise.
+
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: New file.
+
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Return
+       result of lock re-get if it fails.
+
+2003-03-11  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/x86_64/lowlevellock.S: Fix asm syntax.
+       * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/lowlevelmutex.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_signal.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_once.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/sem_post.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/sem_trywait.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/sem_wait.S: Likewise.
+
+       * sysdeps/x86_64/tls.h (THREAD_SELF, THREAD_GETMEM, THREAD_GETMEM_NC,
+       THREAD_SETMEM, THREAD_SETMEM_NC): Correct asm syntax.
+
+       * allocatestack.c [! TLS_MULTIPLE_THREADS_IN_TCB] (allocate_stack):
+       Initialize *__libc_multiple_threads_ptr not __libc_multiple_threads.
+       * sysdeps/pthread/createthread.c [! TLS_MULTIPLE_THREADS_IN_TCB]
+       (create_thread): Likewise.
+       Define __pthread_multiple_threads and __libc_multiple_threads_ptr.
+       * init.c (__pthread_initialize_minimal_internal): Initialize
+       __libc_multiple_threads_ptr if necessary.
+       * pthreadP.h: Adjust prototype for __libc_pthread_init.  Declare
+       __pthread_multiple_threads and __libc_multiple_threads_ptr.
+       * sysdeps/unix/sysv/linux/libc_pthread_init.c: Define
+       __libc_multiple_threads.
+       (__libc_pthread_init): Return pointer to __libc_pthread_init if
+       necessary.
+
+       * sysdeps/i386/tls.h (THREAD_SETMEM): Fix one-byte variant.
+       (THREAD_SETMEM_NC): Likewise.
+
+       * sysdeps/x86_64/pthread_spin_trylock.c: Removed.
+       * sysdeps/x86_64/pthread_spin_trylock.S: New file.
+       * sysdeps/x86_64/pthread_spin_unlock.c: Removed.
+       * sysdeps/x86_64/pthread_spin_unlock.S: New file.
+
+       * sysdeps/i386/i486/pthread_spin_trylock.S (pthread_spin_trylock):
+       Eliminate one entire instruction.
+
+       * cancellation.c (__pthread_enable_asynccancel_2): New function.
+       * pthreadP.h: Declare __pthread_enable_asynccancel_2.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S
+       (__pthread_cond_timedwait): Use __pthread_enable_asynccancel_2
+       instead of __pthread_enable_asynccancel.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S
+       (__pthread_cond_wait): Likewise.
+       * sysdeps/pthread/pthread_cond_timedwait.c
+       (__pthread_cond_timedwait): Likewise.
+       * sysdeps/pthread/pthread_cond_wait.c (__pthread_cond_wait): Likewise.
+
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S
+       (__condvar_cleanup): Wake up all waiters in case we got signaled
+       after being woken up but before disabling asynchronous
+       cancellation.
+       * sysdeps/pthread/pthread_cond_wait.c (__condvar_cleanup): Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S
+       (__condvar_cleanup): Likewise.
+
+       * init.c (__NR_set_tid_address): If already defined, don't redefine.
+       Make it an error if architecture has no #if case.  Add x86-64.
+
+       * sysdeps/unix/sysv/linux/x86_64/Makefile: Add flags for
+       pt-initfini.s generation.
+
+       * sysdeps/x86_64/tls.h: Include <asm/prctl.h>.
+       (TLS_INIT_TP): Fix typo.
+
+2003-03-11  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/ia64/bits/atomic.h (atomic_exchange_and_add): Swap 2nd and
+       3rd argument of __arch_compare_and_exchange_{32,64}_val_acq.
+
+       * sysdeps/unix/sysv/linux/ia64/sem_post.c: Include semaphore.h.
+       * sysdeps/unix/sysv/linux/ia64/sem_timedwait.c: Likewise.
+       * sysdeps/unix/sysv/linux/ia64/sem_trywait.c: Likewise.
+       * sysdeps/unix/sysv/linux/ia64/sem_wait.c: Likewise.
+       * sysdeps/unix/sysv/linux/s390/sem_post.c: Likewise.
+       * sysdeps/unix/sysv/linux/s390/sem_timedwait.c: Likewise.
+       * sysdeps/unix/sysv/linux/s390/sem_trywait.c: Likewise.
+       * sysdeps/unix/sysv/linux/s390/sem_wait.c: Likewise.
+
+2003-03-11  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/pthread_cond_timedwait.c
+       (__pthread_cond_timedwait): Return the result of the final
+       locking.  If it succeeds, the regular function return value.
+
+       * sysdeps/pthread/pthread_cond_wait.c (__pthread_cond_wait):
+       Return result of the final locking.
+       * version.c (__nptl_main): Work around problems with the strange
+       INTERNAL_SYSCALL macro on ppc32.
+       * init.c (__pthread_initialize_minimal_internal): Unblock
+       SIGCANCEL in case the parent blocked it.
+       Reported by Paul Mackerras <paulus@samba.org>.
+
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S: New file.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_signal.S: New file.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S: New file.
+
+2003-03-11  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/pthread/pthread_cond_timedwait.c
+       (__pthread_cond_timedwait): Unlock and fail if
+       __pthread_mutex_unlock_internal failed.
+
+       * sysdeps/pthread/createthread.c (ARCH_CLONE): Define if not defined.
+       (create_thread): Only assert PD->tcb != NULL under [TLS_TCB_AT_TP].
+       Use ARCH_CLONE.
+       * allocatestack.c (ALLOCATE_STACK_PARMS): New macro.
+       [NEED_SEPARATE_REGISTER_STACK] (STACK_VARIABLES,
+       STACK_VARIABLES_ARGS, STACK_VARIABLES_PARMS, ALLOCATE_STACK_PARMS,
+       ALLOCATE_STACK): New macros.
+       (TLS_TPADJ): New macro.
+       (get_cached_stack, queue_stack, __deallocate_stack): Use TLS_TPADJ.
+       (allocate_stack): Handle TLS_DTV_AT_TP and
+       NEED_SEPARATE_REGISTER_STACK.  Use TLS_TPADJ.
+       * pthread_create.c (__pthread_create_2_1) [! TLS_TCB_AT_TP]:
+       Don't set PD->self.
+       * init.c [__ia64__] (__NR_set_tid_address): Define.
+
+       * sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h: New file.
+       * sysdeps/unix/sysv/linux/ia64/bits/semaphore.h: New file.
+       * sysdeps/unix/sysv/linux/ia64/fork.c: New file.
+       * sysdeps/unix/sysv/linux/ia64/createthread.c: New file.
+       * sysdeps/unix/sysv/linux/ia64/libc-lowlevellock.c: New file.
+       * sysdeps/unix/sysv/linux/ia64/libc-lowlevelmutex.c: New file.
+       * sysdeps/unix/sysv/linux/ia64/lowlevellock.c: New file.
+       * sysdeps/unix/sysv/linux/ia64/lowlevellock.h: New file.
+       * sysdeps/unix/sysv/linux/ia64/lowlevelmutex.c: New file.
+       * sysdeps/unix/sysv/linux/ia64/pt-initfini.c: New file.
+       * sysdeps/unix/sysv/linux/ia64/pt-vfork.S: New file.
+       * sysdeps/unix/sysv/linux/ia64/pthread_once.c: New file.
+       * sysdeps/unix/sysv/linux/ia64/sem_post.c: New file.
+       * sysdeps/unix/sysv/linux/ia64/sem_timedwait.c: New file.
+       * sysdeps/unix/sysv/linux/ia64/sem_trywait.c: New file.
+       * sysdeps/unix/sysv/linux/ia64/sem_wait.c: New file.
+       * sysdeps/unix/sysv/linux/ia64/sysdep-cancel.h: New file.
+       * sysdeps/ia64/bits/atomic.h: New file.
+       * sysdeps/ia64/Makefile: New file.
+       * sysdeps/ia64/pthread_spin_init.c: New file.
+       * sysdeps/ia64/pthread_spin_lock.c: New file.
+       * sysdeps/ia64/pthread_spin_trylock.c: New file.
+       * sysdeps/ia64/pthread_spin_unlock.c: New file.
+       * sysdeps/ia64/pthreaddef.h: New file.
+       * sysdeps/ia64/tcb-offsets.sym: New file.
+       * sysdeps/ia64/td_ta_map_lwp2thr.c: New file.
+       * sysdeps/ia64/tls.h: New file.
+
+       * sysdeps/s390/pthreaddef.h (__exit_thread_inline): Pass 1 argument
+       to syscall instead of no arguments.
+
+2003-03-10  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/x86_64/sem_post.S: New file.
+       * sysdeps/unix/sysv/linux/x86_64/sem_trywait.S: New file.
+       * sysdeps/unix/sysv/linux/x86_64/sem_wait.S: New file.
+       * sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S: New file.
+
+       * sysdeps/unix/sysv/linux/i386/i486/sem_post.S: Fix error value in
+       unused code.
+
+       * sysdeps/unix/sysv/linux/x86_64/pthread_barrier_wait.S: New file
+
+       * sysdeps/unix/sysv/linux/Makefile (gen-as-const-headers): Add
+       lowlevelbarrier.sym.
+       * sysdeps/unix/sysv/linux/lowlevelbarrier.sym: New file.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_barrier_wait.S:
+       Include lowlevelbarrier.h and don't define offsets locally.
+       * sysdeps/unix/sysv/linux/sh/pthread_barrier_wait.S: Likewise.
+
+       * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h
+       (__lll_mutex_lock_wait): Reverse order of first two parameters.
+       (__lll_mutex_timedlock_wait): Likewise.
+       (lll_mutex_lock): Adjust asm for that.
+       (lll_mutex_timedlock): Likewise.  Mark cx, cc, r10 as clobbered.
+       (lll_lock): Adjust asm for operand order change.
+       * sysdeps/unix/sysv/linux/x86_64/lowlevelmutex.S: New file.
+       * sysdeps/unix/sysv/linux/x86_64/libc-lowlevelmutex.S: New file.
+
+       * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h (__lll_lock_wait):
+       Reverse order of parameters.
+       (__lll_timedwait_tid): Remove regparms attribute.
+       * sysdeps/unix/sysv/linux/x86_64/lowlevellock.S: New file.
+       * sysdeps/unix/sysv/linux/x86_64/libc-lowlevellock.S: New file.
+
+       * sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S
+       (__lll_timedwait_tid): Remove one unnecessary instruction.
+
+       * sysdeps/unix/sysv/linux/sh/lowlevelmutex.S: Define
+       __lll_mutex_timedlock_wait only for NOT_IN_libc.
+       * sysdeps/unix/sysv/linux/sh/libc-lowlevelmutex.S: Include
+       lowlevelmutex.S.
+
+       * sysdeps/unix/sysv/linux/sh/lowlevellock.S: Define
+       lll_unlock_wake_cb, __lll_wait_tid, and __lll_timedwait_tid only
+       for NOT_IN_libc.
+       * sysdeps/unix/sysv/linux/sh/libc-lowlevellock.S: Include
+       lowlevellock.S.
+
+       * sysdeps/unix/sysv/linux/i386/i486/lowlevelmutex.S: Don't define
+       LOCK is already defined.  Don't define __lll_mutex_timedlock_wait
+       for libc.so.
+       * sysdeps/unix/sysv/linux/i386/i486/libc-lowlevelmutex.S: Only
+       define LOCK here (if UP is not defined).  The actual code is in
+       lowlevelmutex.S.
+
+       * sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S: Don't define
+       LOCK is already defined.  Don't define lll_unlock_wake_cb and
+       __lll_timedwait_tid for libc.so.
+       * sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S: Only
+       define LOCK here (if UP is not defined).  The actual code is in
+       lowlevellock.S.
+
+       * sysdeps/unix/sysv/linux/i386/lowlevelsem.h: Not needed anymore.
+       * sysdeps/unix/sysv/linux/s390/lowlevelsem.h: Likewise.
+       * sysdeps/unix/sysv/linux/s390/sem_post.c: Include lowlevellock.h
+       instead of lowlevelsem.h.
+       * sysdeps/unix/sysv/linux/s390/sem_timedwait.c: Likewise.
+       * sysdeps/unix/sysv/linux/s390/sem_trywait.c: Likewise.
+       * sysdeps/unix/sysv/linux/s390/sem_wait.c: Likewise.
+
+       * sysdeps/unix/sysv/linux/Makefile (gen-as-const-headers): Add
+       lowlevelrwlock.sym.
+       * sysdeps/unix/sysv/linux/lowlevelrwlock.sym: New file.
+       * sysdeps/unix/sysv/linux/i386/lowlevelrwlock.h: Removed.
+       * sysdeps/unix/sysv/linux/sh/lowlevelrwlock.h: Removed.
+
+       * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h (lll_trylock): Fix
+       register loading.
+       * sysdeps/unix/sysv/linux/i386/lowlevellock.h (lll_trylock): Undo
+       last changed.  D'oh.
+
+       * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h: New file.
+
+       * sysdeps/unix/sysv/linux/i386/lowlevellock.h: Remove declaration
+       of __libc_locking_needed.
+       (lll_trylock): Initialize %eax to zero.
+
+       * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: Update
+       pthread_cond_t definition.
+
+2003-03-10  Roland McGrath  <roland@redhat.com>
+
+       * sysdeps/unix/sysv/linux/lowlevelcond.sym: New file.
+       * sysdeps/unix/sysv/linux/Makefile (gen-as-const-headers): Add it.
+       * sysdeps/unix/sysv/linux/sh/lowlevelcond.h: File removed.
+       * sysdeps/unix/sysv/linux/i386/lowlevelcond.h: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/lowlevelcond.h: Likewise.
+
+       * allocatestack.c (allocate_stack) [!TLS_MULTIPLE_THREADS_IN_TCB]:
+       Instead of setting PD->multiple_threads, set globals
+       __pthread_multiple_threads and __libc_multiple_threads.
+       * sysdeps/pthread/createthread.c (create_thread): Likewise.
+       * sysdeps/i386/tls.h (TLS_MULTIPLE_THREADS_IN_TCB): Define it.
+       * sysdeps/s390/tls.h (TLS_MULTIPLE_THREADS_IN_TCB): Likewise.
+
+       * descr.h (struct pthread): Conditionalize first member on
+       [!TLS_DTV_AT_TP].  Replace the `header' member with an anonymous union
+       containing an anonymous tcbhead_t.  Move `list' member out.
+       [TLS_MULTIPLE_THREADS_IN_TCB]: Define a `multiple_threads' member.
+       * allocatestack.c: Remove use of `header.data.' prefix.
+       * pthread_create.c: Likewise.
+       * init.c (__pthread_initialize_minimal_internal): Likewise.
+       * sysdeps/pthread/createthread.c (create_thread): Likewise.
+       * sysdeps/i386/tls.h (INSTALL_DTV): Add parens.
+       (THREAD_SELF, THREAD_DTV, INSTALL_NEW_DTV): No `header.data.' prefix.
+       * sysdeps/x86_64/tls.h: Likewise.
+       * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h
+       (SINGLE_THREAD_P): Likewise.
+       * sysdeps/unix/sysv/linux/sh/sysdep-cancel.h
+       (SINGLE_THREAD_P): Likewise.
+       * sysdeps/i386/tls.h (tcbhead_t): Remove `list' member.
+       * sysdeps/s390/tls.h (tcbhead_t): Likewise.
+
+2003-03-09  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/x86_64/lowlevelcond.h: New file.
+
+       * sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h: New file.
+       * sysdeps/unix/sysv/linux/x86_64/fork.c: New file.
+
+       * sysdeps/unix/sysv/linux/x86_64/pthread_once.S: Fix many
+       leftovers from the ia32 code.
+
+       * sysdeps/unix/sysv/linux/i386/pthread_once.S: Remove unneccessary
+       memory load.
+       (clear_once_control): Don't load %esi.
+
+       * sysdeps/x86_64/tls.h: Remove all traces of segment descriptor
+       handling.
+
+       * sysdeps/unix/sysv/linux/x86_64/fork.c: New file.
+
+       * sysdeps/unix/sysv/linux/s390/createthread.c: Moved to...
+       * sysdeps/unix/sysv/linux/createthread.c: ...here.
+
+       * Makefile (tests): Add tst-cond10.
+       * tst-cond10.c: New file.
+
+2003-03-08  Ulrich Drepper  <drepper@redhat.com>
+
+       * tst-tls2.c (do_test): Add TEMP_FAILURE_RETRY around sem_wait call.
+       * tst-signal3.c (do_test): Likewise.
+       * tst-sem5.c (do_test): Likewise.
+       * tst-kill6.c (do_test): Likewise.
+       * tst-tls3.c (do_test): Likewise.  Include <errno.h>.
+
+       * sysdeps/unix/sysv/linux/i386/lowlevellock.h: Use add/sub instead
+       of inc/dec.
+       * sysdeps/unix/sysv/linux/i386/lowlevelsem.h: Likewise.
+       * sysdeps/unix/sysv/linux/i386/pthread_once.S: Likewise
+       * sysdeps/unix/sysv/linux/i386/i486/sem_timedwait.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/sem_post.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_wrlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_unlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedwrlock.S:
+       Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedrdlock.S:
+       Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_rdlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_signal.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_barrier_wait.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/lowlevelmutex.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S: Likewise.
+
+       * allocatestack.c (allocate_stack): If mprotect() fails free the
+       TLS memory.
+
+2003-03-07  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/i386/i486/bits/atomic.h: Fix a few unused definitions.
+
+       * sysdeps/unix/sysv/linux/i386/lowlevellock.h: Remove all trace of
+       lll_wake_tid.  This was used only to work around kernel limits in
+       the early days.
+       * sysdeps/unix/sysv/linux/s390/lowlevellock.h: Likewise.
+       * sysdeps/unix/sysv/linux/sh/libc-lowlevellock.S: Likewise.
+       * sysdeps/unix/sysv/linux/sh/lowlevellock.S: Likewise.
+       * sysdeps/unix/sysv/linux/sh/lowlevellock.h: Likewise.
+
+       * init.c (__static_tls_align_m1): Renamed from __static_tls_align.
+       (__pthread_initialize_minimal_internal): Change initialization of
+       __static_tls_align_m1 appropriately.
+       * pthreadP.h (__static_tls_align_m1): Renamed from
+       __static_tls_align.
+       * allocatestack.c (allocate_stack): Use __static_tls_align_m1
+       instead of __static_tls_align-1.
+
+2003-03-04  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/x86_64/Makefile: New file.
+
+       * pthread_create.c: Define __pthread_keys using nocommon
+       attribute, not by placing it explicitly in bss.
+       Remove DEFINE_DEALLOC definition.  Not needed anymore.
+
+       * allocatestack.c: Define ARCH_MAP_FLAGS if not already defined.
+       Use it in mmap call to allocate stacks.
+
+       * sysdeps/pthread/createthread.c (create_thread): Fix comment.
+
+       * pthread_create.c (start_thread): Use THREAD_SETMEM to store
+       result of the thread function.
+
+2003-03-03  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/s390/dl-sysdep.h: Removed.  The generic
+       version is just fine.
+
+       * sysdeps/unix/sysv/linux/libc_pthread_init.c
+       (__pthread_child_handler): Renamed from pthread_child_handler,
+       exported, and marked hidden.  Change all users.
+       * sysdeps/unix/sysv/linux/register-atfork.c (free_mem): Do not
+       free __pthread_child_handler from child list.
+
+2003-03-03  Martin Schwidefsky  <schwidefsky@de.ibm.com>
+
+       * atomic.h (atomic_exchange_and_add): Return newval, not oldval.
+
+       * sysdeps/pthread/pthread_cond_timedwait.c (__pthread_cond_timedwait):
+       Fix handling of cancellation and failing pthread_mutex_unlock call.
+       * sysdeps/pthread/pthread_cond_wait.c (__condvar_cleanup): Likewise.
+       (__pthread_cond_wait): Likewise.
+
+       * sysdeps/pthread/pthread_rwlock_timedrdlock.c
+       (pthread_rwlock_timedrdlock): Fix clobber of result variable by
+       lll_futex_timed_wait call.
+       * sysdeps/pthread/pthread_rwlock_timedwrlock.c
+       (pthread_rwlock_timedwrlock): Likewise.
+
+       * sysdeps/unix/sysv/linux/s390/libc-lowlevellock.c (___lll_lock):
+       Don't define lll_unlock_wake_cb and ___lll_timedwait_tid in libc.so.
+       * sysdeps/unix/sysv/linux/s390/lowlevellock.c: Remove XXX comments.
+
+       * sysdeps/unix/sysv/linux/s390/sem_post.c (__new_sem_post): Fix
+       check of lll_futex_wake return value.
+
+2003-03-03  Roland McGrath  <roland@redhat.com>
+
+       * forward.c: Fix typo in __pthread_attr_init_2_0 compat_symbol decl.
+
+       * sysdeps/pthread/pthread-functions.h (struct pthread_functions):
+       Argument to ptr___pthread_cleanup_upto is __jmp_buf, not jmp_buf.
+       * sysdeps/unix/sysv/linux/jmp-unwind.c: Likewise.
+
+2003-03-02  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/timer_create.c (timer_create): Return correct
+       error for CPU clocks.
+
+       * sysdeps/unix/sysv/linux/bits/posix_opt.h: Define
+       _POSIX_MONOTONIC_CLOCK.
+       * sysdeps/unix/sysv/linux/i386/bits/posix_opt.h: Likewise.
+
+       * tst-cancel4.c (tf_sleep): Lower sleep time a bit to not upset
+       recent kernels.
+
+2003-03-01  Ulrich Drepper  <drepper@redhat.com>
+
+       * descr.h (struct pthread): Move cleanup field to the front.
+
+2003-03-01  Roland McGrath  <roland@redhat.com>
+
+       * sem_open.c (sem_open): Braino fix.
+
+2003-03-01  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/i386/tcb-offsets.sym: Add CLEANUP and CLEANUP_PREV.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Inline
+       __pthread_cleanup_pop functionality.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Likewise.
+
+       * descr.h (struct pthread): Move tid field to the front now that
+       it is often used.
+
+       * sysdeps/unix/sysv/linux/i386/i486/libc-lowlevelmutex.S
+       (__lll_mutex_timedlock_wait): Remove.
+       (__lll_mutex_unlock_wake): Don't save, load, and restore %esi.
+       * sysdeps/unix/sysv/linux/i386/i486/lowlevelmutex.S
+       (__lll_mutex_unlock_wake): Don't save, load, and restore %esi.
+       * sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S
+       (lll_unlock_wake_cb): Don't save and restore %esi.
+       (__lll_unlock_wake): Add alignment.  Don't save, load, and restore
+       %esi.
+       (__lll_timedwait_tid): Add alignment.
+       * sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S
+       (__lll_unlock_wake): Add alignment.  Don't save, load, and restore
+       %esi.
+       (__lll_timedwait_tid): Removed.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S
+       (__pthread_cond_broadcast): Don't save, load, and restore %esi.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_barrier_wait.S
+       (pthread_barrier_wait): Don't save, load, and restore %esi for
+       last thread.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_signal.S
+       (__pthread_cond_signal): Don't save, load, and restore %esi.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_unlock.S
+       (__pthread_rwlock_unlock): Don't save, load, and restore %esi.
+       * sysdeps/unix/sysv/linux/i386/i486/sem_post.S (__new_sem_post):
+       Don't save, load, and restore %esi.
+
+2003-02-27  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S:
+       Release lock before waking up the waiters.
+
+       * tst-exit1.c (do_test): Don't start more than one thread in parallel.
+
+       * tst-rwlock9.c (writer_thread): Correct adding TIMEOUT.
+       (reader_thread): Likewise.
+
+       * sysdeps/pthread/pthread_rwlock_unlock.c
+       (__pthread_rwlock_unlock): Release internal lock early.  Don't try
+       to wake up readers if there are none.
+
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_unlock.S:
+       Release internal lock before wake threads.
+
+2003-02-26  Ulrich Drepper  <drepper@redhat.com>
+
+       * Makefile (tests): Add tst-rwlock10 and tst-rwlock11.
+       * tst-rwlock8.c: Initialize lock with INIT.  Allow INIT to be
+       predefined.
+       * tst-rwlock9.c: Likewise.
+       * tst-rwlock10.c: New file.
+       * tst-rwlock11.c: New file.
+
+       * Makefile (tests): Add tst-dlsym1.
+       * tst-dlsym1.c: New file.
+
+       * init.c (__pthread_initialize_minimal_internal): Set
+       GL(dl_error_catch_tsd) to __libc_dl_error_tsd.
+       * Versions (libc:GLIBC_PRIVATE): Export __libc_dl_error_tsd.
+
+2003-02-24  Ulrich Drepper  <drepper@redhat.com>
+
+       * sem_open.c (sem_open): Fix handling of O_CREAT without O_EXCL.
+
+       * tst-cond2.c: Fix sychronization with child.
+
+       * tst-rwlock8.c (reader_thread): Remove unused variable.
+
+       * Makefile: Add rules to build and run tst-tls3.
+       * tst-tls3.c: New file.
+       * tst-tls3mod.c: New file.
+
+       * Makefile (tests): Add tst-rwlock8 and tst-rwlock9.
+       * tst-rwlock8.c: New file.
+       * tst-rwlock9.c: New file.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_rdlock.S: Fix
+       complete broken rwlock implementation.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedrdlock.S:
+       Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedwrlock.S:
+       Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_unlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_wrlock.S: Likewise.
+       * sysdeps/pthread/pthread_rwlock_rdlock.c: Likewise.
+       * sysdeps/pthread/pthread_rwlock_timedrdlock.c: Likewise.
+       * sysdeps/pthread/pthread_rwlock_timedwrlock.c: Likewise.
+       * sysdeps/pthread/pthread_rwlock_unlock.c: Likewise.
+       * sysdeps/pthread/pthread_rwlock_wrlock.c: Likewise.
+
+2003-02-23  Roland McGrath  <roland@redhat.com>
+
+       * Makefile (nptl-version): Change regexp so case sensitivity is ok.
+
+2003-02-23  Ulrich Drepper  <drepper@redhat.com>
+
+       * Makefile (tests): Add tst-context1.
+       * tst-context1.c: New file.
+
+       * Makefile (tests): Add tst-tls1 and tst-tls2.
+       * tst-tls1.c: New file.
+       * tst-tls2.c: New file.
+
+       * libc-cancellation.c (__libc_enable_asynccancel): Correct test
+       for failed cmpxchg.
+
+       * pthread_create.c (start_thread): Set EXITING_BIT early.
+
+       * sysdeps/i386/tls.h (THREAD_GETMEM): Mark asm as volatile.
+       (THREAD_GETMEM_NC): Likewise.
+
+2003-02-22  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_barrier_wait.S: Shave
+       off 3 more bytes by using offset-less instructions when possible.
+
+       * Makefile: Add dependency for $(objpfx)version.d.
+
+       * eintr.c (eintr_source): Add unnecessary return but the compiler
+       insists.
+
+       * tst-kill3.c: Include <unistd.h>.
+
+2003-02-21  Roland McGrath  <roland@redhat.com>
+
+       * pthread_create.c (start_thread): Call __libc_thread_freeres.
+
+2003-02-21  Ulrich Drepper  <drepper@redhat.com>
+
+       * Makefile (tests): Add tst-eintr1.
+       (distribute): Add eintr.c.
+       * tst-eintr1.c: New file.
+       * eintr.c: New file.
+
+       * pthread_cancel.c (pthread_cancel): Use tkill directly.
+
+       * sysdeps/unix/sysv/linux/pthread_kill.c (__pthread_kill):
+       Disallow sending SIGCANCEL.
+
+       * Makefile (tests): Remove tst-basic7.  Add tst-kill1, tst-kill2,
+       tst-kill3, tst-kill4, tst-kill5, tst-kill6.
+       * tst-kill1.c: New file.
+       * tst-kill2.c: New file.
+       * tst-kill3.c: New file.
+       * tst-kill5.c: New file.
+       * tst-kill6.c: New file.
+       * tst-basic7.c: Renamed to...
+       * tst-kill4.c: ...this.
+
+2003-02-21  Roland McGrath  <roland@redhat.com>
+
+       * Makefile (install-lib-ldscripts): New variable.
+
+2003-02-21  Ulrich Drepper  <drepper@redhat.com>
+
+       * pthreadP.h: Define INVALID_TD_P and INVALID_NOT_TERMINATED_TD_P.
+       * pthread_cancel.c: Use INVALID_TD_P.
+       * pthread_detach.c: Likewise.
+       * pthread_getschedparam.c: Likewise.
+       * pthread_setschedparam.c: Likewise.
+       * sysdeps/pthread/pthread_getcpuclockid.c: Likewise.
+       * sysdeps/unix/sysv/linux/pthread_kill.c: Likewise.
+       * pthread_join.c: Use INVALID_NOT_TERMINATED_TD_P.
+       * pthread_timedjoin.c: Likewise.
+
+       * tst-basic7.c: Include <signal.h>.
+
+       * pthread_join.c (pthread_join): Limited checking for invalid
+       descriptors.
+       * pthread_timedjoin.c (pthread_timedjoin_np): Likewise.
+
+2003-02-20  Ulrich Drepper  <drepper@redhat.com>
+
+       * pthread_create.c (deallocate_tsd): Reset found_nonzero at the
+       beginning of the loop.  Clear the entire first block of TSD.
+       * Makefile (tests): Add tst-key4.
+       * tst-key4.c: New file.
+
+2003-02-18  Ulrich Drepper  <drepper@redhat.com>
+
+       * Makefile (tests): Add tst-basic7.
+       * tst-basic7.c: New file.
+
+       * pthread_create.c (deallocate_tsd): Mark as internal_function.
+       Add some more __builtin_expect.
+
+       * pthreadP.h: Define dummy version of DEBUGGING_P.
+
+2003-02-17  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/bits/posix_opt.h: Remnove
+       _POSIX_THREAD_PRIORITY_SCHEDULING.
+       * sysdeps/unix/sysv/linux/i386/bits/posix_opt.h: Remove
+       _XOPEN_REALTIME_THREADS.
+       * sysdeps/unix/sysv/linux/bits/posix_opt.h: Likewise.
+
+       * sysdeps/unix/sysv/linux/pthread_kill.c (__pthread_kill): The
+       kernel returns EINVAL for PID <= 0, work around it.
+
+       * Makefile (tests): Add tst-signal5.
+       * tst-signal5.c: New file.
+
+       * sysdeps/unix/sysv/linux/bits/local_lim.h: Define TTY_NAME_MAX
+       and LOGIN_NAME_MAX.
+
+       * tst-cancel1.c (tf): Block all signals.
+
+       * Makefile (tests): Add tst-basic6.
+       * tst-basic6.c: New file.
+
+       * tst-basic1.c: Add test for process ID.
+
+       * Makefile (tests): Add tst-cancel10.
+       * tst-cancel10.c: New file.
+
+       * Makefile (tests): Add tst-signal4.
+       * tst-signal4.c: New file.
+
+       * sysdeps/pthread/pthread_sigmask.c (pthread_sigmask): Use
+       __sigismember instead of sigismember.  Add __builtin_expect.
+
+2003-02-16  Ulrich Drepper  <drepper@redhat.com>
+
+       * tst-attr1.c (do_test): Add tests for pthread_setcanceltype,
+       pthread_setcancelstate, and pthread_rwlock_setpshared.
+
+       * tst-cancel7.c (do_test): Make sure the pid file exists before
+       canceling the thread.
+
+       * tst-rwlock6.c: More pthread_rwlock_timedwrlock and
+       pthread_rwlock_timedrdlock tests.
+       * tst-rwlock7.c: More pthread_rwlock_timedwrlock tests.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedrdlock.S:
+       Check for invalid tv_nsec field.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedwrlock.S:
+       Likewise.
+
+       * pthread_mutex_trylock.c (__pthread_mutex_trylock): Protect
+       recursive mutex of overflow.
+
+       * tst-attr1.c (do_test): Add test for pthread_mutexattr_setpshared.
+
+       * libc-cancellation.c (__libc_enable_asynccancel): Rewrite to avoid
+       going into an endless loop.
+       * Makefile (tests): Add tst-cancel9.
+       * tst-cancel9.c: New file.
+
+       * pthread_cancel.c (pthread_cancel): Use the result of __pthread_kill.
+
+2003-02-15  Ulrich Drepper  <drepper@redhat.com>
+
+       * tst-mutex5.c (do_test): Add more timedlock tests.
+
+       * tst-mutex2.c: Tests of trylock and unlock with ERROR mutexes.
+       * tst-mutex3.c (do_test): Add tests for trylock with RECURSIVE mutexes.
+
+       * sysdeps/unix/sysv/linux/pthread_kill.c (__pthread_kill): Don't
+       use INLINE_SYSCALL.  Error number is returned, not -1.
+
+       * pthreadP.h: Mark declarations of __find_in_stack_list, __free_tcb,
+       and __deallocate_stack with internal_function.
+       * pthread_create.c: Adjust definitions appropriately.
+       * allocatestack.c: Likewise.
+
+       * pthread_join.c: Add one more __builtin_expect.
+       * pthread_timedjoin.c: Likewise.
+
+       * pthread_getspecific.c (__pthread_getspecific): Clear data->data
+       not data of sequence number does not match.
+       Add one __builtin_expect.
+
+       * Makefile (tests): Add tst-clock1.
+       * tst-clock1.c: New file.
+
+       * pthread_setconcurrency.c (pthread_setconcurrency): Fail for
+       negative arguments.
+       * Makefile (tests): Add tst-basic5.
+       * tst-basic5.c: New file.
+
+2003-02-14  Ulrich Drepper  <drepper@redhat.com>
+
+       * Makefile (tests): Add tst-basic4.
+       * tst-basic4.c: New file.
+
+       * pthreadP.h: Add declaraction for __nptl_nthreads.
+       * pthread_create.c: Define __nptl_nthreads
+       (start_thread): Increment __nptl_nthreads at beginning.  Decrement
+       after thread is done.  If then zero, call exit(0).
+       * sysdeps/pthread/pthread-functions.h (struct pthread_functions):
+       Add ptr_nthreads.  Define HAVE_PTR_NTHREADS.
+       * init.c (pthread_functions): Initialize ptr_nthreads.
+       * allocatestack.c (nptl_nthreads): Remove definition and all uses.
+       (__reclaim_stacks): Decrement __nptl_nthreads.
+       * sysdeps/pthread/Makefile [$(subdir)==csu] (CFLAGS-libc-start.c):
+       Define.
+       * Makefile (tests): Add tst-basic3.
+       * tst-basic3.c: New file.
+
+       * descr.h: Define CANCELING_BIT and CANCELING_BITMASK.  Introduce
+       after CANCELTYPE_BIT, move the other bits up.  Update CANCEL_RESTMASK.
+       * init.c (sigcancel_handler): Also set CANCELING_BITMASK bit in newval.
+       * pthread_cancel.c (pthread_cancel): Likewise.  Also set CANCELING_BIT
+       if asynchronous canceling is enabled.
+       * pthread_join.c (pthread_join): When recognizing circular joins,
+       take into account the other thread might be already canceled.
+       * Makefile (tests): Add tst-join5.
+       * tst-join5.c: New file.
+
+       * Makefile (tests): Add tst-join4.
+       * tst-join4.c: New file.
+
+2003-02-13  Ulrich Drepper  <drepper@redhat.com>
+
+       * tst-cond4.c (main): Add test of pthread_attr_getpshared.
+
+2003-02-13  Martin Schwidefsky  <schwidefsky@de.ibm.com>
+
+       * sysdeps/s390/tls.h (THREAD_GETMEM, THREAD_GETMEM_NC, THREAD_SETMEM,
+       THREAD_SETMEM_NC): Use passed descr instead of THREAD_SELF.
+       * sysdeps/unix/sysv/linux/s390/jmp-unwind.c (_longjmp_unwind): Avoid
+       warning.
+       * sysdeps/unix/sysv/linux/s390/lowlevellock.c: Include <sys/time.h>
+       to avoid warning.
+       * sysdeps/unix/sysv/linux/s390/sem_post.c (__new_sem_post): Return
+       error if lll_futex_wake failed.
+
+2003-02-13  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Fix
+       handling of cancellation and failung pthread_mutex_unlock call.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Likewise.
+       * Makefile (tests): Add tst-cond8 and tst-cond9.
+       * tst-cond8.c: New file.
+       * tst-cond9.c: New file.
+
+       * tst-cond7.c (do_test): Unlock the mutex before canceling the thread.
+
+       * sysdeps/pthread/pthread.h: Add missing initializers.  Protect
+       non-standard initializers with __USE_GNU.
+
+       * Makefile (tests): Add tst-cleanup3.
+       * tst-cleanup3.c: New file.
+
+2003-02-12  Ulrich Drepper  <drepper@redhat.com>
+
+       * Makefile (tests): Add tst-attr1 and tst-attr2.
+       * tst-attr1.c: New file.
+       * tst-attr2.c: New file.
+
+       * Makefile: Add rules to build and run tst-atfork2 test.
+       * tst-atfork2.c: New file.
+       * tst-atfork2mod.c: New file.
+
+       * sysdeps/unix/sysv/linux/unregister-atfork.c
+       (__unregister_atfork): Free the memory allocated for the handlers
+       after removing them from the lists.
+
+       * sysdeps/unix/sysv/linux/register-atfork.c: Define memeory
+       cleanup function.
+
+       * tst-atfork1.c (do_test): Wait for the child we forked.
+       Report error in child.
+
+       * sysdeps/unix/sysv/linux/fork.c (__libc_fork): Fix comment.
+
+       * sysdeps/pthread/Makefile: Define CFLAGS-confstr.c.
+
+2003-02-10  Ulrich Drepper  <drepper@redhat.com>
+
+       * Makefile (tests): Add tst-cancel8.
+       * tst-cancel8.c: New file.
+
+       * sysdeps/unix/sysv/linux/i386/pthread_once.S (clear_once_control): Fix
+       clearing of control variable.
+       * Makefile (tests): Add tst-once3 and tst-once4.
+       * tst-once3.c: New file.
+       * tst-once4.c: New file.
+
+2003-02-08  kaz Kojima  <kkojima@rr.iij4u.or.jp>
+
+       * sysdeps/sh/Makefile: New file.
+       * sysdeps/sh/bits/atomic.h: New file.
+       * sysdeps/sh/pthread_spin_init.c: New file.
+       * sysdeps/sh/pthread_spin_lock.c: New file.
+       * sysdeps/sh/pthread_spin_trylock.S: New file.
+       * sysdeps/sh/pthread_spin_unlock.S: New file.
+       * sysdeps/sh/pthreaddef.h: New file.
+       * sysdeps/sh/tcb-offsets.sym: New file.
+       * sysdeps/sh/td_ta_map_lwp2thr.c: New file.
+       * sysdeps/sh/tls.h: New file.
+       * sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h: New file.
+       * sysdeps/unix/sysv/linux/sh/bits/semaphore.h: New file.
+       * sysdeps/unix/sysv/linux/sh/createthread.c: New file.
+       * sysdeps/unix/sysv/linux/sh/fork.c: New file.
+       * sysdeps/unix/sysv/linux/sh/libc-lowlevellock.S: New file.
+       * sysdeps/unix/sysv/linux/sh/libc-lowlevelmutex.S: New file.
+       * sysdeps/unix/sysv/linux/sh/lowlevel-atomic.h: New file.
+       * sysdeps/unix/sysv/linux/sh/lowlevelcond.h: New file.
+       * sysdeps/unix/sysv/linux/sh/lowlevellock.S: New file.
+       * sysdeps/unix/sysv/linux/sh/lowlevellock.h: New file.
+       * sysdeps/unix/sysv/linux/sh/lowlevelmutex.S: New file.
+       * sysdeps/unix/sysv/linux/sh/lowlevelrwlock.h: New file.
+       * sysdeps/unix/sysv/linux/sh/pt-initfini.c: New file.
+       * sysdeps/unix/sysv/linux/sh/pt-vfork.S: New file.
+       * sysdeps/unix/sysv/linux/sh/pthread_barrier_wait.S: New file.
+       * sysdeps/unix/sysv/linux/sh/pthread_cond_broadcast.S: New file.
+       * sysdeps/unix/sysv/linux/sh/pthread_cond_signal.S: New file.
+       * sysdeps/unix/sysv/linux/sh/pthread_cond_timedwait.S: New file.
+       * sysdeps/unix/sysv/linux/sh/pthread_cond_wait.S: New file.
+       * sysdeps/unix/sysv/linux/sh/pthread_once.S: New file.
+       * sysdeps/unix/sysv/linux/sh/pthread_rwlock_rdlock.S: New file.
+       * sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedrdlock.S: New file.
+       * sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedwrlock.S: New file.
+       * sysdeps/unix/sysv/linux/sh/pthread_rwlock_unlock.S: New file.
+       * sysdeps/unix/sysv/linux/sh/pthread_rwlock_wrlock.S: New file.
+       * sysdeps/unix/sysv/linux/sh/sem_post.S: New file.
+       * sysdeps/unix/sysv/linux/sh/sem_timedwait.S: New file.
+       * sysdeps/unix/sysv/linux/sh/sem_trywait.S: New file.
+       * sysdeps/unix/sysv/linux/sh/sem_wait.S: New file.
+       * sysdeps/unix/sysv/linux/sh/sysdep-cancel.h: New file.
+
+2003-02-08  Ulrich Drepper  <drepper@redhat.com>
+
+       * tst-cond2.c: Rearrange code to not rely on behavior undefined
+       according to POSIX.
+
+       * tst-basic2.c (do_test): Lock mutex before creating the thread.
+
+2003-02-07  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/x86_64/tls.h: Remove unnecessary macros, left over from x86.
+       (TLS_GET_FS): New #define.
+       (TLS_SET_FS): New #define.
+       Correct value of __NR_set_thread_area.
+
+       * sysdeps/x86_64/td_ta_map_lwp2thr.c: New file.
+
+2003-02-06  Ulrich Drepper  <drepper@redhat.com>
+
+       * Makefile (tests): Add tst-popen1.
+       * tst-popen1.c: New file.
+
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Remove wrong
+       but inactive generalization.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_signal.S: Likewise.
+       Minor optimization, remove one instruction.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S: Likewise.
+
+2003-02-04  Martin Schwidefsky  <schwidefsky@de.ibm.com>
+
+       * sysdeps/unix/sysv/linux/s390/fork.c: Correct order of parameters.
+
+2003-01-31  Martin Schwidefsky  <schwidefsky@de.ibm.com>
+
+       * init.c (__NR_set_tid_address): Add #ifdef for s390.
+       * sysdeps/pthread/pthread_barrier_wait.c: New file.
+       * sysdeps/pthread/pthread_cond_broadcast.c: New file.
+       * sysdeps/pthread/pthread_cond_signal.c: New file.
+       * sysdeps/pthread/pthread_cond_timedwait.c: New file.
+       * sysdeps/pthread/pthread_cond_wait.c: New file.
+       * sysdeps/pthread/pthread_rwlock_rdlock.c: New file.
+       * sysdeps/pthread/pthread_rwlock_timedrdlock.c: New file.
+       * sysdeps/pthread/pthread_rwlock_timedwrlock.c: New file.
+       * sysdeps/pthread/pthread_rwlock_unlock.c: New file.
+       * sysdeps/pthread/pthread_rwlock_wrlock.c: New file.
+       * sysdeps/s390/Makefile: New file.
+       * sysdeps/s390/bits/atomic.h: New file.
+       * sysdeps/s390/pthread_spin_init.c: New file.
+       * sysdeps/s390/pthread_spin_lock.c: New file.
+       * sysdeps/s390/pthread_spin_trylock.c: New file.
+       * sysdeps/s390/pthread_spin_unlock.c: New file.
+       * sysdeps/s390/pthreaddef.h: New file.
+       * sysdeps/s390/tcb-offsets.sym: New file.
+       * sysdeps/s390/td_ta_map_lwp2thr.c: New file.
+       * sysdeps/s390/tls.h: New file.
+       * sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h: New file.
+       * sysdeps/unix/sysv/linux/s390/bits/semaphore.h: New file.
+       * sysdeps/unix/sysv/linux/s390/createthread.c: New file.
+       * sysdeps/unix/sysv/linux/s390/dl-sysdep.h: New file.
+       * sysdeps/unix/sysv/linux/s390/fork.c: New file.
+       * sysdeps/unix/sysv/linux/s390/jmp-unwind.c: New file.
+       * sysdeps/unix/sysv/linux/s390/libc-lowlevellock.c: New file.
+       * sysdeps/unix/sysv/linux/s390/libc-lowlevelmutex.c: New file.
+       * sysdeps/unix/sysv/linux/s390/lowlevellock.c: New file.
+       * sysdeps/unix/sysv/linux/s390/lowlevellock.h: New file.
+       * sysdeps/unix/sysv/linux/s390/lowlevelmutex.c: New file.
+       * sysdeps/unix/sysv/linux/s390/lowlevelsem.h: New file.
+       * sysdeps/unix/sysv/linux/s390/pthread_once.c: New file.
+       * sysdeps/unix/sysv/linux/s390/s390-32/pt-initfini.c: New file.
+       * sysdeps/unix/sysv/linux/s390/s390-32/pt-vfork.S: New file.
+       * sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h: New file.
+       * sysdeps/unix/sysv/linux/s390/s390-64/pt-initfini.c: New file.
+       * sysdeps/unix/sysv/linux/s390/s390-64/pt-vfork.S: New file.
+       * sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h: New file.
+       * sysdeps/unix/sysv/linux/s390/sem_post.c: New file.
+       * sysdeps/unix/sysv/linux/s390/sem_timedwait.c: New file.
+       * sysdeps/unix/sysv/linux/s390/libc-lowlevellock.c: New file.
+       * sysdeps/unix/sysv/linux/s390/sem_wait.c: New file.
+
+2003-02-04  Ulrich Drepper  <drepper@redhat.com>
+
+       * atomic.h: Add a couple more default implementations.
+       (atomic_compare_and_exchange_acq): Use
+       __arch_compare_and_exchange_32_acq in return value definition.  It
+       always exists.
+       (atomic_bit_set): Renamed from atomic_set_bit.
+       Add missing atomic_ prefixes.
+
+       * sysdeps/pthread/bits/libc-lock.h (__libc_once): In case no
+       thread library is available, use correct value to mark initialized
+       once variable.
+
+2003-02-03  Ulrich Drepper  <drepper@redhat.com>
+
+       * allocatestack.c (allocate_stack): Use __getpagesize instead of
+       __sysconf to determine pagesize.
+
+       * pthread_create.c: Include <atomic.h>.
+       * allocatestack.c (allocate_stack): Implement coloring of the
+       allocated stack memory.  Rename pagesize to pagesize_m1.  It's the
+       size minus one.  Adjust users.
+       * sysdeps/i386/i686/Makefile: New file.
+
+2003-02-02  Ulrich Drepper  <drepper@redhat.com>
+
+       * allocatestack.c: Improve comment throughout the file.
+
+       * sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S
+       (__lll_lock_wait): Add branch prediction.
+       * sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S
+       (__lll_lock_wait): Likewise.
+       (lll_unlock_wake_cb): Removed.
+
+2003-01-31  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/bits/posix_opt.h: Remove
+       _POSIX_THREAD_PRIORITY_SCHEDULING.
+
+2003-01-30  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/pthread/pthread-functions.h (struct pthread_functions):
+       Fix return type of ptr___pthread_getspecific.
+
+2003-01-29  Ulrich Drepper  <drepper@redhat.com>
+
+       * Makefile (tests): Add tst-umask1.
+       (tst-umask1-ARGS): Define.
+       * tst-umask1.c: New file.
+
+2003-01-28  Ulrich Drepper  <drepper@redhat.com>
+
+       * Makefile (libpthread-routines): Remove lowlevelrwlock.  Add
+       pthread_rwlock_rdlock, pthread_rwlock_timedrdlock,
+       pthread_rwlock_wrlock, pthread_rwlock_timedwrlock, and
+       pthread_rwlock_unlock.
+       * sysdeps/unix/sysv/linux/i386/i486/lowlevelrwlock.S: Removed
+       * sysdeps/unix/sysv/linux/i386/i586/lowlevelrwlock.S: Removed
+       * sysdeps/unix/sysv/linux/i386/i686/lowlevelrwlock.S: Removed
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_rdlock.S: New file.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedrdlock.S:
+       New file.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_wrlock.S: New file.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedwrlock.S:
+       New file.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_unlock.S: New file.
+       * sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_rdlock.S: New file.
+       * sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_timedrdlock.S:
+       New file.
+       * sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_wrlock.S: New file.
+       * sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_timedwrlock.S:
+       New file.
+       * sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_unlock.S: New file.
+       * sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_rdlock.S: New file.
+       * sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_timedrdlock.S:
+       New file.
+       * sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_wrlock.S: New file.
+       * sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_timedwrlock.S:
+       New file.
+       * sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_unlock.S: New file.
+
+       * Makefile (libpthread-routines): Remove lowlevelcond and
+       lowlevelsem.  Add sem_wait, sem_trywait, sem_timedwait, sem_post,
+       pthread_cond_wait, pthread_cond_timedwait, pthread_cond_signal,
+       and pthread_cond_broadcast.
+       * sysdeps/unix/sysv/linux/i386/i486/lowlevelsem.S: Removed
+       * sysdeps/unix/sysv/linux/i386/i486/lowlevelcond.S: Removed
+       * sysdeps/unix/sysv/linux/i386/i586/lowlevelsem.S: Removed
+       * sysdeps/unix/sysv/linux/i386/i586/lowlevelcond.S: Removed
+       * sysdeps/unix/sysv/linux/i386/i686/lowlevelsem.S: Removed
+       * sysdeps/unix/sysv/linux/i386/i686/lowlevelcond.S: Removed
+       * sysdeps/unix/sysv/linux/i386/i486/sem_wait.S: New file.
+       * sysdeps/unix/sysv/linux/i386/i486/sem_trywait.S: New file.
+       * sysdeps/unix/sysv/linux/i386/i486/sem_timedwait.S: New file.
+       * sysdeps/unix/sysv/linux/i386/i486/sem_post.S: New file.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: New file.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: New file.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_signal.S: New file.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S: New file.
+       * sysdeps/unix/sysv/linux/i386/i586/sem_wait.S: New file.
+       * sysdeps/unix/sysv/linux/i386/i586/sem_trywait.S: New file.
+       * sysdeps/unix/sysv/linux/i386/i586/sem_timedwait.S: New file.
+       * sysdeps/unix/sysv/linux/i386/i586/sem_post.S: New file.
+       * sysdeps/unix/sysv/linux/i386/i586/pthread_cond_wait.S: New file.
+       * sysdeps/unix/sysv/linux/i386/i586/pthread_cond_timedwait.S: New file.
+       * sysdeps/unix/sysv/linux/i386/i586/pthread_cond_signal.S: New file.
+       * sysdeps/unix/sysv/linux/i386/i586/pthread_cond_broadcast.S: New file.
+       * sysdeps/unix/sysv/linux/i386/i686/sem_wait.S: New file.
+       * sysdeps/unix/sysv/linux/i386/i686/sem_trywait.S: New file.
+       * sysdeps/unix/sysv/linux/i386/i686/sem_timedwait.S: New file.
+       * sysdeps/unix/sysv/linux/i386/i686/sem_post.S: New file.
+       * sysdeps/unix/sysv/linux/i386/i686/pthread_cond_wait.S: New file.
+       * sysdeps/unix/sysv/linux/i386/i686/pthread_cond_timedwait.S: New file.
+       * sysdeps/unix/sysv/linux/i386/i686/pthread_cond_signal.S: New file.
+       * sysdeps/unix/sysv/linux/i386/i686/pthread_cond_broadcast.S: New file.
+       * sysdeps/unix/sysv/linux/i386/lowlevelcond.h: New file.
+
+       * sysdeps/unix/sysv/linux/i386/createthread.c: Define
+       PREPARE_CREATE and TLS_VALUE with x86-specific bits.  All the rest
+       of the code is moved to ...
+       * sysdeps/pthread/createthread.c: ...here.  New file.
+
+2003-01-27  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/i486/lowlevelsem.S
+       (__new_sem_post): Clear %eax before returning.
+       Reported by MAEDA Naoaki <maeda.naoaki@jp.fujitsu.com>.
+
+       * Makefile (tests): Add tst-cleanup2.
+       * tst-cleanup2.c: New file.
+
+       * sysdeps/pthread/bits/libc-lock.h (__libc_cleanup_region_start):
+       Interpret first parameter correctly.
+
+2003-01-17  Ulrich Drepper  <drepper@redhat.com>
+
+       * Makefile (headers): Add bits/semaphore.h.
+
+2003-01-16  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/i386/tls.h (INIT_SYSINFO): Initialize _head->sysinfo even
+       if not SHARED.
+
+2003-01-14  Ulrich Drepper  <drepper@redhat.com>
+
+       * sem_open.c (sem_open): Return SEM_FAILED if existing semaphore
+       must be used and mapping failed.
+       Reported by Luke Elliott <luke.elliott@activfinancial.com>.
+
+       * Makefile (CFLAGS-pthread_self.os): Define this, not
+       CFLAGS-pthread_self.c.
+
+2003-01-13  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S: Don't export
+       lll_unlock_wake_cb.
+
+       * Makefile (libpthread-routines): Add version.  Add rules to build
+       version.os and banner.h.
+       * version.c: New file.
+
+2003-01-13  Jakub Jelinek  <jakub@redhat.com>
+
+       * pthread_mutex_lock.c (__pthread_mutex_lock_internal): Make
+       the alias unconditional.
+       * pthread_mutex_unlock.c  (__pthread_mutex_unlock_internal): Likewise.
+
+2003-01-13  Ulrich Drepper  <drepper@redhat.com>
+
+       * Makefile (CFLAGS-pthread_self.c): New definition.
+
+2003-01-06  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/pthread/pthread_sigmask.c (pthread_sigmask): Add
+       INTERNAL_SYSCALL_DECL, add err argument to INTERNAL_SYSCALL* macros.
+       * sysdeps/unix/sysv/linux/raise.c (raise): Likewise.
+       * init.c (__pthread_initialize_minimal_internal): Likewise.
+
+2003-01-07  Jakub Jelinek  <jakub@redhat.com>
+
+       * pthreadP.h (__pthread_cond_timedwait): Add prototype.
+
+       * sysdeps/unix/sysv/linux/i386/dl-sysdep.h
+       (RTLD_CORRECT_DYNAMIC_WEAK): Remove.
+       (DL_SYSINFO_IMPLEMENTATION): Change into .text section and back.
+       * sysdeps/unix/sysv/linux/i386/i686/dl-sysdep.h
+       (RTLD_CORRECT_DYNAMIC_WEAK): Remove.
+       (DL_SYSINFO_IMPLEMENTATION): Change into .text section and back.
+
+2003-01-06  Jakub Jelinek  <jakub@redhat.com>
+
+       * pthreadP.h (LIBC_CANCEL_HANDLED): Define.
+       * pt-system.c (LIBC_CANCEL_HANDLED): Add.
+       * tst-cancel-wrappers.sh: Remove all exceptions.
+
+2003-01-05  Ulrich Drepper  <drepper@redhat.com>
+
+       * tst-cancel-wrappers.sh: Invoke gawk not awk since we use GNU awk
+       features.  Reported by Marijn Ros <marijn@mad.scientist.com>.
+
+       * sysdeps/unix/sysv/linux/jmp-unwind.c: Include <pthread-functions.h>.
+       Use __libc_pthread_functions array if SHARED.
+
+       * pthreadP.h: Move pthread_cond_2_0_t definition to...
+       * sysdeps/unix/sysv/linux/internaltypes.h: ...here.
+
+       * sysdeps/pthread/bits/libc-lock.h (__libc_ptf_call): New #define.
+       (__libc_rwlock_rdlock, __libc_rwlock_wrlock, __libc_rwlock_unlock,
+       __libc_key_create, __libc_getspecific, __libc_setspecific): Use
+       __libc_ptf_call instead of __libc_maybe_call.
+       (PTF): New #define.
+       (__libc_cleanup_region_start): Wrap function name with PTF call.
+       (__libc_cleanup_region_end): Likewise.
+       (__libc_cleanup_end): Likewise.
+
+       * pthread_getspecific.c: Add __pthread_getspecific_internal alias.
+       * pthread_setspecific.c: Add __pthread_setspecific_internal alias.
+       * pthread_key_create.c: Add __pthread_key_create_internal alias.
+       * pthreadP.h: Add prototypes.
+
+       * sysdeps/unix/sysv/linux/i386/i486/lowlevelrwlock.S: Add
+       __pthread_rwlock_rdlock, __pthread_rwlock_wrlock, and
+       __pthread_rwlock_unlock aliases.
+       * pthreadP.h: Add prototypes for new aliases.
+
+       * pthreadP.h (struct pthead_functions): Moved to...
+       * sysdeps/pthread/pthread-functions.h: ...here.  New file.
+       * init.c (pthread_functions): Add initializers for new elements.
+
+       * cleanup_defer.c: Add __pthread_cleanup_push_defer and
+       __pthread_cleanup_pop_restore aliases.
+       * pthreadP.h: Add prototypes.
+
+       * cleanup.c: Rename _GI_pthread_cleanup_push to __pthread_cleanup_push
+       and _GI_pthread_cleanup_pop to __pthread_cleanup_pop.
+       * sysdeps/unix/sysv/linux/i386/i486/lowlevelcond.S: Adjust caller.
+       * sysdeps/unix/sysv/linux/i386/pthread_once.S: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_once.S: Likewise.
+       * pthreadP.h: Adjust prototypes and callers.
+
+2003-01-04  Ulrich Drepper  <drepper@redhat.com>
+
+       * Makefile (tests): Add tst-cancel7.
+       (tst-cancel7-ARGS): New variable.
+       * tst-cancel7.c: New file.
+
+       * old_pthread_cond_broadcast.c: Optimize initialization a bit to work
+       around gcc defficiencies.
+       * old_pthread_cond_signal.c: Likewise.
+       * old_pthread_cond_timedwait.c: Likewise.
+       * old_pthread_cond_wait.c: Likewise.
+
+       * pthreadP.h (pthread_cond_2_0_t): Remove unneeded lock element.
+
+2003-01-03  Ulrich Drepper  <drepper@redhat.com>
+
+       * Makefile (tests): Add tst-cond7.
+       * tst-cond7.c: New file.
+
+       * sysdeps/unix/sysv/linux/i386/i486/lowlevelcond.S
+       (condvar_cleanup): Get condvar address from the right place.
+
+       * atomic.h: Correct definitions of atomic_full_barrier,
+       atomic_read_barrier, atomic_write_barrier.
+
+       * old_pthread_cond_broadcast.c: Make memory allocate and initialization
+       race-free.
+       * old_pthread_cond_signal.c: Likewise.
+       * old_pthread_cond_timedwait.c: Likewise.
+       * old_pthread_cond_wait.c: Likewise.
+
+2003-01-03  Jakub Jelinek  <jakub@redhat.com>
+
+       * Makefile ($(objpfx)libpthread.so): Depend on ld.so.
+
+2003-01-03  Ulrich Drepper  <drepper@redhat.com>
+
+       * pthreadP.h (pthread_cond_2_0_t): New type.
+       (struct pthread_functions): Use new type for 2.0 condvar callbacks.
+       Use new type for the 2.0 condvar function prototypes.
+       * forward.c: Use pthread_cond_2_0_t for 2.0 condvar functions.
+       * old_pthread_cond_init.c: Use pthread_cond_2_0_t for condvar
+       parameter.
+       * old_pthread_cond_destroy.c: Likewise.
+       * old_pthread_cond_broadcast.c: Likewise.  Lock appropriately.
+       * old_pthread_cond_signal.c: Likewise.
+       * old_pthread_cond_timedwait.c: Likewise.
+       * old_pthread_cond_wait.c: Likewise.
+
+       * sysdeps/unix/sysv/linux/i386/i486/lowlevelcond.S
+       (__pthread_cond_wait): Don't save cancellation mode and seq value
+       in same location.
+
+       * herrno.c (__h_errno_location): Don't define as weak.
+
+2003-01-02  Jakub Jelinek  <jakub@redhat.com>
+
+       * Versions [libc] (GLIBC_2.3.2): Export pthread_cond_broadcast,
+       pthread_cond_destroy, pthread_cond_init, pthread_cond_signal
+       and pthread_cond_wait.
+       * old_pthread_cond_broadcast.c (__old_pthread_cond_broadcast):
+       Renamed to...
+       (__pthread_cond_broadcast_2_0): ... this.
+       * old_pthread_cond_destroy.c (__old_pthread_cond_destroy):
+       Renamed to...
+       (__pthread_cond_destroy_2_0): ... this.
+       * old_pthread_cond_init.c (__old_pthread_cond_init):
+       Renamed to...
+       (__pthread_cond_init_2_0): ... this.
+       * old_pthread_cond_signal.c (__old_pthread_cond_signal):
+       Renamed to...
+       (__pthread_cond_signal_2_0): ... this.
+       * old_pthread_cond_wait.c (__old_pthread_cond_wait):
+       Renamed to...
+       (__pthread_cond_wait_2_0): ... this.
+       * pthread_cond_destroy.c: Include shlib-compat.h.
+       (pthread_cond_destroy): Change strong_alias into versioned_symbol.
+       * pthread_cond_init.c: Include shlib-compat.h.
+       (pthread_cond_init): Change strong_alias into versioned_symbol.
+       * pthreadP.h (struct pthread_functions): Rename ptr_pthread_cond_*
+       fields to ptr___pthread_cond_* and add ptr___pthread_cond_*_2_0
+       fields.
+       (__pthread_cond_broadcast_2_0, __pthread_cond_destroy_2_0,
+       __pthread_cond_init_2_0, __pthread_cond_signal_2_0,
+       __pthread_cond_wait_2_0): New prototypes.
+       (__old_pthread_cond_broadcast, __old_pthread_cond_destroy,
+       __old_pthread_cond_init, __old_pthread_cond_signal,
+       __old_pthread_cond_wait): Removed.
+       * init.c: Include shlib-compat.h.
+       (pthread_functions): Guard ptr___pthread_attr_init_2_0
+       initialization with SHLIB_COMPAT (GLIBC_2_0, GLIBC_2_1).
+       Rename ptr_pthread_cond_* to ptr___pthread_cond_*, initialize
+       ptr___pthread_cond_*_2_0 fields.
+       * forward.c: Export both pthread_cond_*@@GLIBC_2.3.2 and
+       pthread_cond_*@GLIBC_2.0 compatibility symbols.
+
+       * sysdeps/pthread/sigaction.c (SIGCANCEL): Only define if
+       LIBC_SIGACTION was not yet defined.
+       [!defined LIBC_SIGACTION]: Define LIBC_SIGACTION, #include self.
+       [!defined LIBC_SIGACTION] (__sigaction): New function and
+       libc_hidden_weak.
+       [!defined LIBC_SIGACTION] (sigaction): New weak_alias.
+       [defined LIBC_SIGACTION]: #include_next <sigaction.c>.
+
+2003-01-02  Jakub Jelinek  <jakub@redhat.com>
+
+       * Makefile (CFLAGS-pthread_atfork.c): Add -DNOT_IN_libc.
+
+2003-01-02  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h (pthread_cond_t):
+       New, larger type definition.
+       * sysdeps/unix/sysv/linux/i386/i486/lowlevelcond.S: New condvar
+       implementation.
+       * Versions [libpthread]: Add definitions for new pthread_cond_*
+       interfaces for version GLIBC_2.3.2.
+       * pthread_cond_init.c: Update initialization for new type definition.
+       * Makefile (libpthread-routines): Remove pthread_cond_wait,
+       pthread_cond_timedwait, pthread_cond_signal, and
+       pthread_cond_broadcast.  Add old_pthread_cond_init,
+       old_pthread_cond_destroy, old_pthread_cond_wait,
+       old_pthread_cond_timedwait, old_pthread_cond_signal, and
+       old_pthread_cond_broadcast.
+       * old_pthread_cond_broadcast.c: New file.
+       * old_pthread_cond_destroy.c: New file.
+       * old_pthread_cond_init.c: New file.
+       * old_pthread_cond_signal.c: New file.
+       * old_pthread_cond_timedwait.c: New file.
+       * old_pthread_cond_wait.c: New file.
+       * pthreadP.h: Add prototypes for the compatibility interfaces.
+
+       * pthread_cond_destroy.c: Don't include <errno.h>.
+
+2003-01-01  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/i486/lowlevelrwlock.S: Avoid
+       unnecessary zero offset when addressing MUTEX.
+
+2002-12-31  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/fork.h: Add libc_hidden_proto for
+       __register_atfork.
+       * sysdeps/unix/sysv/linux/register-atfork.c: Add libc_hidden_def
+       for __register_atfork.
+
+2002-12-31  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h: Use __ASSEMBLER__
+       instead of ASSEMBLER test macro.
+
+       * sysdeps/unix/sysv/linux/allocrtsig.c (__libc_current_sigrtmin,
+       __libc_current_sigrtmax): Add libc_hidden_def.
+
+       * sysdeps/pthread/list.h: Remove assert.h include.
+
+2002-12-31  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/pt-initfini.c (call_initialize_minimal): Use
+       __pthread_initialize_minimal_internal not
+       __pthread_initialize_minimal.
+
+2002-12-30  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/pt-initfini.c (call_initialize_minimal): Mark
+       __pthread_initialize_minimal as hidden.
+
+       * init.c (__pthread_initialize_minimal_internal): Don't mark as
+       constructor.
+
+2002-12-31  Jakub Jelinek  <jakub@redhat.com>
+
+       * Makefile ($(inst_libdir)/libpthread.so): Depend on
+       $(common-objpfx)format.lds, include that into the output script.
+       Fix comment.
+       (extra-B-pthread.so): Change linuxthreads/ into nptl/.
+
+2002-12-28  Andreas Jaeger  <aj@suse.de>
+
+       * sysdeps/unix/sysv/linux/xstatconv.c (xstat_conv): Adjust for
+       nsec resolution changes.
+       (xstat64_conv): Likewise.
+       (xstat32_conv): Likewise.
+       * sysdeps/unix/sysv/linux/kernel_stat.h: Add nsec resolution for
+       struct kernel_stat.
+       * sysdeps/unix/sysv/linux/bits/stat.h: Add nsec resolution for
+       structs stat and stat64.
+       * time/time.h (__timespec_defined): Define for __USE_MISC.
+       * io/sys/stat.h [__USE_MISC]: Define __need_timespec for struct stat.
+
+2002-12-30  Jakub Jelinek  <jakub@redhat.com>
+
+       * forward.c (FORWARD2): Renamed from FORWARD3.  Remove unused export
+       argument.
+       (pthread_attr_init_2_0, pthread_attr_init_2_1): Use FORWARD macro.
+       (pthread_exit): Use strong_alias to avoid warnings.
+       * pthreadP.h (struct pthread_functions): Rename ptr_pthread_exit
+       and ptr_pthread_attr_init_2_* to ptr___pthread_exit and
+       ptr___pthread_attr_init_2_*.
+       * init.c (pthread_functions): Adjust.
+
+2002-12-29  Ulrich Drepper  <drepper@redhat.com>
+
+       * forward.c: Make all functions available by default again.  It
+       caused too much trouble.
+
+       * pt-siglongjmp.c: Removed.
+
+2002-12-28  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/i386/tls.h: Include tcb-offsets.h in assembler.
+       (SYSINFO_OFFSET, MULTIPLE_THREADS_OFFSET): Remove.
+       * sysdeps/i386/Makefile: New file.
+       * sysdeps/i386/tcb-offsets.sym: New file.
+       * sysdeps/pthread/tcb-offsets.h: New file.
+       * sysdeps/unix/sysv/linux/libc_pthread_init.c (__libc_pthread_init):
+       Remove MULTIPLE_THREADS_OFFSET and SYSINFO_OFFSET checks.
+
+       * sysdeps/unix/sysv/linux/Versions [libc] (GLIBC_PRIVATE): Move
+       __register_atfork...
+       (GLIBC_2.3.2): ...here.
+
+2002-12-28  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/pthread.h: Mark pthread_attr_getstackaddr and
+       pthread_attr_setstackaddr with __attribute_deprecated__.
+
+2002-12-27  Jakub Jelinek  <jakub@redhat.com>
+
+       * pt-system.c (system): Remove cancellation handling.
+       * tst-cancel-wrappers.sh: Allow pt-system.o* to not use the
+       cancellation routines.
+
+2002-12-28  Ulrich Drepper  <drepper@redhat.com>
+
+       * descr.h: Include <dl-sysdep.h>.
+       (struct pthread): Move header.data.list to the back of the struct.
+       * sysdeps/i386/tls.h (tcbhead_t): Move list to the back of the struct.
+       (MULTIPLE_THREADS_OFFSET): Adjust offset.
+       (SYSINFO_OFFSEET): Likewise.
+
+2002-12-27  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/i686/dl-sysdep.h (USE_DL_SYSINFO):
+       Define.
+       (DL_SYSINFO_DEFAULT): Cast to uintptr_t to avoid warnings.
+       * sysdeps/unix/sysv/linux/i386/dl-sysdep.h (NEED_DL_SYSINFO,
+       DL_SYSINFO_DEFAULT, DL_SYSINFO_IMPLEMENTATION): Define.
+       (USE_DL_SYSINFO): Undef.
+
+2002-12-22  Jakub Jelinek  <jakub@redhat.com>
+
+       * Makefile (tests-reverse): Use $(objpfx)../libc.so instead of
+       $(common-objpfx)libc.so.
+       * tst-cancel4.c (tf_write, tf_writev): Increase buf sizes so that
+       it is bigger than pipe buffer size even on arches with bigger
+       page size.
+       (tf_usleep): Cast usleep argument to useconds_t to avoid warnings.
+
+2002-12-25  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/i486/lowlevelsem.S: Implement
+       correct errno access for case that USE___THREAD is not defined.
+
+2002-12-24  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/dl-sysdep.h: Add missing #endif.
+       Patch by Marijn Ros <marijn@mad.scientist.com>.
+
+2002-12-22  Roland McGrath  <roland@redhat.com>
+
+       * Makefile (omit-deps): Add $(unix-syscalls:%=ptw-%).
+
+2002-12-20  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/bits/stdio-lock.h (_IO_lock_inexpensive): Define.
+
+2002-12-19  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/dl-sysdep.h: Don't define
+       NEED_DL_SYSINFO since no processor < i686 had the sysenter opcode.
+       * sysdeps/unix/sysv/linux/i386/i686/dl-sysdep.h: New file.
+
+       * sysdeps/unix/sysv/linux/i386/pthread_once.S: Use ENTER_KERNEL instead
+       of int $0x80.
+       * sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/libc-lowlevelmutex.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/lowlevelcond.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/lowlevelmutex.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/lowlevelrwlock.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/lowlevelsem.S: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_barrier_wait.S: Likewise.
+
+       * sysdeps/unix/sysv/linux/i386/lowlevellock.h: Add support for using
+       sysenter.
+       * sysdeps/unix/sysv/linux/i386/lowlevelsem.h: Likewise.
+
+       * sysdeps/i386/tls.h: Unconditionally include <dl-sysdep.h>.
+
+       * allocatestack.c (allocate_stack) [NEED_DL_SYSINFO]: Set sysinfo
+       in new TCB.
+       * sysdeps/unix/sysv/linux/i386/createthread.c (create_thread): Check
+       that sysinfo is properly initialized.
+       * sysdeps/unix/sysv/linux/i386/dl-sysdep.h: Define RTLD_PRIVATE_ERRNO
+       to 1 only for ld.so.
+
+       * sysdeps/unix/sysv/linux/i386/dl-sysdep.h: Define
+       RTLD_CORRECT_DYNAMIC_WEAK.
+
+2002-12-19  Jakub Jelinek  <jakub@redhat.com>
+
+       * forward.c (pthread_attr_init_2_0, pthread_attr_init_2_1):
+       Use return 0 as 6th argument to FORWARD4.
+       * pthread_equal.c: Include pthreadP.h instead of pthread.h.
+
+2002-12-18  Ulrich Drepper  <drepper@redhat.com>
+
+       * descr.h (struct pthread) [NEED_DL_SYSINFO]: Add sysinfo member.
+       * sysdeps/i386/tls.h (tcbhead_t): Add sysinfo member.
+       Define SYSINFO_OFFSEET if NEED_DL_SYSINFO is defined.
+       (INIT_SYSINFO): New #define.
+       (TLS_TP_INIT): Use INIT_SYSINFO.
+       * sysdeps/unix/sysv/linux/libc_pthread_init.c (__libc_pthread_init):
+       At test to make sure SYSINFO_OFFSET value is correct.
+       * sysdeps/unix/sysv/linux/i386/dl-sysdep.h: New file.
+
+2002-12-18  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/pthread/flockfile.c (flockfile): Change into weak alias.
+       * sysdeps/unix/sysv/linux/raise.c (gsignal): Add weak alias to raise.
+       * Versions [libc: GLIBC_2.0]: Add pthread_attr_init.
+       [libpthread: GLIBC_2.1]: Remove __pthread_rwlock_init,
+       __pthread_rwlock_destroy, __pthread_rwlock_rdlock,
+       __pthread_rwlock_wrlock, __pthread_rwlock_unlock,
+       __pthread_rwlock_tryrdlock and __pthread_rwlock_trywrlock.
+
+2002-12-18  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h: Use ENTER_KERNEL
+       macro instead of using int $0x80 directly.
+
+       * sysdeps/pthread/bits/stdio-lock.h: New file.
+       * sysdeps/unix/sysv/linux/i386/i486/libc-lowlevelmutex.S: New file.
+       * sysdeps/unix/sysv/linux/i386/i586/libc-lowlevelmutex.S: New file.
+       * sysdeps/unix/sysv/linux/i386/i686/libc-lowlevelmutex.S: New file.
+       * Makefile (routines): Add libc-lowlevelmutex.
+
+       * sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S: Remove
+       __i686.get_pc_thunk.dx.
+
+2002-12-17  Jakub Jelinek  <jakub@redhat.com>
+
+       * Makefile (libpthread-shared-only-routines): Add pt-allocrtsig.
+       (tests): Depend on $(objpfx)tst-cancel-wrappers.out.
+       ($(objpfx)tst-cancel-wrappers.out): New rule.
+       * tst-cancel-wrappers.sh: New test.
+       * tst-locale1.c: Include signal.h.
+       (uselocale): Test static linking of __libc_current_sigrt*.
+
+2002-12-17  Ulrich Drepper  <drepper@redhat.com>
+
+       * Makefile (tests): Add tst-cancel6.
+       * tst-cancel6.c: New file
+
+2002-12-17  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h (SINGLE_THREAD_P):
+       Define meaningfully for assembler as well.
+       * pthreadP.h (struct pthread_functions): Remove
+       ptr_pthread_attr_init field.  Add ptr_pthread_attr_init_2_0
+       and ptr_pthread_attr_init_2_1 fields.
+       * init.c (pthread_functions): Initialize ptr_pthread_attr_init_2_0
+       and ptr_pthread_attr_init_2_1 instead of ptr_pthread_attr_init.
+       * forward.c (FORWARD4): Renamed from FORWARD3. Add export argument.
+       (FORWARD3): Define using FORWARD4.
+       (pthread_attr_init): Provide both @GLIBC_2.0 and @@GLIBC_2.1
+       versions.
+       * pt-system.c: Remove duplicate stdlib.h include.
+
+2002-12-16  Ulrich Drepper  <drepper@redhat.com>
+
+       * sem_init.c: Define sem_init@GLIBC_2.0.
+       * sem_destroy.c: Define sem_destroy@GLIBC_2.0.
+       * sem_getvalue.c: Define sem_getvalue@GLIBC_2.0.
+
+       * flockfile.c: Moved to...
+       * sysdeps/pthread/flockfile.c: ...here.  New file.
+       * funlockfile.c: Moved to...
+       * sysdeps/pthread/funlockfile.c: ...here.  New file.
+       * ftrylockfile.c: Moved to...
+       * sysdeps/pthread/ftrylockfile.c: ...here.  New file.
+
+2002-12-16  Jakub Jelinek  <jakub@redhat.com>
+
+       * libc-cancellation.c: Guard both function with
+       #if !defined NOT_IN_libc.
+       * Makefile (libpthread-routines): Use ptw-, not pt- prefix for the
+       automatically provided pthread wrappers.
+       * pthreadP.h (LIBC_CANCEL_ASYNC, LIBC_CANCEL_RESET): Define to
+       CANCEL_* if IS_IN_libpthread and to dummy versions if not in libc
+       nor in libpthread.
+       * pt-open.c: Removed.
+       * pt-fcntl.c: Removed.
+       * pt-fsync.c: Removed.
+       * pt-lseek.c: Removed.
+       * pt-msgrcv.c: Removed.
+       * pt-msgsnd.c: Removed.
+       * pt-msync.c: Removed.
+       * pt-nanosleep.c: Removed.
+       * pt-open64.c: Removed.
+       * pt-pause.c: Removed.
+       * pt-pread.c: Removed.
+       * pt-pread64.c: Removed.
+       * pt-pwrite.c: Removed.
+       * pt-pwrite64.c: Removed.
+       * pt-read.c: Removed.
+       * pt-recv.c: Removed.
+       * pt-recvfrom.c: Removed.
+       * pt-recvmsg.c: Removed.
+       * pt-send.c: Removed.
+       * pt-sendto.c: Removed.
+       * pt-sigtimedwait.c: Removed.
+       * pt-sigwait.c: Removed.
+       * pt-wait.c: Removed.
+       * pt-waitpid.c: Removed.
+       * pt-write.c: Removed.
+       * pt-accept.c: Removed.
+       * pt-close.c: Removed.
+       * pt-connect.c: Removed.
+       * pt-lseek64.c: Removed.
+       * pt-sendmsg.c: Removed.
+       * pt-tcdrain.c: Removed.
+
+2002-12-15  Ulrich Drepper  <drepper@redhat.com>
+
+       * init.c (__pthread_initialize_minimal_internal): Renamed from
+       __pthread_initialize_minimal.  Make old name an alias.  This
+       converts a normal relocation into a relative relocation.
+
+       * pt-fcntl.c (__fcntl): Use fcntl64 syscall, not fcntl.
+
+       * Versions [libpthread: GLIBC_2.3.2]: Remove creat, poll, pselect,
+       readv, select, sigpause, sigsuspend, sigwaitinfo, waitid, writev.
+       * Makefile (libpthread-routines): Remove pt-creat, pt-poll,
+       pt-pselect, pt-readv, pt-select, pt-sigpause, pt-sigsuspend,
+       pt-sigwaitinfo, pt-waitid, and pt-writev.
+       * pt-creat.c: Removed.
+       * pt-poll.c: Removed.
+       * pt-pselect.c: Removed.
+       * pt-readv.c: Removed.
+       * pt-select.c: Removed.
+       * pt-sigpause.c: Removed.
+       * pt-sigsuspend.c: Removed.
+       * pt-sigwaitinfo.c: Removed.
+       * pt-waitid.c: Removed.
+       * pt-writev.c: Removed.
+
+       * init.c (pthread_functions): New variable.
+       (__pthread_initialize_minimal): Pass pointer to pthread_functions
+       (or NULL) to __libc_pthread_init.
+       * forward.c: Rewrite to use __libc:pthread_functions array to get
+       function addresses.
+       * sysdeps/unix/sysv/linux/fork.h: Remove __libc_pthread_init
+       prototype.
+       * sysdeps/unix/sysv/linux/libc_pthread_init.c (__libc_pthread_init):
+       Take new parameter.  Copy content of variable pointed to by it
+       to __libc_pthread_init.
+
+       * pthreadP.h (struct pthread_functions): New type.
+       (__libc_pthread_init): Declare.
+
+       * pthread_attr_destroy.c: Add namespace protected alias.
+       * pthread_attr_getdetachstate.c: Likewise.
+       * pthread_attr_getinheritsched.c: Likewise.
+       * pthread_attr_getschedparam.c: Likewise.
+       * pthread_attr_getschedpolicy.c: Likewise.
+       * pthread_attr_getscope.c: Likewise.
+       * pthread_attr_setdetachstate.c: Likewise.
+       * pthread_attr_setinheritsched.c: Likewise.
+       * pthread_attr_setschedparam.c: Likewise.
+       * pthread_attr_setschedpolicy.c: Likewise.
+       * pthread_attr_setscope.c: Likewise.
+       * pthread_cond_broadcast.c: Likewise.
+       * pthread_cond_destroy.c: Likewise.
+       * pthread_cond_init.c: Likewise.
+       * pthread_cond_signal.c: Likewise.
+       * pthread_cond_wait.c: Likewise.
+       * pthread_condattr_destroy.c: Likewise.
+       * pthread_condattr_init.c: Likewise.
+       * pthread_equal.c: Likewise.
+       * pthread_exit.c: Likewise.
+       * pthread_getschedparam.c: Likewise.
+       * pthread_self.c: Likewise.
+       * pthread_setcancelstate.c: Likewise.
+       * pthread_setschedparam.c: Likewise.
+       * pthread_mutex_destroy.c: Likewise.
+       * pthread_mutex_init.c: Likewise.
+       * pthreadP.h: Add prototypes for the aliases.
+
+       * sysdeps/unix/sysv/linux/i386/createthread.c (create_thread): Set
+       multiple_threads member in correct TCB to 1.
+
+       * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h: Define
+       SINGLE_THREAD_P.  If in libc or libpthread examine multiple_thread
+       member of thread decriptor, otherwise return unconditionally 1.
+
+2002-12-14  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/pt-socket.S: Changes folded into the
+       regular Linux version.  Remove file.
+       * sysdeps/unix/sysv/linux/connect.S: Likewise.  Remove file.
+       * sysdeps/unix/sysv/linux/llseek.c: Likewise.  Remove file.
+       * sysdeps/unix/sysv/linux/msgrcv.c: Likewise.  Remove file.
+       * sysdeps/unix/sysv/linux/msgsnd.c: Likewise.  Remove file.
+       * sysdeps/unix/sysv/linux/open64.c: Likewise.  Remove file.
+       * sysdeps/unix/sysv/linux/poll.c: Likewise.  Remove file.
+       * sysdeps/unix/sysv/linux/pread.c: Likewise.  Remove file.
+       * sysdeps/unix/sysv/linux/pread64.c: Likewise.  Remove file.
+       * sysdeps/unix/sysv/linux/pselect.c: Likewise.  Remove file.
+       * sysdeps/unix/sysv/linux/pwrite.c: Likewise.  Remove file.
+       * sysdeps/unix/sysv/linux/pwrite64.c: Likewise.  Remove file.
+       * sysdeps/unix/sysv/linux/readv.c: Likewise.  Remove file.
+       * sysdeps/unix/sysv/linux/recv.S: Likewise.  Remove file.
+       * sysdeps/unix/sysv/linux/recvfrom.S: Likewise.  Remove file.
+       * sysdeps/unix/sysv/linux/recvmsg.S: Likewise.  Remove file.
+       * sysdeps/unix/sysv/linux/send.S: Likewise.  Remove file.
+       * sysdeps/unix/sysv/linux/sendmsg.S: Likewise.  Remove file.
+       * sysdeps/unix/sysv/linux/sendto.S: Likewise.  Remove file.
+       * sysdeps/unix/sysv/linux/sigpause.c: Likewise.  Remove file.
+       * sysdeps/unix/sysv/linux/sigsuspend.c: Likewise.  Remove file.
+       * sysdeps/unix/sysv/linux/sigtimedwait.c: Likewise.  Remove file.
+       * sysdeps/unix/sysv/linux/sigwait.c: Likewise.  Remove file.
+       * sysdeps/unix/sysv/linux/sigwaitinfo.c: Likewise.  Remove file.
+       * sysdeps/unix/sysv/linux/system.c: Likewise.  Remove file.
+       * sysdeps/unix/sysv/linux/tcdrain.c: Likewise.  Remove file.
+       * sysdeps/unix/sysv/linux/wait.c: Likewise.  Remove file.
+       * sysdeps/unix/sysv/linux/waitid.c: Likewise.  Remove file.
+       * sysdeps/unix/sysv/linux/waitpid.c: Likewise.  Remove file.
+       * sysdeps/unix/sysv/linux/writev.c: Likewise.  Remove file.
+       * sysdeps/unix/sysv/linux/i386/fcntl.c: Likewise.  Remove file.
+
+2002-12-14  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h: New file.
+       * sysdeps/unix/sysv/linux/open.c: Removed.
+       * sysdeps/unix/sysv/linux/fsync.c: Removed.
+       * sysdeps/unix/sysv/linux/lseek.c: Removed.
+       * sysdeps/unix/sysv/linux/msync.c: Removed.
+       * sysdeps/unix/sysv/linux/read.c: Removed.
+       * sysdeps/unix/sysv/linux/close.c: Removed.
+       * sysdeps/unix/sysv/linux/creat.c: Removed.
+       * sysdeps/unix/sysv/linux/nanosleep.c: Removed.
+       * sysdeps/unix/sysv/linux/pause.c: Removed.
+       * sysdeps/unix/sysv/linux/select.c: Removed.
+       * sysdeps/unix/sysv/linux/write.c: Removed.
+
+2002-12-14  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/pt-socket.S: Check multiple_threads
+       element in TCB to see whether locking is needed.
+
+       * sysdeps/unix/sysv/linux/libc_pthread_init.c: Check that
+       MULTIPLE_THREADS_OFFSET value is correct.
+
+       * sysdeps/unix/sysv/linux/close.c: New file.
+       * sysdeps/unix/sysv/linux/connect.S: New file.
+       * sysdeps/unix/sysv/linux/creat.c: New file.
+       * sysdeps/unix/sysv/linux/fsync.c: New file.
+       * sysdeps/unix/sysv/linux/llseek.c: New file.
+       * sysdeps/unix/sysv/linux/lseek.c: New file.
+       * sysdeps/unix/sysv/linux/msgrcv.c: New file.
+       * sysdeps/unix/sysv/linux/msgsnd.c: New file.
+       * sysdeps/unix/sysv/linux/msync.c: New file.
+       * sysdeps/unix/sysv/linux/nanosleep.c: New file.
+       * sysdeps/unix/sysv/linux/open.c: New file.
+       * sysdeps/unix/sysv/linux/open64.c: New file.
+       * sysdeps/unix/sysv/linux/pause.c: New file.
+       * sysdeps/unix/sysv/linux/poll.c: New file.
+       * sysdeps/unix/sysv/linux/pread.c: New file.
+       * sysdeps/unix/sysv/linux/pread64.c: New file.
+       * sysdeps/unix/sysv/linux/pselect.c: New file.
+       * sysdeps/unix/sysv/linux/pwrite.c: New file.
+       * sysdeps/unix/sysv/linux/pwrite64.c: New file.
+       * sysdeps/unix/sysv/linux/readv.c: New file.
+       * sysdeps/unix/sysv/linux/recv.S: New file.
+       * sysdeps/unix/sysv/linux/recvfrom.S: New file.
+       * sysdeps/unix/sysv/linux/recvmsg.S: New file.
+       * sysdeps/unix/sysv/linux/select.c: New file.
+       * sysdeps/unix/sysv/linux/send.S: New file.
+       * sysdeps/unix/sysv/linux/sendmsg.S: New file.
+       * sysdeps/unix/sysv/linux/sendto.S: New file.
+       * sysdeps/unix/sysv/linux/sigpause.c: New file.
+       * sysdeps/unix/sysv/linux/sigsuspend.c: New file.
+       * sysdeps/unix/sysv/linux/sigtimedwait.c: New file.
+       * sysdeps/unix/sysv/linux/sigwait.c: New file.
+       * sysdeps/unix/sysv/linux/sigwaitinfo.c: New file.
+       * sysdeps/unix/sysv/linux/system.c: New file.
+       * sysdeps/unix/sysv/linux/tcdrain.c: New file.
+       * sysdeps/unix/sysv/linux/wait.c: New file.
+       * sysdeps/unix/sysv/linux/waitid.c: New file.
+       * sysdeps/unix/sysv/linux/waitpid.c: New file.
+       * sysdeps/unix/sysv/linux/writev.c: New file.
+       * sysdeps/unix/sysv/linux/i386/fcntl.c: New file.
+
+       * pt-readv.c: Fix comment.
+
+2002-12-14  Jakub Jelinek  <jakub@redhat.com>
+
+       * tst-cleanup1.c: Include stdlib.h.
+
+       * tst-cancel5.c: New test.
+       * Makefile (tests): Add tst-cancel5.
+       (tst-cancel5): Link against libc.so libpthread.so in that order.
+
+2002-12-13  Ulrich Drepper  <drepper@redhat.com>
+
+       * forward.c (test_loaded): Prevent recursive calls.
+
+       * Makefile (routines): Add libc-cancellation.
+       * libc-cancellation.c: New file.
+       * descr.h (struct pthread): Add multiple_threads field.
+       * allocatestack.c (allocate_stack): Initialize multiple_header field of
+       new thread descriptor to 1.
+       * sysdeps/unix/sysv/linux/i386/createthread.c (create_thread):
+       Initialize multiple_thread field after successful thread creation.
+       * cancellation.c (__do_cancel): Move to pthreadP.h.
+       (__pthread_enable_asynccancel): Remove parameter from __do_cancel call.
+       (__pthread_disable_asynccancel): Add internal_function attribute.
+       * init.c (sigcancel_handler): Remove parameter from __do_cancel call.
+       * pthread_setcancelstate.c: Likewise.
+       * pthread_setcanceltype.c: Likewise.
+       * pthread_exit.c: Likewise.
+       * pthreadP.h (CANCELLATION_P): Likewise.
+       (__do_cancel): Define as static inline.
+       (LIBC_CANCEL_ASYNC, LIBC_CANCEL_RESET): New #defines.
+       (__libc_enable_asynccancel, __libc_disable_asynccancel): New
+       declarations.
+       * sysdeps/i386/tls.h (tcbhead_t): Add list and multiple_threads
+       fields.  Define MULTIPLE_THREADS_OFFSET.
+       * sysdeps/pthread/bits/libc-lock.h: Remove __libc_locking_needed
+       declaration.
+       * sysdeps/unix/sysv/linux/accept.S: New file.
+       * sysdeps/unix/sysv/linux/read.c: New file.
+       * sysdeps/unix/sysv/linux/write.c: New file.
+       * sysdeps/unix/sysv/linux/i386/pt-socket.S: New file.
+       * sysdeps/unix/sysv/linux/libc_pthread_init.c: Remove definition and
+       initialization of __libc_locking_needed.
+       * sysdeps/unix/sysv/linux/i386/lowlevellock.h: Don't use
+       __libc_locking_needed, use multiple_threads field in TCB.
+       * sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S: Likewise.
+
+2002-12-12  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/i686/libc-lowlevellock.S: Use i486
+       version.
+       * sysdeps/unix/sysv/linux/i386/i586/libc-lowlevellock.S: Likewise.
+
+       * sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S: Correct
+       access to __libc_locking_needed for PIC.
+
+2002-12-12  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/pthread/bits/libc-lock.h (__libc_locking_needed): Only
+       declare for libc.so.
+       (__libc_lock_init, __libc_lock_init_recursive): Change into comma
+       expression.
+       (__libc_lock_lock): Put into statement expression.
+       (__libc_lock_unlock): Remove trailing semicolon.
+       * sysdeps/unix/sysv/linux/fork.h (__libc_pthread_init): Fix typo.
+
+2002-12-12  Roland McGrath  <roland@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/lowlevellock.h: Use asm operand with
+       "m" constraint to refer to __libc_locking_needed.  Declare it here.
+
+2002-12-12  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/fork-gen.c: Renamed to...
+       * sysdeps/unix/sysv/linux/libc_pthread_init.c: ...this.
+       Initialize __libc_locking_needed.
+       * init.c (__pthread_initialize_minimal): Call __libc_pthread_init
+       instead of __register_pthread_fork_handler.
+       * sysdeps/pthread/bits/libc-lock.h: Declare __libc_locking_needed.
+       * sysdeps/unix/sysv/linux/Makefile (sysdep_routimes): Replace
+       fork-gen with libc_pthread_init.
+       * sysdeps/unix/sysv/linux/Versions: Use __libc_pthread_init instead
+       of __register_pthread_fork_handler.
+       * sysdeps/unix/sysv/linux/fork.h: Declare __libc_pthread_init instead
+       of __register_pthread_fork_handler.
+       * sysdeps/unix/sysv/linux/i386/lowlevellock.h: Use
+       __libc_locking_needed to determine whether lock prefix can be avoided.
+       * sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S: Likewise.
+
+2002-12-11  Ulrich Drepper  <drepper@redhat.com>
+
+       * Makefile (tests): Add tst-cleanup1.
+       * tst-cleanup1.c: New file.
+       * cancellation.c (__cleanup_thread): Removed.
+       (__do_cancel): Remove call to __cleanup_thread.
+       * pthreadP.h: Remove __cleanup_thread prorotype.
+
+       * sysdeps/pthread/bits/libc-lock.h (__libc_cleanup_region_start):
+       Remember function and argument even if cancellation handler
+       function is not available.
+       (__libc_cleanup_region_end): Execute registered function directly if
+       pthread functions are not available.
+       (__libc_cleanup_end): Likewise.
+
+       * init.c (__pthread_initialize_minimal): Fix initialization in
+       static lib by preventing gcc from being too clever.
+
+2002-12-10  Ulrich Drepper  <drepper@redhat.com>
+
+       * init.c (__pthread_initialize_minimal): Remove unneccesary
+       sigaddset call.
+
+       * Makefile (tests): We can run tst-locale2 now.
+
+2002-12-09  Ulrich Drepper  <drepper@redhat.com>
+
+       * Versions: Remove duplicated sigwait entry.
+
+2002-12-08  Ulrich Drepper  <drepper@redhat.com>
+
+       * pthreadP.h: Enable pthread_cleanup_{push,pop} optimizations only
+       inside libpthread.
+
+       * pt-fcntl.c (__fcntl): Initialize oldtype to avoid warning.
+
+       * pthreadP.h: Declare __pthread_enable_asynccancel and
+       __pthread_disable_asynccancel.
+       (CANCEL_ASYNC): Use __pthread_enable_asynccancel.
+       (CANCEL_RESET): Use __pthread_disable_asynccancel.
+       * cancellation.c (__pthread_enable_asynccancel): New function.
+       (__pthread_disable_asynccancel): New function.
+       * pt-accept.c: Adjust for CANCEL_ASYNC and CANCEL_RESET change.
+       * pt-close.c: Likewise.
+       * pt-connect.c: Likewise.
+       * pt-creat.c: Likewise.
+       * pt-fcntl.c: Likewise.
+       * pt-fsync.c: Likewise.
+       * pt-lseek.c: Likewise.
+       * pt-lseek64.c: Likewise.
+       * pt-msgrcv.c: Likewise.
+       * pt-msgsnd.c: Likewise.
+       * pt-msync.c: Likewise.
+       * pt-nanosleep.c: Likewise.
+       * pt-open.c: Likewise.
+       * pt-open64.c: Likewise.
+       * pt-pause.c: Likewise.
+       * pt-poll.c: Likewise.
+       * pt-pread.c: Likewise.
+       * pt-pread64.c: Likewise.
+       * pt-pselect.c: Likewise.
+       * pt-pwrite.c: Likewise.
+       * pt-pwrite64.c: Likewise.
+       * pt-read.c: Likewise.
+       * pt-readv.c: Likewise.
+       * pt-recv.c: Likewise.
+       * pt-recvfrom.c: Likewise.
+       * pt-recvmsg.c: Likewise.
+       * pt-select.c: Likewise.
+       * pt-send.c: Likewise.
+       * pt-sendmsg.c: Likewise.
+       * pt-sendto.c: Likewise.
+       * pt-sigpause.c: Likewise.
+       * pt-sigsuspend.c: Likewise.
+       * pt-sigtimedwait.c: Likewise.
+       * pt-sigwait.c: Likewise.
+       * pt-sigwaitinfo.c: Likewise.
+       * pt-system.c: Likewise.
+       * pt-tcdrain.c: Likewise.
+       * pt-wait.c: Likewise.
+       * pt-waitid.c: Likewise.
+       * pt-waitpid.c: Likewise.
+       * pt-write.c: Likewise.
+       * pt-writev.c: Likewise.
+       * pthread_join.c: Likewise.
+       * pthread_timedjoin.c: Likewise.
+
+       * pt-sigpause.c (sigsuspend): Call __sigsuspend.
+       (__xpg_sigpause): New function.
+       * Versions (libpthread:GLIBC_2.3.2): Add __xpg_sigpause.
+
+2002-12-07  Ulrich Drepper  <drepper@redhat.com>
+
+       * Makefile (CFLAGS-ftrylockfile.c): Add -D_IO_MTSAFE_IO.
+
+       * cleanup.c: Move declarations of _GI_pthread_cleanup_push and
+       _GI_pthread_cleanup_pop to pthreadP.h.
+
+       * ftrylockfile.c: Use _IO_lock_trylock instead of
+       pthread_mutex_trylock.
+
+       * pthreadP.h (CANCEL_ASYNC): Use __pthread_setcanceltype.
+       (CANCEL_RESET): Likewise.
+       (__pthread_setcanceltype_): Declare.
+       (__pthread_mutex_lock_internal): Declare.
+       (__pthread_mutex_unlock_internal): Declare.
+       (__pthread_once_internal): Declare.
+       (pthread_cleanup_push): Redefine using _GI_pthread_cleanup_push.
+       (pthread_cleanup_pop): Redefine using _GI_pthread_cleanup_pop.
+
+       * pthread_cond_timedwait.c: Use INTUSE is calls to pthread_mutex_lock
+       and pthread_mutex_unlock.
+       * pthread_cond_wait.c: Likewise.
+       * pthread_mutex_lock.c: Use INTDEF to define alias if needed.
+       * pthread_mutex_unlock.c: Likewise.
+
+       * pthread_setcanceltype.c: Add additional alias
+       __pthread_setcanceltype.
+
+       * sem_unlink.c (sem_unlink): Use __pthread_once with INTDEF.
+       * sem_open.c (sem_open): Likewise.
+       Use __libc_open, __libc_write, and __libc_close instead of
+       open, write, and close respectively.
+
+       * sysdeps/pthread/bits/libc-lock.h (__libc_lock_trylock_internal):
+       Rewrite as statement expression since it must return a value.
+
+       * pthread_cancel.c: Use __pthread_kill instead of pthread_kill.
+       * sysdeps/unix/sysv/linux/pthread_kill.c: Define additional alias
+       __pthread_kill.
+
+       * sysdeps/unix/sysv/linux/i386/pthread_once.S: Define additional
+       alias __pthread_once_internal.
+
+       * sysdeps/unix/sysv/linux/raise.c: Use libc_hidden_def for raise.
+
+2002-12-06  Ulrich Drepper  <drepper@redhat.com>
+
+       * Makefile (tests): Add tst-stdio1 and tst-stdio2.
+       * tst-stdio1.c: New file.
+       * tst-stdio2.c: New file.
+
+       * init.c (__pthread_initialize_minimal): Correct INIT_LIST_HEAD use.
+
+       * Makefile (tests): Comment out tst-locale2 for now.
+       (CFLAGS-flockfile.c, CFLAGS-funlockfile.c): Define to -D_IO_MTSAFE_IO.
+
+       * sysdeps/unix/sysv/linux/Makefile: Define CFLAGS-fork.c to
+       -D_IO_MTSAFE_IO.
+       * sysdeps/unix/sysv/linux/fork.c: Include <bits/stdio-lock.h>.
+       Use _IO_lock_init instead of explicit assignment.
+
+       * sysdeps/pthread/bits/libc-lock.h: Define __rtld_lock_* macros.
+       Define __libc_lock_* and __libc_lock_recursive macros with
+       lowlevellock macros, not pthread mutexes.
+
+       * flockfile.c: Include <bits/stdio-lock.h>.  Use _IO_lock_lock instead
+       of pthread_mutex_lock.
+       * funlockfile.c: Include <bits/stdio-lock.h>.  Use _IO_lock_unlock
+       instead of pthread_mutex_unlock.
+
+2002-12-06  Roland McGrath  <roland@redhat.com>
+
+       * allocatestack.c (__stack_user): Use uninitialized defn.
+       * init.c (__pthread_initialize_minimal): Initialize it here.
+
+2002-12-05  Roland McGrath  <roland@redhat.com>
+
+       * sysdeps/i386/tls.h (TLS_INIT_TP): Make it return zero or an error
+       string.
+       * sysdeps/x86_64/tls.h (TLS_INIT_TP): Likewise.
+
+       * sysdeps/unix/sysv/linux/i386/createthread.c (create_thread): Add
+       missing & here too.
+
+2002-12-05  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/Makefile (sysdep_routines): Remove
+       lowlevellock.
+       * sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S: New file.
+       * sysdeps/unix/sysv/linux/i386/i586/libc-lowlevellock.S: New file.
+       * sysdeps/unix/sysv/linux/i386/i686/libc-lowlevellock.S: New file.
+       * sysdeps/pthread/bits/libc-lock.h: Use lowlevellock implementation
+       for __libc_lock_* macros.
+       * Makefile (routines): Add libc-lowlevellock.
+
+2002-10-09  Roland McGrath  <roland@redhat.com>
+
+       * sysdeps/pthread/bits/libc-lock.h (__libc_maybe_call): New macro.
+       Under [__PIC__], call the function via the pointer fetched for
+       comparison rather than a call by name that uses the PLT.
+       (__libc_lock_init, __libc_rwlock_init, __libc_lock_fini)
+       (__libc_rwlock_fini, __libc_lock_lock, __libc_rwlock_rdlock)
+       (__libc_rwlock_wrlock, __libc_lock_trylock, __libc_rwlock_tryrdlock)
+       (__libc_rwlock_trywrlock, __libc_lock_unlock, __libc_rwlock_unlock)
+       (__libc_key_create, __libc_getspecific, __libc_setspecific): Use it.
+
+2002-12-04  Roland McGrath  <roland@redhat.com>
+
+       * forward.c (pthread_self): Use FORWARD3 macro to correct return type.
+
+       * sysdeps/i386/td_ta_map_lwp2thr.c: Moved from ../nptl_db.
+       * sysdeps/generic/td_ta_map_lwp2thr.c: New file.
+
+       * pthread_create.c (start_thread): Add missing & on __nptl_last_event.
+
+2002-12-04  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h: Make pthread_t
+       a completely opaque, non-integer type.
+       * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: Likewise.
+
+2002-12-05  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/i386/tls.h: Include stdlib.h.
+       * sysdeps/x86_64/tls.h: Likewise.
+
+2002-12-04  Ulrich Drepper  <drepper@redhat.com>
+
+       * Makefile (tests): Add tst-locale2.
+       (tests-static): Likewise.
+       * tst-locale2.c: New file.
+
+       * sysdeps/unix/sysv/linux/i386/lowlevellock.h: Mark asms as
+       volatile and add memory clobbers to lock operations.
+
+2002-12-03  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/i386/i686/bits/atomic.h: Use i486 version.
+       * sysdeps/i386/i486/bits/atomic.h: New file.
+       * sysdeps/i386/i586/bits/atomic.h: New file.
+       * sysdeps/i386/i686/pthread_spin_trylock.S: Define HAVE_CMOV and
+       include i486 version.
+       * sysdeps/i386/i486/pthread_spin_trylock.S: New file.
+       * sysdeps/i386/i586/pthread_spin_trylock.S: New file.
+       Patch by Marijn Ros <marijn@mad.scientist.com>.
+
+       * allocatestack.c (get_cached_stack): Don't crash if we first
+       found a stack with a larger size then needed.
+       Reported by Hui Huang <hui.huang@sun.com>.
+
+       * Makefile (tests): Add tst-sysconf.
+       * tst-sysconf.c: New file.
+
+       * sysdeps/unix/sysv/linux/bits/local_lim.h: Undefine
+       PTHREAD_THREADS_MAX.
+
+2002-12-02  Roland McGrath  <roland@redhat.com>
+
+       * pthreadP.h (__stack_user, __nptl_create_event, __nptl_death_event):
+       Declare using hidden_proto instead of attribute_hidden, so there are
+       non-.hidden static symbols for gdb to find.
+       (__pthread_keys): Likewise.
+       * events.c (__nptl_create_event, __nptl_death_event): Add hidden_def.
+       * allocatestack.c (__stack_user): Likewise.
+       * pthread_create.c (__pthread_keys): Likewise.
+       (__nptl_threads_events, __nptl_last_event): Make these static instead
+       of hidden.
+       * pthread_key_create.c (__pthread_pthread_keys_max,
+       __pthread_pthread_key_2ndlevel_size): Renamed from __linuxthreads_*.
+
+2002-12-02  Ulrich Drepper  <drepper@redhat.com>
+
+       * Makefile (tests): Add tst-locale1.  If buid-static is yes link
+       statically.
+       * tst-locale1.c: New file.
+
+       * pthread_cond_timedwait.c: Include <stdlib.h>.
+
+       * Makefile (tests): Add tst-fork2 and tst-fork3.
+       * tst-fork2.c: New file.
+       * tst-fork3.c: New file.
+
+2002-11-28  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/bits/posix_opt.h: New file.
+
+       * sysdeps/unix/sysv/linux/bits/posix_opt.h: Define macros which
+       require it to 200112L.
+
+       * sysdeps/unix/sysv/linux/i386/i486/lowlevelrwlock.S: Use cmov
+       instruction only if HAVE_CMOV is defined.
+       * sysdeps/unix/sysv/linux/i386/i686/lowlevelrwlock.S: Define HAVE_CMOV.
+
+       * sysdeps/unix/sysv/linux/x86_64/bits/semaphore.h: New file.
+
+       * sysdeps/unix/sysv/linux/x86_64/pthread_once.S: New file.
+
+       * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: New file.
+
+       * sysdeps/unix/sysv/linux/x86_64/pt-vfork.S: New file.
+
+2002-11-27  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/x86_64/bits/atomic.h: New file.
+
+       * sysdeps/i386/i686/bits/atomic.h: Fix asm syntax for 8- and
+       16-bit operations.
+
+       * sysdeps/unix/sysv/linux/raise.c (raise): Use INTERNAL_SYSCALL if
+       possible since gettid cannot fail.
+
+       * sysdeps/x86_64/pthreaddef.h: New file.
+
+       * sysdeps/i386/pthreaddef.h (gettid): Removed.
+
+       * sysdeps/x86_64/pthread_spin_init.c: New file.
+       * sysdeps/x86_64/pthread_spin_lock.c: New file.
+       * sysdeps/x86_64/pthread_spin_trylock.c: New file.
+       * sysdeps/x86_64/pthread_spin_unlock.c: New file.
+
+       * sysdeps/i386/i686/pthread_spin_trylock.S (pthread_spin_trylock):
+       Add missing lock prefix.  Minute optimization.
+
+       * tst-spin2.c (main): Also check successful trylock call.
+
+       * sysdeps/pthread/pthread_sigmask.c (pthread_sigmask): Use correct
+       syscall.  Fix typo in case INTERNAL_SYSCALL is not used.
+
+       * sysdeps/i386/pthread_spin_destroy.c: Moved to...
+       * sysdeps/pthread/pthread_spin_destroy.c: ...here.  New file.
+
+       * sysdeps/i386/pthread_sigmask.c: Removed.  Use the generic code.
+       * sysdeps/pthread/pthread_sigmask.c (pthread_sigmask): Return correct
+       value in case of an error.  Add support for INTERNAL_SYSCALL.
+
+       * sysdeps/i386/pthread_sigmask.c (pthread_sigmask): Return correct
+       value in case of an error.
+
+       * sysdeps/x86_64/tls.h: New file.
+
+2002-11-26  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/i386/tls.h (THREAD_GETMEM_NC): Change interface.  It now
+       takes the array member name and the index as parameters.
+       (THREAD_SETMEM_NC): Likewise.
+       * pthread_getspecific.c: Use new THREAD_GETMEM_NC interface.
+       * pthread_setspecific.c: Use new THREAD_GETMEM_NC and THREAD_SETMEM_NC
+       interfaces.
+
+       * sysdeps/i386/tls.h (THREAD_SETMEM): Use size of member element
+       to decide which code to use.
+       (THREAD_SETMEM_NC): Likewise.
+
+       * allocatestack.c (queue_stack): Don't remove stack from list here.
+       Do it in the caller.  Correct condition to prematurely terminate
+       loop to free stacks.
+       (__deallocate_stack): Remove stack from list here.
+
+2002-11-26  Ulrich Drepper  <drepper@redhat.com>
+
+       * Makefile (tests): Add tst-stack1.
+       * tst-stack1.c: New file.
+
+       * allocatestack.c (allocate_stack): Initialize the TCB on a user
+       provided stack.
+
+       * pthread_attr_getstack.c: Return bottom of the thread area.
+
+2002-11-25  Ulrich Drepper  <drepper@redhat.com>
+
+       * Makefile (libpthread-routines): Add pt-allocrtsig and
+       pthread_kill_other_threads.
+       * pt-allocrtsig.c: New file.
+       * pthread_kill_other_threads.c: New file.
+       * sysdeps/unix/sysv/linux/allocrtsig.c: Add additional aliases for
+       all three functions.
+       * sysdeps/unix/sysv/linux/Makefile (sysdep_routines): Remove
+       allocrtsig.
+       * sysdeps/unix/sysv/linux/Versions (libc:GLIBC_PRIVATE): Export
+       __libc_current_sigrtmin_private, __libc_current_sigrtmax_private,
+       and __libc_allocate_rtsig_private.
+       * Versions (libpthread): Export pthread_kill_other_threads_np,
+       __libc_current_sigrtmin, and __libc_current_sigrtmax.
+
+2002-11-24  Ulrich Drepper  <drepper@redhat.com>
+
+       * allocatestack.c (allocate_stack): stackaddr in attribute points to
+       the end of the stack.  Adjust computations.
+       When mprotect call fails dequeue stack and free it.
+       * pthread_attr_setstack.c: Store top of the stack in stackaddr
+       attribute.
+       * pthread_getattr_np.c: Likewise.
+
+       * descr.h (IS_DETACHED): Add some more parenthesis to prevent
+       surprises.
+
+2002-11-23  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/pthread.h (pthread_self): __THROW must come before
+       attribute definitions.  Patch by Luca Barbieri <ldb@ldb.ods.org>.
+
+2002-11-22  Ulrich Drepper  <drepper@redhat.com>
+
+       * pthread_getspecific.c: Optimize access to first 2nd-level array.
+       * pthread_setspecific.c: Likewise.
+
+2002-11-21  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/createthread.c: Remove CLONE_ flags
+       definitions.  Get them from the official place.
+       * sysdeps/unix/sysv/linux/i386/fork.c: Likewise.
+
+       * sysdeps/unix/sysv/linux/i386/createthread.c: Update CLONE_* flags.
+       Use new CLONE_ flags in clone() calls.
+
+       * sysdeps/unix/sysv/linux/fork.c: Use ARCH_FORK to actually fork.
+       * sysdeps/unix/sysv/linux/i386/fork.c: New file.
+
+       * Versions: Add pthread_* functions for libc.
+       * forward.c: New file.
+
+       * sysdeps/pthread/Makefile (libpthread-sysdeps_routines): Add
+       errno-loc.
+       * herrno.c: New file.
+       * res.c: New file.
+
+       * Makefile (libpthread-routines): Remove sem_post, sem_wait,
+       sem_trywait, and sem_timedwait.  Add herrno and res.
+       * sem_init.c: Don't initialize lock and waiters members.
+       * sem_open.c: Likewise.
+       * sem_post.c: Removed.
+       * sem_wait.c: Removed.
+       * sem_trywait.c: Removed.
+       * sem_timedwait.c: Removed.
+       * sysdeps/unix/sysv/linux/i386/i486/lowlevelsem.S: Complete rewrite.
+       Includes full implementations of sem_post, sem_wait, sem_trywait,
+       and sem_timedwait.
+       * sysdeps/unix/sysv/linux/i386/lowlevelsem.h (lll_sem_post): Adjust
+       for new implementation.
+       * sysdeps/unix/sysv/linux/internaltypes.h (struct sem): Remove lock
+       and waiters fields.
+
+       * tst-sem3.c: Improve error message.
+       * tst-signal3.c: Likewise.
+
+       * init.c (__pthread_initialize_minimal): Use set_tid_address syscall
+       to tell the kernel about the termination futex and to initialize tid
+       member.  Don't initialize main_thread.
+       * descr.h (struct pthread): Remove main_thread member.
+       * cancelllation.c (__do_cancel): Remove code handling main thread.
+       The main thread is not special anymore.
+
+       * allocatestack.c (__reclaim_stacks): Mark stacks as unused.  Add
+       size of the stacks to stack_cache_actsize.
+
+       * pt-readv.c: Add missing "defined".
+       * pt-sigwait.c: Likewise.
+       * pt-writev.c: Likewise.
+
+2002-11-09  Ulrich Drepper  <drepper@redhat.com>
+
+       * Versions: Export __connect from libpthread.
+       Patch by Luca Barbieri <ldb@ldb.ods.org>.
+
+       * Makefile (libpthread-routines): Add pt-raise.
+       * sysdeps/unix/sysv/linux/raise.c: New file.
+       * sysdeps/unix/sysv/linux/pt-raise.c: New file.
+       * sysdeps/generic/pt-raise.c: New file.
+
+       * pthread_cond_init.c: Initialize all data elements of the condvar
+       structure.  Patch by Luca Barbieri <ldb@ldb.ods.org>.
+
+       * pthread_attr_init.c: Actually implement 2.0 compatibility version.
+       * pthread_create.c: Likewise.
+
+       * Makefile (tests): Add tst-key1, tst-key2, tst-key3.
+       * tst-key1.c: New file.
+       * tst-key2.c: New file.
+       * tst-key3.c: New file.
+
+       * Versions: Export pthread_detach for version GLIBC_2.0.
+       Reported by Saurabh Desai <sdesai@austin.ibm.com>.
+
+2002-11-08  Ulrich Drepper  <drepper@redhat.com>
+
+       * pthread_key_create.c: Terminate search after an unused key was found.
+       Patch by Luca Barbieri <ldb@ldb.ods.org>.
+
+       * sysdeps/unix/sysv/linux/i386/pthread_once.S: Return zero.
+       Patch by Luca Barbieri <ldb@ldb.ods.org>.
+
+2002-10-10  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/i486/lowlevelsem.S: Use slow generic
+       dynamic lookup for errno in PIC.
+
+       * allocatestack.c (get_cached_stack): Rearrange code slightly to
+       release the stack lock as soon as possible.
+       Call _dl_allocate_tls_init for TCB from the cache to re-initialize
+       the static TLS block.
+       (allocate_stack): Call _dl_allocate_tls_init for user-provided stack.
+
+       * cancellation.c: Renamed from cancelation.c.
+       * Makefile: Adjust accordingly.
+       * pthreadP.h (CANCELLATION_P): Renamed from CANCELATION_P.
+       * cleanup_defer.c: Use CANCELLATION_P.
+       * pthread_testcancel.c: Likewise.
+       * descr.h: Fix spelling in comments.
+       * init.c: Likewise.
+       * pthread_getattr_np.c: Likewise.
+       * pthread_getschedparam.c: Likewise.
+       * pthread_setschedparam.c: Likewise.
+       * Versions: Likewise.
+
+       * pt-pselect.c: New file.
+       * Makefile (libpthread-routines): Add pt-pselect.
+       * Versions: Add pselect.
+
+       * tst-cancel4.c: New file.
+       * Makefile (tests): Add tst-cancel4.
+
+2002-10-09  Ulrich Drepper  <drepper@redhat.com>
+
+       * pthread_mutex_lock.c: Always record lock ownership.
+       * pthread_mutex_timedlock.c: Likewise.
+       * pthread_mutex_trylock.c: Likewise.
+
+       * pt-readv.c: New file.
+       * pt-writev.c: New file.
+       * pt-creat.c: New file.
+       * pt-msgrcv.c: New file.
+       * pt-msgsnd.c: New file.
+       * pt-poll.c: New file.
+       * pt-select.c: New file.
+       * pt-sigpause.c: New file.
+       * pt-sigsuspend.c: New file.
+       * pt-sigwait.c: New file.
+       * pt-sigwaitinfo.c: New file.
+       * pt-waitid.c: New file.
+       * Makefile (libpthread-routines): Add pt-readv, pt-writev, pt-creat,
+       pt-msgrcv, pt-msgsnd, pt-poll, pt-select, pt-sigpause, pt-sigsuspend,
+       pt-sigwait, pt-sigwaitinfo, and pt-waitid.
+       * Versions: Add all the new functions.
+
+       * tst-exit1.c: New file.
+       * Makefile (tests): Add tst-exit1.
+
+       * sem_timedwait.c: Minor optimization for more optimal fastpath.
+
+2002-10-08  Ulrich Drepper  <drepper@redhat.com>
+
+       * pt-fcntl.c: Only enable asynchronous cancellation for F_SETLKW.
+
+       * pthread_join.c: Enable asynchronous cancellation around lll_wait_tid
+       call.  pthread_join is an official cancellation point.
+       * pthread_timedjoin.c: Likewise.
+
+       * pthread_cond_wait.c: Revert order in which internal lock are dropped
+       and the condvar's mutex are retrieved.
+       * pthread_cond_timedwait.c: Likewise.
+       Reported by dice@saros.East.Sun.COM.
+
+2002-10-07  Ulrich Drepper  <drepper@redhat.com>
+
+       * pthreadP.h: Cut out all type definitions and move them...
+       * sysdeps/unix/sysv/linux/internaltypes.h: ...here.  New file.
+       * pthreadP.h: Include <internaltypes.h>.
+
+       * sysdeps/unix/sysv/linux/i386/lowlevelsem.h (lll_sem_post): Little
+       performance tweaks.
+
+       * sem_trywait.c: Shuffle #includes around to get right order.
+       * sem_timedwait.c: Likewise.
+       * sem_post.c: Likewise.
+       * sem_wait.c: Likewise.
+
+       * nptl 0.3 released.
+
+       * Makefile (tests): Add tst-signal3.
+       * tst-signal3.c: New file.
+
+2002-10-05  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/lowlevelsem.h: Tell the compiler that
+       the asms modify the sem object.
+       (__lll_sem_timedwait): Now takes struct sem* as first parameter.
+
+       * sysdeps/unix/sysv/linux/i386/bits/semaphore.h (sem_t): Don't expose
+       the actual members.
+       * pthreadP.h (struct sem): New type.  Actual semaphore type.
+       * semaphoreP.h: Include pthreadP.h.
+       * sem_getvalue.c: Adjust to sem_t change.
+       * sem_init.c: Likewise.
+       * sem_open.c: Likewise.
+       * sem_post.c: Likewise.
+       * sem_timedwait.c: Likewise.
+       * sem_trywait.c: Likewise.
+       * sem_wait.c: Likewise.
+
+2002-10-04  Ulrich Drepper  <drepper@redhat.com>
+
+       * Makefile (tests): Add tst-basic2, tst-exec1, tst-exec3, tst-exec3.
+       * tst-basic2.c: New file.
+       * tst-exec1.c: New file.
+       * tst-exec2.c: New file.
+       * tst-exec3.c: New file.
+
+       * tst-fork1.c: Remove extra */.
+
+       * nptl 0.2 released.  The API for IA-32 is complete.
diff --git a/libpthread/nptl/DESIGN-barrier.txt b/libpthread/nptl/DESIGN-barrier.txt
new file mode 100644 (file)
index 0000000..23463c6
--- /dev/null
@@ -0,0 +1,44 @@
+Barriers pseudocode
+===================
+
+    int pthread_barrier_wait(barrier_t *barrier);
+
+struct barrier_t {
+
+   unsigned int lock:
+         - internal mutex
+
+   unsigned int left;
+         - current barrier count, # of threads still needed.
+
+   unsigned int init_count;
+         - number of threads needed for the barrier to continue.
+
+   unsigned int curr_event;
+         - generation count
+}
+
+pthread_barrier_wait(barrier_t *barrier)
+{
+  unsigned int event;
+  result = 0;
+
+  lll_lock(barrier->lock);
+  if (!--barrier->left) {
+    barrier->curr_event++;
+    futex_wake(&barrier->curr_event, INT_MAX)
+
+    result = BARRIER_SERIAL_THREAD;
+  } else {
+    event = barrier->curr_event;
+    lll_unlock(barrier->lock);
+    do {
+      futex_wait(&barrier->curr_event, event)
+    } while (event == barrier->curr_event);
+  }
+
+  if (atomic_increment_val (barrier->left) == barrier->init_count)
+    lll_unlock(barrier->lock);
+
+  return result;
+}
diff --git a/libpthread/nptl/DESIGN-condvar.txt b/libpthread/nptl/DESIGN-condvar.txt
new file mode 100644 (file)
index 0000000..4845251
--- /dev/null
@@ -0,0 +1,134 @@
+Conditional Variable pseudocode.
+================================
+
+       int pthread_cond_timedwait (pthread_cond_t *cv, pthread_mutex_t *mutex);
+       int pthread_cond_signal    (pthread_cond_t *cv);
+       int pthread_cond_broadcast (pthread_cond_t *cv);
+
+struct pthread_cond_t {
+
+   unsigned int cond_lock;
+
+         internal mutex
+
+   uint64_t total_seq;
+
+     Total number of threads using the conditional variable.
+
+   uint64_t wakeup_seq;
+
+     sequence number for next wakeup.
+
+   uint64_t woken_seq;
+
+     sequence number of last woken thread.
+
+   uint32_t broadcast_seq;
+
+}
+
+
+struct cv_data {
+
+   pthread_cond_t *cv;
+
+   uint32_t bc_seq
+
+}
+
+
+
+cleanup_handler(cv_data)
+{
+  cv = cv_data->cv;
+  lll_lock(cv->lock);
+
+  if (cv_data->bc_seq == cv->broadcast_seq) {
+    ++cv->wakeup_seq;
+    ++cv->woken_seq;
+  }
+
+  /* make sure no signal gets lost.  */
+  FUTEX_WAKE(cv->wakeup_seq, ALL);
+
+  lll_unlock(cv->lock);
+}
+
+
+cond_timedwait(cv, mutex, timeout):
+{
+   lll_lock(cv->lock);
+   mutex_unlock(mutex);
+
+   cleanup_push
+
+   ++cv->total_seq;
+   val = seq =  cv->wakeup_seq;
+   cv_data.bc = cv->broadcast_seq;
+   cv_data.cv = cv;
+
+   while (1) {
+
+     lll_unlock(cv->lock);
+
+     enable_async(&cv_data);
+
+     ret = FUTEX_WAIT(cv->wakeup_seq, val, timeout);
+
+     restore_async
+
+     lll_lock(cv->lock);
+
+     if (bc != cv->broadcast_seq)
+       goto bc_out;
+
+     val = cv->wakeup_seq;
+
+     if (val != seq && cv->woken_seq != val) {
+       ret = 0;
+       break;
+     }
+
+     if (ret == TIMEDOUT) {
+       ++cv->wakeup_seq;
+       break;
+     }
+   }
+
+   ++cv->woken_seq;
+
+ bc_out:
+   lll_unlock(cv->lock);
+
+   cleanup_pop
+
+   mutex_lock(mutex);
+
+   return ret;
+}
+
+cond_signal(cv)
+{
+   lll_lock(cv->lock);
+
+   if (cv->total_seq > cv->wakeup_seq) {
+     ++cv->wakeup_seq;
+     FUTEX_WAKE(cv->wakeup_seq, 1);
+   }
+
+   lll_unlock(cv->lock);
+}
+
+cond_broadcast(cv)
+{
+   lll_lock(cv->lock);
+
+   if (cv->total_seq > cv->wakeup_seq) {
+     cv->wakeup_seq = cv->total_seq;
+     cv->woken_seq = cv->total_seq;
+     ++cv->broadcast_seq;
+     FUTEX_WAKE(cv->wakeup_seq, ALL);
+   }
+
+   lll_unlock(cv->lock);
+}
diff --git a/libpthread/nptl/DESIGN-rwlock.txt b/libpthread/nptl/DESIGN-rwlock.txt
new file mode 100644 (file)
index 0000000..810d1b8
--- /dev/null
@@ -0,0 +1,113 @@
+Reader Writer Locks pseudocode
+==============================
+
+       pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
+       pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
+       pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
+
+struct pthread_rwlock_t {
+
+   unsigned int lock:
+         - internal mutex
+
+   unsigned int writers_preferred;
+         - locking mode: 0 recursive, readers preferred
+                         1 nonrecursive, writers preferred
+
+   unsigned int readers;
+         - number of read-only references various threads have
+
+   pthread_t writer;
+         - descriptor of the writer or 0
+
+   unsigned int readers_wakeup;
+         - 'all readers should wake up' futex.
+
+   unsigned int writer_wakeup;
+         - 'one writer should wake up' futex.
+
+   unsigned int nr_readers_queued;
+         - number of readers queued up.
+
+   unsigned int nr_writers_queued;
+         - number of writers queued up.
+}
+
+pthread_rwlock_rdlock(pthread_rwlock_t *rwlock)
+{
+  lll_lock(rwlock->lock);
+  for (;;) {
+    if (!rwlock->writer && (!rwlock->nr_writers_queued ||
+                                       !rwlock->writers_preferred))
+        break;
+
+    rwlock->nr_readers_queued++;
+    val = rwlock->readers_wakeup;
+    lll_unlock(rwlock->lock);
+
+    futex_wait(&rwlock->readers_wakeup, val)
+
+    lll_lock(rwlock->lock);
+    rwlock->nr_readers_queued--;
+  }
+  rwlock->readers++;
+  lll_unlock(rwlock->lock);
+}
+
+pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock)
+{
+  int result = EBUSY;
+  lll_lock(rwlock->lock);
+  if (!rwlock->writer && (!rwlock->nr_writers_queued ||
+                                       !rwlock->writers_preferred))
+    rwlock->readers++;
+  lll_unlock(rwlock->lock);
+  return result;
+}
+
+pthread_rwlock_wrlock(pthread_rwlock_t *rwlock)
+{
+  lll_lock(rwlock->lock);
+  for (;;) {
+    if (!rwlock->writer && !rwlock->readers)
+       break;
+
+    rwlock->nr_writers_queued++;
+    val = rwlock->writer_wakeup;
+    lll_unlock(rwlock->lock);
+
+    futex_wait(&rwlock->writer_wakeup, val);
+
+    lll_lock(rwlock->lock);
+    rwlock->nr_writers_queued--;
+  }
+  rwlock->writer = pthread_self();
+  lll_unlock(rwlock->lock);
+}
+
+pthread_rwlock_unlock(pthread_rwlock_t *rwlock)
+{
+  lll_lock(rwlock->lock);
+
+  if (rwlock->writer)
+    rwlock->writer = 0;
+  else
+    rwlock->readers--;
+
+  if (!rwlock->readers) {
+    if (rwlock->nr_writers_queued) {
+      ++rwlock->writer_wakeup;
+      lll_unlock(rwlock->lock);
+      futex_wake(&rwlock->writer_wakeup, 1);
+      return;
+    } else
+      if (rwlock->nr_readers_queued) {
+        ++rwlock->readers_wakeup;
+        lll_unlock(rwlock->lock);
+        futex_wake(&rwlock->readers_wakeup, MAX_INT);
+        return;
+      }
+  }
+
+  lll_unlock(rwlock->lock);
+}
diff --git a/libpthread/nptl/DESIGN-sem.txt b/libpthread/nptl/DESIGN-sem.txt
new file mode 100644 (file)
index 0000000..17eb0c1
--- /dev/null
@@ -0,0 +1,46 @@
+Semaphores pseudocode
+==============================
+
+       int sem_wait(sem_t * sem);
+       int sem_trywait(sem_t * sem);
+       int sem_post(sem_t * sem);
+       int sem_getvalue(sem_t * sem, int * sval);
+
+struct sem_t {
+
+   unsigned int count;
+         - current semaphore count, also used as a futex
+}
+
+sem_wait(sem_t *sem)
+{
+  for (;;) {
+
+    if (atomic_decrement_if_positive(sem->count))
+      break;
+
+    futex_wait(&sem->count, 0)
+  }
+}
+
+sem_post(sem_t *sem)
+{
+  n = atomic_increment(sem->count);
+  // Pass the new value of sem->count
+  futex_wake(&sem->count, n + 1);
+}
+
+sem_trywait(sem_t *sem)
+{
+  if (atomic_decrement_if_positive(sem->count)) {
+    return 0;
+  } else {
+    return EAGAIN;
+  }
+}
+
+sem_getvalue(sem_t *sem, int *sval)
+{
+  *sval = sem->count;
+  read_barrier();
+}
diff --git a/libpthread/nptl/Makefile b/libpthread/nptl/Makefile
new file mode 100644 (file)
index 0000000..f910021
--- /dev/null
@@ -0,0 +1,13 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000-2005 Erik Andersen <andersen@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+top_srcdir=../../
+top_builddir=../../
+include $(top_builddir)Rules.mak
+all: libs
+include Makefile.in
+include $(top_srcdir)Makerules
diff --git a/libpthread/nptl/Makefile.in b/libpthread/nptl/Makefile.in
new file mode 100644 (file)
index 0000000..d9f2d23
--- /dev/null
@@ -0,0 +1,341 @@
+# Makefile for uClibc NPTL
+#
+# Copyright (C) 2005-2006 Steven J. Hill <sjhill@realitydiluted.com>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+subdirs += libpthread/nptl/sysdeps/$(TARGET_ARCH) \
+       libpthread/nptl/sysdeps/unix/sysv/linux \
+       libpthread/nptl/sysdeps/pthread
+
+libpthread-routines = init vars events version \
+                     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_setschedprio \
+                     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_mutex_consistent \
+                     pthread_mutexattr_init pthread_mutexattr_destroy \
+                     pthread_mutexattr_getpshared \
+                     pthread_mutexattr_setpshared \
+                     pthread_mutexattr_getrobust \
+                     pthread_mutexattr_setrobust \
+                     pthread_mutexattr_getprotocol \
+                     pthread_mutexattr_setprotocol \
+                     pthread_mutexattr_getprioceiling \
+                     pthread_mutexattr_setprioceiling \
+                     pthread_mutexattr_gettype pthread_mutexattr_settype \
+                     pthread_rwlock_init pthread_rwlock_destroy \
+                     pthread_rwlock_rdlock pthread_rwlock_timedrdlock \
+                     pthread_rwlock_wrlock pthread_rwlock_timedwrlock \
+                     pthread_rwlock_tryrdlock pthread_rwlock_trywrlock \
+                     pthread_rwlock_unlock \
+                     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_condattr_getclock pthread_condattr_setclock \
+                     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 \
+                     pthread_atfork \
+                     pthread_getcpuclockid \
+                     pthread_clock_gettime pthread_clock_settime \
+                     sem_init sem_destroy \
+                     sem_open sem_close sem_unlink \
+                     sem_getvalue \
+                     sem_wait sem_trywait sem_timedwait sem_post \
+                     cleanup cleanup_defer cleanup_compat \
+                     cleanup_defer_compat unwind \
+                     pt-longjmp pt-cleanup\
+                     cancellation \
+                     lowlevellock \
+                     pt-vfork \
+                     ptw-write ptw-read ptw-close ptw-fcntl ptw-accept \
+                     ptw-connect ptw-recv ptw-recvfrom ptw-recvmsg ptw-send \
+                     ptw-sendmsg ptw-sendto ptw-fsync ptw-lseek ptw-llseek \
+                     ptw-msync ptw-nanosleep ptw-open ptw-open64 ptw-pause \
+                     ptw-pread ptw-pread64 ptw-pwrite ptw-pwrite64 \
+                     ptw-tcdrain ptw-wait ptw-waitpid ptw-msgrcv ptw-msgsnd \
+                     ptw-sigwait \
+                     pt-raise pt-system \
+                     flockfile ftrylockfile funlockfile \
+                     sigaction \
+                     herrno res \
+                     pthread_kill_other_threads \
+                     pthread_getaffinity pthread_setaffinity \
+                     pthread_attr_getaffinity pthread_attr_setaffinity \
+                     cleanup_routine unwind-forcedunwind
+
+libpthread-shared-only-routines = version pt-allocrtsig unwind-forcedunwind
+
+CFLAGS-pthread_atfork.c = -DNOT_IN_libc
+
+# Since cancellation handling is in large parts handled using exceptions
+# we have to compile some files with exception handling enabled, some
+# even with asynchronous unwind tables.
+
+# init.c contains sigcancel_handler().
+CFLAGS-init.c = -fexceptions -fasynchronous-unwind-tables
+# The unwind code itself,
+CFLAGS-unwind.c = -fexceptions
+CFLAGS-unwind-forcedunwind.c = -fexceptions -fasynchronous-unwind-tables
+
+# The following three functions must be async-cancel safe.
+CFLAGS-pthread_cancel.c = -fexceptions -fasynchronous-unwind-tables
+CFLAGS-pthread_setcancelstate.c = -fexceptions -fasynchronous-unwind-tables
+CFLAGS-pthread_setcanceltype.c = -fexceptions -fasynchronous-unwind-tables
+
+# These are internal functions which similar functionality as setcancelstate
+# and setcanceltype.
+CFLAGS-cancellation.c = -fasynchronous-unwind-tables
+CFLAGS-libc-cancellation.c = -fasynchronous-unwind-tables
+
+# Calling pthread_exit() must cause the registered cancel handlers to
+# be executed.  Therefore exceptions have to be thrown through this
+# function.
+CFLAGS-pthread_exit.c = -fexceptions
+
+# Among others, __pthread_unwind is forwarded.  This function must handle
+# exceptions.
+CFLAGS-forward.c = -fexceptions
+
+# The following are cancellation points.  Some of the functions can
+# block and therefore temporarily enable asynchronous cancellation.
+# Those must be compiled asynchronous unwind tables.
+CFLAGS-pthread_testcancel.c = -fexceptions
+CFLAGS-pthread_join.c = -fexceptions -fasynchronous-unwind-tables
+CFLAGS-pthread_timedjoin.c = -fexceptions -fasynchronous-unwind-tables
+CFLAGS-pthread_once.c = $(uses-callbacks) -fexceptions \
+                       -fasynchronous-unwind-tables
+CFLAGS-pthread_cond_wait.c = -fexceptions -fasynchronous-unwind-tables
+CFLAGS-pthread_cond_timedwait.c = -fexceptions -fasynchronous-unwind-tables
+CFLAGS-sem_wait.c = -fexceptions -fasynchronous-unwind-tables
+CFLAGS-sem_timedwait.c = -fexceptions -fasynchronous-unwind-tables
+
+# These are the function wrappers we have to duplicate here.
+CFLAGS-fcntl.c = -fexceptions -fasynchronous-unwind-tables
+CFLAGS-lockf.c = -fexceptions
+CFLAGS-pread.c = -fexceptions -fasynchronous-unwind-tables
+CFLAGS-pread64.c = -fexceptions -fasynchronous-unwind-tables
+CFLAGS-pwrite.c = -fexceptions -fasynchronous-unwind-tables
+CFLAGS-pwrite64.c = -fexceptions -fasynchronous-unwind-tables
+CFLAGS-wait.c = -fexceptions -fasynchronous-unwind-tables
+CFLAGS-waitpid.c = -fexceptions -fasynchronous-unwind-tables
+CFLAGS-sigwait.c = -fexceptions -fasynchronous-unwind-tables
+CFLAGS-msgrcv.c = -fexceptions -fasynchronous-unwind-tables
+CFLAGS-msgsnd.c = -fexceptions -fasynchronous-unwind-tables
+CFLAGS-tcdrain.c = -fexceptions -fasynchronous-unwind-tables
+
+CFLAGS-pt-system.c = -fexceptions -I./libc/stdlib
+
+#
+# The rest of this file is uClibc specific.
+#
+CFLAGS-pthread_barrier_init.c = -D_GNU_SOURCE
+CFLAGS-pthread_barrier_destroy.c = -D_GNU_SOURCE
+CFLAGS-pthread_barrierattr_init.c = -D_GNU_SOURCE
+CFLAGS-pthread_barrierattr_destroy.c = -D_GNU_SOURCE
+CFLAGS-pthread_barrierattr_getpshared.c = -D_GNU_SOURCE
+CFLAGS-pthread_barrierattr_setpshared.c = -D_GNU_SOURCE
+CFLAGS-sem_open.c = -D_GNU_SOURCE
+
+CFLAGS-nptl = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 $(SSP_ALL_CFLAGS)
+
+CFLAGS-OMIT-alloca_cutoff.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1
+CFLAGS-OMIT-forward.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1
+CFLAGS-OMIT-libc-lowlevelock.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1
+CFLAGS-OMIT-libc-cancellation.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1
+
+libpthread-os-routines = pthread_yield
+libpthread-misc-routines = pthread_rwlock_rdlock pthread_rwlock_timedrdlock \
+                          pthread_rwlock_wrlock pthread_rwlock_timedwrlock \
+                          pthread_rwlock_unlock pthread_cond_wait \
+                          pthread_cond_timedwait pthread_cond_signal \
+                          pthread_cond_broadcast 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_sigmask \
+                          pthread_kill pthread_once \
+                          pthread_getcpuclockid sem_wait \
+                          sem_trywait sem_timedwait \
+                          sem_post pt-longjmp \
+                          lowlevellock pt-vfork \
+                          ptw-close ptw-read ptw-write \
+                          ptw-fcntl ptw-accept ptw-connect \
+                          ptw-recv ptw-recvfrom ptw-recvmsg \
+                          ptw-send ptw-sendmsg ptw-sendto \
+                          ptw-fsync ptw-lseek ptw-llseek \
+                          ptw-msync ptw-nanosleep ptw-open \
+                          ptw-open64 ptw-pause ptw-pread \
+                          ptw-pread64 ptw-pwrite ptw-pwrite64 \
+                          ptw-tcdrain ptw-wait ptw-waitpid \
+                          ptw-msgrcv ptw-msgsnd ptw-sigwait \
+                          pt-raise flockfile ftrylockfile \
+                          funlockfile sigaction \
+                          pthread_getaffinity \
+                          pthread_setaffinity \
+                          pthread_attr_getaffinity \
+                          pthread_attr_setaffinity \
+                          unwind-forcedunwind
+
+ifeq ($(PTHREADS_DEBUG_SUPPORT),y)
+LDFLAGS-libpthread.so := $(LDFLAGS_NOSTRIP) -Wl,-z,defs
+else
+LDFLAGS-libpthread.so := $(LDFLAGS)
+endif
+
+LDFLAGS-libpthread.so += $(top_builddir)lib/$(UCLIBC_LDSO_NAME)-$(VERSION).so $(top_builddir)lib/libdl-$(VERSION).so
+
+LIBS-libpthread.so := $(LIBS)
+
+ifneq ($(UCLIBC_CTOR_DTOR),y)
+START_FILE-libpthread.so := $(top_builddir)/libpthread/nptl/sysdeps/pthread/crti.o $(SHARED_START_FILES)
+END_FILE-libpthread.so := $(SHARED_END_FILES) $(top_builddir)/libpthread/nptl/sysdeps/pthread/crtn.o
+endif
+
+libpthread_FULL_NAME := libpthread-$(VERSION).so
+
+PTHREAD_DIR := $(top_srcdir)libpthread/nptl
+PTHREAD_OUT := $(top_builddir)libpthread/nptl
+
+libpthread_static_SRC := pthread_atfork
+
+libpthread_a_SRC = $(patsubst %, $(PTHREAD_DIR)/%.c,                   \
+               $(filter-out $(libpthread-os-routines)                  \
+                       $(libpthread-misc-routines)                     \
+                       $(libpthread-shared-only-routines),             \
+               $(libpthread-routines)))
+libpthread_so_SRC = $(patsubst %, $(PTHREAD_DIR)/%.c,                  \
+               $(filter-out $(libpthread-os-routines)                  \
+                       $(libpthread-misc-routines), $(libpthread-routines)))
+
+libc-static-y += $(patsubst %.c, $(PTHREAD_OUT)/%.o, alloca_cutoff.c   \
+       libc-cancellation.c)
+libc-shared-y += $(patsubst %.c, $(PTHREAD_OUT)/%.oS, forward.c                \
+       libc-cancellation.c)
+libpthread-nonshared-y += $(patsubst %,$(PTHREAD_OUT)/%.oS,$(libpthread_static_SRC))
+
+
+ifeq ($(DOPIC),y)
+libpthread-a-y := $(patsubst $(PTHREAD_DIR)/%.c,$(PTHREAD_OUT)/%.os,$(libpthread_a_SRC))
+else
+libpthread-a-y := $(patsubst $(PTHREAD_DIR)/%.c,$(PTHREAD_OUT)/%.o,$(libpthread_a_SRC))
+endif
+
+libpthread-so-y := $(patsubst $(PTHREAD_DIR)/%.c,$(PTHREAD_OUT)/%.oS,$(libpthread_so_SRC))
+libpthread-static-y += $(patsubst $(PTHREAD_DIR)/%.c,$(PTHREAD_OUT)/%.o,$(libpthread_a_SRC) $(libpthread_static_SRC))
+
+objclean-y += libpthread_clean
+headers_clean-y += nptl_headers_clean
+
+-include $(PTHREAD_DIR)/sysdeps/generic/Makefile.in
+-include $(PTHREAD_DIR)/sysdeps/pthread/Makefile.in
+-include $(PTHREAD_DIR)/sysdeps/$(TARGET_ARCH)/Makefile.arch
+-include $(PTHREAD_DIR)/sysdeps/unix/sysv/linux/Makefile.in
+-include $(PTHREAD_DIR)/sysdeps/unix/sysv/linux/$(TARGET_ARCH)/Makefile.arch
+
+lib-a-$(UCLIBC_HAS_THREADS) += $(top_builddir)lib/libpthread.a
+lib-so-$(UCLIBC_HAS_THREADS) += $(top_builddir)lib/libpthread.so
+
+$(top_builddir)lib/libpthread.so: $(PTHREAD_OUT)/libpthread_so.a $(libc.depend) $(libdl.depend) $(top_builddir)lib/libpthread_nonshared.a
+       $(call link.so,$(libpthread_FULL_NAME),$(MAJOR_VERSION))
+       $(Q)$(RM) $@
+       $(Q)cp $(top_srcdir)extra/scripts/format.lds $@
+       $(Q)echo "GROUP ( $(notdir $@).$(MAJOR_VERSION) libpthread_nonshared.a )" >> $@
+
+$(PTHREAD_OUT)/libpthread_so.a: $(libpthread-so-y)
+       $(Q)$(RM) $@
+ifeq ($(PTHREADS_DEBUG_SUPPORT),y)
+       $(do_strip:-x=-X --strip-debug)
+else
+       $(do_strip)
+endif
+       $(do_ar)
+
+$(top_builddir)lib/libpthread.a: $(libpthread-a-y)
+       $(Q)$(INSTALL) -d $(dir $@)
+       $(Q)$(RM) $@
+       $(do_strip)
+       $(do_ar)
+
+#
+# Create 'pthread-errnos.h' header file.
+#
+CFLAGS-pthread-errnos.c = -S
+
+$(PTHREAD_OUT)/pthread-errnos.c: $(PTHREAD_DIR)/pthread-errnos.sym
+       $(do_awk) $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@
+
+$(PTHREAD_OUT)/pthread-errnos.s: $(PTHREAD_OUT)/pthread-errnos.c
+       $(compile.c)
+
+$(PTHREAD_OUT)/pthread-errnos.h: $(PTHREAD_OUT)/pthread-errnos.s
+       $(do_sed) -n "s/^.*@@@name@@@\([^@]*\)@@@value@@@[^0-9Xxa-fA-F-]*\([0-9Xxa-fA-F-][0-9Xxa-fA-F-]*\).*@@@end@@@.*$\/#define \1 \2/p" $< > $@
+
+pregen-headers-$(UCLIBC_HAS_THREADS_NATIVE) += $(PTHREAD_OUT)/pthread-errnos.h
+
+headers-$(UCLIBC_HAS_THREADS_NATIVE) += $(nptl_headers_bootstrap)
+
+$(top_builddir)include/pthread.h:
+       $(do_ln) ../$(PTDIR)/sysdeps/pthread/$(@F) $(top_builddir)$@
+$(top_builddir)include/semaphore.h:
+       $(do_ln) ../$(PTDIR)/$(@F) $(top_builddir)$@
+$(top_builddir)include/bits/semaphore.h: | include/bits
+       $(do_ln) ../../$(PTDIR)/sysdeps/unix/sysv/linux/$(TARGET_ARCH)/bits/$(@F) $(top_builddir)$@
+$(top_builddir)include/bits/pthreadtypes.h: | include/bits
+       $(do_ln) ../../$(PTDIR)/sysdeps/unix/sysv/linux/$(TARGET_ARCH)/bits/$(@F) $(top_builddir)$@
+$(top_builddir)include/bits/libc-lock.h: | include/bits
+       $(do_ln) ../../$(PTDIR)/sysdeps/pthread/bits/$(@F) $(top_builddir)$@
+$(top_builddir)include/bits/stdio-lock.h: | include/bits
+       $(do_ln) ../../$(PTDIR)/sysdeps/pthread/bits/$(@F) $(top_builddir)$@
+
+nptl_headers_bootstrap := $(top_builddir)include/pthread.h \
+               $(top_builddir)include/semaphore.h \
+               $(top_builddir)include/bits/semaphore.h \
+               $(top_builddir)include/bits/pthreadtypes.h \
+               $(top_builddir)include/bits/libc-lock.h \
+               $(top_builddir)include/bits/stdio-lock.h
+
+
+nptl_headers_clean:
+       $(do_rm) $(nptl_headers_bootstrap) \
+             $(addprefix $(PTHREAD_OUT)/pthread-errnos., c h s)
+
+libpthread_clean:
+       $(do_rm) $(addprefix $(PTHREAD_OUT)/*., o os oS a)
diff --git a/libpthread/nptl/README.NPTL b/libpthread/nptl/README.NPTL
new file mode 100644 (file)
index 0000000..7e50984
--- /dev/null
@@ -0,0 +1,307 @@
+The base NPTL code for uClibc is from the glibc project located at
+<http://sourceware.org/glibc/>. The starting version was the HEAD of
+the glibc CVS repository dated 2005-05-06. Important changes from
+glibc will continue to be brought in as necessary until the version
+for uClibc is standing on its own. All of the files were originally
+brought over verbatim with no modifications. Obviously, these will
+undergo any necessary changes needed for integration into uClibc.
+Additionally (or subtractingly), the files and directories below
+were removed and not imported.
+
+-- Steven J. Hill <sjhill@realitydiluted.com> on 2005-05-06
+
+
+nptl/Makeconfig
+nptl/configure
+nptl/shlib-versions
+nptl/sysdeps/generic
+nptl/sysdeps/ia64
+nptl/sysdeps/pthread/Makefile
+nptl/sysdeps/pthread/Subdirs
+nptl/sysdeps/pthread/allocalim.h
+nptl/sysdeps/pthread/configure
+nptl/sysdeps/pthread/configure.in
+nptl/sysdeps/pthread/createthread.c
+nptl/sysdeps/pthread/flockfile.c
+nptl/sysdeps/pthread/ftrylockfile.c
+nptl/sysdeps/pthread/funlockfile.c
+nptl/sysdeps/pthread/librt-cancellation.c
+nptl/sysdeps/pthread/list.h
+nptl/sysdeps/pthread/malloc-machine.h
+nptl/sysdeps/pthread/posix-timer.h
+nptl/sysdeps/pthread/pt-initfini.c
+nptl/sysdeps/pthread/pt-longjmp.c
+nptl/sysdeps/pthread/pthread-functions.h
+nptl/sysdeps/pthread/pthread.h
+nptl/sysdeps/pthread/pthread_barrier_wait.c
+nptl/sysdeps/pthread/pthread_cond_broadcast.c
+nptl/sysdeps/pthread/pthread_cond_signal.c
+nptl/sysdeps/pthread/pthread_cond_timedwait.c
+nptl/sysdeps/pthread/pthread_cond_wait.c
+nptl/sysdeps/pthread/pthread_getcpuclockid.c
+nptl/sysdeps/pthread/pthread_once.c
+nptl/sysdeps/pthread/pthread_rwlock_rdlock.c
+nptl/sysdeps/pthread/pthread_rwlock_timedrdlock.c
+nptl/sysdeps/pthread/pthread_rwlock_timedwrlock.c
+nptl/sysdeps/pthread/pthread_rwlock_unlock.c
+nptl/sysdeps/pthread/pthread_rwlock_wrlock.c
+nptl/sysdeps/pthread/pthread_sigmask.c
+nptl/sysdeps/pthread/pthread_spin_destroy.c
+nptl/sysdeps/pthread/pthread_spin_init.c
+nptl/sysdeps/pthread/pthread_spin_unlock.c
+nptl/sysdeps/pthread/rt-unwind-resume.c
+nptl/sysdeps/pthread/setxid.h
+nptl/sysdeps/pthread/sigaction.c
+nptl/sysdeps/pthread/sigfillset.c
+nptl/sysdeps/pthread/sigprocmask.c
+nptl/sysdeps/pthread/tcb-offsets.h
+nptl/sysdeps/pthread/timer_create.c
+nptl/sysdeps/pthread/timer_delete.c
+nptl/sysdeps/pthread/timer_getoverr.c
+nptl/sysdeps/pthread/timer_gettime.c
+nptl/sysdeps/pthread/timer_routines.c
+nptl/sysdeps/pthread/timer_settime.c
+nptl/sysdeps/pthread/tst-mqueue8x.c
+nptl/sysdeps/pthread/tst-timer.c
+nptl/sysdeps/pthread/unwind-forcedunwind.c
+nptl/sysdeps/pthread/unwind-resume.c
+nptl/sysdeps/s390
+nptl/sysdeps/unix
+nptl/tst-_res1.c
+nptl/tst-_res1mod1.c
+nptl/tst-_res1mod2.c
+nptl/tst-align.c
+nptl/tst-align2.c
+nptl/tst-atfork1.c
+nptl/tst-atfork2.c
+nptl/tst-atfork2mod.c
+nptl/tst-attr1.c
+nptl/tst-attr2.c
+nptl/tst-attr3.c
+nptl/tst-backtrace1.c
+nptl/tst-barrier1.c
+nptl/tst-barrier2.c
+nptl/tst-barrier3.c
+nptl/tst-barrier4.c
+nptl/tst-basic1.c
+nptl/tst-basic2.c
+nptl/tst-basic3.c
+nptl/tst-basic4.c
+nptl/tst-basic5.c
+nptl/tst-basic6.c
+nptl/tst-cancel-wrappers.sh
+nptl/tst-cancel1.c
+nptl/tst-cancel10.c
+nptl/tst-cancel11.c
+nptl/tst-cancel12.c
+nptl/tst-cancel13.c
+nptl/tst-cancel14.c
+nptl/tst-cancel15.c
+nptl/tst-cancel16.c
+nptl/tst-cancel17.c
+nptl/tst-cancel18.c
+nptl/tst-cancel19.c
+nptl/tst-cancel2.c
+nptl/tst-cancel20.c
+nptl/tst-cancel21.c
+nptl/tst-cancel22.c
+nptl/tst-cancel23.c
+nptl/tst-cancel3.c
+nptl/tst-cancel4.c
+nptl/tst-cancel5.c
+nptl/tst-cancel6.c
+nptl/tst-cancel7.c
+nptl/tst-cancel8.c
+nptl/tst-cancel9.c
+nptl/tst-cancelx1.c
+nptl/tst-cancelx10.c
+nptl/tst-cancelx11.c
+nptl/tst-cancelx12.c
+nptl/tst-cancelx13.c
+nptl/tst-cancelx14.c
+nptl/tst-cancelx15.c
+nptl/tst-cancelx16.c
+nptl/tst-cancelx17.c
+nptl/tst-cancelx18.c
+nptl/tst-cancelx2.c
+nptl/tst-cancelx20.c
+nptl/tst-cancelx21.c
+nptl/tst-cancelx3.c
+nptl/tst-cancelx4.c
+nptl/tst-cancelx5.c
+nptl/tst-cancelx6.c
+nptl/tst-cancelx7.c
+nptl/tst-cancelx8.c
+nptl/tst-cancelx9.c
+nptl/tst-cleanup0.c
+nptl/tst-cleanup0.expect
+nptl/tst-cleanup1.c
+nptl/tst-cleanup2.c
+nptl/tst-cleanup3.c
+nptl/tst-cleanup4.c
+nptl/tst-cleanup4aux.c
+nptl/tst-cleanupx0.c
+nptl/tst-cleanupx0.expect
+nptl/tst-cleanupx1.c
+nptl/tst-cleanupx2.c
+nptl/tst-cleanupx3.c
+nptl/tst-cleanupx4.c
+nptl/tst-clock1.c
+nptl/tst-clock2.c
+nptl/tst-cond1.c
+nptl/tst-cond10.c
+nptl/tst-cond11.c
+nptl/tst-cond12.c
+nptl/tst-cond13.c
+nptl/tst-cond14.c
+nptl/tst-cond15.c
+nptl/tst-cond16.c
+nptl/tst-cond17.c
+nptl/tst-cond18.c
+nptl/tst-cond19.c
+nptl/tst-cond2.c
+nptl/tst-cond20.c
+nptl/tst-cond21.c
+nptl/tst-cond3.c
+nptl/tst-cond4.c
+nptl/tst-cond5.c
+nptl/tst-cond6.c
+nptl/tst-cond7.c
+nptl/tst-cond8.c
+nptl/tst-cond9.c
+nptl/tst-context1.c
+nptl/tst-detach1.c
+nptl/tst-dlsym1.c
+nptl/tst-eintr1.c
+nptl/tst-eintr2.c
+nptl/tst-eintr3.c
+nptl/tst-eintr4.c
+nptl/tst-eintr5.c
+nptl/tst-exec1.c
+nptl/tst-exec2.c
+nptl/tst-exec3.c
+nptl/tst-exec4.c
+nptl/tst-execstack-mod.c
+nptl/tst-execstack.c
+nptl/tst-exit1.c
+nptl/tst-exit2.c
+nptl/tst-exit3.c
+nptl/tst-fini1.c
+nptl/tst-fini1mod.c
+nptl/tst-flock1.c
+nptl/tst-flock2.c
+nptl/tst-fork1.c
+nptl/tst-fork2.c
+nptl/tst-fork3.c
+nptl/tst-fork4.c
+nptl/tst-getpid1.c
+nptl/tst-getpid2.c
+nptl/tst-join1.c
+nptl/tst-join2.c
+nptl/tst-join3.c
+nptl/tst-join4.c
+nptl/tst-join5.c
+nptl/tst-key1.c
+nptl/tst-key2.c
+nptl/tst-key3.c
+nptl/tst-key4.c
+nptl/tst-kill1.c
+nptl/tst-kill2.c
+nptl/tst-kill3.c
+nptl/tst-kill4.c
+nptl/tst-kill5.c
+nptl/tst-kill6.c
+nptl/tst-locale1.c
+nptl/tst-locale2.c
+nptl/tst-mutex1.c
+nptl/tst-mutex2.c
+nptl/tst-mutex3.c
+nptl/tst-mutex4.c
+nptl/tst-mutex5.c
+nptl/tst-mutex5a.c
+nptl/tst-mutex6.c
+nptl/tst-mutex7.c
+nptl/tst-mutex7a.c
+nptl/tst-mutex8.c
+nptl/tst-mutex9.c
+nptl/tst-oddstacklimit.c
+nptl/tst-once1.c
+nptl/tst-once2.c
+nptl/tst-once3.c
+nptl/tst-once4.c
+nptl/tst-oncex3.c
+nptl/tst-oncex4.c
+nptl/tst-popen1.c
+nptl/tst-raise1.c
+nptl/tst-rwlock1.c
+nptl/tst-rwlock10.c
+nptl/tst-rwlock11.c
+nptl/tst-rwlock12.c
+nptl/tst-rwlock13.c
+nptl/tst-rwlock14.c
+nptl/tst-rwlock2.c
+nptl/tst-rwlock3.c
+nptl/tst-rwlock4.c
+nptl/tst-rwlock5.c
+nptl/tst-rwlock6.c
+nptl/tst-rwlock7.c
+nptl/tst-rwlock8.c
+nptl/tst-rwlock9.c
+nptl/tst-sched1.c
+nptl/tst-sem1.c
+nptl/tst-sem2.c
+nptl/tst-sem3.c
+nptl/tst-sem4.c
+nptl/tst-sem5.c
+nptl/tst-sem6.c
+nptl/tst-sem7.c
+nptl/tst-sem8.c
+nptl/tst-sem9.c
+nptl/tst-setuid1-static.c
+nptl/tst-setuid1.c
+nptl/tst-signal1.c
+nptl/tst-signal2.c
+nptl/tst-signal3.c
+nptl/tst-signal4.c
+nptl/tst-signal5.c
+nptl/tst-signal6.c
+nptl/tst-spin1.c
+nptl/tst-spin2.c
+nptl/tst-spin3.c
+nptl/tst-stack1.c
+nptl/tst-stack2.c
+nptl/tst-stack3.c
+nptl/tst-stdio1.c
+nptl/tst-stdio2.c
+nptl/tst-sysconf.c
+nptl/tst-tls1.c
+nptl/tst-tls2.c
+nptl/tst-tls3.c
+nptl/tst-tls3mod.c
+nptl/tst-tls4.c
+nptl/tst-tls4moda.c
+nptl/tst-tls4modb.c
+nptl/tst-tls5.c
+nptl/tst-tls5.h
+nptl/tst-tls5mod.c
+nptl/tst-tls5moda.c
+nptl/tst-tls5modb.c
+nptl/tst-tls5modc.c
+nptl/tst-tls5modd.c
+nptl/tst-tls5mode.c
+nptl/tst-tls5modf.c
+nptl/tst-tls6.sh
+nptl/tst-tsd1.c
+nptl/tst-tsd2.c
+nptl/tst-tsd3.c
+nptl/tst-tsd4.c
+nptl/tst-tsd5.c
+nptl/tst-umask1.c
+nptl/tst-unload.c
+nptl/tst-vfork1.c
+nptl/tst-vfork1x.c
+nptl/tst-vfork2.c
+nptl/tst-vfork2x.c
+nptl/version.c
+nptl_db/ChangeLog
+nptl_db/shlib-versions
diff --git a/libpthread/nptl/TODO b/libpthread/nptl/TODO
new file mode 100644 (file)
index 0000000..70b8fe4
--- /dev/null
@@ -0,0 +1,31 @@
+- 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
+
+- for adaptive mutexes: when releasing, determine whether somebody spins.
+If yes, for a short time release lock.  If someone else locks no wakeup
+syscall needed.
+
+
+
+- test with threaded process terminating and semadj (?) being applied
+  only after all threads are gone
+
+
+
+- semaphore changes:
+
+  - sem_post should only wake one thread and only when the state of
+    the semaphore changed from 0 to 1
+
+    this also requires that sem_wait and sem_timedwait don't drop the
+    post if they get canceled.
+
+  - possibly add counter field.  This requires reviving the
+    differences between old and new semaphose funtions.  The old ones
+    stay as they are now.  The new once can use an additional field
+    wich is the counter for the number of waiters
diff --git a/libpthread/nptl/TODO-kernel b/libpthread/nptl/TODO-kernel
new file mode 100644 (file)
index 0000000..ad6d2a4
--- /dev/null
@@ -0,0 +1,20 @@
+- setuid/setgid must effect process
+  + test syscalls (getuid) afterwards
+  + test core file content
+
+  + use UID/GID in access(2), chmod(2), chown(2), link(2)
+
+- nice level is process property
+
+- rlimit should be process-wide and SIGXCPU should be sent if all threads
+  together exceed the limit
+
+- getrusage() must return resource utilization for the process
+
+
+
+The following are possible optimizations and in no way required:
+
+
+- the scheduler should be thread group-aware, i.e., it has to give time to
+  the thread group not proportional to the number of threads.
diff --git a/libpthread/nptl/TODO-testing b/libpthread/nptl/TODO-testing
new file mode 100644 (file)
index 0000000..e076e56
--- /dev/null
@@ -0,0 +1,20 @@
+pthread_attr_setguardsize
+
+  test effectiveness
+
+pthread_attr_[sg]etschedparam
+
+  what to test?
+
+pthread_attr_[sg]etstack
+
+  some more tests needed
+
+pthread_getcpuclockid
+
+  check that value is reset -> rt subdir
+
+pthread_getschedparam
+pthread_setschedparam
+
+  what to test?
diff --git a/libpthread/nptl/alloca_cutoff.c b/libpthread/nptl/alloca_cutoff.c
new file mode 100644 (file)
index 0000000..ba26ceb
--- /dev/null
@@ -0,0 +1,36 @@
+/* Determine whether block of given size can be allocated on the stack or not.
+   Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <alloca.h>
+#include <stdlib.h>
+#include <sys/param.h>
+#include <pthreadP.h>
+
+
+int
+__libc_alloca_cutoff (size_t size)
+{
+  return size <= (MIN (__MAX_ALLOCA_CUTOFF,
+                      THREAD_GETMEM (THREAD_SELF, stackblock_size) / 4
+                      /* The main thread, before the thread library is
+                         initialized, has zero in the stackblock_size
+                         element.  Since it is the main thread we can
+                         assume the maximum available stack space.  */
+                      ?: __MAX_ALLOCA_CUTOFF * 4));
+}
diff --git a/libpthread/nptl/allocatestack.c b/libpthread/nptl/allocatestack.c
new file mode 100644 (file)
index 0000000..7d4f9fd
--- /dev/null
@@ -0,0 +1,1216 @@
+/* Copyright (C) 2002-2007, 2009 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <assert.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+#include <tls.h>
+#include <lowlevellock.h>
+#include <link.h>
+#include <bits/kernel-features.h>
+
+
+#ifndef NEED_SEPARATE_REGISTER_STACK
+
+/* Most architectures have exactly one stack pointer.  Some have more.  */
+# define STACK_VARIABLES void *stackaddr = NULL
+
+/* How to pass the values to the 'create_thread' function.  */
+# define STACK_VARIABLES_ARGS stackaddr
+
+/* How to declare function which gets there parameters.  */
+# define STACK_VARIABLES_PARMS void *stackaddr
+
+/* How to declare allocate_stack.  */
+# define ALLOCATE_STACK_PARMS void **stack
+
+/* This is how the function is called.  We do it this way to allow
+   other variants of the function to have more parameters.  */
+# define ALLOCATE_STACK(attr, pd) allocate_stack (attr, pd, &stackaddr)
+
+#else
+
+/* We need two stacks.  The kernel will place them but we have to tell
+   the kernel about the size of the reserved address space.  */
+# define STACK_VARIABLES void *stackaddr = NULL; size_t stacksize = 0
+
+/* How to pass the values to the 'create_thread' function.  */
+# define STACK_VARIABLES_ARGS stackaddr, stacksize
+
+/* How to declare function which gets there parameters.  */
+# define STACK_VARIABLES_PARMS void *stackaddr, size_t stacksize
+
+/* How to declare allocate_stack.  */
+# define ALLOCATE_STACK_PARMS void **stack, size_t *stacksize
+
+/* This is how the function is called.  We do it this way to allow
+   other variants of the function to have more parameters.  */
+# define ALLOCATE_STACK(attr, pd) \
+  allocate_stack (attr, pd, &stackaddr, &stacksize)
+
+#endif
+
+
+/* Default alignment of stack.  */
+#ifndef STACK_ALIGN
+# define STACK_ALIGN __alignof__ (long double)
+#endif
+
+/* Default value for minimal stack size after allocating thread
+   descriptor and guard.  */
+#ifndef MINIMAL_REST_STACK
+# define MINIMAL_REST_STACK    4096
+#endif
+
+
+/* Newer kernels have the MAP_STACK flag to indicate a mapping is used for
+   a stack.  Use it when possible.  */
+#ifndef MAP_STACK
+# define MAP_STACK 0
+#endif
+
+/* This yields the pointer that TLS support code calls the thread pointer.  */
+#if defined(TLS_TCB_AT_TP)
+# define TLS_TPADJ(pd) (pd)
+#elif defined(TLS_DTV_AT_TP)
+# define TLS_TPADJ(pd) ((struct pthread *)((char *) (pd) + TLS_PRE_TCB_SIZE))
+#endif
+
+/* Cache handling for not-yet free stacks.  */
+
+/* Maximum size in kB of cache.  */
+static size_t stack_cache_maxsize = 40 * 1024 * 1024; /* 40MiBi by default.  */
+static size_t stack_cache_actsize;
+
+/* Mutex protecting this variable.  */
+static int 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);
+
+/* We need to record what list operations we are going to do so that,
+   in case of an asynchronous interruption due to a fork() call, we
+   can correct for the work.  */
+static uintptr_t in_flight_stack;
+
+/* List of the threads with user provided stacks in use.  No need to
+   initialize this, since it's done in __pthread_initialize_minimal.  */
+list_t __stack_user __attribute__ ((nocommon));
+hidden_data_def (__stack_user)
+
+#if COLORING_INCREMENT != 0
+/* Number of threads created.  */
+static unsigned int nptl_ncreated;
+#endif
+
+
+/* Check whether the stack is still used or not.  */
+#define FREE_P(descr) ((descr)->tid <= 0)
+
+
+static void
+stack_list_del (list_t *elem)
+{
+  in_flight_stack = (uintptr_t) elem;
+
+  atomic_write_barrier ();
+
+  list_del (elem);
+
+  atomic_write_barrier ();
+
+  in_flight_stack = 0;
+}
+
+
+static void
+stack_list_add (list_t *elem, list_t *list)
+{
+  in_flight_stack = (uintptr_t) elem | 1;
+
+  atomic_write_barrier ();
+
+  list_add (elem, list);
+
+  atomic_write_barrier ();
+
+  in_flight_stack = 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, LLL_PRIVATE);
+
+  /* Search the cache for a matching entry.  We search for the
+     smallest stack which has at least the required size.  Note that
+     in normal situations the size of all allocated stacks is the
+     same.  As the very least there are only a few different sizes.
+     Therefore this loop will exit early most of the time with an
+     exact match.  */
+  list_for_each (entry, &stack_cache)
+    {
+      struct pthread *curr;
+
+      curr = list_entry (entry, struct pthread, list);
+      if (FREE_P (curr) && curr->stackblock_size >= size)
+       {
+         if (curr->stackblock_size == size)
+           {
+             result = curr;
+             break;
+           }
+
+         if (result == NULL
+             || result->stackblock_size > curr->stackblock_size)
+           result = curr;
+       }
+    }
+
+  if (__builtin_expect (result == NULL, 0)
+      /* Make sure the size difference is not too excessive.  In that
+        case we do not use the block.  */
+      || __builtin_expect (result->stackblock_size > 4 * size, 0))
+    {
+      /* Release the lock.  */
+      lll_unlock (stack_cache_lock, LLL_PRIVATE);
+
+      return NULL;
+    }
+
+  /* Dequeue the entry.  */
+  stack_list_del (&result->list);
+
+  /* And add to the list of stacks in use.  */
+  stack_list_add (&result->list, &stack_used);
+
+  /* And decrease the cache size.  */
+  stack_cache_actsize -= result->stackblock_size;
+
+  /* Release the lock early.  */
+  lll_unlock (stack_cache_lock, LLL_PRIVATE);
+
+  /* Report size and location of the stack to the caller.  */
+  *sizep = result->stackblock_size;
+  *memp = result->stackblock;
+
+  /* Cancellation handling is back to the default.  */
+  result->cancelhandling = 0;
+  result->cleanup = NULL;
+
+  /* No pending event.  */
+  result->nextevent = NULL;
+
+  /* Clear the DTV.  */
+  dtv_t *dtv = GET_DTV (TLS_TPADJ (result));
+  memset (dtv, '\0', (dtv[-1].counter + 1) * sizeof (dtv_t));
+
+  /* Re-initialize the TLS.  */
+  _dl_allocate_tls_init (TLS_TPADJ (result));
+
+  return result;
+}
+
+
+/* Free stacks until cache size is lower than LIMIT.  */
+void
+__free_stacks (size_t limit)
+{
+  /* We reduce the size of the cache.  Remove the last entries until
+     the size is below the limit.  */
+  list_t *entry;
+  list_t *prev;
+
+  /* Search from the end of the list.  */
+  list_for_each_prev_safe (entry, prev, &stack_cache)
+    {
+      struct pthread *curr;
+
+      curr = list_entry (entry, struct pthread, list);
+      if (FREE_P (curr))
+       {
+         /* Unlink the block.  */
+         stack_list_del (entry);
+
+         /* Account for the freed memory.  */
+         stack_cache_actsize -= curr->stackblock_size;
+
+         /* Free the memory associated with the ELF TLS.  */
+         _dl_deallocate_tls (TLS_TPADJ (curr), false);
+
+         /* Remove this block.  This should never fail.  If it does
+            something is really wrong.  */
+         if (munmap (curr->stackblock, curr->stackblock_size) != 0)
+           abort ();
+
+         /* Maybe we have freed enough.  */
+         if (stack_cache_actsize <= limit)
+           break;
+       }
+    }
+}
+
+
+/* Add a stack frame which is not used anymore to the stack.  Must be
+   called with the cache lock held.  */
+static inline void
+__attribute ((always_inline))
+queue_stack (struct pthread *stack)
+{
+  /* We unconditionally add the stack to the list.  The memory may
+     still be in use but it will not be reused until the kernel marks
+     the stack as not used anymore.  */
+  stack_list_add (&stack->list, &stack_cache);
+
+  stack_cache_actsize += stack->stackblock_size;
+  if (__builtin_expect (stack_cache_actsize > stack_cache_maxsize, 0))
+    __free_stacks (stack_cache_maxsize);
+}
+
+
+static int
+internal_function
+change_stack_perm (struct pthread *pd
+#ifdef NEED_SEPARATE_REGISTER_STACK
+                  , size_t pagemask
+#endif
+                  )
+{
+#ifdef NEED_SEPARATE_REGISTER_STACK
+  void *stack = (pd->stackblock
+                + (((((pd->stackblock_size - pd->guardsize) / 2)
+                     & pagemask) + pd->guardsize) & pagemask));
+  size_t len = pd->stackblock + pd->stackblock_size - stack;
+#elif _STACK_GROWS_DOWN
+  void *stack = pd->stackblock + pd->guardsize;
+  size_t len = pd->stackblock_size - pd->guardsize;
+#elif _STACK_GROWS_UP
+  void *stack = pd->stackblock;
+  size_t len = (uintptr_t) pd - pd->guardsize - (uintptr_t) pd->stackblock;
+#else
+# error "Define either _STACK_GROWS_DOWN or _STACK_GROWS_UP"
+#endif
+  if (mprotect (stack, len, PROT_READ | PROT_WRITE | PROT_EXEC) != 0)
+    return errno;
+
+  return 0;
+}
+
+
+static int
+allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
+               ALLOCATE_STACK_PARMS)
+{
+  struct pthread *pd;
+  size_t size;
+  size_t pagesize_m1 = __getpagesize () - 1;
+  void *stacktop;
+
+  assert (attr != NULL);
+  assert (powerof2 (pagesize_m1 + 1));
+  assert (TCB_ALIGNMENT >= STACK_ALIGN);
+
+  /* Get the stack size from the attribute if it is set.  Otherwise we
+     use the default we determined at start time.  */
+  size = attr->stacksize ?: __default_stacksize;
+
+  /* Get memory for the stack.  */
+  if (__builtin_expect (attr->flags & ATTR_FLAG_STACKADDR, 0))
+    {
+      uintptr_t adj;
+
+      /* If the user also specified the size of the stack make sure it
+        is large enough.  */
+      if (attr->stacksize != 0
+         && attr->stacksize < (__static_tls_size + MINIMAL_REST_STACK))
+       return EINVAL;
+
+      /* Adjust stack size for alignment of the TLS block.  */
+#if defined(TLS_TCB_AT_TP)
+      adj = ((uintptr_t) attr->stackaddr - TLS_TCB_SIZE)
+           & __static_tls_align_m1;
+      assert (size > adj + TLS_TCB_SIZE);
+#elif defined(TLS_DTV_AT_TP)
+      adj = ((uintptr_t) attr->stackaddr - __static_tls_size)
+           & __static_tls_align_m1;
+      assert (size > adj);
+#endif
+
+      /* The user provided some memory.  Let's hope it matches the
+        size...  We do not allocate guard pages if the user provided
+        the stack.  It is the user's responsibility to do this if it
+        is wanted.  */
+#if defined(TLS_TCB_AT_TP)
+      pd = (struct pthread *) ((uintptr_t) attr->stackaddr
+                              - TLS_TCB_SIZE - adj);
+#elif defined(TLS_DTV_AT_TP)
+      pd = (struct pthread *) (((uintptr_t) attr->stackaddr
+                               - __static_tls_size - adj)
+                              - TLS_PRE_TCB_SIZE);
+#endif
+
+      /* The user provided stack memory needs to be cleared.  */
+      memset (pd, '\0', sizeof (struct pthread));
+
+      /* The first TSD block is included in the TCB.  */
+      pd->specific[0] = pd->specific_1stblock;
+
+      /* Remember the stack-related values.  */
+      pd->stackblock = (char *) attr->stackaddr - size;
+      pd->stackblock_size = size;
+
+      /* This is a user-provided stack.  It will not be queued in the
+        stack cache nor will the memory (except the TLS memory) be freed.  */
+      pd->user_stack = true;
+
+      /* This is at least the second thread.  */
+      pd->header.multiple_threads = 1;
+#ifndef TLS_MULTIPLE_THREADS_IN_TCB
+      __pthread_multiple_threads = *__libc_multiple_threads_ptr = 1;
+#endif
+
+#ifndef __ASSUME_PRIVATE_FUTEX
+      /* The thread must know when private futexes are supported.  */
+      pd->header.private_futex = THREAD_GETMEM (THREAD_SELF,
+                                               header.private_futex);
+#endif
+
+#ifdef NEED_DL_SYSINFO
+      /* Copy the sysinfo value from the parent.  */
+      THREAD_SYSINFO(pd) = THREAD_SELF_SYSINFO;
+#endif
+
+      /* The process ID is also the same as that of the caller.  */
+      pd->pid = THREAD_GETMEM (THREAD_SELF, pid);
+
+      /* Allocate the DTV for this thread.  */
+      if (_dl_allocate_tls (TLS_TPADJ (pd)) == NULL)
+       {
+         /* Something went wrong.  */
+         assert (errno == ENOMEM);
+         return EAGAIN;
+       }
+
+
+      /* Prepare to modify global data.  */
+      lll_lock (stack_cache_lock, LLL_PRIVATE);
+
+      /* And add to the list of stacks in use.  */
+      list_add (&pd->list, &__stack_user);
+
+      lll_unlock (stack_cache_lock, LLL_PRIVATE);
+    }
+  else
+    {
+      /* Allocate some anonymous memory.  If possible use the cache.  */
+      size_t guardsize;
+      size_t reqsize;
+      void *mem = 0;
+      const int prot = (PROT_READ | PROT_WRITE);
+
+#if COLORING_INCREMENT != 0
+      /* Add one more page for stack coloring.  Don't do it for stacks
+        with 16 times pagesize or larger.  This might just cause
+        unnecessary misalignment.  */
+      if (size <= 16 * pagesize_m1)
+       size += pagesize_m1 + 1;
+#endif
+
+      /* Adjust the stack size for alignment.  */
+      size &= ~__static_tls_align_m1;
+      assert (size != 0);
+
+      /* Make sure the size of the stack is enough for the guard and
+        eventually the thread descriptor.  */
+      guardsize = (attr->guardsize + pagesize_m1) & ~pagesize_m1;
+      if (__builtin_expect (size < ((guardsize + __static_tls_size
+                                    + MINIMAL_REST_STACK + pagesize_m1)
+                                   & ~pagesize_m1),
+                           0))
+       /* The stack is too small (or the guard too large).  */
+       return EINVAL;
+
+      /* Try to get a stack from the cache.  */
+      reqsize = size;
+      pd = get_cached_stack (&size, &mem);
+      if (pd == NULL)
+       {
+         /* To avoid aliasing effects on a larger scale than pages we
+            adjust the allocated stack size if necessary.  This way
+            allocations directly following each other will not have
+            aliasing problems.  */
+#if MULTI_PAGE_ALIASING != 0
+         if ((size % MULTI_PAGE_ALIASING) == 0)
+           size += pagesize_m1 + 1;
+#endif
+
+         mem = mmap (NULL, size, prot,
+                     MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
+
+         if (__builtin_expect (mem == MAP_FAILED, 0))
+           {
+             if (errno == ENOMEM)
+               __set_errno (EAGAIN);
+
+              return errno;
+           }
+
+         /* SIZE is guaranteed to be greater than zero.
+            So we can never get a null pointer back from mmap.  */
+         assert (mem != NULL);
+
+#if COLORING_INCREMENT != 0
+         /* Atomically increment NCREATED.  */
+         unsigned int ncreated = atomic_increment_val (&nptl_ncreated);
+
+         /* We chose the offset for coloring by incrementing it for
+            every new thread by a fixed amount.  The offset used
+            module the page size.  Even if coloring would be better
+            relative to higher alignment values it makes no sense to
+            do it since the mmap() interface does not allow us to
+            specify any alignment for the returned memory block.  */
+         size_t coloring = (ncreated * COLORING_INCREMENT) & pagesize_m1;
+
+         /* Make sure the coloring offsets does not disturb the alignment
+            of the TCB and static TLS block.  */
+         if (__builtin_expect ((coloring & __static_tls_align_m1) != 0, 0))
+           coloring = (((coloring + __static_tls_align_m1)
+                        & ~(__static_tls_align_m1))
+                       & ~pagesize_m1);
+#else
+         /* Unless specified we do not make any adjustments.  */
+# define coloring 0
+#endif
+
+         /* Place the thread descriptor at the end of the stack.  */
+#if defined(TLS_TCB_AT_TP)
+         pd = (struct pthread *) ((char *) mem + size - coloring) - 1;
+#elif defined(TLS_DTV_AT_TP)
+         pd = (struct pthread *) ((((uintptr_t) mem + size - coloring
+                                   - __static_tls_size)
+                                   & ~__static_tls_align_m1)
+                                  - TLS_PRE_TCB_SIZE);
+#endif
+
+         /* Remember the stack-related values.  */
+         pd->stackblock = mem;
+         pd->stackblock_size = size;
+
+         /* We allocated the first block thread-specific data array.
+            This address will not change for the lifetime of this
+            descriptor.  */
+         pd->specific[0] = pd->specific_1stblock;
+
+         /* This is at least the second thread.  */
+         pd->header.multiple_threads = 1;
+#ifndef TLS_MULTIPLE_THREADS_IN_TCB
+         __pthread_multiple_threads = *__libc_multiple_threads_ptr = 1;
+#endif
+
+#ifndef __ASSUME_PRIVATE_FUTEX
+         /* The thread must know when private futexes are supported.  */
+         pd->header.private_futex = THREAD_GETMEM (THREAD_SELF,
+                                                    header.private_futex);
+#endif
+
+#ifdef NEED_DL_SYSINFO
+         /* Copy the sysinfo value from the parent.  */
+         THREAD_SYSINFO(pd) = THREAD_SELF_SYSINFO;
+#endif
+
+         /* The process ID is also the same as that of the caller.  */
+         pd->pid = THREAD_GETMEM (THREAD_SELF, pid);
+
+         /* Allocate the DTV for this thread.  */
+         if (_dl_allocate_tls (TLS_TPADJ (pd)) == NULL)
+           {
+             /* Something went wrong.  */
+             assert (errno == ENOMEM);
+
+             /* Free the stack memory we just allocated.  */
+             (void) munmap (mem, size);
+
+             return EAGAIN;
+           }
+
+
+         /* Prepare to modify global data.  */
+         lll_lock (stack_cache_lock, LLL_PRIVATE);
+
+         /* And add to the list of stacks in use.  */
+         stack_list_add (&pd->list, &stack_used);
+
+         lll_unlock (stack_cache_lock, LLL_PRIVATE);
+
+
+         /* Note that all of the stack and the thread descriptor is
+            zeroed.  This means we do not have to initialize fields
+            with initial value zero.  This is specifically true for
+            the 'tid' field which is always set back to zero once the
+            stack is not used anymore and for the 'guardsize' field
+            which will be read next.  */
+       }
+
+      /* Create or resize the guard area if necessary.  */
+      if (__builtin_expect (guardsize > pd->guardsize, 0))
+       {
+#ifdef NEED_SEPARATE_REGISTER_STACK
+         char *guard = mem + (((size - guardsize) / 2) & ~pagesize_m1);
+#elif _STACK_GROWS_DOWN
+         char *guard = mem;
+# elif _STACK_GROWS_UP
+         char *guard = (char *) (((uintptr_t) pd - guardsize) & ~pagesize_m1);
+#endif
+         if (mprotect (guard, guardsize, PROT_NONE) != 0)
+           {
+             int err;
+           mprot_error:
+             err = errno;
+
+             lll_lock (stack_cache_lock, LLL_PRIVATE);
+
+             /* Remove the thread from the list.  */
+             stack_list_del (&pd->list);
+
+             lll_unlock (stack_cache_lock, LLL_PRIVATE);
+
+             /* Get rid of the TLS block we allocated.  */
+             _dl_deallocate_tls (TLS_TPADJ (pd), false);
+
+             /* Free the stack memory regardless of whether the size
+                of the cache is over the limit or not.  If this piece
+                of memory caused problems we better do not use it
+                anymore.  Uh, and we ignore possible errors.  There
+                is nothing we could do.  */
+             (void) munmap (mem, size);
+
+             return err;
+           }
+
+         pd->guardsize = guardsize;
+       }
+      else if (__builtin_expect (pd->guardsize - guardsize > size - reqsize,
+                                0))
+       {
+         /* The old guard area is too large.  */
+
+#ifdef NEED_SEPARATE_REGISTER_STACK
+         char *guard = mem + (((size - guardsize) / 2) & ~pagesize_m1);
+         char *oldguard = mem + (((size - pd->guardsize) / 2) & ~pagesize_m1);
+
+         if (oldguard < guard
+             && mprotect (oldguard, guard - oldguard, prot) != 0)
+           goto mprot_error;
+
+         if (mprotect (guard + guardsize,
+                       oldguard + pd->guardsize - guard - guardsize,
+                       prot) != 0)
+           goto mprot_error;
+#elif _STACK_GROWS_DOWN
+         if (mprotect ((char *) mem + guardsize, pd->guardsize - guardsize,
+                       prot) != 0)
+           goto mprot_error;
+#elif _STACK_GROWS_UP
+         if (mprotect ((char *) pd - pd->guardsize,
+                       pd->guardsize - guardsize, prot) != 0)
+           goto mprot_error;
+#endif
+
+         pd->guardsize = guardsize;
+       }
+      /* The pthread_getattr_np() calls need to get passed the size
+        requested in the attribute, regardless of how large the
+        actually used guardsize is.  */
+      pd->reported_guardsize = guardsize;
+    }
+
+  /* Initialize the lock.  We have to do this unconditionally since the
+     stillborn thread could be canceled while the lock is taken.  */
+  pd->lock = LLL_LOCK_INITIALIZER;
+
+  /* The robust mutex lists also need to be initialized
+     unconditionally because the cleanup for the previous stack owner
+     might have happened in the kernel.  */
+  pd->robust_head.futex_offset = (offsetof (pthread_mutex_t, __data.__lock)
+                                 - offsetof (pthread_mutex_t,
+                                             __data.__list.__next));
+  pd->robust_head.list_op_pending = NULL;
+#ifdef __PTHREAD_MUTEX_HAVE_PREV
+  pd->robust_prev = &pd->robust_head;
+#endif
+  pd->robust_head.list = &pd->robust_head;
+
+  /* We place the thread descriptor at the end of the stack.  */
+  *pdp = pd;
+
+#if defined(TLS_TCB_AT_TP)
+  /* The stack begins before the TCB and the static TLS block.  */
+  stacktop = ((char *) (pd + 1) - __static_tls_size);
+#elif defined(TLS_DTV_AT_TP)
+  stacktop = (char *) (pd - 1);
+#endif
+
+#ifdef NEED_SEPARATE_REGISTER_STACK
+  *stack = pd->stackblock;
+  *stacksize = stacktop - *stack;
+#elif _STACK_GROWS_DOWN
+  *stack = stacktop;
+#elif _STACK_GROWS_UP
+  *stack = pd->stackblock;
+  assert (*stack > 0);
+#endif
+
+  return 0;
+}
+
+
+void
+internal_function
+__deallocate_stack (struct pthread *pd)
+{
+  lll_lock (stack_cache_lock, LLL_PRIVATE);
+
+  /* Remove the thread from the list of threads with user defined
+     stacks.  */
+  stack_list_del (&pd->list);
+
+  /* Not much to do.  Just free the mmap()ed memory.  Note that we do
+     not reset the 'used' flag in the 'tid' field.  This is done by
+     the kernel.  If no thread has been created yet this field is
+     still zero.  */
+  if (__builtin_expect (! pd->user_stack, 1))
+    (void) queue_stack (pd);
+  else
+    /* Free the memory associated with the ELF TLS.  */
+    _dl_deallocate_tls (TLS_TPADJ (pd), false);
+
+  lll_unlock (stack_cache_lock, LLL_PRIVATE);
+}
+
+
+int
+internal_function
+__make_stacks_executable (void **stack_endp)
+{
+  /* First the main thread's stack.  */
+  int err = EPERM;
+  if (err != 0)
+    return err;
+
+#ifdef NEED_SEPARATE_REGISTER_STACK
+  const size_t pagemask = ~(__getpagesize () - 1);
+#endif
+
+  lll_lock (stack_cache_lock, LLL_PRIVATE);
+
+  list_t *runp;
+  list_for_each (runp, &stack_used)
+    {
+      err = change_stack_perm (list_entry (runp, struct pthread, list)
+#ifdef NEED_SEPARATE_REGISTER_STACK
+                              , pagemask
+#endif
+                              );
+      if (err != 0)
+       break;
+    }
+
+  /* Also change the permission for the currently unused stacks.  This
+     might be wasted time but better spend it here than adding a check
+     in the fast path.  */
+  if (err == 0)
+    list_for_each (runp, &stack_cache)
+      {
+       err = change_stack_perm (list_entry (runp, struct pthread, list)
+#ifdef NEED_SEPARATE_REGISTER_STACK
+                                , pagemask
+#endif
+                                );
+       if (err != 0)
+         break;
+      }
+
+  lll_unlock (stack_cache_lock, LLL_PRIVATE);
+
+  return err;
+}
+
+
+/* In case of a fork() call the memory allocation in the child will be
+   the same but only one thread is running.  All stacks except that of
+   the one running thread are not used anymore.  We have to recycle
+   them.  */
+void
+__reclaim_stacks (void)
+{
+  struct pthread *self = (struct pthread *) THREAD_SELF;
+
+  /* No locking necessary.  The caller is the only stack in use.  But
+     we have to be aware that we might have interrupted a list
+     operation.  */
+
+  if (in_flight_stack != 0)
+    {
+      bool add_p = in_flight_stack & 1;
+      list_t *elem = (list_t *) (in_flight_stack & ~UINTMAX_C (1));
+
+      if (add_p)
+       {
+         /* We always add at the beginning of the list.  So in this
+            case we only need to check the beginning of these lists.  */
+         int check_list (list_t *l)
+         {
+           if (l->next->prev != l)
+             {
+               assert (l->next->prev == elem);
+
+               elem->next = l->next;
+               elem->prev = l;
+               l->next = elem;
+
+               return 1;
+             }
+
+           return 0;
+         }
+
+         if (check_list (&stack_used) == 0)
+           (void) check_list (&stack_cache);
+       }
+      else
+       {
+         /* We can simply always replay the delete operation.  */
+         elem->next->prev = elem->prev;
+         elem->prev->next = elem->next;
+       }
+    }
+
+  /* Mark all stacks except the still running one as free.  */
+  list_t *runp;
+  list_for_each (runp, &stack_used)
+    {
+      struct pthread *curp = list_entry (runp, struct pthread, list);
+      if (curp != self)
+       {
+         /* This marks the stack as free.  */
+         curp->tid = 0;
+
+         /* The PID field must be initialized for the new process.  */
+         curp->pid = self->pid;
+
+         /* Account for the size of the stack.  */
+         stack_cache_actsize += curp->stackblock_size;
+
+         if (curp->specific_used)
+           {
+             /* Clear the thread-specific data.  */
+             memset (curp->specific_1stblock, '\0',
+                     sizeof (curp->specific_1stblock));
+
+             curp->specific_used = false;
+
+             for (size_t cnt = 1; cnt < PTHREAD_KEY_1STLEVEL_SIZE; ++cnt)
+               if (curp->specific[cnt] != NULL)
+                 {
+                   memset (curp->specific[cnt], '\0',
+                           sizeof (curp->specific_1stblock));
+
+                   /* We have allocated the block which we do not
+                      free here so re-set the bit.  */
+                   curp->specific_used = true;
+                 }
+           }
+       }
+    }
+
+  /* Reset the PIDs in any cached stacks.  */
+  list_for_each (runp, &stack_cache)
+    {
+      struct pthread *curp = list_entry (runp, struct pthread, list);
+      curp->pid = self->pid;
+    }
+
+  /* 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.  */
+  stack_list_del (&self->list);
+
+  /* Re-initialize the lists for all the threads.  */
+  INIT_LIST_HEAD (&stack_used);
+  INIT_LIST_HEAD (&__stack_user);
+
+  if (__builtin_expect (THREAD_GETMEM (self, user_stack), 0))
+    list_add (&self->list, &__stack_user);
+  else
+    list_add (&self->list, &stack_used);
+
+  /* There is one thread running.  */
+  __nptl_nthreads = 1;
+
+  in_flight_stack = 0;
+
+  /* Initialize the lock.  */
+  stack_cache_lock = LLL_LOCK_INITIALIZER;
+}
+
+
+#if HP_TIMING_AVAIL
+# undef __find_thread_by_id
+/* Find a thread given the thread ID.  */
+attribute_hidden
+struct pthread *
+__find_thread_by_id (pid_t tid)
+{
+  struct pthread *result = NULL;
+
+  lll_lock (stack_cache_lock, LLL_PRIVATE);
+
+  /* Iterate over the list with system-allocated threads first.  */
+  list_t *runp;
+  list_for_each (runp, &stack_used)
+    {
+      struct pthread *curp;
+
+      curp = list_entry (runp, struct pthread, list);
+
+      if (curp->tid == tid)
+       {
+         result = curp;
+         goto out;
+       }
+    }
+
+  /* Now the list with threads using user-allocated stacks.  */
+  list_for_each (runp, &__stack_user)
+    {
+      struct pthread *curp;
+
+      curp = list_entry (runp, struct pthread, list);
+
+      if (curp->tid == tid)
+       {
+         result = curp;
+         goto out;
+       }
+    }
+
+ out:
+  lll_unlock (stack_cache_lock, LLL_PRIVATE);
+
+  return result;
+}
+#endif
+
+
+static void
+internal_function
+setxid_mark_thread (struct xid_command *cmdp, struct pthread *t)
+{
+  int ch;
+
+  /* Don't let the thread exit before the setxid handler runs.  */
+  t->setxid_futex = 0;
+
+  do
+    {
+      ch = t->cancelhandling;
+
+      /* If the thread is exiting right now, ignore it.  */
+      if ((ch & EXITING_BITMASK) != 0)
+       return;
+    }
+  while (atomic_compare_and_exchange_bool_acq (&t->cancelhandling,
+                                              ch | SETXID_BITMASK, ch));
+}
+
+
+static void
+internal_function
+setxid_unmark_thread (struct xid_command *cmdp, struct pthread *t)
+{
+  int ch;
+
+  do
+    {
+      ch = t->cancelhandling;
+      if ((ch & SETXID_BITMASK) == 0)
+       return;
+    }
+  while (atomic_compare_and_exchange_bool_acq (&t->cancelhandling,
+                                              ch & ~SETXID_BITMASK, ch));
+
+  /* Release the futex just in case.  */
+  t->setxid_futex = 1;
+  lll_futex_wake (&t->setxid_futex, 1, LLL_PRIVATE);
+}
+
+
+static int
+internal_function
+setxid_signal_thread (struct xid_command *cmdp, struct pthread *t)
+{
+  if ((t->cancelhandling & SETXID_BITMASK) == 0)
+    return 0;
+
+  int val;
+  INTERNAL_SYSCALL_DECL (err);
+#if __ASSUME_TGKILL
+  val = INTERNAL_SYSCALL (tgkill, err, 3, THREAD_GETMEM (THREAD_SELF, pid),
+                         t->tid, SIGSETXID);
+#else
+# ifdef __NR_tgkill
+  val = INTERNAL_SYSCALL (tgkill, err, 3, THREAD_GETMEM (THREAD_SELF, pid),
+                         t->tid, SIGSETXID);
+  if (INTERNAL_SYSCALL_ERROR_P (val, err)
+      && INTERNAL_SYSCALL_ERRNO (val, err) == ENOSYS)
+# endif
+    val = INTERNAL_SYSCALL (tkill, err, 2, t->tid, SIGSETXID);
+#endif
+
+  /* If this failed, it must have had not started yet or else exited.  */
+  if (!INTERNAL_SYSCALL_ERROR_P (val, err))
+    {
+      atomic_increment (&cmdp->cntr);
+      return 1;
+    }
+  else
+    return 0;
+}
+
+
+int
+attribute_hidden
+__nptl_setxid (struct xid_command *cmdp)
+{
+  int signalled;
+  int result;
+  lll_lock (stack_cache_lock, LLL_PRIVATE);
+
+  __xidcmd = cmdp;
+  cmdp->cntr = 0;
+
+  struct pthread *self = THREAD_SELF;
+
+  /* Iterate over the list with system-allocated threads first.  */
+  list_t *runp;
+  list_for_each (runp, &stack_used)
+    {
+      struct pthread *t = list_entry (runp, struct pthread, list);
+      if (t == self)
+       continue;
+
+      setxid_mark_thread (cmdp, t);
+    }
+
+  /* Now the list with threads using user-allocated stacks.  */
+  list_for_each (runp, &__stack_user)
+    {
+      struct pthread *t = list_entry (runp, struct pthread, list);
+      if (t == self)
+       continue;
+
+      setxid_mark_thread (cmdp, t);
+    }
+
+  /* Iterate until we don't succeed in signalling anyone.  That means
+     we have gotten all running threads, and their children will be
+     automatically correct once started.  */
+  do
+    {
+      signalled = 0;
+
+      list_for_each (runp, &stack_used)
+       {
+         struct pthread *t = list_entry (runp, struct pthread, list);
+         if (t == self)
+           continue;
+
+         signalled += setxid_signal_thread (cmdp, t);
+       }
+
+      list_for_each (runp, &__stack_user)
+       {
+         struct pthread *t = list_entry (runp, struct pthread, list);
+         if (t == self)
+           continue;
+
+         signalled += setxid_signal_thread (cmdp, t);
+       }
+
+      int cur = cmdp->cntr;
+      while (cur != 0)
+       {
+         lll_futex_wait (&cmdp->cntr, cur, LLL_PRIVATE);
+         cur = cmdp->cntr;
+       }
+    }
+  while (signalled != 0);
+
+  /* Clean up flags, so that no thread blocks during exit waiting
+     for a signal which will never come.  */
+  list_for_each (runp, &stack_used)
+    {
+      struct pthread *t = list_entry (runp, struct pthread, list);
+      if (t == self)
+       continue;
+
+      setxid_unmark_thread (cmdp, t);
+    }
+
+  list_for_each (runp, &__stack_user)
+    {
+      struct pthread *t = list_entry (runp, struct pthread, list);
+      if (t == self)
+       continue;
+
+      setxid_unmark_thread (cmdp, t);
+    }
+
+  /* This must be last, otherwise the current thread might not have
+     permissions to send SIGSETXID syscall to the other threads.  */
+  INTERNAL_SYSCALL_DECL (err);
+  result = INTERNAL_SYSCALL_NCS (cmdp->syscall_no, err, 3,
+                                cmdp->id[0], cmdp->id[1], cmdp->id[2]);
+  if (INTERNAL_SYSCALL_ERROR_P (result, err))
+    {
+      __set_errno (INTERNAL_SYSCALL_ERRNO (result, err));
+      result = -1;
+    }
+
+  lll_unlock (stack_cache_lock, LLL_PRIVATE);
+  return result;
+}
+
+static inline void __attribute__((always_inline))
+init_one_static_tls (struct pthread *curp, struct link_map *map)
+{
+  dtv_t *dtv = GET_DTV (TLS_TPADJ (curp));
+# if defined(TLS_TCB_AT_TP)
+  void *dest = (char *) curp - map->l_tls_offset;
+# elif defined(TLS_DTV_AT_TP)
+  void *dest = (char *) curp + map->l_tls_offset + TLS_PRE_TCB_SIZE;
+# else
+#  error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
+# endif
+
+  /* Fill in the DTV slot so that a later LD/GD access will find it.  */
+  dtv[map->l_tls_modid].pointer.val = dest;
+  dtv[map->l_tls_modid].pointer.is_static = true;
+
+  /* Initialize the memory.  */
+  memset (mempcpy (dest, map->l_tls_initimage, map->l_tls_initimage_size),
+         '\0', map->l_tls_blocksize - map->l_tls_initimage_size);
+}
+
+void
+attribute_hidden
+__pthread_init_static_tls (struct link_map *map)
+{
+  lll_lock (stack_cache_lock, LLL_PRIVATE);
+
+  /* Iterate over the list with system-allocated threads first.  */
+  list_t *runp;
+  list_for_each (runp, &stack_used)
+    init_one_static_tls (list_entry (runp, struct pthread, list), map);
+
+  /* Now the list with threads using user-allocated stacks.  */
+  list_for_each (runp, &__stack_user)
+    init_one_static_tls (list_entry (runp, struct pthread, list), map);
+
+  lll_unlock (stack_cache_lock, LLL_PRIVATE);
+}
+
+
+void
+attribute_hidden
+__wait_lookup_done (void)
+{
+  lll_lock (stack_cache_lock, LLL_PRIVATE);
+
+  struct pthread *self = THREAD_SELF;
+
+  /* Iterate over the list with system-allocated threads first.  */
+  list_t *runp;
+  list_for_each (runp, &stack_used)
+    {
+      struct pthread *t = list_entry (runp, struct pthread, list);
+      if (t == self || t->header.gscope_flag == THREAD_GSCOPE_FLAG_UNUSED)
+       continue;
+
+      int *const gscope_flagp = &t->header.gscope_flag;
+
+      /* We have to wait until this thread is done with the global
+        scope.  First tell the thread that we are waiting and
+        possibly have to be woken.  */
+      if (atomic_compare_and_exchange_bool_acq (gscope_flagp,
+                                               THREAD_GSCOPE_FLAG_WAIT,
+                                               THREAD_GSCOPE_FLAG_USED))
+       continue;
+
+      do
+       lll_futex_wait (gscope_flagp, THREAD_GSCOPE_FLAG_WAIT, LLL_PRIVATE);
+      while (*gscope_flagp == THREAD_GSCOPE_FLAG_WAIT);
+    }
+
+  /* Now the list with threads using user-allocated stacks.  */
+  list_for_each (runp, &__stack_user)
+    {
+      struct pthread *t = list_entry (runp, struct pthread, list);
+      if (t == self || t->header.gscope_flag == THREAD_GSCOPE_FLAG_UNUSED)
+       continue;
+
+      int *const gscope_flagp = &t->header.gscope_flag;
+
+      /* We have to wait until this thread is done with the global
+        scope.  First tell the thread that we are waiting and
+        possibly have to be woken.  */
+      if (atomic_compare_and_exchange_bool_acq (gscope_flagp,
+                                               THREAD_GSCOPE_FLAG_WAIT,
+                                               THREAD_GSCOPE_FLAG_USED))
+       continue;
+
+      do
+       lll_futex_wait (gscope_flagp, THREAD_GSCOPE_FLAG_WAIT, LLL_PRIVATE);
+      while (*gscope_flagp == THREAD_GSCOPE_FLAG_WAIT);
+    }
+
+  lll_unlock (stack_cache_lock, LLL_PRIVATE);
+}
diff --git a/libpthread/nptl/banner.h b/libpthread/nptl/banner.h
new file mode 100644 (file)
index 0000000..9982f42
--- /dev/null
@@ -0,0 +1 @@
+"Native POSIX Threads Library by Ulrich Drepper et al, uClibc port by Steven Hill\n"
diff --git a/libpthread/nptl/cancellation.c b/libpthread/nptl/cancellation.c
new file mode 100644 (file)
index 0000000..eac7973
--- /dev/null
@@ -0,0 +1,100 @@
+/* Copyright (C) 2002, 2003, 2009 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"
+
+
+/* The next two functions are similar to pthread_setcanceltype() but
+   more specialized for the use in the cancelable functions like write().
+   They do not need to check parameters etc.  */
+int
+attribute_hidden
+__pthread_enable_asynccancel (void)
+{
+  struct pthread *self = THREAD_SELF;
+  int oldval = THREAD_GETMEM (self, cancelhandling);
+
+  while (1)
+    {
+      int newval = oldval | CANCELTYPE_BITMASK;
+
+      if (newval == oldval)
+       break;
+
+      int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, newval,
+                                             oldval);
+      if (__builtin_expect (curval == oldval, 1))
+       {
+         if (CANCEL_ENABLED_AND_CANCELED_AND_ASYNCHRONOUS (newval))
+           {
+             THREAD_SETMEM (self, result, PTHREAD_CANCELED);
+             __do_cancel ();
+           }
+
+         break;
+       }
+
+      /* Prepare the next round.  */
+      oldval = curval;
+    }
+
+  return oldval;
+}
+
+
+void
+internal_function attribute_hidden
+__pthread_disable_asynccancel (int oldtype)
+{
+  /* If asynchronous cancellation was enabled before we do not have
+     anything to do.  */
+  if (oldtype & CANCELTYPE_BITMASK)
+    return;
+
+  struct pthread *self = THREAD_SELF;
+  int newval;
+
+  int oldval = THREAD_GETMEM (self, cancelhandling);
+
+  while (1)
+    {
+      newval = oldval & ~CANCELTYPE_BITMASK;
+
+      int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, newval,
+                                             oldval);
+      if (__builtin_expect (curval == oldval, 1))
+       break;
+
+      /* Prepare the next round.  */
+      oldval = curval;
+    }
+
+  /* We cannot return when we are being canceled.  Upon return the
+     thread might be things which would have to be undone.  The
+     following loop should loop until the cancellation signal is
+     delivered.  */
+  while (__builtin_expect ((newval & (CANCELING_BITMASK | CANCELED_BITMASK))
+                          == CANCELING_BITMASK, 0))
+    {
+      lll_futex_wait (&self->cancelhandling, newval, LLL_PRIVATE);
+      newval = THREAD_GETMEM (self, cancelhandling);
+    }
+}
diff --git a/libpthread/nptl/cleanup.c b/libpthread/nptl/cleanup.c
new file mode 100644 (file)
index 0000000..af828c4
--- /dev/null
@@ -0,0 +1,49 @@
+/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stdlib.h>
+#include "pthreadP.h"
+
+
+void
+__cleanup_fct_attribute
+__pthread_register_cancel (__pthread_unwind_buf_t *buf)
+{
+  struct pthread_unwind_buf *ibuf = (struct pthread_unwind_buf *) buf;
+  struct pthread *self = THREAD_SELF;
+
+  /* Store old info.  */
+  ibuf->priv.data.prev = THREAD_GETMEM (self, cleanup_jmp_buf);
+  ibuf->priv.data.cleanup = THREAD_GETMEM (self, cleanup);
+
+  /* Store the new cleanup handler info.  */
+  THREAD_SETMEM (self, cleanup_jmp_buf, (struct pthread_unwind_buf *) buf);
+}
+hidden_def (__pthread_register_cancel)
+
+
+void
+__cleanup_fct_attribute
+__pthread_unregister_cancel (__pthread_unwind_buf_t *buf)
+{
+  struct pthread_unwind_buf *ibuf = (struct pthread_unwind_buf *) buf;
+
+  THREAD_SETMEM (THREAD_SELF, cleanup_jmp_buf, ibuf->priv.data.prev);
+}
+hidden_def (__pthread_unregister_cancel)
diff --git a/libpthread/nptl/cleanup_compat.c b/libpthread/nptl/cleanup_compat.c
new file mode 100644 (file)
index 0000000..77d714f
--- /dev/null
@@ -0,0 +1,55 @@
+/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stdlib.h>
+#include "pthreadP.h"
+
+
+void
+_pthread_cleanup_push (
+     struct _pthread_cleanup_buffer *buffer,
+     void (*routine) (void *),
+     void *arg)
+{
+  struct pthread *self = THREAD_SELF;
+
+  buffer->__routine = routine;
+  buffer->__arg = arg;
+  buffer->__prev = THREAD_GETMEM (self, cleanup);
+
+  THREAD_SETMEM (self, cleanup, buffer);
+}
+strong_alias (_pthread_cleanup_push, __pthread_cleanup_push)
+
+
+void
+_pthread_cleanup_pop (
+     struct _pthread_cleanup_buffer *buffer,
+     int execute)
+{
+  struct pthread *self __attribute ((unused)) = THREAD_SELF;
+
+  THREAD_SETMEM (self, cleanup, buffer->__prev);
+
+  /* If necessary call the cleanup routine after we removed the
+     current cleanup block from the list.  */
+  if (execute)
+    buffer->__routine (buffer->__arg);
+}
+strong_alias (_pthread_cleanup_pop, __pthread_cleanup_pop)
diff --git a/libpthread/nptl/cleanup_defer.c b/libpthread/nptl/cleanup_defer.c
new file mode 100644 (file)
index 0000000..498d955
--- /dev/null
@@ -0,0 +1,92 @@
+/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stdlib.h>
+#include "pthreadP.h"
+
+
+void
+__cleanup_fct_attribute
+__pthread_register_cancel_defer (__pthread_unwind_buf_t *buf)
+{
+  struct pthread_unwind_buf *ibuf = (struct pthread_unwind_buf *) buf;
+  struct pthread *self = THREAD_SELF;
+
+  /* Store old info.  */
+  ibuf->priv.data.prev = THREAD_GETMEM (self, cleanup_jmp_buf);
+  ibuf->priv.data.cleanup = THREAD_GETMEM (self, cleanup);
+
+  int cancelhandling = THREAD_GETMEM (self, cancelhandling);
+
+  /* Disable asynchronous cancellation for now.  */
+  if (__builtin_expect (cancelhandling & CANCELTYPE_BITMASK, 0))
+    while (1)
+      {
+       int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling,
+                                               cancelhandling
+                                               & ~CANCELTYPE_BITMASK,
+                                               cancelhandling);
+       if (__builtin_expect (curval == cancelhandling, 1))
+         /* Successfully replaced the value.  */
+         break;
+
+       /* Prepare for the next round.  */
+       cancelhandling = curval;
+      }
+
+  ibuf->priv.data.canceltype = (cancelhandling & CANCELTYPE_BITMASK
+                               ? PTHREAD_CANCEL_ASYNCHRONOUS
+                               : PTHREAD_CANCEL_DEFERRED);
+
+  /* Store the new cleanup handler info.  */
+  THREAD_SETMEM (self, cleanup_jmp_buf, (struct pthread_unwind_buf *) buf);
+}
+
+
+void
+__cleanup_fct_attribute
+__pthread_unregister_cancel_restore (__pthread_unwind_buf_t *buf)
+{
+  struct pthread *self = THREAD_SELF;
+  struct pthread_unwind_buf *ibuf = (struct pthread_unwind_buf *) buf;
+
+  THREAD_SETMEM (self, cleanup_jmp_buf, ibuf->priv.data.prev);
+
+  int cancelhandling;
+  if (ibuf->priv.data.canceltype != PTHREAD_CANCEL_DEFERRED
+      && ((cancelhandling = THREAD_GETMEM (self, cancelhandling))
+         & CANCELTYPE_BITMASK) == 0)
+    {
+      while (1)
+       {
+         int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling,
+                                                 cancelhandling
+                                                 | CANCELTYPE_BITMASK,
+                                                 cancelhandling);
+         if (__builtin_expect (curval == cancelhandling, 1))
+           /* Successfully replaced the value.  */
+           break;
+
+         /* Prepare for the next round.  */
+         cancelhandling = curval;
+       }
+
+      CANCELLATION_P (self);
+    }
+}
diff --git a/libpthread/nptl/cleanup_defer_compat.c b/libpthread/nptl/cleanup_defer_compat.c
new file mode 100644 (file)
index 0000000..8fd9b54
--- /dev/null
@@ -0,0 +1,98 @@
+/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+
+
+void
+_pthread_cleanup_push_defer (
+     struct _pthread_cleanup_buffer *buffer,
+     void (*routine) (void *),
+     void *arg)
+{
+  struct pthread *self = THREAD_SELF;
+
+  buffer->__routine = routine;
+  buffer->__arg = arg;
+  buffer->__prev = THREAD_GETMEM (self, cleanup);
+
+  int cancelhandling = THREAD_GETMEM (self, cancelhandling);
+
+  /* Disable asynchronous cancellation for now.  */
+  if (__builtin_expect (cancelhandling & CANCELTYPE_BITMASK, 0))
+    while (1)
+      {
+       int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling,
+                                               cancelhandling
+                                               & ~CANCELTYPE_BITMASK,
+                                               cancelhandling);
+       if (__builtin_expect (curval == cancelhandling, 1))
+         /* Successfully replaced the value.  */
+         break;
+
+       /* Prepare for the next round.  */
+       cancelhandling = curval;
+      }
+
+  buffer->__canceltype = (cancelhandling & CANCELTYPE_BITMASK
+                         ? PTHREAD_CANCEL_ASYNCHRONOUS
+                         : PTHREAD_CANCEL_DEFERRED);
+
+  THREAD_SETMEM (self, cleanup, buffer);
+}
+strong_alias (_pthread_cleanup_push_defer, __pthread_cleanup_push_defer)
+
+
+void
+_pthread_cleanup_pop_restore (
+     struct _pthread_cleanup_buffer *buffer,
+     int execute)
+{
+  struct pthread *self = THREAD_SELF;
+
+  THREAD_SETMEM (self, cleanup, buffer->__prev);
+
+  int cancelhandling;
+  if (__builtin_expect (buffer->__canceltype != PTHREAD_CANCEL_DEFERRED, 0)
+      && ((cancelhandling = THREAD_GETMEM (self, cancelhandling))
+         & CANCELTYPE_BITMASK) == 0)
+    {
+      while (1)
+       {
+         int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling,
+                                                 cancelhandling
+                                                 | CANCELTYPE_BITMASK,
+                                                 cancelhandling);
+         if (__builtin_expect (curval == cancelhandling, 1))
+           /* Successfully replaced the value.  */
+           break;
+
+         /* Prepare for the next round.  */
+         cancelhandling = curval;
+       }
+
+      CANCELLATION_P (self);
+    }
+
+  /* If necessary call the cleanup routine after we removed the
+     current cleanup block from the list.  */
+  if (execute)
+    buffer->__routine (buffer->__arg);
+}
+strong_alias (_pthread_cleanup_pop_restore, __pthread_cleanup_pop_restore)
diff --git a/libpthread/nptl/cleanup_routine.c b/libpthread/nptl/cleanup_routine.c
new file mode 100644 (file)
index 0000000..cbf2318
--- /dev/null
@@ -0,0 +1,28 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+
+
+void
+__pthread_cleanup_routine (struct __pthread_cleanup_frame *f)
+{
+  if (f->__do_it)
+    f->__cancel_routine (f->__cancel_arg);
+}
diff --git a/libpthread/nptl/descr.h b/libpthread/nptl/descr.h
new file mode 100644 (file)
index 0000000..40f552d
--- /dev/null
@@ -0,0 +1,377 @@
+/* Copyright (C) 2002-2006, 2007, 2008, 2009 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"
+#include <tls.h>
+#ifdef HAVE_FORCED_UNWIND
+# include <unwind.h>
+#endif
+#define __need_res_state
+#include <resolv.h>
+#include <bits/kernel-features.h>
+#include "uClibc-glue.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)
+
+
+
+
+/* Internal version of the buffer to store cancellation handler
+   information.  */
+struct pthread_unwind_buf
+{
+  struct
+  {
+    __jmp_buf jmp_buf;
+    int mask_was_saved;
+  } cancel_jmp_buf[1];
+
+  union
+  {
+    /* This is the placeholder of the public version.  */
+    void *pad[4];
+
+    struct
+    {
+      /* Pointer to the previous cleanup buffer.  */
+      struct pthread_unwind_buf *prev;
+
+      /* Backward compatibility: state of the old-style cleanup
+        handler at the time of the previous new-style cleanup handler
+        installment.  */
+      struct _pthread_cleanup_buffer *cleanup;
+
+      /* Cancellation type before the push call.  */
+      int canceltype;
+    } data;
+  } priv;
+};
+
+
+/* Opcodes and data types for communication with the signal handler to
+   change user/group IDs.  */
+struct xid_command
+{
+  int syscall_no;
+  long int id[3];
+  volatile int cntr;
+};
+
+
+/* Data structure used by the kernel to find robust futexes.  */
+struct robust_list_head
+{
+  void *list;
+  long int futex_offset;
+  void *list_op_pending;
+};
+
+
+/* Data strcture used to handle thread priority protection.  */
+struct priority_protection_data
+{
+  int priomax;
+  unsigned int priomap[];
+};
+
+
+/* Thread descriptor data structure.  */
+struct pthread
+{
+  union
+  {
+#if !defined(TLS_DTV_AT_TP)
+    /* This overlaps the TCB as used for TLS without threads (see tls.h).  */
+    tcbhead_t header;
+#else
+    struct
+    {
+      int multiple_threads;
+      int gscope_flag;
+# ifndef __ASSUME_PRIVATE_FUTEX
+      int private_futex;
+# endif
+    } header;
+#endif
+
+    /* This extra padding has no special purpose, and this structure layout
+       is private and subject to change without affecting the official ABI.
+       We just have it here in case it might be convenient for some
+       implementation-specific instrumentation hack or suchlike.  */
+    void *__padding[24];
+  };
+
+  /* This descriptor's link on the `stack_used' or `__stack_user' list.  */
+  list_t list;
+
+  /* Thread ID - which is also a 'is this thread descriptor (and
+     therefore stack) used' flag.  */
+  pid_t tid;
+
+  /* Process ID - thread group ID in kernel speak.  */
+  pid_t pid;
+
+  /* List of robust mutexes the thread is holding.  */
+#ifdef __PTHREAD_MUTEX_HAVE_PREV
+  void *robust_prev;
+  struct robust_list_head robust_head;
+
+  /* The list above is strange.  It is basically a double linked list
+     but the pointer to the next/previous element of the list points
+     in the middle of the object, the __next element.  Whenever
+     casting to __pthread_list_t we need to adjust the pointer
+     first.  */
+# define QUEUE_PTR_ADJUST (offsetof (__pthread_list_t, __next))
+
+# define ENQUEUE_MUTEX_BOTH(mutex, val)                                              \
+  do {                                                                       \
+    __pthread_list_t *next = (__pthread_list_t *)                            \
+      ((((uintptr_t) THREAD_GETMEM (THREAD_SELF, robust_head.list)) & ~1ul)   \
+       - QUEUE_PTR_ADJUST);                                                  \
+    next->__prev = (void *) &mutex->__data.__list.__next;                    \
+    mutex->__data.__list.__next = THREAD_GETMEM (THREAD_SELF,                \
+                                                robust_head.list);           \
+    mutex->__data.__list.__prev = (void *) &THREAD_SELF->robust_head;        \
+    THREAD_SETMEM (THREAD_SELF, robust_head.list,                            \
+                  (void *) (((uintptr_t) &mutex->__data.__list.__next)       \
+                            | val));                                         \
+  } while (0)
+# define DEQUEUE_MUTEX(mutex) \
+  do {                                                                       \
+    __pthread_list_t *next = (__pthread_list_t *)                            \
+      ((char *) (((uintptr_t) mutex->__data.__list.__next) & ~1ul)           \
+       - QUEUE_PTR_ADJUST);                                                  \
+    next->__prev = mutex->__data.__list.__prev;                                      \
+    __pthread_list_t *prev = (__pthread_list_t *)                            \
+      ((char *) (((uintptr_t) mutex->__data.__list.__prev) & ~1ul)           \
+       - QUEUE_PTR_ADJUST);                                                  \
+    prev->__next = mutex->__data.__list.__next;                                      \
+    mutex->__data.__list.__prev = NULL;                                              \
+    mutex->__data.__list.__next = NULL;                                              \
+  } while (0)
+#else
+  union
+  {
+    __pthread_slist_t robust_list;
+    struct robust_list_head robust_head;
+  };
+
+# define ENQUEUE_MUTEX_BOTH(mutex, val)                                              \
+  do {                                                                       \
+    mutex->__data.__list.__next                                                      \
+      = THREAD_GETMEM (THREAD_SELF, robust_list.__next);                     \
+    THREAD_SETMEM (THREAD_SELF, robust_list.__next,                          \
+                  (void *) (((uintptr_t) &mutex->__data.__list) | val));     \
+  } while (0)
+# define DEQUEUE_MUTEX(mutex) \
+  do {                                                                       \
+    __pthread_slist_t *runp = (__pthread_slist_t *)                          \
+      (((uintptr_t) THREAD_GETMEM (THREAD_SELF, robust_list.__next)) & ~1ul); \
+    if (runp == &mutex->__data.__list)                                       \
+      THREAD_SETMEM (THREAD_SELF, robust_list.__next, runp->__next);         \
+    else                                                                     \
+      {                                                                              \
+       __pthread_slist_t *next = (__pthread_slist_t *)               \
+         (((uintptr_t) runp->__next) & ~1ul);                                \
+       while (next != &mutex->__data.__list)                                 \
+         {                                                                   \
+           runp = next;                                                      \
+           next = (__pthread_slist_t *) (((uintptr_t) runp->__next) & ~1ul); \
+         }                                                                   \
+                                                                             \
+       runp->__next = next->__next;                                          \
+       mutex->__data.__list.__next = NULL;                                   \
+      }                                                                              \
+  } while (0)
+#endif
+#define ENQUEUE_MUTEX(mutex) ENQUEUE_MUTEX_BOTH (mutex, 0)
+#define ENQUEUE_MUTEX_PI(mutex) ENQUEUE_MUTEX_BOTH (mutex, 1)
+
+  /* List of cleanup buffers.  */
+  struct _pthread_cleanup_buffer *cleanup;
+
+  /* Unwind information.  */
+  struct pthread_unwind_buf *cleanup_jmp_buf;
+#define HAVE_CLEANUP_JMP_BUF
+
+  /* Flags determining processing of cancellation.  */
+  int cancelhandling;
+  /* Bit set if cancellation is disabled.  */
+#define CANCELSTATE_BIT                0
+#define CANCELSTATE_BITMASK    (0x01 << CANCELSTATE_BIT)
+  /* Bit set if asynchronous cancellation mode is selected.  */
+#define CANCELTYPE_BIT         1
+#define CANCELTYPE_BITMASK     (0x01 << CANCELTYPE_BIT)
+  /* Bit set if canceling has been initiated.  */
+#define CANCELING_BIT          2
+#define CANCELING_BITMASK      (0x01 << CANCELING_BIT)
+  /* Bit set if canceled.  */
+#define CANCELED_BIT           3
+#define CANCELED_BITMASK       (0x01 << CANCELED_BIT)
+  /* Bit set if thread is exiting.  */
+#define EXITING_BIT            4
+#define EXITING_BITMASK                (0x01 << EXITING_BIT)
+  /* Bit set if thread terminated and TCB is freed.  */
+#define TERMINATED_BIT         5
+#define TERMINATED_BITMASK     (0x01 << TERMINATED_BIT)
+  /* Bit set if thread is supposed to change XID.  */
+#define SETXID_BIT             6
+#define SETXID_BITMASK         (0x01 << SETXID_BIT)
+  /* Mask for the rest.  Helps the compiler to optimize.  */
+#define CANCEL_RESTMASK                0xffffff80
+
+#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))
+
+  /* Flags.  Including those copied from the thread attribute.  */
+  int flags;
+
+  /* We allocate one block of references here.  This should be enough
+     to avoid allocating any memory dynamically for most applications.  */
+  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_1stblock[PTHREAD_KEY_2NDLEVEL_SIZE];
+
+  /* Two-level array for the thread-specific data.  */
+  struct pthread_key_data *specific[PTHREAD_KEY_1STLEVEL_SIZE];
+
+  /* Flag which is set when specific data is set.  */
+  bool specific_used;
+
+  /* True if events must be reported.  */
+  bool report_events;
+
+  /* True if the user provided the stack.  */
+  bool user_stack;
+
+  /* True if thread must stop at startup time.  */
+  bool stopped_start;
+
+  /* The parent's cancel handling at the time of the pthread_create
+     call.  This might be needed to undo the effects of a cancellation.  */
+  int parent_cancelhandling;
+
+  /* Lock to synchronize access to the descriptor.  */
+  int lock;
+
+  /* Lock for synchronizing setxid calls.  */
+  int setxid_futex;
+
+#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))
+
+  /* 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;
+
+#ifdef HAVE_FORCED_UNWIND
+  /* Machine-specific unwind info.  */
+  struct _Unwind_Exception exc;
+#endif
+
+  /* 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;
+  /* This is what the user specified and what we will report.  */
+  size_t reported_guardsize;
+
+  /* Thread Priority Protection data.  */
+  struct priority_protection_data *tpp;
+
+  /* Resolver state.  */
+  struct __res_state res;
+
+  /* This member must be last.  */
+  char end_padding[];
+
+#define PTHREAD_STRUCT_END_PADDING \
+  (sizeof (struct pthread) - offsetof (struct pthread, end_padding))
+} __attribute ((aligned (TCB_ALIGNMENT)));
+
+
+#endif /* descr.h */
diff --git a/libpthread/nptl/eintr.c b/libpthread/nptl/eintr.c
new file mode 100644 (file)
index 0000000..933c5d8
--- /dev/null
@@ -0,0 +1,89 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <signal.h>
+#include <unistd.h>
+
+
+static int the_sig;
+
+
+static void
+eintr_handler (int sig)
+{
+  if (sig != the_sig)
+    {
+      write (STDOUT_FILENO, "eintr_handler: signal number wrong\n", 35);
+      _exit (1);
+    }
+  write (STDOUT_FILENO, ".", 1);
+}
+
+
+static void *
+eintr_source (void *arg)
+{
+  struct timespec ts = { .tv_sec = 0, .tv_nsec = 500000 };
+
+  if (arg == NULL)
+    {
+      sigset_t ss;
+      sigemptyset (&ss);
+      sigaddset (&ss, the_sig);
+      pthread_sigmask (SIG_BLOCK, &ss, NULL);
+    }
+
+  while (1)
+    {
+      if (arg != NULL)
+       pthread_kill (*(pthread_t *) arg, the_sig);
+      else
+       kill (getpid (), the_sig);
+
+      nanosleep (&ts, NULL);
+    }
+
+  /* NOTREACHED */
+  return NULL;
+}
+
+
+static void
+setup_eintr (int sig, pthread_t *thp)
+{
+  struct sigaction sa;
+  sigemptyset (&sa.sa_mask);
+  sa.sa_flags = 0;
+  sa.sa_handler = eintr_handler;
+  if (sigaction (sig, &sa, NULL) != 0)
+    {
+      puts ("setup_eintr: sigaction failed");
+      exit (1);
+    }
+  the_sig = sig;
+
+  /* Create the thread which will fire off the signals.  */
+  pthread_t th;
+  if (pthread_create (&th, NULL, eintr_source, thp) != 0)
+    {
+      puts ("setup_eintr: pthread_create failed");
+      exit (1);
+    }
+}
diff --git a/libpthread/nptl/events.c b/libpthread/nptl/events.c
new file mode 100644 (file)
index 0000000..df97e54
--- /dev/null
@@ -0,0 +1,34 @@
+/* Event functions used while debugging.
+   Copyright (C) 1999, 2000, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+/* The functions contained here do nothing, they just return.  */
+
+#include "pthreadP.h"
+
+void
+__nptl_create_event (void)
+{
+}
+hidden_def (__nptl_create_event)
+
+void
+__nptl_death_event (void)
+{
+}
+hidden_def (__nptl_death_event)
diff --git a/libpthread/nptl/forward.c b/libpthread/nptl/forward.c
new file mode 100644 (file)
index 0000000..8f528d0
--- /dev/null
@@ -0,0 +1,153 @@
+/* Copyright (C) 2002, 2003, 2004, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <dlfcn.h>
+#include <pthreadP.h>
+#include <signal.h>
+#include <stdlib.h>
+
+#include <atomic.h>
+#include <sysdep.h>
+
+
+/* Pointers to the libc functions.  */
+struct pthread_functions __libc_pthread_functions attribute_hidden;
+int __libc_pthread_functions_init attribute_hidden;
+
+
+#define FORWARD2(name, rettype, decl, params, defaction) \
+rettype                                                                              \
+name decl                                                                    \
+{                                                                            \
+  if (!__libc_pthread_functions_init)                                        \
+    defaction;                                                               \
+                                                                             \
+  return PTHFCT_CALL (ptr_##name, params);                                   \
+}
+
+#define FORWARD(name, decl, params, defretval) \
+  FORWARD2 (name, int, decl, params, return defretval)
+
+
+FORWARD (pthread_attr_destroy, (pthread_attr_t *attr), (attr), 0)
+
+FORWARD (__pthread_attr_init_2_1, (pthread_attr_t *attr), (attr), 0)
+weak_alias(__pthread_attr_init_2_1, pthread_attr_init)
+
+FORWARD (pthread_attr_getdetachstate,
+        (const pthread_attr_t *attr, int *detachstate), (attr, detachstate),
+        0)
+FORWARD (pthread_attr_setdetachstate, (pthread_attr_t *attr, int detachstate),
+        (attr, detachstate), 0)
+
+FORWARD (pthread_attr_getinheritsched,
+        (const pthread_attr_t *attr, int *inherit), (attr, inherit), 0)
+FORWARD (pthread_attr_setinheritsched, (pthread_attr_t *attr, int inherit),
+        (attr, inherit), 0)
+
+FORWARD (pthread_attr_getschedparam,
+        (const pthread_attr_t *attr, struct sched_param *param),
+        (attr, param), 0)
+FORWARD (pthread_attr_setschedparam,
+        (pthread_attr_t *attr, const struct sched_param *param),
+        (attr, param), 0)
+
+FORWARD (pthread_attr_getschedpolicy,
+        (const pthread_attr_t *attr, int *policy), (attr, policy), 0)
+FORWARD (pthread_attr_setschedpolicy, (pthread_attr_t *attr, int policy),
+        (attr, policy), 0)
+
+FORWARD (pthread_attr_getscope,
+        (const pthread_attr_t *attr, int *scope), (attr, scope), 0)
+FORWARD (pthread_attr_setscope, (pthread_attr_t *attr, int scope),
+        (attr, scope), 0)
+
+
+FORWARD (pthread_condattr_destroy, (pthread_condattr_t *attr), (attr), 0)
+FORWARD (pthread_condattr_init, (pthread_condattr_t *attr), (attr), 0)
+
+FORWARD (__pthread_cond_broadcast, (pthread_cond_t *cond), (cond), 0)
+weak_alias(__pthread_cond_broadcast, pthread_cond_broadcast)
+
+FORWARD (__pthread_cond_destroy, (pthread_cond_t *cond), (cond), 0)
+weak_alias(__pthread_cond_destroy, pthread_cond_destroy)
+
+FORWARD (__pthread_cond_init,
+        (pthread_cond_t *cond, const pthread_condattr_t *cond_attr),
+        (cond, cond_attr), 0)
+weak_alias(__pthread_cond_init, pthread_cond_init)
+
+FORWARD (__pthread_cond_signal, (pthread_cond_t *cond), (cond), 0)
+weak_alias(__pthread_cond_signal, pthread_cond_signal)
+
+FORWARD (__pthread_cond_wait, (pthread_cond_t *cond, pthread_mutex_t *mutex),
+        (cond, mutex), 0)
+weak_alias(__pthread_cond_wait, pthread_cond_wait)
+
+FORWARD (__pthread_cond_timedwait,
+        (pthread_cond_t *cond, pthread_mutex_t *mutex,
+         const struct timespec *abstime), (cond, mutex, abstime), 0)
+weak_alias(__pthread_cond_timedwait, pthread_cond_timedwait)
+
+
+FORWARD (pthread_equal, (pthread_t thread1, pthread_t thread2),
+        (thread1, thread2), 1)
+
+
+/* Use an alias to avoid warning, as pthread_exit is declared noreturn.  */
+FORWARD2 (__pthread_exit, void, (void *retval), (retval), exit (EXIT_SUCCESS))
+strong_alias (__pthread_exit, pthread_exit);
+
+
+FORWARD (pthread_getschedparam,
+        (pthread_t target_thread, int *policy, struct sched_param *param),
+        (target_thread, policy, param), 0)
+FORWARD (pthread_setschedparam,
+        (pthread_t target_thread, int policy,
+         const struct sched_param *param), (target_thread, policy, param), 0)
+
+
+FORWARD (pthread_mutex_destroy, (pthread_mutex_t *mutex), (mutex), 0)
+
+FORWARD (pthread_mutex_init,
+        (pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr),
+        (mutex, mutexattr), 0)
+
+FORWARD (pthread_mutex_lock, (pthread_mutex_t *mutex), (mutex), 0)
+
+FORWARD (pthread_mutex_unlock, (pthread_mutex_t *mutex), (mutex), 0)
+
+
+FORWARD2 (pthread_self, pthread_t, (void), (), return 0)
+
+
+FORWARD (pthread_setcancelstate, (int state, int *oldstate), (state, oldstate),
+        0)
+
+FORWARD (pthread_setcanceltype, (int type, int *oldtype), (type, oldtype), 0)
+
+#define return /* value is void */
+FORWARD2(__pthread_unwind,
+        void attribute_hidden __attribute ((noreturn)) __cleanup_fct_attribute,
+        (__pthread_unwind_buf_t *buf), (buf), {
+                      /* We cannot call abort() here.  */
+                      INTERNAL_SYSCALL_DECL (err);
+                      INTERNAL_SYSCALL (kill, err, 1, SIGKILL);
+                    })
+#undef return
diff --git a/libpthread/nptl/herrno.c b/libpthread/nptl/herrno.c
new file mode 100644 (file)
index 0000000..6e8339d
--- /dev/null
@@ -0,0 +1,35 @@
+/* Copyright (C) 1996,97,98,2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <features.h>
+#include <netdb.h>
+#undef h_errno
+
+#include <tls.h>
+
+/* We need to have the error status variable of the resolver
+   accessible in the libc.  */
+extern __thread int h_errno;
+
+
+/* When threaded, h_errno may be a per-thread variable.  */
+int *
+__h_errno_location (void)
+{
+  return &h_errno;
+}
diff --git a/libpthread/nptl/init.c b/libpthread/nptl/init.c
new file mode 100644 (file)
index 0000000..b651a3e
--- /dev/null
@@ -0,0 +1,428 @@
+/* Copyright (C) 2002-2007, 2008, 2009 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 <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <sys/resource.h>
+#include <pthreadP.h>
+#include <atomic.h>
+#include <ldsodefs.h>
+#include <tls.h>
+#include <fork.h>
+#include <version.h>
+#include <smp.h>
+#include <lowlevellock.h>
+#include <bits/kernel-features.h>
+
+
+/* Size and alignment of static TLS block.  */
+size_t __static_tls_size;
+size_t __static_tls_align_m1;
+
+#ifndef __ASSUME_SET_ROBUST_LIST
+/* Negative if we do not have the system call and we can use it.  */
+int __set_robust_list_avail;
+# define set_robust_list_not_avail() \
+  __set_robust_list_avail = -1
+#else
+# define set_robust_list_not_avail() do { } while (0)
+#endif
+
+#ifndef __ASSUME_FUTEX_CLOCK_REALTIME
+/* Nonzero if we do not have FUTEX_CLOCK_REALTIME.  */
+int __have_futex_clock_realtime;
+# define __set_futex_clock_realtime() \
+  __have_futex_clock_realtime = 1
+#else
+#define __set_futex_clock_realtime() do { } while (0)
+#endif
+
+/* Version of the library, used in libthread_db to detect mismatches.  */
+static const char nptl_version[] __attribute_used__ = VERSION;
+
+
+#ifndef SHARED
+extern void __libc_setup_tls (size_t tcbsize, size_t tcbalign);
+#endif
+
+#ifdef SHARED
+static void nptl_freeres (void);
+
+
+static const struct pthread_functions pthread_functions =
+  {
+    .ptr_pthread_attr_destroy = __pthread_attr_destroy,
+    .ptr___pthread_attr_init_2_1 = __pthread_attr_init_2_1,
+    .ptr_pthread_attr_getdetachstate = __pthread_attr_getdetachstate,
+    .ptr_pthread_attr_setdetachstate = __pthread_attr_setdetachstate,
+    .ptr_pthread_attr_getinheritsched = __pthread_attr_getinheritsched,
+    .ptr_pthread_attr_setinheritsched = __pthread_attr_setinheritsched,
+    .ptr_pthread_attr_getschedparam = __pthread_attr_getschedparam,
+    .ptr_pthread_attr_setschedparam = __pthread_attr_setschedparam,
+    .ptr_pthread_attr_getschedpolicy = __pthread_attr_getschedpolicy,
+    .ptr_pthread_attr_setschedpolicy = __pthread_attr_setschedpolicy,
+    .ptr_pthread_attr_getscope = __pthread_attr_getscope,
+    .ptr_pthread_attr_setscope = __pthread_attr_setscope,
+    .ptr_pthread_condattr_destroy = __pthread_condattr_destroy,
+    .ptr_pthread_condattr_init = __pthread_condattr_init,
+    .ptr___pthread_cond_broadcast = __pthread_cond_broadcast,
+    .ptr___pthread_cond_destroy = __pthread_cond_destroy,
+    .ptr___pthread_cond_init = __pthread_cond_init,
+    .ptr___pthread_cond_signal = __pthread_cond_signal,
+    .ptr___pthread_cond_wait = __pthread_cond_wait,
+    .ptr___pthread_cond_timedwait = __pthread_cond_timedwait,
+    .ptr_pthread_equal = __pthread_equal,
+    .ptr___pthread_exit = __pthread_exit,
+    .ptr_pthread_getschedparam = __pthread_getschedparam,
+    .ptr_pthread_setschedparam = __pthread_setschedparam,
+    .ptr_pthread_mutex_destroy = INTUSE(__pthread_mutex_destroy),
+    .ptr_pthread_mutex_init = INTUSE(__pthread_mutex_init),
+    .ptr_pthread_mutex_lock = INTUSE(__pthread_mutex_lock),
+    .ptr_pthread_mutex_unlock = INTUSE(__pthread_mutex_unlock),
+    .ptr_pthread_self = __pthread_self,
+    .ptr_pthread_setcancelstate = __pthread_setcancelstate,
+    .ptr_pthread_setcanceltype = __pthread_setcanceltype,
+    .ptr___pthread_cleanup_upto = __pthread_cleanup_upto,
+    .ptr___pthread_once = __pthread_once_internal,
+    .ptr___pthread_rwlock_rdlock = __pthread_rwlock_rdlock_internal,
+    .ptr___pthread_rwlock_wrlock = __pthread_rwlock_wrlock_internal,
+    .ptr___pthread_rwlock_unlock = __pthread_rwlock_unlock_internal,
+    .ptr___pthread_key_create = __pthread_key_create_internal,
+    .ptr___pthread_getspecific = __pthread_getspecific_internal,
+    .ptr___pthread_setspecific = __pthread_setspecific_internal,
+    .ptr__pthread_cleanup_push_defer = __pthread_cleanup_push_defer,
+    .ptr__pthread_cleanup_pop_restore = __pthread_cleanup_pop_restore,
+    .ptr_nthreads = &__nptl_nthreads,
+    .ptr___pthread_unwind = &__pthread_unwind,
+    .ptr__nptl_deallocate_tsd = __nptl_deallocate_tsd,
+    .ptr__nptl_setxid = __nptl_setxid,
+    /* For now only the stack cache needs to be freed.  */
+    .ptr_freeres = nptl_freeres
+  };
+# define ptr_pthread_functions &pthread_functions
+#else
+# define ptr_pthread_functions NULL
+#endif
+
+
+#ifdef SHARED
+/* This function is called indirectly from the freeres code in libc.  */
+static void
+__libc_freeres_fn_section
+nptl_freeres (void)
+{
+  __unwind_freeres ();
+  __free_stacks (0);
+}
+#endif
+
+
+/* For asynchronous cancellation we use a signal.  This is the handler.  */
+static void
+sigcancel_handler (int sig, siginfo_t *si, void *ctx)
+{
+#ifdef __ASSUME_CORRECT_SI_PID
+  /* Determine the process ID.  It might be negative if the thread is
+     in the middle of a fork() call.  */
+  pid_t pid = THREAD_GETMEM (THREAD_SELF, pid);
+  if (__builtin_expect (pid < 0, 0))
+    pid = -pid;
+#endif
+
+  /* Safety check.  It would be possible to call this function for
+     other signals and send a signal from another process.  This is not
+     correct and might even be a security problem.  Try to catch as
+     many incorrect invocations as possible.  */
+  if (sig != SIGCANCEL
+#ifdef __ASSUME_CORRECT_SI_PID
+      /* Kernels before 2.5.75 stored the thread ID and not the process
+        ID in si_pid so we skip this test.  */
+      || si->si_pid != pid
+#endif
+      || si->si_code != SI_TKILL)
+    return;
+
+  struct pthread *self = THREAD_SELF;
+
+  int oldval = THREAD_GETMEM (self, cancelhandling);
+  while (1)
+    {
+      /* We are canceled now.  When canceled by another thread this flag
+        is already set but if the signal is directly send (internally or
+        from another process) is has to be done here.  */
+      int newval = oldval | CANCELING_BITMASK | CANCELED_BITMASK;
+
+      if (oldval == newval || (oldval & EXITING_BITMASK) != 0)
+       /* Already canceled or exiting.  */
+       break;
+
+      int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, newval,
+                                             oldval);
+      if (curval == oldval)
+       {
+         /* Set the return value.  */
+         THREAD_SETMEM (self, result, PTHREAD_CANCELED);
+
+         /* Make sure asynchronous cancellation is still enabled.  */
+         if ((newval & CANCELTYPE_BITMASK) != 0)
+           /* Run the registered destructors and terminate the thread.  */
+           __do_cancel ();
+
+         break;
+       }
+
+      oldval = curval;
+    }
+}
+
+
+struct xid_command *__xidcmd attribute_hidden;
+
+/* For asynchronous cancellation we use a signal.  This is the handler.  */
+static void
+sighandler_setxid (int sig, siginfo_t *si, void *ctx)
+{
+#ifdef __ASSUME_CORRECT_SI_PID
+  /* Determine the process ID.  It might be negative if the thread is
+     in the middle of a fork() call.  */
+  pid_t pid = THREAD_GETMEM (THREAD_SELF, pid);
+  if (__builtin_expect (pid < 0, 0))
+    pid = -pid;
+#endif
+
+  /* Safety check.  It would be possible to call this function for
+     other signals and send a signal from another process.  This is not
+     correct and might even be a security problem.  Try to catch as
+     many incorrect invocations as possible.  */
+  if (sig != SIGSETXID
+#ifdef __ASSUME_CORRECT_SI_PID
+      /* Kernels before 2.5.75 stored the thread ID and not the process
+        ID in si_pid so we skip this test.  */
+      || si->si_pid != pid
+#endif
+      || si->si_code != SI_TKILL)
+    return;
+
+  INTERNAL_SYSCALL_DECL (err);
+  INTERNAL_SYSCALL_NCS (__xidcmd->syscall_no, err, 3, __xidcmd->id[0],
+                       __xidcmd->id[1], __xidcmd->id[2]);
+
+  /* Reset the SETXID flag.  */
+  struct pthread *self = THREAD_SELF;
+  int flags, newval;
+  do
+    {
+      flags = THREAD_GETMEM (self, cancelhandling);
+      newval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling,
+                                         flags & ~SETXID_BITMASK, flags);
+    }
+  while (flags != newval);
+
+  /* And release the futex.  */
+  self->setxid_futex = 1;
+  lll_futex_wake (&self->setxid_futex, 1, LLL_PRIVATE);
+
+  if (atomic_decrement_val (&__xidcmd->cntr) == 0)
+    lll_futex_wake (&__xidcmd->cntr, 1, LLL_PRIVATE);
+}
+
+
+/* When using __thread for this, we do it in libc so as not
+   to give libpthread its own TLS segment just for this.  */
+extern void **__libc_dl_error_tsd (void) __attribute__ ((const));
+
+
+/* This can be set by the debugger before initialization is complete.  */
+static bool __nptl_initial_report_events __attribute_used__;
+
+void
+__pthread_initialize_minimal_internal (void)
+{
+#ifndef SHARED
+  /* Unlike in the dynamically linked case the dynamic linker has not
+     taken care of initializing the TLS data structures.  */
+  __libc_setup_tls (TLS_TCB_SIZE, TLS_TCB_ALIGN);
+
+  /* We must prevent gcc from being clever and move any of the
+     following code ahead of the __libc_setup_tls call.  This function
+     will initialize the thread register which is subsequently
+     used.  */
+  __asm __volatile ("");
+#endif
+
+  /* Minimal initialization of the thread descriptor.  */
+  struct pthread *pd = THREAD_SELF;
+  INTERNAL_SYSCALL_DECL (err);
+  pd->pid = pd->tid = INTERNAL_SYSCALL (set_tid_address, err, 1, &pd->tid);
+  THREAD_SETMEM (pd, specific[0], &pd->specific_1stblock[0]);
+  THREAD_SETMEM (pd, user_stack, true);
+  if (LLL_LOCK_INITIALIZER != 0)
+    THREAD_SETMEM (pd, lock, LLL_LOCK_INITIALIZER);
+#if HP_TIMING_AVAIL
+  THREAD_SETMEM (pd, cpuclock_offset, GL(dl_cpuclock_offset));
+#endif
+
+  /* Initialize the robust mutex data.  */
+#ifdef __PTHREAD_MUTEX_HAVE_PREV
+  pd->robust_prev = &pd->robust_head;
+#endif
+  pd->robust_head.list = &pd->robust_head;
+#ifdef __NR_set_robust_list
+  pd->robust_head.futex_offset = (offsetof (pthread_mutex_t, __data.__lock)
+                                 - offsetof (pthread_mutex_t,
+                                             __data.__list.__next));
+  int res = INTERNAL_SYSCALL (set_robust_list, err, 2, &pd->robust_head,
+                             sizeof (struct robust_list_head));
+  if (INTERNAL_SYSCALL_ERROR_P (res, err))
+#endif
+    set_robust_list_not_avail ();
+
+#ifndef __ASSUME_PRIVATE_FUTEX
+  /* Private futexes are always used (at least internally) so that
+     doing the test once this early is beneficial.  */
+  {
+    int word = 0;
+    word = INTERNAL_SYSCALL (futex, err, 3, &word,
+                           FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1);
+    if (!INTERNAL_SYSCALL_ERROR_P (word, err))
+      THREAD_SETMEM (pd, header.private_futex, FUTEX_PRIVATE_FLAG);
+  }
+
+  /* Private futexes have been introduced earlier than the
+     FUTEX_CLOCK_REALTIME flag.  We don't have to run the test if we
+     know the former are not supported.  This also means we know the
+     kernel will return ENOSYS for unknown operations.  */
+  if (THREAD_GETMEM (pd, header.private_futex) != 0)
+#endif
+#ifndef __ASSUME_FUTEX_CLOCK_REALTIME
+    {
+      int word = 0;
+      /* NB: the syscall actually takes six parameters.  The last is the
+        bit mask.  But since we will not actually wait at all the value
+        is irrelevant.  Given that passing six parameters is difficult
+        on some architectures we just pass whatever random value the
+        calling convention calls for to the kernel.  It causes no harm.  */
+      word = INTERNAL_SYSCALL (futex, err, 5, &word,
+                              FUTEX_WAIT_BITSET | FUTEX_CLOCK_REALTIME
+                              | FUTEX_PRIVATE_FLAG, 1, NULL, 0);
+      assert (INTERNAL_SYSCALL_ERROR_P (word, err));
+      if (INTERNAL_SYSCALL_ERRNO (word, err) != ENOSYS)
+       __set_futex_clock_realtime ();
+    }
+#endif
+
+  /* Set initial thread's stack block from 0 up to __libc_stack_end.
+     It will be bigger than it actually is, but for unwind.c/pt-longjmp.c
+     purposes this is good enough.  */
+  THREAD_SETMEM (pd, stackblock_size, (size_t) __libc_stack_end);
+
+  /* Initialize the list of all running threads with the main thread.  */
+  INIT_LIST_HEAD (&__stack_user);
+  list_add (&pd->list, &__stack_user);
+
+  /* Before initializing __stack_user, the debugger could not find us and
+     had to set __nptl_initial_report_events.  Propagate its setting.  */
+  THREAD_SETMEM (pd, report_events, __nptl_initial_report_events);
+
+  /* Install the cancellation signal handler.  If for some reason we
+     cannot install the handler we do not abort.  Maybe we should, but
+     it is only asynchronous cancellation which is affected.  */
+  struct sigaction sa;
+  sa.sa_sigaction = sigcancel_handler;
+  sa.sa_flags = SA_SIGINFO;
+  __sigemptyset (&sa.sa_mask);
+
+  (void) __libc_sigaction (SIGCANCEL, &sa, NULL);
+
+  /* Install the handle to change the threads' uid/gid.  */
+  sa.sa_sigaction = sighandler_setxid;
+  sa.sa_flags = SA_SIGINFO | SA_RESTART;
+
+  (void) __libc_sigaction (SIGSETXID, &sa, NULL);
+
+  /* The parent process might have left the signals blocked.  Just in
+     case, unblock it.  We reuse the signal mask in the sigaction
+     structure.  It is already cleared.  */
+  __sigaddset (&sa.sa_mask, SIGCANCEL);
+  __sigaddset (&sa.sa_mask, SIGSETXID);
+  (void) INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_UNBLOCK, &sa.sa_mask,
+                          NULL, _NSIG / 8);
+
+  /* Get the size of the static and alignment requirements for the TLS
+     block.  */
+  size_t static_tls_align;
+  _dl_get_tls_static_info (&__static_tls_size, &static_tls_align);
+
+  /* Make sure the size takes all the alignments into account.  */
+  if (STACK_ALIGN > static_tls_align)
+    static_tls_align = STACK_ALIGN;
+  __static_tls_align_m1 = static_tls_align - 1;
+
+  __static_tls_size = roundup (__static_tls_size, static_tls_align);
+
+  /* Determine the default allowed stack size.  This is the size used
+     in case the user does not specify one.  */
+  struct rlimit limit;
+  if (getrlimit (RLIMIT_STACK, &limit) != 0
+      || limit.rlim_cur == RLIM_INFINITY)
+    /* The system limit is not usable.  Use an architecture-specific
+       default.  */
+    limit.rlim_cur = ARCH_STACK_DEFAULT_SIZE;
+  else if (limit.rlim_cur < PTHREAD_STACK_MIN)
+    /* The system limit is unusably small.
+       Use the minimal size acceptable.  */
+    limit.rlim_cur = PTHREAD_STACK_MIN;
+
+  /* Make sure it meets the minimum size that allocate_stack
+     (allocatestack.c) will demand, which depends on the page size.  */
+  const uintptr_t pagesz = sysconf (_SC_PAGESIZE);
+  const size_t minstack = pagesz + __static_tls_size + MINIMAL_REST_STACK;
+  if (limit.rlim_cur < minstack)
+    limit.rlim_cur = minstack;
+
+  /* Round the resource limit up to page size.  */
+  limit.rlim_cur = (limit.rlim_cur + pagesz - 1) & -pagesz;
+  __default_stacksize = limit.rlim_cur;
+
+#ifdef SHARED
+  /* Transfer the old value from the dynamic linker's internal location.  */
+  *__libc_dl_error_tsd () = *(*GL(dl_error_catch_tsd)) ();
+  GL(dl_error_catch_tsd) = &__libc_dl_error_tsd;
+
+#endif
+
+  GL(dl_init_static_tls) = &__pthread_init_static_tls;
+
+  /* Register the fork generation counter with the libc.  */
+#ifndef TLS_MULTIPLE_THREADS_IN_TCB
+  __libc_multiple_threads_ptr =
+#endif
+    __libc_pthread_init (&__fork_generation, __reclaim_stacks,
+                        ptr_pthread_functions);
+
+  /* Determine whether the machine is SMP or not.  */
+  __is_smp = is_smp_system ();
+}
+strong_alias (__pthread_initialize_minimal_internal,
+             __pthread_initialize_minimal)
diff --git a/libpthread/nptl/libc-cancellation.c b/libpthread/nptl/libc-cancellation.c
new file mode 100644 (file)
index 0000000..e9334a4
--- /dev/null
@@ -0,0 +1,25 @@
+/* Copyright (C) 2002, 2003, 2005, 2009 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"
+
+
+#define __pthread_enable_asynccancel __libc_enable_asynccancel
+#define __pthread_disable_asynccancel __libc_disable_asynccancel
+#include "cancellation.c"
diff --git a/libpthread/nptl/linux_fsinfo.h b/libpthread/nptl/linux_fsinfo.h
new file mode 100644 (file)
index 0000000..13c3856
--- /dev/null
@@ -0,0 +1,153 @@
+/* Constants from kernel header for various FSes.
+   Copyright (C) 1998,1999,2000,2001,2002,2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _LINUX_FSINFO_H
+#define _LINUX_FSINFO_H        1
+
+/* These definitions come from the kernel headers.  But we cannot
+   include the headers here because of type clashes.  If new
+   filesystem types will become available we have to add the
+   appropriate definitions here.*/
+
+/* Constants that identify the `adfs' filesystem.  */
+#define ADFS_SUPER_MAGIC       0xadf5
+
+/* Constants that identify the `affs' filesystem.  */
+#define AFFS_SUPER_MAGIC       0xadff
+
+/* Constants that identify the `autofs' filesystem.  */
+#define AUTOFS_SUPER_MAGIC     0x187
+
+/* Constants that identify the `bfs' filesystem.  */
+#define BFS_MAGIC              0x1BADFACE
+
+/* Constants that identify the `coda' filesystem.  */
+#define CODA_SUPER_MAGIC       0x73757245
+
+/* Constants that identify the `coherent' filesystem.  */
+#define COH_SUPER_MAGIC                0x012ff7b7
+
+/* Constant that identifies the `ramfs' filesystem.  */
+#define CRAMFS_MAGIC           0x28cd3d45
+
+/* Constant that identifies the `devfs' filesystem.  */
+#define DEVFS_SUPER_MAGIC      0x1373
+
+/* Constant that identifies the `devpts' filesystem.  */
+#define DEVPTS_SUPER_MAGIC     0x1cd1
+
+/* Constant that identifies the `efs' filesystem.  */
+#define EFS_SUPER_MAGIC                0x414A53
+#define EFS_MAGIC              0x072959
+
+/* Constant that identifies the `ext2' and `ext3' filesystems.  */
+#define EXT2_SUPER_MAGIC       0xef53
+
+/* Constant that identifies the `hpfs' filesystem.  */
+#define HPFS_SUPER_MAGIC       0xf995e849
+
+/* Constant that identifies the `iso9660' filesystem.  */
+#define ISOFS_SUPER_MAGIC      0x9660
+
+/* Constant that identifies the `jffs' filesystem.  */
+#define JFFS_SUPER_MAGIC       0x07c0
+
+/* Constant that identifies the `jffs2' filesystem.  */
+#define JFFS2_SUPER_MAGIC      0x72b6
+
+/* Constant that identifies the `jfs' filesystem.  */
+#define JFS_SUPER_MAGIC                0x3153464a
+
+/* Constants that identify the `minix2' filesystem.  */
+#define MINIX2_SUPER_MAGIC     0x2468
+#define MINIX2_SUPER_MAGIC2    0x2478
+
+/* Constants that identify the `minix' filesystem.  */
+#define MINIX_SUPER_MAGIC      0x137f
+#define MINIX_SUPER_MAGIC2     0x138F
+
+/* Constants that identify the `msdos' filesystem.  */
+#define MSDOS_SUPER_MAGIC      0x4d44
+
+/* Constants that identify the `ncp' filesystem.  */
+#define NCP_SUPER_MAGIC                0x564c
+
+/* Constants that identify the `nfs' filesystem.  */
+#define NFS_SUPER_MAGIC                0x6969
+
+/* Constants that identify the `ntfs' filesystem.  */
+#define NTFS_SUPER_MAGIC       0x5346544e
+
+/* Constants that identify the `proc' filesystem.  */
+#define PROC_SUPER_MAGIC       0x9fa0
+
+/* Constant that identifies the `usbdevfs' filesystem.  */
+#define USBDEVFS_SUPER_MAGIC   0x9fa2
+
+/* Constants that identify the `qnx4' filesystem.  */
+#define QNX4_SUPER_MAGIC       0x002f
+
+/* Constants that identify the `reiser' filesystem.  */
+#define REISERFS_SUPER_MAGIC   0x52654973
+
+/* Constant that identifies the `romfs' filesystem.  */
+#define ROMFS_SUPER_MAGIC      0x7275
+
+/* Constants that identify the `smb' filesystem.  */
+#define SMB_SUPER_MAGIC                0x517b
+
+/* Constants that identify the `sysV' filesystem.  */
+#define SYSV2_SUPER_MAGIC      0x012ff7b6
+#define SYSV4_SUPER_MAGIC      0x012ff7b5
+
+/* Constants that identify the `udf' filesystem.  */
+#define UDF_SUPER_MAGIC                0x15013346
+
+/* Constants that identify the `ufs' filesystem.  */
+#define UFS_MAGIC              0x00011954
+#define UFS_CIGAM              0x54190100 /* byteswapped MAGIC */
+
+/* Constants that identify the `xenix' filesystem.  */
+#define XENIX_SUPER_MAGIC      0x012ff7b4
+
+/* Constant that identifies the `shm' filesystem.  */
+#define SHMFS_SUPER_MAGIC      0x01021994
+
+/* Constants that identify the `xfs' filesystem.  */
+#define XFS_SUPER_MAGIC                0x58465342
+
+/* Constants that identify the `vxfs' filesystem.  */
+#define VXFS_SUPER_MAGIC       0xa501fcf5
+
+/* Maximum link counts.  */
+#define COH_LINK_MAX           10000
+#define EXT2_LINK_MAX          32000
+#define MINIX2_LINK_MAX                65530
+#define MINIX_LINK_MAX         250
+#define REISERFS_LINK_MAX      64535
+#define SYSV_LINK_MAX          126     /* 127? 251? */
+#define UFS_LINK_MAX           EXT2_LINK_MAX
+#define XENIX_LINK_MAX         126     /* ?? */
+#define XFS_LINK_MAX           2147483647
+
+/* The Linux kernel header mentioned this as a kind of generic value.  */
+#define LINUX_LINK_MAX 127
+
+
+#endif /* linux_fsinfo.h */
diff --git a/libpthread/nptl/pt-cleanup.c b/libpthread/nptl/pt-cleanup.c
new file mode 100644 (file)
index 0000000..f72ea26
--- /dev/null
@@ -0,0 +1,63 @@
+/* Copyright (C) 2002, 2003, 2005 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"
+#include <jmpbuf-unwind.h>
+
+void
+__pthread_cleanup_upto (__jmp_buf target, char *targetframe)
+{
+  struct pthread *self = THREAD_SELF;
+  struct _pthread_cleanup_buffer *cbuf;
+
+  /* Adjust all pointers used in comparisons, so that top of thread's
+     stack is at the top of address space.  Without that, things break
+     if stack is allocated above the main stack.  */
+  uintptr_t adj = (uintptr_t) self->stackblock + self->stackblock_size;
+  uintptr_t targetframe_adj = (uintptr_t) targetframe - adj;
+
+  for (cbuf = THREAD_GETMEM (self, cleanup);
+       cbuf != NULL && _JMPBUF_UNWINDS_ADJ (target, cbuf, adj);
+       cbuf = cbuf->__prev)
+    {
+#if _STACK_GROWS_DOWN
+      if ((uintptr_t) cbuf - adj <= targetframe_adj)
+        {
+          cbuf = NULL;
+          break;
+        }
+#elif _STACK_GROWS_UP
+      if ((uintptr_t) cbuf - adj >= targetframe_adj)
+        {
+          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);
+}
+hidden_def (__pthread_cleanup_upto)
diff --git a/libpthread/nptl/pt-system.c b/libpthread/nptl/pt-system.c
new file mode 100644 (file)
index 0000000..4728a7c
--- /dev/null
@@ -0,0 +1,36 @@
+/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <sysdep.h>
+#include "pthreadP.h"
+
+extern __typeof(system) __libc_system;
+#include <system.c>
+
+
+int
+system (const char *line)
+{
+  return __libc_system (line);
+}
+
+/* __libc_system in libc.so handles cancellation.  */
+LIBC_CANCEL_HANDLED ();
diff --git a/libpthread/nptl/pthread-errnos.sym b/libpthread/nptl/pthread-errnos.sym
new file mode 100644 (file)
index 0000000..0975b7a
--- /dev/null
@@ -0,0 +1,13 @@
+#include <errno.h>
+
+-- These errno codes are used by some assembly code.
+
+EAGAIN         EAGAIN
+EBUSY          EBUSY
+EDEADLK                EDEADLK
+EINTR          EINTR
+EINVAL         EINVAL
+ENOSYS         ENOSYS
+EOVERFLOW      EOVERFLOW
+ETIMEDOUT      ETIMEDOUT
+EWOULDBLOCK    EWOULDBLOCK
diff --git a/libpthread/nptl/pthreadP.h b/libpthread/nptl/pthreadP.h
new file mode 100644 (file)
index 0000000..85601d4
--- /dev/null
@@ -0,0 +1,587 @@
+/* Copyright (C) 2002-2007, 2009 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 <stdbool.h>
+#include <sys/syscall.h>
+#include "descr.h"
+#include <tls.h>
+#include <lowlevellock.h>
+#include <bits/stackinfo.h>
+#include <internaltypes.h>
+#include <pthread-functions.h>
+#include <atomic.h>
+#include <bits/kernel-features.h>
+
+
+/* Atomic operations on TLS memory.  */
+#ifndef THREAD_ATOMIC_CMPXCHG_VAL
+# define THREAD_ATOMIC_CMPXCHG_VAL(descr, member, new, old) \
+  atomic_compare_and_exchange_val_acq (&(descr)->member, new, old)
+#endif
+
+#ifndef THREAD_ATOMIC_BIT_SET
+# define THREAD_ATOMIC_BIT_SET(descr, member, bit) \
+  atomic_bit_set (&(descr)->member, bit)
+#endif
+
+
+/* Adaptive mutex definitions.  */
+#ifndef MAX_ADAPTIVE_COUNT
+# define MAX_ADAPTIVE_COUNT 100
+#endif
+
+
+/* Magic cookie representing robust mutex with dead owner.  */
+#define PTHREAD_MUTEX_INCONSISTENT     INT_MAX
+/* Magic cookie representing not recoverable robust mutex.  */
+#define PTHREAD_MUTEX_NOTRECOVERABLE   (INT_MAX - 1)
+
+
+/* Internal mutex type value.  */
+enum
+{
+  PTHREAD_MUTEX_KIND_MASK_NP = 3,
+  PTHREAD_MUTEX_ROBUST_NORMAL_NP = 16,
+  PTHREAD_MUTEX_ROBUST_RECURSIVE_NP
+  = PTHREAD_MUTEX_ROBUST_NORMAL_NP | PTHREAD_MUTEX_RECURSIVE_NP,
+  PTHREAD_MUTEX_ROBUST_ERRORCHECK_NP
+  = PTHREAD_MUTEX_ROBUST_NORMAL_NP | PTHREAD_MUTEX_ERRORCHECK_NP,
+  PTHREAD_MUTEX_ROBUST_ADAPTIVE_NP
+  = PTHREAD_MUTEX_ROBUST_NORMAL_NP | PTHREAD_MUTEX_ADAPTIVE_NP,
+  PTHREAD_MUTEX_PRIO_INHERIT_NP = 32,
+  PTHREAD_MUTEX_PI_NORMAL_NP
+  = PTHREAD_MUTEX_PRIO_INHERIT_NP | PTHREAD_MUTEX_NORMAL,
+  PTHREAD_MUTEX_PI_RECURSIVE_NP
+  = PTHREAD_MUTEX_PRIO_INHERIT_NP | PTHREAD_MUTEX_RECURSIVE_NP,
+  PTHREAD_MUTEX_PI_ERRORCHECK_NP
+  = PTHREAD_MUTEX_PRIO_INHERIT_NP | PTHREAD_MUTEX_ERRORCHECK_NP,
+  PTHREAD_MUTEX_PI_ADAPTIVE_NP
+  = PTHREAD_MUTEX_PRIO_INHERIT_NP | PTHREAD_MUTEX_ADAPTIVE_NP,
+  PTHREAD_MUTEX_PI_ROBUST_NORMAL_NP
+  = PTHREAD_MUTEX_PRIO_INHERIT_NP | PTHREAD_MUTEX_ROBUST_NORMAL_NP,
+  PTHREAD_MUTEX_PI_ROBUST_RECURSIVE_NP
+  = PTHREAD_MUTEX_PRIO_INHERIT_NP | PTHREAD_MUTEX_ROBUST_RECURSIVE_NP,
+  PTHREAD_MUTEX_PI_ROBUST_ERRORCHECK_NP
+  = PTHREAD_MUTEX_PRIO_INHERIT_NP | PTHREAD_MUTEX_ROBUST_ERRORCHECK_NP,
+  PTHREAD_MUTEX_PI_ROBUST_ADAPTIVE_NP
+  = PTHREAD_MUTEX_PRIO_INHERIT_NP | PTHREAD_MUTEX_ROBUST_ADAPTIVE_NP,
+  PTHREAD_MUTEX_PRIO_PROTECT_NP = 64,
+  PTHREAD_MUTEX_PP_NORMAL_NP
+  = PTHREAD_MUTEX_PRIO_PROTECT_NP | PTHREAD_MUTEX_NORMAL,
+  PTHREAD_MUTEX_PP_RECURSIVE_NP
+  = PTHREAD_MUTEX_PRIO_PROTECT_NP | PTHREAD_MUTEX_RECURSIVE_NP,
+  PTHREAD_MUTEX_PP_ERRORCHECK_NP
+  = PTHREAD_MUTEX_PRIO_PROTECT_NP | PTHREAD_MUTEX_ERRORCHECK_NP,
+  PTHREAD_MUTEX_PP_ADAPTIVE_NP
+  = PTHREAD_MUTEX_PRIO_PROTECT_NP | PTHREAD_MUTEX_ADAPTIVE_NP
+};
+#define PTHREAD_MUTEX_PSHARED_BIT 128
+
+#define PTHREAD_MUTEX_TYPE(m) \
+  ((m)->__data.__kind & 127)
+
+#if LLL_PRIVATE == 0 && LLL_SHARED == 128
+# define PTHREAD_MUTEX_PSHARED(m) \
+  ((m)->__data.__kind & 128)
+#else
+# define PTHREAD_MUTEX_PSHARED(m) \
+  (((m)->__data.__kind & 128) ? LLL_SHARED : LLL_PRIVATE)
+#endif
+
+/* The kernel when waking robust mutexes on exit never uses
+   FUTEX_PRIVATE_FLAG FUTEX_WAKE.  */
+#define PTHREAD_ROBUST_MUTEX_PSHARED(m) LLL_SHARED
+
+/* Ceiling in __data.__lock.  __data.__lock is signed, so don't
+   use the MSB bit in there, but in the mask also include that bit,
+   so that the compiler can optimize & PTHREAD_MUTEX_PRIO_CEILING_MASK
+   masking if the value is then shifted down by
+   PTHREAD_MUTEX_PRIO_CEILING_SHIFT.  */
+#define PTHREAD_MUTEX_PRIO_CEILING_SHIFT       19
+#define PTHREAD_MUTEX_PRIO_CEILING_MASK                0xfff80000
+
+
+/* Flags in mutex attr.  */
+#define PTHREAD_MUTEXATTR_PROTOCOL_SHIFT       28
+#define PTHREAD_MUTEXATTR_PROTOCOL_MASK                0x30000000
+#define PTHREAD_MUTEXATTR_PRIO_CEILING_SHIFT   12
+#define PTHREAD_MUTEXATTR_PRIO_CEILING_MASK    0x00fff000
+#define PTHREAD_MUTEXATTR_FLAG_ROBUST          0x40000000
+#define PTHREAD_MUTEXATTR_FLAG_PSHARED         0x80000000
+#define PTHREAD_MUTEXATTR_FLAG_BITS \
+  (PTHREAD_MUTEXATTR_FLAG_ROBUST | PTHREAD_MUTEXATTR_FLAG_PSHARED \
+   | PTHREAD_MUTEXATTR_PROTOCOL_MASK | PTHREAD_MUTEXATTR_PRIO_CEILING_MASK)
+
+
+/* Check whether rwlock prefers readers.   */
+#define PTHREAD_RWLOCK_PREFER_READER_P(rwlock) \
+  ((rwlock)->__data.__flags == 0)
+
+
+/* Bits used in robust mutex implementation.  */
+#define FUTEX_WAITERS          0x80000000
+#define FUTEX_OWNER_DIED       0x40000000
+#define FUTEX_TID_MASK         0x3fffffff
+
+
+/* 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_m1 attribute_hidden;
+
+/* Flag whether the machine is SMP or not.  */
+extern int __is_smp attribute_hidden;
+
+/* Thread descriptor handling.  */
+extern list_t __stack_user;
+hidden_proto (__stack_user)
+
+/* Attribute handling.  */
+extern struct pthread_attr *__attr_list attribute_hidden;
+extern int __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];
+hidden_proto (__pthread_keys)
+
+/* Number of threads running.  */
+extern unsigned int __nptl_nthreads attribute_hidden;
+
+#ifndef __ASSUME_SET_ROBUST_LIST
+/* Negative if we do not have the system call and we can use it.  */
+extern int __set_robust_list_avail attribute_hidden;
+#endif
+
+/* Thread Priority Protection.  */
+extern int __sched_fifo_min_prio attribute_hidden;
+extern int __sched_fifo_max_prio attribute_hidden;
+extern void __init_sched_fifo_prio (void) attribute_hidden;
+extern int __pthread_tpp_change_priority (int prev_prio, int new_prio)
+     attribute_hidden;
+extern int __pthread_current_priority (void) attribute_hidden;
+
+/* The library can run in debugging mode where it performs a lot more
+   tests.  */
+extern int __pthread_debug attribute_hidden;
+/** For now disable debugging support.  */
+#if 0
+# define DEBUGGING_P __builtin_expect (__pthread_debug, 0)
+# define INVALID_TD_P(pd) (DEBUGGING_P && __find_in_stack_list (pd) == NULL)
+# define INVALID_NOT_TERMINATED_TD_P(pd) INVALID_TD_P (pd)
+#else
+# define DEBUGGING_P 0
+/* Simplified test.  This will not catch all invalid descriptors but
+   is better than nothing.  And if the test triggers the thread
+   descriptor is guaranteed to be invalid.  */
+# define INVALID_TD_P(pd) __builtin_expect ((pd)->tid <= 0, 0)
+# define INVALID_NOT_TERMINATED_TD_P(pd) __builtin_expect ((pd)->tid < 0, 0)
+#endif
+
+
+/* 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 ();                                                       \
+      }                                                                              \
+  } while (0)
+
+
+extern void __pthread_unwind (__pthread_unwind_buf_t *__buf)
+     __cleanup_fct_attribute __attribute ((__noreturn__))
+#if !defined SHARED && !defined IS_IN_libpthread
+     weak_function
+#endif
+     ;
+extern void __pthread_unwind_next (__pthread_unwind_buf_t *__buf)
+     __cleanup_fct_attribute __attribute ((__noreturn__))
+#ifndef SHARED
+     weak_function
+#endif
+     ;
+extern void __pthread_register_cancel (__pthread_unwind_buf_t *__buf)
+     __cleanup_fct_attribute;
+extern void __pthread_unregister_cancel (__pthread_unwind_buf_t *__buf)
+     __cleanup_fct_attribute;
+#if defined NOT_IN_libc && defined IS_IN_libpthread
+hidden_proto (__pthread_unwind)
+hidden_proto (__pthread_unwind_next)
+hidden_proto (__pthread_register_cancel)
+hidden_proto (__pthread_unregister_cancel)
+# ifdef SHARED
+extern void attribute_hidden pthread_cancel_init (void);
+extern void __unwind_freeres (void);
+# endif
+#endif
+
+
+/* Called when a thread reacts on a cancellation request.  */
+static inline void
+__attribute ((noreturn, always_inline))
+__do_cancel (void)
+{
+  struct pthread *self = THREAD_SELF;
+
+  /* Make sure we get no more cancellations.  */
+  THREAD_ATOMIC_BIT_SET (self, cancelhandling, EXITING_BIT);
+
+  __pthread_unwind ((__pthread_unwind_buf_t *)
+                   THREAD_GETMEM (self, cleanup_jmp_buf));
+}
+
+
+/* Set cancellation mode to asynchronous.  */
+#define CANCEL_ASYNC() \
+  __pthread_enable_asynccancel ()
+/* Reset to previous cancellation mode.  */
+#define CANCEL_RESET(oldtype) \
+  __pthread_disable_asynccancel (oldtype)
+
+#if !defined NOT_IN_libc
+/* Same as CANCEL_ASYNC, but for use in libc.so.  */
+# define LIBC_CANCEL_ASYNC() \
+  __libc_enable_asynccancel ()
+/* Same as CANCEL_RESET, but for use in libc.so.  */
+# define LIBC_CANCEL_RESET(oldtype) \
+  __libc_disable_asynccancel (oldtype)
+# define LIBC_CANCEL_HANDLED() \
+  __asm__ (".globl " __USER_LABEL_PREFIX__ "__libc_enable_asynccancel"); \
+  __asm__ (".globl " __USER_LABEL_PREFIX__ "__libc_disable_asynccancel")
+#elif defined NOT_IN_libc && defined IS_IN_libpthread
+# define LIBC_CANCEL_ASYNC() CANCEL_ASYNC ()
+# define LIBC_CANCEL_RESET(val) CANCEL_RESET (val)
+# define LIBC_CANCEL_HANDLED() \
+  __asm__ (".globl " __USER_LABEL_PREFIX__ "__pthread_enable_asynccancel"); \
+  __asm__ (".globl " __USER_LABEL_PREFIX__ "__pthread_disable_asynccancel")
+#elif defined NOT_IN_libc && defined IS_IN_librt
+# define LIBC_CANCEL_ASYNC() \
+  __librt_enable_asynccancel ()
+# define LIBC_CANCEL_RESET(val) \
+  __librt_disable_asynccancel (val)
+# define LIBC_CANCEL_HANDLED() \
+  __asm__ (".globl " __USER_LABEL_PREFIX__ "__librt_enable_asynccancel"); \
+  __asm__ (".globl " __USER_LABEL_PREFIX__ "__librt_disable_asynccancel")
+#else
+# define LIBC_CANCEL_ASYNC()   0 /* Just a dummy value.  */
+# define LIBC_CANCEL_RESET(val)        ((void)(val)) /* Nothing, but evaluate it.  */
+# define LIBC_CANCEL_HANDLED() /* Nothing.  */
+#endif
+
+/* The signal used for asynchronous cancelation.  */
+#define SIGCANCEL      __SIGRTMIN
+
+
+/* Signal needed for the kernel-supported POSIX timer implementation.
+   We can reuse the cancellation signal since we can distinguish
+   cancellation from timer expirations.  */
+#define SIGTIMER       SIGCANCEL
+
+
+/* Signal used to implement the setuid et.al. functions.  */
+#define SIGSETXID      (__SIGRTMIN + 1)
+
+/* Used to communicate with signal handler.  */
+extern struct xid_command *__xidcmd attribute_hidden;
+
+
+/* Internal prototypes.  */
+
+/* Thread list handling.  */
+extern struct pthread *__find_in_stack_list (struct pthread *pd)
+     attribute_hidden internal_function;
+
+/* Deallocate a thread's stack after optionally making sure the thread
+   descriptor is still valid.  */
+extern void __free_tcb (struct pthread *pd) attribute_hidden internal_function;
+
+/* Free allocated stack.  */
+extern void __deallocate_stack (struct pthread *pd)
+     attribute_hidden internal_function;
+
+/* 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;
+
+/* Make all threads's stacks executable.  */
+extern int __make_stacks_executable (void **stack_endp)
+     internal_function attribute_hidden;
+
+/* longjmp handling.  */
+extern void __pthread_cleanup_upto (__jmp_buf target, char *targetframe);
+#if defined NOT_IN_libc && defined IS_IN_libpthread
+hidden_proto (__pthread_cleanup_upto)
+#endif
+
+
+/* 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);
+extern void __nptl_death_event (void);
+hidden_proto (__nptl_create_event)
+hidden_proto (__nptl_death_event)
+
+/* Register the generation counter in the libpthread with the libc.  */
+#ifdef TLS_MULTIPLE_THREADS_IN_TCB
+extern void __libc_pthread_init (unsigned long int *ptr,
+                                void (*reclaim) (void),
+                                const struct pthread_functions *functions);
+#else
+extern int *__libc_pthread_init (unsigned long int *ptr,
+                                void (*reclaim) (void),
+                                const struct pthread_functions *functions);
+
+/* Variable set to a nonzero value if more than one thread runs or ran.  */
+extern int __pthread_multiple_threads attribute_hidden;
+/* Pointer to the corresponding variable in libc.  */
+extern int *__libc_multiple_threads_ptr attribute_hidden;
+#endif
+
+/* Find a thread given its TID.  */
+extern struct pthread *__find_thread_by_id (pid_t tid) attribute_hidden
+#ifdef SHARED
+;
+#else
+weak_function;
+#define __find_thread_by_id(tid) \
+  (__find_thread_by_id ? (__find_thread_by_id) (tid) : (struct pthread *) NULL)
+#endif
+
+extern void __pthread_init_static_tls (struct link_map *) attribute_hidden;
+
+
+/* Namespace save aliases.  */
+extern int __pthread_getschedparam (pthread_t thread_id, int *policy,
+                                   struct sched_param *param);
+extern int __pthread_setschedparam (pthread_t thread_id, int policy,
+                                   const struct sched_param *param);
+extern int __pthread_setcancelstate (int state, int *oldstate);
+extern int __pthread_mutex_init (pthread_mutex_t *__mutex,
+                                __const pthread_mutexattr_t *__mutexattr);
+extern int __pthread_mutex_init_internal (pthread_mutex_t *__mutex,
+                                         __const pthread_mutexattr_t *__mutexattr)
+     attribute_hidden;
+extern int __pthread_mutex_destroy (pthread_mutex_t *__mutex);
+extern int __pthread_mutex_destroy_internal (pthread_mutex_t *__mutex)
+     attribute_hidden;
+extern int __pthread_mutex_trylock (pthread_mutex_t *_mutex);
+extern int __pthread_mutex_lock (pthread_mutex_t *__mutex);
+extern int __pthread_mutex_lock_internal (pthread_mutex_t *__mutex)
+     attribute_hidden;
+extern int __pthread_mutex_cond_lock (pthread_mutex_t *__mutex);
+extern void __pthread_mutex_cond_lock_adjust (pthread_mutex_t *__mutex);
+extern int __pthread_mutex_unlock (pthread_mutex_t *__mutex);
+extern int __pthread_mutex_unlock_internal (pthread_mutex_t *__mutex)
+     attribute_hidden;
+extern int __pthread_mutex_unlock_usercnt (pthread_mutex_t *__mutex,
+                                          int __decr)
+     attribute_hidden internal_function;
+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_destroy (pthread_attr_t *attr);
+extern int __pthread_attr_getdetachstate (const pthread_attr_t *attr,
+                                         int *detachstate);
+extern int __pthread_attr_setdetachstate (pthread_attr_t *attr,
+                                         int detachstate);
+extern int __pthread_attr_getinheritsched (const pthread_attr_t *attr,
+                                          int *inherit);
+extern int __pthread_attr_setinheritsched (pthread_attr_t *attr, int inherit);
+extern int __pthread_attr_getschedparam (const pthread_attr_t *attr,
+                                        struct sched_param *param);
+extern int __pthread_attr_setschedparam (pthread_attr_t *attr,
+                                        const struct sched_param *param);
+extern int __pthread_attr_getschedpolicy (const pthread_attr_t *attr,
+                                         int *policy);
+extern int __pthread_attr_setschedpolicy (pthread_attr_t *attr, int policy);
+extern int __pthread_attr_getscope (const pthread_attr_t *attr, int *scope);
+extern int __pthread_attr_setscope (pthread_attr_t *attr, int scope);
+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_rdlock_internal (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_wrlock_internal (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_rwlock_unlock_internal (pthread_rwlock_t *__rwlock);
+extern int __pthread_cond_broadcast (pthread_cond_t *cond);
+extern int __pthread_cond_destroy (pthread_cond_t *cond);
+extern int __pthread_cond_init (pthread_cond_t *cond,
+                               const pthread_condattr_t *cond_attr);
+extern int __pthread_cond_signal (pthread_cond_t *cond);
+extern int __pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex);
+extern int __pthread_cond_timedwait (pthread_cond_t *cond,
+                                    pthread_mutex_t *mutex,
+                                    const struct timespec *abstime);
+extern int __pthread_condattr_destroy (pthread_condattr_t *attr);
+extern int __pthread_condattr_init (pthread_condattr_t *attr);
+extern int __pthread_key_create (pthread_key_t *key, void (*destr) (void *));
+extern int __pthread_key_create_internal (pthread_key_t *key,
+                                         void (*destr) (void *));
+extern void *__pthread_getspecific (pthread_key_t key);
+extern void *__pthread_getspecific_internal (pthread_key_t key);
+extern int __pthread_setspecific (pthread_key_t key, const void *value);
+extern int __pthread_setspecific_internal (pthread_key_t key,
+                                          const void *value);
+extern int __pthread_once (pthread_once_t *once_control,
+                          void (*init_routine) (void));
+extern int __pthread_once_internal (pthread_once_t *once_control,
+                                   void (*init_routine) (void));
+extern int __pthread_atfork (void (*prepare) (void), void (*parent) (void),
+                            void (*child) (void));
+extern pthread_t __pthread_self (void);
+extern int __pthread_equal (pthread_t thread1, pthread_t thread2);
+extern int __pthread_kill (pthread_t threadid, int signo);
+extern void __pthread_exit (void *value);
+extern int __pthread_setcanceltype (int type, int *oldtype);
+extern int __pthread_enable_asynccancel (void) attribute_hidden;
+extern void __pthread_disable_asynccancel (int oldtype)
+     internal_function attribute_hidden;
+
+extern int __pthread_cond_broadcast_2_0 (pthread_cond_2_0_t *cond);
+extern int __pthread_cond_destroy_2_0 (pthread_cond_2_0_t *cond);
+extern int __pthread_cond_init_2_0 (pthread_cond_2_0_t *cond,
+                                   const pthread_condattr_t *cond_attr);
+extern int __pthread_cond_signal_2_0 (pthread_cond_2_0_t *cond);
+extern int __pthread_cond_timedwait_2_0 (pthread_cond_2_0_t *cond,
+                                        pthread_mutex_t *mutex,
+                                        const struct timespec *abstime);
+extern int __pthread_cond_wait_2_0 (pthread_cond_2_0_t *cond,
+                                   pthread_mutex_t *mutex);
+
+extern int __pthread_getaffinity_np (pthread_t th, size_t cpusetsize,
+                                    cpu_set_t *cpuset);
+
+/* The two functions are in libc.so and not exported.  */
+extern int __libc_enable_asynccancel (void) attribute_hidden;
+extern void __libc_disable_asynccancel (int oldtype)
+     internal_function attribute_hidden;
+
+
+/* The two functions are in librt.so and not exported.  */
+extern int __librt_enable_asynccancel (void) attribute_hidden;
+extern void __librt_disable_asynccancel (int oldtype)
+     internal_function attribute_hidden;
+
+#ifdef IS_IN_libpthread
+/* Special versions which use non-exported functions.  */
+extern void __pthread_cleanup_push (struct _pthread_cleanup_buffer *buffer,
+                                   void (*routine) (void *), void *arg)
+     attribute_hidden;
+# undef pthread_cleanup_push
+# define pthread_cleanup_push(routine,arg) \
+  { struct _pthread_cleanup_buffer _buffer;                                  \
+    __pthread_cleanup_push (&_buffer, (routine), (arg));
+
+extern void __pthread_cleanup_pop (struct _pthread_cleanup_buffer *buffer,
+                                  int execute) attribute_hidden;
+# undef pthread_cleanup_pop
+# define pthread_cleanup_pop(execute) \
+    __pthread_cleanup_pop (&_buffer, (execute)); }
+#endif
+
+extern void __pthread_cleanup_push_defer (struct _pthread_cleanup_buffer *buffer,
+                                         void (*routine) (void *), void *arg);
+extern void __pthread_cleanup_pop_restore (struct _pthread_cleanup_buffer *buffer,
+                                          int execute);
+
+/* Old cleanup interfaces, still used in libc.so.  */
+extern void _pthread_cleanup_push (struct _pthread_cleanup_buffer *buffer,
+                                   void (*routine) (void *), void *arg);
+extern void _pthread_cleanup_pop (struct _pthread_cleanup_buffer *buffer,
+                                  int execute);
+extern void _pthread_cleanup_push_defer (struct _pthread_cleanup_buffer *buffer,
+                                         void (*routine) (void *), void *arg);
+extern void _pthread_cleanup_pop_restore (struct _pthread_cleanup_buffer *buffer,
+                                          int execute);
+
+extern void __nptl_deallocate_tsd (void) attribute_hidden;
+
+extern int __nptl_setxid (struct xid_command *cmdp) attribute_hidden;
+
+extern void __free_stacks (size_t limit) attribute_hidden;
+
+extern void __wait_lookup_done (void) attribute_hidden;
+
+#ifdef SHARED
+# define PTHREAD_STATIC_FN_REQUIRE(name)
+#else
+# define PTHREAD_STATIC_FN_REQUIRE(name) __asm__ (".globl " #name);
+#endif
+
+
+#ifndef __NR_set_robust_list
+/* XXX For the time being...  Once we can rely on the kernel headers
+   having the definition remove these lines.  */
+# if defined __i386__
+#  define __NR_set_robust_list  311
+# elif defined __x86_64__
+#  define __NR_set_robust_list  273
+# endif
+#endif
+
+#endif /* pthreadP.h */
diff --git a/libpthread/nptl/pthread_atfork.c b/libpthread/nptl/pthread_atfork.c
new file mode 100644 (file)
index 0000000..e607d49
--- /dev/null
@@ -0,0 +1,56 @@
+/* Copyright (C) 2002, 2006 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   In addition to the permissions in the GNU Lesser General Public
+   License, the Free Software Foundation gives you unlimited
+   permission to link the compiled version of this file with other
+   programs, and to distribute those programs without any restriction
+   coming from the use of this file. (The GNU Lesser General Public
+   License restrictions do apply in other respects; for example, they
+   cover modification of the file, and distribution when not linked
+   into another program.)
+
+   Note that people who make modified versions of this file are not
+   obligated to grant this special exception for their modified
+   versions; it is their choice whether to do so. The GNU Lesser
+   General Public License gives permission to release a modified
+   version without this exception; this exception also makes it
+   possible to release a modified version which carries forward this
+   exception.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+#include <fork.h>
+
+/* This is defined by newer gcc version unique for each module.  */
+extern void *__dso_handle __attribute__ ((__weak__));
+                                         //,__visibility__ ("hidden")));
+
+
+/* Hide the symbol so that no definition but the one locally in the
+   executable or DSO is used.  */
+int
+__pthread_atfork (
+     void (*prepare) (void),
+     void (*parent) (void),
+     void (*child) (void))
+{
+  return __register_atfork (prepare, parent, child,
+                           &__dso_handle == NULL ? NULL : __dso_handle);
+}
+strong_alias (__pthread_atfork, pthread_atfork)
diff --git a/libpthread/nptl/pthread_attr_destroy.c b/libpthread/nptl/pthread_attr_destroy.c
new file mode 100644 (file)
index 0000000..b8e6a37
--- /dev/null
@@ -0,0 +1,40 @@
+/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include "pthreadP.h"
+
+int
+__pthread_attr_destroy (
+     pthread_attr_t *attr)
+{
+  struct pthread_attr *iattr;
+
+  assert (sizeof (*attr) >= sizeof (struct pthread_attr));
+  iattr = (struct pthread_attr *) attr;
+
+  /* The affinity CPU set might be allocated dynamically.  */
+  free (iattr->cpuset);
+
+  return 0;
+}
+strong_alias (__pthread_attr_destroy, pthread_attr_destroy)
diff --git a/libpthread/nptl/pthread_attr_getdetachstate.c b/libpthread/nptl/pthread_attr_getdetachstate.c
new file mode 100644 (file)
index 0000000..5f549ba
--- /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_getdetachstate (
+     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;
+}
+strong_alias (__pthread_attr_getdetachstate, pthread_attr_getdetachstate)
diff --git a/libpthread/nptl/pthread_attr_getguardsize.c b/libpthread/nptl/pthread_attr_getguardsize.c
new file mode 100644 (file)
index 0000000..6fc3e6a
--- /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 <assert.h>
+#include "pthreadP.h"
+
+
+int
+pthread_attr_getguardsize (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/libpthread/nptl/pthread_attr_getinheritsched.c b/libpthread/nptl/pthread_attr_getinheritsched.c
new file mode 100644 (file)
index 0000000..3ff3040
--- /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_getinheritsched (
+     const pthread_attr_t *attr,
+     int *inherit)
+{
+  struct pthread_attr *iattr;
+
+  assert (sizeof (*attr) >= sizeof (struct pthread_attr));
+  iattr = (struct pthread_attr *) attr;
+
+  /* Store the current values.  */
+  *inherit = (iattr->flags & ATTR_FLAG_NOTINHERITSCHED
+             ? PTHREAD_EXPLICIT_SCHED : PTHREAD_INHERIT_SCHED);
+
+  return 0;
+}
+strong_alias (__pthread_attr_getinheritsched, pthread_attr_getinheritsched)
diff --git a/libpthread/nptl/pthread_attr_getschedparam.c b/libpthread/nptl/pthread_attr_getschedparam.c
new file mode 100644 (file)
index 0000000..82b2371
--- /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 <string.h>
+#include "pthreadP.h"
+
+
+int
+__pthread_attr_getschedparam (
+        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;
+}
+strong_alias (__pthread_attr_getschedparam, pthread_attr_getschedparam)
diff --git a/libpthread/nptl/pthread_attr_getschedpolicy.c b/libpthread/nptl/pthread_attr_getschedpolicy.c
new file mode 100644 (file)
index 0000000..7b8f1de
--- /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_getschedpolicy (
+     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;
+}
+strong_alias (__pthread_attr_getschedpolicy, pthread_attr_getschedpolicy)
diff --git a/libpthread/nptl/pthread_attr_getscope.c b/libpthread/nptl/pthread_attr_getscope.c
new file mode 100644 (file)
index 0000000..9b05ffa
--- /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_getscope (
+     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;
+}
+strong_alias (__pthread_attr_getscope, pthread_attr_getscope)
diff --git a/libpthread/nptl/pthread_attr_getstack.c b/libpthread/nptl/pthread_attr_getstack.c
new file mode 100644 (file)
index 0000000..cb74536
--- /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 (
+     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/libpthread/nptl/pthread_attr_getstackaddr.c b/libpthread/nptl/pthread_attr_getstackaddr.c
new file mode 100644 (file)
index 0000000..305910c
--- /dev/null
@@ -0,0 +1,45 @@
+/* Copyright (C) 2002, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <assert.h>
+#include <errno.h>
+#include "pthreadP.h"
+
+
+int
+__pthread_attr_getstackaddr (
+     const pthread_attr_t *attr,
+     void **stackaddr)
+{
+  struct pthread_attr *iattr;
+
+  assert (sizeof (*attr) >= sizeof (struct pthread_attr));
+  iattr = (struct pthread_attr *) attr;
+
+  /* Some code assumes this function to work even if no stack address
+     has been set.  Let them figure it out for themselves what the
+     value means.  Simply 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/libpthread/nptl/pthread_attr_getstacksize.c b/libpthread/nptl/pthread_attr_getstacksize.c
new file mode 100644 (file)
index 0000000..ec20f6b
--- /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 (
+     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/libpthread/nptl/pthread_attr_init.c b/libpthread/nptl/pthread_attr_init.c
new file mode 100644 (file)
index 0000000..65ce4e5
--- /dev/null
@@ -0,0 +1,50 @@
+/* Copyright (C) 2002, 2003, 2004, 2007 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"
+
+
+struct pthread_attr *__attr_list;
+int __attr_list_lock = LLL_LOCK_INITIALIZER;
+
+
+int
+__pthread_attr_init_2_1 (
+     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 ();
+
+  return 0;
+}
+weak_alias(__pthread_attr_init_2_1, pthread_attr_init)
diff --git a/libpthread/nptl/pthread_attr_setdetachstate.c b/libpthread/nptl/pthread_attr_setdetachstate.c
new file mode 100644 (file)
index 0000000..b6d9bb5
--- /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_setdetachstate (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;
+}
+strong_alias (__pthread_attr_setdetachstate, pthread_attr_setdetachstate)
diff --git a/libpthread/nptl/pthread_attr_setguardsize.c b/libpthread/nptl/pthread_attr_setguardsize.c
new file mode 100644 (file)
index 0000000..a424312
--- /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_setguardsize (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/libpthread/nptl/pthread_attr_setinheritsched.c b/libpthread/nptl/pthread_attr_setinheritsched.c
new file mode 100644 (file)
index 0000000..9d0234a
--- /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_setinheritsched (
+     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;
+}
+strong_alias (__pthread_attr_setinheritsched, pthread_attr_setinheritsched)
diff --git a/libpthread/nptl/pthread_attr_setschedparam.c b/libpthread/nptl/pthread_attr_setschedparam.c
new file mode 100644 (file)
index 0000000..741e641
--- /dev/null
@@ -0,0 +1,48 @@
+/* Copyright (C) 2002, 2004, 2009 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 (
+     pthread_attr_t *attr,
+     const struct sched_param *param)
+{
+  assert (sizeof (*attr) >= sizeof (struct pthread_attr));
+  struct pthread_attr *iattr = (struct pthread_attr *) attr;
+
+  int min = sched_get_priority_min (iattr->schedpolicy);
+  int max = sched_get_priority_max (iattr->schedpolicy);
+  if (min == -1 || max == -1
+      || param->sched_priority > max || param->sched_priority < min)
+    return EINVAL;
+
+  /* Copy the new values.  */
+  memcpy (&iattr->schedparam, param, sizeof (struct sched_param));
+
+  /* Remember we set the value.  */
+  iattr->flags |= ATTR_FLAG_SCHED_SET;
+
+  return 0;
+}
+strong_alias (__pthread_attr_setschedparam, pthread_attr_setschedparam)
diff --git a/libpthread/nptl/pthread_attr_setschedpolicy.c b/libpthread/nptl/pthread_attr_setschedpolicy.c
new file mode 100644 (file)
index 0000000..1d87b53
--- /dev/null
@@ -0,0 +1,47 @@
+/* Copyright (C) 2002, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <assert.h>
+#include <errno.h>
+#include "pthreadP.h"
+
+
+int
+__pthread_attr_setschedpolicy (
+     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;
+
+  /* Remember we set the value.  */
+  iattr->flags |= ATTR_FLAG_POLICY_SET;
+
+  return 0;
+}
+strong_alias (__pthread_attr_setschedpolicy, pthread_attr_setschedpolicy)
diff --git a/libpthread/nptl/pthread_attr_setscope.c b/libpthread/nptl/pthread_attr_setscope.c
new file mode 100644 (file)
index 0000000..cc4e467
--- /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 <assert.h>
+#include <errno.h>
+#include "pthreadP.h"
+
+
+int
+__pthread_attr_setscope (
+     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;
+}
+strong_alias (__pthread_attr_setscope, pthread_attr_setscope)
diff --git a/libpthread/nptl/pthread_attr_setstack.c b/libpthread/nptl/pthread_attr_setstack.c
new file mode 100644 (file)
index 0000000..d400f3d
--- /dev/null
@@ -0,0 +1,56 @@
+/* Copyright (C) 2002, 2003, 2006 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 (
+     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;
+
+#ifdef EXTRA_PARAM_CHECKS
+  EXTRA_PARAM_CHECKS;
+#endif
+
+  iattr->stacksize = stacksize;
+  iattr->stackaddr = (char *) stackaddr + stacksize;
+  iattr->flags |= ATTR_FLAG_STACKADDR;
+
+  return 0;
+}
+
+#if PTHREAD_STACK_MIN == 16384
+strong_alias(__pthread_attr_setstack, pthread_attr_setstack)
+#else
+weak_alias(__pthread_attr_setstack, pthread_attr_setstack)
+#endif
diff --git a/libpthread/nptl/pthread_attr_setstackaddr.c b/libpthread/nptl/pthread_attr_setstackaddr.c
new file mode 100644 (file)
index 0000000..ead54ba
--- /dev/null
@@ -0,0 +1,47 @@
+/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <assert.h>
+#include <errno.h>
+#include "pthreadP.h"
+
+
+int
+__pthread_attr_setstackaddr (
+     pthread_attr_t *attr,
+     void *stackaddr)
+{
+  struct pthread_attr *iattr;
+
+#ifdef EXTRA_PARAM_CHECKS
+  EXTRA_PARAM_CHECKS;
+#endif
+
+  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/libpthread/nptl/pthread_attr_setstacksize.c b/libpthread/nptl/pthread_attr_setstacksize.c
new file mode 100644 (file)
index 0000000..24e5b0a
--- /dev/null
@@ -0,0 +1,49 @@
+/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include "pthreadP.h"
+
+
+int
+__pthread_attr_setstacksize (
+     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;
+}
+
+#if PTHREAD_STACK_MIN == 16384
+strong_alias(__pthread_attr_setstacksize, pthread_attr_setstacksize)
+#else
+weak_alias(__pthread_attr_setstacksize, pthread_attr_setstacksize)
+#endif
diff --git a/libpthread/nptl/pthread_barrierattr_destroy.c b/libpthread/nptl/pthread_barrierattr_destroy.c
new file mode 100644 (file)
index 0000000..5cdcb76
--- /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_barrierattr_destroy (pthread_barrierattr_t *attr)
+{
+  /* Nothing to do.  */
+
+  return 0;
+}
diff --git a/libpthread/nptl/pthread_barrierattr_getpshared.c b/libpthread/nptl/pthread_barrierattr_getpshared.c
new file mode 100644 (file)
index 0000000..ee96c02
--- /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_barrierattr_getpshared (
+     const pthread_barrierattr_t *attr,
+     int *pshared)
+{
+  *pshared = ((const struct pthread_barrierattr *) attr)->pshared;
+
+  return 0;
+}
diff --git a/libpthread/nptl/pthread_barrierattr_init.c b/libpthread/nptl/pthread_barrierattr_init.c
new file mode 100644 (file)
index 0000000..17391f9
--- /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_barrierattr_init (pthread_barrierattr_t *attr)
+{
+  ((struct pthread_barrierattr *) attr)->pshared = PTHREAD_PROCESS_PRIVATE;
+
+  return 0;
+}
diff --git a/libpthread/nptl/pthread_barrierattr_setpshared.c b/libpthread/nptl/pthread_barrierattr_setpshared.c
new file mode 100644 (file)
index 0000000..fbf6fcb
--- /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_barrierattr_setpshared (
+     pthread_barrierattr_t *attr,
+     int pshared)
+{
+  struct pthread_barrierattr *iattr;
+
+  if (pshared != PTHREAD_PROCESS_PRIVATE
+      && __builtin_expect (pshared != PTHREAD_PROCESS_SHARED, 0))
+    return EINVAL;
+
+  iattr = (struct pthread_barrierattr *) attr;
+
+  iattr->pshared = pshared;
+
+  return 0;
+}
diff --git a/libpthread/nptl/pthread_cancel.c b/libpthread/nptl/pthread_cancel.c
new file mode 100644 (file)
index 0000000..4a958bc
--- /dev/null
@@ -0,0 +1,108 @@
+/* Copyright (C) 2002, 2003, 2004, 2009 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <signal.h>
+#include "pthreadP.h"
+#include "atomic.h"
+#include <sysdep.h>
+#include <bits/kernel-features.h>
+
+
+int
+pthread_cancel (
+     pthread_t th)
+{
+  volatile struct pthread *pd = (volatile struct pthread *) th;
+
+  /* Make sure the descriptor is valid.  */
+  if (INVALID_TD_P (pd))
+    /* Not a valid thread handle.  */
+    return ESRCH;
+
+#ifdef SHARED
+  pthread_cancel_init ();
+#endif
+  int result = 0;
+  int oldval;
+  int newval;
+  do
+    {
+    again:
+      oldval = pd->cancelhandling;
+      newval = oldval | CANCELING_BITMASK | CANCELED_BITMASK;
+
+      /* Avoid doing unnecessary work.  The atomic operation can
+        potentially be expensive if the bug has to be locked and
+        remote cache lines have to be invalidated.  */
+      if (oldval == newval)
+       break;
+
+      /* If the cancellation is handled asynchronously just send a
+        signal.  We avoid this if possible since it's more
+        expensive.  */
+      if (CANCEL_ENABLED_AND_CANCELED_AND_ASYNCHRONOUS (newval))
+       {
+         /* Mark the cancellation as "in progress".  */
+         if (atomic_compare_and_exchange_bool_acq (&pd->cancelhandling,
+                                                   oldval | CANCELING_BITMASK,
+                                                   oldval))
+           goto again;
+
+         /* The cancellation handler will take care of marking the
+            thread as canceled.  */
+         INTERNAL_SYSCALL_DECL (err);
+
+         /* One comment: The PID field in the TCB can temporarily be
+            changed (in fork).  But this must not affect this code
+            here.  Since this function would have to be called while
+            the thread is executing fork, it would have to happen in
+            a signal handler.  But this is no allowed, pthread_cancel
+            is not guaranteed to be async-safe.  */
+         int val;
+#if __ASSUME_TGKILL
+         val = INTERNAL_SYSCALL (tgkill, err, 3,
+                                 THREAD_GETMEM (THREAD_SELF, pid), pd->tid,
+                                 SIGCANCEL);
+#else
+# ifdef __NR_tgkill
+         val = INTERNAL_SYSCALL (tgkill, err, 3,
+                                 THREAD_GETMEM (THREAD_SELF, pid), pd->tid,
+                                 SIGCANCEL);
+         if (INTERNAL_SYSCALL_ERROR_P (val, err)
+             && INTERNAL_SYSCALL_ERRNO (val, err) == ENOSYS)
+# endif
+           val = INTERNAL_SYSCALL (tkill, err, 2, pd->tid, SIGCANCEL);
+#endif
+
+         if (INTERNAL_SYSCALL_ERROR_P (val, err))
+           result = INTERNAL_SYSCALL_ERRNO (val, err);
+
+         break;
+       }
+    }
+  /* Mark the thread as canceled.  This has to be done
+     atomically since other bits could be modified as well.  */
+  while (atomic_compare_and_exchange_bool_acq (&pd->cancelhandling, newval,
+                                              oldval));
+
+  return result;
+}
+
+PTHREAD_STATIC_FN_REQUIRE (pthread_create)
diff --git a/libpthread/nptl/pthread_clock_gettime.c b/libpthread/nptl/pthread_clock_gettime.c
new file mode 100644 (file)
index 0000000..a71174c
--- /dev/null
@@ -0,0 +1,69 @@
+/* Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <time.h>
+#include <libc-internal.h>
+#include "pthreadP.h"
+
+
+#if HP_TIMING_AVAIL
+int
+__pthread_clock_gettime (clockid_t clock_id, hp_timing_t freq,
+                        struct timespec *tp)
+{
+  hp_timing_t tsc;
+
+  /* Get the current counter.  */
+  HP_TIMING_NOW (tsc);
+
+  /* This is the ID of the thread we are looking for.  */
+  pid_t tid = ((unsigned int) clock_id) >> CLOCK_IDFIELD_SIZE;
+
+  /* Compute the offset since the start time of the process.  */
+  if (tid == 0 || tid == THREAD_GETMEM (THREAD_SELF, tid))
+    /* Our own clock.  */
+    tsc -= THREAD_GETMEM (THREAD_SELF, cpuclock_offset);
+  else
+    {
+      /* This is more complicated.  We have to locate the thread based
+        on the ID.  This means walking the list of existing
+        threads.  */
+      struct pthread *thread = __find_thread_by_id (tid);
+      if (thread == NULL)
+       {
+         __set_errno (EINVAL);
+         return -1;
+       }
+
+      /* There is a race here.  The thread might terminate and the stack
+        become unusable.  But this is the user's problem.  */
+      tsc -= thread->cpuclock_offset;
+    }
+
+  /* Compute the seconds.  */
+  tp->tv_sec = tsc / freq;
+
+  /* And the nanoseconds.  This computation should be stable until
+     we get machines with about 16GHz frequency.  */
+  tp->tv_nsec = ((tsc % freq) * 1000000000ull) / freq;
+
+  return 0;
+}
+#endif
diff --git a/libpthread/nptl/pthread_clock_settime.c b/libpthread/nptl/pthread_clock_settime.c
new file mode 100644 (file)
index 0000000..61002a8
--- /dev/null
@@ -0,0 +1,56 @@
+/* Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <time.h>
+#include <libc-internal.h>
+#include "pthreadP.h"
+
+
+#if HP_TIMING_AVAIL
+int
+__pthread_clock_settime (clockid_t clock_id, hp_timing_t offset)
+{
+  /* This is the ID of the thread we are looking for.  */
+  pid_t tid = ((unsigned int) clock_id) >> CLOCK_IDFIELD_SIZE;
+
+  /* Compute the offset since the start time of the process.  */
+  if (tid == 0 || tid == THREAD_GETMEM (THREAD_SELF, tid))
+    /* Our own clock.  */
+    THREAD_SETMEM (THREAD_SELF, cpuclock_offset, offset);
+  else
+    {
+      /* This is more complicated.  We have to locate the thread based
+        on the ID.  This means walking the list of existing
+        threads.  */
+      struct pthread *thread = __find_thread_by_id (tid);
+      if (thread == NULL)
+       {
+         __set_errno (EINVAL);
+         return -1;
+       }
+
+      /* There is a race here.  The thread might terminate and the stack
+        become unusable.  But this is the user's problem.  */
+      thread->cpuclock_offset = offset;
+    }
+
+  return 0;
+}
+#endif
diff --git a/libpthread/nptl/pthread_cond_destroy.c b/libpthread/nptl/pthread_cond_destroy.c
new file mode 100644 (file)
index 0000000..b67b535
--- /dev/null
@@ -0,0 +1,83 @@
+/* Copyright (C) 2002, 2003, 2004, 2007 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 (
+     pthread_cond_t *cond)
+{
+  int pshared = (cond->__data.__mutex == (void *) ~0l)
+               ? LLL_SHARED : LLL_PRIVATE;
+
+  /* Make sure we are alone.  */
+  lll_lock (cond->__data.__lock, pshared);
+
+  if (cond->__data.__total_seq > cond->__data.__wakeup_seq)
+    {
+      /* If there are still some waiters which have not been
+        woken up, this is an application bug.  */
+      lll_unlock (cond->__data.__lock, pshared);
+      return EBUSY;
+    }
+
+  /* Tell pthread_cond_*wait that this condvar is being destroyed.  */
+  cond->__data.__total_seq = -1ULL;
+
+  /* If there are waiters which have been already signalled or
+     broadcasted, but still are using the pthread_cond_t structure,
+     pthread_cond_destroy needs to wait for them.  */
+  unsigned int nwaiters = cond->__data.__nwaiters;
+
+  if (nwaiters >= (1 << COND_NWAITERS_SHIFT))
+    {
+      /* Wake everybody on the associated mutex in case there are
+         threads that have been requeued to it.
+         Without this, pthread_cond_destroy could block potentially
+         for a long time or forever, as it would depend on other
+         thread's using the mutex.
+         When all threads waiting on the mutex are woken up, pthread_cond_wait
+         only waits for threads to acquire and release the internal
+         condvar lock.  */
+      if (cond->__data.__mutex != NULL
+         && cond->__data.__mutex != (void *) ~0l)
+       {
+         pthread_mutex_t *mut = (pthread_mutex_t *) cond->__data.__mutex;
+         lll_futex_wake (&mut->__data.__lock, INT_MAX,
+                         PTHREAD_MUTEX_PSHARED (mut));
+       }
+
+      do
+       {
+         lll_unlock (cond->__data.__lock, pshared);
+
+         lll_futex_wait (&cond->__data.__nwaiters, nwaiters, pshared);
+
+         lll_lock (cond->__data.__lock, pshared);
+
+         nwaiters = cond->__data.__nwaiters;
+       }
+      while (nwaiters >= (1 << COND_NWAITERS_SHIFT));
+    }
+
+  return 0;
+}
+weak_alias(__pthread_cond_destroy, pthread_cond_destroy)
diff --git a/libpthread/nptl/pthread_cond_init.c b/libpthread/nptl/pthread_cond_init.c
new file mode 100644 (file)
index 0000000..dec6444
--- /dev/null
@@ -0,0 +1,46 @@
+/* Copyright (C) 2002, 2003, 2004, 2005, 2007, 2008
+   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 (
+     pthread_cond_t *cond,
+     const pthread_condattr_t *cond_attr)
+{
+  struct pthread_condattr *icond_attr = (struct pthread_condattr *) cond_attr;
+
+  cond->__data.__lock = LLL_LOCK_INITIALIZER;
+  cond->__data.__futex = 0;
+  cond->__data.__nwaiters = (icond_attr != NULL
+                            ? ((icond_attr->value >> 1)
+                               & ((1 << COND_NWAITERS_SHIFT) - 1))
+                            : CLOCK_REALTIME);
+  cond->__data.__total_seq = 0;
+  cond->__data.__wakeup_seq = 0;
+  cond->__data.__woken_seq = 0;
+  cond->__data.__mutex = (icond_attr == NULL || (icond_attr->value & 1) == 0
+                         ? NULL : (void *) ~0l);
+  cond->__data.__broadcast_seq = 0;
+
+  return 0;
+}
+weak_alias(__pthread_cond_init, pthread_cond_init)
diff --git a/libpthread/nptl/pthread_condattr_destroy.c b/libpthread/nptl/pthread_condattr_destroy.c
new file mode 100644 (file)
index 0000000..bdb6441
--- /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 (pthread_condattr_t *attr)
+{
+  /* Nothing to be done.  */
+  return 0;
+}
+strong_alias (__pthread_condattr_destroy, pthread_condattr_destroy)
diff --git a/libpthread/nptl/pthread_condattr_getclock.c b/libpthread/nptl/pthread_condattr_getclock.c
new file mode 100644 (file)
index 0000000..3603f84
--- /dev/null
@@ -0,0 +1,31 @@
+/* Copyright (C) 2003, 2004, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+
+
+int
+pthread_condattr_getclock (
+     const pthread_condattr_t *attr,
+     clockid_t *clock_id)
+{
+  *clock_id = (((((const struct pthread_condattr *) attr)->value) >> 1)
+              & ((1 << COND_NWAITERS_SHIFT) - 1));
+  return 0;
+}
diff --git a/libpthread/nptl/pthread_condattr_getpshared.c b/libpthread/nptl/pthread_condattr_getpshared.c
new file mode 100644 (file)
index 0000000..a558fdb
--- /dev/null
@@ -0,0 +1,31 @@
+/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+
+
+int
+pthread_condattr_getpshared (
+     const pthread_condattr_t *attr,
+     int *pshared)
+{
+  *pshared = ((const struct pthread_condattr *) attr)->value & 1;
+
+  return 0;
+}
diff --git a/libpthread/nptl/pthread_condattr_init.c b/libpthread/nptl/pthread_condattr_init.c
new file mode 100644 (file)
index 0000000..d22ca1e
--- /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 (pthread_condattr_t *attr)
+{
+  memset (attr, '\0', sizeof (*attr));
+
+  return 0;
+}
+strong_alias (__pthread_condattr_init, pthread_condattr_init)
diff --git a/libpthread/nptl/pthread_condattr_setclock.c b/libpthread/nptl/pthread_condattr_setclock.c
new file mode 100644 (file)
index 0000000..87597c8
--- /dev/null
@@ -0,0 +1,73 @@
+/* Copyright (C) 2003, 2004, 2007, 2008 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <time.h>
+#include <sysdep.h>
+#include "pthreadP.h"
+#include <bits/kernel-features.h>
+
+
+int
+pthread_condattr_setclock (
+     pthread_condattr_t *attr,
+     clockid_t clock_id)
+{
+  /* Only a few clocks are allowed.  CLOCK_REALTIME is always allowed.
+     CLOCK_MONOTONIC only if the kernel has the necessary support.  */
+  if (clock_id == CLOCK_MONOTONIC)
+    {
+#ifndef __ASSUME_POSIX_TIMERS
+# ifdef __NR_clock_getres
+      /* Check whether the clock is available.  */
+      static int avail;
+
+      if (avail == 0)
+       {
+         struct timespec ts;
+
+         INTERNAL_SYSCALL_DECL (err);
+         int val;
+         val = INTERNAL_SYSCALL (clock_getres, err, 2, CLOCK_MONOTONIC, &ts);
+         avail = INTERNAL_SYSCALL_ERROR_P (val, err) ? -1 : 1;
+       }
+
+      if (avail < 0)
+# endif
+       /* Not available.  */
+       return EINVAL;
+#endif
+    }
+  else if (clock_id != CLOCK_REALTIME)
+    /* If more clocks are allowed some day the storing of the clock ID
+       in the pthread_cond_t structure needs to be adjusted.  */
+    return EINVAL;
+
+  /* Make sure the value fits in the bits we reserved.  */
+  assert (clock_id < (1 << COND_NWAITERS_SHIFT));
+
+  int *valuep = &((struct pthread_condattr *) attr)->value;
+
+  *valuep = ((*valuep & ~(((1 << COND_NWAITERS_SHIFT) - 1) << 1))
+            | (clock_id << 1));
+
+  return 0;
+}
diff --git a/libpthread/nptl/pthread_condattr_setpshared.c b/libpthread/nptl/pthread_condattr_setpshared.c
new file mode 100644 (file)
index 0000000..f3d39aa
--- /dev/null
@@ -0,0 +1,37 @@
+/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthreadP.h>
+
+int
+pthread_condattr_setpshared (
+     pthread_condattr_t *attr,
+     int pshared)
+{
+  if (pshared != PTHREAD_PROCESS_PRIVATE
+      && __builtin_expect (pshared != PTHREAD_PROCESS_SHARED, 0))
+    return EINVAL;
+
+  int *valuep = &((struct pthread_condattr *) attr)->value;
+
+  *valuep = (*valuep & ~1) | (pshared != PTHREAD_PROCESS_PRIVATE);
+
+  return 0;
+}
diff --git a/libpthread/nptl/pthread_create.c b/libpthread/nptl/pthread_create.c
new file mode 100644 (file)
index 0000000..8b53cb1
--- /dev/null
@@ -0,0 +1,586 @@
+/* Copyright (C) 2002-2007,2008,2009 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include "pthreadP.h"
+#include <hp-timing.h>
+#include <ldsodefs.h>
+#include <atomic.h>
+#include <libc-internal.h>
+#include <resolv.h>
+#include <bits/kernel-features.h>
+
+
+/* Local function to start thread and handle cleanup.  */
+static int start_thread (void *arg);
+
+
+/* Nozero if debugging mode is enabled.  */
+int __pthread_debug;
+
+/* Globally enabled events.  */
+static td_thr_events_t __nptl_threads_events __attribute_used__;
+
+/* Pointer to descriptor with the last event.  */
+static struct pthread *__nptl_last_event __attribute_used__;
+
+/* Number of threads running.  */
+unsigned int __nptl_nthreads = 1;
+
+
+/* Code to allocate and deallocate a stack.  */
+#include "allocatestack.c"
+
+/* Code to create the thread.  */
+#include <createthread.c>
+
+
+struct pthread *
+internal_function
+__find_in_stack_list (
+     struct pthread *pd)
+{
+  list_t *entry;
+  struct pthread *result = NULL;
+
+  lll_lock (stack_cache_lock, LLL_PRIVATE);
+
+  list_for_each (entry, &stack_used)
+    {
+      struct pthread *curp;
+
+      curp = list_entry (entry, struct pthread, list);
+      if (curp == pd)
+       {
+         result = curp;
+         break;
+       }
+    }
+
+  if (result == NULL)
+    list_for_each (entry, &__stack_user)
+      {
+       struct pthread *curp;
+
+       curp = list_entry (entry, struct pthread, list);
+       if (curp == pd)
+         {
+           result = curp;
+           break;
+         }
+      }
+
+  lll_unlock (stack_cache_lock, LLL_PRIVATE);
+
+  return result;
+}
+
+
+/* Deallocate POSIX thread-local-storage.  */
+void
+attribute_hidden
+__nptl_deallocate_tsd (void)
+{
+  struct pthread *self = THREAD_SELF;
+
+  /* Maybe no data was ever allocated.  This happens often so we have
+     a flag for this.  */
+  if (THREAD_GETMEM (self, specific_used))
+    {
+      size_t round;
+      size_t cnt;
+
+      round = 0;
+      do
+       {
+         size_t idx;
+
+         /* So far no new nonzero data entry.  */
+         THREAD_SETMEM (self, specific_used, false);
+
+         for (cnt = idx = 0; cnt < PTHREAD_KEY_1STLEVEL_SIZE; ++cnt)
+           {
+             struct pthread_key_data *level2;
+
+             level2 = THREAD_GETMEM_NC (self, specific, cnt);
+
+             if (level2 != NULL)
+               {
+                 size_t inner;
+
+                 for (inner = 0; inner < PTHREAD_KEY_2NDLEVEL_SIZE;
+                      ++inner, ++idx)
+                   {
+                     void *data = level2[inner].data;
+
+                     if (data != NULL)
+                       {
+                         /* Always clear the data.  */
+                         level2[inner].data = NULL;
+
+                         /* Make sure the data corresponds to a valid
+                            key.  This test fails if the key was
+                            deallocated and also if it was
+                            re-allocated.  It is the user's
+                            responsibility to free the memory in this
+                            case.  */
+                         if (level2[inner].seq
+                             == __pthread_keys[idx].seq
+                             /* It is not necessary to register a destructor
+                                function.  */
+                             && __pthread_keys[idx].destr != NULL)
+                           /* Call the user-provided destructor.  */
+                           __pthread_keys[idx].destr (data);
+                       }
+                   }
+               }
+             else
+               idx += PTHREAD_KEY_1STLEVEL_SIZE;
+           }
+
+         if (THREAD_GETMEM (self, specific_used) == 0)
+           /* No data has been modified.  */
+           goto just_free;
+       }
+      /* We only repeat the process a fixed number of times.  */
+      while (__builtin_expect (++round < PTHREAD_DESTRUCTOR_ITERATIONS, 0));
+
+      /* Just clear the memory of the first block for reuse.  */
+      memset (&THREAD_SELF->specific_1stblock, '\0',
+             sizeof (self->specific_1stblock));
+
+    just_free:
+      /* Free the memory for the other blocks.  */
+      for (cnt = 1; cnt < PTHREAD_KEY_1STLEVEL_SIZE; ++cnt)
+       {
+         struct pthread_key_data *level2;
+
+         level2 = THREAD_GETMEM_NC (self, specific, cnt);
+         if (level2 != NULL)
+           {
+             /* The first block is allocated as part of the thread
+                descriptor.  */
+             free (level2);
+             THREAD_SETMEM_NC (self, specific, cnt, NULL);
+           }
+       }
+
+      THREAD_SETMEM (self, specific_used, false);
+    }
+}
+
+
+/* Deallocate a thread's stack after optionally making sure the thread
+   descriptor is still valid.  */
+void
+internal_function
+__free_tcb (struct pthread *pd)
+{
+  /* The thread is exiting now.  */
+  if (__builtin_expect (atomic_bit_test_set (&pd->cancelhandling,
+                                            TERMINATED_BIT) == 0, 1))
+    {
+      /* Remove the descriptor from the list.  */
+      if (DEBUGGING_P && __find_in_stack_list (pd) == NULL)
+       /* Something is really wrong.  The descriptor for a still
+          running thread is gone.  */
+       abort ();
+
+      /* Free TPP data.  */
+      if (__builtin_expect (pd->tpp != NULL, 0))
+       {
+         struct priority_protection_data *tpp = pd->tpp;
+
+         pd->tpp = NULL;
+         free (tpp);
+       }
+
+      /* Queue the stack memory block for reuse and exit the process.  The
+        kernel will signal via writing to the address returned by
+        QUEUE-STACK when the stack is available.  */
+      __deallocate_stack (pd);
+    }
+}
+
+
+static int
+start_thread (void *arg)
+{
+  struct pthread *pd = (struct pthread *) arg;
+
+#if HP_TIMING_AVAIL
+  /* Remember the time when the thread was started.  */
+  hp_timing_t now;
+  HP_TIMING_NOW (now);
+  THREAD_SETMEM (pd, cpuclock_offset, now);
+#endif
+
+  /* Initialize resolver state pointer.  */
+  __resp = &pd->res;
+
+#ifdef __NR_set_robust_list
+# ifndef __ASSUME_SET_ROBUST_LIST
+  if (__set_robust_list_avail >= 0)
+# endif
+    {
+      INTERNAL_SYSCALL_DECL (err);
+      /* This call should never fail because the initial call in init.c
+        succeeded.  */
+      INTERNAL_SYSCALL (set_robust_list, err, 2, &pd->robust_head,
+                       sizeof (struct robust_list_head));
+    }
+#endif
+
+  /* If the parent was running cancellation handlers while creating
+     the thread the new thread inherited the signal mask.  Reset the
+     cancellation signal mask.  */
+  if (__builtin_expect (pd->parent_cancelhandling & CANCELING_BITMASK, 0))
+    {
+      INTERNAL_SYSCALL_DECL (err);
+      sigset_t mask;
+      __sigemptyset (&mask);
+      __sigaddset (&mask, SIGCANCEL);
+      (void) INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_UNBLOCK, &mask,
+                              NULL, _NSIG / 8);
+    }
+
+  /* This is where the try/finally block should be created.  For
+     compilers without that support we do use setjmp.  */
+  struct pthread_unwind_buf unwind_buf;
+
+  /* No previous handlers.  */
+  unwind_buf.priv.data.prev = NULL;
+  unwind_buf.priv.data.cleanup = NULL;
+
+  int not_first_call;
+  not_first_call = setjmp ((struct __jmp_buf_tag *) unwind_buf.cancel_jmp_buf);
+  if (__builtin_expect (! not_first_call, 1))
+    {
+      /* Store the new cleanup handler info.  */
+      THREAD_SETMEM (pd, cleanup_jmp_buf, &unwind_buf);
+
+      if (__builtin_expect (pd->stopped_start, 0))
+       {
+         int oldtype = CANCEL_ASYNC ();
+
+         /* Get the lock the parent locked to force synchronization.  */
+         lll_lock (pd->lock, LLL_PRIVATE);
+         /* And give it up right away.  */
+         lll_unlock (pd->lock, LLL_PRIVATE);
+
+         CANCEL_RESET (oldtype);
+       }
+
+      /* Run the code the user provided.  */
+#ifdef CALL_THREAD_FCT
+      THREAD_SETMEM (pd, result, CALL_THREAD_FCT (pd));
+#else
+      THREAD_SETMEM (pd, result, pd->start_routine (pd->arg));
+#endif
+    }
+
+  /* Run the destructor for the thread-local data.  */
+  __nptl_deallocate_tsd ();
+
+  /* Clean up any state libc stored in thread-local variables.  */
+  /* disable for now
+  __libc_thread_freeres ();
+  */
+  /* If this is the last thread we terminate the process now.  We
+     do not notify the debugger, it might just irritate it if there
+     is no thread left.  */
+  if (__builtin_expect (atomic_decrement_and_test (&__nptl_nthreads), 0))
+    /* This was the last thread.  */
+    exit (0);
+
+  /* Report the death of the thread if this is wanted.  */
+  if (__builtin_expect (pd->report_events, 0))
+    {
+      /* See whether TD_DEATH is in any of the mask.  */
+      const int idx = __td_eventword (TD_DEATH);
+      const uint32_t mask = __td_eventmask (TD_DEATH);
+
+      if ((mask & (__nptl_threads_events.event_bits[idx]
+                  | pd->eventbuf.eventmask.event_bits[idx])) != 0)
+       {
+         /* Yep, we have to signal the death.  Add the descriptor to
+            the list but only if it is not already on it.  */
+         if (pd->nextevent == NULL)
+           {
+             pd->eventbuf.eventnum = TD_DEATH;
+             pd->eventbuf.eventdata = pd;
+
+             do
+               pd->nextevent = __nptl_last_event;
+             while (atomic_compare_and_exchange_bool_acq (&__nptl_last_event,
+                                                          pd, pd->nextevent));
+           }
+
+         /* Now call the function to signal the event.  */
+         __nptl_death_event ();
+       }
+    }
+
+  /* The thread is exiting now.  Don't set this bit until after we've hit
+     the event-reporting breakpoint, so that td_thr_get_info on us while at
+     the breakpoint reports TD_THR_RUN state rather than TD_THR_ZOMBIE.  */
+  atomic_bit_set (&pd->cancelhandling, EXITING_BIT);
+
+#ifndef __ASSUME_SET_ROBUST_LIST
+  /* If this thread has any robust mutexes locked, handle them now.  */
+# if __WORDSIZE == 64
+  void *robust = pd->robust_head.list;
+# else
+  __pthread_slist_t *robust = pd->robust_list.__next;
+# endif
+  /* We let the kernel do the notification if it is able to do so.
+     If we have to do it here there for sure are no PI mutexes involved
+     since the kernel support for them is even more recent.  */
+  if (__set_robust_list_avail < 0
+      && __builtin_expect (robust != (void *) &pd->robust_head, 0))
+    {
+      do
+       {
+         struct __pthread_mutex_s *this = (struct __pthread_mutex_s *)
+           ((char *) robust - offsetof (struct __pthread_mutex_s,
+                                        __list.__next));
+         robust = *((void **) robust);
+
+# ifdef __PTHREAD_MUTEX_HAVE_PREV
+         this->__list.__prev = NULL;
+# endif
+         this->__list.__next = NULL;
+
+         lll_robust_dead (this->__lock, /* XYZ */ LLL_SHARED);
+       }
+      while (robust != (void *) &pd->robust_head);
+    }
+#endif
+
+  /* Mark the memory of the stack as usable to the kernel.  We free
+     everything except for the space used for the TCB itself.  */
+  size_t pagesize_m1 = __getpagesize () - 1;
+#ifdef _STACK_GROWS_DOWN
+  char *sp = CURRENT_STACK_FRAME;
+  size_t freesize = (sp - (char *) pd->stackblock) & ~pagesize_m1;
+#else
+# error "to do"
+#endif
+  assert (freesize < pd->stackblock_size);
+  if (freesize > PTHREAD_STACK_MIN)
+    madvise (pd->stackblock, freesize - PTHREAD_STACK_MIN, MADV_DONTNEED);
+
+  /* If the thread is detached free the TCB.  */
+  if (IS_DETACHED (pd))
+    /* Free the TCB.  */
+    __free_tcb (pd);
+  else if (__builtin_expect (pd->cancelhandling & SETXID_BITMASK, 0))
+    {
+      /* Some other thread might call any of the setXid functions and expect
+        us to reply.  In this case wait until we did that.  */
+      do
+       lll_futex_wait (&pd->setxid_futex, 0, LLL_PRIVATE);
+      while (pd->cancelhandling & SETXID_BITMASK);
+
+      /* Reset the value so that the stack can be reused.  */
+      pd->setxid_futex = 0;
+    }
+
+  /* We cannot call '_exit' here.  '_exit' will terminate the process.
+
+     The 'exit' implementation in the kernel will signal when the
+     process is really dead since 'clone' got passed the CLONE_CLEARTID
+     flag.  The 'tid' field in the TCB will be set to zero.
+
+     The exit code is zero since in case all threads exit by calling
+     'pthread_exit' the exit status must be 0 (zero).  */
+  __exit_thread_inline (0);
+
+  /* NOTREACHED */
+  return 0;
+}
+
+
+/* Default thread attributes for the case when the user does not
+   provide any.  */
+static const struct pthread_attr default_attr =
+  {
+    /* Just some value > 0 which gets rounded to the nearest page size.  */
+    .guardsize = 1,
+  };
+
+
+int
+__pthread_create_2_1 (
+     pthread_t *newthread,
+     const pthread_attr_t *attr,
+     void *(*start_routine) (void *),
+     void *arg)
+{
+  STACK_VARIABLES;
+
+  const struct pthread_attr *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;
+
+  struct pthread *pd = NULL;
+  int err = ALLOCATE_STACK (iattr, &pd);
+  if (__builtin_expect (err != 0, 0))
+    /* Something went wrong.  Maybe a parameter of the attributes is
+       invalid or we could not allocate memory.  */
+    return err;
+
+
+  /* Initialize the TCB.  All initializations with zero should be
+     performed in 'get_cached_stack'.  This way we avoid doing this if
+     the stack freshly allocated with 'mmap'.  */
+
+#ifdef TLS_TCB_AT_TP
+  /* Reference to the TCB itself.  */
+  pd->header.self = pd;
+
+  /* Self-reference for TLS.  */
+  pd->header.tcb = pd;
+#endif
+
+  /* Store the address of the start routine and the parameter.  Since
+     we do not start the function directly the stillborn thread will
+     get the information from its thread descriptor.  */
+  pd->start_routine = start_routine;
+  pd->arg = arg;
+
+  /* Copy the thread attribute flags.  */
+  struct pthread *self = THREAD_SELF;
+  pd->flags = ((iattr->flags & ~(ATTR_FLAG_SCHED_SET | ATTR_FLAG_POLICY_SET))
+              | (self->flags & (ATTR_FLAG_SCHED_SET | ATTR_FLAG_POLICY_SET)));
+
+  /* Initialize the field for the ID of the thread which is waiting
+     for us.  This is a self-reference in case the thread is created
+     detached.  */
+  pd->joinid = iattr->flags & ATTR_FLAG_DETACHSTATE ? pd : NULL;
+
+  /* The debug events are inherited from the parent.  */
+  pd->eventbuf = self->eventbuf;
+
+
+  /* Copy the parent's scheduling parameters.  The flags will say what
+     is valid and what is not.  */
+  pd->schedpolicy = self->schedpolicy;
+  pd->schedparam = self->schedparam;
+
+  /* Copy the stack guard canary.  */
+#ifdef THREAD_COPY_STACK_GUARD
+  THREAD_COPY_STACK_GUARD (pd);
+#endif
+
+  /* Copy the pointer guard value.  */
+#ifdef THREAD_COPY_POINTER_GUARD
+  THREAD_COPY_POINTER_GUARD (pd);
+#endif
+
+  /* Determine scheduling parameters for the thread.  */
+  if (attr != NULL
+      && __builtin_expect ((iattr->flags & ATTR_FLAG_NOTINHERITSCHED) != 0, 0)
+      && (iattr->flags & (ATTR_FLAG_SCHED_SET | ATTR_FLAG_POLICY_SET)) != 0)
+    {
+      INTERNAL_SYSCALL_DECL (scerr);
+
+      /* Use the scheduling parameters the user provided.  */
+      if (iattr->flags & ATTR_FLAG_POLICY_SET)
+       pd->schedpolicy = iattr->schedpolicy;
+      else if ((pd->flags & ATTR_FLAG_POLICY_SET) == 0)
+       {
+         pd->schedpolicy = INTERNAL_SYSCALL (sched_getscheduler, scerr, 1, 0);
+         pd->flags |= ATTR_FLAG_POLICY_SET;
+       }
+
+      if (iattr->flags & ATTR_FLAG_SCHED_SET)
+       memcpy (&pd->schedparam, &iattr->schedparam,
+               sizeof (struct sched_param));
+      else if ((pd->flags & ATTR_FLAG_SCHED_SET) == 0)
+       {
+         INTERNAL_SYSCALL (sched_getparam, scerr, 2, 0, &pd->schedparam);
+         pd->flags |= ATTR_FLAG_SCHED_SET;
+       }
+
+      /* Check for valid priorities.  */
+      int minprio = INTERNAL_SYSCALL (sched_get_priority_min, scerr, 1,
+                                     iattr->schedpolicy);
+      int maxprio = INTERNAL_SYSCALL (sched_get_priority_max, scerr, 1,
+                                     iattr->schedpolicy);
+      if (pd->schedparam.sched_priority < minprio
+         || pd->schedparam.sched_priority > maxprio)
+       {
+         err = EINVAL;
+         goto errout;
+       }
+    }
+
+  /* Pass the descriptor to the caller.  */
+  *newthread = (pthread_t) pd;
+
+  /* Remember whether the thread is detached or not.  In case of an
+     error we have to free the stacks of non-detached stillborn
+     threads.  */
+  bool is_detached = IS_DETACHED (pd);
+
+  /* Start the thread.  */
+  err = create_thread (pd, iattr, STACK_VARIABLES_ARGS);
+  if (err != 0)
+    {
+      /* Something went wrong.  Free the resources.  */
+      if (!is_detached)
+       {
+       errout:
+         __deallocate_stack (pd);
+       }
+      return err;
+    }
+
+  return 0;
+}
+weak_alias(__pthread_create_2_1, pthread_create)
+\f
+/* Information for libthread_db.  */
+
+#include "../nptl_db/db_info.c"
+\f
+/* If pthread_create is present, libgcc_eh.a and libsupc++.a expects some other POSIX thread
+   functions to be present as well.  */
+PTHREAD_STATIC_FN_REQUIRE (pthread_mutex_lock)
+PTHREAD_STATIC_FN_REQUIRE (pthread_mutex_trylock)
+PTHREAD_STATIC_FN_REQUIRE (pthread_mutex_unlock)
+
+PTHREAD_STATIC_FN_REQUIRE (pthread_once)
+PTHREAD_STATIC_FN_REQUIRE (pthread_cancel)
+
+PTHREAD_STATIC_FN_REQUIRE (pthread_key_create)
+PTHREAD_STATIC_FN_REQUIRE (pthread_key_delete)
+PTHREAD_STATIC_FN_REQUIRE (pthread_setspecific)
+PTHREAD_STATIC_FN_REQUIRE (pthread_getspecific)
+
+/* UCLIBC_MUTEX_xxx macros expects to have these as well */
+PTHREAD_STATIC_FN_REQUIRE (pthread_mutex_init)
+PTHREAD_STATIC_FN_REQUIRE (_pthread_cleanup_push_defer)
+PTHREAD_STATIC_FN_REQUIRE (_pthread_cleanup_pop_restore)
diff --git a/libpthread/nptl/pthread_detach.c b/libpthread/nptl/pthread_detach.c
new file mode 100644 (file)
index 0000000..054d779
--- /dev/null
@@ -0,0 +1,56 @@
+/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include "pthreadP.h"
+#include <atomic.h>
+
+
+int
+pthread_detach (pthread_t th)
+{
+  struct pthread *pd = (struct pthread *) th;
+
+  /* Make sure the descriptor is valid.  */
+  if (INVALID_NOT_TERMINATED_TD_P (pd))
+    /* Not a valid thread handle.  */
+    return ESRCH;
+
+  int result = 0;
+
+  /* Mark the thread as detached.  */
+  if (atomic_compare_and_exchange_bool_acq (&pd->joinid, pd, NULL))
+    {
+      /* 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/libpthread/nptl/pthread_equal.c b/libpthread/nptl/pthread_equal.c
new file mode 100644 (file)
index 0000000..8587e0f
--- /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"
+
+
+int
+__pthread_equal (pthread_t thread1, pthread_t thread2)
+{
+  return thread1 == thread2;
+}
+strong_alias (__pthread_equal, pthread_equal)
diff --git a/libpthread/nptl/pthread_exit.c b/libpthread/nptl/pthread_exit.c
new file mode 100644 (file)
index 0000000..a8c92fd
--- /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 (void* value)
+{
+  THREAD_SETMEM (THREAD_SELF, result, value);
+
+  __do_cancel ();
+}
+strong_alias (__pthread_exit, pthread_exit)
diff --git a/libpthread/nptl/pthread_getattr_np.c b/libpthread/nptl/pthread_getattr_np.c
new file mode 100644 (file)
index 0000000..86a4385
--- /dev/null
@@ -0,0 +1,179 @@
+/* Copyright (C) 2002, 2003, 2004, 2006, 2007 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 <inttypes.h>
+#include <stdio.h>
+#include <stdio_ext.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/resource.h>
+#include "pthreadP.h"
+#include <lowlevellock.h>
+#include <ldsodefs.h>
+
+
+int
+pthread_getattr_np (
+     pthread_t thread_id,
+     pthread_attr_t *attr)
+{
+  struct pthread *thread = (struct pthread *) thread_id;
+  struct pthread_attr *iattr = (struct pthread_attr *) attr;
+  int ret = 0;
+
+  lll_lock (thread->lock, LLL_PRIVATE);
+
+  /* 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->reported_guardsize;
+
+  /* The sizes are subject to alignment.  */
+  if (__builtin_expect (thread->stackblock != NULL, 1))
+    {
+      iattr->stacksize = thread->stackblock_size;
+      iattr->stackaddr = (char *) thread->stackblock + iattr->stacksize;
+    }
+  else
+    {
+      /* No stack information available.  This must be for the initial
+        thread.  Get the info in some magical way.  */
+      assert (abs (thread->pid) == thread->tid);
+
+      /* Stack size limit.  */
+      struct rlimit rl;
+
+      /* The safest way to get the top of the stack is to read
+        /proc/self/maps and locate the line into which
+        __libc_stack_end falls.  */
+      FILE *fp = fopen ("/proc/self/maps", "rc");
+      if (fp == NULL)
+       ret = errno;
+      /* We need the limit of the stack in any case.  */
+      else
+       {
+         if (getrlimit (RLIMIT_STACK, &rl) != 0)
+           ret = errno;
+         else
+           {
+             /* We need no locking.  */
+             __fsetlocking (fp, FSETLOCKING_BYCALLER);
+
+             /* Until we found an entry (which should always be the case)
+                mark the result as a failure.  */
+             ret = ENOENT;
+
+             char *line = NULL;
+             size_t linelen = 0;
+             uintptr_t last_to = 0;
+
+             while (! feof_unlocked (fp))
+               {
+                 if (getdelim (&line, &linelen, '\n', fp) <= 0)
+                   break;
+
+                 uintptr_t from;
+                 uintptr_t to;
+                 if (sscanf (line, "%" SCNxPTR "-%" SCNxPTR, &from, &to) != 2)
+                   continue;
+                 if (from <= (uintptr_t) __libc_stack_end
+                     && (uintptr_t) __libc_stack_end < to)
+                   {
+                     /* Found the entry.  Now we have the info we need.  */
+                     iattr->stacksize = rl.rlim_cur;
+                     iattr->stackaddr = (void *) to;
+
+                     /* The limit might be too high.  */
+                     if ((size_t) iattr->stacksize
+                         > (size_t) iattr->stackaddr - last_to)
+                       iattr->stacksize = (size_t) iattr->stackaddr - last_to;
+
+                     /* We succeed and no need to look further.  */
+                     ret = 0;
+                     break;
+                   }
+                 last_to = to;
+               }
+
+             free (line);
+           }
+
+         fclose (fp);
+       }
+    }
+
+  iattr->flags |= ATTR_FLAG_STACKADDR;
+
+  if (ret == 0)
+    {
+      size_t size = 16;
+      cpu_set_t *cpuset = NULL;
+
+      do
+       {
+         size <<= 1;
+
+         void *newp = realloc (cpuset, size);
+         if (newp == NULL)
+           {
+             ret = ENOMEM;
+             break;
+           }
+         cpuset = (cpu_set_t *) newp;
+
+         ret = __pthread_getaffinity_np (thread_id, size, cpuset);
+       }
+      /* Pick some ridiculous upper limit.  Is 8 million CPUs enough?  */
+      while (ret == EINVAL && size < 1024 * 1024);
+
+      if (ret == 0)
+       {
+         iattr->cpuset = cpuset;
+         iattr->cpusetsize = size;
+       }
+      else
+       {
+         free (cpuset);
+         if (ret == ENOSYS)
+           {
+             /* There is no such functionality.  */
+             ret = 0;
+             iattr->cpuset = NULL;
+             iattr->cpusetsize = 0;
+           }
+       }
+    }
+
+  lll_unlock (thread->lock, LLL_PRIVATE);
+
+  return ret;
+}
diff --git a/libpthread/nptl/pthread_getconcurrency.c b/libpthread/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/libpthread/nptl/pthread_getschedparam.c b/libpthread/nptl/pthread_getschedparam.c
new file mode 100644 (file)
index 0000000..bb5f0a9
--- /dev/null
@@ -0,0 +1,75 @@
+/* Copyright (C) 2002, 2003, 2004, 2007 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 <string.h>
+#include "pthreadP.h"
+#include <lowlevellock.h>
+
+
+int
+__pthread_getschedparam (
+     pthread_t threadid,
+     int *policy,
+     struct sched_param *param)
+{
+  struct pthread *pd = (struct pthread *) threadid;
+
+  /* Make sure the descriptor is valid.  */
+  if (INVALID_TD_P (pd))
+    /* Not a valid thread handle.  */
+    return ESRCH;
+
+  int result = 0;
+
+  lll_lock (pd->lock, LLL_PRIVATE);
+
+  /* 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.  In case the descriptor's values have
+     not yet been retrieved do it now.  */
+  if ((pd->flags & ATTR_FLAG_SCHED_SET) == 0)
+    {
+      if (sched_getparam (pd->tid, &pd->schedparam) != 0)
+       result = 1;
+      else
+       pd->flags |= ATTR_FLAG_SCHED_SET;
+    }
+
+  if ((pd->flags & ATTR_FLAG_POLICY_SET) == 0)
+    {
+      pd->schedpolicy = sched_getscheduler (pd->tid);
+      if (pd->schedpolicy == -1)
+       result = 1;
+      else
+       pd->flags |= ATTR_FLAG_POLICY_SET;
+    }
+
+  if (result == 0)
+    {
+      *policy = pd->schedpolicy;
+      memcpy (param, &pd->schedparam, sizeof (struct sched_param));
+    }
+
+  lll_unlock (pd->lock, LLL_PRIVATE);
+
+  return result;
+}
+strong_alias (__pthread_getschedparam, pthread_getschedparam)
diff --git a/libpthread/nptl/pthread_getspecific.c b/libpthread/nptl/pthread_getspecific.c
new file mode 100644 (file)
index 0000000..62c48fe
--- /dev/null
@@ -0,0 +1,68 @@
+/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stdlib.h>
+#include "pthreadP.h"
+
+
+void *
+__pthread_getspecific (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 (__builtin_expect (seq != __pthread_keys[key].seq, 0))
+       result = data->data = NULL;
+    }
+
+  return result;
+}
+strong_alias (__pthread_getspecific, pthread_getspecific)
+strong_alias (__pthread_getspecific, __pthread_getspecific_internal)
diff --git a/libpthread/nptl/pthread_join.c b/libpthread/nptl/pthread_join.c
new file mode 100644 (file)
index 0000000..ce6cf6f
--- /dev/null
@@ -0,0 +1,114 @@
+/* Copyright (C) 2002, 2003, 2005, 2006 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)
+{
+  /* If we already changed the waiter ID, reset it.  The call cannot
+     fail for any reason but the thread not having done that yet so
+     there is no reason for a loop.  */
+  (void) atomic_compare_and_exchange_bool_acq ((struct pthread **) arg, NULL,
+                                              THREAD_SELF);
+}
+
+
+int
+pthread_join (
+     pthread_t threadid,
+     void **thread_return)
+{
+  struct pthread *pd = (struct pthread *) threadid;
+
+  /* Make sure the descriptor is valid.  */
+  if (INVALID_NOT_TERMINATED_TD_P (pd))
+    /* Not a valid thread handle.  */
+    return ESRCH;
+
+  /* Is the thread joinable?.  */
+  if (IS_DETACHED (pd))
+    /* We cannot wait for the thread.  */
+    return EINVAL;
+
+  struct pthread *self = THREAD_SELF;
+  int result = 0;
+
+  /* During the wait we change to asynchronous cancellation.  If we
+     are canceled 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 ();
+
+  if ((pd == self
+       || (self->joinid == pd
+          && (pd->cancelhandling
+              & (CANCELING_BITMASK | CANCELED_BITMASK | EXITING_BITMASK
+                 | TERMINATED_BITMASK)) == 0))
+      && !CANCEL_ENABLED_AND_CANCELED (self->cancelhandling))
+    /* 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.  */
+    result = EDEADLK;
+  /* Wait for the thread to finish.  If it is already locked something
+     is wrong.  There can only be one waiter.  */
+  else if (__builtin_expect (atomic_compare_and_exchange_bool_acq (&pd->joinid,
+                                                                  self,
+                                                                  NULL), 0))
+    /* There is already somebody waiting for the thread.  */
+    result = EINVAL;
+  else
+    /* Wait for the child.  */
+    lll_wait_tid (pd->tid);
+
+
+  /* Restore cancellation mode.  */
+  CANCEL_RESET (oldtype);
+
+  /* Remove the handler.  */
+  pthread_cleanup_pop (0);
+
+
+  if (__builtin_expect (result == 0, 1))
+    {
+      /* We mark the thread as terminated and as joined.  */
+      pd->tid = -1;
+
+      /* Store the return value if the caller is interested.  */
+      if (thread_return != NULL)
+       *thread_return = pd->result;
+
+
+      /* Free the TCB.  */
+      __free_tcb (pd);
+    }
+
+  return result;
+}
diff --git a/libpthread/nptl/pthread_key_create.c b/libpthread/nptl/pthread_key_create.c
new file mode 100644 (file)
index 0000000..3744c08
--- /dev/null
@@ -0,0 +1,54 @@
+/* Copyright (C) 2002, 2003, 2006 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_create (
+     pthread_key_t *key,
+     void (*destr) (void *))
+{
+  /* Find a slot in __pthread_kyes which is unused.  */
+  for (size_t cnt = 0; cnt < PTHREAD_KEYS_MAX; ++cnt)
+    {
+      uintptr_t seq = __pthread_keys[cnt].seq;
+
+      if (KEY_UNUSED (seq) && KEY_USABLE (seq)
+         /* We found an unused slot.  Try to allocate it.  */
+         && ! atomic_compare_and_exchange_bool_acq (&__pthread_keys[cnt].seq,
+                                                    seq + 1, seq))
+       {
+         /* Remember the destructor.  */
+         __pthread_keys[cnt].destr = destr;
+
+         /* Return the key to the caller.  */
+         *key = cnt;
+
+         /* The call succeeded.  */
+         return 0;
+       }
+    }
+
+  return EAGAIN;
+}
+strong_alias (__pthread_key_create, pthread_key_create)
+strong_alias (__pthread_key_create, __pthread_key_create_internal)
diff --git a/libpthread/nptl/pthread_key_delete.c b/libpthread/nptl/pthread_key_delete.c
new file mode 100644 (file)
index 0000000..cb408f0
--- /dev/null
@@ -0,0 +1,42 @@
+/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include "pthreadP.h"
+#include <atomic.h>
+
+
+int
+pthread_key_delete (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_bool_acq (&__pthread_keys[key].seq,
+                                                    seq + 1, seq))
+       /* We deleted a valid key.  */
+       result = 0;
+    }
+
+  return result;
+}
diff --git a/libpthread/nptl/pthread_kill_other_threads.c b/libpthread/nptl/pthread_kill_other_threads.c
new file mode 100644 (file)
index 0000000..09401aa
--- /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.  */
+
+#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)
+{
+}
+#endif
diff --git a/libpthread/nptl/pthread_mutex_consistent.c b/libpthread/nptl/pthread_mutex_consistent.c
new file mode 100644 (file)
index 0000000..1e8f074
--- /dev/null
@@ -0,0 +1,37 @@
+/* Copyright (C) 2005, 2006, 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2005.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with 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_mutex_consistent (
+     pthread_mutex_t *mutex)
+{
+  /* Test whether this is a robust mutex with a dead owner.  */
+  if ((mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) == 0
+      || mutex->__data.__owner != PTHREAD_MUTEX_INCONSISTENT)
+    return EINVAL;
+
+  mutex->__data.__owner = THREAD_GETMEM (THREAD_SELF, tid);
+
+  return 0;
+}
+weak_alias (pthread_mutex_consistent, pthread_mutex_consistent_np)
diff --git a/libpthread/nptl/pthread_mutex_destroy.c b/libpthread/nptl/pthread_mutex_destroy.c
new file mode 100644 (file)
index 0000000..f487d61
--- /dev/null
@@ -0,0 +1,38 @@
+/* Copyright (C) 2002, 2003, 2005, 2006 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_mutex_destroy (
+     pthread_mutex_t *mutex)
+{
+  if ((mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) == 0
+      && mutex->__data.__nusers != 0)
+    return EBUSY;
+
+  /* Set to an invalid value.  */
+  mutex->__data.__kind = -1;
+
+  return 0;
+}
+strong_alias (__pthread_mutex_destroy, pthread_mutex_destroy)
+INTDEF(__pthread_mutex_destroy)
diff --git a/libpthread/nptl/pthread_mutex_getprioceiling.c b/libpthread/nptl/pthread_mutex_getprioceiling.c
new file mode 100644 (file)
index 0000000..1ce5eae
--- /dev/null
@@ -0,0 +1,38 @@
+/* Get current priority ceiling of pthread_mutex_t.
+   Copyright (C) 2006 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2006.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with 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_mutex_getprioceiling (mutex, prioceiling)
+     const pthread_mutex_t *mutex;
+     int *prioceiling;
+{
+  if (__builtin_expect ((mutex->__data.__kind
+                        & PTHREAD_MUTEX_PRIO_PROTECT_NP) == 0, 0))
+    return EINVAL;
+
+  *prioceiling = (mutex->__data.__lock & PTHREAD_MUTEX_PRIO_CEILING_MASK)
+                >> PTHREAD_MUTEX_PRIO_CEILING_SHIFT;
+
+  return 0;
+}
diff --git a/libpthread/nptl/pthread_mutex_init.c b/libpthread/nptl/pthread_mutex_init.c
new file mode 100644 (file)
index 0000000..dd6e6d6
--- /dev/null
@@ -0,0 +1,141 @@
+/* Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007
+   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 <bits/kernel-features.h>
+#include "pthreadP.h"
+
+static const struct pthread_mutexattr default_attr =
+  {
+    /* Default is a normal mutex, not shared between processes.  */
+    .mutexkind = PTHREAD_MUTEX_NORMAL
+  };
+
+
+#ifndef __ASSUME_FUTEX_LOCK_PI
+static int tpi_supported;
+#endif
+
+
+int
+__pthread_mutex_init (
+     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;
+
+  /* Sanity checks.  */
+  switch (__builtin_expect (imutexattr->mutexkind
+                           & PTHREAD_MUTEXATTR_PROTOCOL_MASK,
+                           PTHREAD_PRIO_NONE
+                           << PTHREAD_MUTEXATTR_PROTOCOL_SHIFT))
+    {
+    case PTHREAD_PRIO_NONE << PTHREAD_MUTEXATTR_PROTOCOL_SHIFT:
+      break;
+
+    case PTHREAD_PRIO_INHERIT << PTHREAD_MUTEXATTR_PROTOCOL_SHIFT:
+#ifndef __ASSUME_FUTEX_LOCK_PI
+      if (__builtin_expect (tpi_supported == 0, 0))
+       {
+         int lock = 0;
+         INTERNAL_SYSCALL_DECL (err);
+         int ret = INTERNAL_SYSCALL (futex, err, 4, &lock, FUTEX_UNLOCK_PI,
+                                     0, 0);
+         assert (INTERNAL_SYSCALL_ERROR_P (ret, err));
+         tpi_supported = INTERNAL_SYSCALL_ERRNO (ret, err) == ENOSYS ? -1 : 1;
+       }
+      if (__builtin_expect (tpi_supported < 0, 0))
+       return ENOTSUP;
+#endif
+      break;
+
+    default:
+      /* XXX: For now we don't support robust priority protected mutexes.  */
+      if (imutexattr->mutexkind & PTHREAD_MUTEXATTR_FLAG_ROBUST)
+       return ENOTSUP;
+      break;
+    }
+
+  /* Clear the whole variable.  */
+  memset (mutex, '\0', __SIZEOF_PTHREAD_MUTEX_T);
+
+  /* Copy the values from the attribute.  */
+  mutex->__data.__kind = imutexattr->mutexkind & ~PTHREAD_MUTEXATTR_FLAG_BITS;
+
+  if ((imutexattr->mutexkind & PTHREAD_MUTEXATTR_FLAG_ROBUST) != 0)
+    {
+#ifndef __ASSUME_SET_ROBUST_LIST
+      if ((imutexattr->mutexkind & PTHREAD_MUTEXATTR_FLAG_PSHARED) != 0
+         && __set_robust_list_avail < 0)
+       return ENOTSUP;
+#endif
+
+      mutex->__data.__kind |= PTHREAD_MUTEX_ROBUST_NORMAL_NP;
+    }
+
+  switch (imutexattr->mutexkind & PTHREAD_MUTEXATTR_PROTOCOL_MASK)
+    {
+    case PTHREAD_PRIO_INHERIT << PTHREAD_MUTEXATTR_PROTOCOL_SHIFT:
+      mutex->__data.__kind |= PTHREAD_MUTEX_PRIO_INHERIT_NP;
+      break;
+
+    case PTHREAD_PRIO_PROTECT << PTHREAD_MUTEXATTR_PROTOCOL_SHIFT:
+      mutex->__data.__kind |= PTHREAD_MUTEX_PRIO_PROTECT_NP;
+
+      int ceiling = (imutexattr->mutexkind
+                    & PTHREAD_MUTEXATTR_PRIO_CEILING_MASK)
+                   >> PTHREAD_MUTEXATTR_PRIO_CEILING_SHIFT;
+      if (! ceiling)
+       {
+         if (__sched_fifo_min_prio == -1)
+           __init_sched_fifo_prio ();
+         if (ceiling < __sched_fifo_min_prio)
+           ceiling = __sched_fifo_min_prio;
+       }
+      mutex->__data.__lock = ceiling << PTHREAD_MUTEX_PRIO_CEILING_SHIFT;
+      break;
+
+    default:
+      break;
+    }
+
+  /* The kernel when waking robust mutexes on exit never uses
+     FUTEX_PRIVATE_FLAG FUTEX_WAKE.  */
+  if ((imutexattr->mutexkind & (PTHREAD_MUTEXATTR_FLAG_PSHARED
+                               | PTHREAD_MUTEXATTR_FLAG_ROBUST)) != 0)
+    mutex->__data.__kind |= PTHREAD_MUTEX_PSHARED_BIT;
+
+  /* Default values: mutex not used yet.  */
+  // mutex->__count = 0;       already done by memset
+  // mutex->__owner = 0;       already done by memset
+  // mutex->__nusers = 0;      already done by memset
+  // mutex->__spins = 0;       already done by memset
+  // mutex->__next = NULL;     already done by memset
+
+  return 0;
+}
+strong_alias (__pthread_mutex_init, pthread_mutex_init)
+INTDEF(__pthread_mutex_init)
diff --git a/libpthread/nptl/pthread_mutex_lock.c b/libpthread/nptl/pthread_mutex_lock.c
new file mode 100644 (file)
index 0000000..47e4d41
--- /dev/null
@@ -0,0 +1,494 @@
+/* Copyright (C) 2002-2007, 2008, 2009 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 <stdlib.h>
+#include <unistd.h>
+#include <not-cancel.h>
+#include "pthreadP.h"
+#include <lowlevellock.h>
+
+
+#ifndef LLL_MUTEX_LOCK
+# define LLL_MUTEX_LOCK(mutex) \
+  lll_lock ((mutex)->__data.__lock, PTHREAD_MUTEX_PSHARED (mutex))
+# define LLL_MUTEX_TRYLOCK(mutex) \
+  lll_trylock ((mutex)->__data.__lock)
+# define LLL_ROBUST_MUTEX_LOCK(mutex, id) \
+  lll_robust_lock ((mutex)->__data.__lock, id, \
+                  PTHREAD_ROBUST_MUTEX_PSHARED (mutex))
+#endif
+
+
+static int __pthread_mutex_lock_full (pthread_mutex_t *mutex)
+     __attribute_noinline__;
+
+
+int
+__pthread_mutex_lock (
+     pthread_mutex_t *mutex)
+{
+  assert (sizeof (mutex->__size) >= sizeof (mutex->__data));
+
+  unsigned int type = PTHREAD_MUTEX_TYPE (mutex);
+  if (__builtin_expect (type & ~PTHREAD_MUTEX_KIND_MASK_NP, 0))
+    return __pthread_mutex_lock_full (mutex);
+
+  pid_t id = THREAD_GETMEM (THREAD_SELF, tid);
+
+  if (__builtin_expect (type, PTHREAD_MUTEX_TIMED_NP)
+      == PTHREAD_MUTEX_TIMED_NP)
+    {
+    simple:
+      /* Normal mutex.  */
+      LLL_MUTEX_LOCK (mutex);
+      assert (mutex->__data.__owner == 0);
+    }
+  else if (__builtin_expect (type == PTHREAD_MUTEX_RECURSIVE_NP, 1))
+    {
+      /* Recursive mutex.  */
+
+      /* Check whether we already hold the mutex.  */
+      if (mutex->__data.__owner == id)
+       {
+         /* Just bump the counter.  */
+         if (__builtin_expect (mutex->__data.__count + 1 == 0, 0))
+           /* Overflow of the counter.  */
+           return EAGAIN;
+
+         ++mutex->__data.__count;
+
+         return 0;
+       }
+
+      /* We have to get the mutex.  */
+      LLL_MUTEX_LOCK (mutex);
+
+      assert (mutex->__data.__owner == 0);
+      mutex->__data.__count = 1;
+    }
+  else if (__builtin_expect (type == PTHREAD_MUTEX_ADAPTIVE_NP, 1))
+    {
+      if (! __is_smp)
+       goto simple;
+
+      if (LLL_MUTEX_TRYLOCK (mutex) != 0)
+       {
+         int cnt = 0;
+         int max_cnt = MIN (MAX_ADAPTIVE_COUNT,
+                            mutex->__data.__spins * 2 + 10);
+         do
+           {
+             if (cnt++ >= max_cnt)
+               {
+                 LLL_MUTEX_LOCK (mutex);
+                 break;
+               }
+
+#ifdef BUSY_WAIT_NOP
+             BUSY_WAIT_NOP;
+#endif
+           }
+         while (LLL_MUTEX_TRYLOCK (mutex) != 0);
+
+         mutex->__data.__spins += (cnt - mutex->__data.__spins) / 8;
+       }
+      assert (mutex->__data.__owner == 0);
+    }
+  else
+    {
+      assert (type == PTHREAD_MUTEX_ERRORCHECK_NP);
+      /* Check whether we already hold the mutex.  */
+      if (__builtin_expect (mutex->__data.__owner == id, 0))
+       return EDEADLK;
+      goto simple;
+    }
+
+  /* Record the ownership.  */
+  mutex->__data.__owner = id;
+#ifndef NO_INCR
+  ++mutex->__data.__nusers;
+#endif
+
+  return 0;
+}
+
+static int
+__pthread_mutex_lock_full (pthread_mutex_t *mutex)
+{
+  int oldval;
+  pid_t id = THREAD_GETMEM (THREAD_SELF, tid);
+
+  switch (PTHREAD_MUTEX_TYPE (mutex))
+    {
+    case PTHREAD_MUTEX_ROBUST_RECURSIVE_NP:
+    case PTHREAD_MUTEX_ROBUST_ERRORCHECK_NP:
+    case PTHREAD_MUTEX_ROBUST_NORMAL_NP:
+    case PTHREAD_MUTEX_ROBUST_ADAPTIVE_NP:
+      THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
+                    &mutex->__data.__list.__next);
+
+      oldval = mutex->__data.__lock;
+      do
+       {
+       again:
+         if ((oldval & FUTEX_OWNER_DIED) != 0)
+           {
+             /* The previous owner died.  Try locking the mutex.  */
+             int newval = id;
+#ifdef NO_INCR
+             newval |= FUTEX_WAITERS;
+#else
+             newval |= (oldval & FUTEX_WAITERS);
+#endif
+
+             newval
+               = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
+                                                      newval, oldval);
+
+             if (newval != oldval)
+               {
+                 oldval = newval;
+                 goto again;
+               }
+
+             /* We got the mutex.  */
+             mutex->__data.__count = 1;
+             /* But it is inconsistent unless marked otherwise.  */
+             mutex->__data.__owner = PTHREAD_MUTEX_INCONSISTENT;
+
+             ENQUEUE_MUTEX (mutex);
+             THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+
+             /* Note that we deliberately exit here.  If we fall
+                through to the end of the function __nusers would be
+                incremented which is not correct because the old
+                owner has to be discounted.  If we are not supposed
+                to increment __nusers we actually have to decrement
+                it here.  */
+#ifdef NO_INCR
+             --mutex->__data.__nusers;
+#endif
+
+             return EOWNERDEAD;
+           }
+
+         /* Check whether we already hold the mutex.  */
+         if (__builtin_expect ((oldval & FUTEX_TID_MASK) == id, 0))
+           {
+             int kind = PTHREAD_MUTEX_TYPE (mutex);
+             if (kind == PTHREAD_MUTEX_ROBUST_ERRORCHECK_NP)
+               {
+                 THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
+                                NULL);
+                 return EDEADLK;
+               }
+
+             if (kind == PTHREAD_MUTEX_ROBUST_RECURSIVE_NP)
+               {
+                 THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
+                                NULL);
+
+                 /* Just bump the counter.  */
+                 if (__builtin_expect (mutex->__data.__count + 1 == 0, 0))
+                   /* Overflow of the counter.  */
+                   return EAGAIN;
+
+                 ++mutex->__data.__count;
+
+                 return 0;
+               }
+           }
+
+         oldval = LLL_ROBUST_MUTEX_LOCK (mutex, id);
+
+         if (__builtin_expect (mutex->__data.__owner
+                               == PTHREAD_MUTEX_NOTRECOVERABLE, 0))
+           {
+             /* This mutex is now not recoverable.  */
+             mutex->__data.__count = 0;
+             lll_unlock (mutex->__data.__lock,
+                         PTHREAD_ROBUST_MUTEX_PSHARED (mutex));
+             THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+             return ENOTRECOVERABLE;
+           }
+       }
+      while ((oldval & FUTEX_OWNER_DIED) != 0);
+
+      mutex->__data.__count = 1;
+      ENQUEUE_MUTEX (mutex);
+      THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+      break;
+
+    case PTHREAD_MUTEX_PI_RECURSIVE_NP:
+    case PTHREAD_MUTEX_PI_ERRORCHECK_NP:
+    case PTHREAD_MUTEX_PI_NORMAL_NP:
+    case PTHREAD_MUTEX_PI_ADAPTIVE_NP:
+    case PTHREAD_MUTEX_PI_ROBUST_RECURSIVE_NP:
+    case PTHREAD_MUTEX_PI_ROBUST_ERRORCHECK_NP:
+    case PTHREAD_MUTEX_PI_ROBUST_NORMAL_NP:
+    case PTHREAD_MUTEX_PI_ROBUST_ADAPTIVE_NP:
+      {
+       int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP;
+       int robust = mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP;
+
+       if (robust)
+         /* Note: robust PI futexes are signaled by setting bit 0.  */
+         THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
+                        (void *) (((uintptr_t) &mutex->__data.__list.__next)
+                                  | 1));
+
+       oldval = mutex->__data.__lock;
+
+       /* Check whether we already hold the mutex.  */
+       if (__builtin_expect ((oldval & FUTEX_TID_MASK) == id, 0))
+         {
+           if (kind == PTHREAD_MUTEX_ERRORCHECK_NP)
+             {
+               THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+               return EDEADLK;
+             }
+
+           if (kind == PTHREAD_MUTEX_RECURSIVE_NP)
+             {
+               THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+
+               /* Just bump the counter.  */
+               if (__builtin_expect (mutex->__data.__count + 1 == 0, 0))
+                 /* Overflow of the counter.  */
+                 return EAGAIN;
+
+               ++mutex->__data.__count;
+
+               return 0;
+             }
+         }
+
+       int newval = id;
+#ifdef NO_INCR
+       newval |= FUTEX_WAITERS;
+#endif
+       oldval = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
+                                                     newval, 0);
+
+       if (oldval != 0)
+         {
+           /* The mutex is locked.  The kernel will now take care of
+              everything.  */
+           int private = (robust
+                          ? PTHREAD_ROBUST_MUTEX_PSHARED (mutex)
+                          : PTHREAD_MUTEX_PSHARED (mutex));
+           INTERNAL_SYSCALL_DECL (__err);
+           int e = INTERNAL_SYSCALL (futex, __err, 4, &mutex->__data.__lock,
+                                     __lll_private_flag (FUTEX_LOCK_PI,
+                                                         private), 1, 0);
+
+           if (INTERNAL_SYSCALL_ERROR_P (e, __err)
+               && (INTERNAL_SYSCALL_ERRNO (e, __err) == ESRCH
+                   || INTERNAL_SYSCALL_ERRNO (e, __err) == EDEADLK))
+             {
+               assert (INTERNAL_SYSCALL_ERRNO (e, __err) != EDEADLK
+                       || (kind != PTHREAD_MUTEX_ERRORCHECK_NP
+                           && kind != PTHREAD_MUTEX_RECURSIVE_NP));
+               /* ESRCH can happen only for non-robust PI mutexes where
+                  the owner of the lock died.  */
+               assert (INTERNAL_SYSCALL_ERRNO (e, __err) != ESRCH || !robust);
+
+               /* Delay the thread indefinitely.  */
+               while (1)
+                 pause_not_cancel ();
+             }
+
+           oldval = mutex->__data.__lock;
+
+           assert (robust || (oldval & FUTEX_OWNER_DIED) == 0);
+         }
+
+       if (__builtin_expect (oldval & FUTEX_OWNER_DIED, 0))
+         {
+           atomic_and (&mutex->__data.__lock, ~FUTEX_OWNER_DIED);
+
+           /* We got the mutex.  */
+           mutex->__data.__count = 1;
+           /* But it is inconsistent unless marked otherwise.  */
+           mutex->__data.__owner = PTHREAD_MUTEX_INCONSISTENT;
+
+           ENQUEUE_MUTEX_PI (mutex);
+           THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+
+           /* Note that we deliberately exit here.  If we fall
+              through to the end of the function __nusers would be
+              incremented which is not correct because the old owner
+              has to be discounted.  If we are not supposed to
+              increment __nusers we actually have to decrement it here.  */
+#ifdef NO_INCR
+           --mutex->__data.__nusers;
+#endif
+
+           return EOWNERDEAD;
+         }
+
+       if (robust
+           && __builtin_expect (mutex->__data.__owner
+                                == PTHREAD_MUTEX_NOTRECOVERABLE, 0))
+         {
+           /* This mutex is now not recoverable.  */
+           mutex->__data.__count = 0;
+
+           INTERNAL_SYSCALL_DECL (__err);
+           INTERNAL_SYSCALL (futex, __err, 4, &mutex->__data.__lock,
+                             __lll_private_flag (FUTEX_UNLOCK_PI,
+                                                 PTHREAD_ROBUST_MUTEX_PSHARED (mutex)),
+                             0, 0);
+
+           THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+           return ENOTRECOVERABLE;
+         }
+
+       mutex->__data.__count = 1;
+       if (robust)
+         {
+           ENQUEUE_MUTEX_PI (mutex);
+           THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+         }
+      }
+      break;
+
+    case PTHREAD_MUTEX_PP_RECURSIVE_NP:
+    case PTHREAD_MUTEX_PP_ERRORCHECK_NP:
+    case PTHREAD_MUTEX_PP_NORMAL_NP:
+    case PTHREAD_MUTEX_PP_ADAPTIVE_NP:
+      {
+       int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP;
+
+       oldval = mutex->__data.__lock;
+
+       /* Check whether we already hold the mutex.  */
+       if (mutex->__data.__owner == id)
+         {
+           if (kind == PTHREAD_MUTEX_ERRORCHECK_NP)
+             return EDEADLK;
+
+           if (kind == PTHREAD_MUTEX_RECURSIVE_NP)
+             {
+               /* Just bump the counter.  */
+               if (__builtin_expect (mutex->__data.__count + 1 == 0, 0))
+                 /* Overflow of the counter.  */
+                 return EAGAIN;
+
+               ++mutex->__data.__count;
+
+               return 0;
+             }
+         }
+
+       int oldprio = -1, ceilval;
+       do
+         {
+           int ceiling = (oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK)
+                         >> PTHREAD_MUTEX_PRIO_CEILING_SHIFT;
+
+           if (__pthread_current_priority () > ceiling)
+             {
+               if (oldprio != -1)
+                 __pthread_tpp_change_priority (oldprio, -1);
+               return EINVAL;
+             }
+
+           int retval = __pthread_tpp_change_priority (oldprio, ceiling);
+           if (retval)
+             return retval;
+
+           ceilval = ceiling << PTHREAD_MUTEX_PRIO_CEILING_SHIFT;
+           oldprio = ceiling;
+
+           oldval
+             = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
+#ifdef NO_INCR
+                                                    ceilval | 2,
+#else
+                                                    ceilval | 1,
+#endif
+                                                    ceilval);
+
+           if (oldval == ceilval)
+             break;
+
+           do
+             {
+               oldval
+                 = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
+                                                        ceilval | 2,
+                                                        ceilval | 1);
+
+               if ((oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK) != ceilval)
+                 break;
+
+               if (oldval != ceilval)
+                 lll_futex_wait (&mutex->__data.__lock, ceilval | 2,
+                                 PTHREAD_MUTEX_PSHARED (mutex));
+             }
+           while (atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
+                                                       ceilval | 2, ceilval)
+                  != ceilval);
+         }
+       while ((oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK) != ceilval);
+
+       assert (mutex->__data.__owner == 0);
+       mutex->__data.__count = 1;
+      }
+      break;
+
+    default:
+      /* Correct code cannot set any other type.  */
+      return EINVAL;
+    }
+
+  /* Record the ownership.  */
+  mutex->__data.__owner = id;
+#ifndef NO_INCR
+  ++mutex->__data.__nusers;
+#endif
+
+  return 0;
+}
+#ifndef __pthread_mutex_lock
+strong_alias (__pthread_mutex_lock, pthread_mutex_lock)
+strong_alias (__pthread_mutex_lock, __pthread_mutex_lock_internal)
+#endif
+
+
+#ifdef NO_INCR
+void
+__pthread_mutex_cond_lock_adjust (
+     pthread_mutex_t *mutex)
+{
+  assert ((mutex->__data.__kind & PTHREAD_MUTEX_PRIO_INHERIT_NP) != 0);
+  assert ((mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) == 0);
+  assert ((mutex->__data.__kind & PTHREAD_MUTEX_PSHARED_BIT) == 0);
+
+  /* Record the ownership.  */
+  pid_t id = THREAD_GETMEM (THREAD_SELF, tid);
+  mutex->__data.__owner = id;
+
+  if (mutex->__data.__kind == PTHREAD_MUTEX_PI_RECURSIVE_NP)
+    ++mutex->__data.__count;
+}
+#endif
diff --git a/libpthread/nptl/pthread_mutex_setprioceiling.c b/libpthread/nptl/pthread_mutex_setprioceiling.c
new file mode 100644 (file)
index 0000000..836c9a3
--- /dev/null
@@ -0,0 +1,119 @@
+/* Set current priority ceiling of pthread_mutex_t.
+   Copyright (C) 2006, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2006.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stdbool.h>
+#include <errno.h>
+#include <pthreadP.h>
+
+
+int
+pthread_mutex_setprioceiling (mutex, prioceiling, old_ceiling)
+     pthread_mutex_t *mutex;
+     int prioceiling;
+     int *old_ceiling;
+{
+  /* The low bits of __kind aren't ever changed after pthread_mutex_init,
+     so we don't need a lock yet.  */
+  if ((mutex->__data.__kind & PTHREAD_MUTEX_PRIO_PROTECT_NP) == 0)
+    return EINVAL;
+
+  if (__sched_fifo_min_prio == -1)
+    __init_sched_fifo_prio ();
+
+  if (__builtin_expect (prioceiling < __sched_fifo_min_prio, 0)
+      || __builtin_expect (prioceiling > __sched_fifo_max_prio, 0)
+      || __builtin_expect ((prioceiling
+                           & (PTHREAD_MUTEXATTR_PRIO_CEILING_MASK
+                              >> PTHREAD_MUTEXATTR_PRIO_CEILING_SHIFT))
+                          != prioceiling, 0))
+    return EINVAL;
+
+  /* Check whether we already hold the mutex.  */
+  bool locked = false;
+  int kind = PTHREAD_MUTEX_TYPE (mutex);
+  if (mutex->__data.__owner == THREAD_GETMEM (THREAD_SELF, tid))
+    {
+      if (kind == PTHREAD_MUTEX_PP_ERRORCHECK_NP)
+       return EDEADLK;
+
+      if (kind == PTHREAD_MUTEX_PP_RECURSIVE_NP)
+       locked = true;
+    }
+
+  int oldval = mutex->__data.__lock;
+  if (! locked)
+    do
+      {
+       /* Need to lock the mutex, but without obeying the priority
+          protect protocol.  */
+       int ceilval = (oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK);
+
+       oldval = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
+                                                     ceilval | 1, ceilval);
+       if (oldval == ceilval)
+         break;
+
+       do
+         {
+           oldval
+             = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
+                                                    ceilval | 2,
+                                                    ceilval | 1);
+
+           if ((oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK) != ceilval)
+             break;
+
+           if (oldval != ceilval)
+             lll_futex_wait (&mutex->__data.__lock, ceilval | 2,
+                             PTHREAD_MUTEX_PSHARED (mutex));
+         }
+       while (atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
+                                                   ceilval | 2, ceilval)
+              != ceilval);
+
+       if ((oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK) != ceilval)
+         continue;
+      }
+    while (0);
+
+  int oldprio = (oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK)
+               >> PTHREAD_MUTEX_PRIO_CEILING_SHIFT;
+  if (locked)
+    {
+      int ret = __pthread_tpp_change_priority (oldprio, prioceiling);
+      if (ret)
+       return ret;
+    }
+
+  if (old_ceiling != NULL)
+    *old_ceiling = oldprio;
+
+  int newlock = 0;
+  if (locked)
+    newlock = (mutex->__data.__lock & ~PTHREAD_MUTEX_PRIO_CEILING_MASK);
+  mutex->__data.__lock = newlock
+                        | (prioceiling << PTHREAD_MUTEX_PRIO_CEILING_SHIFT);
+  atomic_full_barrier ();
+
+  lll_futex_wake (&mutex->__data.__lock, INT_MAX,
+                 PTHREAD_MUTEX_PSHARED (mutex));
+
+  return 0;
+}
diff --git a/libpthread/nptl/pthread_mutex_timedlock.c b/libpthread/nptl/pthread_mutex_timedlock.c
new file mode 100644 (file)
index 0000000..d6ab60e
--- /dev/null
@@ -0,0 +1,488 @@
+/* Copyright (C) 2002-2007, 2008 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 <time.h>
+#include "pthreadP.h"
+#include <lowlevellock.h>
+#include <not-cancel.h>
+
+/* We need to build this function with optimization to avoid
+ * lll_timedlock erroring out with
+ * error: can't find a register in class â€˜GENERAL_REGS’ while reloading â€˜asm’
+ */
+int
+attribute_optimize("Os")
+pthread_mutex_timedlock (
+     pthread_mutex_t *mutex,
+     const struct timespec *abstime)
+{
+  int oldval;
+  pid_t id = THREAD_GETMEM (THREAD_SELF, tid);
+  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 (__builtin_expect (PTHREAD_MUTEX_TYPE (mutex),
+                           PTHREAD_MUTEX_TIMED_NP))
+    {
+      /* Recursive mutex.  */
+    case PTHREAD_MUTEX_RECURSIVE_NP:
+      /* Check whether we already hold the mutex.  */
+      if (mutex->__data.__owner == id)
+       {
+         /* Just bump the counter.  */
+         if (__builtin_expect (mutex->__data.__count + 1 == 0, 0))
+           /* Overflow of the counter.  */
+           return EAGAIN;
+
+         ++mutex->__data.__count;
+
+         goto out;
+       }
+
+      /* We have to get the mutex.  */
+      result = lll_timedlock (mutex->__data.__lock, abstime,
+                             PTHREAD_MUTEX_PSHARED (mutex));
+
+      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 (__builtin_expect (mutex->__data.__owner == id, 0))
+       return EDEADLK;
+
+      /* FALLTHROUGH */
+
+    case PTHREAD_MUTEX_TIMED_NP:
+    simple:
+      /* Normal mutex.  */
+      result = lll_timedlock (mutex->__data.__lock, abstime,
+                             PTHREAD_MUTEX_PSHARED (mutex));
+      break;
+
+    case PTHREAD_MUTEX_ADAPTIVE_NP:
+      if (! __is_smp)
+       goto simple;
+
+      if (lll_trylock (mutex->__data.__lock) != 0)
+       {
+         int cnt = 0;
+         int max_cnt = MIN (MAX_ADAPTIVE_COUNT,
+                            mutex->__data.__spins * 2 + 10);
+         do
+           {
+             if (cnt++ >= max_cnt)
+               {
+                 result = lll_timedlock (mutex->__data.__lock, abstime,
+                                         PTHREAD_MUTEX_PSHARED (mutex));
+                 break;
+               }
+
+#ifdef BUSY_WAIT_NOP
+             BUSY_WAIT_NOP;
+#endif
+           }
+         while (lll_trylock (mutex->__data.__lock) != 0);
+
+         mutex->__data.__spins += (cnt - mutex->__data.__spins) / 8;
+       }
+      break;
+
+    case PTHREAD_MUTEX_ROBUST_RECURSIVE_NP:
+    case PTHREAD_MUTEX_ROBUST_ERRORCHECK_NP:
+    case PTHREAD_MUTEX_ROBUST_NORMAL_NP:
+    case PTHREAD_MUTEX_ROBUST_ADAPTIVE_NP:
+      THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
+                    &mutex->__data.__list.__next);
+
+      oldval = mutex->__data.__lock;
+      do
+       {
+       again:
+         if ((oldval & FUTEX_OWNER_DIED) != 0)
+           {
+             /* The previous owner died.  Try locking the mutex.  */
+             int newval = id | (oldval & FUTEX_WAITERS);
+
+             newval
+               = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
+                                                      newval, oldval);
+             if (newval != oldval)
+               {
+                 oldval = newval;
+                 goto again;
+               }
+
+             /* We got the mutex.  */
+             mutex->__data.__count = 1;
+             /* But it is inconsistent unless marked otherwise.  */
+             mutex->__data.__owner = PTHREAD_MUTEX_INCONSISTENT;
+
+             ENQUEUE_MUTEX (mutex);
+             THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+
+             /* Note that we deliberately exit here.  If we fall
+                through to the end of the function __nusers would be
+                incremented which is not correct because the old
+                owner has to be discounted.  */
+             return EOWNERDEAD;
+           }
+
+         /* Check whether we already hold the mutex.  */
+         if (__builtin_expect ((oldval & FUTEX_TID_MASK) == id, 0))
+           {
+             int kind = PTHREAD_MUTEX_TYPE (mutex);
+             if (kind == PTHREAD_MUTEX_ROBUST_ERRORCHECK_NP)
+               {
+                 THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
+                                NULL);
+                 return EDEADLK;
+               }
+
+             if (kind == PTHREAD_MUTEX_ROBUST_RECURSIVE_NP)
+               {
+                 THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
+                                NULL);
+
+                 /* Just bump the counter.  */
+                 if (__builtin_expect (mutex->__data.__count + 1 == 0, 0))
+                   /* Overflow of the counter.  */
+                   return EAGAIN;
+
+                 ++mutex->__data.__count;
+
+                 return 0;
+               }
+           }
+
+         result = lll_robust_timedlock (mutex->__data.__lock, abstime, id,
+                                        PTHREAD_ROBUST_MUTEX_PSHARED (mutex));
+
+         if (__builtin_expect (mutex->__data.__owner
+                               == PTHREAD_MUTEX_NOTRECOVERABLE, 0))
+           {
+             /* This mutex is now not recoverable.  */
+             mutex->__data.__count = 0;
+             lll_unlock (mutex->__data.__lock,
+                         PTHREAD_ROBUST_MUTEX_PSHARED (mutex));
+             THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+             return ENOTRECOVERABLE;
+           }
+
+         if (result == ETIMEDOUT || result == EINVAL)
+           goto out;
+
+         oldval = result;
+       }
+      while ((oldval & FUTEX_OWNER_DIED) != 0);
+
+      mutex->__data.__count = 1;
+      ENQUEUE_MUTEX (mutex);
+      THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+      break;
+
+    case PTHREAD_MUTEX_PI_RECURSIVE_NP:
+    case PTHREAD_MUTEX_PI_ERRORCHECK_NP:
+    case PTHREAD_MUTEX_PI_NORMAL_NP:
+    case PTHREAD_MUTEX_PI_ADAPTIVE_NP:
+    case PTHREAD_MUTEX_PI_ROBUST_RECURSIVE_NP:
+    case PTHREAD_MUTEX_PI_ROBUST_ERRORCHECK_NP:
+    case PTHREAD_MUTEX_PI_ROBUST_NORMAL_NP:
+    case PTHREAD_MUTEX_PI_ROBUST_ADAPTIVE_NP:
+      {
+       int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP;
+       int robust = mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP;
+
+       if (robust)
+         /* Note: robust PI futexes are signaled by setting bit 0.  */
+         THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
+                        (void *) (((uintptr_t) &mutex->__data.__list.__next)
+                                  | 1));
+
+       oldval = mutex->__data.__lock;
+
+       /* Check whether we already hold the mutex.  */
+       if (__builtin_expect ((oldval & FUTEX_TID_MASK) == id, 0))
+         {
+           if (kind == PTHREAD_MUTEX_ERRORCHECK_NP)
+             {
+               THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+               return EDEADLK;
+             }
+
+           if (kind == PTHREAD_MUTEX_RECURSIVE_NP)
+             {
+               THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+
+               /* Just bump the counter.  */
+               if (__builtin_expect (mutex->__data.__count + 1 == 0, 0))
+                 /* Overflow of the counter.  */
+                 return EAGAIN;
+
+               ++mutex->__data.__count;
+
+               return 0;
+             }
+         }
+
+       oldval = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
+                                                     id, 0);
+
+       if (oldval != 0)
+         {
+           /* The mutex is locked.  The kernel will now take care of
+              everything.  The timeout value must be a relative value.
+              Convert it.  */
+           int private = (robust
+                          ? PTHREAD_ROBUST_MUTEX_PSHARED (mutex)
+                          : PTHREAD_MUTEX_PSHARED (mutex));
+           INTERNAL_SYSCALL_DECL (__err);
+
+           int e = INTERNAL_SYSCALL (futex, __err, 4, &mutex->__data.__lock,
+                                     __lll_private_flag (FUTEX_LOCK_PI,
+                                                         private), 1,
+                                     abstime);
+           if (INTERNAL_SYSCALL_ERROR_P (e, __err))
+             {
+               if (INTERNAL_SYSCALL_ERRNO (e, __err) == ETIMEDOUT)
+                 return ETIMEDOUT;
+
+               if (INTERNAL_SYSCALL_ERRNO (e, __err) == ESRCH
+                   || INTERNAL_SYSCALL_ERRNO (e, __err) == EDEADLK)
+                 {
+                   assert (INTERNAL_SYSCALL_ERRNO (e, __err) != EDEADLK
+                           || (kind != PTHREAD_MUTEX_ERRORCHECK_NP
+                               && kind != PTHREAD_MUTEX_RECURSIVE_NP));
+                   /* ESRCH can happen only for non-robust PI mutexes where
+                      the owner of the lock died.  */
+                   assert (INTERNAL_SYSCALL_ERRNO (e, __err) != ESRCH
+                           || !robust);
+
+                   /* Delay the thread until the timeout is reached.
+                      Then return ETIMEDOUT.  */
+                   struct timespec reltime;
+                   struct timespec now;
+
+                   INTERNAL_SYSCALL (clock_gettime, __err, 2, CLOCK_REALTIME,
+                                     &now);
+                   reltime.tv_sec = abstime->tv_sec - now.tv_sec;
+                   reltime.tv_nsec = abstime->tv_nsec - now.tv_nsec;
+                   if (reltime.tv_nsec < 0)
+                     {
+                       reltime.tv_nsec += 1000000000;
+                       --reltime.tv_sec;
+                     }
+                   if (reltime.tv_sec >= 0)
+                     while (nanosleep_not_cancel (&reltime, &reltime) != 0)
+                       continue;
+
+                   return ETIMEDOUT;
+                 }
+
+               return INTERNAL_SYSCALL_ERRNO (e, __err);
+             }
+
+           oldval = mutex->__data.__lock;
+
+           assert (robust || (oldval & FUTEX_OWNER_DIED) == 0);
+         }
+
+       if (__builtin_expect (oldval & FUTEX_OWNER_DIED, 0))
+         {
+           atomic_and (&mutex->__data.__lock, ~FUTEX_OWNER_DIED);
+
+           /* We got the mutex.  */
+           mutex->__data.__count = 1;
+           /* But it is inconsistent unless marked otherwise.  */
+           mutex->__data.__owner = PTHREAD_MUTEX_INCONSISTENT;
+
+           ENQUEUE_MUTEX_PI (mutex);
+           THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+
+           /* Note that we deliberately exit here.  If we fall
+              through to the end of the function __nusers would be
+              incremented which is not correct because the old owner
+              has to be discounted.  */
+           return EOWNERDEAD;
+         }
+
+       if (robust
+           && __builtin_expect (mutex->__data.__owner
+                                == PTHREAD_MUTEX_NOTRECOVERABLE, 0))
+         {
+           /* This mutex is now not recoverable.  */
+           mutex->__data.__count = 0;
+
+           INTERNAL_SYSCALL_DECL (__err);
+           INTERNAL_SYSCALL (futex, __err, 4, &mutex->__data.__lock,
+                             __lll_private_flag (FUTEX_UNLOCK_PI,
+                                                 PTHREAD_ROBUST_MUTEX_PSHARED (mutex)),
+                             0, 0);
+
+           THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+           return ENOTRECOVERABLE;
+         }
+
+       mutex->__data.__count = 1;
+       if (robust)
+         {
+           ENQUEUE_MUTEX_PI (mutex);
+           THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+         }
+       }
+      break;
+
+    case PTHREAD_MUTEX_PP_RECURSIVE_NP:
+    case PTHREAD_MUTEX_PP_ERRORCHECK_NP:
+    case PTHREAD_MUTEX_PP_NORMAL_NP:
+    case PTHREAD_MUTEX_PP_ADAPTIVE_NP:
+      {
+       int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP;
+
+       oldval = mutex->__data.__lock;
+
+       /* Check whether we already hold the mutex.  */
+       if (mutex->__data.__owner == id)
+         {
+           if (kind == PTHREAD_MUTEX_ERRORCHECK_NP)
+             return EDEADLK;
+
+           if (kind == PTHREAD_MUTEX_RECURSIVE_NP)
+             {
+               /* Just bump the counter.  */
+               if (__builtin_expect (mutex->__data.__count + 1 == 0, 0))
+                 /* Overflow of the counter.  */
+                 return EAGAIN;
+
+               ++mutex->__data.__count;
+
+               return 0;
+             }
+         }
+
+       int oldprio = -1, ceilval;
+       do
+         {
+           int ceiling = (oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK)
+                         >> PTHREAD_MUTEX_PRIO_CEILING_SHIFT;
+
+           if (__pthread_current_priority () > ceiling)
+             {
+               result = EINVAL;
+             failpp:
+               if (oldprio != -1)
+                 __pthread_tpp_change_priority (oldprio, -1);
+               return result;
+             }
+
+           result = __pthread_tpp_change_priority (oldprio, ceiling);
+           if (result)
+             return result;
+
+           ceilval = ceiling << PTHREAD_MUTEX_PRIO_CEILING_SHIFT;
+           oldprio = ceiling;
+
+           oldval
+             = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
+                                                    ceilval | 1, ceilval);
+
+           if (oldval == ceilval)
+             break;
+
+           do
+             {
+               oldval
+                 = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
+                                                        ceilval | 2,
+                                                        ceilval | 1);
+
+               if ((oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK) != ceilval)
+                 break;
+
+               if (oldval != ceilval)
+                 {
+                   /* Reject invalid timeouts.  */
+                   if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)
+                     {
+                       result = EINVAL;
+                       goto failpp;
+                     }
+
+                   struct timeval tv;
+                   struct timespec rt;
+
+                   /* Get the current time.  */
+                   (void) gettimeofday (&tv, NULL);
+
+                   /* Compute relative timeout.  */
+                   rt.tv_sec = abstime->tv_sec - tv.tv_sec;
+                   rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000;
+                   if (rt.tv_nsec < 0)
+                     {
+                       rt.tv_nsec += 1000000000;
+                       --rt.tv_sec;
+                     }
+
+                   /* Already timed out?  */
+                   if (rt.tv_sec < 0)
+                     {
+                       result = ETIMEDOUT;
+                       goto failpp;
+                     }
+
+                   lll_futex_timed_wait (&mutex->__data.__lock,
+                                         ceilval | 2, &rt,
+                                         PTHREAD_MUTEX_PSHARED (mutex));
+                 }
+             }
+           while (atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
+                                                       ceilval | 2, ceilval)
+                  != ceilval);
+         }
+       while ((oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK) != ceilval);
+
+       assert (mutex->__data.__owner == 0);
+       mutex->__data.__count = 1;
+      }
+      break;
+
+    default:
+      /* Correct code cannot set any other type.  */
+      return EINVAL;
+    }
+
+  if (result == 0)
+    {
+      /* Record the ownership.  */
+      mutex->__data.__owner = id;
+      ++mutex->__data.__nusers;
+    }
+
+ out:
+  return result;
+}
diff --git a/libpthread/nptl/pthread_mutex_trylock.c b/libpthread/nptl/pthread_mutex_trylock.c
new file mode 100644 (file)
index 0000000..5555afc
--- /dev/null
@@ -0,0 +1,382 @@
+/* Copyright (C) 2002, 2003, 2005-2007, 2008 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 <stdlib.h>
+#include "pthreadP.h"
+#include <lowlevellock.h>
+
+
+int
+__pthread_mutex_trylock (
+     pthread_mutex_t *mutex)
+{
+  int oldval;
+  pid_t id = THREAD_GETMEM (THREAD_SELF, tid);
+
+  switch (__builtin_expect (PTHREAD_MUTEX_TYPE (mutex),
+                           PTHREAD_MUTEX_TIMED_NP))
+    {
+      /* Recursive mutex.  */
+    case PTHREAD_MUTEX_RECURSIVE_NP:
+      /* Check whether we already hold the mutex.  */
+      if (mutex->__data.__owner == id)
+       {
+         /* Just bump the counter.  */
+         if (__builtin_expect (mutex->__data.__count + 1 == 0, 0))
+           /* Overflow of the counter.  */
+           return EAGAIN;
+
+         ++mutex->__data.__count;
+         return 0;
+       }
+
+      if (lll_trylock (mutex->__data.__lock) == 0)
+       {
+         /* Record the ownership.  */
+         mutex->__data.__owner = id;
+         mutex->__data.__count = 1;
+         ++mutex->__data.__nusers;
+         return 0;
+       }
+      break;
+
+    case PTHREAD_MUTEX_ERRORCHECK_NP:
+    case PTHREAD_MUTEX_TIMED_NP:
+    case PTHREAD_MUTEX_ADAPTIVE_NP:
+      /* Normal mutex.  */
+      if (lll_trylock (mutex->__data.__lock) != 0)
+       break;
+
+      /* Record the ownership.  */
+      mutex->__data.__owner = id;
+      ++mutex->__data.__nusers;
+
+      return 0;
+
+    case PTHREAD_MUTEX_ROBUST_RECURSIVE_NP:
+    case PTHREAD_MUTEX_ROBUST_ERRORCHECK_NP:
+    case PTHREAD_MUTEX_ROBUST_NORMAL_NP:
+    case PTHREAD_MUTEX_ROBUST_ADAPTIVE_NP:
+      THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
+                    &mutex->__data.__list.__next);
+
+      oldval = mutex->__data.__lock;
+      do
+       {
+       again:
+         if ((oldval & FUTEX_OWNER_DIED) != 0)
+           {
+             /* The previous owner died.  Try locking the mutex.  */
+             int newval = id | (oldval & FUTEX_WAITERS);
+
+             newval
+               = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
+                                                      newval, oldval);
+
+             if (newval != oldval)
+               {
+                 oldval = newval;
+                 goto again;
+               }
+
+             /* We got the mutex.  */
+             mutex->__data.__count = 1;
+             /* But it is inconsistent unless marked otherwise.  */
+             mutex->__data.__owner = PTHREAD_MUTEX_INCONSISTENT;
+
+             ENQUEUE_MUTEX (mutex);
+             THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+
+             /* Note that we deliberately exist here.  If we fall
+                through to the end of the function __nusers would be
+                incremented which is not correct because the old
+                owner has to be discounted.  */
+             return EOWNERDEAD;
+           }
+
+         /* Check whether we already hold the mutex.  */
+         if (__builtin_expect ((oldval & FUTEX_TID_MASK) == id, 0))
+           {
+             int kind = PTHREAD_MUTEX_TYPE (mutex);
+             if (kind == PTHREAD_MUTEX_ROBUST_ERRORCHECK_NP)
+               {
+                 THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
+                                NULL);
+                 return EDEADLK;
+               }
+
+             if (kind == PTHREAD_MUTEX_ROBUST_RECURSIVE_NP)
+               {
+                 THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
+                                NULL);
+
+                 /* Just bump the counter.  */
+                 if (__builtin_expect (mutex->__data.__count + 1 == 0, 0))
+                   /* Overflow of the counter.  */
+                   return EAGAIN;
+
+                 ++mutex->__data.__count;
+
+                 return 0;
+               }
+           }
+
+         oldval = lll_robust_trylock (mutex->__data.__lock, id);
+         if (oldval != 0 && (oldval & FUTEX_OWNER_DIED) == 0)
+           {
+             THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+
+             return EBUSY;
+           }
+
+         if (__builtin_expect (mutex->__data.__owner
+                               == PTHREAD_MUTEX_NOTRECOVERABLE, 0))
+           {
+             /* This mutex is now not recoverable.  */
+             mutex->__data.__count = 0;
+             if (oldval == id)
+               lll_unlock (mutex->__data.__lock,
+                           PTHREAD_ROBUST_MUTEX_PSHARED (mutex));
+             THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+             return ENOTRECOVERABLE;
+           }
+       }
+      while ((oldval & FUTEX_OWNER_DIED) != 0);
+
+      ENQUEUE_MUTEX (mutex);
+      THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+
+      mutex->__data.__owner = id;
+      ++mutex->__data.__nusers;
+      mutex->__data.__count = 1;
+
+      return 0;
+
+    case PTHREAD_MUTEX_PI_RECURSIVE_NP:
+    case PTHREAD_MUTEX_PI_ERRORCHECK_NP:
+    case PTHREAD_MUTEX_PI_NORMAL_NP:
+    case PTHREAD_MUTEX_PI_ADAPTIVE_NP:
+    case PTHREAD_MUTEX_PI_ROBUST_RECURSIVE_NP:
+    case PTHREAD_MUTEX_PI_ROBUST_ERRORCHECK_NP:
+    case PTHREAD_MUTEX_PI_ROBUST_NORMAL_NP:
+    case PTHREAD_MUTEX_PI_ROBUST_ADAPTIVE_NP:
+      {
+       int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP;
+       int robust = mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP;
+
+       if (robust)
+         /* Note: robust PI futexes are signaled by setting bit 0.  */
+         THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
+                        (void *) (((uintptr_t) &mutex->__data.__list.__next)
+                                  | 1));
+
+       oldval = mutex->__data.__lock;
+
+       /* Check whether we already hold the mutex.  */
+       if (__builtin_expect ((oldval & FUTEX_TID_MASK) == id, 0))
+         {
+           if (kind == PTHREAD_MUTEX_ERRORCHECK_NP)
+             {
+               THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+               return EDEADLK;
+             }
+
+           if (kind == PTHREAD_MUTEX_RECURSIVE_NP)
+             {
+               THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+
+               /* Just bump the counter.  */
+               if (__builtin_expect (mutex->__data.__count + 1 == 0, 0))
+                 /* Overflow of the counter.  */
+                 return EAGAIN;
+
+               ++mutex->__data.__count;
+
+               return 0;
+             }
+         }
+
+       oldval
+         = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
+                                                id, 0);
+
+       if (oldval != 0)
+         {
+           if ((oldval & FUTEX_OWNER_DIED) == 0)
+             {
+               THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+
+               return EBUSY;
+             }
+
+           assert (robust);
+
+           /* The mutex owner died.  The kernel will now take care of
+              everything.  */
+           int private = (robust
+                          ? PTHREAD_ROBUST_MUTEX_PSHARED (mutex)
+                          : PTHREAD_MUTEX_PSHARED (mutex));
+           INTERNAL_SYSCALL_DECL (__err);
+           int e = INTERNAL_SYSCALL (futex, __err, 4, &mutex->__data.__lock,
+                                     __lll_private_flag (FUTEX_TRYLOCK_PI,
+                                                         private), 0, 0);
+
+           if (INTERNAL_SYSCALL_ERROR_P (e, __err)
+               && INTERNAL_SYSCALL_ERRNO (e, __err) == EWOULDBLOCK)
+             {
+               THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+
+               return EBUSY;
+             }
+
+           oldval = mutex->__data.__lock;
+         }
+
+       if (__builtin_expect (oldval & FUTEX_OWNER_DIED, 0))
+         {
+           atomic_and (&mutex->__data.__lock, ~FUTEX_OWNER_DIED);
+
+           /* We got the mutex.  */
+           mutex->__data.__count = 1;
+           /* But it is inconsistent unless marked otherwise.  */
+           mutex->__data.__owner = PTHREAD_MUTEX_INCONSISTENT;
+
+           ENQUEUE_MUTEX (mutex);
+           THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+
+           /* Note that we deliberately exit here.  If we fall
+              through to the end of the function __nusers would be
+              incremented which is not correct because the old owner
+              has to be discounted.  */
+           return EOWNERDEAD;
+         }
+
+       if (robust
+           && __builtin_expect (mutex->__data.__owner
+                                == PTHREAD_MUTEX_NOTRECOVERABLE, 0))
+         {
+           /* This mutex is now not recoverable.  */
+           mutex->__data.__count = 0;
+
+           INTERNAL_SYSCALL_DECL (__err);
+           INTERNAL_SYSCALL (futex, __err, 4, &mutex->__data.__lock,
+                             __lll_private_flag (FUTEX_UNLOCK_PI,
+                                                 PTHREAD_ROBUST_MUTEX_PSHARED (mutex)),
+                             0, 0);
+
+           THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+           return ENOTRECOVERABLE;
+         }
+
+       if (robust)
+         {
+           ENQUEUE_MUTEX_PI (mutex);
+           THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+         }
+
+       mutex->__data.__owner = id;
+       ++mutex->__data.__nusers;
+       mutex->__data.__count = 1;
+
+       return 0;
+      }
+
+    case PTHREAD_MUTEX_PP_RECURSIVE_NP:
+    case PTHREAD_MUTEX_PP_ERRORCHECK_NP:
+    case PTHREAD_MUTEX_PP_NORMAL_NP:
+    case PTHREAD_MUTEX_PP_ADAPTIVE_NP:
+      {
+       int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP;
+
+       oldval = mutex->__data.__lock;
+
+       /* Check whether we already hold the mutex.  */
+       if (mutex->__data.__owner == id)
+         {
+           if (kind == PTHREAD_MUTEX_ERRORCHECK_NP)
+             return EDEADLK;
+
+           if (kind == PTHREAD_MUTEX_RECURSIVE_NP)
+             {
+               /* Just bump the counter.  */
+               if (__builtin_expect (mutex->__data.__count + 1 == 0, 0))
+                 /* Overflow of the counter.  */
+                 return EAGAIN;
+
+               ++mutex->__data.__count;
+
+               return 0;
+             }
+         }
+
+       int oldprio = -1, ceilval;
+       do
+         {
+           int ceiling = (oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK)
+                         >> PTHREAD_MUTEX_PRIO_CEILING_SHIFT;
+
+           if (__pthread_current_priority () > ceiling)
+             {
+               if (oldprio != -1)
+                 __pthread_tpp_change_priority (oldprio, -1);
+               return EINVAL;
+             }
+
+           int retval = __pthread_tpp_change_priority (oldprio, ceiling);
+           if (retval)
+             return retval;
+
+           ceilval = ceiling << PTHREAD_MUTEX_PRIO_CEILING_SHIFT;
+           oldprio = ceiling;
+
+           oldval
+             = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
+                                                    ceilval | 1, ceilval);
+
+           if (oldval == ceilval)
+             break;
+         }
+       while ((oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK) != ceilval);
+
+       if (oldval != ceilval)
+         {
+           __pthread_tpp_change_priority (oldprio, -1);
+           break;
+         }
+
+       assert (mutex->__data.__owner == 0);
+       /* Record the ownership.  */
+       mutex->__data.__owner = id;
+       ++mutex->__data.__nusers;
+       mutex->__data.__count = 1;
+
+       return 0;
+      }
+      break;
+
+    default:
+      /* Correct code cannot set any other type.  */
+      return EINVAL;
+    }
+
+  return EBUSY;
+}
+strong_alias (__pthread_mutex_trylock, pthread_mutex_trylock)
diff --git a/libpthread/nptl/pthread_mutex_unlock.c b/libpthread/nptl/pthread_mutex_unlock.c
new file mode 100644 (file)
index 0000000..f164cde
--- /dev/null
@@ -0,0 +1,293 @@
+/* Copyright (C) 2002, 2003, 2005-2008, 2009 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 <stdlib.h>
+#include "pthreadP.h"
+#include <lowlevellock.h>
+
+static int
+internal_function
+__pthread_mutex_unlock_full (pthread_mutex_t *mutex, int decr)
+     __attribute_noinline__;
+
+int
+internal_function attribute_hidden
+__pthread_mutex_unlock_usercnt (
+     pthread_mutex_t *mutex,
+     int decr)
+{
+  int type = PTHREAD_MUTEX_TYPE (mutex);
+  if (__builtin_expect (type & ~PTHREAD_MUTEX_KIND_MASK_NP, 0))
+    return __pthread_mutex_unlock_full (mutex, decr);
+
+  if (__builtin_expect (type, PTHREAD_MUTEX_TIMED_NP)
+      == PTHREAD_MUTEX_TIMED_NP)
+    {
+      /* Always reset the owner field.  */
+    normal:
+      mutex->__data.__owner = 0;
+      if (decr)
+       /* One less user.  */
+       --mutex->__data.__nusers;
+
+      /* Unlock.  */
+      lll_unlock (mutex->__data.__lock, PTHREAD_MUTEX_PSHARED (mutex));
+      return 0;
+    }
+  else if (__builtin_expect (type == PTHREAD_MUTEX_RECURSIVE_NP, 1))
+    {
+      /* Recursive mutex.  */
+      if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid))
+       return EPERM;
+
+      if (--mutex->__data.__count != 0)
+       /* We still hold the mutex.  */
+       return 0;
+      goto normal;
+    }
+  else if (__builtin_expect (type == PTHREAD_MUTEX_ADAPTIVE_NP, 1))
+    goto normal;
+  else
+    {
+      /* Error checking mutex.  */
+      assert (type == PTHREAD_MUTEX_ERRORCHECK_NP);
+      if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid)
+         || ! lll_islocked (mutex->__data.__lock))
+       return EPERM;
+      goto normal;
+    }
+}
+
+
+static int
+internal_function
+__pthread_mutex_unlock_full (pthread_mutex_t *mutex, int decr)
+{
+  int newowner = 0;
+
+  switch (PTHREAD_MUTEX_TYPE (mutex))
+    {
+    case PTHREAD_MUTEX_ROBUST_RECURSIVE_NP:
+      /* Recursive mutex.  */
+      if ((mutex->__data.__lock & FUTEX_TID_MASK)
+         == THREAD_GETMEM (THREAD_SELF, tid)
+         && __builtin_expect (mutex->__data.__owner
+                              == PTHREAD_MUTEX_INCONSISTENT, 0))
+       {
+         if (--mutex->__data.__count != 0)
+           /* We still hold the mutex.  */
+           return ENOTRECOVERABLE;
+
+         goto notrecoverable;
+       }
+
+      if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid))
+       return EPERM;
+
+      if (--mutex->__data.__count != 0)
+       /* We still hold the mutex.  */
+       return 0;
+
+      goto robust;
+
+    case PTHREAD_MUTEX_ROBUST_ERRORCHECK_NP:
+    case PTHREAD_MUTEX_ROBUST_NORMAL_NP:
+    case PTHREAD_MUTEX_ROBUST_ADAPTIVE_NP:
+      if ((mutex->__data.__lock & FUTEX_TID_MASK)
+         != THREAD_GETMEM (THREAD_SELF, tid)
+         || ! lll_islocked (mutex->__data.__lock))
+       return EPERM;
+
+      /* If the previous owner died and the caller did not succeed in
+        making the state consistent, mark the mutex as unrecoverable
+        and make all waiters.  */
+      if (__builtin_expect (mutex->__data.__owner
+                           == PTHREAD_MUTEX_INCONSISTENT, 0))
+      notrecoverable:
+       newowner = PTHREAD_MUTEX_NOTRECOVERABLE;
+
+    robust:
+      /* Remove mutex from the list.  */
+      THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
+                    &mutex->__data.__list.__next);
+      DEQUEUE_MUTEX (mutex);
+
+      mutex->__data.__owner = newowner;
+      if (decr)
+       /* One less user.  */
+       --mutex->__data.__nusers;
+
+      /* Unlock.  */
+      lll_robust_unlock (mutex->__data.__lock,
+                        PTHREAD_ROBUST_MUTEX_PSHARED (mutex));
+
+      THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+      break;
+
+    case PTHREAD_MUTEX_PI_RECURSIVE_NP:
+      /* Recursive mutex.  */
+      if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid))
+       return EPERM;
+
+      if (--mutex->__data.__count != 0)
+       /* We still hold the mutex.  */
+       return 0;
+      goto continue_pi_non_robust;
+
+    case PTHREAD_MUTEX_PI_ROBUST_RECURSIVE_NP:
+      /* Recursive mutex.  */
+      if ((mutex->__data.__lock & FUTEX_TID_MASK)
+         == THREAD_GETMEM (THREAD_SELF, tid)
+         && __builtin_expect (mutex->__data.__owner
+                              == PTHREAD_MUTEX_INCONSISTENT, 0))
+       {
+         if (--mutex->__data.__count != 0)
+           /* We still hold the mutex.  */
+           return ENOTRECOVERABLE;
+
+         goto pi_notrecoverable;
+       }
+
+      if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid))
+       return EPERM;
+
+      if (--mutex->__data.__count != 0)
+       /* We still hold the mutex.  */
+       return 0;
+
+      goto continue_pi_robust;
+
+    case PTHREAD_MUTEX_PI_ERRORCHECK_NP:
+    case PTHREAD_MUTEX_PI_NORMAL_NP:
+    case PTHREAD_MUTEX_PI_ADAPTIVE_NP:
+    case PTHREAD_MUTEX_PI_ROBUST_ERRORCHECK_NP:
+    case PTHREAD_MUTEX_PI_ROBUST_NORMAL_NP:
+    case PTHREAD_MUTEX_PI_ROBUST_ADAPTIVE_NP:
+      if ((mutex->__data.__lock & FUTEX_TID_MASK)
+         != THREAD_GETMEM (THREAD_SELF, tid)
+         || ! lll_islocked (mutex->__data.__lock))
+       return EPERM;
+
+      /* If the previous owner died and the caller did not succeed in
+        making the state consistent, mark the mutex as unrecoverable
+        and make all waiters.  */
+      if ((mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) != 0
+         && __builtin_expect (mutex->__data.__owner
+                              == PTHREAD_MUTEX_INCONSISTENT, 0))
+      pi_notrecoverable:
+       newowner = PTHREAD_MUTEX_NOTRECOVERABLE;
+
+      if ((mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) != 0)
+       {
+       continue_pi_robust:
+         /* Remove mutex from the list.
+            Note: robust PI futexes are signaled by setting bit 0.  */
+         THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
+                        (void *) (((uintptr_t) &mutex->__data.__list.__next)
+                                  | 1));
+         DEQUEUE_MUTEX (mutex);
+       }
+
+    continue_pi_non_robust:
+      mutex->__data.__owner = newowner;
+      if (decr)
+       /* One less user.  */
+       --mutex->__data.__nusers;
+
+      /* Unlock.  */
+      if ((mutex->__data.__lock & FUTEX_WAITERS) != 0
+         || atomic_compare_and_exchange_bool_rel (&mutex->__data.__lock, 0,
+                                                  THREAD_GETMEM (THREAD_SELF,
+                                                                 tid)))
+       {
+         int robust = mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP;
+         int private = (robust
+                        ? PTHREAD_ROBUST_MUTEX_PSHARED (mutex)
+                        : PTHREAD_MUTEX_PSHARED (mutex));
+         INTERNAL_SYSCALL_DECL (__err);
+         INTERNAL_SYSCALL (futex, __err, 2, &mutex->__data.__lock,
+                           __lll_private_flag (FUTEX_UNLOCK_PI, private));
+       }
+
+      THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+      break;
+
+    case PTHREAD_MUTEX_PP_RECURSIVE_NP:
+      /* Recursive mutex.  */
+      if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid))
+       return EPERM;
+
+      if (--mutex->__data.__count != 0)
+       /* We still hold the mutex.  */
+       return 0;
+      goto pp;
+
+    case PTHREAD_MUTEX_PP_ERRORCHECK_NP:
+      /* Error checking mutex.  */
+      if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid)
+         || (mutex->__data.__lock & ~ PTHREAD_MUTEX_PRIO_CEILING_MASK) == 0)
+       return EPERM;
+      /* FALLTHROUGH */
+
+    case PTHREAD_MUTEX_PP_NORMAL_NP:
+    case PTHREAD_MUTEX_PP_ADAPTIVE_NP:
+      /* Always reset the owner field.  */
+    pp:
+      mutex->__data.__owner = 0;
+
+      if (decr)
+       /* One less user.  */
+       --mutex->__data.__nusers;
+
+      /* Unlock.  */
+      int newval, oldval;
+      do
+       {
+         oldval = mutex->__data.__lock;
+         newval = oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK;
+       }
+      while (atomic_compare_and_exchange_bool_rel (&mutex->__data.__lock,
+                                                  newval, oldval));
+
+      if ((oldval & ~PTHREAD_MUTEX_PRIO_CEILING_MASK) > 1)
+       lll_futex_wake (&mutex->__data.__lock, 1,
+                       PTHREAD_MUTEX_PSHARED (mutex));
+
+      int oldprio = newval >> PTHREAD_MUTEX_PRIO_CEILING_SHIFT;
+      return __pthread_tpp_change_priority (oldprio, -1);
+
+    default:
+      /* Correct code cannot set any other type.  */
+      return EINVAL;
+    }
+
+  return 0;
+}
+
+
+int
+__pthread_mutex_unlock (
+     pthread_mutex_t *mutex)
+{
+  return __pthread_mutex_unlock_usercnt (mutex, 1);
+}
+strong_alias (__pthread_mutex_unlock, pthread_mutex_unlock)
+strong_alias (__pthread_mutex_unlock, __pthread_mutex_unlock_internal)
diff --git a/libpthread/nptl/pthread_mutexattr_destroy.c b/libpthread/nptl/pthread_mutexattr_destroy.c
new file mode 100644 (file)
index 0000000..adf2884
--- /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>
+
+
+int
+__pthread_mutexattr_destroy (pthread_mutexattr_t *attr)
+{
+  return 0;
+}
+strong_alias (__pthread_mutexattr_destroy, pthread_mutexattr_destroy)
diff --git a/libpthread/nptl/pthread_mutexattr_getprioceiling.c b/libpthread/nptl/pthread_mutexattr_getprioceiling.c
new file mode 100644 (file)
index 0000000..29e3eb2
--- /dev/null
@@ -0,0 +1,48 @@
+/* Get priority ceiling setting from pthread_mutexattr_t.
+   Copyright (C) 2006 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2006.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with 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_getprioceiling (
+     const pthread_mutexattr_t *attr,
+     int *prioceiling)
+{
+  const struct pthread_mutexattr *iattr;
+  int ceiling;
+
+  iattr = (const struct pthread_mutexattr *) attr;
+
+  ceiling = ((iattr->mutexkind & PTHREAD_MUTEXATTR_PRIO_CEILING_MASK)
+            >> PTHREAD_MUTEXATTR_PRIO_CEILING_SHIFT);
+
+  if (! ceiling)
+    {
+      if (__sched_fifo_min_prio == -1)
+       __init_sched_fifo_prio ();
+      if (ceiling < __sched_fifo_min_prio)
+       ceiling = __sched_fifo_min_prio;
+    }
+
+  *prioceiling = ceiling;
+
+  return 0;
+}
diff --git a/libpthread/nptl/pthread_mutexattr_getprotocol.c b/libpthread/nptl/pthread_mutexattr_getprotocol.c
new file mode 100644 (file)
index 0000000..49c5157
--- /dev/null
@@ -0,0 +1,37 @@
+/* Get priority protocol setting from pthread_mutexattr_t.
+   Copyright (C) 2006 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2006.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with 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_getprotocol (
+     const pthread_mutexattr_t *attr,
+     int *protocol)
+{
+  const struct pthread_mutexattr *iattr;
+
+  iattr = (const struct pthread_mutexattr *) attr;
+
+  *protocol = ((iattr->mutexkind & PTHREAD_MUTEXATTR_PROTOCOL_MASK)
+              >> PTHREAD_MUTEXATTR_PROTOCOL_SHIFT);
+
+  return 0;
+}
diff --git a/libpthread/nptl/pthread_mutexattr_getpshared.c b/libpthread/nptl/pthread_mutexattr_getpshared.c
new file mode 100644 (file)
index 0000000..e67cf15
--- /dev/null
@@ -0,0 +1,36 @@
+/* Copyright (C) 2002, 2005 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 (
+     const pthread_mutexattr_t *attr,
+     int *pshared)
+{
+  const struct pthread_mutexattr *iattr;
+
+  iattr = (const struct pthread_mutexattr *) attr;
+
+  *pshared = ((iattr->mutexkind & PTHREAD_MUTEXATTR_FLAG_PSHARED) != 0
+             ? PTHREAD_PROCESS_SHARED : PTHREAD_PROCESS_PRIVATE);
+
+  return 0;
+}
diff --git a/libpthread/nptl/pthread_mutexattr_getrobust.c b/libpthread/nptl/pthread_mutexattr_getrobust.c
new file mode 100644 (file)
index 0000000..7d495f8
--- /dev/null
@@ -0,0 +1,37 @@
+/* Copyright (C) 2005, 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2005.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with 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_getrobust (
+     const pthread_mutexattr_t *attr,
+     int *robustness)
+{
+  const struct pthread_mutexattr *iattr;
+
+  iattr = (const struct pthread_mutexattr *) attr;
+
+  *robustness = ((iattr->mutexkind & PTHREAD_MUTEXATTR_FLAG_ROBUST) != 0
+                ? PTHREAD_MUTEX_ROBUST_NP : PTHREAD_MUTEX_STALLED_NP);
+
+  return 0;
+}
+weak_alias (pthread_mutexattr_getrobust, pthread_mutexattr_getrobust_np)
diff --git a/libpthread/nptl/pthread_mutexattr_gettype.c b/libpthread/nptl/pthread_mutexattr_gettype.c
new file mode 100644 (file)
index 0000000..2543486
--- /dev/null
@@ -0,0 +1,36 @@
+/* Copyright (C) 2002, 2005 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 (
+     const pthread_mutexattr_t *attr,
+     int *kind)
+{
+  const struct pthread_mutexattr *iattr;
+
+  iattr = (const struct pthread_mutexattr *) attr;
+
+  *kind = iattr->mutexkind & ~PTHREAD_MUTEXATTR_FLAG_BITS;
+
+  return 0;
+}
+weak_alias (pthread_mutexattr_gettype, pthread_mutexattr_getkind_np)
diff --git a/libpthread/nptl/pthread_mutexattr_init.c b/libpthread/nptl/pthread_mutexattr_init.c
new file mode 100644 (file)
index 0000000..1b67284
--- /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 (
+     pthread_mutexattr_t *attr)
+{
+  if (sizeof (struct pthread_mutexattr) != sizeof (pthread_mutexattr_t))
+    memset (attr, '\0', sizeof (*attr));
+
+  /* We use bit 31 to signal 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/libpthread/nptl/pthread_mutexattr_setprioceiling.c b/libpthread/nptl/pthread_mutexattr_setprioceiling.c
new file mode 100644 (file)
index 0000000..3a13fb8
--- /dev/null
@@ -0,0 +1,47 @@
+/* Change priority ceiling setting in pthread_mutexattr_t.
+   Copyright (C) 2006 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2006.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with 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_setprioceiling (
+     pthread_mutexattr_t *attr,
+     int prioceiling)
+{
+  if (__sched_fifo_min_prio == -1)
+    __init_sched_fifo_prio ();
+
+  if (__builtin_expect (prioceiling < __sched_fifo_min_prio, 0)
+      || __builtin_expect (prioceiling > __sched_fifo_max_prio, 0)
+      || __builtin_expect ((prioceiling
+                           & (PTHREAD_MUTEXATTR_PRIO_CEILING_MASK
+                              >> PTHREAD_MUTEXATTR_PRIO_CEILING_SHIFT))
+                          != prioceiling, 0))
+    return EINVAL;
+
+  struct pthread_mutexattr *iattr = (struct pthread_mutexattr *) attr;
+
+  iattr->mutexkind = ((iattr->mutexkind & ~PTHREAD_MUTEXATTR_PRIO_CEILING_MASK)
+                     | (prioceiling << PTHREAD_MUTEXATTR_PRIO_CEILING_SHIFT));
+
+  return 0;
+}
diff --git a/libpthread/nptl/pthread_mutexattr_setprotocol.c b/libpthread/nptl/pthread_mutexattr_setprotocol.c
new file mode 100644 (file)
index 0000000..1ffcaf6
--- /dev/null
@@ -0,0 +1,41 @@
+/* Change priority protocol setting in pthread_mutexattr_t.
+   Copyright (C) 2006 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2006.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with 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_setprotocol (
+     pthread_mutexattr_t *attr,
+     int protocol)
+{
+  if (protocol != PTHREAD_PRIO_NONE
+      && protocol != PTHREAD_PRIO_INHERIT
+      && __builtin_expect (protocol != PTHREAD_PRIO_PROTECT, 0))
+    return EINVAL;
+
+  struct pthread_mutexattr *iattr = (struct pthread_mutexattr *) attr;
+
+  iattr->mutexkind = ((iattr->mutexkind & ~PTHREAD_MUTEXATTR_PROTOCOL_MASK)
+                     | (protocol << PTHREAD_MUTEXATTR_PROTOCOL_SHIFT));
+
+  return 0;
+}
diff --git a/libpthread/nptl/pthread_mutexattr_setpshared.c b/libpthread/nptl/pthread_mutexattr_setpshared.c
new file mode 100644 (file)
index 0000000..d84a92e
--- /dev/null
@@ -0,0 +1,43 @@
+/* Copyright (C) 2002, 2005 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 (
+     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;
+
+  if (pshared == PTHREAD_PROCESS_PRIVATE)
+    iattr->mutexkind &= ~PTHREAD_MUTEXATTR_FLAG_PSHARED;
+  else
+    iattr->mutexkind |= PTHREAD_MUTEXATTR_FLAG_PSHARED;
+
+  return 0;
+}
diff --git a/libpthread/nptl/pthread_mutexattr_setrobust.c b/libpthread/nptl/pthread_mutexattr_setrobust.c
new file mode 100644 (file)
index 0000000..fe94fd2
--- /dev/null
@@ -0,0 +1,44 @@
+/* Copyright (C) 2005, 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2005.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with 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_setrobust (
+     pthread_mutexattr_t *attr,
+     int robustness)
+{
+  if (robustness != PTHREAD_MUTEX_STALLED_NP
+      && __builtin_expect (robustness != PTHREAD_MUTEX_ROBUST_NP, 0))
+    return EINVAL;
+
+  struct pthread_mutexattr *iattr = (struct pthread_mutexattr *) attr;
+
+  /* We use bit 30 to signal whether the mutex is going to be
+     robust or not.  */
+  if (robustness == PTHREAD_MUTEX_STALLED_NP)
+    iattr->mutexkind &= ~PTHREAD_MUTEXATTR_FLAG_ROBUST;
+  else
+    iattr->mutexkind |= PTHREAD_MUTEXATTR_FLAG_ROBUST;
+
+  return 0;
+}
+weak_alias (pthread_mutexattr_setrobust, pthread_mutexattr_setrobust_np)
diff --git a/libpthread/nptl/pthread_mutexattr_settype.c b/libpthread/nptl/pthread_mutexattr_settype.c
new file mode 100644 (file)
index 0000000..f86dd63
--- /dev/null
@@ -0,0 +1,41 @@
+/* Copyright (C) 2002, 2005 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 (
+     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;
+
+  iattr->mutexkind = (iattr->mutexkind & PTHREAD_MUTEXATTR_FLAG_BITS) | kind;
+
+  return 0;
+}
+weak_alias (__pthread_mutexattr_settype, pthread_mutexattr_setkind_np)
+strong_alias (__pthread_mutexattr_settype, pthread_mutexattr_settype)
diff --git a/libpthread/nptl/pthread_rwlock_destroy.c b/libpthread/nptl/pthread_rwlock_destroy.c
new file mode 100644 (file)
index 0000000..d38202b
--- /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_rwlock_destroy (pthread_rwlock_t *rwlock)
+{
+  /* Nothing to be done.  For now.  */
+  return 0;
+}
+strong_alias (__pthread_rwlock_destroy, pthread_rwlock_destroy)
diff --git a/libpthread/nptl/pthread_rwlock_init.c b/libpthread/nptl/pthread_rwlock_init.c
new file mode 100644 (file)
index 0000000..aab832e
--- /dev/null
@@ -0,0 +1,73 @@
+/* Copyright (C) 2002, 2007, 2009 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 <bits/kernel-features.h>
+
+
+static const struct pthread_rwlockattr default_attr =
+  {
+    .lockkind = PTHREAD_RWLOCK_DEFAULT_NP,
+    .pshared = PTHREAD_PROCESS_PRIVATE
+  };
+
+
+int
+__pthread_rwlock_init (
+     pthread_rwlock_t *rwlock,
+     const pthread_rwlockattr_t *attr)
+{
+  const struct pthread_rwlockattr *iattr;
+
+  iattr = ((const struct pthread_rwlockattr *) attr) ?: &default_attr;
+
+  memset (rwlock, '\0', sizeof (*rwlock));
+
+  rwlock->__data.__flags
+    = iattr->lockkind == PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP;
+
+  /* The __SHARED field is computed to minimize the work that needs to
+     be done while handling the futex.  There are two inputs: the
+     availability of private futexes and whether the rwlock is shared
+     or private.  Unfortunately the value of a private rwlock is
+     fixed: it must be zero.  The PRIVATE_FUTEX flag has the value
+     0x80 in case private futexes are available and zero otherwise.
+     This leads to the following table:
+
+                |     pshared     |     result
+                | shared  private | shared  private |
+     ------------+-----------------+-----------------+
+     !avail 0    |     0       0   |     0       0   |
+      avail 0x80 |  0x80       0   |     0    0x80   |
+
+     If the pshared value is in locking functions XORed with avail
+     we get the expected result.  */
+#ifdef __ASSUME_PRIVATE_FUTEX
+  rwlock->__data.__shared = (iattr->pshared == PTHREAD_PROCESS_PRIVATE
+                            ? 0 : FUTEX_PRIVATE_FLAG);
+#else
+  rwlock->__data.__shared = (iattr->pshared == PTHREAD_PROCESS_PRIVATE
+                            ? 0
+                            : THREAD_GETMEM (THREAD_SELF,
+                                             header.private_futex));
+#endif
+
+  return 0;
+}
+strong_alias (__pthread_rwlock_init, pthread_rwlock_init)
diff --git a/libpthread/nptl/pthread_rwlock_tryrdlock.c b/libpthread/nptl/pthread_rwlock_tryrdlock.c
new file mode 100644 (file)
index 0000000..30e6dc5
--- /dev/null
@@ -0,0 +1,50 @@
+/* Copyright (C) 2002, 2007 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 (
+     pthread_rwlock_t *rwlock)
+{
+  int result = EBUSY;
+
+  lll_lock (rwlock->__data.__lock, rwlock->__data.__shared);
+
+  if (rwlock->__data.__writer == 0
+      && (rwlock->__data.__nr_writers_queued == 0
+         || PTHREAD_RWLOCK_PREFER_READER_P (rwlock)))
+    {
+      if (__builtin_expect (++rwlock->__data.__nr_readers == 0, 0))
+       {
+         --rwlock->__data.__nr_readers;
+         result = EAGAIN;
+       }
+      else
+       result = 0;
+    }
+
+  lll_unlock (rwlock->__data.__lock, rwlock->__data.__shared);
+
+  return result;
+}
+strong_alias (__pthread_rwlock_tryrdlock, pthread_rwlock_tryrdlock)
diff --git a/libpthread/nptl/pthread_rwlock_trywrlock.c b/libpthread/nptl/pthread_rwlock_trywrlock.c
new file mode 100644 (file)
index 0000000..a6f9ee4
--- /dev/null
@@ -0,0 +1,43 @@
+/* Copyright (C) 2002, 2003, 2007 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 (
+     pthread_rwlock_t *rwlock)
+{
+  int result = EBUSY;
+
+  lll_lock (rwlock->__data.__lock, rwlock->__data.__shared);
+
+  if (rwlock->__data.__writer == 0 && rwlock->__data.__nr_readers == 0)
+    {
+      rwlock->__data.__writer = THREAD_GETMEM (THREAD_SELF, tid);
+      result = 0;
+    }
+
+  lll_unlock (rwlock->__data.__lock, rwlock->__data.__shared);
+
+  return result;
+}
+strong_alias (__pthread_rwlock_trywrlock, pthread_rwlock_trywrlock)
diff --git a/libpthread/nptl/pthread_rwlockattr_destroy.c b/libpthread/nptl/pthread_rwlockattr_destroy.c
new file mode 100644 (file)
index 0000000..db18704
--- /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_rwlockattr_destroy (pthread_rwlockattr_t *attr)
+{
+  /* Nothing to do.  For now.  */
+
+  return 0;
+}
diff --git a/libpthread/nptl/pthread_rwlockattr_getkind_np.c b/libpthread/nptl/pthread_rwlockattr_getkind_np.c
new file mode 100644 (file)
index 0000000..b15275c
--- /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 (
+     const pthread_rwlockattr_t *attr,
+     int *pref)
+{
+  *pref = ((const struct pthread_rwlockattr *) attr)->lockkind;
+
+  return 0;
+}
diff --git a/libpthread/nptl/pthread_rwlockattr_getpshared.c b/libpthread/nptl/pthread_rwlockattr_getpshared.c
new file mode 100644 (file)
index 0000000..2e0437c
--- /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 (
+     const pthread_rwlockattr_t *attr,
+     int *pshared)
+{
+  *pshared = ((const struct pthread_rwlockattr *) attr)->pshared;
+
+  return 0;
+}
diff --git a/libpthread/nptl/pthread_rwlockattr_init.c b/libpthread/nptl/pthread_rwlockattr_init.c
new file mode 100644 (file)
index 0000000..b33ae5b
--- /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 "pthreadP.h"
+
+
+int
+pthread_rwlockattr_init (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/libpthread/nptl/pthread_rwlockattr_setkind_np.c b/libpthread/nptl/pthread_rwlockattr_setkind_np.c
new file mode 100644 (file)
index 0000000..186bf73
--- /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 (
+     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/libpthread/nptl/pthread_rwlockattr_setpshared.c b/libpthread/nptl/pthread_rwlockattr_setpshared.c
new file mode 100644 (file)
index 0000000..a30de0e
--- /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 (
+     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/libpthread/nptl/pthread_self.c b/libpthread/nptl/pthread_self.c
new file mode 100644 (file)
index 0000000..f0e3b3f
--- /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"
+#include <tls.h>
+
+
+pthread_t
+__pthread_self (void)
+{
+  return (pthread_t) THREAD_SELF;
+}
+strong_alias (__pthread_self, pthread_self)
diff --git a/libpthread/nptl/pthread_setcancelstate.c b/libpthread/nptl/pthread_setcancelstate.c
new file mode 100644 (file)
index 0000000..e53b52d
--- /dev/null
@@ -0,0 +1,73 @@
+/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include "pthreadP.h"
+#include <atomic.h>
+
+
+int
+__pthread_setcancelstate (
+     int state,
+     int *oldstate)
+{
+  volatile struct pthread *self;
+
+  if (state < PTHREAD_CANCEL_ENABLE || state > PTHREAD_CANCEL_DISABLE)
+    return EINVAL;
+
+  self = THREAD_SELF;
+
+  int oldval = THREAD_GETMEM (self, cancelhandling);
+  while (1)
+    {
+      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 memory 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.  */
+      int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, newval,
+                                             oldval);
+      if (__builtin_expect (curval == oldval, 1))
+       {
+         if (CANCEL_ENABLED_AND_CANCELED_AND_ASYNCHRONOUS (newval))
+           __do_cancel ();
+
+         break;
+       }
+
+      /* Prepare for the next round.  */
+      oldval = curval;
+    }
+
+  return 0;
+}
+strong_alias (__pthread_setcancelstate, pthread_setcancelstate)
diff --git a/libpthread/nptl/pthread_setcanceltype.c b/libpthread/nptl/pthread_setcanceltype.c
new file mode 100644 (file)
index 0000000..47c104b
--- /dev/null
@@ -0,0 +1,76 @@
+/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include "pthreadP.h"
+#include <atomic.h>
+
+
+int
+__pthread_setcanceltype (
+     int type,
+     int *oldtype)
+{
+  volatile struct pthread *self;
+
+  if (type < PTHREAD_CANCEL_DEFERRED || type > PTHREAD_CANCEL_ASYNCHRONOUS)
+    return EINVAL;
+
+  self = THREAD_SELF;
+
+  int oldval = THREAD_GETMEM (self, cancelhandling);
+  while (1)
+    {
+      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 memory 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.  */
+      int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, newval,
+                                             oldval);
+      if (__builtin_expect (curval == oldval, 1))
+       {
+         if (CANCEL_ENABLED_AND_CANCELED_AND_ASYNCHRONOUS (newval))
+           {
+             THREAD_SETMEM (self, result, PTHREAD_CANCELED);
+             __do_cancel ();
+           }
+
+         break;
+       }
+
+      /* Prepare for the next round.  */
+      oldval = curval;
+    }
+
+  return 0;
+}
+strong_alias (__pthread_setcanceltype, pthread_setcanceltype)
diff --git a/libpthread/nptl/pthread_setconcurrency.c b/libpthread/nptl/pthread_setconcurrency.c
new file mode 100644 (file)
index 0000000..754fe3f
--- /dev/null
@@ -0,0 +1,40 @@
+/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include "pthreadP.h"
+
+
+/* Global definition.  Needed in pthread_getconcurrency as well.  */
+int __concurrency_level;
+
+
+int
+pthread_setconcurrency (int level)
+{
+  if (level < 0)
+    return EINVAL;
+
+  __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/libpthread/nptl/pthread_setegid.c b/libpthread/nptl/pthread_setegid.c
new file mode 100644 (file)
index 0000000..9252dfa
--- /dev/null
@@ -0,0 +1,3 @@
+#define SINGLE_THREAD
+#define setegid pthread_setegid_np
+#include <setegid.c>
diff --git a/libpthread/nptl/pthread_seteuid.c b/libpthread/nptl/pthread_seteuid.c
new file mode 100644 (file)
index 0000000..47bb698
--- /dev/null
@@ -0,0 +1,3 @@
+#define SINGLE_THREAD
+#define seteuid pthread_seteuid_np
+#include <seteuid.c>
diff --git a/libpthread/nptl/pthread_setgid.c b/libpthread/nptl/pthread_setgid.c
new file mode 100644 (file)
index 0000000..b06bffb
--- /dev/null
@@ -0,0 +1,3 @@
+#define SINGLE_THREAD
+#define __setgid pthread_setgid_np
+#include <setgid.c>
diff --git a/libpthread/nptl/pthread_setregid.c b/libpthread/nptl/pthread_setregid.c
new file mode 100644 (file)
index 0000000..7461d2b
--- /dev/null
@@ -0,0 +1,3 @@
+#define SINGLE_THREAD
+#define __setregid pthread_setregid_np
+#include <setregid.c>
diff --git a/libpthread/nptl/pthread_setresgid.c b/libpthread/nptl/pthread_setresgid.c
new file mode 100644 (file)
index 0000000..369fae2
--- /dev/null
@@ -0,0 +1,3 @@
+#define SINGLE_THREAD
+#define __setresgid pthread_setresgid_np
+#include <setresgid.c>
diff --git a/libpthread/nptl/pthread_setresuid.c b/libpthread/nptl/pthread_setresuid.c
new file mode 100644 (file)
index 0000000..ac57c0f
--- /dev/null
@@ -0,0 +1,3 @@
+#define SINGLE_THREAD
+#define __setresuid pthread_setresuid_np
+#include <setresuid.c>
diff --git a/libpthread/nptl/pthread_setreuid.c b/libpthread/nptl/pthread_setreuid.c
new file mode 100644 (file)
index 0000000..aa804ab
--- /dev/null
@@ -0,0 +1,3 @@
+#define SINGLE_THREAD
+#define __setreuid pthread_setreuid_np
+#include <setreuid.c>
diff --git a/libpthread/nptl/pthread_setschedparam.c b/libpthread/nptl/pthread_setschedparam.c
new file mode 100644 (file)
index 0000000..9b33b3e
--- /dev/null
@@ -0,0 +1,74 @@
+/* Copyright (C) 2002, 2003, 2004, 2006, 2007 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 (
+     pthread_t threadid,
+     int policy,
+     const struct sched_param *param)
+{
+  struct pthread *pd = (struct pthread *) threadid;
+
+  /* Make sure the descriptor is valid.  */
+  if (INVALID_TD_P (pd))
+    /* Not a valid thread handle.  */
+    return ESRCH;
+
+  int result = 0;
+
+  lll_lock (pd->lock, LLL_PRIVATE);
+
+  struct sched_param p;
+  const struct sched_param *orig_param = param;
+
+  /* If the thread should have higher priority because of some
+     PTHREAD_PRIO_PROTECT mutexes it holds, adjust the priority.  */
+  if (__builtin_expect (pd->tpp != NULL, 0)
+      && pd->tpp->priomax > param->sched_priority)
+    {
+      p = *param;
+      p.sched_priority = pd->tpp->priomax;
+      param = &p;
+    }
+
+  /* Try to set the scheduler information.  */
+  if (__builtin_expect (__sched_setscheduler (pd->tid, policy,
+                                             param) == -1, 0))
+    result = errno;
+  else
+    {
+      /* We succeeded changing the kernel information.  Reflect this
+        change in the thread descriptor.  */
+      pd->schedpolicy = policy;
+      memcpy (&pd->schedparam, orig_param, sizeof (struct sched_param));
+      pd->flags |= ATTR_FLAG_SCHED_SET | ATTR_FLAG_POLICY_SET;
+    }
+
+  lll_unlock (pd->lock, LLL_PRIVATE);
+
+  return result;
+}
+strong_alias (__pthread_setschedparam, pthread_setschedparam)
diff --git a/libpthread/nptl/pthread_setschedprio.c b/libpthread/nptl/pthread_setschedprio.c
new file mode 100644 (file)
index 0000000..7951460
--- /dev/null
@@ -0,0 +1,66 @@
+/* Copyright (C) 2002, 2003, 2004, 2007 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 <sched.h>
+#include "pthreadP.h"
+#include <lowlevellock.h>
+
+
+int
+pthread_setschedprio (
+     pthread_t threadid,
+     int prio)
+{
+  struct pthread *pd = (struct pthread *) threadid;
+
+  /* Make sure the descriptor is valid.  */
+  if (INVALID_TD_P (pd))
+    /* Not a valid thread handle.  */
+    return ESRCH;
+
+  int result = 0;
+  struct sched_param param;
+  param.sched_priority = prio;
+
+  lll_lock (pd->lock, LLL_PRIVATE);
+
+  /* If the thread should have higher priority because of some
+     PTHREAD_PRIO_PROTECT mutexes it holds, adjust the priority.  */
+  if (__builtin_expect (pd->tpp != NULL, 0) && pd->tpp->priomax > prio)
+    param.sched_priority = pd->tpp->priomax;
+
+  /* Try to set the scheduler information.  */
+  if (__builtin_expect (sched_setparam (pd->tid, &param) == -1, 0))
+    result = errno;
+  else
+    {
+      /* We succeeded changing the kernel information.  Reflect this
+        change in the thread descriptor.  */
+      param.sched_priority = prio;
+      memcpy (&pd->schedparam, &param, sizeof (struct sched_param));
+      pd->flags |= ATTR_FLAG_SCHED_SET;
+    }
+
+  lll_unlock (pd->lock, LLL_PRIVATE);
+
+  return result;
+}
diff --git a/libpthread/nptl/pthread_setspecific.c b/libpthread/nptl/pthread_setspecific.c
new file mode 100644 (file)
index 0000000..8e24be7
--- /dev/null
@@ -0,0 +1,96 @@
+/* Copyright (C) 2002, 2003, 2006 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 (
+     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];
+
+      /* Remember that we stored at least one set of data.  */
+      if (value != NULL)
+       THREAD_SETMEM (self, specific_used, true);
+    }
+  else
+    {
+      if (key >= PTHREAD_KEYS_MAX
+         || KEY_UNUSED ((seq = __pthread_keys[key].seq)))
+       /* 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];
+
+      /* Remember that we stored at least one set of data.  */
+      THREAD_SETMEM (self, specific_used, true);
+    }
+
+  /* Store the data and the sequence number so that we can recognize
+     stale data.  */
+  level2->seq = seq;
+  level2->data = (void *) value;
+
+  return 0;
+}
+strong_alias (__pthread_setspecific, pthread_setspecific)
+strong_alias (__pthread_setspecific, __pthread_setspecific_internal)
diff --git a/libpthread/nptl/pthread_setuid.c b/libpthread/nptl/pthread_setuid.c
new file mode 100644 (file)
index 0000000..ff949c8
--- /dev/null
@@ -0,0 +1,3 @@
+#define SINGLE_THREAD
+#define __setuid pthread_setuid_np
+#include <setuid.c>
diff --git a/libpthread/nptl/pthread_testcancel.c b/libpthread/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/libpthread/nptl/pthread_timedjoin.c b/libpthread/nptl/pthread_timedjoin.c
new file mode 100644 (file)
index 0000000..4098a73
--- /dev/null
@@ -0,0 +1,107 @@
+/* Copyright (C) 2002, 2003, 2005 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 (
+     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 (INVALID_NOT_TERMINATED_TD_P (pd))
+    /* 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 (__builtin_expect (atomic_compare_and_exchange_bool_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 ();
+
+
+  /* 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/libpthread/nptl/pthread_tryjoin.c b/libpthread/nptl/pthread_tryjoin.c
new file mode 100644 (file)
index 0000000..5746a9e
--- /dev/null
@@ -0,0 +1,75 @@
+/* Copyright (C) 2002, 2003, 2005 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 (
+     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_bool_acq (&pd->joinid, self, NULL))
+    /* 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/libpthread/nptl/res.c b/libpthread/nptl/res.c
new file mode 100644 (file)
index 0000000..6a4d18b
--- /dev/null
@@ -0,0 +1,27 @@
+/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <features.h>
+#include <tls.h>
+#include <resolv.h>
+
+struct __res_state *
+__res_state (void)
+{
+  return __resp;
+}
diff --git a/libpthread/nptl/sem_close.c b/libpthread/nptl/sem_close.c
new file mode 100644 (file)
index 0000000..dcf30f7
--- /dev/null
@@ -0,0 +1,81 @@
+/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <search.h>
+#include <sys/mman.h>
+#include "semaphoreP.h"
+
+
+/* Global variables to parametrize the walk function.  This works
+   since we always have to use locks.  And we have to use the twalk
+   function since the entries are not sorted wrt the mapping
+   address.  */
+static sem_t *the_sem;
+static struct inuse_sem *rec;
+
+static void
+walker (const void *inodep, const VISIT which, const int depth)
+{
+  struct inuse_sem *nodep = *(struct inuse_sem **) inodep;
+
+  if (nodep->sem == the_sem)
+    rec = nodep;
+}
+
+
+int
+sem_close (
+     sem_t *sem)
+{
+  int result = 0;
+
+  /* Get the lock.  */
+  lll_lock (__sem_mappings_lock, LLL_PRIVATE);
+
+  /* Locate the entry for the mapping the caller provided.  */
+  rec = NULL;
+  the_sem = sem;
+  twalk (__sem_mappings, walker);
+  if  (rec != NULL)
+    {
+      /* Check the reference counter.  If it is going to be zero, free
+        all the resources.  */
+      if (--rec->refcnt == 0)
+       {
+         /* Remove the record from the tree.  */
+         (void) tdelete (rec, &__sem_mappings, __sem_search);
+
+         result = munmap (rec->sem, sizeof (sem_t));
+
+         free (rec);
+       }
+    }
+  else
+    {
+      /* This is no valid semaphore.  */
+      result = -1;
+      __set_errno (EINVAL);
+    }
+
+  /* Release the lock.  */
+  lll_unlock (__sem_mappings_lock, LLL_PRIVATE);
+
+  return result;
+}
diff --git a/libpthread/nptl/sem_destroy.c b/libpthread/nptl/sem_destroy.c
new file mode 100644 (file)
index 0000000..6362c0e
--- /dev/null
@@ -0,0 +1,33 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <semaphore.h>
+#include "semaphoreP.h"
+
+
+int
+__new_sem_destroy (
+     sem_t *sem)
+{
+  /* XXX Check for valid parameter.  */
+
+  /* Nothing to do.  */
+  return 0;
+}
+weak_alias(__new_sem_destroy, sem_destroy)
diff --git a/libpthread/nptl/sem_getvalue.c b/libpthread/nptl/sem_getvalue.c
new file mode 100644 (file)
index 0000000..928026f
--- /dev/null
@@ -0,0 +1,37 @@
+/* Copyright (C) 2002, 2007 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 "semaphoreP.h"
+
+
+int
+__new_sem_getvalue (
+     sem_t *sem,
+     int *sval)
+{
+  struct new_sem *isem = (struct new_sem *) sem;
+
+  /* XXX Check for valid SEM parameter.  */
+
+  *sval = isem->value;
+
+  return 0;
+}
+weak_alias(__new_sem_getvalue, sem_getvalue)
diff --git a/libpthread/nptl/sem_init.c b/libpthread/nptl/sem_init.c
new file mode 100644 (file)
index 0000000..0a224f3
--- /dev/null
@@ -0,0 +1,56 @@
+/* Copyright (C) 2002, 2007 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 "semaphoreP.h"
+#include <bits/kernel-features.h>
+
+
+int
+__new_sem_init (
+     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 new_sem *isem = (struct new_sem *) sem;
+
+  /* Use the values the user provided.  */
+  isem->value = value;
+#ifdef __ASSUME_PRIVATE_FUTEX
+  isem->private = pshared ? 0 : FUTEX_PRIVATE_FLAG;
+#else
+  isem->private = pshared ? 0 : THREAD_GETMEM (THREAD_SELF,
+                                              header.private_futex);
+#endif
+
+  isem->nwaiters = 0;
+
+  return 0;
+}
+weak_alias(__new_sem_init, sem_init)
diff --git a/libpthread/nptl/sem_open.c b/libpthread/nptl/sem_open.c
new file mode 100644 (file)
index 0000000..8ded82c
--- /dev/null
@@ -0,0 +1,396 @@
+/* Copyright (C) 2002, 2003, 2006, 2007, 2009 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <mntent.h>
+#include <paths.h>
+#include <pthread.h>
+#include <search.h>
+#include <semaphore.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/statfs.h>
+#include <linux_fsinfo.h>
+#include "semaphoreP.h"
+#include "../../libc/misc/internals/tempname.h"
+
+
+/* Compatibility defines. */
+#define __endmntent                    endmntent
+#define __fxstat64(vers, fd, buf)      fstat64(fd, buf)
+#define __getmntent_r                  getmntent_r
+#define __setmntent                    setmntent
+#define __statfs                       statfs
+#define __libc_close                   close
+#define __libc_open                    open
+#define __libc_write                   write
+
+
+/* Information about the mount point.  */
+struct mountpoint_info mountpoint attribute_hidden;
+
+/* This is the default mount point.  */
+static const char defaultmount[] = "/dev/shm";
+/* This is the default directory.  */
+static const char defaultdir[] = "/dev/shm/sem.";
+
+/* Protect the `mountpoint' variable above.  */
+pthread_once_t __namedsem_once attribute_hidden = PTHREAD_ONCE_INIT;
+
+
+/* Determine where the shmfs is mounted (if at all).  */
+void
+attribute_hidden
+__where_is_shmfs (void)
+{
+  char buf[512];
+  struct statfs f;
+  struct mntent resmem;
+  struct mntent *mp;
+  FILE *fp;
+
+  /* The canonical place is /dev/shm.  This is at least what the
+     documentation tells everybody to do.  */
+  if (__statfs (defaultmount, &f) == 0 && f.f_type == SHMFS_SUPER_MAGIC)
+    {
+      /* It is in the normal place.  */
+      mountpoint.dir = (char *) defaultdir;
+      mountpoint.dirlen = sizeof (defaultdir) - 1;
+
+      return;
+    }
+
+  /* OK, do it the hard way.  Look through the /proc/mounts file and if
+     this does not exist through /etc/fstab to find the mount point.  */
+  fp = __setmntent ("/proc/mounts", "r");
+  if (__builtin_expect (fp == NULL, 0))
+    {
+      fp = __setmntent (_PATH_MNTTAB, "r");
+      if (__builtin_expect (fp == NULL, 0))
+       /* There is nothing we can do.  Blind guesses are not helpful.  */
+       return;
+    }
+
+  /* Now read the entries.  */
+  while ((mp = __getmntent_r (fp, &resmem, buf, sizeof buf)) != NULL)
+    /* The original name is "shm" but this got changed in early Linux
+       2.4.x to "tmpfs".  */
+    if (strcmp (mp->mnt_type, "tmpfs") == 0
+       || strcmp (mp->mnt_type, "shm") == 0)
+      {
+       /* Found it.  There might be more than one place where the
+           filesystem is mounted but one is enough for us.  */
+       size_t namelen;
+
+       /* First make sure this really is the correct entry.  At least
+          some versions of the kernel give wrong information because
+          of the implicit mount of the shmfs for SysV IPC.  */
+       if (__statfs (mp->mnt_dir, &f) != 0 || f.f_type != SHMFS_SUPER_MAGIC)
+         continue;
+
+       namelen = strlen (mp->mnt_dir);
+
+       if (namelen == 0)
+         /* Hum, maybe some crippled entry.  Keep on searching.  */
+         continue;
+
+       mountpoint.dir = (char *) malloc (namelen + 4 + 2);
+       if (mountpoint.dir != NULL)
+         {
+           char *cp = mempcpy (mountpoint.dir, mp->mnt_dir, namelen);
+           if (cp[-1] != '/')
+             *cp++ = '/';
+           cp = stpcpy (cp, "sem.");
+           mountpoint.dirlen = cp - mountpoint.dir;
+         }
+
+       break;
+      }
+
+  /* Close the stream.  */
+  __endmntent (fp);
+}
+
+
+/* Comparison function for search of existing mapping.  */
+int
+attribute_hidden
+__sem_search (const void *a, const void *b)
+{
+  const struct inuse_sem *as = (const struct inuse_sem *) a;
+  const struct inuse_sem *bs = (const struct inuse_sem *) b;
+
+  if (as->ino != bs->ino)
+    /* Cannot return the difference the type is larger than int.  */
+    return as->ino < bs->ino ? -1 : (as->ino == bs->ino ? 0 : 1);
+
+  if (as->dev != bs->dev)
+    /* Cannot return the difference the type is larger than int.  */
+    return as->dev < bs->dev ? -1 : (as->dev == bs->dev ? 0 : 1);
+
+  return strcmp (as->name, bs->name);
+}
+
+
+/* The search tree for existing mappings.  */
+void *__sem_mappings attribute_hidden;
+
+/* Lock to protect the search tree.  */
+int __sem_mappings_lock attribute_hidden = LLL_LOCK_INITIALIZER;
+
+
+/* Search for existing mapping and if possible add the one provided.  */
+static sem_t *
+check_add_mapping (const char *name, size_t namelen, int fd, sem_t *existing)
+{
+  sem_t *result = SEM_FAILED;
+
+  /* Get the information about the file.  */
+#ifdef __UCLIBC_HAS_LFS__
+  struct stat64 st;
+  if (__fxstat64 (_STAT_VER, fd, &st) == 0)
+#else
+  struct stat st;
+  if (fstat (fd, &st) == 0)
+#endif
+    {
+      /* Get the lock.  */
+      lll_lock (__sem_mappings_lock, LLL_PRIVATE);
+
+      /* Search for an existing mapping given the information we have.  */
+      struct inuse_sem *fake;
+      fake = (struct inuse_sem *) alloca (sizeof (*fake) + namelen);
+      memcpy (fake->name, name, namelen);
+      fake->dev = st.st_dev;
+      fake->ino = st.st_ino;
+
+      struct inuse_sem **foundp = tfind (fake, &__sem_mappings, __sem_search);
+      if (foundp != NULL)
+       {
+         /* There is already a mapping.  Use it.  */
+         result = (*foundp)->sem;
+         ++(*foundp)->refcnt;
+       }
+      else
+       {
+         /* We haven't found a mapping.  Install ione.  */
+         struct inuse_sem *newp;
+
+         newp = (struct inuse_sem *) malloc (sizeof (*newp) + namelen);
+         if (newp != NULL)
+           {
+             /* If the caller hasn't provided any map it now.  */
+             if (existing == SEM_FAILED)
+               existing = (sem_t *) mmap (NULL, sizeof (sem_t),
+                                          PROT_READ | PROT_WRITE, MAP_SHARED,
+                                          fd, 0);
+
+             newp->dev = st.st_dev;
+             newp->ino = st.st_ino;
+             newp->refcnt = 1;
+             newp->sem = existing;
+             memcpy (newp->name, name, namelen);
+
+             /* Insert the new value.  */
+             if (existing != MAP_FAILED
+                 && tsearch (newp, &__sem_mappings, __sem_search) != NULL)
+               /* Successful.  */
+               result = existing;
+             else
+               /* Something went wrong while inserting the new
+                  value.  We fail completely.  */
+               free (newp);
+           }
+       }
+
+      /* Release the lock.  */
+      lll_unlock (__sem_mappings_lock, LLL_PRIVATE);
+    }
+
+  if (result != existing && existing != SEM_FAILED && existing != MAP_FAILED)
+    {
+      /* Do not disturb errno.  */
+      INTERNAL_SYSCALL_DECL (err);
+      INTERNAL_SYSCALL (munmap, err, 2, existing, sizeof (sem_t));
+    }
+
+  return result;
+}
+
+
+sem_t *
+sem_open (const char *name, int oflag, ...)
+{
+  char *finalname;
+  sem_t *result = SEM_FAILED;
+  int fd;
+
+  /* Determine where the shmfs is mounted.  */
+  __pthread_once (&__namedsem_once, __where_is_shmfs);
+
+  /* If we don't know the mount points there is nothing we can do.  Ever.  */
+  if (mountpoint.dir == NULL)
+    {
+      __set_errno (ENOSYS);
+      return SEM_FAILED;
+    }
+
+  /* Construct the filename.  */
+  while (name[0] == '/')
+    ++name;
+
+  if (name[0] == '\0')
+    {
+      /* The name "/" is not supported.  */
+      __set_errno (EINVAL);
+      return SEM_FAILED;
+    }
+  size_t namelen = strlen (name) + 1;
+
+  /* Create the name of the final file.  */
+  finalname = (char *) alloca (mountpoint.dirlen + namelen);
+  mempcpy (mempcpy (finalname, mountpoint.dir, mountpoint.dirlen),
+            name, namelen);
+
+  /* If the semaphore object has to exist simply open it.  */
+  if ((oflag & O_CREAT) == 0 || (oflag & O_EXCL) == 0)
+    {
+    try_again:
+      fd = __libc_open (finalname,
+                       (oflag & ~(O_CREAT|O_ACCMODE)) | O_NOFOLLOW | O_RDWR);
+
+      if (fd == -1)
+       {
+         /* If we are supposed to create the file try this next.  */
+         if ((oflag & O_CREAT) != 0 && errno == ENOENT)
+           goto try_create;
+
+         /* Return.  errno is already set.  */
+       }
+      else
+       /* Check whether we already have this semaphore mapped and
+          create one if necessary.  */
+       result = check_add_mapping (name, namelen, fd, SEM_FAILED);
+    }
+  else
+    {
+      /* We have to open a temporary file first since it must have the
+        correct form before we can start using it.  */
+      char *tmpfname;
+      mode_t mode;
+      unsigned int value;
+      va_list ap;
+
+    try_create:
+      va_start (ap, oflag);
+
+      mode = va_arg (ap, mode_t);
+      value = va_arg (ap, unsigned int);
+
+      va_end (ap);
+
+      if (value > SEM_VALUE_MAX)
+       {
+         __set_errno (EINVAL);
+         return SEM_FAILED;
+       }
+
+      /* Create the initial file content.  */
+      union
+      {
+       sem_t initsem;
+       struct new_sem newsem;
+      } sem;
+
+      sem.newsem.value = value;
+      sem.newsem.private = 0;
+      sem.newsem.nwaiters = 0;
+
+      /* Initialize the remaining bytes as well.  */
+      memset ((char *) &sem.initsem + sizeof (struct new_sem), '\0',
+             sizeof (sem_t) - sizeof (struct new_sem));
+
+      tmpfname = (char *) alloca (mountpoint.dirlen + 6 + 1);
+      mempcpy (tmpfname, mountpoint.dir, mountpoint.dirlen);
+
+      fd = __gen_tempname (tmpfname, __GT_FILE, mode);
+      if (fd == -1)
+        return SEM_FAILED;
+
+      if (TEMP_FAILURE_RETRY (__libc_write (fd, &sem.initsem, sizeof (sem_t)))
+         == sizeof (sem_t)
+         /* Map the sem_t structure from the file.  */
+         && (result = (sem_t *) mmap (NULL, sizeof (sem_t),
+                                      PROT_READ | PROT_WRITE, MAP_SHARED,
+                                      fd, 0)) != MAP_FAILED)
+       {
+         /* Create the file.  Don't overwrite an existing file.  */
+         if (link (tmpfname, finalname) != 0)
+           {
+             /* Undo the mapping.  */
+             (void) munmap (result, sizeof (sem_t));
+
+             /* Reinitialize 'result'.  */
+             result = SEM_FAILED;
+
+             /* This failed.  If O_EXCL is not set and the problem was
+                that the file exists, try again.  */
+             if ((oflag & O_EXCL) == 0 && errno == EEXIST)
+               {
+                 /* Remove the file.  */
+                 (void) unlink (tmpfname);
+
+                 /* Close the file.  */
+                 (void) __libc_close (fd);
+
+                 goto try_again;
+               }
+           }
+         else
+           /* Insert the mapping into the search tree.  This also
+              determines whether another thread sneaked by and already
+              added such a mapping despite the fact that we created it.  */
+           result = check_add_mapping (name, namelen, fd, result);
+       }
+
+      /* Now remove the temporary name.  This should never fail.  If
+        it fails we leak a file name.  Better fix the kernel.  */
+      (void) unlink (tmpfname);
+    }
+
+  /* Map the mmap error to the error we need.  */
+  if (MAP_FAILED != (void *) SEM_FAILED && result == MAP_FAILED)
+    result = SEM_FAILED;
+
+  /* We don't need the file descriptor anymore.  */
+  if (fd != -1)
+    {
+      /* Do not disturb errno.  */
+      INTERNAL_SYSCALL_DECL (err);
+      INTERNAL_SYSCALL (close, err, 1, fd);
+    }
+
+  return result;
+}
diff --git a/libpthread/nptl/sem_unlink.c b/libpthread/nptl/sem_unlink.c
new file mode 100644 (file)
index 0000000..beed02e
--- /dev/null
@@ -0,0 +1,67 @@
+/* Copyright (C) 2002, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <semaphore.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "semaphoreP.h"
+
+
+int
+sem_unlink (
+     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.  */
+  int ret = unlink (fname);
+  if (ret < 0 && errno == EPERM)
+    __set_errno (EACCES);
+  return ret;
+}
diff --git a/libpthread/nptl/semaphore.h b/libpthread/nptl/semaphore.h
new file mode 100644 (file)
index 0000000..4f13725
--- /dev/null
@@ -0,0 +1,79 @@
+/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _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 flags 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.
+
+   This function is a cancellation point and therefore not marked with
+   __THROW.  */
+extern int sem_wait (sem_t *__sem);
+
+#ifdef __USE_XOPEN2K
+/* Similar to `sem_wait' but wait only until ABSTIME.
+
+   This function is a cancellation point and therefore not marked with
+   __THROW.  */
+extern int sem_timedwait (sem_t *__restrict __sem,
+                         __const struct timespec *__restrict __abstime);
+#endif
+
+/* Test whether SEM is posted.  */
+extern int sem_trywait (sem_t *__sem) __THROW;
+
+/* Post SEM.  */
+extern int sem_post (sem_t *__sem) __THROW;
+
+/* Get current value of SEM and store it in *SVAL.  */
+extern int sem_getvalue (sem_t *__restrict __sem, int *__restrict __sval)
+     __THROW;
+
+
+__END_DECLS
+
+#endif /* semaphore.h */
diff --git a/libpthread/nptl/semaphoreP.h b/libpthread/nptl/semaphoreP.h
new file mode 100644 (file)
index 0000000..7d6fd25
--- /dev/null
@@ -0,0 +1,69 @@
+/* Copyright (C) 2002, 2003, 2006, 2007 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 "pthreadP.h"
+
+
+/* Mount point of the shared memory filesystem.  */
+struct mountpoint_info
+{
+  char *dir;
+  size_t dirlen;
+};
+
+/* Keeping track of currently used mappings.  */
+struct inuse_sem
+{
+  dev_t dev;
+  ino_t ino;
+  int refcnt;
+  sem_t *sem;
+  char name[0];
+};
+
+
+/* Variables used in multiple interfaces.  */
+extern struct mountpoint_info mountpoint attribute_hidden;
+
+extern pthread_once_t __namedsem_once attribute_hidden;
+
+/* The search tree for existing mappings.  */
+extern void *__sem_mappings attribute_hidden;
+
+/* Lock to protect the search tree.  */
+extern int __sem_mappings_lock attribute_hidden;
+
+
+/* Initializer for mountpoint.  */
+extern void __where_is_shmfs (void) attribute_hidden;
+
+/* Comparison function for search in tree with existing mappings.  */
+extern int __sem_search (const void *a, const void *b) attribute_hidden;
+
+
+/* Prototypes of functions with multiple interfaces.  */
+extern int __new_sem_init (sem_t *sem, int pshared, unsigned int value);
+extern int __old_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 __old_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/libpthread/nptl/sysdeps/alpha/Makefile b/libpthread/nptl/sysdeps/alpha/Makefile
new file mode 100644 (file)
index 0000000..88c106b
--- /dev/null
@@ -0,0 +1,21 @@
+# Copyright (C) 2003 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+#
+# The GNU C Library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# The GNU C Library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with the GNU C Library; if not, write to the Free
+# Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+# 02111-1307 USA.
+
+ifeq ($(subdir),csu)
+gen-as-const-headers += tcb-offsets.sym
+endif
diff --git a/libpthread/nptl/sysdeps/alpha/dl-tls.h b/libpthread/nptl/sysdeps/alpha/dl-tls.h
new file mode 100644 (file)
index 0000000..f81f95d
--- /dev/null
@@ -0,0 +1,29 @@
+/* Thread-local storage handling in the ELF dynamic linker.  Alpha 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.  */
+
+
+/* Type used for the representation of TLS information in the GOT.  */
+typedef struct
+{
+  unsigned long int ti_module;
+  unsigned long int ti_offset;
+} tls_index;
+
+
+extern void *__tls_get_addr (tls_index *ti);
diff --git a/libpthread/nptl/sysdeps/alpha/elf/pt-initfini.c b/libpthread/nptl/sysdeps/alpha/elf/pt-initfini.c
new file mode 100644 (file)
index 0000000..ba2e419
--- /dev/null
@@ -0,0 +1,89 @@
+/* Special .init and .fini section support for Alpha.  NPTL version.
+   Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* This file is compiled into assembly code which is then munged by a sed
+   script into two files: crti.s and crtn.s.
+
+   * crti.s puts a function prologue at the beginning of the .init and .fini
+   sections and defines global symbols for those addresses, so they can be
+   called as functions.
+
+   * crtn.s puts the corresponding function epilogues in the .init and .fini
+   sections.
+
+   This differs from what would be generated by the generic code in that
+   we save and restore the GP within the function.  In order for linker
+   relaxation to work, the value in the GP register on exit from a function
+   must be valid for the function entry point.  Normally, a function is
+   contained within one object file and this is not an issue, provided
+   that the function reloads the gp after making any function calls.
+   However, _init and _fini are constructed from pieces of many object
+   files, all of which may have different GP values.  So we must reload
+   the GP value from crti.o in crtn.o.  */
+
+__asm__ ("                                             \n\
+#include \"defs.h\"                                    \n\
+                                                       \n\
+/*@HEADER_ENDS*/                                       \n\
+                                                       \n\
+/*@_init_PROLOG_BEGINS*/                               \n\
+       .section .init, \"ax\", @progbits               \n\
+       .globl  _init                                   \n\
+       .type   _init,@function                         \n\
+       .usepv  _init,std                               \n\
+_init:                                                 \n\
+       ldgp    $29, 0($27)                             \n\
+       subq    $30, 16, $30                            \n\
+       stq     $26, 0($30)                             \n\
+       stq     $29, 8($30)                             \n\
+       bsr     $26, __pthread_initialize_minimal_internal !samegp \n\
+       .align 3                                        \n\
+/*@_init_PROLOG_ENDS*/                                 \n\
+                                                       \n\
+/*@_init_EPILOG_BEGINS*/                               \n\
+       .section .init, \"ax\", @progbits               \n\
+       ldq     $26, 0($30)                             \n\
+       ldq     $29, 8($30)                             \n\
+       addq    $30, 16, $30                            \n\
+       ret                                             \n\
+/*@_init_EPILOG_ENDS*/                                 \n\
+                                                       \n\
+/*@_fini_PROLOG_BEGINS*/                               \n\
+       .section .fini, \"ax\", @progbits               \n\
+       .globl  _fini                                   \n\
+       .type   _fini,@function                         \n\
+       .usepv  _fini,std                               \n\
+_fini:                                                 \n\
+       ldgp    $29, 0($27)                             \n\
+       subq    $30, 16, $30                            \n\
+       stq     $26, 0($30)                             \n\
+       stq     $29, 8($30)                             \n\
+       .align 3                                        \n\
+/*@_fini_PROLOG_ENDS*/                                 \n\
+                                                       \n\
+/*@_fini_EPILOG_BEGINS*/                               \n\
+       .section .fini, \"ax\", @progbits               \n\
+       ldq     $26, 0($30)                             \n\
+       ldq     $29, 8($30)                             \n\
+       addq    $30, 16, $30                            \n\
+       ret                                             \n\
+/*@_fini_EPILOG_ENDS*/                                 \n\
+                                                       \n\
+/*@TRAILER_BEGINS*/                                    \n\
+");
diff --git a/libpthread/nptl/sysdeps/alpha/jmpbuf-unwind.h b/libpthread/nptl/sysdeps/alpha/jmpbuf-unwind.h
new file mode 100644 (file)
index 0000000..5cef8b1
--- /dev/null
@@ -0,0 +1,31 @@
+/* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <setjmp.h>
+#include <stdint.h>
+#include <unwind.h>
+
+#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \
+  _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj)
+
+#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \
+  ((uintptr_t) (_address) - (_adj) < (uintptr_t) (_jmpbuf)[JB_SP] - (_adj))
+
+/* We use the normal lobngjmp for unwinding.  */
+#define __libc_unwind_longjmp(buf, val) __libc_longjmp (buf, val)
diff --git a/libpthread/nptl/sysdeps/alpha/libc-tls.c b/libpthread/nptl/sysdeps/alpha/libc-tls.c
new file mode 100644 (file)
index 0000000..a3b68e9
--- /dev/null
@@ -0,0 +1,37 @@
+/* Thread-local storage handling in the ELF dynamic linker.  Alpha version.
+   Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdeps/generic/libc-tls.c>
+#include <dl-tls.h>
+
+#if USE_TLS
+
+/* On Alpha, linker optimizations are not required, so __tls_get_addr
+   can be called even in statically linked binaries.  In this case module
+   must be always 1 and PT_TLS segment exist in the binary, otherwise it
+   would not link.  */
+
+void *
+__tls_get_addr (tls_index *ti)
+{
+  dtv_t *dtv = THREAD_DTV ();
+  return (char *) dtv[1].pointer.val + ti->ti_offset;
+}
+
+#endif
diff --git a/libpthread/nptl/sysdeps/alpha/pthread_spin_lock.S b/libpthread/nptl/sysdeps/alpha/pthread_spin_lock.S
new file mode 100644 (file)
index 0000000..ce6cd41
--- /dev/null
@@ -0,0 +1,45 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Richard Henderson  <rth@twiddle.net>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+
+       .text
+       .align  4
+
+       .globl  pthread_spin_lock
+       .ent    pthread_spin_lock
+pthread_spin_lock:
+       .frame  $sp, 0, $26, 0
+       .prologue 0
+
+0:     ldl_l   $1, 0($16)
+       lda     $2, 1
+       lda     $0, 0
+       bne     $1, 1f
+
+       stl_c   $2, 0($16)
+       beq     $2, 1f
+       mb
+       ret
+
+1:     ldl     $1, 0($16)
+       bne     $1, 1b
+       unop
+       br      0b
+
+       .end    pthread_spin_lock
diff --git a/libpthread/nptl/sysdeps/alpha/pthread_spin_trylock.S b/libpthread/nptl/sysdeps/alpha/pthread_spin_trylock.S
new file mode 100644 (file)
index 0000000..0948da6
--- /dev/null
@@ -0,0 +1,46 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Richard Henderson  <rth@twiddle.net>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+
+#define _ERRNO_H 1
+#include <bits/errno.h>
+
+       .text
+       .align  4
+
+       .globl  pthread_spin_trylock
+       .ent    pthread_spin_trylock
+pthread_spin_trylock:
+       .frame  $sp, 0, $26, 0
+       .prologue 0
+
+0:     ldl_l   $1, 0($16)
+       lda     $2, 1
+       lda     $0, EBUSY
+       bne     $1, 1f
+
+       stl_c   $2, 0($16)
+       beq     $2, 2f
+       mb
+       lda     $0, 0
+
+1:     ret
+2:     br      0b
+
+       .end    pthread_spin_trylock
diff --git a/libpthread/nptl/sysdeps/alpha/pthreaddef.h b/libpthread/nptl/sysdeps/alpha/pthreaddef.h
new file mode 100644 (file)
index 0000000..26c4daf
--- /dev/null
@@ -0,0 +1,38 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* Default stack size.  */
+#define ARCH_STACK_DEFAULT_SIZE        (4 * 1024 * 1024)
+
+/* Required stack pointer alignment at beginning.  The ABI requires 16.  */
+#define STACK_ALIGN            16
+
+/* Minimal stack size after allocating thread descriptor and guard size.  */
+#define MINIMAL_REST_STACK     4096
+
+/* Alignment requirement for TCB.  */
+#define TCB_ALIGNMENT          16
+
+/* 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) \
+  INLINE_SYSCALL (exit, 1, (val))
diff --git a/libpthread/nptl/sysdeps/alpha/tcb-offsets.sym b/libpthread/nptl/sysdeps/alpha/tcb-offsets.sym
new file mode 100644 (file)
index 0000000..c21a791
--- /dev/null
@@ -0,0 +1,14 @@
+#include <sysdep.h>
+#include <tls.h>
+
+--
+
+-- Abuse tls.h macros to derive offsets relative to the thread register.
+-- # define __builtin_thread_pointer()  ((void *) 0)
+-- # define thread_offsetof(mem)     ((void *) &THREAD_SELF->mem - (void *) 0)
+-- Ho hum, this doesn't work in gcc4, so Know Things about THREAD_SELF
+#define thread_offsetof(mem)   (long)(offsetof(struct pthread, mem) - sizeof(struct pthread))
+
+MULTIPLE_THREADS_OFFSET                thread_offsetof (header.multiple_threads)
+PID_OFFSET                     thread_offsetof (pid)
+TID_OFFSET                     thread_offsetof (tid)
diff --git a/libpthread/nptl/sysdeps/alpha/tls.h b/libpthread/nptl/sysdeps/alpha/tls.h
new file mode 100644 (file)
index 0000000..99cd27a
--- /dev/null
@@ -0,0 +1,127 @@
+/* Definition for thread-local data handling.  NPTL/Alpha version.
+   Copyright (C) 2003, 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _TLS_H
+#define _TLS_H 1
+
+#ifndef __ASSEMBLER__
+# include <stdbool.h>
+# include <stddef.h>
+# include <stdint.h>
+
+/* Type for the dtv.  */
+typedef union dtv
+{
+  size_t counter;
+  struct
+  {
+    void *val;
+    bool is_static;
+  } pointer;
+} dtv_t;
+
+#else /* __ASSEMBLER__ */
+# include <tcb-offsets.h>
+#endif /* __ASSEMBLER__ */
+
+
+/* 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
+
+#ifndef __ASSEMBLER__
+
+/* Get system call information.  */
+# include <sysdep.h>
+
+/* The TP points to the start of the thread blocks.  */
+# define TLS_DTV_AT_TP 1
+
+/* Get the thread descriptor definition.  */
+# include <nptl/descr.h>
+
+typedef struct
+{
+  dtv_t *dtv;
+  void *private;
+} tcbhead_t;
+
+/* This is the size of the initial TCB.  */
+# define TLS_INIT_TCB_SIZE     sizeof (tcbhead_t)
+
+/* Alignment requirements for the initial TCB.  */
+# define TLS_INIT_TCB_ALIGN    16
+
+/* This is the size of the TCB.  */
+# define TLS_TCB_SIZE          sizeof (tcbhead_t)
+
+/* This is the size we need before TCB.  */
+# define TLS_PRE_TCB_SIZE      sizeof (struct pthread)
+
+/* Alignment requirements for the TCB.  */
+# define TLS_TCB_ALIGN         16
+
+/* Install the dtv pointer.  The pointer passed is to the element with
+   index -1 which contain the length.  */
+# define INSTALL_DTV(tcbp, dtvp) \
+  (((tcbhead_t *) (tcbp))->dtv = (dtvp) + 1)
+
+/* Install new dtv for current thread.  */
+# define INSTALL_NEW_DTV(dtv) \
+  (THREAD_DTV() = (dtv))
+
+/* Return dtv of given thread descriptor.  */
+# define GET_DTV(tcbp) \
+  (((tcbhead_t *) (tcbp))->dtv)
+
+/* Code to initially initialize the thread pointer.  This might need
+   special attention since 'errno' is not yet available and if the
+   operation can cause a failure 'errno' must not be touched.  */
+# define TLS_INIT_TP(tcbp, secondcall) \
+  (__builtin_set_thread_pointer ((void *)(tcbp)), NULL)
+
+/* Return the address of the dtv for the current thread.  */
+# define THREAD_DTV() \
+  (((tcbhead_t *) __builtin_thread_pointer ())->dtv)
+
+/* Return the thread descriptor for the current thread.  */
+# define THREAD_SELF \
+ ((struct pthread *)__builtin_thread_pointer () - 1)
+
+/* Magic for libthread_db to know how to do THREAD_SELF.  */
+# define DB_THREAD_SELF \
+  REGISTER (64, 64, 32 * 8, -sizeof (struct pthread))
+
+/* Access to data in the thread descriptor is easy.  */
+#define THREAD_GETMEM(descr, member) \
+  descr->member
+#define THREAD_GETMEM_NC(descr, member, idx) \
+  descr->member[idx]
+#define THREAD_SETMEM(descr, member, value) \
+  descr->member = (value)
+#define THREAD_SETMEM_NC(descr, member, idx, value) \
+  descr->member[idx] = (value)
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* tls.h */
diff --git a/libpthread/nptl/sysdeps/arm/Makefile.arch b/libpthread/nptl/sysdeps/arm/Makefile.arch
new file mode 100644 (file)
index 0000000..8b4ce70
--- /dev/null
@@ -0,0 +1,71 @@
+# Makefile for uClibc NPTL
+#
+# Copyright (C) 2005 Steven J. Hill <sjhill@uclibc.org>
+# Portions Copyright (C) 2006 CodeSourcery
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+libpthread_SSRC = pthread_spin_lock.S pthread_spin_trylock.S aeabi_read_tp.S \
+       thumb_atomics.S
+libpthread_CSRC = aeabi_unwind_cpp_pr1.c
+
+librt_SSRC = aeabi_read_tp.S thumb_atomics.S
+librt_CSRC = aeabi_unwind_cpp_pr1.c
+
+libc_a_CSRC =
+
+CFLAGS-pt-raise.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1
+
+ASFLAGS-pthread_spin_lock.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1
+ASFLAGS-pthread_spin_trylock.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1
+ASFLAGS-aeabi_read_tp.S = -DNOT_IN_libc=1
+
+CFLAGS-arm = $(SSP_ALL_CFLAGS)
+
+PTHREAD_ARCH_DIR := $(top_srcdir)libpthread/nptl/sysdeps/arm
+PTHREAD_ARCH_OUT := $(top_builddir)libpthread/nptl/sysdeps/arm
+PTHREAD_ARCH_OBJ := $(patsubst %.S,$(PTHREAD_ARCH_OUT)/%.o,$(libpthread_SSRC))
+PTHREAD_ARCH_OBJ += $(patsubst %.c,$(PTHREAD_ARCH_OUT)/%.o,$(libpthread_CSRC))
+LIBRT_ARCH_OBJ := $(patsubst %.S,$(PTHREAD_ARCH_OUT)/%.o,$(librt_SSRC))
+LIBRT_ARCH_OBJ += $(patsubst %.c,$(PTHREAD_ARCH_OUT)/%.o,$(librt_CSRC))
+
+
+ifeq ($(DOPIC),y)
+libpthread-a-y += $(PTHREAD_ARCH_OBJ:.o=.os)
+else
+libpthread-a-y += $(PTHREAD_ARCH_OBJ)
+endif
+libpthread-so-y += $(PTHREAD_ARCH_OBJ:.o=.oS)
+
+librt-a-y += $(LIBRT_ARCH_OBJ)
+librt-so-y += $(LIBRT_ARCH_OBJ:.o=.oS)
+
+libpthread-nomulti-y += $(PTHREAD_ARCH_OBJ)
+
+objclean-y += nptl_arch_objclean
+headers_clean-y += nptl_arch_headers_clean
+
+#
+# Create 'tcb-offsets.h' header file.
+#
+CFLAGS-tcb-offsets.c = -S
+
+$(PTHREAD_ARCH_OUT)/tcb-offsets.c: $(PTHREAD_ARCH_DIR)/tcb-offsets.sym
+       $(do_awk) $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@
+
+$(PTHREAD_ARCH_OUT)/tcb-offsets.s: $(PTHREAD_ARCH_OUT)/tcb-offsets.c
+       $(compile.c)
+
+$(PTHREAD_ARCH_OUT)/tcb-offsets.h: $(PTHREAD_ARCH_OUT)/tcb-offsets.s
+       $(do_sed) -n "s/^.*@@@name@@@\([^@]*\)@@@value@@@[^0-9Xxa-fA-F-]*\([0-9Xxa-fA-F-][0-9Xxa-fA-F-]*\).*@@@end@@@.*$\/#define \1 \2/p" $< > $@
+
+pregen-headers-$(UCLIBC_HAS_THREADS_NATIVE) += $(PTHREAD_ARCH_OUT)/tcb-offsets.h
+
+nptl_arch_headers_clean:
+       $(RM) $(PTHREAD_ARCH_OUT)/tcb-offsets.c         \
+             $(PTHREAD_ARCH_OUT)/tcb-offsets.s         \
+             $(PTHREAD_ARCH_OUT)/tcb-offsets.h
+
+nptl_arch_objclean:
+       $(RM) $(PTHREAD_ARCH_OUT)/*.{o,os,oS}
diff --git a/libpthread/nptl/sysdeps/arm/aeabi_read_tp.S b/libpthread/nptl/sysdeps/arm/aeabi_read_tp.S
new file mode 100644 (file)
index 0000000..af640d6
--- /dev/null
@@ -0,0 +1 @@
+#include <../../../../ldso/ldso/arm/aeabi_read_tp.S>
diff --git a/libpthread/nptl/sysdeps/arm/aeabi_unwind_cpp_pr1.c b/libpthread/nptl/sysdeps/arm/aeabi_unwind_cpp_pr1.c
new file mode 100644 (file)
index 0000000..8468362
--- /dev/null
@@ -0,0 +1 @@
+#include <../../../../libc/sysdeps/linux/arm/aeabi_unwind_cpp_pr1.c>
diff --git a/libpthread/nptl/sysdeps/arm/dl-tls.h b/libpthread/nptl/sysdeps/arm/dl-tls.h
new file mode 100644 (file)
index 0000000..e0324a7
--- /dev/null
@@ -0,0 +1,29 @@
+/* Thread-local storage handling in the ELF dynamic linker.  ARM version.
+   Copyright (C) 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+
+/* Type used for the representation of TLS information in the GOT.  */
+typedef struct
+{
+  unsigned long int ti_module;
+  unsigned long int ti_offset;
+} tls_index;
+
+
+extern void *__tls_get_addr (tls_index *ti);
diff --git a/libpthread/nptl/sysdeps/arm/jmpbuf-unwind.h b/libpthread/nptl/sysdeps/arm/jmpbuf-unwind.h
new file mode 100644 (file)
index 0000000..6e8f01d
--- /dev/null
@@ -0,0 +1,36 @@
+/* Copyright (C) 2005,2006 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <setjmp.h>
+#include <stdint.h>
+#include <unwind.h>
+
+/* Test if longjmp to JMPBUF would unwind the frame
+   containing a local variable at ADDRESS.  */
+#undef _JMPBUF_UNWINDS
+#define _JMPBUF_UNWINDS(jmpbuf, address, demangle) \
+  ((void *) (address) < (void *) demangle (jmpbuf[__JMP_BUF_SP]))
+
+#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \
+  _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj)
+
+#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \
+  ((uintptr_t) (_address) - (_adj) < (uintptr_t) (_jmpbuf)[__JMP_BUF_SP] - (_adj))
+
+/* We use the normal longjmp for unwinding.  */
+#define __libc_unwind_longjmp(buf, val) longjmp (buf, val)
diff --git a/libpthread/nptl/sysdeps/arm/pthread_spin_lock.S b/libpthread/nptl/sysdeps/arm/pthread_spin_lock.S
new file mode 100644 (file)
index 0000000..bd6adf7
--- /dev/null
@@ -0,0 +1,31 @@
+/* Copyright (C) 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+
+       .text
+       .align  4
+
+ENTRY (pthread_spin_lock)
+       mov     r1, #1
+1:     swp     r2, r1, [r0]
+       teq     r2, #0
+       bne     1b
+       mov     r0, #0
+       PSEUDO_RET_NOERRNO
+END (pthread_spin_lock)
diff --git a/libpthread/nptl/sysdeps/arm/pthread_spin_trylock.S b/libpthread/nptl/sysdeps/arm/pthread_spin_trylock.S
new file mode 100644 (file)
index 0000000..8593150
--- /dev/null
@@ -0,0 +1,34 @@
+/* Copyright (C) 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#define _ERRNO_H 1
+#include <bits/errno.h>
+
+#include <sysdep.h>
+
+       .text
+       .align  4
+
+ENTRY (pthread_spin_trylock)
+       mov     r1, #1
+       swp     r2, r1, [r0]
+       teq     r2, #0
+       moveq   r0, #0
+       movne   r0, #EBUSY
+       PSEUDO_RET_NOERRNO
+END (pthread_spin_trylock)
diff --git a/libpthread/nptl/sysdeps/arm/pthreaddef.h b/libpthread/nptl/sysdeps/arm/pthreaddef.h
new file mode 100644 (file)
index 0000000..783828a
--- /dev/null
@@ -0,0 +1,39 @@
+/* Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* 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
+
+
+/* Location of current stack frame.  */
+#define CURRENT_STACK_FRAME    __builtin_frame_address (0)
+
+
+/* XXX Until we have a better place keep the definitions here.  */
+#define __exit_thread_inline(val) \
+  INLINE_SYSCALL (exit, 1, (val))
diff --git a/libpthread/nptl/sysdeps/arm/tcb-offsets.sym b/libpthread/nptl/sysdeps/arm/tcb-offsets.sym
new file mode 100644 (file)
index 0000000..92cc441
--- /dev/null
@@ -0,0 +1,11 @@
+#include <sysdep.h>
+#include <tls.h>
+
+--
+
+-- Derive offsets relative to the thread register.
+#define thread_offsetof(mem)   (long)(offsetof(struct pthread, mem) - sizeof(struct pthread))
+
+MULTIPLE_THREADS_OFFSET                thread_offsetof (header.multiple_threads)
+PID_OFFSET                     thread_offsetof (pid)
+TID_OFFSET                     thread_offsetof (tid)
diff --git a/libpthread/nptl/sysdeps/arm/thumb_atomics.S b/libpthread/nptl/sysdeps/arm/thumb_atomics.S
new file mode 100644 (file)
index 0000000..aaa7a3d
--- /dev/null
@@ -0,0 +1 @@
+#include <../../../../ldso/ldso/arm/thumb_atomics.S>
diff --git a/libpthread/nptl/sysdeps/arm/tls.h b/libpthread/nptl/sysdeps/arm/tls.h
new file mode 100644 (file)
index 0000000..0ca597a
--- /dev/null
@@ -0,0 +1,159 @@
+/* Definition for thread-local data handling.  NPTL/ARM version.
+   Copyright (C) 2005,2007 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 <stdbool.h>
+# include <stddef.h>
+# include <stdint.h>
+
+/* Type for the dtv.  */
+typedef union dtv
+{
+  size_t counter;
+  struct
+  {
+    void *val;
+    bool is_static;
+  } pointer;
+} dtv_t;
+
+#else /* __ASSEMBLER__ */
+# include <tcb-offsets.h>
+#endif /* __ASSEMBLER__ */
+
+
+/* We require TLS support in the tools.  */
+#define HAVE_TLS_SUPPORT                1
+#define HAVE_TLS_MODEL_ATTRIBUTE        1
+#define HAVE___THREAD                   1
+
+/* Signal that TLS support is available.  */
+#define USE_TLS        1
+
+#ifndef __ASSEMBLER__
+
+/* Get system call information.  */
+# include <sysdep.h>
+
+/* The TP points to the start of the thread blocks.  */
+# define TLS_DTV_AT_TP 1
+
+/* Get the thread descriptor definition.  */
+# include <../../descr.h>
+
+typedef struct
+{
+  dtv_t *dtv;
+  void *private;
+} tcbhead_t;
+
+/* This is the size of the initial TCB.  */
+# define TLS_INIT_TCB_SIZE     sizeof (tcbhead_t)
+
+/* Alignment requirements for the initial TCB.  */
+# define TLS_INIT_TCB_ALIGN    16
+
+/* This is the size of the TCB.  */
+# define TLS_TCB_SIZE          sizeof (tcbhead_t)
+
+/* This is the size we need before TCB.  */
+# define TLS_PRE_TCB_SIZE      sizeof (struct pthread)
+
+/* Alignment requirements for the TCB.  */
+# define TLS_TCB_ALIGN         16
+
+/* Install the dtv pointer.  The pointer passed is to the element with
+   index -1 which contain the length.  */
+# define INSTALL_DTV(tcbp, dtvp) \
+  (((tcbhead_t *) (tcbp))->dtv = (dtvp) + 1)
+
+/* Install new dtv for current thread.  */
+# define INSTALL_NEW_DTV(dtv) \
+  (THREAD_DTV() = (dtv))
+
+/* Return dtv of given thread descriptor.  */
+# define GET_DTV(tcbp) \
+  (((tcbhead_t *) (tcbp))->dtv)
+
+/* Code to initially initialize the thread pointer.  This might need
+   special attention since 'errno' is not yet available and if the
+   operation can cause a failure 'errno' must not be touched.  */
+# define TLS_INIT_TP(tcbp, secondcall) \
+  ({ INTERNAL_SYSCALL_DECL (err);                                      \
+     long result_var;                                                  \
+     result_var = INTERNAL_SYSCALL_ARM (set_tls, err, 1, (tcbp));      \
+     INTERNAL_SYSCALL_ERROR_P (result_var, err)                                \
+       ? "unknown error" : NULL; })
+
+/* Return the address of the dtv for the current thread.  */
+# define THREAD_DTV() \
+  (((tcbhead_t *) __builtin_thread_pointer ())->dtv)
+
+/* Return the thread descriptor for the current thread.  */
+# define THREAD_SELF \
+ ((struct pthread *)__builtin_thread_pointer () - 1)
+
+/* Magic for libthread_db to know how to do THREAD_SELF.  */
+# define DB_THREAD_SELF \
+  CONST_THREAD_AREA (32, sizeof (struct pthread))
+
+/* Access to data in the thread descriptor is easy.  */
+#define THREAD_GETMEM(descr, member) \
+  descr->member
+#define THREAD_GETMEM_NC(descr, member, idx) \
+  descr->member[idx]
+#define THREAD_SETMEM(descr, member, value) \
+  descr->member = (value)
+#define THREAD_SETMEM_NC(descr, member, idx, value) \
+  descr->member[idx] = (value)
+
+/* Initializing the thread pointer will generate a SIGILL if the syscall
+   is not available.  */
+#define TLS_INIT_TP_EXPENSIVE 1
+
+/* Get and set the global scope generation counter in struct pthread.  */
+#define THREAD_GSCOPE_FLAG_UNUSED 0
+#define THREAD_GSCOPE_FLAG_USED   1
+#define THREAD_GSCOPE_FLAG_WAIT   2
+#define THREAD_GSCOPE_RESET_FLAG() \
+  do                                                                        \
+    { int __res                                                                     \
+       = atomic_exchange_rel (&THREAD_SELF->header.gscope_flag,             \
+                              THREAD_GSCOPE_FLAG_UNUSED);                   \
+      if (__res == THREAD_GSCOPE_FLAG_WAIT)                                 \
+       lll_futex_wake (&THREAD_SELF->header.gscope_flag, 1, LLL_PRIVATE);   \
+    }                                                                       \
+  while (0)
+#define THREAD_GSCOPE_SET_FLAG() \
+  do                                                                        \
+    {                                                                       \
+      THREAD_SELF->header.gscope_flag = THREAD_GSCOPE_FLAG_USED;            \
+      atomic_write_barrier ();                                              \
+    }                                                                       \
+  while (0)
+#define THREAD_GSCOPE_WAIT() \
+  GL(dl_wait_lookup_done) ()
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* tls.h */
diff --git a/libpthread/nptl/sysdeps/generic/Makefile b/libpthread/nptl/sysdeps/generic/Makefile
new file mode 100644 (file)
index 0000000..582661f
--- /dev/null
@@ -0,0 +1,13 @@
+# Makefile for uClibc NPTL
+#
+# Copyright (C) 2006 Steven J. Hill <sjhill@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+top_srcdir=../../../../
+top_builddir=../../../../
+all: objs
+include $(top_builddir)Rules.mak
+include Makefile.in
+include $(top_srcdir)Makerules
diff --git a/libpthread/nptl/sysdeps/generic/Makefile.in b/libpthread/nptl/sysdeps/generic/Makefile.in
new file mode 100644 (file)
index 0000000..1079a5f
--- /dev/null
@@ -0,0 +1,30 @@
+# Makefile for uClibc NPTL
+#
+# Copyright (C) 2006 Steven J. Hill <sjhill@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+#
+# NOTE: Alpha and MIPS have their own versions of 'libc-tls.c' in
+#       their architecture specific directory which will override
+#       the one here.
+#
+libc_a_CSRC = dl-tls.c libc-tls.c
+
+
+CFLAGS-generic = $(SSP_ALL_CFLAGS)
+#CFLAGS:=$(CFLAGS:-O1=-O2)
+
+PTHREAD_GENERIC_OUT:=$(top_builddir)libpthread/nptl/sysdeps/generic
+
+LIBC_GENERIC_OBJ:=$(patsubst %.c,$(PTHREAD_GENERIC_OUT)/%.o,$(libc_a_CSRC))
+
+libc-static-y+=$(LIBC_GENERIC_OBJ)
+
+libc-nomulti-y+=$(LIBC_GENERIC_OBJ)
+
+objclean-y+=nptl_pthread_generic_clean
+
+nptl_pthread_generic_clean:
+       $(do_rm) $(addprefix $(PTHREAD_GENERIC_OUT)/*., o os oS)
diff --git a/libpthread/nptl/sysdeps/generic/dl-tls.c b/libpthread/nptl/sysdeps/generic/dl-tls.c
new file mode 100644 (file)
index 0000000..da6ebbd
--- /dev/null
@@ -0,0 +1,895 @@
+/* Thread-local storage handling in the ELF dynamic linker.  Generic version.
+   Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <libintl.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <sys/param.h>
+#include <tls.h>
+#include <dl-tls.h>
+#include <ldsodefs.h>
+#include <dl-elf.h>
+#include <dl-hash.h>
+
+#include <assert.h>
+#include <link.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#define        _dl_malloc      malloc
+#define _dl_memset     memset
+#define _dl_mempcpy    mempcpy
+#define _dl_dprintf    fprintf
+#define _dl_debug_file stderr
+#define _dl_exit       exit
+
+/* Amount of excess space to allocate in the static TLS area
+   to allow dynamic loading of modules defining IE-model TLS data.  */
+# define TLS_STATIC_SURPLUS    64 + DL_NNS * 100
+
+/* Value used for dtv entries for which the allocation is delayed.  */
+# define TLS_DTV_UNALLOCATED   ((void *) -1l)
+
+
+/* Out-of-memory handler.  */
+# ifdef SHARED
+static void
+__attribute__ ((__noreturn__))
+oom (void)
+{
+       do {
+               _dl_dprintf (_dl_debug_file,
+                       "cannot allocate thread-local memory: ABORT\n");
+               _dl_exit (127);
+       } while (1);
+}
+# endif
+
+
+void *_dl_memalign(size_t alignment, size_t bytes)
+{
+       return _dl_malloc(bytes);
+}
+
+
+/*
+ * We are trying to perform a static TLS relocation in MAP, but it was
+ * dynamically loaded.  This can only work if there is enough surplus in
+ * the static TLS area already allocated for each running thread.  If this
+ * object's TLS segment is too big to fit, we fail.  If it fits,
+ * we set MAP->l_tls_offset and return.
+ * This function intentionally does not return any value but signals error
+ * directly, as static TLS should be rare and code handling it should
+ * not be inlined as much as possible.
+ */
+
+
+void
+internal_function __attribute_noinline__
+_dl_allocate_static_tls (struct link_map *map)
+{
+       /* If the alignment requirements are too high fail.  */
+       if (map->l_tls_align > _dl_tls_static_align)
+       {
+fail:
+               _dl_dprintf(_dl_debug_file, "cannot allocate memory in static TLS block");
+               _dl_exit(30);
+       }
+
+# if defined(TLS_TCB_AT_TP)
+       size_t freebytes;
+       size_t n;
+       size_t blsize;
+
+       freebytes = _dl_tls_static_size - _dl_tls_static_used - TLS_TCB_SIZE;
+
+       blsize = map->l_tls_blocksize + map->l_tls_firstbyte_offset;
+       if (freebytes < blsize)
+               goto fail;
+
+       n = (freebytes - blsize) / map->l_tls_align;
+
+       size_t offset = _dl_tls_static_used + (freebytes - n * map->l_tls_align
+               - map->l_tls_firstbyte_offset);
+
+       map->l_tls_offset = _dl_tls_static_used = offset;
+# elif defined(TLS_DTV_AT_TP)
+       size_t used;
+       size_t check;
+
+       size_t offset = roundup (_dl_tls_static_used, map->l_tls_align);
+       used = offset + map->l_tls_blocksize;
+       check = used;
+
+       /* dl_tls_static_used includes the TCB at the beginning. */
+       if (check > _dl_tls_static_size)
+               goto fail;
+
+       map->l_tls_offset = offset;
+       _dl_tls_static_used = used;
+# else
+#  error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
+# endif
+
+       /*
+        * If the object is not yet relocated we cannot initialize the
+        * static TLS region.  Delay it.
+        */
+       if (((struct elf_resolve *) map)->init_flag & RELOCS_DONE)
+    {
+#ifdef SHARED
+               /*
+                * Update the slot information data for at least the generation of
+                * the DSO we are allocating data for.
+                */
+               if (__builtin_expect (THREAD_DTV()[0].counter != _dl_tls_generation, 0))
+                       (void) _dl_update_slotinfo (map->l_tls_modid);
+#endif
+               _dl_init_static_tls (map);
+       }
+       else
+               map->l_need_tls_init = 1;
+}
+
+size_t
+internal_function
+_dl_next_tls_modid (void)
+{
+  size_t result;
+
+  if (__builtin_expect (GL(dl_tls_dtv_gaps), false))
+    {
+      size_t disp = 0;
+      struct dtv_slotinfo_list *runp = GL(dl_tls_dtv_slotinfo_list);
+
+      /* Note that this branch will never be executed during program
+        start since there are no gaps at that time.  Therefore it
+        does not matter that the dl_tls_dtv_slotinfo is not allocated
+        yet when the function is called for the first times.
+
+        NB: the offset +1 is due to the fact that DTV[0] is used
+        for something else.  */
+      result = GL(dl_tls_static_nelem) + 1;
+      if (result <= GL(dl_tls_max_dtv_idx))
+       do
+         {
+           while (result - disp < runp->len)
+             {
+               if (runp->slotinfo[result - disp].map == NULL)
+                 break;
+
+               ++result;
+               assert (result <= GL(dl_tls_max_dtv_idx) + 1);
+             }
+
+           if (result - disp < runp->len)
+             break;
+
+           disp += runp->len;
+         }
+       while ((runp = runp->next) != NULL);
+
+      if (result > GL(dl_tls_max_dtv_idx))
+       {
+         /* The new index must indeed be exactly one higher than the
+            previous high.  */
+         assert (result == GL(dl_tls_max_dtv_idx) + 1);
+         /* There is no gap anymore.  */
+         GL(dl_tls_dtv_gaps) = false;
+
+         goto nogaps;
+       }
+    }
+  else
+    {
+      /* No gaps, allocate a new entry.  */
+    nogaps:
+
+      result = ++GL(dl_tls_max_dtv_idx);
+    }
+
+  return result;
+}
+
+
+# ifdef SHARED
+void
+internal_function
+_dl_determine_tlsoffset (void)
+{
+  size_t max_align = TLS_TCB_ALIGN;
+  size_t freetop = 0;
+  size_t freebottom = 0;
+
+  /* The first element of the dtv slot info list is allocated.  */
+  assert (GL(dl_tls_dtv_slotinfo_list) != NULL);
+  /* There is at this point only one element in the
+     dl_tls_dtv_slotinfo_list list.  */
+  assert (GL(dl_tls_dtv_slotinfo_list)->next == NULL);
+
+  struct dtv_slotinfo *slotinfo = GL(dl_tls_dtv_slotinfo_list)->slotinfo;
+
+  /* Determining the offset of the various parts of the static TLS
+     block has several dependencies.  In addition we have to work
+     around bugs in some toolchains.
+
+     Each TLS block from the objects available at link time has a size
+     and an alignment requirement.  The GNU ld computes the alignment
+     requirements for the data at the positions *in the file*, though.
+     I.e, it is not simply possible to allocate a block with the size
+     of the TLS program header entry.  The data is layed out assuming
+     that the first byte of the TLS block fulfills
+
+       p_vaddr mod p_align == &TLS_BLOCK mod p_align
+
+     This means we have to add artificial padding at the beginning of
+     the TLS block.  These bytes are never used for the TLS data in
+     this module but the first byte allocated must be aligned
+     according to mod p_align == 0 so that the first byte of the TLS
+     block is aligned according to p_vaddr mod p_align.  This is ugly
+     and the linker can help by computing the offsets in the TLS block
+     assuming the first byte of the TLS block is aligned according to
+     p_align.
+
+     The extra space which might be allocated before the first byte of
+     the TLS block need not go unused.  The code below tries to use
+     that memory for the next TLS block.  This can work if the total
+     memory requirement for the next TLS block is smaller than the
+     gap.  */
+
+# if defined(TLS_TCB_AT_TP)
+  /* We simply start with zero.  */
+  size_t offset = 0;
+
+  for (size_t cnt = 0; slotinfo[cnt].map != NULL; ++cnt)
+    {
+      assert (cnt < GL(dl_tls_dtv_slotinfo_list)->len);
+
+      size_t firstbyte = (-slotinfo[cnt].map->l_tls_firstbyte_offset
+                         & (slotinfo[cnt].map->l_tls_align - 1));
+      size_t off;
+      max_align = MAX (max_align, slotinfo[cnt].map->l_tls_align);
+
+      if (freebottom - freetop >= slotinfo[cnt].map->l_tls_blocksize)
+       {
+         off = roundup (freetop + slotinfo[cnt].map->l_tls_blocksize
+                        - firstbyte, slotinfo[cnt].map->l_tls_align)
+               + firstbyte;
+         if (off <= freebottom)
+           {
+             freetop = off;
+
+             /* XXX For some architectures we perhaps should store the
+                negative offset.  */
+             slotinfo[cnt].map->l_tls_offset = off;
+             continue;
+           }
+       }
+
+      off = roundup (offset + slotinfo[cnt].map->l_tls_blocksize - firstbyte,
+                    slotinfo[cnt].map->l_tls_align) + firstbyte;
+      if (off > offset + slotinfo[cnt].map->l_tls_blocksize
+               + (freebottom - freetop))
+       {
+         freetop = offset;
+         freebottom = off - slotinfo[cnt].map->l_tls_blocksize;
+       }
+      offset = off;
+
+      /* XXX For some architectures we perhaps should store the
+        negative offset.  */
+      slotinfo[cnt].map->l_tls_offset = off;
+    }
+
+  GL(dl_tls_static_used) = offset;
+  GL(dl_tls_static_size) = (roundup (offset + TLS_STATIC_SURPLUS, max_align)
+                           + TLS_TCB_SIZE);
+# elif defined(TLS_DTV_AT_TP)
+  /* The TLS blocks start right after the TCB.  */
+  size_t offset = TLS_TCB_SIZE;
+  size_t cnt;
+
+  for (cnt = 0; slotinfo[cnt].map != NULL; ++cnt)
+    {
+      assert (cnt < GL(dl_tls_dtv_slotinfo_list)->len);
+
+      size_t firstbyte = (-slotinfo[cnt].map->l_tls_firstbyte_offset
+                         & (slotinfo[cnt].map->l_tls_align - 1));
+      size_t off;
+      max_align = MAX (max_align, slotinfo[cnt].map->l_tls_align);
+
+      if (slotinfo[cnt].map->l_tls_blocksize <= freetop - freebottom)
+       {
+         off = roundup (freebottom, slotinfo[cnt].map->l_tls_align);
+         if (off - freebottom < firstbyte)
+           off += slotinfo[cnt].map->l_tls_align;
+         if (off + slotinfo[cnt].map->l_tls_blocksize - firstbyte <= freetop)
+           {
+             slotinfo[cnt].map->l_tls_offset = off - firstbyte;
+             freebottom = (off + slotinfo[cnt].map->l_tls_blocksize
+                           - firstbyte);
+             continue;
+           }
+       }
+
+      off = roundup (offset, slotinfo[cnt].map->l_tls_align);
+      if (off - offset < firstbyte)
+       off += slotinfo[cnt].map->l_tls_align;
+
+      slotinfo[cnt].map->l_tls_offset = off - firstbyte;
+      if (off - firstbyte - offset > freetop - freebottom)
+       {
+         freebottom = offset;
+         freetop = off - firstbyte;
+       }
+
+      offset = off + slotinfo[cnt].map->l_tls_blocksize - firstbyte;
+    }
+
+  GL(dl_tls_static_used) = offset;
+  GL(dl_tls_static_size) = roundup (offset + TLS_STATIC_SURPLUS,
+                                   TLS_TCB_ALIGN);
+# else
+#  error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
+# endif
+
+  /* The alignment requirement for the static TLS block.  */
+  GL(dl_tls_static_align) = max_align;
+}
+
+
+/* This is called only when the data structure setup was skipped at startup,
+   when there was no need for it then.  Now we have dynamically loaded
+   something needing TLS, or libpthread needs it.  */
+int
+internal_function
+_dl_tls_setup (void)
+{
+  assert (GL(dl_tls_dtv_slotinfo_list) == NULL);
+  assert (GL(dl_tls_max_dtv_idx) == 0);
+
+  const size_t nelem = 2 + TLS_SLOTINFO_SURPLUS;
+
+  GL(dl_tls_dtv_slotinfo_list)
+    = calloc (1, (sizeof (struct dtv_slotinfo_list)
+                 + nelem * sizeof (struct dtv_slotinfo)));
+  if (GL(dl_tls_dtv_slotinfo_list) == NULL)
+    return -1;
+
+  GL(dl_tls_dtv_slotinfo_list)->len = nelem;
+
+  /* Number of elements in the static TLS block.  It can't be zero
+     because of various assumptions.  The one element is null.  */
+  GL(dl_tls_static_nelem) = GL(dl_tls_max_dtv_idx) = 1;
+
+  /* This initializes more variables for us.  */
+  _dl_determine_tlsoffset ();
+
+  return 0;
+}
+# endif
+
+static void *
+internal_function
+allocate_dtv (void *result)
+{
+  dtv_t *dtv;
+  size_t dtv_length;
+
+  /* We allocate a few more elements in the dtv than are needed for the
+     initial set of modules.  This should avoid in most cases expansions
+     of the dtv.  */
+  dtv_length = GL(dl_tls_max_dtv_idx) + DTV_SURPLUS;
+  dtv = calloc (dtv_length + 2, sizeof (dtv_t));
+  if (dtv != NULL)
+    {
+      /* This is the initial length of the dtv.  */
+      dtv[0].counter = dtv_length;
+
+      /* The rest of the dtv (including the generation counter) is
+        Initialize with zero to indicate nothing there.  */
+
+      /* Add the dtv to the thread data structures.  */
+      INSTALL_DTV (result, dtv);
+    }
+  else
+    result = NULL;
+
+  return result;
+}
+
+
+/* Get size and alignment requirements of the static TLS block.  */
+void
+internal_function
+_dl_get_tls_static_info (size_t *sizep, size_t *alignp)
+{
+  *sizep = GL(dl_tls_static_size);
+  *alignp = GL(dl_tls_static_align);
+}
+
+
+void *
+internal_function
+_dl_allocate_tls_storage (void)
+{
+  void *result;
+  size_t size = GL(dl_tls_static_size);
+
+# if defined(TLS_DTV_AT_TP)
+  /* Memory layout is:
+     [ TLS_PRE_TCB_SIZE ] [ TLS_TCB_SIZE ] [ TLS blocks ]
+                         ^ This should be returned.  */
+  size += (TLS_PRE_TCB_SIZE + GL(dl_tls_static_align) - 1)
+         & ~(GL(dl_tls_static_align) - 1);
+# endif
+
+  /* Allocate a correctly aligned chunk of memory.  */
+  result = _dl_memalign (GL(dl_tls_static_align), size);
+  if (__builtin_expect (result != NULL, 1))
+    {
+      /* Allocate the DTV.  */
+      void *allocated = result;
+
+# if defined(TLS_TCB_AT_TP)
+      /* The TCB follows the TLS blocks.  */
+      result = (char *) result + size - TLS_TCB_SIZE;
+
+      /* Clear the TCB data structure.  We can't ask the caller (i.e.
+        libpthread) to do it, because we will initialize the DTV et al.  */
+      _dl_memset (result, '\0', TLS_TCB_SIZE);
+# elif defined(TLS_DTV_AT_TP)
+      result = (char *) result + size - GL(dl_tls_static_size);
+
+      /* Clear the TCB data structure and TLS_PRE_TCB_SIZE bytes before it.
+        We can't ask the caller (i.e. libpthread) to do it, because we will
+        initialize the DTV et al.  */
+      _dl_memset ((char *) result - TLS_PRE_TCB_SIZE, '\0',
+             TLS_PRE_TCB_SIZE + TLS_TCB_SIZE);
+# endif
+
+      result = allocate_dtv (result);
+      if (result == NULL)
+       free (allocated);
+    }
+
+  return result;
+}
+
+
+void *
+internal_function
+_dl_allocate_tls_init (void *result)
+{
+  if (result == NULL)
+    /* The memory allocation failed.  */
+    return NULL;
+
+  dtv_t *dtv = GET_DTV (result);
+  struct dtv_slotinfo_list *listp;
+  size_t total = 0;
+  size_t maxgen = 0;
+
+  /* We have to prepare the dtv for all currently loaded modules using
+     TLS.  For those which are dynamically loaded we add the values
+     indicating deferred allocation.  */
+  listp = GL(dl_tls_dtv_slotinfo_list);
+  while (1)
+    {
+      size_t cnt;
+
+      for (cnt = total == 0 ? 1 : 0; cnt < listp->len; ++cnt)
+       {
+         struct link_map *map;
+         void *dest;
+
+         /* Check for the total number of used slots.  */
+         if (total + cnt > GL(dl_tls_max_dtv_idx))
+           break;
+
+         map = listp->slotinfo[cnt].map;
+         if (map == NULL)
+           /* Unused entry.  */
+           continue;
+
+         /* Keep track of the maximum generation number.  This might
+            not be the generation counter.  */
+         maxgen = MAX (maxgen, listp->slotinfo[cnt].gen);
+
+         if (map->l_tls_offset == NO_TLS_OFFSET)
+           {
+             /* For dynamically loaded modules we simply store
+                the value indicating deferred allocation.  */
+             dtv[map->l_tls_modid].pointer.val = TLS_DTV_UNALLOCATED;
+             dtv[map->l_tls_modid].pointer.is_static = false;
+             continue;
+           }
+
+         assert (map->l_tls_modid == cnt);
+         assert (map->l_tls_blocksize >= map->l_tls_initimage_size);
+# if defined(TLS_TCB_AT_TP)
+         assert ((size_t) map->l_tls_offset >= map->l_tls_blocksize);
+         dest = (char *) result - map->l_tls_offset;
+# elif defined(TLS_DTV_AT_TP)
+         dest = (char *) result + map->l_tls_offset;
+# else
+#  error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
+# endif
+
+         /* Copy the initialization image and clear the BSS part.  */
+         dtv[map->l_tls_modid].pointer.val = dest;
+         dtv[map->l_tls_modid].pointer.is_static = true;
+         _dl_memset (_dl_mempcpy (dest, map->l_tls_initimage,
+                            map->l_tls_initimage_size), '\0',
+                 map->l_tls_blocksize - map->l_tls_initimage_size);
+       }
+
+      total += cnt;
+      if (total >= GL(dl_tls_max_dtv_idx))
+       break;
+
+      listp = listp->next;
+      assert (listp != NULL);
+    }
+
+  /* The DTV version is up-to-date now.  */
+  dtv[0].counter = maxgen;
+
+  return result;
+}
+
+void *
+internal_function
+_dl_allocate_tls (void *mem)
+{
+  return _dl_allocate_tls_init (mem == NULL
+                               ? _dl_allocate_tls_storage ()
+                               : allocate_dtv (mem));
+}
+
+
+void
+internal_function
+_dl_deallocate_tls (void *tcb, bool dealloc_tcb)
+{
+  dtv_t *dtv = GET_DTV (tcb);
+  size_t cnt;
+
+  /* We need to free the memory allocated for non-static TLS.  */
+  for (cnt = 0; cnt < dtv[-1].counter; ++cnt)
+    if (! dtv[1 + cnt].pointer.is_static
+       && dtv[1 + cnt].pointer.val != TLS_DTV_UNALLOCATED)
+      free (dtv[1 + cnt].pointer.val);
+
+  /* The array starts with dtv[-1].  */
+#ifdef SHARED
+  if (dtv != GL(dl_initial_dtv))
+#endif
+    free (dtv - 1);
+
+  if (dealloc_tcb)
+    {
+# if defined(TLS_TCB_AT_TP)
+      /* The TCB follows the TLS blocks.  Back up to free the whole block.  */
+      tcb -= GL(dl_tls_static_size) - TLS_TCB_SIZE;
+# elif defined(TLS_DTV_AT_TP)
+      /* Back up the TLS_PRE_TCB_SIZE bytes.  */
+      tcb -= (TLS_PRE_TCB_SIZE + GL(dl_tls_static_align) - 1)
+            & ~(GL(dl_tls_static_align) - 1);
+# endif
+      free (tcb);
+    }
+}
+
+
+# ifdef SHARED
+/* The __tls_get_addr function has two basic forms which differ in the
+   arguments.  The IA-64 form takes two parameters, the module ID and
+   offset.  The form used, among others, on IA-32 takes a reference to
+   a special structure which contain the same information.  The second
+   form seems to be more often used (in the moment) so we default to
+   it.  Users of the IA-64 form have to provide adequate definitions
+   of the following macros.  */
+#  ifndef GET_ADDR_ARGS
+#   define GET_ADDR_ARGS tls_index *ti
+#  endif
+#  ifndef GET_ADDR_MODULE
+#   define GET_ADDR_MODULE ti->ti_module
+#  endif
+#  ifndef GET_ADDR_OFFSET
+#   define GET_ADDR_OFFSET ti->ti_offset
+#  endif
+
+
+static void *
+allocate_and_init (struct link_map *map)
+{
+  void *newp;
+
+  newp = _dl_memalign (map->l_tls_align, map->l_tls_blocksize);
+  if (newp == NULL)
+    oom ();
+
+  /* Initialize the memory.  */
+  _dl_memset (_dl_mempcpy (newp, map->l_tls_initimage, map->l_tls_initimage_size),
+         '\0', map->l_tls_blocksize - map->l_tls_initimage_size);
+
+  return newp;
+}
+
+
+struct link_map *
+_dl_update_slotinfo (unsigned long int req_modid)
+{
+  struct link_map *the_map = NULL;
+  dtv_t *dtv = THREAD_DTV ();
+
+  /* The global dl_tls_dtv_slotinfo array contains for each module
+     index the generation counter current when the entry was created.
+     This array never shrinks so that all module indices which were
+     valid at some time can be used to access it.  Before the first
+     use of a new module index in this function the array was extended
+     appropriately.  Access also does not have to be guarded against
+     modifications of the array.  It is assumed that pointer-size
+     values can be read atomically even in SMP environments.  It is
+     possible that other threads at the same time dynamically load
+     code and therefore add to the slotinfo list.  This is a problem
+     since we must not pick up any information about incomplete work.
+     The solution to this is to ignore all dtv slots which were
+     created after the one we are currently interested.  We know that
+     dynamic loading for this module is completed and this is the last
+     load operation we know finished.  */
+  unsigned long int idx = req_modid;
+  struct dtv_slotinfo_list *listp = GL(dl_tls_dtv_slotinfo_list);
+
+  while (idx >= listp->len)
+    {
+      idx -= listp->len;
+      listp = listp->next;
+    }
+
+  if (dtv[0].counter < listp->slotinfo[idx].gen)
+    {
+      /* The generation counter for the slot is higher than what the
+        current dtv implements.  We have to update the whole dtv but
+        only those entries with a generation counter <= the one for
+        the entry we need.  */
+      size_t new_gen = listp->slotinfo[idx].gen;
+      size_t total = 0;
+
+      /* We have to look through the entire dtv slotinfo list.  */
+      listp =  GL(dl_tls_dtv_slotinfo_list);
+      do
+       {
+         size_t cnt;
+
+         for (cnt = total == 0 ? 1 : 0; cnt < listp->len; ++cnt)
+           {
+             size_t gen = listp->slotinfo[cnt].gen;
+
+             if (gen > new_gen)
+               /* This is a slot for a generation younger than the
+                  one we are handling now.  It might be incompletely
+                  set up so ignore it.  */
+               continue;
+
+             /* If the entry is older than the current dtv layout we
+                know we don't have to handle it.  */
+             if (gen <= dtv[0].counter)
+               continue;
+
+             /* If there is no map this means the entry is empty.  */
+             struct link_map *map = listp->slotinfo[cnt].map;
+             if (map == NULL)
+               {
+                 /* If this modid was used at some point the memory
+                    might still be allocated.  */
+                 if (! dtv[total + cnt].pointer.is_static
+                     && dtv[total + cnt].pointer.val != TLS_DTV_UNALLOCATED)
+                   {
+                     free (dtv[total + cnt].pointer.val);
+                     dtv[total + cnt].pointer.val = TLS_DTV_UNALLOCATED;
+                   }
+
+                 continue;
+               }
+
+             /* Check whether the current dtv array is large enough.  */
+             size_t modid = map->l_tls_modid;
+             assert (total + cnt == modid);
+             if (dtv[-1].counter < modid)
+               {
+                 /* Reallocate the dtv.  */
+                 dtv_t *newp;
+                 size_t newsize = GL(dl_tls_max_dtv_idx) + DTV_SURPLUS;
+                 size_t oldsize = dtv[-1].counter;
+
+                 assert (map->l_tls_modid <= newsize);
+
+                 if (dtv == GL(dl_initial_dtv))
+                   {
+                     /* This is the initial dtv that was allocated
+                        during rtld startup using the dl-minimal.c
+                        malloc instead of the real malloc.  We can't
+                        free it, we have to abandon the old storage.  */
+
+                     newp = malloc ((2 + newsize) * sizeof (dtv_t));
+                     if (newp == NULL)
+                       oom ();
+                     _dl_memcpy (newp, &dtv[-1], oldsize * sizeof (dtv_t));
+                   }
+                 else
+                   {
+                     newp = realloc (&dtv[-1],
+                                     (2 + newsize) * sizeof (dtv_t));
+                     if (newp == NULL)
+                       oom ();
+                   }
+
+                 newp[0].counter = newsize;
+
+                 /* Clear the newly allocated part.  */
+                 _dl_memset (newp + 2 + oldsize, '\0',
+                         (newsize - oldsize) * sizeof (dtv_t));
+
+                 /* Point dtv to the generation counter.  */
+                 dtv = &newp[1];
+
+                 /* Install this new dtv in the thread data
+                    structures.  */
+                 INSTALL_NEW_DTV (dtv);
+               }
+
+             /* If there is currently memory allocate for this
+                dtv entry free it.  */
+             /* XXX Ideally we will at some point create a memory
+                pool.  */
+             if (! dtv[modid].pointer.is_static
+                 && dtv[modid].pointer.val != TLS_DTV_UNALLOCATED)
+               /* Note that free is called for NULL is well.  We
+                  deallocate even if it is this dtv entry we are
+                  supposed to load.  The reason is that we call
+                  memalign and not malloc.  */
+               free (dtv[modid].pointer.val);
+
+             /* This module is loaded dynamically- We defer memory
+                allocation.  */
+             dtv[modid].pointer.is_static = false;
+             dtv[modid].pointer.val = TLS_DTV_UNALLOCATED;
+
+             if (modid == req_modid)
+               the_map = map;
+           }
+
+         total += listp->len;
+       }
+      while ((listp = listp->next) != NULL);
+
+      /* This will be the new maximum generation counter.  */
+      dtv[0].counter = new_gen;
+    }
+
+  return the_map;
+}
+
+
+/* The generic dynamic and local dynamic model cannot be used in
+   statically linked applications.  */
+void *
+__tls_get_addr (GET_ADDR_ARGS)
+{
+  dtv_t *dtv = THREAD_DTV ();
+  struct link_map *the_map = NULL;
+  void *p;
+
+  if (__builtin_expect (dtv[0].counter != GL(dl_tls_generation), 0))
+    the_map = _dl_update_slotinfo (GET_ADDR_MODULE);
+
+  p = dtv[GET_ADDR_MODULE].pointer.val;
+
+  if (__builtin_expect (p == TLS_DTV_UNALLOCATED, 0))
+    {
+      /* The allocation was deferred.  Do it now.  */
+      if (the_map == NULL)
+       {
+         /* Find the link map for this module.  */
+         size_t idx = GET_ADDR_MODULE;
+         struct dtv_slotinfo_list *listp = GL(dl_tls_dtv_slotinfo_list);
+
+         while (idx >= listp->len)
+           {
+             idx -= listp->len;
+             listp = listp->next;
+           }
+
+         the_map = listp->slotinfo[idx].map;
+       }
+
+      p = dtv[GET_ADDR_MODULE].pointer.val = allocate_and_init (the_map);
+      dtv[GET_ADDR_MODULE].pointer.is_static = false;
+    }
+
+  return (char *) p + GET_ADDR_OFFSET;
+}
+# endif
+
+
+
+void
+_dl_add_to_slotinfo (struct link_map  *l)
+{
+  /* Now that we know the object is loaded successfully add
+     modules containing TLS data to the dtv info table.  We
+     might have to increase its size.  */
+  struct dtv_slotinfo_list *listp;
+  struct dtv_slotinfo_list *prevp;
+  size_t idx = l->l_tls_modid;
+
+  /* Find the place in the dtv slotinfo list.  */
+  listp = GL(dl_tls_dtv_slotinfo_list);
+  prevp = NULL;                /* Needed to shut up gcc.  */
+  do
+    {
+      /* Does it fit in the array of this list element?  */
+      if (idx < listp->len)
+       break;
+      idx -= listp->len;
+      prevp = listp;
+      listp = listp->next;
+    }
+  while (listp != NULL);
+
+  if (listp == NULL)
+    {
+      /* When we come here it means we have to add a new element
+        to the slotinfo list.  And the new module must be in
+        the first slot.  */
+      assert (idx == 0);
+
+      listp = prevp->next = (struct dtv_slotinfo_list *)
+       malloc (sizeof (struct dtv_slotinfo_list)
+               + TLS_SLOTINFO_SURPLUS * sizeof (struct dtv_slotinfo));
+      if (listp == NULL)
+       {
+         /* We ran out of memory.  We will simply fail this
+            call but don't undo anything we did so far.  The
+            application will crash or be terminated anyway very
+            soon.  */
+
+         /* We have to do this since some entries in the dtv
+            slotinfo array might already point to this
+            generation.  */
+         ++GL(dl_tls_generation);
+
+         _dl_dprintf (_dl_debug_file,
+                       "cannot create TLS data structures: ABORT\n");
+         _dl_exit (127);
+       }
+
+      listp->len = TLS_SLOTINFO_SURPLUS;
+      listp->next = NULL;
+      _dl_memset (listp->slotinfo, '\0',
+             TLS_SLOTINFO_SURPLUS * sizeof (struct dtv_slotinfo));
+    }
+
+  /* Add the information into the slotinfo data structure.  */
+  listp->slotinfo[idx].map = l;
+  listp->slotinfo[idx].gen = GL(dl_tls_generation) + 1;
+}
diff --git a/libpthread/nptl/sysdeps/generic/dl-tls.h b/libpthread/nptl/sysdeps/generic/dl-tls.h
new file mode 100644 (file)
index 0000000..7703a97
--- /dev/null
@@ -0,0 +1,2 @@
+/* There has to be an architecture specific version of this file.  */
+#error "architecture-specific version of <dl-tls.h> missing"
diff --git a/libpthread/nptl/sysdeps/generic/libc-tls.c b/libpthread/nptl/sysdeps/generic/libc-tls.c
new file mode 100644 (file)
index 0000000..b78d964
--- /dev/null
@@ -0,0 +1,265 @@
+/* Initialization code for TLS in statically linked application.
+   Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <ldsodefs.h>
+#include <tls.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/param.h>
+#include <elf.h>
+#include <link.h>
+#include <string.h>
+#include <stdlib.h>
+
+
+#ifdef SHARED
+ #error makefile bug, this file is for static only
+#endif
+
+#if USE_TLS
+extern ElfW(Phdr) *_dl_phdr;
+extern size_t _dl_phnum;
+
+
+static dtv_t static_dtv[2 + TLS_SLOTINFO_SURPLUS];
+
+
+static struct
+{
+  struct dtv_slotinfo_list si;
+  /* The dtv_slotinfo_list data structure does not include the actual
+     information since it is defined as an array of size zero.  We define
+     here the necessary entries.  Note that it is not important whether
+     there is padding or not since we will always access the information
+     through the 'si' element.  */
+  struct dtv_slotinfo info[2 + TLS_SLOTINFO_SURPLUS];
+} static_slotinfo;
+
+/* Fake link map for the application.  */
+static struct link_map static_map;
+
+
+/* Highest dtv index currently needed.  */
+size_t _dl_tls_max_dtv_idx;
+/* Flag signalling whether there are gaps in the module ID allocation.  */
+bool _dl_tls_dtv_gaps;
+/* Information about the dtv slots.  */
+struct dtv_slotinfo_list *_dl_tls_dtv_slotinfo_list;
+/* Number of modules in the static TLS block.  */
+size_t _dl_tls_static_nelem;
+/* Size of the static TLS block.  */
+size_t _dl_tls_static_size;
+/* Size actually allocated in the static TLS block.  */
+size_t _dl_tls_static_used;
+/* Alignment requirement of the static TLS block.  */
+size_t _dl_tls_static_align;
+
+/* Generation counter for the dtv.  */
+size_t _dl_tls_generation;
+
+
+/* Additional definitions needed by TLS initialization.  */
+#ifdef TLS_INIT_HELPER
+TLS_INIT_HELPER
+#endif
+
+static inline void
+init_slotinfo (void)
+{
+  /* Create the slotinfo list.  */
+  static_slotinfo.si.len = (((char *) (&static_slotinfo + 1)
+                            - (char *) &static_slotinfo.si.slotinfo[0])
+                           / sizeof static_slotinfo.si.slotinfo[0]);
+  // static_slotinfo.si.next = NULL;   already zero
+
+  /* The slotinfo list.  Will be extended by the code doing dynamic
+     linking.  */
+  GL(dl_tls_max_dtv_idx) = 1;
+  GL(dl_tls_dtv_slotinfo_list) = &static_slotinfo.si;
+}
+
+static inline void
+init_static_tls (size_t memsz, size_t align)
+{
+  /* That is the size of the TLS memory for this object.  The initialized
+     value of _dl_tls_static_size is provided by dl-open.c to request some
+     surplus that permits dynamic loading of modules with IE-model TLS.  */
+  GL(dl_tls_static_size) = roundup (memsz + GL(dl_tls_static_size),
+                                   TLS_TCB_ALIGN);
+  GL(dl_tls_static_used) = memsz;
+  /* The alignment requirement for the static TLS block.  */
+  GL(dl_tls_static_align) = align;
+  /* Number of elements in the static TLS block.  */
+  GL(dl_tls_static_nelem) = GL(dl_tls_max_dtv_idx);
+}
+
+void
+__libc_setup_tls (size_t tcbsize, size_t tcbalign)
+{
+  void *tlsblock;
+  size_t memsz = 0;
+  size_t filesz = 0;
+  void *initimage = NULL;
+  size_t align = 0;
+  size_t max_align = tcbalign;
+  size_t tcb_offset;
+  ElfW(Phdr) *phdr;
+
+  /* Look through the TLS segment if there is any.  */
+  if (_dl_phdr != NULL)
+    for (phdr = _dl_phdr; phdr < &_dl_phdr[_dl_phnum]; ++phdr)
+      if (phdr->p_type == PT_TLS)
+       {
+         /* Remember the values we need.  */
+         memsz = phdr->p_memsz;
+         filesz = phdr->p_filesz;
+         initimage = (void *) phdr->p_vaddr;
+         align = phdr->p_align;
+         if (phdr->p_align > max_align)
+           max_align = phdr->p_align;
+         break;
+       }
+
+  /* We have to set up the TCB block which also (possibly) contains
+     'errno'.  Therefore we avoid 'malloc' which might touch 'errno'.
+     Instead we use 'sbrk' which would only uses 'errno' if it fails.
+     In this case we are right away out of memory and the user gets
+     what she/he deserves.
+
+     The initialized value of _dl_tls_static_size is provided by dl-open.c
+     to request some surplus that permits dynamic loading of modules with
+     IE-model TLS.  */
+# if defined(TLS_TCB_AT_TP)
+  tcb_offset = roundup (memsz + GL(dl_tls_static_size), tcbalign);
+  tlsblock = sbrk (tcb_offset + tcbsize + max_align);
+# elif defined(TLS_DTV_AT_TP)
+  tcb_offset = roundup (tcbsize, align ?: 1);
+  tlsblock = sbrk (tcb_offset + memsz + max_align
+                    + TLS_PRE_TCB_SIZE + GL(dl_tls_static_size));
+  tlsblock += TLS_PRE_TCB_SIZE;
+# else
+  /* In case a model with a different layout for the TCB and DTV
+     is defined add another #elif here and in the following #ifs.  */
+#  error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
+# endif
+
+  /* Align the TLS block.  */
+  tlsblock = (void *) (((uintptr_t) tlsblock + max_align - 1)
+                      & ~(max_align - 1));
+
+  /* Initialize the dtv.  [0] is the length, [1] the generation counter.  */
+  static_dtv[0].counter = (sizeof (static_dtv) / sizeof (static_dtv[0])) - 2;
+  // static_dtv[1].counter = 0;                would be needed if not already done
+
+  /* Initialize the TLS block.  */
+# if defined(TLS_TCB_AT_TP)
+  static_dtv[2].pointer.val = ((char *) tlsblock + tcb_offset
+                              - roundup (memsz, align ?: 1));
+  static_map.l_tls_offset = roundup (memsz, align ?: 1);
+# elif defined(TLS_DTV_AT_TP)
+  static_dtv[2].pointer.val = (char *) tlsblock + tcb_offset;
+  static_map.l_tls_offset = tcb_offset;
+# else
+#  error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
+# endif
+  static_dtv[2].pointer.is_static = true;
+  /* sbrk gives us zero'd memory, so we don't need to clear the remainder.  */
+  memcpy (static_dtv[2].pointer.val, initimage, filesz);
+
+  /* Install the pointer to the dtv.  */
+
+  /* Initialize the thread pointer.  */
+# if defined(TLS_TCB_AT_TP)
+  INSTALL_DTV ((char *) tlsblock + tcb_offset, static_dtv);
+
+  const char *lossage = TLS_INIT_TP ((char *) tlsblock + tcb_offset, 0);
+# elif defined(TLS_DTV_AT_TP)
+  INSTALL_DTV (tlsblock, static_dtv);
+  const char *lossage = (char *)TLS_INIT_TP (tlsblock, 0);
+# else
+#  error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
+# endif
+  if (__builtin_expect (lossage != NULL, 0))
+    abort();
+
+  /* We have to create a fake link map which normally would be created
+     by the dynamic linker.  It just has to have enough information to
+     make the TLS routines happy.  */
+  static_map.l_tls_align = align;
+  static_map.l_tls_blocksize = memsz;
+  static_map.l_tls_initimage = initimage;
+  static_map.l_tls_initimage_size = filesz;
+  static_map.l_tls_modid = 1;
+
+  init_slotinfo ();
+  // static_slotinfo.si.slotinfo[1].gen = 0; already zero
+  static_slotinfo.si.slotinfo[1].map = &static_map;
+
+  memsz = roundup (memsz, align ?: 1);
+
+# if defined(TLS_TCB_AT_TP)
+  memsz += tcbsize;
+# elif defined(TLS_DTV_AT_TP)
+  memsz += tcb_offset;
+# endif
+
+  init_static_tls (memsz, MAX (TLS_TCB_ALIGN, max_align));
+}
+
+/* This is called only when the data structure setup was skipped at startup,
+   when there was no need for it then.  Now we have dynamically loaded
+   something needing TLS, or libpthread needs it.  */
+int
+internal_function
+_dl_tls_setup (void)
+{
+  init_slotinfo ();
+  init_static_tls (
+# if defined(TLS_TCB_AT_TP)
+                  TLS_TCB_SIZE,
+# else
+                  0,
+# endif
+                  TLS_TCB_ALIGN);
+  return 0;
+}
+
+
+/* This is the minimal initialization function used when libpthread is
+   not used.  */
+void
+__attribute__ ((weak))
+__pthread_initialize_minimal (void)
+{
+  __libc_setup_tls (TLS_INIT_TCB_SIZE, TLS_INIT_TCB_ALIGN);
+}
+
+#elif defined NONTLS_INIT_TP
+
+/* This is the minimal initialization function used when libpthread is
+   not used.  */
+void
+__attribute__ ((weak))
+__pthread_initialize_minimal (void)
+{
+  NONTLS_INIT_TP;
+}
+
+#endif
diff --git a/libpthread/nptl/sysdeps/generic/lowlevellock.h b/libpthread/nptl/sysdeps/generic/lowlevellock.h
new file mode 100644 (file)
index 0000000..0600e17
--- /dev/null
@@ -0,0 +1,84 @@
+/* Low level locking macros used in NPTL implementation.  Stub version.
+   Copyright (C) 2002, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <atomic.h>
+
+
+/* Mutex lock counter:
+   bit 31 clear means unlocked;
+   bit 31 set means locked.
+
+   All code that looks at bit 31 first increases the 'number of
+   interested threads' usage counter, which is in bits 0-30.
+
+   All negative mutex values indicate that the mutex is still locked.  */
+
+
+static inline void
+__generic_mutex_lock (int *mutex)
+{
+  unsigned int v;
+
+  /* Bit 31 was clear, we got the mutex.  (this is the fastpath).  */
+  if (atomic_bit_test_set (mutex, 31) == 0)
+    return;
+
+  atomic_increment (mutex);
+
+  while (1)
+    {
+      if (atomic_bit_test_set (mutex, 31) == 0)
+       {
+         atomic_decrement (mutex);
+         return;
+       }
+
+      /* We have to wait now. First make sure the futex value we are
+        monitoring is truly negative (i.e. locked). */
+      v = *mutex;
+      if (v >= 0)
+       continue;
+
+      lll_futex_wait (mutex, v,
+                     // XYZ check mutex flag
+                     LLL_SHARED);
+    }
+}
+
+
+static inline void
+__generic_mutex_unlock (int *mutex)
+{
+  /* Adding 0x80000000 to the counter results in 0 if and only if
+     there are not other interested threads - we can return (this is
+     the fastpath).  */
+  if (atomic_add_zero (mutex, 0x80000000))
+    return;
+
+  /* There are other threads waiting for this mutex, wake one of them
+     up.  */
+  lll_futex_wake (mutex, 1,
+                 // XYZ check mutex flag
+                 LLL_SHARED);
+}
+
+
+#define lll_mutex_lock(futex) __generic_mutex_lock (&(futex))
+#define lll_mutex_unlock(futex) __generic_mutex_unlock (&(futex))
diff --git a/libpthread/nptl/sysdeps/i386/Makefile b/libpthread/nptl/sysdeps/i386/Makefile
new file mode 100644 (file)
index 0000000..2f0d88f
--- /dev/null
@@ -0,0 +1,27 @@
+# Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+
+# The GNU C Library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+
+# The GNU C Library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public
+# License along with the GNU C Library; if not, write to the Free
+# Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+# 02111-1307 USA.
+
+ifeq ($(subdir),csu)
+gen-as-const-headers += tcb-offsets.sym
+endif
+
+ifeq ($(subdir),nptl)
+CFLAGS-pthread_create.c += -mpreferred-stack-boundary=4
+CFLAGS-tst-align.c += -mpreferred-stack-boundary=4
+CFLAGS-tst-align2.c += -mpreferred-stack-boundary=4
+endif
diff --git a/libpthread/nptl/sysdeps/i386/Makefile.arch b/libpthread/nptl/sysdeps/i386/Makefile.arch
new file mode 100644 (file)
index 0000000..e2bb2ef
--- /dev/null
@@ -0,0 +1,53 @@
+# Makefile for uClibc NPTL
+#
+# Copyright (C) 2005 Steven J. Hill <sjhill@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+libpthread_CSRC = pthread_spin_lock.c
+libpthread_SSRC = i486/pthread_spin_trylock.S
+
+CFLAGS-pthread_spin_lock.c += -D_GNU_SOURCE
+
+CFLAGS-i386 = $(SSP_ALL_CFLAGS)
+#CFLAGS:=$(CFLAGS:-O1=-O2)
+
+PTHREAD_ARCH_DIR := $(top_srcdir)libpthread/nptl/sysdeps/i386
+PTHREAD_ARCH_OUT := $(top_builddir)libpthread/nptl/sysdeps/i386
+PTHREAD_ARCH_OBJ := $(patsubst %.S,$(PTHREAD_ARCH_OUT)/%.o,$(libpthread_SSRC))
+PTHREAD_ARCH_OBJ += $(patsubst %.c,$(PTHREAD_ARCH_OUT)/%.o,$(libpthread_CSRC))
+
+ifeq ($(DOPIC),y)
+libpthread-a-y += $(PTHREAD_ARCH_OBJ:.o=.os)
+else
+libpthread-a-y += $(PTHREAD_ARCH_OBJ)
+endif
+libpthread-so-y += $(PTHREAD_ARCH_OBJ:.o=.oS)
+
+libpthread-nomulti-y += $(PTHREAD_ARCH_OBJ)
+
+objclean-y += nptl_arch_clean
+headers_clean-y += nptl_arch_headers_clean
+
+#
+# Create 'tcb-offsets.h' header file.
+#
+CFLAGS-tcb-offsets.c = -S
+
+$(PTHREAD_ARCH_OUT)/tcb-offsets.c: $(PTHREAD_ARCH_DIR)/tcb-offsets.sym
+       $(do_awk) $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@
+
+$(PTHREAD_ARCH_OUT)/tcb-offsets.s: $(PTHREAD_ARCH_OUT)/tcb-offsets.c
+       $(compile.c)
+
+$(PTHREAD_ARCH_OUT)/tcb-offsets.h: $(PTHREAD_ARCH_OUT)/tcb-offsets.s
+       $(do_sed) -n "s/^.*@@@name@@@\([^@]*\)@@@value@@@[^0-9Xxa-fA-F-]*\([0-9Xxa-fA-F-][0-9Xxa-fA-F-]*\).*@@@end@@@.*$\/#define \1 \2/p" $< > $@
+
+pregen-headers-$(UCLIBC_HAS_THREADS_NATIVE) += $(PTHREAD_ARCH_OUT)/tcb-offsets.h
+
+nptl_arch_headers_clean:
+       $(do_rm) $(addprefix $(PTHREAD_ARCH_OUT)/tcb-offsets., c s h)
+
+nptl_arch_clean:
+       $(do_rm) $(addprefix $(PTHREAD_ARCH_OUT)/*., o os oS)
diff --git a/libpthread/nptl/sysdeps/i386/dl-tls.h b/libpthread/nptl/sysdeps/i386/dl-tls.h
new file mode 100644 (file)
index 0000000..a170719
--- /dev/null
@@ -0,0 +1,60 @@
+/* Thread-local storage handling in the ELF dynamic linker.  i386 version.
+   Copyright (C) 2002, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+
+/* Type used for the representation of TLS information in the GOT.  */
+typedef struct
+{
+  unsigned long int ti_module;
+  unsigned long int ti_offset;
+} tls_index;
+
+
+#ifdef SHARED
+/* This is the prototype for the GNU version.  */
+extern void *___tls_get_addr (tls_index *ti)
+     __attribute__ ((__regparm__ (1)));
+extern void *___tls_get_addr_internal (tls_index *ti)
+     __attribute__ ((__regparm__ (1))) attribute_hidden;
+
+# ifdef IS_IN_rtld
+/* The special thing about the x86 TLS ABI is that we have two
+   variants of the __tls_get_addr function with different calling
+   conventions.  The GNU version, which we are mostly concerned here,
+   takes the parameter in a register.  The name is changed by adding
+   an additional underscore at the beginning.  The Sun version uses
+   the normal calling convention.  */
+void *
+__tls_get_addr (tls_index *ti)
+{
+  return ___tls_get_addr_internal (ti);
+}
+
+
+/* Prepare using the definition of __tls_get_addr in the generic
+   version of this file.  */
+# define __tls_get_addr __attribute__ ((__regparm__ (1))) ___tls_get_addr
+strong_alias (___tls_get_addr, ___tls_get_addr_internal)
+#else
+
+/* Users should get the better interface.  */
+# define __tls_get_addr ___tls_get_addr
+
+# endif
+#endif
diff --git a/libpthread/nptl/sysdeps/i386/i486/pthread_spin_trylock.S b/libpthread/nptl/sysdeps/i386/i486/pthread_spin_trylock.S
new file mode 100644 (file)
index 0000000..e30072c
--- /dev/null
@@ -0,0 +1,47 @@
+/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread-errnos.h>
+
+
+#ifdef UP
+# define LOCK
+#else
+# define LOCK lock
+#endif
+
+       .globl  pthread_spin_trylock
+       .type   pthread_spin_trylock,@function
+       .align  16
+pthread_spin_trylock:
+       movl    4(%esp), %edx
+       movl    $1, %eax
+       xorl    %ecx, %ecx
+       LOCK
+       cmpxchgl %ecx, (%edx)
+       movl    $EBUSY, %eax
+#ifdef HAVE_CMOV
+       cmovel  %ecx, %eax
+#else
+       jne     0f
+       movl    %ecx, %eax
+0:
+#endif
+       ret
+       .size   pthread_spin_trylock,.-pthread_spin_trylock
diff --git a/libpthread/nptl/sysdeps/i386/i586/pthread_spin_trylock.S b/libpthread/nptl/sysdeps/i386/i586/pthread_spin_trylock.S
new file mode 100644 (file)
index 0000000..ffe3d45
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "../i486/pthread_spin_trylock.S"
diff --git a/libpthread/nptl/sysdeps/i386/i686/Makefile b/libpthread/nptl/sysdeps/i386/i686/Makefile
new file mode 100644 (file)
index 0000000..137c0a2
--- /dev/null
@@ -0,0 +1,32 @@
+# Copyright (C) 2003 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+# Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+# The GNU C Library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+
+# The GNU C Library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public
+# License along with the GNU C Library; if not, write to the Free
+# Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+# 02111-1307 USA.
+
+ifeq ($(subdir),nptl)
+# It turns out that stack coloring is in general not good on P4s.  Some
+# applications will benefit.  We will probably have a configuration option
+# at some point.  Enabling coloring can be done with
+#
+#   -DCOLORING_INCREMENT=128
+#
+# What is useful is to avoid the 64k aliasing problem which reliably
+# happens if all stacks use sizes which are a multiple of 64k.  Tell
+# the stack allocator to disturb this by allocation one more page if
+# necessary.
+CFLAGS-pthread_create.c += -DMULTI_PAGE_ALIASING=65536
+endif
diff --git a/libpthread/nptl/sysdeps/i386/i686/pthread_spin_trylock.S b/libpthread/nptl/sysdeps/i386/i686/pthread_spin_trylock.S
new file mode 100644 (file)
index 0000000..a5d861f
--- /dev/null
@@ -0,0 +1,21 @@
+/* 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 HAVE_CMOV      1
+#include "../i486/pthread_spin_trylock.S"
diff --git a/libpthread/nptl/sysdeps/i386/i686/tls.h b/libpthread/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/libpthread/nptl/sysdeps/i386/jmpbuf-unwind.h b/libpthread/nptl/sysdeps/i386/jmpbuf-unwind.h
new file mode 100644 (file)
index 0000000..b9528f3
--- /dev/null
@@ -0,0 +1,32 @@
+/* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <setjmp.h>
+#include <stdint.h>
+#include <unwind.h>
+
+#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \
+  _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj)
+
+#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \
+  ((uintptr_t) (_address) - (_adj) < (uintptr_t) (_jmpbuf)[JB_SP] - (_adj))
+
+/* We use the normal lobngjmp for unwinding.  */
+extern __typeof(longjmp) __libc_longjmp attribute_noreturn;
+#define __libc_unwind_longjmp(buf, val) __libc_longjmp (buf, val)
diff --git a/libpthread/nptl/sysdeps/i386/pthread_spin_init.c b/libpthread/nptl/sysdeps/i386/pthread_spin_init.c
new file mode 100644 (file)
index 0000000..0a47981
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* Not needed.  pthread_spin_init is an alias for pthread_spin_unlock.  */
diff --git a/libpthread/nptl/sysdeps/i386/pthread_spin_lock.c b/libpthread/nptl/sysdeps/i386/pthread_spin_lock.c
new file mode 100644 (file)
index 0000000..34cd525
--- /dev/null
@@ -0,0 +1,49 @@
+/* Copyright (C) 2002,2003,2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+
+#ifndef LOCK_PREFIX
+# ifdef UP
+#  define LOCK_PREFIX  /* nothing */
+# else
+#  define LOCK_PREFIX  "lock;"
+# endif
+#endif
+
+
+int
+pthread_spin_lock (
+     pthread_spinlock_t *lock)
+{
+  __asm__ ("\n"
+       "1:\t" LOCK_PREFIX "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)
+       : "m" (*lock));
+
+  return 0;
+}
diff --git a/libpthread/nptl/sysdeps/i386/pthread_spin_unlock.S b/libpthread/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/libpthread/nptl/sysdeps/i386/pthreaddef.h b/libpthread/nptl/sysdeps/i386/pthreaddef.h
new file mode 100644 (file)
index 0000000..81456a4
--- /dev/null
@@ -0,0 +1,48 @@
+/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* 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
+
+
+/* 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));                           \
+  }
diff --git a/libpthread/nptl/sysdeps/i386/tcb-offsets.sym b/libpthread/nptl/sysdeps/i386/tcb-offsets.sym
new file mode 100644 (file)
index 0000000..69f9deb
--- /dev/null
@@ -0,0 +1,17 @@
+#include <sysdep.h>
+#include <tls.h>
+
+RESULT                 offsetof (struct pthread, result)
+TID                    offsetof (struct pthread, tid)
+PID                    offsetof (struct pthread, pid)
+CANCELHANDLING         offsetof (struct pthread, cancelhandling)
+CLEANUP_JMP_BUF                offsetof (struct pthread, cleanup_jmp_buf)
+MULTIPLE_THREADS_OFFSET        offsetof (tcbhead_t, multiple_threads)
+SYSINFO_OFFSET         offsetof (tcbhead_t, sysinfo)
+CLEANUP                        offsetof (struct pthread, cleanup)
+CLEANUP_PREV           offsetof (struct _pthread_cleanup_buffer, __prev)
+MUTEX_FUTEX            offsetof (pthread_mutex_t, __data.__lock)
+POINTER_GUARD          offsetof (tcbhead_t, pointer_guard)
+#ifndef __ASSUME_PRIVATE_FUTEX
+PRIVATE_FUTEX          offsetof (tcbhead_t, private_futex)
+#endif
diff --git a/libpthread/nptl/sysdeps/i386/tls.h b/libpthread/nptl/sysdeps/i386/tls.h
new file mode 100644 (file)
index 0000000..5f27d8f
--- /dev/null
@@ -0,0 +1,480 @@
+/* Definition for thread-local data handling.  nptl/i386 version.
+   Copyright (C) 2002-2007, 2009 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 <stdbool.h>
+# include <stddef.h>
+# include <stdint.h>
+# include <stdlib.h>
+# include <list.h>
+# include <sysdep.h>
+# include <bits/kernel-features.h>
+
+
+/* Type for the dtv.  */
+typedef union dtv
+{
+  size_t counter;
+  struct
+  {
+    void *val;
+    bool is_static;
+  } pointer;
+} dtv_t;
+
+
+typedef struct
+{
+  void *tcb;           /* Pointer to the TCB.  Not necessarily the
+                          thread descriptor used by libpthread.  */
+  dtv_t *dtv;
+  void *self;          /* Pointer to the thread descriptor.  */
+  int multiple_threads;
+  uintptr_t sysinfo;
+  uintptr_t stack_guard;
+  uintptr_t pointer_guard;
+  int gscope_flag;
+#ifndef __ASSUME_PRIVATE_FUTEX
+  int private_futex;
+#else
+  int __unused1;
+#endif
+  /* Reservation of some values for the TM ABI.  */
+  void *__private_tm[5];
+} tcbhead_t;
+
+# define TLS_MULTIPLE_THREADS_IN_TCB 1
+
+#else /* __ASSEMBLER__ */
+# include <tcb-offsets.h>
+#endif
+
+
+/* We require TLS support in the tools.  */
+#define HAVE_TLS_SUPPORT
+#define HAVE___THREAD 1
+#define HAVE_TLS_MODEL_ATTRIBUTE 1
+
+/* Signal that TLS support is available.  */
+#define USE_TLS        1
+
+
+/* Alignment requirement for the stack.  For IA-32 this is governed 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 <descr.h>
+
+/* This is the size of the initial TCB.  Can't be just sizeof (tcbhead_t),
+   because NPTL getpid, __libc_alloca_cutoff etc. need (almost) the whole
+   struct pthread even when not linked with -lpthread.  */
+# define TLS_INIT_TCB_SIZE sizeof (struct pthread)
+
+/* Alignment requirements for the initial TCB.  */
+# define TLS_INIT_TCB_ALIGN __alignof__ (struct pthread)
+
+/* 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(dtvp) \
+  ({ struct pthread *__pd;                                                   \
+     THREAD_SETMEM (__pd, header.dtv, (dtvp)); })
+
+/* Return dtv of given thread descriptor.  */
+# define GET_DTV(descr) \
+  (((tcbhead_t *) (descr))->dtv)
+
+#define THREAD_SELF_SYSINFO    THREAD_GETMEM (THREAD_SELF, header.sysinfo)
+#define THREAD_SYSINFO(pd)     ((pd)->header.sysinfo)
+
+/* 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
+
+#if defined NEED_DL_SYSINFO
+# define INIT_SYSINFO \
+  _head->sysinfo = GLRO(dl_sysinfo)
+#else
+# define INIT_SYSINFO
+#endif
+
+#ifndef LOCK_PREFIX
+# ifdef UP
+#  define LOCK_PREFIX  /* nothing */
+# else
+#  define LOCK_PREFIX "lock;"
+# endif
+#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;                                                \
+     /* New syscall handling support.  */                                    \
+     INIT_SYSINFO;                                                           \
+                                                                             \
+     /* 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 == 0 ? NULL                                                     \
+     : "set_thread_area failed when setting up thread-local storage\n"; })
+
+
+/* Return the address of the dtv for the current thread.  */
+# define THREAD_DTV() \
+  ({ struct pthread *__pd;                                                   \
+     THREAD_GETMEM (__pd, header.dtv); })
+
+
+/* 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.self)));                    \
+     __self;})
+
+/* Magic for libthread_db to know how to do THREAD_SELF.  */
+# define DB_THREAD_SELF \
+  REGISTER_THREAD_AREA (32, offsetof (struct user_regs_struct, xgs), 3) \
+  REGISTER_THREAD_AREA (64, 26 * 8, 3) /* x86-64's user_regs_struct->gs */
+
+
+/* Read member of the thread descriptor directly.  */
+# define THREAD_GETMEM(descr, member) \
+  ({ __typeof (descr->member) __value;                                       \
+     if (sizeof (__value) == 1)                                                      \
+       __asm__ volatile ("movb %%gs:%P2,%b0"                               \
+                    : "=q" (__value)                                         \
+                    : "0" (0), "i" (offsetof (struct pthread, member)));     \
+     else if (sizeof (__value) == 4)                                         \
+       __asm__ volatile ("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__ volatile ("movl %%gs:%P1,%%eax\n\t"                          \
+                      "movl %%gs:%P2,%%edx"                                  \
+                      : "=A" (__value)                                       \
+                      : "i" (offsetof (struct pthread, member)),             \
+                        "i" (offsetof (struct pthread, member) + 4));        \
+       }                                                                     \
+     __value; })
+
+
+/* Same as THREAD_GETMEM, but the member offset can be non-constant.  */
+# define THREAD_GETMEM_NC(descr, member, idx) \
+  ({ __typeof (descr->member[0]) __value;                                    \
+     if (sizeof (__value) == 1)                                                      \
+       __asm__ volatile ("movb %%gs:%P2(%3),%b0"                                     \
+                    : "=q" (__value)                                         \
+                    : "0" (0), "i" (offsetof (struct pthread, member[0])),   \
+                    "r" (idx));                                              \
+     else if (sizeof (__value) == 4)                                         \
+       __asm__ volatile ("movl %%gs:%P1(,%2,4),%0"                                   \
+                    : "=r" (__value)                                         \
+                    : "i" (offsetof (struct pthread, member[0])),            \
+                      "r" (idx));                                            \
+     else                                                                    \
+       {                                                                     \
+        if (sizeof (__value) != 8)                                           \
+          /* There should not be any value with a size other than 1,         \
+             4 or 8.  */                                                     \
+          abort ();                                                          \
+                                                                             \
+        __asm__ volatile  ("movl %%gs:%P1(,%2,8),%%eax\n\t"                  \
+                       "movl %%gs:4+%P1(,%2,8),%%edx"                        \
+                       : "=&A" (__value)                                     \
+                       : "i" (offsetof (struct pthread, member[0])),         \
+                         "r" (idx));                                         \
+       }                                                                     \
+     __value; })
+
+
+/* Same as THREAD_SETMEM, but the member offset can be non-constant.  */
+# define THREAD_SETMEM(descr, member, value) \
+  ({ if (sizeof (descr->member) == 1)                                        \
+       __asm__ volatile ("movb %b0,%%gs:%P1" :                               \
+                    : "iq" (value),                                          \
+                      "i" (offsetof (struct pthread, member)));              \
+     else if (sizeof (descr->member) == 4)                                   \
+       __asm__ volatile ("movl %0,%%gs:%P1" :                                \
+                    : "ir" (value),                                          \
+                      "i" (offsetof (struct pthread, member)));              \
+     else                                                                    \
+       {                                                                     \
+        if (sizeof (descr->member) != 8)                                     \
+          /* There should not be any value with a size other than 1,         \
+             4 or 8.  */                                                     \
+          abort ();                                                          \
+                                                                             \
+        __asm__ volatile ("movl %%eax,%%gs:%P1\n\t"                          \
+                      "movl %%edx,%%gs:%P2" :                                \
+                      : "A" (value),                                         \
+                        "i" (offsetof (struct pthread, member)),             \
+                        "i" (offsetof (struct pthread, member) + 4));        \
+       }})
+
+
+/* Set member of the thread descriptor directly.  */
+# define THREAD_SETMEM_NC(descr, member, idx, value) \
+  ({ if (sizeof (descr->member[0]) == 1)                                     \
+       __asm__ volatile ("movb %b0,%%gs:%P1(%2)" :                                   \
+                    : "iq" (value),                                          \
+                      "i" (offsetof (struct pthread, member)),               \
+                      "r" (idx));                                            \
+     else if (sizeof (descr->member[0]) == 4)                                \
+       __asm__ volatile ("movl %0,%%gs:%P1(,%2,4)" :                         \
+                    : "ir" (value),                                          \
+                      "i" (offsetof (struct pthread, member)),               \
+                      "r" (idx));                                            \
+     else                                                                    \
+       {                                                                     \
+        if (sizeof (descr->member[0]) != 8)                                  \
+          /* There should not be any value with a size other than 1,         \
+             4 or 8.  */                                                     \
+          abort ();                                                          \
+                                                                             \
+        __asm__ volatile ("movl %%eax,%%gs:%P1(,%2,8)\n\t"                           \
+                      "movl %%edx,%%gs:4+%P1(,%2,8)" :                       \
+                      : "A" (value),                                         \
+                        "i" (offsetof (struct pthread, member)),             \
+                        "r" (idx));                                          \
+       }})
+
+
+/* Atomic compare and exchange on TLS, returning old value.  */
+#define THREAD_ATOMIC_CMPXCHG_VAL(descr, member, newval, oldval) \
+  ({ __typeof (descr->member) __ret;                                         \
+     __typeof (oldval) __old = (oldval);                                     \
+     if (sizeof (descr->member) == 4)                                        \
+       __asm__ volatile (LOCK_PREFIX "cmpxchgl %2, %%gs:%P3"                 \
+                    : "=a" (__ret)                                           \
+                    : "0" (__old), "r" (newval),                             \
+                      "i" (offsetof (struct pthread, member)));              \
+     else                                                                    \
+       /* Not necessary for other sizes in the moment.  */                   \
+       abort ();                                                             \
+     __ret; })
+
+
+/* Atomic logical and.  */
+#define THREAD_ATOMIC_AND(descr, member, val) \
+  (void) ({ if (sizeof ((descr)->member) == 4)                               \
+             __asm__ volatile (LOCK_PREFIX "andl %1, %%gs:%P0"               \
+                           :: "i" (offsetof (struct pthread, member)),       \
+                              "ir" (val));                                   \
+           else                                                              \
+             /* Not necessary for other sizes in the moment.  */             \
+             abort (); })
+
+
+/* Atomic set bit.  */
+#define THREAD_ATOMIC_BIT_SET(descr, member, bit) \
+  (void) ({ if (sizeof ((descr)->member) == 4)                               \
+             __asm__ volatile (LOCK_PREFIX "orl %1, %%gs:%P0"                \
+                           :: "i" (offsetof (struct pthread, member)),       \
+                              "ir" (1 << (bit)));                            \
+           else                                                              \
+             /* Not necessary for other sizes in the moment.  */             \
+             abort (); })
+
+
+/* Call the user-provided thread function.  */
+#define CALL_THREAD_FCT(descr) \
+  ({ void *__res;                                                            \
+     int __ignore1, __ignore2;                                               \
+     __asm__ volatile ("pushl %%eax\n\t"                                             \
+                  "pushl %%eax\n\t"                                          \
+                  "pushl %%eax\n\t"                                          \
+                  "pushl %%gs:%P4\n\t"                                       \
+                  "call *%%gs:%P3\n\t"                                       \
+                  "addl $16, %%esp"                                          \
+                  : "=a" (__res), "=c" (__ignore1), "=d" (__ignore2)         \
+                  : "i" (offsetof (struct pthread, start_routine)),          \
+                    "i" (offsetof (struct pthread, arg)));                   \
+     __res; })
+
+
+/* Set the stack guard field in TCB head.  */
+#define THREAD_SET_STACK_GUARD(value) \
+  THREAD_SETMEM (THREAD_SELF, header.stack_guard, value)
+#define THREAD_COPY_STACK_GUARD(descr) \
+  ((descr)->header.stack_guard                                               \
+   = THREAD_GETMEM (THREAD_SELF, header.stack_guard))
+
+
+/* Set the pointer guard field in the TCB head.  */
+#define THREAD_SET_POINTER_GUARD(value) \
+  THREAD_SETMEM (THREAD_SELF, header.pointer_guard, value)
+#define THREAD_COPY_POINTER_GUARD(descr) \
+  ((descr)->header.pointer_guard                                             \
+   = THREAD_GETMEM (THREAD_SELF, header.pointer_guard))
+
+
+/* Get and set the global scope generation counter in the TCB head.  */
+#define THREAD_GSCOPE_FLAG_UNUSED 0
+#define THREAD_GSCOPE_FLAG_USED   1
+#define THREAD_GSCOPE_FLAG_WAIT   2
+#define THREAD_GSCOPE_RESET_FLAG() \
+  do                                                                         \
+    { int __res;                                                             \
+      __asm__ volatile ("xchgl %0, %%gs:%P1"                                 \
+                   : "=r" (__res)                                            \
+                   : "i" (offsetof (struct pthread, header.gscope_flag)),    \
+                     "0" (THREAD_GSCOPE_FLAG_UNUSED));                       \
+      if (__res == THREAD_GSCOPE_FLAG_WAIT)                                  \
+       lll_futex_wake (&THREAD_SELF->header.gscope_flag, 1, LLL_PRIVATE);    \
+    }                                                                        \
+  while (0)
+#define THREAD_GSCOPE_SET_FLAG() \
+  THREAD_SETMEM (THREAD_SELF, header.gscope_flag, THREAD_GSCOPE_FLAG_USED)
+#define THREAD_GSCOPE_WAIT() \
+  GL(dl_wait_lookup_done) ()
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* tls.h */
diff --git a/libpthread/nptl/sysdeps/mips/Makefile b/libpthread/nptl/sysdeps/mips/Makefile
new file mode 100644 (file)
index 0000000..6371d28
--- /dev/null
@@ -0,0 +1,13 @@
+# Makefile for uClibc NPTL
+#
+# Copyright (C) 2005 Steven J. Hill <sjhill@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+top_srcdir=../../../../
+top_builddir=../../../../
+all: objs
+include $(top_builddir)Rules.mak
+include Makefile.arch
+include $(top_srcdir)Makerules
diff --git a/libpthread/nptl/sysdeps/mips/Makefile.arch b/libpthread/nptl/sysdeps/mips/Makefile.arch
new file mode 100644 (file)
index 0000000..2b17aee
--- /dev/null
@@ -0,0 +1,67 @@
+# Makefile for uClibc NPTL
+#
+# Copyright (C) 2005 Steven J. Hill <sjhill@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+libpthread_SSRC = pthread_spin_lock.S pthread_spin_trylock.S   \
+                 nptl-sysdep.S
+
+libc_a_CSRC = libc-tls.c
+
+CFLAGS-pt-raise.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1
+
+ASFLAGS-pthread_spin_lock.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1
+ASFLAGS-pthread_spin_trylock.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1
+ASFLAGS-nptl-sysdep.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1   \
+                       -I$(top_srcdir)libc/sysdeps/linux/mips
+
+CFLAGS-mips = $(SSP_ALL_CFLAGS)
+#CFLAGS:=$(CFLAGS:-O1=-O2)
+
+PTHREAD_ARCH_DIR := $(top_srcdir)libpthread/nptl/sysdeps/mips
+PTHREAD_ARCH_OUT := $(top_builddir)libpthread/nptl/sysdeps/mips
+PTHREAD_ARCH_OBJ := $(patsubst %.S,$(PTHREAD_ARCH_OUT)/%.o,$(libpthread_SSRC))
+
+ifeq ($(DOPIC),y)
+libpthread-a-y += $(PTHREAD_ARCH_OBJ:.o=.os)
+else
+libpthread-a-y += $(PTHREAD_ARCH_OBJ)
+endif
+libpthread-so-y += $(PTHREAD_ARCH_OBJ:.o=.oS)
+
+libpthread-nomulti-y += $(PTHREAD_ARCH_OBJ)
+
+LIBC_ARCH_OBJ := $(patsubst %.c,$(PTHREAD_ARCH_OUT)/%.o,$(libc_a_CSRC))
+
+libc-static-y += $(LIBC_ARCH_OBJ)
+
+libc-nomulti-y += $(LIBC_ARCH_OBJ)
+
+objclean-y += nptl_arch_objclean
+headers_clean-y += nptl_arch_headers_clean
+
+#
+# Create 'tcb-offsets.h' header file.
+#
+CFLAGS-tcb-offsets.c = -S
+
+$(PTHREAD_ARCH_OUT)/tcb-offsets.c: $(PTHREAD_ARCH_DIR)/tcb-offsets.sym
+       $(do_awk) -f $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@
+
+$(PTHREAD_ARCH_OUT)/tcb-offsets.s: $(PTHREAD_ARCH_OUT)/tcb-offsets.c
+       $(compile.c)
+
+$(PTHREAD_ARCH_OUT)/tcb-offsets.h: $(PTHREAD_ARCH_OUT)/tcb-offsets.s
+       $(do_sed) -n "s/^.*@@@name@@@\([^@]*\)@@@value@@@[^0-9Xxa-fA-F-]*\([0-9Xxa-fA-F-][0-9Xxa-fA-F-]*\).*@@@end@@@.*$\/#define \1 \2/p" $< > $@
+
+pregen-headers-$(UCLIBC_HAS_THREADS_NATIVE) += $(PTHREAD_ARCH_OUT)/tcb-offsets.h
+
+nptl_arch_headers_clean:
+       $(RM) $(PTHREAD_ARCH_OUT)/tcb-offsets.c         \
+             $(PTHREAD_ARCH_OUT)/tcb-offsets.s         \
+             $(PTHREAD_ARCH_OUT)/tcb-offsets.h
+
+nptl_arch_objclean:
+       $(RM) $(PTHREAD_ARCH_OUT)/*.{o,os,oS}
diff --git a/libpthread/nptl/sysdeps/mips/dl-tls.h b/libpthread/nptl/sysdeps/mips/dl-tls.h
new file mode 100644 (file)
index 0000000..3ad3b2b
--- /dev/null
@@ -0,0 +1,46 @@
+/* Thread-local storage handling in the ELF dynamic linker.  MIPS version.
+   Copyright (C) 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+
+/* Type used for the representation of TLS information in the GOT.  */
+typedef struct
+{
+  unsigned long int ti_module;
+  unsigned long int ti_offset;
+} tls_index;
+
+/* The thread pointer points 0x7000 past the first static TLS block.  */
+#define TLS_TP_OFFSET          0x7000
+
+/* Dynamic thread vector pointers point 0x8000 past the start of each
+   TLS block.  */
+#define TLS_DTV_OFFSET         0x8000
+
+/* Compute the value for a GOTTPREL reloc.  */
+#define TLS_TPREL_VALUE(sym_map, sym_val) \
+  ((sym_map)->l_tls_offset + sym_val - TLS_TP_OFFSET)
+
+/* Compute the value for a DTPREL reloc.  */
+#define TLS_DTPREL_VALUE(sym_val) \
+  (sym_val - TLS_DTV_OFFSET)
+
+extern void *__tls_get_addr (tls_index *ti);
+
+# define GET_ADDR_OFFSET       (ti->ti_offset + TLS_DTV_OFFSET)
+# define __TLS_GET_ADDR(__ti)  (__tls_get_addr (__ti) - TLS_DTV_OFFSET)
diff --git a/libpthread/nptl/sysdeps/mips/jmpbuf-unwind.h b/libpthread/nptl/sysdeps/mips/jmpbuf-unwind.h
new file mode 100644 (file)
index 0000000..a9cfe43
--- /dev/null
@@ -0,0 +1,30 @@
+/* Copyright (C) 2003, 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <setjmp.h>
+#include <stdint.h>
+#include <unwind.h>
+
+#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \
+  _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj)
+
+#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \
+  ((uintptr_t) (_address) - (_adj) < (uintptr_t) (_jmpbuf)[0].__sp - (_adj))
+
+/* We use the normal longjmp for unwinding.  */
+#define __libc_unwind_longjmp(buf, val) longjmp (buf, val)
diff --git a/libpthread/nptl/sysdeps/mips/libc-tls.c b/libpthread/nptl/sysdeps/mips/libc-tls.c
new file mode 100644 (file)
index 0000000..fdedc9f
--- /dev/null
@@ -0,0 +1,37 @@
+/* Thread-local storage handling in the ELF dynamic linker.  MIPS version.
+   Copyright (C) 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <../generic/libc-tls.c>
+#include <dl-tls.h>
+
+#if USE_TLS
+
+/* On MIPS, linker optimizations are not required, so __tls_get_addr
+   can be called even in statically linked binaries.  In this case module
+   must be always 1 and PT_TLS segment exist in the binary, otherwise it
+   would not link.  */
+
+void *
+__tls_get_addr (tls_index *ti)
+{
+  dtv_t *dtv = THREAD_DTV ();
+  return (char *) dtv[1].pointer.val + GET_ADDR_OFFSET;
+}
+
+#endif
diff --git a/libpthread/nptl/sysdeps/mips/nptl-sysdep.S b/libpthread/nptl/sysdeps/mips/nptl-sysdep.S
new file mode 100644 (file)
index 0000000..7a4a8d3
--- /dev/null
@@ -0,0 +1,2 @@
+/* Pull in __syscall_error.  */
+#include <syscall_error.S>
diff --git a/libpthread/nptl/sysdeps/mips/pthread_spin_lock.S b/libpthread/nptl/sysdeps/mips/pthread_spin_lock.S
new file mode 100644 (file)
index 0000000..e35c381
--- /dev/null
@@ -0,0 +1,38 @@
+/* Copyright (C) 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sys/asm.h>
+#include <sysdep.h>
+#include <sgidefs.h>
+
+ENTRY (pthread_spin_lock)
+       .set    push
+#if _MIPS_SIM == _ABIO32
+       .set    mips2
+#endif
+1:     ll      a2, 0(a0)
+       li      a1, 1
+       bnez    a2, 1b
+       sc      a1, 0(a0)
+       beqz    a1, 1b
+       MIPS_SYNC
+       .set    pop
+       li      v0, 0
+       j       ra
+       nop
+END (pthread_spin_lock)
diff --git a/libpthread/nptl/sysdeps/mips/pthread_spin_trylock.S b/libpthread/nptl/sysdeps/mips/pthread_spin_trylock.S
new file mode 100644 (file)
index 0000000..b547328
--- /dev/null
@@ -0,0 +1,43 @@
+/* Copyright (C) 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sys/asm.h>
+#include <sysdep.h>
+#define _ERRNO_H 1
+#include <bits/errno.h>
+#include <sgidefs.h>
+
+ENTRY (pthread_spin_trylock)
+       .set    push
+#if _MIPS_SIM == _ABIO32
+       .set    mips2
+#endif
+       ll      a2, 0(a0)
+       li      a1, 1
+       bnez    a2, 1f
+       sc      a1, 0(a0)
+       beqz    a1, 1f
+       MIPS_SYNC
+       .set    pop
+       li      v0, 0
+       j       ra
+       nop
+1:     li      v0, EBUSY
+       j       ra
+       nop
+END (pthread_spin_trylock)
diff --git a/libpthread/nptl/sysdeps/mips/pthreaddef.h b/libpthread/nptl/sysdeps/mips/pthreaddef.h
new file mode 100644 (file)
index 0000000..e72b4bc
--- /dev/null
@@ -0,0 +1,39 @@
+/* Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* Default stack size.  */
+#define ARCH_STACK_DEFAULT_SIZE        (2 * 1024 * 1024)
+
+/* Required stack pointer alignment at beginning.  */
+#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
+
+
+/* Location of current stack frame.  */
+#define CURRENT_STACK_FRAME    __builtin_frame_address (0)
+
+
+/* XXX Until we have a better place keep the definitions here.  */
+
+#define __exit_thread_inline(val) \
+  INLINE_SYSCALL (exit, 1, (val))
diff --git a/libpthread/nptl/sysdeps/mips/regdef.h b/libpthread/nptl/sysdeps/mips/regdef.h
new file mode 100644 (file)
index 0000000..a462d51
--- /dev/null
@@ -0,0 +1,26 @@
+/* Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ralf Baechle <ralf@gnu.org>.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _REGDEF_H
+#define _REGDEF_H
+
+#include <sys/regdef.h>
+#include <sys/fpregdef.h>
+
+#endif /* _REGDEF_H */
diff --git a/libpthread/nptl/sysdeps/mips/tcb-offsets.sym b/libpthread/nptl/sysdeps/mips/tcb-offsets.sym
new file mode 100644 (file)
index 0000000..e0e71dc
--- /dev/null
@@ -0,0 +1,11 @@
+#include <sysdep.h>
+#include <tls.h>
+
+--
+
+-- Abuse tls.h macros to derive offsets relative to the thread register.
+#define thread_offsetof(mem)   (long)(offsetof(struct pthread, mem) - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE)
+
+MULTIPLE_THREADS_OFFSET                thread_offsetof (header.multiple_threads)
+PID_OFFSET                     thread_offsetof (pid)
+TID_OFFSET                     thread_offsetof (tid)
diff --git a/libpthread/nptl/sysdeps/mips/tls.h b/libpthread/nptl/sysdeps/mips/tls.h
new file mode 100644 (file)
index 0000000..27b1c15
--- /dev/null
@@ -0,0 +1,181 @@
+/* Definition for thread-local data handling.  NPTL/MIPS version.
+   Copyright (C) 2005, 2007 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 <stdbool.h>
+# include <stddef.h>
+# include <stdint.h>
+
+/* Type for the dtv.  */
+typedef union dtv
+{
+  size_t counter;
+  struct
+  {
+    void *val;
+    bool is_static;
+  } pointer;
+} dtv_t;
+
+/* Note: rd must be $v1 to be ABI-conformant.  */
+# define READ_THREAD_POINTER() \
+    ({ void *__result;                                                       \
+       __asm__ __volatile__ (".set\tpush\n\t.set\tmips32r2\n\t"                      \
+                    "rdhwr\t%0, $29\n\t.set\tpop" : "=v" (__result));        \
+       __result; })
+
+#else /* __ASSEMBLER__ */
+# include <tcb-offsets.h>
+
+# define READ_THREAD_POINTER(rd) \
+       .set    push;                                                         \
+       .set    mips32r2;                                                     \
+       rdhwr   rd, $29;                                                      \
+       .set    pop
+#endif /* __ASSEMBLER__ */
+
+
+/* We require TLS support in the tools.  */
+#define HAVE_TLS_SUPPORT               1
+#define HAVE_TLS_MODEL_ATTRIBUTE       1
+#define HAVE___THREAD                  1
+
+/* Signal that TLS support is available.  */
+#define USE_TLS        1
+
+#ifndef __ASSEMBLER__
+
+/* Get system call information.  */
+# include <sysdep.h>
+
+/* The TP points to the start of the thread blocks.  */
+# define TLS_DTV_AT_TP 1
+
+/* Get the thread descriptor definition.  */
+#include <../../descr.h>
+
+typedef struct
+{
+  dtv_t *dtv;
+  void *private;
+} tcbhead_t;
+
+/* This is the size of the initial TCB.  Because our TCB is before the thread
+   pointer, we don't need this.  */
+# define TLS_INIT_TCB_SIZE     0
+
+/* Alignment requirements for the initial TCB.  */
+# define TLS_INIT_TCB_ALIGN    __alignof__ (struct pthread)
+
+/* This is the size of the TCB.  Because our TCB is before the thread
+   pointer, we don't need this.  */
+# define TLS_TCB_SIZE          0
+
+/* Alignment requirements for the TCB.  */
+# define TLS_TCB_ALIGN         __alignof__ (struct pthread)
+
+/* This is the size we need before TCB - actually, it includes the TCB.  */
+# define TLS_PRE_TCB_SIZE \
+  (sizeof (struct pthread)                                                   \
+   + ((sizeof (tcbhead_t) + TLS_TCB_ALIGN - 1) & ~(TLS_TCB_ALIGN - 1)))
+
+/* The thread pointer (in hardware register $29) points to the end of
+   the TCB + 0x7000, as for PowerPC.  The pthread_descr structure is
+   immediately in front of the TCB.  */
+# define TLS_TCB_OFFSET        0x7000
+
+/* Install the dtv pointer.  The pointer passed is to the element with
+   index -1 which contain the length.  */
+# define INSTALL_DTV(tcbp, dtvp) \
+  (((tcbhead_t *) (tcbp))[-1].dtv = (dtvp) + 1)
+
+/* Install new dtv for current thread.  */
+# define INSTALL_NEW_DTV(dtv) \
+  (THREAD_DTV() = (dtv))
+
+/* Return dtv of given thread descriptor.  */
+# define GET_DTV(tcbp) \
+  (((tcbhead_t *) (tcbp))[-1].dtv)
+
+/* Code to initially initialize the thread pointer.  This might need
+   special attention since 'errno' is not yet available and if the
+   operation can cause a failure 'errno' must not be touched.  */
+# define TLS_INIT_TP(tcbp, secondcall) \
+  ({ INTERNAL_SYSCALL_DECL (err);                                      \
+     long result_var;                                                  \
+     result_var = INTERNAL_SYSCALL (set_thread_area, err, 1,           \
+                                   (char *) (tcbp) + TLS_TCB_OFFSET);  \
+     INTERNAL_SYSCALL_ERROR_P (result_var, err)                                \
+       ? "unknown error" : NULL; })
+
+/* Return the address of the dtv for the current thread.  */
+# define THREAD_DTV() \
+  (((tcbhead_t *) (READ_THREAD_POINTER () - TLS_TCB_OFFSET))[-1].dtv)
+
+/* Return the thread descriptor for the current thread.  */
+# define THREAD_SELF \
+ ((struct pthread *) (READ_THREAD_POINTER ()                        \
+                     - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE))
+
+/* Magic for libthread_db to know how to do THREAD_SELF.  */
+# define DB_THREAD_SELF \
+  CONST_THREAD_AREA (32, TLS_TCB_OFFSET + TLS_PRE_TCB_SIZE)
+
+/* Access to data in the thread descriptor is easy.  */
+# define THREAD_GETMEM(descr, member) \
+  descr->member
+# define THREAD_GETMEM_NC(descr, member, idx) \
+  descr->member[idx]
+# define THREAD_SETMEM(descr, member, value) \
+  descr->member = (value)
+# define THREAD_SETMEM_NC(descr, member, idx, value) \
+  descr->member[idx] = (value)
+
+/* l_tls_offset == 0 is perfectly valid on MIPS, so we have to use some
+   different value to mean unset l_tls_offset.  */
+# define NO_TLS_OFFSET         -1
+/* Get and set the global scope generation counter in struct pthread.  */
+#define THREAD_GSCOPE_FLAG_UNUSED 0
+#define THREAD_GSCOPE_FLAG_USED   1
+#define THREAD_GSCOPE_FLAG_WAIT   2
+#define THREAD_GSCOPE_RESET_FLAG() \
+  do                                                                        \
+    { int __res                                                                     \
+       = atomic_exchange_rel (&THREAD_SELF->header.gscope_flag,             \
+                              THREAD_GSCOPE_FLAG_UNUSED);                   \
+      if (__res == THREAD_GSCOPE_FLAG_WAIT)                                 \
+       lll_futex_wake (&THREAD_SELF->header.gscope_flag, 1, LLL_PRIVATE);   \
+    }                                                                       \
+  while (0)
+#define THREAD_GSCOPE_SET_FLAG() \
+  do                                                                        \
+    {                                                                       \
+      THREAD_SELF->header.gscope_flag = THREAD_GSCOPE_FLAG_USED;            \
+      atomic_write_barrier ();                                              \
+    }                                                                       \
+  while (0)
+#define THREAD_GSCOPE_WAIT() \
+  GL(dl_wait_lookup_done) ()
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* tls.h */
diff --git a/libpthread/nptl/sysdeps/powerpc/Makefile b/libpthread/nptl/sysdeps/powerpc/Makefile
new file mode 100644 (file)
index 0000000..3af2456
--- /dev/null
@@ -0,0 +1,21 @@
+# Copyright (C) 2003 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+
+# The GNU C Library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+
+# The GNU C Library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public
+# License along with the GNU C Library; if not, write to the Free
+# Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+# 02111-1307 USA.
+
+ifeq ($(subdir),csu)
+gen-as-const-headers += tcb-offsets.sym
+endif
diff --git a/libpthread/nptl/sysdeps/powerpc/dl-tls.h b/libpthread/nptl/sysdeps/powerpc/dl-tls.h
new file mode 100644 (file)
index 0000000..957d4b4
--- /dev/null
@@ -0,0 +1,49 @@
+/* Thread-local storage handling in the ELF dynamic linker.  PowerPC version.
+   Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+
+/* Type used for the representation of TLS information in the TOC.  */
+typedef struct
+{
+  unsigned long int ti_module;
+  unsigned long int ti_offset;
+} tls_index;
+
+/* The thread pointer points 0x7000 past the first static TLS block.  */
+#define TLS_TP_OFFSET          0x7000
+
+/* Dynamic thread vector pointers point 0x8000 past the start of each
+   TLS block.  */
+#define TLS_DTV_OFFSET         0x8000
+
+/* Compute the value for a @tprel reloc.  */
+#define TLS_TPREL_VALUE(sym_map, sym, reloc) \
+  ((sym_map)->l_tls_offset + (sym)->st_value + (reloc)->r_addend \
+   - TLS_TP_OFFSET)
+
+/* Compute the value for a @dtprel reloc.  */
+#define TLS_DTPREL_VALUE(sym, reloc) \
+  ((sym)->st_value + (reloc)->r_addend - TLS_DTV_OFFSET)
+
+#ifdef SHARED
+extern void *__tls_get_addr (tls_index *ti);
+
+# define GET_ADDR_OFFSET       (ti->ti_offset + TLS_DTV_OFFSET)
+# define __TLS_GET_ADDR(__ti)  (__tls_get_addr (__ti) - TLS_DTV_OFFSET)
+#endif
diff --git a/libpthread/nptl/sysdeps/powerpc/jmpbuf-unwind.h b/libpthread/nptl/sysdeps/powerpc/jmpbuf-unwind.h
new file mode 100644 (file)
index 0000000..0b81716
--- /dev/null
@@ -0,0 +1,31 @@
+/* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <setjmp.h>
+#include <stdint.h>
+#include <unwind.h>
+
+#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \
+  _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj)
+
+#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \
+  ((uintptr_t) (_address) - (_adj) < (uintptr_t) (_jmpbuf)[JB_GPR1] - (_adj))
+
+/* We use the normal lobngjmp for unwinding.  */
+#define __libc_unwind_longjmp(buf, val) __libc_longjmp (buf, val)
diff --git a/libpthread/nptl/sysdeps/powerpc/pthread_spin_lock.c b/libpthread/nptl/sysdeps/powerpc/pthread_spin_lock.c
new file mode 100644 (file)
index 0000000..e2293fd
--- /dev/null
@@ -0,0 +1,45 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+
+int
+pthread_spin_lock (lock)
+     pthread_spinlock_t *lock;
+{
+  unsigned int __tmp;
+
+  asm volatile (
+       "1:     lwarx   %0,0,%1\n"
+       "       cmpwi   0,%0,0\n"
+       "       bne-    2f\n"
+       "       stwcx.  %2,0,%1\n"
+       "       bne-    2f\n"
+       "       isync\n"
+       "       .subsection 1\n"
+       "2:     lwzx    %0,0,%1\n"
+       "       cmpwi   0,%0,0\n"
+       "       bne     2b\n"
+       "       b       1b\n"
+       "       .previous"
+       : "=&r" (__tmp)
+       : "r" (lock), "r" (1)
+       : "cr0", "memory");
+  return 0;
+}
diff --git a/libpthread/nptl/sysdeps/powerpc/pthread_spin_trylock.c b/libpthread/nptl/sysdeps/powerpc/pthread_spin_trylock.c
new file mode 100644 (file)
index 0000000..d8e1dbc
--- /dev/null
@@ -0,0 +1,43 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include "pthreadP.h"
+
+int
+pthread_spin_trylock (lock)
+     pthread_spinlock_t *lock;
+{
+  unsigned int old;
+  int err = EBUSY;
+
+  asm ("1:     lwarx   %0,0,%2\n"
+       "       cmpwi   0,%0,0\n"
+       "       bne     2f\n"
+       "       stwcx.  %3,0,%2\n"
+       "       bne-    1b\n"
+       "       li      %1,0\n"
+       "       isync\n"
+       "2:     "
+       : "=&r" (old), "=&r" (err)
+       : "r" (lock), "r" (1), "1" (err)
+       : "cr0", "memory");
+
+  return err;
+}
diff --git a/libpthread/nptl/sysdeps/powerpc/pthreaddef.h b/libpthread/nptl/sysdeps/powerpc/pthreaddef.h
new file mode 100644 (file)
index 0000000..342c15c
--- /dev/null
@@ -0,0 +1,41 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* Default stack size.  */
+#define ARCH_STACK_DEFAULT_SIZE        (4 * 1024 * 1024)
+
+/* Required stack pointer alignment at beginning.  The ABI requires 16
+   bytes (for both 32-bit and 64-bit PowerPC).  */
+#define STACK_ALIGN            16
+
+/* Minimal stack size after allocating thread descriptor and guard size.  */
+#define MINIMAL_REST_STACK     4096
+
+/* Alignment requirement for TCB.  */
+#define TCB_ALIGNMENT          16
+
+
+/* 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) \
+  INLINE_SYSCALL (exit, 1, (val))
diff --git a/libpthread/nptl/sysdeps/powerpc/tcb-offsets.sym b/libpthread/nptl/sysdeps/powerpc/tcb-offsets.sym
new file mode 100644 (file)
index 0000000..8ac133d
--- /dev/null
@@ -0,0 +1,20 @@
+#include <sysdep.h>
+#include <tls.h>
+
+--
+
+-- Abuse tls.h macros to derive offsets relative to the thread register.
+# undef __thread_register
+# define __thread_register     ((void *) 0)
+# define thread_offsetof(mem)  ((ptrdiff_t) THREAD_SELF + offsetof (struct pthread, mem))
+
+
+#if TLS_MULTIPLE_THREADS_IN_TCB
+MULTIPLE_THREADS_OFFSET                thread_offsetof (header.multiple_threads)
+#endif
+PID                            thread_offsetof (pid)
+TID                            thread_offsetof (tid)
+POINTER_GUARD                  (offsetof (tcbhead_t, pointer_guard) - TLS_TCB_OFFSET - sizeof (tcbhead_t))
+#ifndef __ASSUME_PRIVATE_FUTEX
+PRIVATE_FUTEX_OFFSET           thread_offsetof (header.private_futex)
+#endif
diff --git a/libpthread/nptl/sysdeps/powerpc/tls.h b/libpthread/nptl/sysdeps/powerpc/tls.h
new file mode 100644 (file)
index 0000000..ce5559e
--- /dev/null
@@ -0,0 +1,209 @@
+/* Definition for thread-local data handling.  NPTL/PowerPC version.
+   Copyright (C) 2003, 2005, 2006, 2007 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 <stdbool.h>
+# include <stddef.h>
+# include <stdint.h>
+
+/* Type for the dtv.  */
+typedef union dtv
+{
+  size_t counter;
+  struct
+  {
+    void *val;
+    bool is_static;
+  } pointer;
+} dtv_t;
+
+#else /* __ASSEMBLER__ */
+# include <tcb-offsets.h>
+#endif /* __ASSEMBLER__ */
+
+
+/* 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
+
+#ifndef __ASSEMBLER__
+
+/* Get system call information.  */
+# include <sysdep.h>
+
+/* The TP points to the start of the thread blocks.  */
+# define TLS_DTV_AT_TP 1
+
+/* We use the multiple_threads field in the pthread struct */
+#define TLS_MULTIPLE_THREADS_IN_TCB    1
+
+/* Get the thread descriptor definition.  */
+# include <nptl/descr.h>
+
+/* The stack_guard is accessed directly by GCC -fstack-protector code,
+   so it is a part of public ABI.  The dtv and pointer_guard fields
+   are private.  */
+typedef struct
+{
+  uintptr_t pointer_guard;
+  uintptr_t stack_guard;
+  dtv_t *dtv;
+} tcbhead_t;
+
+/* This is the size of the initial TCB.  */
+# define TLS_INIT_TCB_SIZE     0
+
+/* Alignment requirements for the initial TCB.  */
+# define TLS_INIT_TCB_ALIGN    __alignof__ (struct pthread)
+
+/* This is the size of the TCB.  */
+# define TLS_TCB_SIZE          0
+
+/* Alignment requirements for the TCB.  */
+# define TLS_TCB_ALIGN         __alignof__ (struct pthread)
+
+/* This is the size we need before TCB.  */
+# define TLS_PRE_TCB_SIZE \
+  (sizeof (struct pthread)                                                   \
+   + ((sizeof (tcbhead_t) + TLS_TCB_ALIGN - 1) & ~(TLS_TCB_ALIGN - 1)))
+
+# ifndef __powerpc64__
+/* Register r2 (tp) is reserved by the ABI as "thread pointer". */
+register void *__thread_register __asm__ ("r2");
+#  define PT_THREAD_POINTER PT_R2
+# else
+/* Register r13 (tp) is reserved by the ABI as "thread pointer". */
+register void *__thread_register __asm__ ("r13");
+#  define PT_THREAD_POINTER PT_R13
+# endif
+
+/* The following assumes that TP (R2 or R13) points to the end of the
+   TCB + 0x7000 (per the ABI).  This implies that TCB address is
+   TP - 0x7000.  As we define TLS_DTV_AT_TP we can
+   assume that the pthread struct is allocated immediately ahead of the
+   TCB.  This implies that the pthread_descr address is
+   TP - (TLS_PRE_TCB_SIZE + 0x7000).  */
+# define TLS_TCB_OFFSET        0x7000
+
+/* Install the dtv pointer.  The pointer passed is to the element with
+   index -1 which contain the length.  */
+# define INSTALL_DTV(tcbp, dtvp) \
+  ((tcbhead_t *) (tcbp))[-1].dtv = dtvp + 1
+
+/* Install new dtv for current thread.  */
+# define INSTALL_NEW_DTV(dtv) (THREAD_DTV() = (dtv))
+
+/* Return dtv of given thread descriptor.  */
+# define GET_DTV(tcbp) (((tcbhead_t *) (tcbp))[-1].dtv)
+
+/* Code to initially initialize the thread pointer.  This might need
+   special attention since 'errno' is not yet available and if the
+   operation can cause a failure 'errno' must not be touched.  */
+# define TLS_INIT_TP(tcbp, secondcall) \
+    (__thread_register = (void *) (tcbp) + TLS_TCB_OFFSET, NULL)
+
+/* Return the address of the dtv for the current thread.  */
+# define THREAD_DTV() \
+    (((tcbhead_t *) (__thread_register - TLS_TCB_OFFSET))[-1].dtv)
+
+/* Return the thread descriptor for the current thread.  */
+# define THREAD_SELF \
+    ((struct pthread *) (__thread_register \
+                        - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE))
+
+/* Magic for libthread_db to know how to do THREAD_SELF.  */
+# define DB_THREAD_SELF                                                              \
+  REGISTER (32, 32, PT_THREAD_POINTER * 4,                                   \
+           - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE)                              \
+  REGISTER (64, 64, PT_THREAD_POINTER * 8,                                   \
+           - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE)
+
+/* Read member of the thread descriptor directly.  */
+# define THREAD_GETMEM(descr, member) ((void)(descr), (THREAD_SELF)->member)
+
+/* Same as THREAD_GETMEM, but the member offset can be non-constant.  */
+# define THREAD_GETMEM_NC(descr, member, idx) \
+    ((void)(descr), (THREAD_SELF)->member[idx])
+
+/* Set member of the thread descriptor directly.  */
+# define THREAD_SETMEM(descr, member, value) \
+    ((void)(descr), (THREAD_SELF)->member = (value))
+
+/* Same as THREAD_SETMEM, but the member offset can be non-constant.  */
+# define THREAD_SETMEM_NC(descr, member, idx, value) \
+    ((void)(descr), (THREAD_SELF)->member[idx] = (value))
+
+/* Set the stack guard field in TCB head.  */
+# define THREAD_SET_STACK_GUARD(value) \
+    (((tcbhead_t *) ((char *) __thread_register                                      \
+                    - TLS_TCB_OFFSET))[-1].stack_guard = (value))
+# define THREAD_COPY_STACK_GUARD(descr) \
+    (((tcbhead_t *) ((char *) (descr)                                        \
+                    + TLS_PRE_TCB_SIZE))[-1].stack_guard                     \
+     = ((tcbhead_t *) ((char *) __thread_register                            \
+                      - TLS_TCB_OFFSET))[-1].stack_guard)
+
+/* Set the stack guard field in TCB head.  */
+# define THREAD_GET_POINTER_GUARD() \
+    (((tcbhead_t *) ((char *) __thread_register                                      \
+                    - TLS_TCB_OFFSET))[-1].pointer_guard)
+# define THREAD_SET_POINTER_GUARD(value) \
+    (THREAD_GET_POINTER_GUARD () = (value))
+# define THREAD_COPY_POINTER_GUARD(descr) \
+    (((tcbhead_t *) ((char *) (descr)                                        \
+                    + TLS_PRE_TCB_SIZE))[-1].pointer_guard                   \
+     = THREAD_GET_POINTER_GUARD())
+
+/* l_tls_offset == 0 is perfectly valid on PPC, so we have to use some
+   different value to mean unset l_tls_offset.  */
+# define NO_TLS_OFFSET         -1
+
+/* Get and set the global scope generation counter in struct pthread.  */
+#define THREAD_GSCOPE_FLAG_UNUSED 0
+#define THREAD_GSCOPE_FLAG_USED   1
+#define THREAD_GSCOPE_FLAG_WAIT   2
+#define THREAD_GSCOPE_RESET_FLAG() \
+  do                                                                        \
+    { int __res                                                                     \
+       = atomic_exchange_rel (&THREAD_SELF->header.gscope_flag,             \
+                              THREAD_GSCOPE_FLAG_UNUSED);                   \
+      if (__res == THREAD_GSCOPE_FLAG_WAIT)                                 \
+       lll_futex_wake (&THREAD_SELF->header.gscope_flag, 1, LLL_PRIVATE);   \
+    }                                                                       \
+  while (0)
+#define THREAD_GSCOPE_SET_FLAG() \
+  do                                                                        \
+    {                                                                       \
+      THREAD_SELF->header.gscope_flag = THREAD_GSCOPE_FLAG_USED;            \
+      atomic_write_barrier ();                                              \
+    }                                                                       \
+  while (0)
+#define THREAD_GSCOPE_WAIT() \
+  GL(dl_wait_lookup_done) ()
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* tls.h */
diff --git a/libpthread/nptl/sysdeps/pthread/Makefile b/libpthread/nptl/sysdeps/pthread/Makefile
new file mode 100644 (file)
index 0000000..a30ded5
--- /dev/null
@@ -0,0 +1,13 @@
+# Makefile for uClibc NPTL
+#
+# Copyright (C) 2005 Steven J. Hill <sjhill@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+top_srcdir=../../../../
+top_builddir=../../../../
+all: objs
+include $(top_builddir)Rules.mak
+include Makefile.in
+include $(top_srcdir)Makerules
diff --git a/libpthread/nptl/sysdeps/pthread/Makefile.in b/libpthread/nptl/sysdeps/pthread/Makefile.in
new file mode 100644 (file)
index 0000000..2a94e43
--- /dev/null
@@ -0,0 +1,163 @@
+# Makefile for uClibc NPTL
+#
+# Copyright (C) 2005-2006 Steven J. Hill <sjhill@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+#
+# NOTE: glibc puts flockfile.c, ftrylockfile.c, funlockfile.c, and
+#       pt-longjmp.c in libc and libpthread. For uClibc, they are
+#       in libc only.
+#
+libpthread_CSRC = pthread_barrier_init.c pthread_barrier_destroy.c    \
+                 pthread_barrier_wait.c pthread_cond_broadcast.c       \
+                 pthread_cond_signal.c pthread_cond_timedwait.c        \
+                 pthread_cond_wait.c pthread_rwlock_rdlock.c           \
+                 pthread_rwlock_timedrdlock.c                          \
+                 pthread_rwlock_timedwrlock.c pthread_rwlock_unlock.c  \
+                 pthread_rwlock_wrlock.c pthread_sigmask.c             \
+                 pthread_spin_destroy.c pthread_spin_init.c            \
+                 pthread_spin_unlock.c pt-sigfillset.c \
+                 pt-longjmp.c tpp.c
+
+
+ifeq ($(TARGET_ARCH),i386)
+X86_PTHREAD_EXCLUDE_LIST = pthread_spin_unlock.c pthread_spin_init.c \
+               pthread_barrier_wait.c pthread_cond_broadcast.c \
+               pthread_cond_signal.c pthread_rwlock_timedrdlock.c      \
+               pthread_rwlock_timedwrlock.c pthread_rwlock_unlock.c pthread_rwlock_wrlock.c \
+               pthread_rwlock_rdlock.c
+
+libpthread_CSRC := $(filter-out $(X86_PTHREAD_EXCLUDE_LIST),$(libpthread_CSRC))
+endif
+
+ifeq ($(TARGET_ARCH),sh)
+SH_PTHREAD_EXCLUDE_LIST = pthread_spin_unlock.c pthread_spin_init.c \
+               pthread_rwlock_wrlock.c pthread_rwlock_rdlock.c \
+               pthread_rwlock_unlock.c pt-longjmp.c \
+               pthread_barrier_wait.c pthread_cond_broadcast.c \
+               pthread_cond_signal.c \
+               pthread_rwlock_timedrdlock.c \
+               pthread_rwlock_timedwrlock.c
+
+libpthread_CSRC := $(filter-out $(SH_PTHREAD_EXCLUDE_LIST),$(libpthread_CSRC))
+endif
+
+ifeq ($(TARGET_ARCH),sparc)
+SPARC_PTHREAD_EXCLUDE_LIST = pthread_barrier_init.c pthread_barrier_wait.c \
+               pthread_barrier_destroy.c
+
+libpthread_CSRC := $(filter-out $(SPARC_PTHREAD_EXCLUDE_LIST),$(libpthread_CSRC))
+endif
+
+ifeq ($(TARGET_ARCH),x86_64)
+X64_PTHREAD_EXCLUDE_LIST = pthread_spin_unlock.c pthread_spin_init.c \
+               pthread_barrier_wait.c pthread_cond_broadcast.c \
+               pthread_cond_signal.c pthread_rwlock_timedrdlock.c      \
+               pthread_rwlock_timedwrlock.c pthread_rwlock_unlock.c pthread_rwlock_wrlock.c \
+               pthread_rwlock_rdlock.c pthread_cond_timedwait.c pthread_cond_wait.c
+
+libpthread_CSRC := $(filter-out $(X64_PTHREAD_EXCLUDE_LIST),$(libpthread_CSRC))
+endif
+
+
+
+CFLAGS-pt-common = -DNOT_IN_libc=1 $(SSP_ALL_CFLAGS)
+CFLAGS-pthread_barrier_init.c = $(CFLAGS-pt-common)    -DIS_IN_libpthread=1
+CFLAGS-pthread_barrier_destroy.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1
+CFLAGS-pthread_barrier_wait.c = -D_GNU_SOURCE $(CFLAGS-pt-common)      \
+                               -DIS_IN_libpthread=1
+CFLAGS-pthread_cond_broadcast.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1
+CFLAGS-pthread_cond_signal.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1
+CFLAGS-pthread_cond_timedwait.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1
+CFLAGS-pthread_cond_wait.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1
+CFLAGS-pthread_rwlock_rdlock.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1
+CFLAGS-pthread_rwlock_timedrdlock.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1
+CFLAGS-pthread_rwlock_timedwrlock.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1
+CFLAGS-pthread_rwlock_unlock.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1
+CFLAGS-pthread_rwlock_wrlock.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1
+CFLAGS-pthread_sigmask.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1
+CFLAGS-pthread_spin_destroy.c = -D_GNU_SOURCE $(CFLAGS-pt-common)      \
+                               -DIS_IN_libpthread=1
+CFLAGS-pthread_spin_init.c = -D_GNU_SOURCE $(CFLAGS-pt-common)         \
+                            -DIS_IN_libpthread=1
+CFLAGS-pthread_spin_unlock.c = -D_GNU_SOURCE $(CFLAGS-pt-common)       \
+                              -DIS_IN_libpthread=1
+CFLAGS-pt-sigaction.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1       \
+                    -I$(top_srcdir)libc/sysdeps/linux/$(TARGET_ARCH)   \
+                    -I$(top_srcdir)libc/signal
+CFLAGS-pt-sigfillset.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1      \
+                     -I$(top_srcdir)libc/signal
+CFLAGS-pt-sigprocmask.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1     \
+                      -I$(top_srcdir)libc/sysdeps/linux/common
+CFLAGS-unwind-forcedunwind.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1 -fexceptions -fasynchronous-unwind-tables
+CFLAGS-librt-cancellation.c = -DIS_IN_librt=1 $(CFLAGS-pt-common)      \
+                             -fexceptions -fasynchronous-unwind-tables
+CFLAGS-rt-unwind-resume.c = -DIS_IN_librt=1 $(CFLAGS-pt-common)                \
+                           -fexceptions -fasynchronous-unwind-tables
+CFLAGS-tpp.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1
+
+#CFLAGS:=$(CFLAGS:-O1=-O2)
+
+pthread_DIR := $(top_srcdir)libpthread/nptl/sysdeps/pthread
+pthread_OUT := $(top_builddir)libpthread/nptl/sysdeps/pthread
+
+pthread_SRC = $(patsubst %.c, $(pthread_DIR)/%.c, $(libpthread_CSRC))
+pthread_OBJ = $(patsubst %.c, $(pthread_OUT)/%.o, $(libpthread_CSRC))
+
+ifeq ($(DOPIC),y)
+libpthread-a-y += $(pthread_OBJ:.o=.os)
+else
+libpthread-a-y += $(pthread_OBJ)
+endif
+libpthread-so-y += $(pthread_OBJ:.o=.oS)
+libpthread-so-y += $(pthread_OUT)/pt-sigaction.oS $(pthread_OUT)/pt-sigprocmask.oS \
+                                       $(pthread_OUT)/unwind-forcedunwind.oS
+
+CFLAGS-sigaction.c = -I$(top_srcdir)libc/signal
+libc-y += $(pthread_OUT)/sigaction.o
+
+librt-a-y += $(pthread_OUT)/librt-cancellation.o
+librt-so-y += $(pthread_OUT)/librt-cancellation.oS             \
+             $(pthread_OUT)/rt-unwind-resume.oS
+
+ifeq ($(UCLIBC_CTOR_DTOR),y)
+CFLAGS-pt-initfini.c = -S -g0 -fPIC -fno-inline-functions      \
+                      $(call check_gcc,-fno-unit-at-a-time,)   \
+                      -finhibit-size-directive                 \
+                      $(patsubst -f%,-fno-%,$(call check_gcc,-fexceptions,))
+ASFLAGS-crti.S = -g0
+ASFLAGS-crtn.S = -g0
+
+$(pthread_OUT)/pt-initfini.s: $(pthread_DIR)/pt-initfini.c
+       $(compile.c)
+       $(do_sed) '/@TESTS_BEGIN/,/@TESTS_END/p' $< | \
+               $(AWK) -f $(pthread_DIR)/defs.awk > $(pthread_OUT)/defs.h
+
+$(pthread_OUT)/crti.S: $(pthread_OUT)/pt-initfini.s
+       $(do_sed) -e '1,/@HEADER_ENDS/p' \
+              -e '/@_.*_PROLOG_BEGINS/,/@_.*_PROLOG_ENDS/p' \
+              -e '/@TRAILER_BEGINS/,$$p' $< > $@
+
+$(pthread_OUT)/crtn.S: $(pthread_OUT)/pt-initfini.s
+       $(do_sed) -e '1,/@HEADER_ENDS/p' \
+              -e '/@_.*_EPILOG_BEGINS/,/@_.*_EPILOG_ENDS/p' \
+              -e '/@TRAILER_BEGINS/,$$p' $< > $@
+endif
+
+$(pthread_DIR)/pt-sigaction.c:
+       $(LN) -s sigaction.c $@
+
+$(pthread_DIR)/pt-sigfillset.c:
+       $(LN) -s sigfillset.c $@
+
+$(pthread_DIR)/pt-sigprocmask.c:
+       $(LN) -s sigprocmask.c $@
+
+objclean-y += nptl_pthread_clean
+
+nptl_pthread_clean:
+       $(do_rm) $(addprefix $(pthread_OUT)/*., o os oS s S) $(pthread_OUT)/defs.h \
+             $(pthread_DIR)/pt-sigaction.c $(pthread_DIR)/pt-sigfillset.c \
+             $(pthread_DIR)/pt-sigprocmask.c
diff --git a/libpthread/nptl/sysdeps/pthread/allocalim.h b/libpthread/nptl/sysdeps/pthread/allocalim.h
new file mode 100644 (file)
index 0000000..f13c3a3
--- /dev/null
@@ -0,0 +1,30 @@
+/* Determine whether block of given size can be allocated on the stack or not.
+   Copyright (C) 2002, 2006 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <alloca.h>
+#include <limits.h>
+
+
+extern int
+__always_inline
+__libc_use_alloca (size_t size)
+{
+  return (__builtin_expect (size <= PTHREAD_STACK_MIN / 4, 1)
+         || __libc_alloca_cutoff (size));
+}
diff --git a/libpthread/nptl/sysdeps/pthread/bits/libc-lock.h b/libpthread/nptl/sysdeps/pthread/bits/libc-lock.h
new file mode 100644 (file)
index 0000000..3268aa5
--- /dev/null
@@ -0,0 +1,586 @@
+/* libc-internal interface for mutex locks.  NPTL version.
+   Copyright (C) 1996-2003, 2005, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef _BITS_LIBC_LOCK_H
+#define _BITS_LIBC_LOCK_H 1
+
+#include <pthread.h>
+#define __need_NULL
+#include <stddef.h>
+
+
+/* Fortunately Linux now has a mean to do locking which is realtime
+   safe without the aid of the thread library.  We also need no fancy
+   options like error checking mutexes etc.  We only need simple
+   locks, maybe recursive.  This can be easily and cheaply implemented
+   using futexes.  We will use them everywhere except in ld.so since
+   ld.so might be used on old kernels with a different libc.so.  */
+#ifdef _LIBC
+# include <lowlevellock.h>
+# include <tls.h>
+# include <pthread-functions.h>
+#endif
+
+/* Mutex type.  */
+#if defined _LIBC || defined _IO_MTSAFE_IO
+# if (defined NOT_IN_libc && !defined IS_IN_libpthread) || !defined _LIBC
+typedef pthread_mutex_t __libc_lock_t;
+typedef struct { pthread_mutex_t mutex; } __libc_lock_recursive_t;
+# else
+typedef int __libc_lock_t;
+typedef struct { int lock; int cnt; void *owner; } __libc_lock_recursive_t;
+# endif
+typedef struct { pthread_mutex_t mutex; } __rtld_lock_recursive_t;
+# ifdef __USE_UNIX98
+typedef pthread_rwlock_t __libc_rwlock_t;
+# else
+typedef struct __libc_rwlock_opaque__ __libc_rwlock_t;
+# endif
+#else
+typedef struct __libc_lock_opaque__ __libc_lock_t;
+typedef struct __libc_lock_recursive_opaque__ __libc_lock_recursive_t;
+typedef struct __libc_rwlock_opaque__ __libc_rwlock_t;
+#endif
+
+/* Type for key to thread-specific data.  */
+typedef pthread_key_t __libc_key_t;
+
+# define __libc_freeres_fn_section \
+      __attribute__ ((section ("__libc_freeres_fn")))
+
+
+/* Define a lock variable NAME with storage class CLASS.  The lock must be
+   initialized with __libc_lock_init before it can be used (or define it
+   with __libc_lock_define_initialized, below).  Use `extern' for CLASS to
+   declare a lock defined in another module.  In public structure
+   definitions you must use a pointer to the lock structure (i.e., NAME
+   begins with a `*'), because its storage size will not be known outside
+   of libc.  */
+#define __libc_lock_define(CLASS,NAME) \
+  CLASS __libc_lock_t NAME;
+#define __libc_rwlock_define(CLASS,NAME) \
+  CLASS __libc_rwlock_t NAME;
+#define __libc_lock_define_recursive(CLASS,NAME) \
+  CLASS __libc_lock_recursive_t NAME;
+#define __rtld_lock_define_recursive(CLASS,NAME) \
+  CLASS __rtld_lock_recursive_t NAME;
+
+/* Define an initialized lock variable NAME with storage class CLASS.
+
+   For the C library we take a deeper look at the initializer.  For
+   this implementation all fields are initialized to zero.  Therefore
+   we don't initialize the variable which allows putting it into the
+   BSS section.  (Except on PA-RISC and other odd architectures, where
+   initialized locks must be set to one due to the lack of normal
+   atomic operations.) */
+
+#if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread)
+# if LLL_LOCK_INITIALIZER == 0
+#  define __libc_lock_define_initialized(CLASS,NAME) \
+  CLASS __libc_lock_t NAME;
+# else
+#  define __libc_lock_define_initialized(CLASS,NAME) \
+  CLASS __libc_lock_t NAME = LLL_LOCK_INITIALIZER;
+# endif
+#else
+# if __LT_SPINLOCK_INIT == 0
+#  define __libc_lock_define_initialized(CLASS,NAME) \
+  CLASS __libc_lock_t NAME;
+# else
+#  define __libc_lock_define_initialized(CLASS,NAME) \
+  CLASS __libc_lock_t NAME = PTHREAD_MUTEX_INITIALIZER;
+# endif
+#endif
+
+#define __libc_rwlock_define_initialized(CLASS,NAME) \
+  CLASS __libc_rwlock_t NAME = PTHREAD_RWLOCK_INITIALIZER;
+
+/* Define an initialized recursive lock variable NAME with storage
+   class CLASS.  */
+#if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread)
+# if LLL_LOCK_INITIALIZER == 0
+#  define __libc_lock_define_initialized_recursive(CLASS,NAME) \
+  CLASS __libc_lock_recursive_t NAME;
+# else
+#  define __libc_lock_define_initialized_recursive(CLASS,NAME) \
+  CLASS __libc_lock_recursive_t NAME = _LIBC_LOCK_RECURSIVE_INITIALIZER;
+# endif
+# define _LIBC_LOCK_RECURSIVE_INITIALIZER \
+  { LLL_LOCK_INITIALIZER, 0, NULL }
+#else
+# define __libc_lock_define_initialized_recursive(CLASS,NAME) \
+  CLASS __libc_lock_recursive_t NAME = _LIBC_LOCK_RECURSIVE_INITIALIZER;
+# define _LIBC_LOCK_RECURSIVE_INITIALIZER \
+  {PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP}
+#endif
+
+#define __rtld_lock_define_initialized_recursive(CLASS,NAME) \
+  CLASS __rtld_lock_recursive_t NAME = _RTLD_LOCK_RECURSIVE_INITIALIZER;
+#define _RTLD_LOCK_RECURSIVE_INITIALIZER \
+  {PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP}
+
+#define __rtld_lock_initialize(NAME) \
+  (void) ((NAME) = (__rtld_lock_recursive_t) _RTLD_LOCK_RECURSIVE_INITIALIZER)
+
+/* If we check for a weakly referenced symbol and then perform a
+   normal jump to it te code generated for some platforms in case of
+   PIC is unnecessarily slow.  What would happen is that the function
+   is first referenced as data and then it is called indirectly
+   through the PLT.  We can make this a direct jump.  */
+#ifdef __PIC__
+# define __libc_maybe_call(FUNC, ARGS, ELSE) \
+  (__extension__ ({ __typeof (FUNC) *_fn = (FUNC); \
+                    _fn != NULL ? (*_fn) ARGS : ELSE; }))
+#else
+# define __libc_maybe_call(FUNC, ARGS, ELSE) \
+  (FUNC != NULL ? FUNC ARGS : ELSE)
+#endif
+
+/* Call thread functions through the function pointer table.  */
+#if defined SHARED && !defined NOT_IN_libc
+# define PTFAVAIL(NAME) __libc_pthread_functions_init
+# define __libc_ptf_call(FUNC, ARGS, ELSE) \
+  (__libc_pthread_functions_init ? PTHFCT_CALL (ptr_##FUNC, ARGS) : ELSE)
+# define __libc_ptf_call_always(FUNC, ARGS) \
+  PTHFCT_CALL (ptr_##FUNC, ARGS)
+#else
+# define PTFAVAIL(NAME) (NAME != NULL)
+# define __libc_ptf_call(FUNC, ARGS, ELSE) \
+  __libc_maybe_call (FUNC, ARGS, ELSE)
+# define __libc_ptf_call_always(FUNC, ARGS) \
+  FUNC ARGS
+#endif
+
+
+/* Initialize the named lock variable, leaving it in a consistent, unlocked
+   state.  */
+#if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread)
+# define __libc_lock_init(NAME) ((NAME) = LLL_LOCK_INITIALIZER, 0)
+#else
+# define __libc_lock_init(NAME) \
+  __libc_maybe_call (__pthread_mutex_init, (&(NAME), NULL), 0)
+#endif
+#if defined SHARED && !defined NOT_IN_libc
+/* ((NAME) = (__libc_rwlock_t) PTHREAD_RWLOCK_INITIALIZER, 0) is
+   inefficient.  */
+# define __libc_rwlock_init(NAME) \
+  (__builtin_memset (&(NAME), '\0', sizeof (NAME)), 0)
+#else
+# define __libc_rwlock_init(NAME) \
+  __libc_maybe_call (__pthread_rwlock_init, (&(NAME), NULL), 0)
+#endif
+
+/* Same as last but this time we initialize a recursive mutex.  */
+#if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread)
+# define __libc_lock_init_recursive(NAME) \
+  ((NAME) = (__libc_lock_recursive_t) _LIBC_LOCK_RECURSIVE_INITIALIZER, 0)
+#else
+# define __libc_lock_init_recursive(NAME) \
+  do {                                                                       \
+    if (__pthread_mutex_init != NULL)                                        \
+      {                                                                              \
+       pthread_mutexattr_t __attr;                                           \
+       __pthread_mutexattr_init (&__attr);                                   \
+       __pthread_mutexattr_settype (&__attr, PTHREAD_MUTEX_RECURSIVE_NP);    \
+       __pthread_mutex_init (&(NAME).mutex, &__attr);                        \
+       __pthread_mutexattr_destroy (&__attr);                                \
+      }                                                                              \
+  } while (0)
+#endif
+
+#define __rtld_lock_init_recursive(NAME) \
+  do {                                                                       \
+    if (__pthread_mutex_init != NULL)                                        \
+      {                                                                              \
+       pthread_mutexattr_t __attr;                                           \
+       __pthread_mutexattr_init (&__attr);                                   \
+       __pthread_mutexattr_settype (&__attr, PTHREAD_MUTEX_RECURSIVE_NP);    \
+       __pthread_mutex_init (&(NAME).mutex, &__attr);                        \
+       __pthread_mutexattr_destroy (&__attr);                                \
+      }                                                                              \
+  } while (0)
+
+/* Finalize the named lock variable, which must be locked.  It cannot be
+   used again until __libc_lock_init is called again on it.  This must be
+   called on a lock variable before the containing storage is reused.  */
+#if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread)
+# define __libc_lock_fini(NAME) ((void) 0)
+#else
+# define __libc_lock_fini(NAME) \
+  __libc_maybe_call (__pthread_mutex_destroy, (&(NAME)), 0)
+#endif
+#if defined SHARED && !defined NOT_IN_libc
+# define __libc_rwlock_fini(NAME) ((void) 0)
+#else
+# define __libc_rwlock_fini(NAME) \
+  __libc_maybe_call (__pthread_rwlock_destroy, (&(NAME)), 0)
+#endif
+
+/* Finalize recursive named lock.  */
+#if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread)
+# define __libc_lock_fini_recursive(NAME) ((void) 0)
+#else
+# define __libc_lock_fini_recursive(NAME) \
+  __libc_maybe_call (__pthread_mutex_destroy, (&(NAME)), 0)
+#endif
+
+/* Lock the named lock variable.  */
+#if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread)
+# define __libc_lock_lock(NAME) \
+  ({ lll_lock (NAME, LLL_PRIVATE); 0; })
+#else
+# define __libc_lock_lock(NAME) \
+  __libc_maybe_call (__pthread_mutex_lock, (&(NAME)), 0)
+#endif
+#define __libc_rwlock_rdlock(NAME) \
+  __libc_ptf_call (__pthread_rwlock_rdlock, (&(NAME)), 0)
+#define __libc_rwlock_wrlock(NAME) \
+  __libc_ptf_call (__pthread_rwlock_wrlock, (&(NAME)), 0)
+
+/* Lock the recursive named lock variable.  */
+#if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread)
+# define __libc_lock_lock_recursive(NAME) \
+  do {                                                                       \
+    void *self = THREAD_SELF;                                                \
+    if ((NAME).owner != self)                                                \
+      {                                                                              \
+       lll_lock ((NAME).lock, LLL_PRIVATE);                                  \
+       (NAME).owner = self;                                                  \
+      }                                                                              \
+    ++(NAME).cnt;                                                            \
+  } while (0)
+#else
+# define __libc_lock_lock_recursive(NAME) \
+  __libc_maybe_call (__pthread_mutex_lock, (&(NAME).mutex), 0)
+#endif
+
+/* Try to lock the named lock variable.  */
+#if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread)
+# define __libc_lock_trylock(NAME) \
+  lll_trylock (NAME)
+#else
+# define __libc_lock_trylock(NAME) \
+  __libc_maybe_call (__pthread_mutex_trylock, (&(NAME)), 0)
+#endif
+#define __libc_rwlock_tryrdlock(NAME) \
+  __libc_maybe_call (__pthread_rwlock_tryrdlock, (&(NAME)), 0)
+#define __libc_rwlock_trywrlock(NAME) \
+  __libc_maybe_call (__pthread_rwlock_trywrlock, (&(NAME)), 0)
+
+/* Try to lock the recursive named lock variable.  */
+#if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread)
+# define __libc_lock_trylock_recursive(NAME) \
+  ({                                                                         \
+    int result = 0;                                                          \
+    void *self = THREAD_SELF;                                                \
+    if ((NAME).owner != self)                                                \
+      {                                                                              \
+       if (lll_trylock ((NAME).lock) == 0)                                   \
+         {                                                                   \
+           (NAME).owner = self;                                              \
+           (NAME).cnt = 1;                                                   \
+         }                                                                   \
+       else                                                                  \
+         result = EBUSY;                                                     \
+      }                                                                              \
+    else                                                                     \
+      ++(NAME).cnt;                                                          \
+    result;                                                                  \
+  })
+#else
+# define __libc_lock_trylock_recursive(NAME) \
+  __libc_maybe_call (__pthread_mutex_trylock, (&(NAME)), 0)
+#endif
+
+#define __rtld_lock_trylock_recursive(NAME) \
+  __libc_maybe_call (__pthread_mutex_trylock, (&(NAME).mutex), 0)
+
+/* Unlock the named lock variable.  */
+#if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread)
+# define __libc_lock_unlock(NAME) \
+  lll_unlock (NAME, LLL_PRIVATE)
+#else
+# define __libc_lock_unlock(NAME) \
+  __libc_maybe_call (__pthread_mutex_unlock, (&(NAME)), 0)
+#endif
+#define __libc_rwlock_unlock(NAME) \
+  __libc_ptf_call (__pthread_rwlock_unlock, (&(NAME)), 0)
+
+/* Unlock the recursive named lock variable.  */
+#if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread)
+/* We do no error checking here.  */
+# define __libc_lock_unlock_recursive(NAME) \
+  do {                                                                       \
+    if (--(NAME).cnt == 0)                                                   \
+      {                                                                              \
+       (NAME).owner = NULL;                                                  \
+       lll_unlock ((NAME).lock, LLL_PRIVATE);                                \
+      }                                                                              \
+  } while (0)
+#else
+# define __libc_lock_unlock_recursive(NAME) \
+  __libc_maybe_call (__pthread_mutex_unlock, (&(NAME)), 0)
+#endif
+
+#if defined _LIBC && defined SHARED
+# define __rtld_lock_default_lock_recursive(lock) \
+  ++((pthread_mutex_t *)(lock))->__data.__count;
+
+# define __rtld_lock_default_unlock_recursive(lock) \
+  --((pthread_mutex_t *)(lock))->__data.__count;
+
+# define __rtld_lock_lock_recursive(NAME) \
+  GL(dl_rtld_lock_recursive) (&(NAME).mutex)
+
+# define __rtld_lock_unlock_recursive(NAME) \
+  GL(dl_rtld_unlock_recursive) (&(NAME).mutex)
+#else
+# define __rtld_lock_lock_recursive(NAME) \
+  __libc_maybe_call (__pthread_mutex_lock, (&(NAME).mutex), 0)
+
+# define __rtld_lock_unlock_recursive(NAME) \
+  __libc_maybe_call (__pthread_mutex_unlock, (&(NAME).mutex), 0)
+#endif
+
+/* Define once control variable.  */
+#if PTHREAD_ONCE_INIT == 0
+/* Special case for static variables where we can avoid the initialization
+   if it is zero.  */
+# define __libc_once_define(CLASS, NAME) \
+  CLASS pthread_once_t NAME
+#else
+# define __libc_once_define(CLASS, NAME) \
+  CLASS pthread_once_t NAME = PTHREAD_ONCE_INIT
+#endif
+
+/* Call handler iff the first call.  */
+#define __libc_once(ONCE_CONTROL, INIT_FUNCTION) \
+  do {                                                                       \
+    if (PTFAVAIL (__pthread_once))                                           \
+      __libc_ptf_call_always (__pthread_once, (&(ONCE_CONTROL),                      \
+                                              INIT_FUNCTION));               \
+    else if ((ONCE_CONTROL) == PTHREAD_ONCE_INIT) {                          \
+      INIT_FUNCTION ();                                                              \
+      (ONCE_CONTROL) |= 2;                                                   \
+    }                                                                        \
+  } while (0)
+
+
+/* Note that for I/O cleanup handling we are using the old-style
+   cancel handling.  It does not have to be integrated with C++ snce
+   no C++ code is called in the middle.  The old-style handling is
+   faster and the support is not going away.  */
+extern void _pthread_cleanup_push (struct _pthread_cleanup_buffer *buffer,
+                                   void (*routine) (void *), void *arg);
+extern void _pthread_cleanup_pop (struct _pthread_cleanup_buffer *buffer,
+                                  int execute);
+extern void _pthread_cleanup_push_defer (struct _pthread_cleanup_buffer *buffer,
+                                         void (*routine) (void *), void *arg);
+extern void _pthread_cleanup_pop_restore (struct _pthread_cleanup_buffer *buffer,
+                                          int execute);
+
+/* Start critical region with cleanup.  */
+#define __libc_cleanup_region_start(DOIT, FCT, ARG) \
+  { struct _pthread_cleanup_buffer _buffer;                                  \
+    int _avail;                                                                      \
+    if (DOIT) {                                                                      \
+      _avail = PTFAVAIL (_pthread_cleanup_push_defer);                       \
+      if (_avail) {                                                          \
+       __libc_ptf_call_always (_pthread_cleanup_push_defer, (&_buffer, FCT,  \
+                                                             ARG));          \
+      } else {                                                               \
+       _buffer.__routine = (FCT);                                            \
+       _buffer.__arg = (ARG);                                                \
+      }                                                                              \
+    } else {                                                                 \
+      _avail = 0;                                                            \
+    }
+
+/* End critical region with cleanup.  */
+#define __libc_cleanup_region_end(DOIT) \
+    if (_avail) {                                                            \
+      __libc_ptf_call_always (_pthread_cleanup_pop_restore, (&_buffer, DOIT));\
+    } else if (DOIT)                                                         \
+      _buffer.__routine (_buffer.__arg);                                     \
+  }
+
+/* Sometimes we have to exit the block in the middle.  */
+#define __libc_cleanup_end(DOIT) \
+    if (_avail) {                                                            \
+      __libc_ptf_call_always (_pthread_cleanup_pop_restore, (&_buffer, DOIT));\
+    } else if (DOIT)                                                         \
+      _buffer.__routine (_buffer.__arg)
+
+
+/* Normal cleanup handling, based on C cleanup attribute.  */
+__extern_inline void
+__libc_cleanup_routine (struct __pthread_cleanup_frame *f)
+{
+  if (f->__do_it)
+    f->__cancel_routine (f->__cancel_arg);
+}
+
+#define __libc_cleanup_push(fct, arg) \
+  do {                                                                       \
+    struct __pthread_cleanup_frame __clframe                                 \
+      __attribute__ ((__cleanup__ (__libc_cleanup_routine)))                 \
+      = { .__cancel_routine = (fct), .__cancel_arg = (arg),                  \
+          .__do_it = 1 };
+
+#define __libc_cleanup_pop(execute) \
+    __clframe.__do_it = (execute);                                           \
+  } while (0)
+
+
+/* Create thread-specific key.  */
+#define __libc_key_create(KEY, DESTRUCTOR) \
+  __libc_ptf_call (__pthread_key_create, (KEY, DESTRUCTOR), 1)
+
+/* Get thread-specific data.  */
+#define __libc_getspecific(KEY) \
+  __libc_ptf_call (__pthread_getspecific, (KEY), NULL)
+
+/* Set thread-specific data.  */
+#define __libc_setspecific(KEY, VALUE) \
+  __libc_ptf_call (__pthread_setspecific, (KEY, VALUE), 0)
+
+
+/* Register handlers to execute before and after `fork'.  Note that the
+   last parameter is NULL.  The handlers registered by the libc are
+   never removed so this is OK.  */
+#define __libc_atfork(PREPARE, PARENT, CHILD) \
+  __register_atfork (PREPARE, PARENT, CHILD, NULL)
+extern int __register_atfork (void (*__prepare) (void),
+                             void (*__parent) (void),
+                             void (*__child) (void),
+                             void *__dso_handle);
+
+/* Functions that are used by this file and are internal to the GNU C
+   library.  */
+
+extern int __pthread_mutex_init (pthread_mutex_t *__mutex,
+                                __const pthread_mutexattr_t *__mutex_attr);
+
+extern int __pthread_mutex_destroy (pthread_mutex_t *__mutex);
+
+extern int __pthread_mutex_trylock (pthread_mutex_t *__mutex);
+
+extern int __pthread_mutex_lock (pthread_mutex_t *__mutex);
+
+extern int __pthread_mutex_unlock (pthread_mutex_t *__mutex);
+
+extern int __pthread_mutexattr_init (pthread_mutexattr_t *__attr);
+
+extern int __pthread_mutexattr_destroy (pthread_mutexattr_t *__attr);
+
+extern int __pthread_mutexattr_settype (pthread_mutexattr_t *__attr,
+                                       int __kind);
+
+#ifdef __USE_UNIX98
+extern int __pthread_rwlock_init (pthread_rwlock_t *__rwlock,
+                                 __const pthread_rwlockattr_t *__attr);
+
+extern int __pthread_rwlock_destroy (pthread_rwlock_t *__rwlock);
+
+extern int __pthread_rwlock_rdlock (pthread_rwlock_t *__rwlock);
+
+extern int __pthread_rwlock_tryrdlock (pthread_rwlock_t *__rwlock);
+
+extern int __pthread_rwlock_wrlock (pthread_rwlock_t *__rwlock);
+
+extern int __pthread_rwlock_trywrlock (pthread_rwlock_t *__rwlock);
+
+extern int __pthread_rwlock_unlock (pthread_rwlock_t *__rwlock);
+#endif
+
+extern int __pthread_key_create (pthread_key_t *__key,
+                                void (*__destr_function) (void *));
+
+extern int __pthread_setspecific (pthread_key_t __key,
+                                 __const void *__pointer);
+
+extern void *__pthread_getspecific (pthread_key_t __key);
+
+extern int __pthread_once (pthread_once_t *__once_control,
+                          void (*__init_routine) (void));
+
+extern int __pthread_atfork (void (*__prepare) (void),
+                            void (*__parent) (void),
+                            void (*__child) (void));
+
+
+
+/* Make the pthread functions weak so that we can elide them from
+   single-threaded processes.  */
+#ifndef __NO_WEAK_PTHREAD_ALIASES
+# ifdef weak_extern
+weak_extern (__pthread_mutex_init)
+weak_extern (__pthread_mutex_destroy)
+weak_extern (__pthread_mutex_lock)
+weak_extern (__pthread_mutex_trylock)
+weak_extern (__pthread_mutex_unlock)
+weak_extern (__pthread_mutexattr_init)
+weak_extern (__pthread_mutexattr_destroy)
+weak_extern (__pthread_mutexattr_settype)
+weak_extern (__pthread_rwlock_init)
+weak_extern (__pthread_rwlock_destroy)
+weak_extern (__pthread_rwlock_rdlock)
+weak_extern (__pthread_rwlock_tryrdlock)
+weak_extern (__pthread_rwlock_wrlock)
+weak_extern (__pthread_rwlock_trywrlock)
+weak_extern (__pthread_rwlock_unlock)
+weak_extern (__pthread_key_create)
+weak_extern (__pthread_setspecific)
+weak_extern (__pthread_getspecific)
+weak_extern (__pthread_once)
+//weak_extern (__pthread_initialize)
+weak_extern (__pthread_atfork)
+#ifdef SHARED
+weak_extern (_pthread_cleanup_push_defer)
+weak_extern (_pthread_cleanup_pop_restore)
+#endif
+weak_extern (pthread_setcancelstate)
+# else
+#  pragma weak __pthread_mutex_init
+#  pragma weak __pthread_mutex_destroy
+#  pragma weak __pthread_mutex_lock
+#  pragma weak __pthread_mutex_trylock
+#  pragma weak __pthread_mutex_unlock
+#  pragma weak __pthread_mutexattr_init
+#  pragma weak __pthread_mutexattr_destroy
+#  pragma weak __pthread_mutexattr_settype
+#  pragma weak __pthread_rwlock_destroy
+#  pragma weak __pthread_rwlock_rdlock
+#  pragma weak __pthread_rwlock_tryrdlock
+#  pragma weak __pthread_rwlock_wrlock
+#  pragma weak __pthread_rwlock_trywrlock
+#  pragma weak __pthread_rwlock_unlock
+#  pragma weak __pthread_key_create
+#  pragma weak __pthread_setspecific
+#  pragma weak __pthread_getspecific
+#  pragma weak __pthread_once
+//#  pragma weak __pthread_initialize
+#  pragma weak __pthread_atfork
+#  pragma weak _pthread_cleanup_push_defer
+#  pragma weak _pthread_cleanup_pop_restore
+#  pragma weak pthread_setcancelstate
+# endif
+#endif
+
+#endif /* bits/libc-lock.h */
diff --git a/libpthread/nptl/sysdeps/pthread/bits/libc-tsd.h b/libpthread/nptl/sysdeps/pthread/bits/libc-tsd.h
new file mode 100644 (file)
index 0000000..3f1676b
--- /dev/null
@@ -0,0 +1,69 @@
+/* libc-internal interface for thread-specific data.  Stub or TLS version.
+   Copyright (C) 1998,2001,02 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _GENERIC_BITS_LIBC_TSD_H
+#define _GENERIC_BITS_LIBC_TSD_H 1
+
+/* This file defines the following macros for accessing a small fixed
+   set of thread-specific `void *' data used only internally by libc.
+
+   __libc_tsd_define(CLASS, KEY)       -- Define or declare a `void *' datum
+                       for KEY.  CLASS can be `static' for
+                                          keys used in only one source file,
+                                          empty for global definitions, or
+                                          `extern' for global declarations.
+   __libc_tsd_address(KEY)             -- Return the `void **' pointing to
+                       the current thread's datum for KEY.
+   __libc_tsd_get(KEY)                 -- Return the `void *' datum for KEY.
+   __libc_tsd_set(KEY, VALUE)          -- Set the datum for KEY to VALUE.
+
+   The set of available KEY's will usually be provided as an enum,
+   and contains (at least):
+               _LIBC_TSD_KEY_MALLOC
+               _LIBC_TSD_KEY_DL_ERROR
+               _LIBC_TSD_KEY_RPC_VARS
+   All uses must be the literal _LIBC_TSD_* name in the __libc_tsd_* macros.
+   Some implementations may not provide any enum at all and instead
+   using string pasting in the macros.  */
+
+#include <tls.h>
+
+/* When full support for __thread variables is available, this interface is
+   just a trivial wrapper for it.  Without TLS, this is the generic/stub
+   implementation for wholly single-threaded systems.
+
+   We don't define an enum for the possible key values, because the KEYs
+   translate directly into variables by macro magic.  */
+
+#if USE___THREAD
+# define __libc_tsd_define(CLASS, KEY) \
+  CLASS __thread void *__libc_tsd_##KEY attribute_tls_model_ie;
+
+# define __libc_tsd_address(KEY)       (&__libc_tsd_##KEY)
+# define __libc_tsd_get(KEY)           (__libc_tsd_##KEY)
+# define __libc_tsd_set(KEY, VALUE)    (__libc_tsd_##KEY = (VALUE))
+#else
+# define __libc_tsd_define(CLASS, KEY) CLASS void *__libc_tsd_##KEY##_data;
+
+# define __libc_tsd_address(KEY)       (&__libc_tsd_##KEY##_data)
+# define __libc_tsd_get(KEY)           (__libc_tsd_##KEY##_data)
+# define __libc_tsd_set(KEY, VALUE)    (__libc_tsd_##KEY##_data = (VALUE))
+#endif
+
+#endif /* bits/libc-tsd.h */
diff --git a/libpthread/nptl/sysdeps/pthread/bits/sigthread.h b/libpthread/nptl/sysdeps/pthread/bits/sigthread.h
new file mode 100644 (file)
index 0000000..9a524e5
--- /dev/null
@@ -0,0 +1,44 @@
+/* Signal handling function for threaded programs.
+   Copyright (C) 1998, 1999, 2000, 2002, 2009 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef _BITS_SIGTHREAD_H
+#define _BITS_SIGTHREAD_H      1
+
+#if !defined _SIGNAL_H && !defined _PTHREAD_H
+# error "Never include this file directly.  Use <pthread.h> instead"
+#endif
+
+/* Functions for handling signals. */
+
+/* Modify the signal mask for the calling thread.  The arguments have
+   the same meaning as for sigprocmask(2). */
+extern int pthread_sigmask (int __how,
+                           __const __sigset_t *__restrict __newmask,
+                           __sigset_t *__restrict __oldmask)__THROW;
+
+/* Send signal SIGNO to the given thread. */
+extern int pthread_kill (pthread_t __threadid, int __signo) __THROW;
+
+#ifdef __USE_GNU
+/* Queue signal and data to a thread.  */
+extern int pthread_sigqueue (pthread_t __threadid, int __signo,
+                            const union sigval __value) __THROW;
+#endif
+
+#endif /* bits/sigthread.h */
diff --git a/libpthread/nptl/sysdeps/pthread/bits/stdio-lock.h b/libpthread/nptl/sysdeps/pthread/bits/stdio-lock.h
new file mode 100644 (file)
index 0000000..b8efdd8
--- /dev/null
@@ -0,0 +1,111 @@
+/* Thread package specific definitions of stream lock type.  NPTL version.
+   Copyright (C) 2000, 2001, 2002, 2003, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _BITS_STDIO_LOCK_H
+#define _BITS_STDIO_LOCK_H 1
+
+#include <bits/libc-lock.h>
+#include <lowlevellock.h>
+
+
+/* The locking here is very inexpensive, even for inlining.  */
+#define _IO_lock_inexpensive   1
+
+typedef struct { int lock; int cnt; void *owner; } _IO_lock_t;
+
+#define _IO_lock_initializer { LLL_LOCK_INITIALIZER, 0, NULL }
+
+#define _IO_lock_init(_name) \
+  ((_name) = (_IO_lock_t) _IO_lock_initializer , 0)
+
+#define _IO_lock_fini(_name) \
+  ((void) 0)
+
+#define _IO_lock_lock(_name) \
+  do {                                                                       \
+    void *__self = THREAD_SELF;                                                      \
+    if ((_name).owner != __self)                                             \
+      {                                                                              \
+       lll_lock ((_name).lock, LLL_PRIVATE);                                 \
+        (_name).owner = __self;                                                      \
+      }                                                                              \
+    ++(_name).cnt;                                                           \
+  } while (0)
+
+#define _IO_lock_trylock(_name) \
+  ({                                                                         \
+    int __result = 0;                                                        \
+    void *__self = THREAD_SELF;                                                      \
+    if ((_name).owner != __self)                                             \
+      {                                                                              \
+        if (lll_trylock ((_name).lock) == 0)                                 \
+          {                                                                  \
+            (_name).owner = __self;                                          \
+            (_name).cnt = 1;                                                 \
+          }                                                                  \
+        else                                                                 \
+          __result = EBUSY;                                                  \
+      }                                                                              \
+    else                                                                     \
+      ++(_name).cnt;                                                         \
+    __result;                                                                \
+  })
+
+#define _IO_lock_unlock(_name) \
+  do {                                                                       \
+    if (--(_name).cnt == 0)                                                  \
+      {                                                                              \
+        (_name).owner = NULL;                                                \
+       lll_unlock ((_name).lock, LLL_PRIVATE);                               \
+      }                                                                              \
+  } while (0)
+
+
+
+#define _IO_cleanup_region_start(_fct, _fp) \
+  __libc_cleanup_region_start (((_fp)->_flags & _IO_USER_LOCK) == 0, _fct, _fp)
+#define _IO_cleanup_region_start_noarg(_fct) \
+  __libc_cleanup_region_start (1, _fct, NULL)
+#define _IO_cleanup_region_end(_doit) \
+  __libc_cleanup_region_end (_doit)
+
+#if defined _LIBC && !defined NOT_IN_libc
+
+# ifdef __EXCEPTIONS
+#  define _IO_acquire_lock(_fp) \
+  do {                                                                       \
+    _IO_FILE *_IO_acquire_lock_file                                          \
+       __attribute__((cleanup (_IO_acquire_lock_fct)))                       \
+       = (_fp);                                                              \
+    _IO_flockfile (_IO_acquire_lock_file);
+#  define _IO_acquire_lock_clear_flags2(_fp) \
+  do {                                                                       \
+    _IO_FILE *_IO_acquire_lock_file                                          \
+       __attribute__((cleanup (_IO_acquire_lock_clear_flags2_fct)))          \
+       = (_fp);                                                              \
+    _IO_flockfile (_IO_acquire_lock_file);
+# else
+#  define _IO_acquire_lock(_fp) _IO_acquire_lock_needs_exceptions_enabled
+#  define _IO_acquire_lock_clear_flags2(_fp) _IO_acquire_lock (_fp)
+# endif
+# define _IO_release_lock(_fp) ; } while (0)
+
+#endif
+
+#endif /* bits/stdio-lock.h */
diff --git a/libpthread/nptl/sysdeps/pthread/createthread.c b/libpthread/nptl/sysdeps/pthread/createthread.c
new file mode 100644 (file)
index 0000000..a676e27
--- /dev/null
@@ -0,0 +1,257 @@
+/* Copyright (C) 2002-2007, 2008 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sched.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <atomic.h>
+#include <ldsodefs.h>
+#include <tls.h>
+
+#include <bits/kernel-features.h>
+
+
+#define CLONE_SIGNAL           (CLONE_SIGHAND | CLONE_THREAD)
+
+/* Unless otherwise specified, the thread "register" is going to be
+   initialized with a pointer to the TCB.  */
+#ifndef TLS_VALUE
+# define TLS_VALUE pd
+#endif
+
+#ifndef ARCH_CLONE
+# define ARCH_CLONE __clone
+#endif
+
+
+#ifndef TLS_MULTIPLE_THREADS_IN_TCB
+/* Pointer to the corresponding variable in libc.  */
+int *__libc_multiple_threads_ptr attribute_hidden;
+#endif
+
+
+static int
+do_clone (struct pthread *pd, const struct pthread_attr *attr,
+         int clone_flags, int (*fct) (void *), STACK_VARIABLES_PARMS,
+         int stopped)
+{
+#ifdef PREPARE_CREATE
+  PREPARE_CREATE;
+#endif
+
+  if (__builtin_expect (stopped != 0, 0))
+    /* We make sure the thread does not run far by forcing it to get a
+       lock.  We lock it here too so that the new thread cannot continue
+       until we tell it to.  */
+    lll_lock (pd->lock, LLL_PRIVATE);
+
+  /* One more thread.  We cannot have the thread do this itself, since it
+     might exist but not have been scheduled yet by the time we've returned
+     and need to check the value to behave correctly.  We must do it before
+     creating the thread, in case it does get scheduled first and then
+     might mistakenly think it was the only thread.  In the failure case,
+     we momentarily store a false value; this doesn't matter because there
+     is no kosher thing a signal handler interrupting us right here can do
+     that cares whether the thread count is correct.  */
+  atomic_increment (&__nptl_nthreads);
+
+  if (ARCH_CLONE (fct, STACK_VARIABLES_ARGS, clone_flags,
+                 pd, &pd->tid, TLS_VALUE, &pd->tid) == -1)
+    {
+      atomic_decrement (&__nptl_nthreads); /* Oops, we lied for a second.  */
+
+      /* Failed.  If the thread is detached, remove the TCB here since
+        the caller cannot do this.  The caller remembered the thread
+        as detached and cannot reverify that it is not since it must
+        not access the thread descriptor again.  */
+      if (IS_DETACHED (pd))
+       __deallocate_stack (pd);
+
+      /* We have to translate error codes.  */
+      return errno == ENOMEM ? EAGAIN : errno;
+    }
+
+  /* Now we have the possibility to set scheduling parameters etc.  */
+  if (__builtin_expect (stopped != 0, 0))
+    {
+      INTERNAL_SYSCALL_DECL (err);
+      int res = 0;
+
+      /* Set the affinity mask if necessary.  */
+      if (attr->cpuset != NULL)
+       {
+         res = INTERNAL_SYSCALL (sched_setaffinity, err, 3, pd->tid,
+                                 attr->cpusetsize, attr->cpuset);
+
+         if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (res, err), 0))
+           {
+             /* The operation failed.  We have to kill the thread.  First
+                send it the cancellation signal.  */
+             INTERNAL_SYSCALL_DECL (err2);
+           err_out:
+#if __ASSUME_TGKILL
+             (void) INTERNAL_SYSCALL (tgkill, err2, 3,
+                                      THREAD_GETMEM (THREAD_SELF, pid),
+                                      pd->tid, SIGCANCEL);
+#else
+             (void) INTERNAL_SYSCALL (tkill, err2, 2, pd->tid, SIGCANCEL);
+#endif
+
+             return (INTERNAL_SYSCALL_ERROR_P (res, err)
+                     ? INTERNAL_SYSCALL_ERRNO (res, err)
+                     : 0);
+           }
+       }
+
+      /* Set the scheduling parameters.  */
+      if ((attr->flags & ATTR_FLAG_NOTINHERITSCHED) != 0)
+       {
+         res = INTERNAL_SYSCALL (sched_setscheduler, err, 3, pd->tid,
+                                 pd->schedpolicy, &pd->schedparam);
+
+         if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (res, err), 0))
+           goto err_out;
+       }
+    }
+
+  /* We now have for sure more than one thread.  The main thread might
+     not yet have the flag set.  No need to set the global variable
+     again if this is what we use.  */
+  THREAD_SETMEM (THREAD_SELF, header.multiple_threads, 1);
+
+  return 0;
+}
+
+
+static int
+create_thread (struct pthread *pd, const struct pthread_attr *attr,
+              STACK_VARIABLES_PARMS)
+{
+#ifdef TLS_TCB_AT_TP
+  assert (pd->header.tcb != NULL);
+#endif
+
+  /* We rely heavily on various flags the CLONE function understands:
+
+     CLONE_VM, CLONE_FS, CLONE_FILES
+       These flags select semantics with shared address space and
+       file descriptors according to what POSIX requires.
+
+     CLONE_SIGNAL
+       This flag selects the POSIX signal semantics.
+
+     CLONE_SETTLS
+       The sixth parameter to CLONE determines the TLS area for the
+       new thread.
+
+     CLONE_PARENT_SETTID
+       The kernels writes the thread ID of the newly created thread
+       into the location pointed to by the fifth parameters to CLONE.
+
+       Note that it would be semantically equivalent to use
+       CLONE_CHILD_SETTID but it is be more expensive in the kernel.
+
+     CLONE_CHILD_CLEARTID
+       The kernels clears the thread ID of a thread that has called
+       sys_exit() in the location pointed to by the seventh parameter
+       to CLONE.
+
+     CLONE_DETACHED
+       No signal is generated if the thread exists and it is
+       automatically reaped.
+
+     The termination signal is chosen to be zero which means no signal
+     is sent.  */
+  int clone_flags = (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGNAL
+                    | CLONE_SETTLS | CLONE_PARENT_SETTID
+                    | CLONE_CHILD_CLEARTID | CLONE_SYSVSEM
+#if __ASSUME_NO_CLONE_DETACHED == 0
+                    | CLONE_DETACHED
+#endif
+                    | 0);
+
+  if (__builtin_expect (THREAD_GETMEM (THREAD_SELF, report_events), 0))
+    {
+      /* The parent thread is supposed to report events.  Check whether
+        the TD_CREATE event is needed, too.  */
+      const int _idx = __td_eventword (TD_CREATE);
+      const uint32_t _mask = __td_eventmask (TD_CREATE);
+
+      if ((_mask & (__nptl_threads_events.event_bits[_idx]
+                   | pd->eventbuf.eventmask.event_bits[_idx])) != 0)
+       {
+         /* We always must have the thread start stopped.  */
+         pd->stopped_start = true;
+
+         /* Create the thread.  We always create the thread stopped
+            so that it does not get far before we tell the debugger.  */
+         int res = do_clone (pd, attr, clone_flags, start_thread,
+                             STACK_VARIABLES_ARGS, 1);
+         if (res == 0)
+           {
+             /* Now fill in the information about the new thread in
+                the newly created thread's data structure.  We cannot let
+                the new thread do this since we don't know whether it was
+                already scheduled when we send the event.  */
+             pd->eventbuf.eventnum = TD_CREATE;
+             pd->eventbuf.eventdata = pd;
+
+             /* Enqueue the descriptor.  */
+             do
+               pd->nextevent = __nptl_last_event;
+             while (atomic_compare_and_exchange_bool_acq (&__nptl_last_event,
+                                                          pd, pd->nextevent)
+                    != 0);
+
+             /* Now call the function which signals the event.  */
+             __nptl_create_event ();
+
+             /* And finally restart the new thread.  */
+             lll_unlock (pd->lock, LLL_PRIVATE);
+           }
+
+         return res;
+       }
+    }
+
+#ifdef NEED_DL_SYSINFO
+  assert (THREAD_SELF_SYSINFO == THREAD_SYSINFO (pd));
+#endif
+
+  /* Determine whether the newly created threads has to be started
+     stopped since we have to set the scheduling parameters or set the
+     affinity.  */
+  bool stopped = false;
+  if (attr != NULL && (attr->cpuset != NULL
+                      || (attr->flags & ATTR_FLAG_NOTINHERITSCHED) != 0))
+    stopped = true;
+  pd->stopped_start = stopped;
+  pd->parent_cancelhandling = THREAD_GETMEM (THREAD_SELF, cancelhandling);
+
+  /* Actually create the thread.  */
+  int res = do_clone (pd, attr, clone_flags, start_thread,
+                     STACK_VARIABLES_ARGS, stopped);
+
+  if (res == 0 && stopped)
+    /* And finally restart the new thread.  */
+    lll_unlock (pd->lock, LLL_PRIVATE);
+
+  return res;
+}
diff --git a/libpthread/nptl/sysdeps/pthread/defs.awk b/libpthread/nptl/sysdeps/pthread/defs.awk
new file mode 100644 (file)
index 0000000..d41d57b
--- /dev/null
@@ -0,0 +1,24 @@
+/^[    ]*\.endp/        { need_endp = 1 }
+/^[    ]*\.end/         { need_end = 1 }
+/^[    ]*\.align/ { if($2 > max) max = $2; }
+
+END {
+    if(need_endp)
+    {
+       print "#define END_INIT .endp _init";
+       print "#define END_FINI .endp _fini";
+    } else if(need_end)
+    {
+       print "#define END_INIT .end _init";
+       print "#define END_FINI .end _fini";
+    }
+    else
+    {
+       print "#define END_INIT";
+       print "#define END_FINI";
+    }
+    if(max)
+       print "#define ALIGN .align", max;
+    else
+       print "#define ALIGN";
+}
diff --git a/libpthread/nptl/sysdeps/pthread/librt-cancellation.c b/libpthread/nptl/sysdeps/pthread/librt-cancellation.c
new file mode 100644 (file)
index 0000000..ad189e8
--- /dev/null
@@ -0,0 +1,25 @@
+/* Copyright (C) 2002, 2003, 2009 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"
+
+
+#define __pthread_enable_asynccancel __librt_enable_asynccancel
+#define __pthread_disable_asynccancel __librt_disable_asynccancel
+#include "cancellation.c"
diff --git a/libpthread/nptl/sysdeps/pthread/list.h b/libpthread/nptl/sysdeps/pthread/list.h
new file mode 100644 (file)
index 0000000..6ddccb9
--- /dev/null
@@ -0,0 +1,103 @@
+/* Copyright (C) 2002, 2009 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _LIST_H
+#define _LIST_H        1
+
+/* The definitions of this file are adopted from those which can be
+   found in the Linux kernel headers to enable people familiar with
+   the latter find their way in these sources as well.  */
+
+
+/* Basic type for the double-link list.  */
+typedef struct list_head
+{
+  struct list_head *next;
+  struct list_head *prev;
+} list_t;
+
+
+/* Define a variable with the head and tail of the list.  */
+#define LIST_HEAD(name) \
+  list_t name = { &(name), &(name) }
+
+/* Initialize a new list head.  */
+#define INIT_LIST_HEAD(ptr) \
+  (ptr)->next = (ptr)->prev = (ptr)
+
+
+/* Add new element at the head of the list.  */
+static inline void
+list_add (list_t *newp, list_t *head)
+{
+  newp->next = head->next;
+  newp->prev = head;
+  head->next->prev = newp;
+  head->next = newp;
+}
+
+
+/* Remove element from list.  */
+static inline void
+list_del (list_t *elem)
+{
+  elem->next->prev = elem->prev;
+  elem->prev->next = elem->next;
+}
+
+
+/* Join two lists.  */
+static inline void
+list_splice (list_t *add, list_t *head)
+{
+  /* Do nothing if the list which gets added is empty.  */
+  if (add != add->next)
+    {
+      add->next->prev = head;
+      add->prev->next = head->next;
+      head->next->prev = add->prev;
+      head->next = add->next;
+    }
+}
+
+
+/* Get typed element from list at a given position.  */
+#define list_entry(ptr, type, member) \
+  ((type *) ((char *) (ptr) - (unsigned long) (&((type *) 0)->member)))
+
+
+
+/* Iterate forward over the elements of the list.  */
+#define list_for_each(pos, head) \
+  for (pos = (head)->next; pos != (head); pos = pos->next)
+
+
+/* Iterate forward over the elements of the list.  */
+#define list_for_each_prev(pos, head) \
+  for (pos = (head)->prev; pos != (head); pos = pos->prev)
+
+
+/* Iterate backwards over the elements list.  The list elements can be
+   removed from the list while doing this.  */
+#define list_for_each_prev_safe(pos, p, head) \
+  for (pos = (head)->prev, p = pos->prev; \
+       pos != (head); \
+       pos = p, p = pos->prev)
+
+#endif /* list.h */
diff --git a/libpthread/nptl/sysdeps/pthread/malloc-machine.h b/libpthread/nptl/sysdeps/pthread/malloc-machine.h
new file mode 100644 (file)
index 0000000..e99aaa7
--- /dev/null
@@ -0,0 +1,73 @@
+/* Basic platform-independent macro definitions for mutexes,
+   thread-specific data and parameters for malloc.
+   Copyright (C) 2003, 2007, 2008 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 _MALLOC_MACHINE_H
+#define _MALLOC_MACHINE_H
+
+#undef thread_atfork_static
+
+#include <atomic.h>
+#include <bits/libc-lock.h>
+
+__libc_lock_define (typedef, mutex_t)
+
+#define mutex_init(m)          __libc_lock_init (*(m))
+#define mutex_lock(m)          __libc_lock_lock (*(m))
+#define mutex_trylock(m)       __libc_lock_trylock (*(m))
+#define mutex_unlock(m)                __libc_lock_unlock (*(m))
+
+/* This is defined by newer gcc version unique for each module.  */
+extern void *__dso_handle __attribute__ ((__weak__));
+
+#include <fork.h>
+
+#define ATFORK_MEM static struct fork_handler atfork_mem
+
+#ifdef SHARED
+# define thread_atfork(prepare, parent, child) \
+  atfork_mem.prepare_handler = prepare;                                              \
+  atfork_mem.parent_handler = parent;                                        \
+  atfork_mem.child_handler = child;                                          \
+  atfork_mem.dso_handle = __dso_handle;                                              \
+  atfork_mem.refcntr = 1;                                                    \
+  __linkin_atfork (&atfork_mem)
+#else
+# define thread_atfork(prepare, parent, child) \
+  atfork_mem.prepare_handler = prepare;                                              \
+  atfork_mem.parent_handler = parent;                                        \
+  atfork_mem.child_handler = child;                                          \
+  atfork_mem.dso_handle = &__dso_handle == NULL ? NULL : __dso_handle;       \
+  atfork_mem.refcntr = 1;                                                    \
+  __linkin_atfork (&atfork_mem)
+#endif
+
+/* thread specific data for glibc */
+
+#include <bits/libc-tsd.h>
+
+typedef int tsd_key_t[1];      /* no key data structure, libc magic does it */
+__libc_tsd_define (static, void *, MALLOC)     /* declaration/common definition */
+#define tsd_key_create(key, destr)     ((void) (key))
+#define tsd_setspecific(key, data)     __libc_tsd_set (void *, MALLOC, (data))
+#define tsd_getspecific(key, vptr)     ((vptr) = __libc_tsd_get (void *, MALLOC))
+
+#include <sysdeps/generic/malloc-machine.h>
+
+#endif /* !defined(_MALLOC_MACHINE_H) */
diff --git a/libpthread/nptl/sysdeps/pthread/posix-timer.h b/libpthread/nptl/sysdeps/pthread/posix-timer.h
new file mode 100644 (file)
index 0000000..8b4cbc8
--- /dev/null
@@ -0,0 +1,197 @@
+/* Definitions for POSIX timer implementation on top of NPTL.
+   Copyright (C) 2000, 2002, 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Kaz Kylheku <kaz@ashi.footprints.net>.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <limits.h>
+#include <signal.h>
+
+/* Double linked list.  */
+struct list_links
+{
+  struct list_links *next;
+  struct list_links *prev;
+};
+
+
+/* Forward declaration.  */
+struct timer_node;
+
+
+/* Definitions for an internal thread of the POSIX timer implementation.  */
+struct thread_node
+{
+  struct list_links links;
+  pthread_attr_t attr;
+  pthread_t id;
+  unsigned int exists;
+  struct list_links timer_queue;
+  pthread_cond_t cond;
+  struct timer_node *current_timer;
+  pthread_t captured;
+  clockid_t clock_id;
+};
+
+
+/* Internal representation of a timer.  */
+struct timer_node
+{
+  struct list_links links;
+  struct sigevent event;
+  clockid_t clock;
+  struct itimerspec value;
+  struct timespec expirytime;
+  pthread_attr_t attr;
+  unsigned int abstime;
+  unsigned int armed;
+  enum {
+    TIMER_FREE, TIMER_INUSE, TIMER_DELETED
+  } inuse;
+  struct thread_node *thread;
+  pid_t creator_pid;
+  int refcount;
+  int overrun_count;
+};
+
+
+/* The limit is not published if we are compiled with kernel timer support.
+   But we still compiled in this implementation with its limit unless built
+   to require the kernel support.  */
+#ifndef TIMER_MAX
+# define TIMER_MAX 256
+#endif
+
+/* Static array with the structures for all the timers.  */
+extern struct timer_node __timer_array[TIMER_MAX];
+
+/* Global lock to protect operation on the lists.  */
+extern pthread_mutex_t __timer_mutex;
+
+/* Variable to protext initialization.  */
+extern pthread_once_t __timer_init_once_control;
+
+/* Nonzero if initialization of timer implementation failed.  */
+extern int __timer_init_failed;
+
+/* Node for the thread used to deliver signals.  */
+extern struct thread_node __timer_signal_thread_rclk;
+
+
+/* Return pointer to timer structure corresponding to ID.  */
+#define timer_id2ptr(timerid) ((struct timer_node *) timerid)
+#define timer_ptr2id(timerid) ((void *) timerid)
+
+/* Check whether timer is valid; global mutex must be held. */
+static inline int
+timer_valid (struct timer_node *timer)
+{
+  return timer && timer->inuse == TIMER_INUSE;
+}
+
+/* Timer refcount functions; need global mutex. */
+extern void __timer_dealloc (struct timer_node *timer);
+
+static inline void
+timer_addref (struct timer_node *timer)
+{
+  timer->refcount++;
+}
+
+static inline void
+timer_delref (struct timer_node *timer)
+{
+  if (--timer->refcount == 0)
+    __timer_dealloc (timer);
+}
+
+/* Timespec helper routines.  */
+static inline int
+__attribute ((always_inline))
+timespec_compare (const struct timespec *left, const struct timespec *right)
+{
+  if (left->tv_sec < right->tv_sec)
+    return -1;
+  if (left->tv_sec > right->tv_sec)
+    return 1;
+
+  if (left->tv_nsec < right->tv_nsec)
+    return -1;
+  if (left->tv_nsec > right->tv_nsec)
+    return 1;
+
+  return 0;
+}
+
+static inline void
+timespec_add (struct timespec *sum, const struct timespec *left,
+             const struct timespec *right)
+{
+  sum->tv_sec = left->tv_sec + right->tv_sec;
+  sum->tv_nsec = left->tv_nsec + right->tv_nsec;
+
+  if (sum->tv_nsec >= 1000000000)
+    {
+      ++sum->tv_sec;
+      sum->tv_nsec -= 1000000000;
+    }
+}
+
+static inline void
+timespec_sub (struct timespec *diff, const struct timespec *left,
+             const struct timespec *right)
+{
+  diff->tv_sec = left->tv_sec - right->tv_sec;
+  diff->tv_nsec = left->tv_nsec - right->tv_nsec;
+
+  if (diff->tv_nsec < 0)
+    {
+      --diff->tv_sec;
+      diff->tv_nsec += 1000000000;
+    }
+}
+
+
+/* We need one of the list functions in the other modules.  */
+static inline void
+list_unlink_ip (struct list_links *list)
+{
+  struct list_links *lnext = list->next, *lprev = list->prev;
+
+  lnext->prev = lprev;
+  lprev->next = lnext;
+
+  /* The suffix ip means idempotent; list_unlink_ip can be called
+   * two or more times on the same node.
+   */
+
+  list->next = list;
+  list->prev = list;
+}
+
+
+/* Functions in the helper file.  */
+extern void __timer_mutex_cancel_handler (void *arg);
+extern void __timer_init_once (void);
+extern struct timer_node *__timer_alloc (void);
+extern int __timer_thread_start (struct thread_node *thread);
+extern struct thread_node *__timer_thread_find_matching (const pthread_attr_t *desired_attr, clockid_t);
+extern struct thread_node *__timer_thread_alloc (const pthread_attr_t *desired_attr, clockid_t);
+extern void __timer_thread_dealloc (struct thread_node *thread);
+extern int __timer_thread_queue_timer (struct thread_node *thread,
+                                      struct timer_node *insert);
+extern void __timer_thread_wakeup (struct thread_node *thread);
diff --git a/libpthread/nptl/sysdeps/pthread/pt-initfini.c b/libpthread/nptl/sysdeps/pthread/pt-initfini.c
new file mode 100644 (file)
index 0000000..b26a504
--- /dev/null
@@ -0,0 +1,125 @@
+/* Special .init and .fini section support.  Linuxthread version.
+   Copyright (C) 1995,1996,1997,2000,2001,2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it
+   and/or modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2 of the License, or (at your option) any later version.
+
+   In addition to the permissions in the GNU Lesser General Public
+   License, the Free Software Foundation gives you unlimited
+   permission to link the compiled version of this file with other
+   programs, and to distribute those programs without any restriction
+   coming from the use of this file.  (The Library General Public
+   License restrictions do apply in other respects; for example, they
+   cover modification of the file, and distribution when not linked
+   into another program.)
+
+   The GNU C Library is distributed in the hope that it will be
+   useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+   of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+/* This file is compiled into assembly code which is then munged by a sed
+   script into two files: crti.s and crtn.s.
+
+   * crti.s puts a function prologue at the beginning of the
+   .init and .fini sections and defines global symbols for
+   those addresses, so they can be called as functions.
+
+   * crtn.s puts the corresponding function epilogues
+   in the .init and .fini sections. */
+
+#include <stdlib.h>
+
+/* We use embedded asm for .section unconditionally, as this makes it
+   easier to insert the necessary directives into crtn.S. */
+#define SECTION(x) __asm__ (".section " x )
+
+/* Embed an #include to pull in the alignment and .end directives. */
+asm ("\n#include \"defs.h\"");
+
+/* The initial common code ends here. */
+asm ("\n/*@HEADER_ENDS*/");
+
+/* To determine whether we need .end and .align: */
+asm ("\n/*@TESTS_BEGIN*/");
+extern void dummy (void (*foo) (void));
+void
+dummy (void (*foo) (void))
+{
+  if (foo)
+    (*foo) ();
+}
+asm ("\n/*@TESTS_END*/");
+
+/* The beginning of _init:  */
+asm ("\n/*@_init_PROLOG_BEGINS*/");
+
+static void
+call_initialize_minimal (void)
+{
+  extern void __pthread_initialize_minimal_internal (void)
+    __attribute ((visibility ("hidden")));
+
+  __pthread_initialize_minimal_internal ();
+}
+
+SECTION (".init");
+extern void __attribute__ ((section (".init"))) _init (void);
+void
+_init (void)
+{
+  /* The very first thing we must do is to set up the registers.  */
+  call_initialize_minimal ();
+
+  asm ("ALIGN");
+  asm("END_INIT");
+  /* Now the epilog. */
+  asm ("\n/*@_init_PROLOG_ENDS*/");
+  asm ("\n/*@_init_EPILOG_BEGINS*/");
+  SECTION(".init");
+}
+asm ("END_INIT");
+
+/* End of the _init epilog, beginning of the _fini prolog. */
+asm ("\n/*@_init_EPILOG_ENDS*/");
+asm ("\n/*@_fini_PROLOG_BEGINS*/");
+
+SECTION (".fini");
+extern void __attribute__ ((section (".fini"))) _fini (void);
+void
+_fini (void)
+{
+
+  /* End of the _fini prolog. */
+  asm ("ALIGN");
+  asm ("END_FINI");
+  asm ("\n/*@_fini_PROLOG_ENDS*/");
+
+  {
+    /* Let GCC know that _fini is not a leaf function by having a dummy
+       function call here.  We arrange for this call to be omitted from
+       either crt file.  */
+    extern void i_am_not_a_leaf (void);
+    i_am_not_a_leaf ();
+  }
+
+  /* Beginning of the _fini epilog. */
+  asm ("\n/*@_fini_EPILOG_BEGINS*/");
+  SECTION (".fini");
+}
+asm ("END_FINI");
+
+/* End of the _fini epilog.  Any further generated assembly (e.g. .ident)
+   is shared between both crt files. */
+asm ("\n/*@_fini_EPILOG_ENDS*/");
+asm ("\n/*@TRAILER_BEGINS*/");
+
+/* End of file. */
diff --git a/libpthread/nptl/sysdeps/pthread/pt-longjmp.c b/libpthread/nptl/sysdeps/pthread/pt-longjmp.c
new file mode 100644 (file)
index 0000000..f161380
--- /dev/null
@@ -0,0 +1,29 @@
+/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <setjmp.h>
+#include <stdlib.h>
+#include "pthreadP.h"
+
+void
+longjmp (jmp_buf env, int val)
+{
+  __libc_longjmp (env, val);
+}
+weak_alias (longjmp, siglongjmp)
diff --git a/libpthread/nptl/sysdeps/pthread/pthread-functions.h b/libpthread/nptl/sysdeps/pthread/pthread-functions.h
new file mode 100644 (file)
index 0000000..0c404fc
--- /dev/null
@@ -0,0 +1,117 @@
+/* Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _PTHREAD_FUNCTIONS_H
+#define _PTHREAD_FUNCTIONS_H   1
+
+#include <pthread.h>
+#include <setjmp.h>
+#include <internaltypes.h>
+#include <sysdep.h>
+
+struct xid_command;
+
+/* Data type shared with libc.  The libc uses it to pass on calls to
+   the thread functions.  */
+struct pthread_functions
+{
+  int (*ptr_pthread_attr_destroy) (pthread_attr_t *);
+  int (*ptr___pthread_attr_init_2_0) (pthread_attr_t *);
+  int (*ptr___pthread_attr_init_2_1) (pthread_attr_t *);
+  int (*ptr_pthread_attr_getdetachstate) (const pthread_attr_t *, int *);
+  int (*ptr_pthread_attr_setdetachstate) (pthread_attr_t *, int);
+  int (*ptr_pthread_attr_getinheritsched) (const pthread_attr_t *, int *);
+  int (*ptr_pthread_attr_setinheritsched) (pthread_attr_t *, int);
+  int (*ptr_pthread_attr_getschedparam) (const pthread_attr_t *,
+                                        struct sched_param *);
+  int (*ptr_pthread_attr_setschedparam) (pthread_attr_t *,
+                                        const struct sched_param *);
+  int (*ptr_pthread_attr_getschedpolicy) (const pthread_attr_t *, int *);
+  int (*ptr_pthread_attr_setschedpolicy) (pthread_attr_t *, int);
+  int (*ptr_pthread_attr_getscope) (const pthread_attr_t *, int *);
+  int (*ptr_pthread_attr_setscope) (pthread_attr_t *, int);
+  int (*ptr_pthread_condattr_destroy) (pthread_condattr_t *);
+  int (*ptr_pthread_condattr_init) (pthread_condattr_t *);
+  int (*ptr___pthread_cond_broadcast) (pthread_cond_t *);
+  int (*ptr___pthread_cond_destroy) (pthread_cond_t *);
+  int (*ptr___pthread_cond_init) (pthread_cond_t *,
+                                 const pthread_condattr_t *);
+  int (*ptr___pthread_cond_signal) (pthread_cond_t *);
+  int (*ptr___pthread_cond_wait) (pthread_cond_t *, pthread_mutex_t *);
+  int (*ptr___pthread_cond_timedwait) (pthread_cond_t *, pthread_mutex_t *,
+                                      const struct timespec *);
+  int (*ptr___pthread_cond_broadcast_2_0) (pthread_cond_2_0_t *);
+  int (*ptr___pthread_cond_destroy_2_0) (pthread_cond_2_0_t *);
+  int (*ptr___pthread_cond_init_2_0) (pthread_cond_2_0_t *,
+                                     const pthread_condattr_t *);
+  int (*ptr___pthread_cond_signal_2_0) (pthread_cond_2_0_t *);
+  int (*ptr___pthread_cond_wait_2_0) (pthread_cond_2_0_t *, pthread_mutex_t *);
+  int (*ptr___pthread_cond_timedwait_2_0) (pthread_cond_2_0_t *,
+                                          pthread_mutex_t *,
+                                          const struct timespec *);
+  int (*ptr_pthread_equal) (pthread_t, pthread_t);
+  void (*ptr___pthread_exit) (void *);
+  int (*ptr_pthread_getschedparam) (pthread_t, int *, struct sched_param *);
+  int (*ptr_pthread_setschedparam) (pthread_t, int,
+                                   const struct sched_param *);
+  int (*ptr_pthread_mutex_destroy) (pthread_mutex_t *);
+  int (*ptr_pthread_mutex_init) (pthread_mutex_t *,
+                                const pthread_mutexattr_t *);
+  int (*ptr_pthread_mutex_lock) (pthread_mutex_t *);
+  int (*ptr_pthread_mutex_unlock) (pthread_mutex_t *);
+  pthread_t (*ptr_pthread_self) (void);
+  int (*ptr_pthread_setcancelstate) (int, int *);
+  int (*ptr_pthread_setcanceltype) (int, int *);
+  void (*ptr___pthread_cleanup_upto) (__jmp_buf, char *);
+  int (*ptr___pthread_once) (pthread_once_t *, void (*) (void));
+  int (*ptr___pthread_rwlock_rdlock) (pthread_rwlock_t *);
+  int (*ptr___pthread_rwlock_wrlock) (pthread_rwlock_t *);
+  int (*ptr___pthread_rwlock_unlock) (pthread_rwlock_t *);
+  int (*ptr___pthread_key_create) (pthread_key_t *, void (*) (void *));
+  void *(*ptr___pthread_getspecific) (pthread_key_t);
+  int (*ptr___pthread_setspecific) (pthread_key_t, const void *);
+  void (*ptr__pthread_cleanup_push_defer) (struct _pthread_cleanup_buffer *,
+                                          void (*) (void *), void *);
+  void (*ptr__pthread_cleanup_pop_restore) (struct _pthread_cleanup_buffer *,
+                                           int);
+#define HAVE_PTR_NTHREADS
+  unsigned int *ptr_nthreads;
+  void (*ptr___pthread_unwind) (__pthread_unwind_buf_t *)
+       __attribute ((noreturn)) __cleanup_fct_attribute;
+  void (*ptr__nptl_deallocate_tsd) (void);
+  int (*ptr__nptl_setxid) (struct xid_command *);
+  void (*ptr_freeres) (void);
+};
+
+/* Variable in libc.so.  */
+extern struct pthread_functions __libc_pthread_functions attribute_hidden;
+extern int __libc_pthread_functions_init attribute_hidden;
+
+#ifdef PTR_DEMANGLE
+# define PTHFCT_CALL(fct, params) \
+  ({ __typeof (__libc_pthread_functions.fct) __p;                            \
+     __p = __libc_pthread_functions.fct;                                     \
+     PTR_DEMANGLE (__p);                                                     \
+     __p params; })
+#else
+# define PTHFCT_CALL(fct, params) \
+  __libc_pthread_functions.fct params
+#endif
+
+#endif /* pthread-functions.h */
diff --git a/libpthread/nptl/sysdeps/pthread/pthread.h b/libpthread/nptl/sysdeps/pthread/pthread.h
new file mode 100644 (file)
index 0000000..deb7430
--- /dev/null
@@ -0,0 +1,1138 @@
+/* Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+   Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _PTHREAD_H
+#define _PTHREAD_H     1
+
+#include <features.h>
+#include <endian.h>
+#include <sched.h>
+#include <time.h>
+
+#define __need_sigset_t
+#include <signal.h>
+#include <bits/pthreadtypes.h>
+#include <bits/setjmp.h>
+#include <bits/wordsize.h>
+#if defined _LIBC && ( defined IS_IN_libc || defined NOT_IN_libc )
+#include <bits/uClibc_pthread.h>
+#endif
+
+
+/* Detach state.  */
+enum
+{
+  PTHREAD_CREATE_JOINABLE,
+#define PTHREAD_CREATE_JOINABLE        PTHREAD_CREATE_JOINABLE
+  PTHREAD_CREATE_DETACHED
+#define PTHREAD_CREATE_DETACHED        PTHREAD_CREATE_DETACHED
+};
+
+
+/* Mutex types.  */
+enum
+{
+  PTHREAD_MUTEX_TIMED_NP,
+  PTHREAD_MUTEX_RECURSIVE_NP,
+  PTHREAD_MUTEX_ERRORCHECK_NP,
+  PTHREAD_MUTEX_ADAPTIVE_NP
+#if defined __USE_UNIX98 || defined __USE_XOPEN2K8
+  ,
+  PTHREAD_MUTEX_NORMAL = PTHREAD_MUTEX_TIMED_NP,
+  PTHREAD_MUTEX_RECURSIVE = PTHREAD_MUTEX_RECURSIVE_NP,
+  PTHREAD_MUTEX_ERRORCHECK = PTHREAD_MUTEX_ERRORCHECK_NP,
+  PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL
+#endif
+#ifdef __USE_GNU
+  /* For compatibility.  */
+  , PTHREAD_MUTEX_FAST_NP = PTHREAD_MUTEX_TIMED_NP
+#endif
+};
+
+
+#ifdef __USE_XOPEN2K
+/* Robust mutex or not flags.  */
+enum
+{
+  PTHREAD_MUTEX_STALLED,
+  PTHREAD_MUTEX_STALLED_NP = PTHREAD_MUTEX_STALLED,
+  PTHREAD_MUTEX_ROBUST,
+  PTHREAD_MUTEX_ROBUST_NP = PTHREAD_MUTEX_ROBUST
+};
+#endif
+
+
+#ifdef __USE_UNIX98
+/* Mutex protocols.  */
+enum
+{
+  PTHREAD_PRIO_NONE,
+  PTHREAD_PRIO_INHERIT,
+  PTHREAD_PRIO_PROTECT
+};
+#endif
+
+
+/* Mutex initializers.  */
+#if __WORDSIZE == 64
+# define PTHREAD_MUTEX_INITIALIZER \
+  { { 0, 0, 0, 0, 0, 0, { 0, 0 } } }
+# ifdef __USE_GNU
+#  define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP \
+  { { 0, 0, 0, 0, PTHREAD_MUTEX_RECURSIVE_NP, 0, { 0, 0 } } }
+#  define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP \
+  { { 0, 0, 0, 0, PTHREAD_MUTEX_ERRORCHECK_NP, 0, { 0, 0 } } }
+#  define PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP \
+  { { 0, 0, 0, 0, PTHREAD_MUTEX_ADAPTIVE_NP, 0, { 0, 0 } } }
+# endif
+#else
+# define PTHREAD_MUTEX_INITIALIZER \
+  { { 0, 0, 0, 0, 0, { 0 } } }
+# ifdef __USE_GNU
+#  define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP \
+  { { 0, 0, 0, PTHREAD_MUTEX_RECURSIVE_NP, 0, { 0 } } }
+#  define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP \
+  { { 0, 0, 0, PTHREAD_MUTEX_ERRORCHECK_NP, 0, { 0 } } }
+#  define PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP \
+  { { 0, 0, 0, PTHREAD_MUTEX_ADAPTIVE_NP, 0, { 0 } } }
+# endif
+#endif
+
+
+/* Read-write lock types.  */
+#if defined __USE_UNIX98 || defined __USE_XOPEN2K
+enum
+{
+  PTHREAD_RWLOCK_PREFER_READER_NP,
+  PTHREAD_RWLOCK_PREFER_WRITER_NP,
+  PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP,
+  PTHREAD_RWLOCK_DEFAULT_NP = PTHREAD_RWLOCK_PREFER_READER_NP
+};
+
+/* Read-write lock initializers.  */
+# define PTHREAD_RWLOCK_INITIALIZER \
+  { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }
+# ifdef __USE_GNU
+#  if __WORDSIZE == 64
+#   define PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP \
+  { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                                          \
+       PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP } }
+#  else
+#   if __BYTE_ORDER == __LITTLE_ENDIAN
+#    define PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP \
+  { { 0, 0, 0, 0, 0, 0, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP, \
+      0, 0, 0, 0 } }
+#   else
+#    define PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP \
+  { { 0, 0, 0, 0, 0, 0, 0, 0, 0, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP,\
+      0 } }
+#   endif
+#  endif
+# endif
+#endif  /* Unix98 or XOpen2K */
+
+
+/* Scheduler inheritance.  */
+enum
+{
+  PTHREAD_INHERIT_SCHED,
+#define PTHREAD_INHERIT_SCHED   PTHREAD_INHERIT_SCHED
+  PTHREAD_EXPLICIT_SCHED
+#define PTHREAD_EXPLICIT_SCHED  PTHREAD_EXPLICIT_SCHED
+};
+
+
+/* Scope handling.  */
+enum
+{
+  PTHREAD_SCOPE_SYSTEM,
+#define PTHREAD_SCOPE_SYSTEM    PTHREAD_SCOPE_SYSTEM
+  PTHREAD_SCOPE_PROCESS
+#define PTHREAD_SCOPE_PROCESS   PTHREAD_SCOPE_PROCESS
+};
+
+
+/* Process shared or private flag.  */
+enum
+{
+  PTHREAD_PROCESS_PRIVATE,
+#define PTHREAD_PROCESS_PRIVATE PTHREAD_PROCESS_PRIVATE
+  PTHREAD_PROCESS_SHARED
+#define PTHREAD_PROCESS_SHARED  PTHREAD_PROCESS_SHARED
+};
+
+
+
+/* Conditional variable handling.  */
+#define PTHREAD_COND_INITIALIZER { { 0, 0, 0, 0, 0, (void *) 0, 0, 0 } }
+
+
+/* Cleanup buffers */
+struct _pthread_cleanup_buffer
+{
+  void (*__routine) (void *);             /* Function to call.  */
+  void *__arg;                            /* Its argument.  */
+  int __canceltype;                       /* Saved cancellation type. */
+  struct _pthread_cleanup_buffer *__prev; /* Chaining of cleanup functions.  */
+};
+
+/* Cancellation */
+enum
+{
+  PTHREAD_CANCEL_ENABLE,
+#define PTHREAD_CANCEL_ENABLE   PTHREAD_CANCEL_ENABLE
+  PTHREAD_CANCEL_DISABLE
+#define PTHREAD_CANCEL_DISABLE  PTHREAD_CANCEL_DISABLE
+};
+enum
+{
+  PTHREAD_CANCEL_DEFERRED,
+#define PTHREAD_CANCEL_DEFERRED        PTHREAD_CANCEL_DEFERRED
+  PTHREAD_CANCEL_ASYNCHRONOUS
+#define PTHREAD_CANCEL_ASYNCHRONOUS    PTHREAD_CANCEL_ASYNCHRONOUS
+};
+#define PTHREAD_CANCELED ((void *) -1)
+
+
+/* Single execution handling.  */
+#define PTHREAD_ONCE_INIT 0
+
+
+#ifdef __USE_XOPEN2K
+/* Value returned by 'pthread_barrier_wait' for one of the threads after
+   the required number of threads have called this function.
+   -1 is distinct from 0 and all errno constants */
+# define PTHREAD_BARRIER_SERIAL_THREAD -1
+#endif
+
+
+__BEGIN_DECLS
+
+/* Create a new thread, starting with execution of START-ROUTINE
+   getting passed ARG.  Creation attributed come from ATTR.  The new
+   handle is stored in *NEWTHREAD.  */
+extern int pthread_create (pthread_t *__restrict __newthread,
+                          __const pthread_attr_t *__restrict __attr,
+                          void *(*__start_routine) (void *),
+                          void *__restrict __arg) __THROW __nonnull ((1, 3));
+
+/* Terminate calling thread.
+
+   The registered cleanup handlers are called via exception handling
+   so we cannot mark this function with __THROW.*/
+extern void pthread_exit (void *__retval) __attribute__ ((__noreturn__));
+
+/* Make calling thread wait for termination of the thread TH.  The
+   exit status of the thread is stored in *THREAD_RETURN, if THREAD_RETURN
+   is not NULL.
+
+   This function is a cancellation point and therefore not marked with
+   __THROW.  */
+extern int pthread_join (pthread_t __th, void **__thread_return);
+
+#ifdef __USE_GNU
+/* Check whether thread TH has terminated.  If yes return the status of
+   the thread in *THREAD_RETURN, if THREAD_RETURN is not NULL.  */
+extern int pthread_tryjoin_np (pthread_t __th, void **__thread_return) __THROW;
+
+/* Make calling thread wait for termination of the thread TH, but only
+   until TIMEOUT.  The exit status of the thread is stored in
+   *THREAD_RETURN, if THREAD_RETURN is not NULL.
+
+   This function is a cancellation point and therefore not marked with
+   __THROW.  */
+extern int pthread_timedjoin_np (pthread_t __th, void **__thread_return,
+                                __const struct timespec *__abstime);
+#endif
+
+/* Indicate that the thread TH is never to be joined with PTHREAD_JOIN.
+   The resources of TH will therefore be freed immediately when it
+   terminates, instead of waiting for another thread to perform PTHREAD_JOIN
+   on it.  */
+extern int pthread_detach (pthread_t __th) __THROW;
+
+
+/* Obtain the identifier of the current thread.  */
+extern pthread_t pthread_self (void) __THROW __attribute__ ((__const__));
+
+/* Compare two thread identifiers.  */
+extern int pthread_equal (pthread_t __thread1, pthread_t __thread2) __THROW;
+
+
+/* Thread attribute handling.  */
+
+/* Initialize thread attribute *ATTR with default attributes
+   (detachstate is PTHREAD_JOINABLE, scheduling policy is SCHED_OTHER,
+    no user-provided stack).  */
+extern int pthread_attr_init (pthread_attr_t *__attr) __THROW __nonnull ((1));
+
+/* Destroy thread attribute *ATTR.  */
+extern int pthread_attr_destroy (pthread_attr_t *__attr)
+     __THROW __nonnull ((1));
+
+/* Get detach state attribute.  */
+extern int pthread_attr_getdetachstate (__const pthread_attr_t *__attr,
+                                       int *__detachstate)
+     __THROW __nonnull ((1, 2));
+
+/* Set detach state attribute.  */
+extern int pthread_attr_setdetachstate (pthread_attr_t *__attr,
+                                       int __detachstate)
+     __THROW __nonnull ((1));
+
+
+/* Get the size of the guard area created for stack overflow protection.  */
+extern int pthread_attr_getguardsize (__const pthread_attr_t *__attr,
+                                     size_t *__guardsize)
+     __THROW __nonnull ((1, 2));
+
+/* Set the size of the guard area created for stack overflow protection.  */
+extern int pthread_attr_setguardsize (pthread_attr_t *__attr,
+                                     size_t __guardsize)
+     __THROW __nonnull ((1));
+
+
+/* Return in *PARAM the scheduling parameters of *ATTR.  */
+extern int pthread_attr_getschedparam (__const pthread_attr_t *__restrict
+                                      __attr,
+                                      struct sched_param *__restrict __param)
+     __THROW __nonnull ((1, 2));
+
+/* Set scheduling parameters (priority, etc) in *ATTR according to PARAM.  */
+extern int pthread_attr_setschedparam (pthread_attr_t *__restrict __attr,
+                                      __const struct sched_param *__restrict
+                                      __param) __THROW __nonnull ((1, 2));
+
+/* Return in *POLICY the scheduling policy of *ATTR.  */
+extern int pthread_attr_getschedpolicy (__const pthread_attr_t *__restrict
+                                       __attr, int *__restrict __policy)
+     __THROW __nonnull ((1, 2));
+
+/* Set scheduling policy in *ATTR according to POLICY.  */
+extern int pthread_attr_setschedpolicy (pthread_attr_t *__attr, int __policy)
+     __THROW __nonnull ((1));
+
+/* Return in *INHERIT the scheduling inheritance mode of *ATTR.  */
+extern int pthread_attr_getinheritsched (__const pthread_attr_t *__restrict
+                                        __attr, int *__restrict __inherit)
+     __THROW __nonnull ((1, 2));
+
+/* Set scheduling inheritance mode in *ATTR according to INHERIT.  */
+extern int pthread_attr_setinheritsched (pthread_attr_t *__attr,
+                                        int __inherit)
+     __THROW __nonnull ((1));
+
+
+/* Return in *SCOPE the scheduling contention scope of *ATTR.  */
+extern int pthread_attr_getscope (__const pthread_attr_t *__restrict __attr,
+                                 int *__restrict __scope)
+     __THROW __nonnull ((1, 2));
+
+/* Set scheduling contention scope in *ATTR according to SCOPE.  */
+extern int pthread_attr_setscope (pthread_attr_t *__attr, int __scope)
+     __THROW __nonnull ((1));
+
+/* Return the previously set address for the stack.  */
+extern int pthread_attr_getstackaddr (__const pthread_attr_t *__restrict
+                                     __attr, void **__restrict __stackaddr)
+     __THROW __nonnull ((1, 2)) __attribute_deprecated__;
+
+/* Set the starting address of the stack of the thread to be created.
+   Depending on whether the stack grows up or down the value must either
+   be higher or lower than all the address in the memory block.  The
+   minimal size of the block must be PTHREAD_STACK_MIN.  */
+extern int pthread_attr_setstackaddr (pthread_attr_t *__attr,
+                                     void *__stackaddr)
+     __THROW __nonnull ((1)) __attribute_deprecated__;
+
+/* Return the currently used minimal stack size.  */
+extern int pthread_attr_getstacksize (__const pthread_attr_t *__restrict
+                                     __attr, size_t *__restrict __stacksize)
+     __THROW __nonnull ((1, 2));
+
+/* Add information about the minimum stack size needed for the thread
+   to be started.  This size must never be less than PTHREAD_STACK_MIN
+   and must also not exceed the system limits.  */
+extern int pthread_attr_setstacksize (pthread_attr_t *__attr,
+                                     size_t __stacksize)
+     __THROW __nonnull ((1));
+
+#ifdef __USE_XOPEN2K
+/* Return the previously set address for the stack.  */
+extern int pthread_attr_getstack (__const pthread_attr_t *__restrict __attr,
+                                 void **__restrict __stackaddr,
+                                 size_t *__restrict __stacksize)
+     __THROW __nonnull ((1, 2, 3));
+
+/* The following two interfaces are intended to replace the last two.  They
+   require setting the address as well as the size since only setting the
+   address will make the implementation on some architectures impossible.  */
+extern int pthread_attr_setstack (pthread_attr_t *__attr, void *__stackaddr,
+                                 size_t __stacksize) __THROW __nonnull ((1));
+#endif
+
+#ifdef __USE_GNU
+/* Thread created with attribute ATTR will be limited to run only on
+   the processors represented in CPUSET.  */
+extern int pthread_attr_setaffinity_np (pthread_attr_t *__attr,
+                                       size_t __cpusetsize,
+                                       __const cpu_set_t *__cpuset)
+     __THROW __nonnull ((1, 3));
+
+/* Get bit set in CPUSET representing the processors threads created with
+   ATTR can run on.  */
+extern int pthread_attr_getaffinity_np (__const pthread_attr_t *__attr,
+                                       size_t __cpusetsize,
+                                       cpu_set_t *__cpuset)
+     __THROW __nonnull ((1, 3));
+
+
+/* Initialize thread attribute *ATTR with attributes corresponding to the
+   already running thread TH.  It shall be called on uninitialized ATTR
+   and destroyed with pthread_attr_destroy when no longer needed.  */
+extern int pthread_getattr_np (pthread_t __th, pthread_attr_t *__attr)
+     __THROW __nonnull ((2));
+#endif
+
+
+/* Functions for scheduling control.  */
+
+/* Set the scheduling parameters for TARGET_THREAD according to POLICY
+   and *PARAM.  */
+extern int pthread_setschedparam (pthread_t __target_thread, int __policy,
+                                 __const struct sched_param *__param)
+     __THROW __nonnull ((3));
+
+/* Return in *POLICY and *PARAM the scheduling parameters for TARGET_THREAD. */
+extern int pthread_getschedparam (pthread_t __target_thread,
+                                 int *__restrict __policy,
+                                 struct sched_param *__restrict __param)
+     __THROW __nonnull ((2, 3));
+
+/* Set the scheduling priority for TARGET_THREAD.  */
+extern int pthread_setschedprio (pthread_t __target_thread, int __prio)
+     __THROW;
+
+
+#ifdef __USE_UNIX98
+/* Determine level of concurrency.  */
+extern int pthread_getconcurrency (void) __THROW;
+
+/* Set new concurrency level to LEVEL.  */
+extern int pthread_setconcurrency (int __level) __THROW;
+#endif
+
+#ifdef __USE_GNU
+/* Yield the processor to another thread or process.
+   This function is similar to the POSIX `sched_yield' function but
+   might be differently implemented in the case of a m-on-n thread
+   implementation.  */
+extern int pthread_yield (void) __THROW;
+
+
+/* Limit specified thread TH to run only on the processors represented
+   in CPUSET.  */
+extern int pthread_setaffinity_np (pthread_t __th, size_t __cpusetsize,
+                                  __const cpu_set_t *__cpuset)
+     __THROW __nonnull ((3));
+
+/* Get bit set in CPUSET representing the processors TH can run on.  */
+extern int pthread_getaffinity_np (pthread_t __th, size_t __cpusetsize,
+                                  cpu_set_t *__cpuset)
+     __THROW __nonnull ((3));
+#endif
+
+
+/* Functions for handling initialization.  */
+
+/* Guarantee that the initialization function INIT_ROUTINE will be called
+   only once, even if pthread_once is executed several times with the
+   same ONCE_CONTROL argument. ONCE_CONTROL must point to a static or
+   extern variable initialized to PTHREAD_ONCE_INIT.
+
+   The initialization functions might throw exception which is why
+   this function is not marked with __THROW.  */
+extern int pthread_once (pthread_once_t *__once_control,
+                        void (*__init_routine) (void)) __nonnull ((1, 2));
+
+
+/* Functions for handling cancellation.
+
+   Note that these functions are explicitly not marked to not throw an
+   exception in C++ code.  If cancellation is implemented by unwinding
+   this is necessary to have the compiler generate the unwind information.  */
+
+/* Set cancelability state of current thread to STATE, returning old
+   state in *OLDSTATE if OLDSTATE is not NULL.  */
+extern int pthread_setcancelstate (int __state, int *__oldstate);
+
+/* Set cancellation state of current thread to TYPE, returning the old
+   type in *OLDTYPE if OLDTYPE is not NULL.  */
+extern int pthread_setcanceltype (int __type, int *__oldtype);
+
+/* Cancel THREAD immediately or at the next possibility.  */
+extern int pthread_cancel (pthread_t __th);
+
+/* Test for pending cancellation for the current thread and terminate
+   the thread as per pthread_exit(PTHREAD_CANCELED) if it has been
+   cancelled.  */
+extern void pthread_testcancel (void);
+
+
+/* Cancellation handling with integration into exception handling.  */
+
+typedef struct
+{
+  struct
+  {
+    __jmp_buf __cancel_jmp_buf;
+    int __mask_was_saved;
+  } __cancel_jmp_buf[1];
+  void *__pad[4];
+} __pthread_unwind_buf_t __attribute__ ((__aligned__));
+
+/* No special attributes by default.  */
+#ifndef __cleanup_fct_attribute
+# define __cleanup_fct_attribute
+#endif
+
+
+/* Structure to hold the cleanup handler information.  */
+struct __pthread_cleanup_frame
+{
+  void (*__cancel_routine) (void *);
+  void *__cancel_arg;
+  int __do_it;
+  int __cancel_type;
+};
+
+#if defined __GNUC__ && defined __EXCEPTIONS
+# ifdef __cplusplus
+/* Class to handle cancellation handler invocation.  */
+class __pthread_cleanup_class
+{
+  void (*__cancel_routine) (void *);
+  void *__cancel_arg;
+  int __do_it;
+  int __cancel_type;
+
+ public:
+  __pthread_cleanup_class (void (*__fct) (void *), void *__arg)
+    : __cancel_routine (__fct), __cancel_arg (__arg), __do_it (1) { }
+  ~__pthread_cleanup_class () { if (__do_it) __cancel_routine (__cancel_arg); }
+  void __setdoit (int __newval) { __do_it = __newval; }
+  void __defer () { pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED,
+                                          &__cancel_type); }
+  void __restore () const { pthread_setcanceltype (__cancel_type, 0); }
+};
+
+/* Install a cleanup handler: ROUTINE will be called with arguments ARG
+   when the thread is canceled or calls pthread_exit.  ROUTINE will also
+   be called with arguments ARG when the matching pthread_cleanup_pop
+   is executed with non-zero EXECUTE argument.
+
+   pthread_cleanup_push and pthread_cleanup_pop are macros and must always
+   be used in matching pairs at the same nesting level of braces.  */
+#  define pthread_cleanup_push(routine, arg) \
+  do {                                                                       \
+    __pthread_cleanup_class __clframe (routine, arg)
+
+/* Remove a cleanup handler installed by the matching pthread_cleanup_push.
+   If EXECUTE is non-zero, the handler function is called. */
+#  define pthread_cleanup_pop(execute) \
+    __clframe.__setdoit (execute);                                           \
+  } while (0)
+
+#  ifdef __USE_GNU
+/* Install a cleanup handler as pthread_cleanup_push does, but also
+   saves the current cancellation type and sets it to deferred
+   cancellation.  */
+#   define pthread_cleanup_push_defer_np(routine, arg) \
+  do {                                                                       \
+    __pthread_cleanup_class __clframe (routine, arg);                        \
+    __clframe.__defer ()
+
+/* Remove a cleanup handler as pthread_cleanup_pop does, but also
+   restores the cancellation type that was in effect when the matching
+   pthread_cleanup_push_defer was called.  */
+#   define pthread_cleanup_pop_restore_np(execute) \
+    __clframe.__restore ();                                                  \
+    __clframe.__setdoit (execute);                                           \
+  } while (0)
+#  endif
+# else
+/* Function called to call the cleanup handler.  As an extern inline
+   function the compiler is free to decide inlining the change when
+   needed or fall back on the copy which must exist somewhere
+   else.  */
+__extern_inline void
+__pthread_cleanup_routine (struct __pthread_cleanup_frame *__frame)
+{
+  if (__frame->__do_it)
+    __frame->__cancel_routine (__frame->__cancel_arg);
+}
+
+/* Install a cleanup handler: ROUTINE will be called with arguments ARG
+   when the thread is canceled or calls pthread_exit.  ROUTINE will also
+   be called with arguments ARG when the matching pthread_cleanup_pop
+   is executed with non-zero EXECUTE argument.
+
+   pthread_cleanup_push and pthread_cleanup_pop are macros and must always
+   be used in matching pairs at the same nesting level of braces.  */
+#  define pthread_cleanup_push(routine, arg) \
+  do {                                                                       \
+    struct __pthread_cleanup_frame __clframe                                 \
+      __attribute__ ((__cleanup__ (__pthread_cleanup_routine)))                      \
+      = { .__cancel_routine = (routine), .__cancel_arg = (arg),                      \
+         .__do_it = 1 };
+
+/* Remove a cleanup handler installed by the matching pthread_cleanup_push.
+   If EXECUTE is non-zero, the handler function is called. */
+#  define pthread_cleanup_pop(execute) \
+    __clframe.__do_it = (execute);                                           \
+  } while (0)
+
+#  ifdef __USE_GNU
+/* Install a cleanup handler as pthread_cleanup_push does, but also
+   saves the current cancellation type and sets it to deferred
+   cancellation.  */
+#   define pthread_cleanup_push_defer_np(routine, arg) \
+  do {                                                                       \
+    struct __pthread_cleanup_frame __clframe                                 \
+      __attribute__ ((__cleanup__ (__pthread_cleanup_routine)))                      \
+      = { .__cancel_routine = (routine), .__cancel_arg = (arg),                      \
+         .__do_it = 1 };                                                     \
+    (void) pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED,                   \
+                                 &__clframe.__cancel_type)
+
+/* Remove a cleanup handler as pthread_cleanup_pop does, but also
+   restores the cancellation type that was in effect when the matching
+   pthread_cleanup_push_defer was called.  */
+#   define pthread_cleanup_pop_restore_np(execute) \
+    (void) pthread_setcanceltype (__clframe.__cancel_type, NULL);            \
+    __clframe.__do_it = (execute);                                           \
+  } while (0)
+#  endif
+# endif
+#else
+/* Install a cleanup handler: ROUTINE will be called with arguments ARG
+   when the thread is canceled or calls pthread_exit.  ROUTINE will also
+   be called with arguments ARG when the matching pthread_cleanup_pop
+   is executed with non-zero EXECUTE argument.
+
+   pthread_cleanup_push and pthread_cleanup_pop are macros and must always
+   be used in matching pairs at the same nesting level of braces.  */
+# define pthread_cleanup_push(routine, arg) \
+  do {                                                                       \
+    __pthread_unwind_buf_t __cancel_buf;                                     \
+    void (*__cancel_routine) (void *) = (routine);                           \
+    void *__cancel_arg = (arg);                                                      \
+    int not_first_call = __sigsetjmp ((struct __jmp_buf_tag *) (void *)              \
+                                     __cancel_buf.__cancel_jmp_buf, 0);      \
+    if (__builtin_expect (not_first_call, 0))                                \
+      {                                                                              \
+       __cancel_routine (__cancel_arg);                                      \
+       __pthread_unwind_next (&__cancel_buf);                                \
+       /* NOTREACHED */                                                      \
+      }                                                                              \
+                                                                             \
+    __pthread_register_cancel (&__cancel_buf);                               \
+    do {
+extern void __pthread_register_cancel (__pthread_unwind_buf_t *__buf)
+     __cleanup_fct_attribute;
+
+/* Remove a cleanup handler installed by the matching pthread_cleanup_push.
+   If EXECUTE is non-zero, the handler function is called. */
+# define pthread_cleanup_pop(execute) \
+      do { } while (0);/* Empty to allow label before pthread_cleanup_pop.  */\
+    } while (0);                                                             \
+    __pthread_unregister_cancel (&__cancel_buf);                             \
+    if (execute)                                                             \
+      __cancel_routine (__cancel_arg);                                       \
+  } while (0)
+extern void __pthread_unregister_cancel (__pthread_unwind_buf_t *__buf)
+  __cleanup_fct_attribute;
+
+# ifdef __USE_GNU
+/* Install a cleanup handler as pthread_cleanup_push does, but also
+   saves the current cancellation type and sets it to deferred
+   cancellation.  */
+#  define pthread_cleanup_push_defer_np(routine, arg) \
+  do {                                                                       \
+    __pthread_unwind_buf_t __cancel_buf;                                     \
+    void (*__cancel_routine) (void *) = (routine);                           \
+    void *__cancel_arg = (arg);                                                      \
+    int not_first_call = __sigsetjmp ((struct __jmp_buf_tag *) (void *)              \
+                                     __cancel_buf.__cancel_jmp_buf, 0);      \
+    if (__builtin_expect (not_first_call, 0))                                \
+      {                                                                              \
+       __cancel_routine (__cancel_arg);                                      \
+       __pthread_unwind_next (&__cancel_buf);                                \
+       /* NOTREACHED */                                                      \
+      }                                                                              \
+                                                                             \
+    __pthread_register_cancel_defer (&__cancel_buf);                         \
+    do {
+extern void __pthread_register_cancel_defer (__pthread_unwind_buf_t *__buf)
+     __cleanup_fct_attribute;
+
+/* Remove a cleanup handler as pthread_cleanup_pop does, but also
+   restores the cancellation type that was in effect when the matching
+   pthread_cleanup_push_defer was called.  */
+#  define pthread_cleanup_pop_restore_np(execute) \
+      do { } while (0);/* Empty to allow label before pthread_cleanup_pop.  */\
+    } while (0);                                                             \
+    __pthread_unregister_cancel_restore (&__cancel_buf);                     \
+    if (execute)                                                             \
+      __cancel_routine (__cancel_arg);                                       \
+  } while (0)
+extern void __pthread_unregister_cancel_restore (__pthread_unwind_buf_t *__buf)
+  __cleanup_fct_attribute;
+# endif
+
+/* Internal interface to initiate cleanup.  */
+extern void __pthread_unwind_next (__pthread_unwind_buf_t *__buf)
+     __cleanup_fct_attribute __attribute__ ((__noreturn__))
+# ifndef SHARED
+     __attribute__ ((__weak__))
+# endif
+     ;
+#endif
+
+/* Function used in the macros.  */
+struct __jmp_buf_tag;
+extern int __sigsetjmp (struct __jmp_buf_tag *__env, int __savemask) __THROW;
+
+
+/* Mutex handling.  */
+
+/* Initialize a mutex.  */
+extern int pthread_mutex_init (pthread_mutex_t *__mutex,
+                              __const pthread_mutexattr_t *__mutexattr)
+     __THROW __nonnull ((1));
+
+/* Destroy a mutex.  */
+extern int pthread_mutex_destroy (pthread_mutex_t *__mutex)
+     __THROW __nonnull ((1));
+
+/* Try locking a mutex.  */
+extern int pthread_mutex_trylock (pthread_mutex_t *__mutex)
+     __THROW __nonnull ((1));
+
+/* Lock a mutex.  */
+extern int pthread_mutex_lock (pthread_mutex_t *__mutex)
+     __THROW __nonnull ((1));
+
+#ifdef __USE_XOPEN2K
+/* Wait until lock becomes available, or specified time passes. */
+extern int pthread_mutex_timedlock (pthread_mutex_t *__restrict __mutex,
+                                   __const struct timespec *__restrict
+                                   __abstime) __THROW __nonnull ((1, 2));
+#endif
+
+/* Unlock a mutex.  */
+extern int pthread_mutex_unlock (pthread_mutex_t *__mutex)
+     __THROW __nonnull ((1));
+
+
+/* Get the priority ceiling of MUTEX.  */
+extern int pthread_mutex_getprioceiling (__const pthread_mutex_t *
+                                        __restrict __mutex,
+                                        int *__restrict __prioceiling)
+     __THROW __nonnull ((1, 2));
+
+/* Set the priority ceiling of MUTEX to PRIOCEILING, return old
+   priority ceiling value in *OLD_CEILING.  */
+extern int pthread_mutex_setprioceiling (pthread_mutex_t *__restrict __mutex,
+                                        int __prioceiling,
+                                        int *__restrict __old_ceiling)
+     __THROW __nonnull ((1, 3));
+
+
+#ifdef __USE_XOPEN2K8
+/* Declare the state protected by MUTEX as consistent.  */
+extern int pthread_mutex_consistent (pthread_mutex_t *__mutex)
+     __THROW __nonnull ((1));
+# ifdef __USE_GNU
+extern int pthread_mutex_consistent_np (pthread_mutex_t *__mutex)
+     __THROW __nonnull ((1));
+# endif
+#endif
+
+
+/* Functions for handling mutex attributes.  */
+
+/* Initialize mutex attribute object ATTR with default attributes
+   (kind is PTHREAD_MUTEX_TIMED_NP).  */
+extern int pthread_mutexattr_init (pthread_mutexattr_t *__attr)
+     __THROW __nonnull ((1));
+
+/* Destroy mutex attribute object ATTR.  */
+extern int pthread_mutexattr_destroy (pthread_mutexattr_t *__attr)
+     __THROW __nonnull ((1));
+
+/* Get the process-shared flag of the mutex attribute ATTR.  */
+extern int pthread_mutexattr_getpshared (__const pthread_mutexattr_t *
+                                        __restrict __attr,
+                                        int *__restrict __pshared)
+     __THROW __nonnull ((1, 2));
+
+/* Set the process-shared flag of the mutex attribute ATTR.  */
+extern int pthread_mutexattr_setpshared (pthread_mutexattr_t *__attr,
+                                        int __pshared)
+     __THROW __nonnull ((1));
+
+#if defined __USE_UNIX98 || defined __USE_XOPEN2K8
+/* Return in *KIND the mutex kind attribute in *ATTR.  */
+extern int pthread_mutexattr_gettype (__const pthread_mutexattr_t *__restrict
+                                     __attr, int *__restrict __kind)
+     __THROW __nonnull ((1, 2));
+
+/* Set the mutex kind attribute in *ATTR to KIND (either PTHREAD_MUTEX_NORMAL,
+   PTHREAD_MUTEX_RECURSIVE, PTHREAD_MUTEX_ERRORCHECK, or
+   PTHREAD_MUTEX_DEFAULT).  */
+extern int pthread_mutexattr_settype (pthread_mutexattr_t *__attr, int __kind)
+     __THROW __nonnull ((1));
+#endif
+
+/* Return in *PROTOCOL the mutex protocol attribute in *ATTR.  */
+extern int pthread_mutexattr_getprotocol (__const pthread_mutexattr_t *
+                                         __restrict __attr,
+                                         int *__restrict __protocol)
+     __THROW __nonnull ((1, 2));
+
+/* Set the mutex protocol attribute in *ATTR to PROTOCOL (either
+   PTHREAD_PRIO_NONE, PTHREAD_PRIO_INHERIT, or PTHREAD_PRIO_PROTECT).  */
+extern int pthread_mutexattr_setprotocol (pthread_mutexattr_t *__attr,
+                                         int __protocol)
+     __THROW __nonnull ((1));
+
+/* Return in *PRIOCEILING the mutex prioceiling attribute in *ATTR.  */
+extern int pthread_mutexattr_getprioceiling (__const pthread_mutexattr_t *
+                                            __restrict __attr,
+                                            int *__restrict __prioceiling)
+     __THROW __nonnull ((1, 2));
+
+/* Set the mutex prioceiling attribute in *ATTR to PRIOCEILING.  */
+extern int pthread_mutexattr_setprioceiling (pthread_mutexattr_t *__attr,
+                                            int __prioceiling)
+     __THROW __nonnull ((1));
+
+#ifdef __USE_XOPEN2K
+/* Get the robustness flag of the mutex attribute ATTR.  */
+extern int pthread_mutexattr_getrobust (__const pthread_mutexattr_t *__attr,
+                                       int *__robustness)
+     __THROW __nonnull ((1, 2));
+# ifdef __USE_GNU
+extern int pthread_mutexattr_getrobust_np (__const pthread_mutexattr_t *__attr,
+                                          int *__robustness)
+     __THROW __nonnull ((1, 2));
+# endif
+
+/* Set the robustness flag of the mutex attribute ATTR.  */
+extern int pthread_mutexattr_setrobust (pthread_mutexattr_t *__attr,
+                                       int __robustness)
+     __THROW __nonnull ((1));
+# ifdef __USE_GNU
+extern int pthread_mutexattr_setrobust_np (pthread_mutexattr_t *__attr,
+                                          int __robustness)
+     __THROW __nonnull ((1));
+# endif
+#endif
+
+
+#if defined __USE_UNIX98 || defined __USE_XOPEN2K
+/* Functions for handling read-write locks.  */
+
+/* Initialize read-write lock RWLOCK using attributes ATTR, or use
+   the default values if later is NULL.  */
+extern int pthread_rwlock_init (pthread_rwlock_t *__restrict __rwlock,
+                               __const pthread_rwlockattr_t *__restrict
+                               __attr) __THROW __nonnull ((1));
+
+/* Destroy read-write lock RWLOCK.  */
+extern int pthread_rwlock_destroy (pthread_rwlock_t *__rwlock)
+     __THROW __nonnull ((1));
+
+/* Acquire read lock for RWLOCK.  */
+extern int pthread_rwlock_rdlock (pthread_rwlock_t *__rwlock)
+     __THROW __nonnull ((1));
+
+/* Try to acquire read lock for RWLOCK.  */
+extern int pthread_rwlock_tryrdlock (pthread_rwlock_t *__rwlock)
+  __THROW __nonnull ((1));
+
+# ifdef __USE_XOPEN2K
+/* Try to acquire read lock for RWLOCK or return after specfied time.  */
+extern int pthread_rwlock_timedrdlock (pthread_rwlock_t *__restrict __rwlock,
+                                      __const struct timespec *__restrict
+                                      __abstime) __THROW __nonnull ((1, 2));
+# endif
+
+/* Acquire write lock for RWLOCK.  */
+extern int pthread_rwlock_wrlock (pthread_rwlock_t *__rwlock)
+     __THROW __nonnull ((1));
+
+/* Try to acquire write lock for RWLOCK.  */
+extern int pthread_rwlock_trywrlock (pthread_rwlock_t *__rwlock)
+     __THROW __nonnull ((1));
+
+# ifdef __USE_XOPEN2K
+/* Try to acquire write lock for RWLOCK or return after specfied time.  */
+extern int pthread_rwlock_timedwrlock (pthread_rwlock_t *__restrict __rwlock,
+                                      __const struct timespec *__restrict
+                                      __abstime) __THROW __nonnull ((1, 2));
+# endif
+
+/* Unlock RWLOCK.  */
+extern int pthread_rwlock_unlock (pthread_rwlock_t *__rwlock)
+     __THROW __nonnull ((1));
+
+
+/* Functions for handling read-write lock attributes.  */
+
+/* Initialize attribute object ATTR with default values.  */
+extern int pthread_rwlockattr_init (pthread_rwlockattr_t *__attr)
+     __THROW __nonnull ((1));
+
+/* Destroy attribute object ATTR.  */
+extern int pthread_rwlockattr_destroy (pthread_rwlockattr_t *__attr)
+     __THROW __nonnull ((1));
+
+/* Return current setting of process-shared attribute of ATTR in PSHARED.  */
+extern int pthread_rwlockattr_getpshared (__const pthread_rwlockattr_t *
+                                         __restrict __attr,
+                                         int *__restrict __pshared)
+     __THROW __nonnull ((1, 2));
+
+/* Set process-shared attribute of ATTR to PSHARED.  */
+extern int pthread_rwlockattr_setpshared (pthread_rwlockattr_t *__attr,
+                                         int __pshared)
+     __THROW __nonnull ((1));
+
+/* Return current setting of reader/writer preference.  */
+extern int pthread_rwlockattr_getkind_np (__const pthread_rwlockattr_t *
+                                         __restrict __attr,
+                                         int *__restrict __pref)
+     __THROW __nonnull ((1, 2));
+
+/* Set reader/write preference.  */
+extern int pthread_rwlockattr_setkind_np (pthread_rwlockattr_t *__attr,
+                                         int __pref) __THROW __nonnull ((1));
+#endif
+
+
+/* Functions for handling conditional variables.  */
+
+/* Initialize condition variable COND using attributes ATTR, or use
+   the default values if later is NULL.  */
+extern int pthread_cond_init (pthread_cond_t *__restrict __cond,
+                             __const pthread_condattr_t *__restrict
+                             __cond_attr) __THROW __nonnull ((1));
+
+/* Destroy condition variable COND.  */
+extern int pthread_cond_destroy (pthread_cond_t *__cond)
+     __THROW __nonnull ((1));
+
+/* Wake up one thread waiting for condition variable COND.  */
+extern int pthread_cond_signal (pthread_cond_t *__cond)
+     __THROW __nonnull ((1));
+
+/* Wake up all threads waiting for condition variables COND.  */
+extern int pthread_cond_broadcast (pthread_cond_t *__cond)
+     __THROW __nonnull ((1));
+
+/* Wait for condition variable COND to be signaled or broadcast.
+   MUTEX is assumed to be locked before.
+
+   This function is a cancellation point and therefore not marked with
+   __THROW.  */
+extern int pthread_cond_wait (pthread_cond_t *__restrict __cond,
+                             pthread_mutex_t *__restrict __mutex)
+     __nonnull ((1, 2));
+
+/* Wait for condition variable COND to be signaled or broadcast until
+   ABSTIME.  MUTEX is assumed to be locked before.  ABSTIME is an
+   absolute time specification; zero is the beginning of the epoch
+   (00:00:00 GMT, January 1, 1970).
+
+   This function is a cancellation point and therefore not marked with
+   __THROW.  */
+extern int pthread_cond_timedwait (pthread_cond_t *__restrict __cond,
+                                  pthread_mutex_t *__restrict __mutex,
+                                  __const struct timespec *__restrict
+                                  __abstime) __nonnull ((1, 2, 3));
+
+/* Functions for handling condition variable attributes.  */
+
+/* Initialize condition variable attribute ATTR.  */
+extern int pthread_condattr_init (pthread_condattr_t *__attr)
+     __THROW __nonnull ((1));
+
+/* Destroy condition variable attribute ATTR.  */
+extern int pthread_condattr_destroy (pthread_condattr_t *__attr)
+     __THROW __nonnull ((1));
+
+/* Get the process-shared flag of the condition variable attribute ATTR.  */
+extern int pthread_condattr_getpshared (__const pthread_condattr_t *
+                                       __restrict __attr,
+                                       int *__restrict __pshared)
+     __THROW __nonnull ((1, 2));
+
+/* Set the process-shared flag of the condition variable attribute ATTR.  */
+extern int pthread_condattr_setpshared (pthread_condattr_t *__attr,
+                                       int __pshared) __THROW __nonnull ((1));
+
+#ifdef __USE_XOPEN2K
+/* Get the clock selected for the conditon variable attribute ATTR.  */
+extern int pthread_condattr_getclock (__const pthread_condattr_t *
+                                     __restrict __attr,
+                                     __clockid_t *__restrict __clock_id)
+     __THROW __nonnull ((1, 2));
+
+/* Set the clock selected for the conditon variable attribute ATTR.  */
+extern int pthread_condattr_setclock (pthread_condattr_t *__attr,
+                                     __clockid_t __clock_id)
+     __THROW __nonnull ((1));
+#endif
+
+
+#ifdef __USE_XOPEN2K
+/* Functions to handle spinlocks.  */
+
+/* Initialize the spinlock LOCK.  If PSHARED is nonzero the spinlock can
+   be shared between different processes.  */
+extern int pthread_spin_init (pthread_spinlock_t *__lock, int __pshared)
+     __THROW __nonnull ((1));
+
+/* Destroy the spinlock LOCK.  */
+extern int pthread_spin_destroy (pthread_spinlock_t *__lock)
+     __THROW __nonnull ((1));
+
+/* Wait until spinlock LOCK is retrieved.  */
+extern int pthread_spin_lock (pthread_spinlock_t *__lock)
+     __THROW __nonnull ((1));
+
+/* Try to lock spinlock LOCK.  */
+extern int pthread_spin_trylock (pthread_spinlock_t *__lock)
+     __THROW __nonnull ((1));
+
+/* Release spinlock LOCK.  */
+extern int pthread_spin_unlock (pthread_spinlock_t *__lock)
+     __THROW __nonnull ((1));
+
+
+/* Functions to handle barriers.  */
+
+/* Initialize BARRIER with the attributes in ATTR.  The barrier is
+   opened when COUNT waiters arrived.  */
+extern int pthread_barrier_init (pthread_barrier_t *__restrict __barrier,
+                                __const pthread_barrierattr_t *__restrict
+                                __attr, unsigned int __count)
+     __THROW __nonnull ((1));
+
+/* Destroy a previously dynamically initialized barrier BARRIER.  */
+extern int pthread_barrier_destroy (pthread_barrier_t *__barrier)
+     __THROW __nonnull ((1));
+
+/* Wait on barrier BARRIER.  */
+extern int pthread_barrier_wait (pthread_barrier_t *__barrier)
+     __THROW __nonnull ((1));
+
+
+/* Initialize barrier attribute ATTR.  */
+extern int pthread_barrierattr_init (pthread_barrierattr_t *__attr)
+     __THROW __nonnull ((1));
+
+/* Destroy previously dynamically initialized barrier attribute ATTR.  */
+extern int pthread_barrierattr_destroy (pthread_barrierattr_t *__attr)
+     __THROW __nonnull ((1));
+
+/* Get the process-shared flag of the barrier attribute ATTR.  */
+extern int pthread_barrierattr_getpshared (__const pthread_barrierattr_t *
+                                          __restrict __attr,
+                                          int *__restrict __pshared)
+     __THROW __nonnull ((1, 2));
+
+/* Set the process-shared flag of the barrier attribute ATTR.  */
+extern int pthread_barrierattr_setpshared (pthread_barrierattr_t *__attr,
+                                          int __pshared)
+     __THROW __nonnull ((1));
+#endif
+
+
+/* Functions for handling thread-specific data.  */
+
+/* Create a key value identifying a location in the thread-specific
+   data area.  Each thread maintains a distinct thread-specific data
+   area.  DESTR_FUNCTION, if non-NULL, is called with the value
+   associated to that key when the key is destroyed.
+   DESTR_FUNCTION is not called if the value associated is NULL when
+   the key is destroyed.  */
+extern int pthread_key_create (pthread_key_t *__key,
+                              void (*__destr_function) (void *))
+     __THROW __nonnull ((1));
+
+/* Destroy KEY.  */
+extern int pthread_key_delete (pthread_key_t __key) __THROW;
+
+/* Return current value of the thread-specific data slot identified by KEY.  */
+extern void *pthread_getspecific (pthread_key_t __key) __THROW;
+
+/* Store POINTER in the thread-specific data slot identified by KEY. */
+extern int pthread_setspecific (pthread_key_t __key,
+                               __const void *__pointer) __THROW ;
+
+
+#ifdef __USE_XOPEN2K
+/* Get ID of CPU-time clock for thread THREAD_ID.  */
+extern int pthread_getcpuclockid (pthread_t __thread_id,
+                                 __clockid_t *__clock_id)
+     __THROW __nonnull ((2));
+#endif
+
+
+/* Install handlers to be called when a new process is created with FORK.
+   The PREPARE handler is called in the parent process just before performing
+   FORK. The PARENT handler is called in the parent process just after FORK.
+   The CHILD handler is called in the child process.  Each of the three
+   handlers can be NULL, meaning that no handler needs to be called at that
+   point.
+   PTHREAD_ATFORK can be called several times, in which case the PREPARE
+   handlers are called in LIFO order (last added with PTHREAD_ATFORK,
+   first called before FORK), and the PARENT and CHILD handlers are called
+   in FIFO (first added, first called).  */
+
+extern int pthread_atfork (void (*__prepare) (void),
+                          void (*__parent) (void),
+                          void (*__child) (void)) __THROW;
+
+
+#ifdef __USE_EXTERN_INLINES
+/* Optimizations.  */
+__extern_inline int
+__NTH (pthread_equal (pthread_t __thread1, pthread_t __thread2))
+{
+  return __thread1 == __thread2;
+}
+#endif
+
+__END_DECLS
+
+#endif /* pthread.h */
diff --git a/libpthread/nptl/sysdeps/pthread/pthread_barrier_destroy.c b/libpthread/nptl/sysdeps/pthread/pthread_barrier_destroy.c
new file mode 100644 (file)
index 0000000..2afe5b3
--- /dev/null
@@ -0,0 +1,44 @@
+/* Copyright (C) 2002, 2007 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_barrier_destroy (
+     pthread_barrier_t *barrier)
+{
+  struct pthread_barrier *ibarrier;
+  int result = EBUSY;
+
+  ibarrier = (struct pthread_barrier *) barrier;
+
+  lll_lock (ibarrier->lock, ibarrier->private ^ FUTEX_PRIVATE_FLAG);
+
+  if (__builtin_expect (ibarrier->left == ibarrier->init_count, 1))
+    /* The barrier is not used anymore.  */
+    result = 0;
+  else
+    /* Still used, return with an error.  */
+    lll_unlock (ibarrier->lock, ibarrier->private ^ FUTEX_PRIVATE_FLAG);
+
+  return result;
+}
diff --git a/libpthread/nptl/sysdeps/pthread/pthread_barrier_init.c b/libpthread/nptl/sysdeps/pthread/pthread_barrier_init.c
new file mode 100644 (file)
index 0000000..f0396f9
--- /dev/null
@@ -0,0 +1,71 @@
+/* Copyright (C) 2002, 2007 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>
+#include <bits/kernel-features.h>
+
+
+static const struct pthread_barrierattr default_attr =
+  {
+    .pshared = PTHREAD_PROCESS_PRIVATE
+  };
+
+
+int
+pthread_barrier_init (
+     pthread_barrier_t *barrier,
+     const pthread_barrierattr_t *attr,
+     unsigned int count)
+{
+  struct pthread_barrier *ibarrier;
+
+  if (__builtin_expect (count == 0, 0))
+    return EINVAL;
+
+  const struct pthread_barrierattr *iattr
+    = (attr != NULL
+       ? iattr = (struct pthread_barrierattr *) attr
+       : &default_attr);
+
+  if (iattr->pshared != PTHREAD_PROCESS_PRIVATE
+      && __builtin_expect (iattr->pshared != PTHREAD_PROCESS_SHARED, 0))
+    /* Invalid attribute.  */
+    return EINVAL;
+
+  ibarrier = (struct pthread_barrier *) barrier;
+
+  /* Initialize the individual fields.  */
+  ibarrier->lock = LLL_LOCK_INITIALIZER;
+  ibarrier->left = count;
+  ibarrier->init_count = count;
+  ibarrier->curr_event = 0;
+
+#ifdef __ASSUME_PRIVATE_FUTEX
+  ibarrier->private = (iattr->pshared != PTHREAD_PROCESS_PRIVATE
+                      ? 0 : FUTEX_PRIVATE_FLAG);
+#else
+  ibarrier->private = (iattr->pshared != PTHREAD_PROCESS_PRIVATE
+                      ? 0 : THREAD_GETMEM (THREAD_SELF,
+                                           header.private_futex));
+#endif
+
+  return 0;
+}
diff --git a/libpthread/nptl/sysdeps/pthread/pthread_barrier_wait.c b/libpthread/nptl/sysdeps/pthread/pthread_barrier_wait.c
new file mode 100644 (file)
index 0000000..d113539
--- /dev/null
@@ -0,0 +1,79 @@
+/* Copyright (C) 2003, 2004, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <pthreadP.h>
+
+
+/* Wait on barrier.  */
+int
+pthread_barrier_wait (
+     pthread_barrier_t *barrier)
+{
+  struct pthread_barrier *ibarrier = (struct pthread_barrier *) barrier;
+  int result = 0;
+
+  /* Make sure we are alone.  */
+  lll_lock (ibarrier->lock, ibarrier->private ^ FUTEX_PRIVATE_FLAG);
+
+  /* One more arrival.  */
+  --ibarrier->left;
+
+  /* Are these all?  */
+  if (ibarrier->left == 0)
+    {
+      /* Yes. Increment the event counter to avoid invalid wake-ups and
+        tell the current waiters that it is their turn.  */
+      ++ibarrier->curr_event;
+
+      /* Wake up everybody.  */
+      lll_futex_wake (&ibarrier->curr_event, INT_MAX,
+                     ibarrier->private ^ FUTEX_PRIVATE_FLAG);
+
+      /* This is the thread which finished the serialization.  */
+      result = PTHREAD_BARRIER_SERIAL_THREAD;
+    }
+  else
+    {
+      /* The number of the event we are waiting for.  The barrier's event
+        number must be bumped before we continue.  */
+      unsigned int event = ibarrier->curr_event;
+
+      /* Before suspending, make the barrier available to others.  */
+      lll_unlock (ibarrier->lock, ibarrier->private ^ FUTEX_PRIVATE_FLAG);
+
+      /* Wait for the event counter of the barrier to change.  */
+      do
+       lll_futex_wait (&ibarrier->curr_event, event,
+                       ibarrier->private ^ FUTEX_PRIVATE_FLAG);
+      while (event == ibarrier->curr_event);
+    }
+
+  /* Make sure the init_count is stored locally or in a register.  */
+  unsigned int init_count = ibarrier->init_count;
+
+  /* If this was the last woken thread, unlock.  */
+  if (atomic_increment_val (&ibarrier->left) == init_count)
+    /* We are done.  */
+    lll_unlock (ibarrier->lock, ibarrier->private ^ FUTEX_PRIVATE_FLAG);
+
+  return result;
+}
diff --git a/libpthread/nptl/sysdeps/pthread/pthread_cond_broadcast.c b/libpthread/nptl/sysdeps/pthread/pthread_cond_broadcast.c
new file mode 100644 (file)
index 0000000..5e74657
--- /dev/null
@@ -0,0 +1,89 @@
+/* Copyright (C) 2003, 2004, 2006, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <endian.h>
+#include <errno.h>
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <pthread.h>
+#include <pthreadP.h>
+
+#include <bits/kernel-features.h>
+
+
+int
+__pthread_cond_broadcast (
+     pthread_cond_t *cond)
+{
+  int pshared = (cond->__data.__mutex == (void *) ~0l)
+               ? LLL_SHARED : LLL_PRIVATE;
+  /* Make sure we are alone.  */
+  lll_lock (cond->__data.__lock, pshared);
+
+  /* Are there any waiters to be woken?  */
+  if (cond->__data.__total_seq > cond->__data.__wakeup_seq)
+    {
+      /* Yes.  Mark them all as woken.  */
+      cond->__data.__wakeup_seq = cond->__data.__total_seq;
+      cond->__data.__woken_seq = cond->__data.__total_seq;
+      cond->__data.__futex = (unsigned int) cond->__data.__total_seq * 2;
+      int futex_val = cond->__data.__futex;
+      /* Signal that a broadcast happened.  */
+      ++cond->__data.__broadcast_seq;
+
+      /* We are done.  */
+      lll_unlock (cond->__data.__lock, pshared);
+
+      /* Do not use requeue for pshared condvars.  */
+      if (cond->__data.__mutex == (void *) ~0l)
+       goto wake_all;
+
+      /* Wake everybody.  */
+      pthread_mutex_t *mut = (pthread_mutex_t *) cond->__data.__mutex;
+
+      /* XXX: Kernel so far doesn't support requeue to PI futex.  */
+      /* XXX: Kernel so far can only requeue to the same type of futex,
+        in this case private (we don't requeue for pshared condvars).  */
+      if (__builtin_expect (mut->__data.__kind
+                           & (PTHREAD_MUTEX_PRIO_INHERIT_NP
+                              | PTHREAD_MUTEX_PSHARED_BIT), 0))
+       goto wake_all;
+
+      /* lll_futex_requeue returns 0 for success and non-zero
+        for errors.  */
+      if (__builtin_expect (lll_futex_requeue (&cond->__data.__futex, 1,
+                                              INT_MAX, &mut->__data.__lock,
+                                              futex_val, LLL_PRIVATE), 0))
+       {
+         /* The requeue functionality is not available.  */
+       wake_all:
+         lll_futex_wake (&cond->__data.__futex, INT_MAX, pshared);
+       }
+
+      /* That's all.  */
+      return 0;
+    }
+
+  /* We are done.  */
+  lll_unlock (cond->__data.__lock, pshared);
+
+  return 0;
+}
+
+weak_alias(__pthread_cond_broadcast, pthread_cond_broadcast)
diff --git a/libpthread/nptl/sysdeps/pthread/pthread_cond_signal.c b/libpthread/nptl/sysdeps/pthread/pthread_cond_signal.c
new file mode 100644 (file)
index 0000000..d66f3ed
--- /dev/null
@@ -0,0 +1,62 @@
+/* Copyright (C) 2003, 2004, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <endian.h>
+#include <errno.h>
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <pthread.h>
+#include <pthreadP.h>
+
+#include <bits/kernel-features.h>
+
+
+int
+__pthread_cond_signal (
+     pthread_cond_t *cond)
+{
+  int pshared = (cond->__data.__mutex == (void *) ~0l)
+               ? LLL_SHARED : LLL_PRIVATE;
+
+  /* Make sure we are alone.  */
+  lll_lock (cond->__data.__lock, pshared);
+
+  /* Are there any waiters to be woken?  */
+  if (cond->__data.__total_seq > cond->__data.__wakeup_seq)
+    {
+      /* Yes.  Mark one of them as woken.  */
+      ++cond->__data.__wakeup_seq;
+      ++cond->__data.__futex;
+
+      /* Wake one.  */
+      if (! __builtin_expect (lll_futex_wake_unlock (&cond->__data.__futex, 1,
+                                                    1, &cond->__data.__lock,
+                                                    pshared), 0))
+       return 0;
+
+      lll_futex_wake (&cond->__data.__futex, 1, pshared);
+    }
+
+  /* We are done.  */
+  lll_unlock (cond->__data.__lock, pshared);
+
+  return 0;
+}
+
+weak_alias(__pthread_cond_signal, pthread_cond_signal)
diff --git a/libpthread/nptl/sysdeps/pthread/pthread_cond_timedwait.c b/libpthread/nptl/sysdeps/pthread/pthread_cond_timedwait.c
new file mode 100644 (file)
index 0000000..4aaf5df
--- /dev/null
@@ -0,0 +1,215 @@
+/* Copyright (C) 2003, 2004, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <endian.h>
+#include <errno.h>
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <pthread.h>
+#include <pthreadP.h>
+#include <bits/kernel-features.h>
+
+
+/* Cleanup handler, defined in pthread_cond_wait.c.  */
+extern void __condvar_cleanup (void *arg)
+     __attribute__ ((visibility ("hidden")));
+
+struct _condvar_cleanup_buffer
+{
+  int oldtype;
+  pthread_cond_t *cond;
+  pthread_mutex_t *mutex;
+  unsigned int bc_seq;
+};
+
+int
+__pthread_cond_timedwait (
+     pthread_cond_t *cond,
+     pthread_mutex_t *mutex,
+     const struct timespec *abstime)
+{
+  struct _pthread_cleanup_buffer buffer;
+  struct _condvar_cleanup_buffer cbuffer;
+  int result = 0;
+
+  /* Catch invalid parameters.  */
+  if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)
+    return EINVAL;
+
+  int pshared = (cond->__data.__mutex == (void *) ~0l)
+               ? LLL_SHARED : LLL_PRIVATE;
+
+  /* Make sure we are along.  */
+  lll_lock (cond->__data.__lock, pshared);
+
+  /* Now we can release the mutex.  */
+  int err = __pthread_mutex_unlock_usercnt (mutex, 0);
+  if (err)
+    {
+      lll_unlock (cond->__data.__lock, pshared);
+      return err;
+    }
+
+  /* We have one new user of the condvar.  */
+  ++cond->__data.__total_seq;
+  ++cond->__data.__futex;
+  cond->__data.__nwaiters += 1 << COND_NWAITERS_SHIFT;
+
+  /* Remember the mutex we are using here.  If there is already a
+     different address store this is a bad user bug.  Do not store
+     anything for pshared condvars.  */
+  if (cond->__data.__mutex != (void *) ~0l)
+    cond->__data.__mutex = mutex;
+
+  /* Prepare structure passed to cancellation handler.  */
+  cbuffer.cond = cond;
+  cbuffer.mutex = mutex;
+
+  /* Before we block we enable cancellation.  Therefore we have to
+     install a cancellation handler.  */
+  __pthread_cleanup_push (&buffer, __condvar_cleanup, &cbuffer);
+
+  /* The current values of the wakeup counter.  The "woken" counter
+     must exceed this value.  */
+  unsigned long long int val;
+  unsigned long long int seq;
+  val = seq = cond->__data.__wakeup_seq;
+  /* Remember the broadcast counter.  */
+  cbuffer.bc_seq = cond->__data.__broadcast_seq;
+
+  while (1)
+    {
+      struct timespec rt;
+      {
+#ifdef __NR_clock_gettime
+       INTERNAL_SYSCALL_DECL (err);
+       int ret;
+       ret = INTERNAL_SYSCALL (clock_gettime, err, 2,
+                               (cond->__data.__nwaiters
+                                & ((1 << COND_NWAITERS_SHIFT) - 1)),
+                               &rt);
+# ifndef __ASSUME_POSIX_TIMERS
+       if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (ret, err), 0))
+         {
+           struct timeval tv;
+           (void) gettimeofday (&tv, NULL);
+
+           /* Convert the absolute timeout value to a relative timeout.  */
+           rt.tv_sec = abstime->tv_sec - tv.tv_sec;
+           rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000;
+         }
+       else
+# endif
+         {
+           /* Convert the absolute timeout value to a relative timeout.  */
+           rt.tv_sec = abstime->tv_sec - rt.tv_sec;
+           rt.tv_nsec = abstime->tv_nsec - rt.tv_nsec;
+         }
+#else
+       /* Get the current time.  So far we support only one clock.  */
+       struct timeval tv;
+       (void) gettimeofday (&tv, NULL);
+
+       /* Convert the absolute timeout value to a relative timeout.  */
+       rt.tv_sec = abstime->tv_sec - tv.tv_sec;
+       rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000;
+#endif
+      }
+      if (rt.tv_nsec < 0)
+       {
+         rt.tv_nsec += 1000000000;
+         --rt.tv_sec;
+       }
+      /* Did we already time out?  */
+      if (__builtin_expect (rt.tv_sec < 0, 0))
+       {
+         if (cbuffer.bc_seq != cond->__data.__broadcast_seq)
+           goto bc_out;
+
+         goto timeout;
+       }
+
+      unsigned int futex_val = cond->__data.__futex;
+
+      /* Prepare to wait.  Release the condvar futex.  */
+      lll_unlock (cond->__data.__lock, pshared);
+
+      /* Enable asynchronous cancellation.  Required by the standard.  */
+      cbuffer.oldtype = __pthread_enable_asynccancel ();
+
+      /* Wait until woken by signal or broadcast.  */
+      err = lll_futex_timed_wait (&cond->__data.__futex,
+                                 futex_val, &rt, pshared);
+
+      /* Disable asynchronous cancellation.  */
+      __pthread_disable_asynccancel (cbuffer.oldtype);
+
+      /* We are going to look at shared data again, so get the lock.  */
+      lll_lock (cond->__data.__lock, pshared);
+
+      /* If a broadcast happened, we are done.  */
+      if (cbuffer.bc_seq != cond->__data.__broadcast_seq)
+       goto bc_out;
+
+      /* Check whether we are eligible for wakeup.  */
+      val = cond->__data.__wakeup_seq;
+      if (val != seq && cond->__data.__woken_seq != val)
+       break;
+
+      /* Not woken yet.  Maybe the time expired?  */
+      if (__builtin_expect (err == -ETIMEDOUT, 0))
+       {
+       timeout:
+         /* Yep.  Adjust the counters.  */
+         ++cond->__data.__wakeup_seq;
+         ++cond->__data.__futex;
+
+         /* The error value.  */
+         result = ETIMEDOUT;
+         break;
+       }
+    }
+
+  /* Another thread woken up.  */
+  ++cond->__data.__woken_seq;
+
+ bc_out:
+
+  cond->__data.__nwaiters -= 1 << COND_NWAITERS_SHIFT;
+
+  /* If pthread_cond_destroy was called on this variable already,
+     notify the pthread_cond_destroy caller all waiters have left
+     and it can be successfully destroyed.  */
+  if (cond->__data.__total_seq == -1ULL
+      && cond->__data.__nwaiters < (1 << COND_NWAITERS_SHIFT))
+    lll_futex_wake (&cond->__data.__nwaiters, 1, pshared);
+
+  /* We are done with the condvar.  */
+  lll_unlock (cond->__data.__lock, pshared);
+
+  /* The cancellation handling is back to normal, remove the handler.  */
+  __pthread_cleanup_pop (&buffer, 0);
+
+  /* Get the mutex before returning.  */
+  err = __pthread_mutex_cond_lock (mutex);
+
+  return err ?: result;
+}
+
+weak_alias(__pthread_cond_timedwait, pthread_cond_timedwait)
diff --git a/libpthread/nptl/sysdeps/pthread/pthread_cond_wait.c b/libpthread/nptl/sysdeps/pthread/pthread_cond_wait.c
new file mode 100644 (file)
index 0000000..2fac02d
--- /dev/null
@@ -0,0 +1,192 @@
+/* Copyright (C) 2003, 2004, 2006, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <endian.h>
+#include <errno.h>
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <pthread.h>
+#include <pthreadP.h>
+
+
+struct _condvar_cleanup_buffer
+{
+  int oldtype;
+  pthread_cond_t *cond;
+  pthread_mutex_t *mutex;
+  unsigned int bc_seq;
+};
+
+
+void
+__attribute__ ((visibility ("hidden")))
+__condvar_cleanup (void *arg)
+{
+  struct _condvar_cleanup_buffer *cbuffer =
+    (struct _condvar_cleanup_buffer *) arg;
+  unsigned int destroying;
+  int pshared = (cbuffer->cond->__data.__mutex == (void *) ~0l)
+               ? LLL_SHARED : LLL_PRIVATE;
+
+  /* We are going to modify shared data.  */
+  lll_lock (cbuffer->cond->__data.__lock, pshared);
+
+  if (cbuffer->bc_seq == cbuffer->cond->__data.__broadcast_seq)
+    {
+      /* This thread is not waiting anymore.  Adjust the sequence counters
+        appropriately.  We do not increment WAKEUP_SEQ if this would
+        bump it over the value of TOTAL_SEQ.  This can happen if a thread
+        was woken and then canceled.  */
+      if (cbuffer->cond->__data.__wakeup_seq
+         < cbuffer->cond->__data.__total_seq)
+       {
+         ++cbuffer->cond->__data.__wakeup_seq;
+         ++cbuffer->cond->__data.__futex;
+       }
+      ++cbuffer->cond->__data.__woken_seq;
+    }
+
+  cbuffer->cond->__data.__nwaiters -= 1 << COND_NWAITERS_SHIFT;
+
+  /* If pthread_cond_destroy was called on this variable already,
+     notify the pthread_cond_destroy caller all waiters have left
+     and it can be successfully destroyed.  */
+  destroying = 0;
+  if (cbuffer->cond->__data.__total_seq == -1ULL
+      && cbuffer->cond->__data.__nwaiters < (1 << COND_NWAITERS_SHIFT))
+    {
+      lll_futex_wake (&cbuffer->cond->__data.__nwaiters, 1, pshared);
+      destroying = 1;
+    }
+
+  /* We are done.  */
+  lll_unlock (cbuffer->cond->__data.__lock, pshared);
+
+  /* Wake everybody to make sure no condvar signal gets lost.  */
+  if (! destroying)
+    lll_futex_wake (&cbuffer->cond->__data.__futex, INT_MAX, pshared);
+
+  /* Get the mutex before returning unless asynchronous cancellation
+     is in effect.  */
+  __pthread_mutex_cond_lock (cbuffer->mutex);
+}
+
+
+int
+__pthread_cond_wait (
+     pthread_cond_t *cond,
+     pthread_mutex_t *mutex)
+{
+  struct _pthread_cleanup_buffer buffer;
+  struct _condvar_cleanup_buffer cbuffer;
+  int err;
+  int pshared = (cond->__data.__mutex == (void *) ~0l)
+               ? LLL_SHARED : LLL_PRIVATE;
+
+  /* Make sure we are along.  */
+  lll_lock (cond->__data.__lock, pshared);
+
+  /* Now we can release the mutex.  */
+  err = __pthread_mutex_unlock_usercnt (mutex, 0);
+  if (__builtin_expect (err, 0))
+    {
+      lll_unlock (cond->__data.__lock, pshared);
+      return err;
+    }
+
+  /* We have one new user of the condvar.  */
+  ++cond->__data.__total_seq;
+  ++cond->__data.__futex;
+  cond->__data.__nwaiters += 1 << COND_NWAITERS_SHIFT;
+
+  /* Remember the mutex we are using here.  If there is already a
+     different address store this is a bad user bug.  Do not store
+     anything for pshared condvars.  */
+  if (cond->__data.__mutex != (void *) ~0l)
+    cond->__data.__mutex = mutex;
+
+  /* Prepare structure passed to cancellation handler.  */
+  cbuffer.cond = cond;
+  cbuffer.mutex = mutex;
+
+  /* Before we block we enable cancellation.  Therefore we have to
+     install a cancellation handler.  */
+  __pthread_cleanup_push (&buffer, __condvar_cleanup, &cbuffer);
+
+  /* The current values of the wakeup counter.  The "woken" counter
+     must exceed this value.  */
+  unsigned long long int val;
+  unsigned long long int seq;
+  val = seq = cond->__data.__wakeup_seq;
+  /* Remember the broadcast counter.  */
+  cbuffer.bc_seq = cond->__data.__broadcast_seq;
+
+  do
+    {
+      unsigned int futex_val = cond->__data.__futex;
+
+      /* Prepare to wait.  Release the condvar futex.  */
+      lll_unlock (cond->__data.__lock, pshared);
+
+      /* Enable asynchronous cancellation.  Required by the standard.  */
+      cbuffer.oldtype = __pthread_enable_asynccancel ();
+
+      /* Wait until woken by signal or broadcast.  */
+      lll_futex_wait (&cond->__data.__futex, futex_val, pshared);
+
+      /* Disable asynchronous cancellation.  */
+      __pthread_disable_asynccancel (cbuffer.oldtype);
+
+      /* We are going to look at shared data again, so get the lock.  */
+      lll_lock (cond->__data.__lock, pshared);
+
+      /* If a broadcast happened, we are done.  */
+      if (cbuffer.bc_seq != cond->__data.__broadcast_seq)
+       goto bc_out;
+
+      /* Check whether we are eligible for wakeup.  */
+      val = cond->__data.__wakeup_seq;
+    }
+  while (val == seq || cond->__data.__woken_seq == val);
+
+  /* Another thread woken up.  */
+  ++cond->__data.__woken_seq;
+
+ bc_out:
+
+  cond->__data.__nwaiters -= 1 << COND_NWAITERS_SHIFT;
+
+  /* If pthread_cond_destroy was called on this varaible already,
+     notify the pthread_cond_destroy caller all waiters have left
+     and it can be successfully destroyed.  */
+  if (cond->__data.__total_seq == -1ULL
+      && cond->__data.__nwaiters < (1 << COND_NWAITERS_SHIFT))
+    lll_futex_wake (&cond->__data.__nwaiters, 1, pshared);
+
+  /* We are done with the condvar.  */
+  lll_unlock (cond->__data.__lock, pshared);
+
+  /* The cancellation handling is back to normal, remove the handler.  */
+  __pthread_cleanup_pop (&buffer, 0);
+
+  /* Get the mutex before returning.  */
+  return __pthread_mutex_cond_lock (mutex);
+}
+
+weak_alias(__pthread_cond_wait, pthread_cond_wait)
diff --git a/libpthread/nptl/sysdeps/pthread/pthread_once.c b/libpthread/nptl/sysdeps/pthread/pthread_once.c
new file mode 100644 (file)
index 0000000..57bb6b9
--- /dev/null
@@ -0,0 +1,54 @@
+/* Copyright (C) 2002, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+#include <lowlevellock.h>
+
+
+
+static int once_lock = LLL_LOCK_INITIALIZER;
+
+
+int
+__pthread_once (
+     pthread_once_t *once_control,
+     void (*init_routine) (void))
+{
+  /* XXX Depending on whether the LOCK_IN_ONCE_T is defined use a
+     global lock variable or one which is part of the pthread_once_t
+     object.  */
+  if (*once_control == PTHREAD_ONCE_INIT)
+    {
+      lll_lock (once_lock, LLL_PRIVATE);
+
+      /* XXX This implementation is not complete.  It doesn't take
+        cancelation and fork into account.  */
+      if (*once_control == PTHREAD_ONCE_INIT)
+       {
+         init_routine ();
+
+         *once_control = !PTHREAD_ONCE_INIT;
+       }
+
+      lll_unlock (once_lock, LLL_PRIVATE);
+    }
+
+  return 0;
+}
+strong_alias (__pthread_once, pthread_once)
diff --git a/libpthread/nptl/sysdeps/pthread/pthread_rwlock_rdlock.c b/libpthread/nptl/sysdeps/pthread/pthread_rwlock_rdlock.c
new file mode 100644 (file)
index 0000000..dc00f2a
--- /dev/null
@@ -0,0 +1,96 @@
+/* Copyright (C) 2003, 2004, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <pthread.h>
+#include <pthreadP.h>
+
+
+/* Acquire read lock for RWLOCK.  */
+int
+__pthread_rwlock_rdlock (
+     pthread_rwlock_t *rwlock)
+{
+  int result = 0;
+
+  /* Make sure we are along.  */
+  lll_lock (rwlock->__data.__lock, rwlock->__data.__shared);
+
+  while (1)
+    {
+      /* Get the rwlock if there is no writer...  */
+      if (rwlock->__data.__writer == 0
+         /* ...and if either no writer is waiting or we prefer readers.  */
+         && (!rwlock->__data.__nr_writers_queued
+             || PTHREAD_RWLOCK_PREFER_READER_P (rwlock)))
+       {
+         /* Increment the reader counter.  Avoid overflow.  */
+         if (__builtin_expect (++rwlock->__data.__nr_readers == 0, 0))
+           {
+             /* Overflow on number of readers.  */
+             --rwlock->__data.__nr_readers;
+             result = EAGAIN;
+           }
+
+         break;
+       }
+
+      /* Make sure we are not holding the rwlock as a writer.  This is
+        a deadlock situation we recognize and report.  */
+      if (__builtin_expect (rwlock->__data.__writer
+                           == THREAD_GETMEM (THREAD_SELF, tid), 0))
+       {
+         result = EDEADLK;
+         break;
+       }
+
+      /* Remember that we are a reader.  */
+      if (__builtin_expect (++rwlock->__data.__nr_readers_queued == 0, 0))
+       {
+         /* Overflow on number of queued readers.  */
+         --rwlock->__data.__nr_readers_queued;
+         result = EAGAIN;
+         break;
+       }
+
+      int waitval = rwlock->__data.__readers_wakeup;
+
+      /* Free the lock.  */
+      lll_unlock (rwlock->__data.__lock, rwlock->__data.__shared);
+
+      /* Wait for the writer to finish.  */
+      lll_futex_wait (&rwlock->__data.__readers_wakeup, waitval,
+                     rwlock->__data.__shared);
+
+      /* Get the lock.  */
+      lll_lock (rwlock->__data.__lock, rwlock->__data.__shared);
+
+      --rwlock->__data.__nr_readers_queued;
+    }
+
+  /* We are done, free the lock.  */
+  lll_unlock (rwlock->__data.__lock, rwlock->__data.__shared);
+
+  return result;
+}
+
+weak_alias (__pthread_rwlock_rdlock, pthread_rwlock_rdlock)
+strong_alias (__pthread_rwlock_rdlock, __pthread_rwlock_rdlock_internal)
diff --git a/libpthread/nptl/sysdeps/pthread/pthread_rwlock_timedrdlock.c b/libpthread/nptl/sysdeps/pthread/pthread_rwlock_timedrdlock.c
new file mode 100644 (file)
index 0000000..3daefc7
--- /dev/null
@@ -0,0 +1,137 @@
+/* Copyright (C) 2003, 2004, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <pthread.h>
+#include <pthreadP.h>
+
+
+/* Try to acquire read lock for RWLOCK or return after specfied time.  */
+int
+pthread_rwlock_timedrdlock (
+     pthread_rwlock_t *rwlock,
+     const struct timespec *abstime)
+{
+  int result = 0;
+
+  /* Make sure we are along.  */
+  lll_lock(rwlock->__data.__lock, rwlock->__data.__shared);
+
+  while (1)
+    {
+      int err;
+
+      /* Get the rwlock if there is no writer...  */
+      if (rwlock->__data.__writer == 0
+         /* ...and if either no writer is waiting or we prefer readers.  */
+         && (!rwlock->__data.__nr_writers_queued
+             || PTHREAD_RWLOCK_PREFER_READER_P (rwlock)))
+       {
+         /* Increment the reader counter.  Avoid overflow.  */
+         if (++rwlock->__data.__nr_readers == 0)
+           {
+             /* Overflow on number of readers.  */
+             --rwlock->__data.__nr_readers;
+             result = EAGAIN;
+           }
+
+         break;
+       }
+
+      /* Make sure we are not holding the rwlock as a writer.  This is
+        a deadlock situation we recognize and report.  */
+      if (__builtin_expect (rwlock->__data.__writer
+                           == THREAD_GETMEM (THREAD_SELF, tid), 0))
+       {
+         result = EDEADLK;
+         break;
+       }
+
+      /* Make sure the passed in timeout value is valid.  Ideally this
+        test would be executed once.  But since it must not be
+        performed if we would not block at all simply moving the test
+        to the front is no option.  Replicating all the code is
+        costly while this test is not.  */
+      if (__builtin_expect (abstime->tv_nsec >= 1000000000
+                            || abstime->tv_nsec < 0, 0))
+       {
+         result = EINVAL;
+         break;
+       }
+
+      /* Get the current time.  So far we support only one clock.  */
+      struct timeval tv;
+      (void) gettimeofday (&tv, NULL);
+
+      /* Convert the absolute timeout value to a relative timeout.  */
+      struct timespec rt;
+      rt.tv_sec = abstime->tv_sec - tv.tv_sec;
+      rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000;
+      if (rt.tv_nsec < 0)
+       {
+         rt.tv_nsec += 1000000000;
+         --rt.tv_sec;
+       }
+      /* Did we already time out?  */
+      if (rt.tv_sec < 0)
+       {
+         /* Yep, return with an appropriate error.  */
+         result = ETIMEDOUT;
+         break;
+       }
+
+      /* Remember that we are a reader.  */
+      if (++rwlock->__data.__nr_readers_queued == 0)
+       {
+         /* Overflow on number of queued readers.  */
+         --rwlock->__data.__nr_readers_queued;
+         result = EAGAIN;
+         break;
+       }
+
+      int waitval = rwlock->__data.__readers_wakeup;
+
+      /* Free the lock.  */
+      lll_unlock (rwlock->__data.__lock, rwlock->__data.__shared);
+
+      /* Wait for the writer to finish.  */
+      err = lll_futex_timed_wait (&rwlock->__data.__readers_wakeup,
+                                 waitval, &rt, rwlock->__data.__shared);
+
+      /* Get the lock.  */
+      lll_lock (rwlock->__data.__lock, rwlock->__data.__shared);
+
+      --rwlock->__data.__nr_readers_queued;
+
+      /* Did the futex call time out?  */
+      if (err == -ETIMEDOUT)
+       {
+         /* Yep, report it.  */
+         result = ETIMEDOUT;
+         break;
+       }
+    }
+
+  /* We are done, free the lock.  */
+  lll_unlock (rwlock->__data.__lock, rwlock->__data.__shared);
+
+  return result;
+}
diff --git a/libpthread/nptl/sysdeps/pthread/pthread_rwlock_timedwrlock.c b/libpthread/nptl/sysdeps/pthread/pthread_rwlock_timedwrlock.c
new file mode 100644 (file)
index 0000000..e6fcb16
--- /dev/null
@@ -0,0 +1,127 @@
+/* Copyright (C) 2003, 2004, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <pthread.h>
+#include <pthreadP.h>
+
+
+/* Try to acquire write lock for RWLOCK or return after specfied time. */
+int
+pthread_rwlock_timedwrlock (
+     pthread_rwlock_t *rwlock,
+     const struct timespec *abstime)
+{
+  int result = 0;
+
+  /* Make sure we are along.  */
+  lll_lock (rwlock->__data.__lock, rwlock->__data.__shared);
+
+  while (1)
+    {
+      int err;
+
+      /* Get the rwlock if there is no writer and no reader.  */
+      if (rwlock->__data.__writer == 0 && rwlock->__data.__nr_readers == 0)
+       {
+         /* Mark self as writer.  */
+         rwlock->__data.__writer = THREAD_GETMEM (THREAD_SELF, tid);
+         break;
+       }
+
+      /* Make sure we are not holding the rwlock as a writer.  This is
+        a deadlock situation we recognize and report.  */
+      if (__builtin_expect (rwlock->__data.__writer
+                           == THREAD_GETMEM (THREAD_SELF, tid), 0))
+       {
+         result = EDEADLK;
+         break;
+       }
+
+      /* Make sure the passed in timeout value is valid.  Ideally this
+        test would be executed once.  But since it must not be
+        performed if we would not block at all simply moving the test
+        to the front is no option.  Replicating all the code is
+        costly while this test is not.  */
+      if (__builtin_expect (abstime->tv_nsec >= 1000000000
+                            || abstime->tv_nsec < 0, 0))
+       {
+         result = EINVAL;
+         break;
+       }
+
+      /* Get the current time.  So far we support only one clock.  */
+      struct timeval tv;
+      (void) gettimeofday (&tv, NULL);
+
+      /* Convert the absolute timeout value to a relative timeout.  */
+      struct timespec rt;
+      rt.tv_sec = abstime->tv_sec - tv.tv_sec;
+      rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000;
+      if (rt.tv_nsec < 0)
+       {
+         rt.tv_nsec += 1000000000;
+         --rt.tv_sec;
+       }
+      /* Did we already time out?  */
+      if (rt.tv_sec < 0)
+       {
+         result = ETIMEDOUT;
+         break;
+       }
+
+      /* Remember that we are a writer.  */
+      if (++rwlock->__data.__nr_writers_queued == 0)
+       {
+         /* Overflow on number of queued writers.  */
+         --rwlock->__data.__nr_writers_queued;
+         result = EAGAIN;
+         break;
+       }
+
+      int waitval = rwlock->__data.__writer_wakeup;
+
+      /* Free the lock.  */
+      lll_unlock (rwlock->__data.__lock, rwlock->__data.__shared);
+
+      /* Wait for the writer or reader(s) to finish.  */
+      err = lll_futex_timed_wait (&rwlock->__data.__writer_wakeup,
+                                 waitval, &rt, rwlock->__data.__shared);
+
+      /* Get the lock.  */
+      lll_lock (rwlock->__data.__lock, rwlock->__data.__shared);
+
+      /* To start over again, remove the thread from the writer list.  */
+      --rwlock->__data.__nr_writers_queued;
+
+      /* Did the futex call time out?  */
+      if (err == -ETIMEDOUT)
+       {
+         result = ETIMEDOUT;
+         break;
+       }
+    }
+
+  /* We are done, free the lock.  */
+  lll_unlock (rwlock->__data.__lock, rwlock->__data.__shared);
+
+  return result;
+}
diff --git a/libpthread/nptl/sysdeps/pthread/pthread_rwlock_unlock.c b/libpthread/nptl/sysdeps/pthread/pthread_rwlock_unlock.c
new file mode 100644 (file)
index 0000000..a7ef71a
--- /dev/null
@@ -0,0 +1,59 @@
+/* Copyright (C) 2003, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <pthread.h>
+#include <pthreadP.h>
+
+/* Unlock RWLOCK.  */
+int
+__pthread_rwlock_unlock (pthread_rwlock_t *rwlock)
+{
+  lll_lock (rwlock->__data.__lock, rwlock->__data.__shared);
+  if (rwlock->__data.__writer)
+    rwlock->__data.__writer = 0;
+  else
+    --rwlock->__data.__nr_readers;
+  if (rwlock->__data.__nr_readers == 0)
+    {
+      if (rwlock->__data.__nr_writers_queued)
+       {
+         ++rwlock->__data.__writer_wakeup;
+         lll_unlock (rwlock->__data.__lock, rwlock->__data.__shared);
+         lll_futex_wake (&rwlock->__data.__writer_wakeup, 1,
+                         rwlock->__data.__shared);
+         return 0;
+       }
+      else if (rwlock->__data.__nr_readers_queued)
+       {
+         ++rwlock->__data.__readers_wakeup;
+         lll_unlock (rwlock->__data.__lock, rwlock->__data.__shared);
+         lll_futex_wake (&rwlock->__data.__readers_wakeup, INT_MAX,
+                         rwlock->__data.__shared);
+         return 0;
+       }
+    }
+  lll_unlock (rwlock->__data.__lock, rwlock->__data.__shared);
+  return 0;
+}
+
+weak_alias (__pthread_rwlock_unlock, pthread_rwlock_unlock)
+strong_alias (__pthread_rwlock_unlock, __pthread_rwlock_unlock_internal)
diff --git a/libpthread/nptl/sysdeps/pthread/pthread_rwlock_wrlock.c b/libpthread/nptl/sysdeps/pthread/pthread_rwlock_wrlock.c
new file mode 100644 (file)
index 0000000..81e6daa
--- /dev/null
@@ -0,0 +1,88 @@
+/* Copyright (C) 2003, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <pthread.h>
+#include <pthreadP.h>
+
+
+/* Acquire write lock for RWLOCK.  */
+int
+__pthread_rwlock_wrlock (
+     pthread_rwlock_t *rwlock)
+{
+  int result = 0;
+
+  /* Make sure we are along.  */
+  lll_lock (rwlock->__data.__lock, rwlock->__data.__shared);
+
+  while (1)
+    {
+      /* Get the rwlock if there is no writer and no reader.  */
+      if (rwlock->__data.__writer == 0 && rwlock->__data.__nr_readers == 0)
+       {
+         /* Mark self as writer.  */
+         rwlock->__data.__writer = THREAD_GETMEM (THREAD_SELF, tid);
+         break;
+       }
+
+      /* Make sure we are not holding the rwlock as a writer.  This is
+        a deadlock situation we recognize and report.  */
+      if (__builtin_expect (rwlock->__data.__writer
+                           == THREAD_GETMEM (THREAD_SELF, tid), 0))
+       {
+         result = EDEADLK;
+         break;
+       }
+
+      /* Remember that we are a writer.  */
+      if (++rwlock->__data.__nr_writers_queued == 0)
+       {
+         /* Overflow on number of queued writers.  */
+         --rwlock->__data.__nr_writers_queued;
+         result = EAGAIN;
+         break;
+       }
+
+      int waitval = rwlock->__data.__writer_wakeup;
+
+      /* Free the lock.  */
+      lll_unlock (rwlock->__data.__lock, rwlock->__data.__shared);
+
+      /* Wait for the writer or reader(s) to finish.  */
+      lll_futex_wait (&rwlock->__data.__writer_wakeup, waitval,
+                     rwlock->__data.__shared);
+
+      /* Get the lock.  */
+      lll_lock (rwlock->__data.__lock, rwlock->__data.__shared);
+
+      /* To start over again, remove the thread from the writer list.  */
+      --rwlock->__data.__nr_writers_queued;
+    }
+
+  /* We are done, free the lock.  */
+  lll_unlock (rwlock->__data.__lock, rwlock->__data.__shared);
+
+  return result;
+}
+
+weak_alias (__pthread_rwlock_wrlock, pthread_rwlock_wrlock)
+strong_alias (__pthread_rwlock_wrlock, __pthread_rwlock_wrlock_internal)
diff --git a/libpthread/nptl/sysdeps/pthread/pthread_sigmask.c b/libpthread/nptl/sysdeps/pthread/pthread_sigmask.c
new file mode 100644 (file)
index 0000000..6f66bbb
--- /dev/null
@@ -0,0 +1,58 @@
+/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <signal.h>
+#include <pthreadP.h>
+#include <sysdep.h>
+
+
+int
+pthread_sigmask (
+     int how,
+     const sigset_t *newmask,
+     sigset_t *oldmask)
+{
+  sigset_t local_newmask;
+
+  /* The only thing we have to make sure here is that SIGCANCEL and
+     SIGSETXID is not blocked.  */
+  if (newmask != NULL
+      && (__builtin_expect (__sigismember (newmask, SIGCANCEL), 0)
+         || __builtin_expect (__sigismember (newmask, SIGSETXID), 0)))
+    {
+      local_newmask = *newmask;
+      __sigdelset (&local_newmask, SIGCANCEL);
+      __sigdelset (&local_newmask, SIGSETXID);
+      newmask = &local_newmask;
+    }
+
+#ifdef INTERNAL_SYSCALL
+  /* We know that realtime signals are available if NPTL is used.  */
+  INTERNAL_SYSCALL_DECL (err);
+  int result = INTERNAL_SYSCALL (rt_sigprocmask, err, 4, how, newmask,
+                                oldmask, _NSIG / 8);
+
+  return (INTERNAL_SYSCALL_ERROR_P (result, err)
+         ? INTERNAL_SYSCALL_ERRNO (result, err)
+         : 0);
+#else
+  return sigprocmask (how, newmask, oldmask) == -1 ? errno : 0;
+#endif
+}
diff --git a/libpthread/nptl/sysdeps/pthread/pthread_spin_destroy.c b/libpthread/nptl/sysdeps/pthread/pthread_spin_destroy.c
new file mode 100644 (file)
index 0000000..7118f8a
--- /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_spin_destroy (
+     pthread_spinlock_t *lock)
+{
+  /* Nothing to do.  */
+  return 0;
+}
diff --git a/libpthread/nptl/sysdeps/pthread/pthread_spin_init.c b/libpthread/nptl/sysdeps/pthread/pthread_spin_init.c
new file mode 100644 (file)
index 0000000..c227508
--- /dev/null
@@ -0,0 +1,28 @@
+/* pthread_spin_init -- initialize a spin lock.  Generic version.
+   Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+
+int
+pthread_spin_init (pthread_spinlock_t *lock, int pshared)
+{
+  *lock = 0;
+  return 0;
+}
diff --git a/libpthread/nptl/sysdeps/pthread/pthread_spin_unlock.c b/libpthread/nptl/sysdeps/pthread/pthread_spin_unlock.c
new file mode 100644 (file)
index 0000000..f97cadf
--- /dev/null
@@ -0,0 +1,30 @@
+/* pthread_spin_unlock -- unlock a spin lock.  Generic version.
+   Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+#include <atomic.h>
+
+int
+pthread_spin_unlock (pthread_spinlock_t *lock)
+{
+  atomic_full_barrier ();
+  *lock = 0;
+  return 0;
+}
diff --git a/libpthread/nptl/sysdeps/pthread/rt-unwind-resume.c b/libpthread/nptl/sysdeps/pthread/rt-unwind-resume.c
new file mode 100644 (file)
index 0000000..743e675
--- /dev/null
@@ -0,0 +1 @@
+#include <unwind-resume.c>
diff --git a/libpthread/nptl/sysdeps/pthread/setxid.h b/libpthread/nptl/sysdeps/pthread/setxid.h
new file mode 100644 (file)
index 0000000..aebdbd2
--- /dev/null
@@ -0,0 +1,63 @@
+/* Copyright (C) 2004, 2007 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 <pthreadP.h>
+#include <sysdep.h>
+
+#define __SETXID_1(cmd, arg1) \
+  cmd.id[0] = arg1
+#define __SETXID_2(cmd, arg1, arg2) \
+  __SETXID_1 (cmd, arg1); cmd.id[1] = arg2
+#define __SETXID_3(cmd, arg1, arg2, arg3) \
+  __SETXID_2 (cmd, arg1, arg2); cmd.id[2] = arg3
+
+#ifdef SINGLE_THREAD
+# define INLINE_SETXID_SYSCALL(name, nr, args...) \
+  INLINE_SYSCALL (name, nr, args)
+#elif defined SHARED
+# define INLINE_SETXID_SYSCALL(name, nr, args...) \
+  ({                                                                   \
+    int __result;                                                      \
+    if (__builtin_expect (__libc_pthread_functions_init, 0))           \
+      {                                                                        \
+       struct xid_command __cmd;                                       \
+       __cmd.syscall_no = __NR_##name;                                 \
+       __SETXID_##nr (__cmd, args);                                    \
+       __result = PTHFCT_CALL (ptr__nptl_setxid, (&__cmd));            \
+       }                                                               \
+    else                                                               \
+      __result = INLINE_SYSCALL (name, nr, args);                      \
+    __result;                                                          \
+   })
+#else
+# define INLINE_SETXID_SYSCALL(name, nr, args...) \
+  ({                                                                   \
+    extern __typeof (__nptl_setxid) __nptl_setxid __attribute__((weak));\
+    int __result;                                                      \
+    if (__builtin_expect (__nptl_setxid        != NULL, 0))                    \
+      {                                                                        \
+       struct xid_command __cmd;                                       \
+       __cmd.syscall_no = __NR_##name;                                 \
+       __SETXID_##nr (__cmd, args);                                    \
+       __result =__nptl_setxid (&__cmd);                               \
+      }                                                                        \
+    else                                                               \
+      __result = INLINE_SYSCALL (name, nr, args);                      \
+    __result;                                                          \
+   })
+#endif
diff --git a/libpthread/nptl/sysdeps/pthread/sigaction.c b/libpthread/nptl/sysdeps/pthread/sigaction.c
new file mode 100644 (file)
index 0000000..20cff89
--- /dev/null
@@ -0,0 +1,51 @@
+/* Copyright (C) 2002, 2003, 2005 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 LIBC_SIGACTION
+
+#include <pthreadP.h>
+
+/* We use the libc implementation but we tell it to not allow
+   SIGCANCEL or SIGTIMER to be handled.  */
+#define LIBC_SIGACTION 1
+#include <sigaction.c>
+
+int
+sigaction (int sig, const struct sigaction *act, struct sigaction *oact);
+int
+__sigaction (int sig, const struct sigaction *act, struct sigaction *oact)
+{
+  if (__builtin_expect (sig == SIGCANCEL || sig == SIGSETXID, 0))
+    {
+      __set_errno (EINVAL);
+      return -1;
+    }
+
+  return __libc_sigaction (sig, act, oact);
+}
+libc_hidden_proto(sigaction)
+weak_alias (__sigaction, sigaction)
+libc_hidden_weak(sigaction)
+
+#else
+
+# include_next <sigaction.c>
+
+#endif /* LIBC_SIGACTION */
diff --git a/libpthread/nptl/sysdeps/pthread/sigfillset.c b/libpthread/nptl/sysdeps/pthread/sigfillset.c
new file mode 100644 (file)
index 0000000..eed75e2
--- /dev/null
@@ -0,0 +1,21 @@
+/* Copyright (C) 2003, 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthreadP.h>
+
+#include <../../../../libc/signal/sigfillset.c>
diff --git a/libpthread/nptl/sysdeps/pthread/sigprocmask.c b/libpthread/nptl/sysdeps/pthread/sigprocmask.c
new file mode 100644 (file)
index 0000000..35aa843
--- /dev/null
@@ -0,0 +1,22 @@
+/* Copyright (C) 1997,1998,1999,2000,2001,2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthreadP.h>
+#undef _LARGEFILE64_SOURCE
+
+#include <../../../../libc/sysdeps/linux/common/sigprocmask.c>
diff --git a/libpthread/nptl/sysdeps/pthread/tcb-offsets.h b/libpthread/nptl/sysdeps/pthread/tcb-offsets.h
new file mode 100644 (file)
index 0000000..3fe1370
--- /dev/null
@@ -0,0 +1 @@
+/* This is overridden by generated tcb-offsets.h on arches which need it.  */
diff --git a/libpthread/nptl/sysdeps/pthread/timer_create.c b/libpthread/nptl/sysdeps/pthread/timer_create.c
new file mode 100644 (file)
index 0000000..ae82c5a
--- /dev/null
@@ -0,0 +1,170 @@
+/* Copyright (C) 2000, 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Kaz Kylheku <kaz@ashi.footprints.net>.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <errno.h>
+#include <signal.h>
+#include <pthread.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "posix-timer.h"
+
+
+/* Create new per-process timer using CLOCK.  */
+int
+timer_create (
+     clockid_t clock_id,
+     struct sigevent *evp,
+     timer_t *timerid)
+{
+  int retval = -1;
+  struct timer_node *newtimer = NULL;
+  struct thread_node *thread = NULL;
+
+  if (0
+#if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0
+      || clock_id == CLOCK_PROCESS_CPUTIME_ID
+#endif
+#if defined _POSIX_THREAD_CPUTIME && _POSIX_THREAD_CPUTIME >= 0
+      || clock_id == CLOCK_THREAD_CPUTIME_ID
+#endif
+      )
+    {
+      /* We don't allow timers for CPU clocks.  At least not in the
+        moment.  */
+      __set_errno (ENOTSUP);
+      return -1;
+    }
+
+  if (clock_id != CLOCK_REALTIME)
+    {
+      __set_errno (EINVAL);
+      return -1;
+    }
+
+  pthread_once (&__timer_init_once_control, __timer_init_once);
+
+  if (__timer_init_failed)
+    {
+      __set_errno (ENOMEM);
+      return -1;
+    }
+
+  pthread_mutex_lock (&__timer_mutex);
+
+  newtimer = __timer_alloc ();
+  if (__builtin_expect (newtimer == NULL, 0))
+    {
+      __set_errno (EAGAIN);
+      goto unlock_bail;
+    }
+
+  if (evp != NULL)
+    newtimer->event = *evp;
+  else
+    {
+      newtimer->event.sigev_notify = SIGEV_SIGNAL;
+      newtimer->event.sigev_signo = SIGALRM;
+      newtimer->event.sigev_value.sival_ptr = timer_ptr2id (newtimer);
+      newtimer->event.sigev_notify_function = 0;
+    }
+
+  newtimer->event.sigev_notify_attributes = &newtimer->attr;
+  newtimer->creator_pid = getpid ();
+
+  switch (__builtin_expect (newtimer->event.sigev_notify, SIGEV_SIGNAL))
+    {
+    case SIGEV_NONE:
+    case SIGEV_SIGNAL:
+      /* We have a global thread for delivering timed signals.
+        If it is not running, try to start it up.  */
+      thread = &__timer_signal_thread_rclk;
+      if (! thread->exists)
+       {
+         if (__builtin_expect (__timer_thread_start (thread),
+                               1) < 0)
+           {
+             __set_errno (EAGAIN);
+             goto unlock_bail;
+            }
+        }
+      break;
+
+    case SIGEV_THREAD:
+      /* Copy over thread attributes or set up default ones.  */
+      if (evp->sigev_notify_attributes)
+       newtimer->attr = *(pthread_attr_t *) evp->sigev_notify_attributes;
+      else
+       pthread_attr_init (&newtimer->attr);
+
+      /* Ensure thread attributes call for deatched thread.  */
+      pthread_attr_setdetachstate (&newtimer->attr, PTHREAD_CREATE_DETACHED);
+
+      /* Try to find existing thread having the right attributes.  */
+      thread = __timer_thread_find_matching (&newtimer->attr, clock_id);
+
+      /* If no existing thread has these attributes, try to allocate one.  */
+      if (thread == NULL)
+       thread = __timer_thread_alloc (&newtimer->attr, clock_id);
+
+      /* Out of luck; no threads are available.  */
+      if (__builtin_expect (thread == NULL, 0))
+       {
+         __set_errno (EAGAIN);
+         goto unlock_bail;
+       }
+
+      /* If the thread is not running already, try to start it.  */
+      if (! thread->exists
+         && __builtin_expect (! __timer_thread_start (thread), 0))
+       {
+         __set_errno (EAGAIN);
+         goto unlock_bail;
+       }
+      break;
+
+    default:
+      __set_errno (EINVAL);
+      goto unlock_bail;
+    }
+
+  newtimer->clock = clock_id;
+  newtimer->abstime = 0;
+  newtimer->armed = 0;
+  newtimer->thread = thread;
+
+  *timerid = timer_ptr2id (newtimer);
+  retval = 0;
+
+  if (__builtin_expect (retval, 0) == -1)
+    {
+    unlock_bail:
+      if (thread != NULL)
+       __timer_thread_dealloc (thread);
+      if (newtimer != NULL)
+       {
+         timer_delref (newtimer);
+         __timer_dealloc (newtimer);
+       }
+    }
+
+  pthread_mutex_unlock (&__timer_mutex);
+
+  return retval;
+}
diff --git a/libpthread/nptl/sysdeps/pthread/timer_delete.c b/libpthread/nptl/sysdeps/pthread/timer_delete.c
new file mode 100644 (file)
index 0000000..4c53112
--- /dev/null
@@ -0,0 +1,70 @@
+/* Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Kaz Kylheku <kaz@ashi.footprints.net>.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <assert.h>
+#include <errno.h>
+#include <pthread.h>
+#include <time.h>
+
+#include "posix-timer.h"
+
+
+/* Delete timer TIMERID.  */
+int
+timer_delete (
+     timer_t timerid)
+{
+  struct timer_node *timer;
+  int retval = -1;
+
+  pthread_mutex_lock (&__timer_mutex);
+
+  timer = timer_id2ptr (timerid);
+  if (! timer_valid (timer))
+    /* Invalid timer ID or the timer is not in use.  */
+    __set_errno (EINVAL);
+  else
+    {
+      if (timer->armed && timer->thread != NULL)
+       {
+         struct thread_node *thread = timer->thread;
+         assert (thread != NULL);
+
+         /* If thread is cancelled while waiting for handler to terminate,
+            the mutex is unlocked and timer_delete is aborted.  */
+         pthread_cleanup_push (__timer_mutex_cancel_handler, &__timer_mutex);
+
+         /* If timer is currently being serviced, wait for it to finish.  */
+         while (thread->current_timer == timer)
+           pthread_cond_wait (&thread->cond, &__timer_mutex);
+
+         pthread_cleanup_pop (0);
+        }
+
+      /* Remove timer from whatever queue it may be on and deallocate it.  */
+      timer->inuse = TIMER_DELETED;
+      list_unlink_ip (&timer->links);
+      timer_delref (timer);
+      retval = 0;
+    }
+
+  pthread_mutex_unlock (&__timer_mutex);
+
+  return retval;
+}
diff --git a/libpthread/nptl/sysdeps/pthread/timer_getoverr.c b/libpthread/nptl/sysdeps/pthread/timer_getoverr.c
new file mode 100644 (file)
index 0000000..f3e2221
--- /dev/null
@@ -0,0 +1,45 @@
+/* Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Kaz Kylheku <kaz@ashi.footprints.net>.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <time.h>
+
+#include "posix-timer.h"
+
+
+/* Get expiration overrun for timer TIMERID.  */
+int
+timer_getoverrun (timerid)
+     timer_t timerid;
+{
+  struct timer_node *timer;
+  int retval = -1;
+
+  pthread_mutex_lock (&__timer_mutex);
+
+  if (! timer_valid (timer = timer_id2ptr (timerid)))
+    __set_errno (EINVAL);
+  else
+    retval = timer->overrun_count;
+
+  pthread_mutex_unlock (&__timer_mutex);
+
+  return retval;
+}
diff --git a/libpthread/nptl/sysdeps/pthread/timer_gettime.c b/libpthread/nptl/sysdeps/pthread/timer_gettime.c
new file mode 100644 (file)
index 0000000..723a616
--- /dev/null
@@ -0,0 +1,77 @@
+/* Copyright (C) 2000, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Kaz Kylheku <kaz@ashi.footprints.net>.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <time.h>
+
+#include "posix-timer.h"
+
+
+/* Get current value of timer TIMERID and store it in VLAUE.  */
+int
+timer_gettime (timerid, value)
+     timer_t timerid;
+     struct itimerspec *value;
+{
+  struct timer_node *timer;
+  struct timespec now, expiry;
+  int retval = -1, armed = 0, valid;
+  clock_t clock = 0;
+
+  pthread_mutex_lock (&__timer_mutex);
+
+  timer = timer_id2ptr (timerid);
+  valid = timer_valid (timer);
+
+  if (valid) {
+    armed = timer->armed;
+    expiry = timer->expirytime;
+    clock = timer->clock;
+    value->it_interval = timer->value.it_interval;
+  }
+
+  pthread_mutex_unlock (&__timer_mutex);
+
+  if (valid)
+    {
+      if (armed)
+       {
+         clock_gettime (clock, &now);
+         if (timespec_compare (&now, &expiry) < 0)
+           timespec_sub (&value->it_value, &expiry, &now);
+         else
+           {
+             value->it_value.tv_sec = 0;
+             value->it_value.tv_nsec = 0;
+           }
+       }
+      else
+       {
+         value->it_value.tv_sec = 0;
+         value->it_value.tv_nsec = 0;
+       }
+
+      retval = 0;
+    }
+  else
+    __set_errno (EINVAL);
+
+  return retval;
+}
diff --git a/libpthread/nptl/sysdeps/pthread/timer_routines.c b/libpthread/nptl/sysdeps/pthread/timer_routines.c
new file mode 100644 (file)
index 0000000..8d5b1d1
--- /dev/null
@@ -0,0 +1,578 @@
+/* Helper code for POSIX timer implementation on NPTL.
+   Copyright (C) 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Kaz Kylheku <kaz@ashi.footprints.net>.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <assert.h>
+#include <errno.h>
+#include <pthread.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysdep.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+
+#include "posix-timer.h"
+#include <pthreadP.h>
+
+
+/* Number of threads used.  */
+#define THREAD_MAXNODES        16
+
+/* Array containing the descriptors for the used threads.  */
+static struct thread_node thread_array[THREAD_MAXNODES];
+
+/* Static array with the structures for all the timers.  */
+struct timer_node __timer_array[TIMER_MAX];
+
+/* Global lock to protect operation on the lists.  */
+pthread_mutex_t __timer_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/* Variable to protext initialization.  */
+pthread_once_t __timer_init_once_control = PTHREAD_ONCE_INIT;
+
+/* Nonzero if initialization of timer implementation failed.  */
+int __timer_init_failed;
+
+/* Node for the thread used to deliver signals.  */
+struct thread_node __timer_signal_thread_rclk;
+
+/* Lists to keep free and used timers and threads.  */
+struct list_links timer_free_list;
+struct list_links thread_free_list;
+struct list_links thread_active_list;
+
+
+#ifdef __NR_rt_sigqueueinfo
+extern int __syscall_rt_sigqueueinfo (int, int, siginfo_t *);
+#endif
+
+
+/* List handling functions.  */
+static inline void
+list_init (struct list_links *list)
+{
+  list->next = list->prev = list;
+}
+
+static inline void
+list_append (struct list_links *list, struct list_links *newp)
+{
+  newp->prev = list->prev;
+  newp->next = list;
+  list->prev->next = newp;
+  list->prev = newp;
+}
+
+static inline void
+list_insbefore (struct list_links *list, struct list_links *newp)
+{
+  list_append (list, newp);
+}
+
+/*
+ * Like list_unlink_ip, except that calling it on a node that
+ * is already unlinked is disastrous rather than a noop.
+ */
+
+static inline void
+list_unlink (struct list_links *list)
+{
+  struct list_links *lnext = list->next, *lprev = list->prev;
+
+  lnext->prev = lprev;
+  lprev->next = lnext;
+}
+
+static inline struct list_links *
+list_first (struct list_links *list)
+{
+  return list->next;
+}
+
+static inline struct list_links *
+list_null (struct list_links *list)
+{
+  return list;
+}
+
+static inline struct list_links *
+list_next (struct list_links *list)
+{
+  return list->next;
+}
+
+static inline int
+list_isempty (struct list_links *list)
+{
+  return list->next == list;
+}
+
+
+/* Functions build on top of the list functions.  */
+static inline struct thread_node *
+thread_links2ptr (struct list_links *list)
+{
+  return (struct thread_node *) ((char *) list
+                                - offsetof (struct thread_node, links));
+}
+
+static inline struct timer_node *
+timer_links2ptr (struct list_links *list)
+{
+  return (struct timer_node *) ((char *) list
+                               - offsetof (struct timer_node, links));
+}
+
+
+/* Initialize a newly allocated thread structure.  */
+static void
+thread_init (struct thread_node *thread, const pthread_attr_t *attr, clockid_t clock_id)
+{
+  if (attr != NULL)
+    thread->attr = *attr;
+  else
+    {
+      pthread_attr_init (&thread->attr);
+      pthread_attr_setdetachstate (&thread->attr, PTHREAD_CREATE_DETACHED);
+    }
+
+  thread->exists = 0;
+  list_init (&thread->timer_queue);
+  pthread_cond_init (&thread->cond, 0);
+  thread->current_timer = 0;
+  thread->captured = pthread_self ();
+  thread->clock_id = clock_id;
+}
+
+
+/* Initialize the global lists, and acquire global resources.  Error
+   reporting is done by storing a non-zero value to the global variable
+   timer_init_failed.  */
+static void
+init_module (void)
+{
+  int i;
+
+  list_init (&timer_free_list);
+  list_init (&thread_free_list);
+  list_init (&thread_active_list);
+
+  for (i = 0; i < TIMER_MAX; ++i)
+    {
+      list_append (&timer_free_list, &__timer_array[i].links);
+      __timer_array[i].inuse = TIMER_FREE;
+    }
+
+  for (i = 0; i < THREAD_MAXNODES; ++i)
+    list_append (&thread_free_list, &thread_array[i].links);
+
+  thread_init (&__timer_signal_thread_rclk, 0, CLOCK_REALTIME);
+}
+
+
+/* This is a handler executed in a child process after a fork()
+   occurs.  It reinitializes the module, resetting all of the data
+   structures to their initial state.  The mutex is initialized in
+   case it was locked in the parent process.  */
+static void
+reinit_after_fork (void)
+{
+  init_module ();
+  pthread_mutex_init (&__timer_mutex, 0);
+}
+
+
+/* Called once form pthread_once in timer_init. This initializes the
+   module and ensures that reinit_after_fork will be executed in any
+   child process.  */
+void
+__timer_init_once (void)
+{
+  init_module ();
+  pthread_atfork (0, 0, reinit_after_fork);
+}
+
+
+/* Deinitialize a thread that is about to be deallocated.  */
+static void
+thread_deinit (struct thread_node *thread)
+{
+  assert (list_isempty (&thread->timer_queue));
+  pthread_cond_destroy (&thread->cond);
+}
+
+
+/* Allocate a thread structure from the global free list.  Global
+   mutex lock must be held by caller.  The thread is moved to
+   the active list. */
+struct thread_node *
+__timer_thread_alloc (const pthread_attr_t *desired_attr, clockid_t clock_id)
+{
+  struct list_links *node = list_first (&thread_free_list);
+
+  if (node != list_null (&thread_free_list))
+    {
+      struct thread_node *thread = thread_links2ptr (node);
+      list_unlink (node);
+      thread_init (thread, desired_attr, clock_id);
+      list_append (&thread_active_list, node);
+      return thread;
+    }
+
+  return 0;
+}
+
+
+/* Return a thread structure to the global free list.  Global lock
+   must be held by caller.  */
+void
+__timer_thread_dealloc (struct thread_node *thread)
+{
+  thread_deinit (thread);
+  list_unlink (&thread->links);
+  list_append (&thread_free_list, &thread->links);
+}
+
+
+/* Each of our threads which terminates executes this cleanup
+   handler. We never terminate threads ourselves; if a thread gets here
+   it means that the evil application has killed it.  If the thread has
+   timers, these require servicing and so we must hire a replacement
+   thread right away.  We must also unblock another thread that may
+   have been waiting for this thread to finish servicing a timer (see
+   timer_delete()).  */
+
+static void
+thread_cleanup (void *val)
+{
+  if (val != NULL)
+    {
+      struct thread_node *thread = val;
+
+      /* How did the signal thread get killed?  */
+      assert (thread != &__timer_signal_thread_rclk);
+
+      pthread_mutex_lock (&__timer_mutex);
+
+      thread->exists = 0;
+
+      /* We are no longer processing a timer event.  */
+      thread->current_timer = 0;
+
+      if (list_isempty (&thread->timer_queue))
+       __timer_thread_dealloc (thread);
+      else
+       (void) __timer_thread_start (thread);
+
+      pthread_mutex_unlock (&__timer_mutex);
+
+      /* Unblock potentially blocked timer_delete().  */
+      pthread_cond_broadcast (&thread->cond);
+    }
+}
+
+
+/* Handle a timer which is supposed to go off now.  */
+static void
+thread_expire_timer (struct thread_node *self, struct timer_node *timer)
+{
+  self->current_timer = timer; /* Lets timer_delete know timer is running. */
+
+  pthread_mutex_unlock (&__timer_mutex);
+
+  switch (__builtin_expect (timer->event.sigev_notify, SIGEV_SIGNAL))
+    {
+    case SIGEV_NONE:
+      break;
+
+    case SIGEV_SIGNAL:
+#ifdef __NR_rt_sigqueueinfo
+      {
+       siginfo_t info;
+
+       /* First, clear the siginfo_t structure, so that we don't pass our
+          stack content to other tasks.  */
+       memset (&info, 0, sizeof (siginfo_t));
+       /* We must pass the information about the data in a siginfo_t
+           value.  */
+       info.si_signo = timer->event.sigev_signo;
+       info.si_code = SI_TIMER;
+       info.si_pid = timer->creator_pid;
+       info.si_uid = getuid ();
+       info.si_value = timer->event.sigev_value;
+
+       INLINE_SYSCALL (rt_sigqueueinfo, 3, info.si_pid, info.si_signo, &info);
+      }
+#else
+      if (pthread_kill (self->captured, timer->event.sigev_signo) != 0)
+       {
+         if (pthread_kill (self->id, timer->event.sigev_signo) != 0)
+           abort ();
+        }
+#endif
+      break;
+
+    case SIGEV_THREAD:
+      timer->event.sigev_notify_function (timer->event.sigev_value);
+      break;
+
+    default:
+      assert (! "unknown event");
+      break;
+    }
+
+  pthread_mutex_lock (&__timer_mutex);
+
+  self->current_timer = 0;
+
+  pthread_cond_broadcast (&self->cond);
+}
+
+
+/* Thread function; executed by each timer thread. The job of this
+   function is to wait on the thread's timer queue and expire the
+   timers in chronological order as close to their scheduled time as
+   possible.  */
+static void
+__attribute__ ((noreturn))
+thread_func (void *arg)
+{
+  struct thread_node *self = arg;
+
+  /* Register cleanup handler, in case rogue application terminates
+     this thread.  (This cannot happen to __timer_signal_thread, which
+     doesn't invoke application callbacks). */
+
+  pthread_cleanup_push (thread_cleanup, self);
+
+  pthread_mutex_lock (&__timer_mutex);
+
+  while (1)
+    {
+      struct list_links *first;
+      struct timer_node *timer = NULL;
+
+      /* While the timer queue is not empty, inspect the first node.  */
+      first = list_first (&self->timer_queue);
+      if (first != list_null (&self->timer_queue))
+       {
+         struct timespec now;
+
+         timer = timer_links2ptr (first);
+
+         /* This assumes that the elements of the list of one thread
+            are all for the same clock.  */
+         clock_gettime (timer->clock, &now);
+
+         while (1)
+           {
+             /* If the timer is due or overdue, remove it from the queue.
+                If it's a periodic timer, re-compute its new time and
+                requeue it.  Either way, perform the timer expiry. */
+             if (timespec_compare (&now, &timer->expirytime) < 0)
+               break;
+
+             list_unlink_ip (first);
+
+             if (__builtin_expect (timer->value.it_interval.tv_sec, 0) != 0
+                 || timer->value.it_interval.tv_nsec != 0)
+               {
+                 timer->overrun_count = 0;
+                 timespec_add (&timer->expirytime, &timer->expirytime,
+                               &timer->value.it_interval);
+                 while (timespec_compare (&timer->expirytime, &now) < 0)
+                   {
+                     timespec_add (&timer->expirytime, &timer->expirytime,
+                                   &timer->value.it_interval);
+                     if (timer->overrun_count < DELAYTIMER_MAX)
+                       ++timer->overrun_count;
+                   }
+                 __timer_thread_queue_timer (self, timer);
+               }
+
+             thread_expire_timer (self, timer);
+
+             first = list_first (&self->timer_queue);
+             if (first == list_null (&self->timer_queue))
+               break;
+
+             timer = timer_links2ptr (first);
+           }
+       }
+
+      /* If the queue is not empty, wait until the expiry time of the
+        first node.  Otherwise wait indefinitely.  Insertions at the
+        head of the queue must wake up the thread by broadcasting
+        this condition variable.  */
+      if (timer != NULL)
+       pthread_cond_timedwait (&self->cond, &__timer_mutex,
+                               &timer->expirytime);
+      else
+       pthread_cond_wait (&self->cond, &__timer_mutex);
+    }
+  /* This macro will never be executed since the while loop loops
+     forever - but we have to add it for proper nesting.  */
+  pthread_cleanup_pop (1);
+}
+
+
+/* Enqueue a timer in wakeup order in the thread's timer queue.
+   Returns 1 if the timer was inserted at the head of the queue,
+   causing the queue's next wakeup time to change. */
+
+int
+__timer_thread_queue_timer (struct thread_node *thread,
+                           struct timer_node *insert)
+{
+  struct list_links *iter;
+  int athead = 1;
+
+  for (iter = list_first (&thread->timer_queue);
+       iter != list_null (&thread->timer_queue);
+        iter = list_next (iter))
+    {
+      struct timer_node *timer = timer_links2ptr (iter);
+
+      if (timespec_compare (&insert->expirytime, &timer->expirytime) < 0)
+         break;
+      athead = 0;
+    }
+
+  list_insbefore (iter, &insert->links);
+  return athead;
+}
+
+
+/* Start a thread and associate it with the given thread node.  Global
+   lock must be held by caller.  */
+int
+__timer_thread_start (struct thread_node *thread)
+{
+  int retval = 1;
+
+  assert (!thread->exists);
+  thread->exists = 1;
+
+  if (pthread_create (&thread->id, &thread->attr,
+                     (void *(*) (void *)) thread_func, thread) != 0)
+    {
+      thread->exists = 0;
+      retval = -1;
+    }
+
+  return retval;
+}
+
+
+void
+__timer_thread_wakeup (struct thread_node *thread)
+{
+  pthread_cond_broadcast (&thread->cond);
+}
+
+
+/* Compare two pthread_attr_t thread attributes for exact equality.
+   Returns 1 if they are equal, otherwise zero if they are not equal
+   or contain illegal values.  This version is NPTL-specific for
+   performance reason.  One could use the access functions to get the
+   values of all the fields of the attribute structure.  */
+static int
+thread_attr_compare (const pthread_attr_t *left, const pthread_attr_t *right)
+{
+  struct pthread_attr *ileft = (struct pthread_attr *) left;
+  struct pthread_attr *iright = (struct pthread_attr *) right;
+
+  return (ileft->flags == iright->flags
+         && ileft->schedpolicy == iright->schedpolicy
+         && (ileft->schedparam.sched_priority
+             == iright->schedparam.sched_priority)
+         && ileft->guardsize == iright->guardsize
+         && ileft->stackaddr == iright->stackaddr
+         && ileft->stacksize == iright->stacksize
+         && ((ileft->cpuset == NULL && iright->cpuset == NULL)
+             || (ileft->cpuset != NULL && iright->cpuset != NULL
+                 && ileft->cpusetsize == iright->cpusetsize
+                 && memcmp (ileft->cpuset, iright->cpuset,
+                            ileft->cpusetsize) == 0)));
+}
+
+
+/* Search the list of active threads and find one which has matching
+   attributes.  Global mutex lock must be held by caller.  */
+struct thread_node *
+__timer_thread_find_matching (const pthread_attr_t *desired_attr,
+                             clockid_t desired_clock_id)
+{
+  struct list_links *iter = list_first (&thread_active_list);
+
+  while (iter != list_null (&thread_active_list))
+    {
+      struct thread_node *candidate = thread_links2ptr (iter);
+
+      if (thread_attr_compare (desired_attr, &candidate->attr)
+         && desired_clock_id == candidate->clock_id)
+       return candidate;
+
+      iter = list_next (iter);
+    }
+
+  return NULL;
+}
+
+
+/* Grab a free timer structure from the global free list.  The global
+   lock must be held by the caller.  */
+struct timer_node *
+__timer_alloc (void)
+{
+  struct list_links *node = list_first (&timer_free_list);
+
+  if (node != list_null (&timer_free_list))
+    {
+      struct timer_node *timer = timer_links2ptr (node);
+      list_unlink_ip (node);
+      timer->inuse = TIMER_INUSE;
+      timer->refcount = 1;
+      return timer;
+    }
+
+  return NULL;
+}
+
+
+/* Return a timer structure to the global free list.  The global lock
+   must be held by the caller.  */
+void
+__timer_dealloc (struct timer_node *timer)
+{
+  assert (timer->refcount == 0);
+  timer->thread = NULL;        /* Break association between timer and thread.  */
+  timer->inuse = TIMER_FREE;
+  list_append (&timer_free_list, &timer->links);
+}
+
+
+/* Thread cancellation handler which unlocks a mutex.  */
+void
+__timer_mutex_cancel_handler (void *arg)
+{
+  pthread_mutex_unlock (arg);
+}
diff --git a/libpthread/nptl/sysdeps/pthread/timer_settime.c b/libpthread/nptl/sysdeps/pthread/timer_settime.c
new file mode 100644 (file)
index 0000000..592b527
--- /dev/null
@@ -0,0 +1,137 @@
+/* Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Kaz Kylheku <kaz@ashi.footprints.net>.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <time.h>
+
+#include "posix-timer.h"
+
+
+/* Set timer TIMERID to VALUE, returning old value in OVLAUE.  */
+int
+timer_settime (timerid, flags, value, ovalue)
+     timer_t timerid;
+     int flags;
+     const struct itimerspec *value;
+     struct itimerspec *ovalue;
+{
+  struct timer_node *timer;
+  struct thread_node *thread = NULL;
+  struct timespec now;
+  int have_now = 0, need_wakeup = 0;
+  int retval = -1;
+
+  timer = timer_id2ptr (timerid);
+  if (timer == NULL)
+    {
+      __set_errno (EINVAL);
+      goto bail;
+    }
+
+  if (value->it_interval.tv_nsec < 0
+      || value->it_interval.tv_nsec >= 1000000000
+      || value->it_value.tv_nsec < 0
+      || value->it_value.tv_nsec >= 1000000000)
+    {
+      __set_errno (EINVAL);
+      goto bail;
+    }
+
+  /* Will need to know current time since this is a relative timer;
+     might as well make the system call outside of the lock now! */
+
+  if ((flags & TIMER_ABSTIME) == 0)
+    {
+      clock_gettime (timer->clock, &now);
+      have_now = 1;
+    }
+
+  pthread_mutex_lock (&__timer_mutex);
+  timer_addref (timer);
+
+  /* One final check of timer validity; this one is possible only
+     until we have the mutex, because it accesses the inuse flag. */
+
+  if (! timer_valid(timer))
+    {
+      __set_errno (EINVAL);
+      goto unlock_bail;
+    }
+
+  if (ovalue != NULL)
+    {
+      ovalue->it_interval = timer->value.it_interval;
+
+      if (timer->armed)
+       {
+         if (! have_now)
+           {
+             pthread_mutex_unlock (&__timer_mutex);
+             clock_gettime (timer->clock, &now);
+             have_now = 1;
+             pthread_mutex_lock (&__timer_mutex);
+             timer_addref (timer);
+           }
+
+         timespec_sub (&ovalue->it_value, &timer->expirytime, &now);
+       }
+      else
+       {
+         ovalue->it_value.tv_sec = 0;
+         ovalue->it_value.tv_nsec = 0;
+       }
+    }
+
+  timer->value = *value;
+
+  list_unlink_ip (&timer->links);
+  timer->armed = 0;
+
+  thread = timer->thread;
+
+  /* A value of { 0, 0 } causes the timer to be stopped. */
+  if (value->it_value.tv_sec != 0
+      || __builtin_expect (value->it_value.tv_nsec != 0, 1))
+    {
+      if ((flags & TIMER_ABSTIME) != 0)
+       /* The user specified the expiration time.  */
+       timer->expirytime = value->it_value;
+      else
+       timespec_add (&timer->expirytime, &now, &value->it_value);
+
+      /* Only need to wake up the thread if timer is inserted
+        at the head of the queue. */
+      if (thread != NULL)
+       need_wakeup = __timer_thread_queue_timer (thread, timer);
+      timer->armed = 1;
+    }
+
+  retval = 0;
+
+unlock_bail:
+  timer_delref (timer);
+  pthread_mutex_unlock (&__timer_mutex);
+
+bail:
+  if (thread != NULL && need_wakeup)
+    __timer_thread_wakeup (thread);
+
+  return retval;
+}
diff --git a/libpthread/nptl/sysdeps/pthread/tpp.c b/libpthread/nptl/sysdeps/pthread/tpp.c
new file mode 100644 (file)
index 0000000..9adab79
--- /dev/null
@@ -0,0 +1,172 @@
+/* Thread Priority Protect helpers.
+   Copyright (C) 2006, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2006.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with 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 <atomic.h>
+#include <errno.h>
+#include <pthreadP.h>
+#include <sched.h>
+#include <stdlib.h>
+#include "uClibc-glue.h"
+
+int __sched_fifo_min_prio = -1;
+int __sched_fifo_max_prio = -1;
+
+void
+__init_sched_fifo_prio (void)
+{
+  __sched_fifo_max_prio = sched_get_priority_max (SCHED_FIFO);
+  atomic_write_barrier ();
+  __sched_fifo_min_prio = sched_get_priority_min (SCHED_FIFO);
+}
+
+int
+__pthread_tpp_change_priority (int previous_prio, int new_prio)
+{
+  struct pthread *self = THREAD_SELF;
+  struct priority_protection_data *tpp = THREAD_GETMEM (self, tpp);
+
+  if (tpp == NULL)
+    {
+      if (__sched_fifo_min_prio == -1)
+       __init_sched_fifo_prio ();
+
+      size_t size = sizeof *tpp;
+      size += (__sched_fifo_max_prio - __sched_fifo_min_prio + 1)
+             * sizeof (tpp->priomap[0]);
+      tpp = calloc (size, 1);
+      if (tpp == NULL)
+       return ENOMEM;
+      tpp->priomax = __sched_fifo_min_prio - 1;
+      THREAD_SETMEM (self, tpp, tpp);
+    }
+
+  assert (new_prio == -1
+         || (new_prio >= __sched_fifo_min_prio
+             && new_prio <= __sched_fifo_max_prio));
+  assert (previous_prio == -1
+         || (previous_prio >= __sched_fifo_min_prio
+             && previous_prio <= __sched_fifo_max_prio));
+
+  int priomax = tpp->priomax;
+  int newpriomax = priomax;
+  if (new_prio != -1)
+    {
+      if (tpp->priomap[new_prio - __sched_fifo_min_prio] + 1 == 0)
+       return EAGAIN;
+      ++tpp->priomap[new_prio - __sched_fifo_min_prio];
+      if (new_prio > priomax)
+       newpriomax = new_prio;
+    }
+
+  if (previous_prio != -1)
+    {
+      if (--tpp->priomap[previous_prio - __sched_fifo_min_prio] == 0
+         && priomax == previous_prio
+         && previous_prio > new_prio)
+       {
+         int i;
+         for (i = previous_prio - 1; i >= __sched_fifo_min_prio; --i)
+           if (tpp->priomap[i - __sched_fifo_min_prio])
+             break;
+         newpriomax = i;
+       }
+    }
+
+  if (priomax == newpriomax)
+    return 0;
+
+  lll_lock (self->lock, LLL_PRIVATE);
+
+  tpp->priomax = newpriomax;
+
+  int result = 0;
+
+  if ((self->flags & ATTR_FLAG_SCHED_SET) == 0)
+    {
+      if (__sched_getparam (self->tid, &self->schedparam) != 0)
+       result = errno;
+      else
+       self->flags |= ATTR_FLAG_SCHED_SET;
+    }
+
+  if ((self->flags & ATTR_FLAG_POLICY_SET) == 0)
+    {
+      self->schedpolicy = __sched_getscheduler (self->tid);
+      if (self->schedpolicy == -1)
+       result = errno;
+      else
+       self->flags |= ATTR_FLAG_POLICY_SET;
+    }
+
+  if (result == 0)
+    {
+      struct sched_param sp = self->schedparam;
+      if (sp.sched_priority < newpriomax || sp.sched_priority < priomax)
+       {
+         if (sp.sched_priority < newpriomax)
+           sp.sched_priority = newpriomax;
+
+         if (__sched_setscheduler (self->tid, self->schedpolicy, &sp) < 0)
+           result = errno;
+       }
+    }
+
+  lll_unlock (self->lock, LLL_PRIVATE);
+
+  return result;
+}
+
+int
+__pthread_current_priority (void)
+{
+  struct pthread *self = THREAD_SELF;
+  if ((self->flags & (ATTR_FLAG_POLICY_SET | ATTR_FLAG_SCHED_SET))
+      == (ATTR_FLAG_POLICY_SET | ATTR_FLAG_SCHED_SET))
+    return self->schedparam.sched_priority;
+
+  int result = 0;
+
+  lll_lock (self->lock, LLL_PRIVATE);
+
+  if ((self->flags & ATTR_FLAG_SCHED_SET) == 0)
+    {
+      if (__sched_getparam (self->tid, &self->schedparam) != 0)
+       result = -1;
+      else
+       self->flags |= ATTR_FLAG_SCHED_SET;
+    }
+
+  if ((self->flags & ATTR_FLAG_POLICY_SET) == 0)
+    {
+      self->schedpolicy = __sched_getscheduler (self->tid);
+      if (self->schedpolicy == -1)
+       result = -1;
+      else
+       self->flags |= ATTR_FLAG_POLICY_SET;
+    }
+
+  if (result != -1)
+    result = self->schedparam.sched_priority;
+
+  lll_unlock (self->lock, LLL_PRIVATE);
+
+  return result;
+}
diff --git a/libpthread/nptl/sysdeps/pthread/uClibc-glue.h b/libpthread/nptl/sysdeps/pthread/uClibc-glue.h
new file mode 100644 (file)
index 0000000..b957ded
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef _UCLIBC_GLUE_H
+#define _UCLIBC_GLUE_H 1
+
+#include <features.h>
+#include <sys/cdefs.h>
+#include <bits/uClibc_page.h>
+
+#ifdef IS_IN_libpthread
+#include <bits/kernel-features.h>
+
+#ifndef __GLIBC_HAVE_LONG_LONG
+# define __GLIBC_HAVE_LONG_LONG
+#endif
+
+#define __getpagesize getpagesize
+#define __sched_get_priority_max sched_get_priority_max
+#define __sched_get_priority_min sched_get_priority_min
+#define __sched_getscheduler sched_getscheduler
+#define __sched_setscheduler sched_setscheduler
+#define __sched_getparam sched_getparam
+#define __getpid getpid
+#define __gettimeofday gettimeofday
+#define __poll poll
+#define __sysctl sysctl
+#define __open open
+#define __read read
+#define __close close
+#define __on_exit on_exit
+#define __libc_current_sigrtmin_private __libc_current_sigrtmin
+#define __clone clone
+
+extern void *__libc_stack_end;
+extern int __cxa_atexit (void (*func) (void *), void *arg, void *d);
+
+#endif /* IS_IN_libpthread */
+
+#ifdef __UCLIBC_HAS_XLOCALE__
+# define __uselocale(x) uselocale(x)
+#else
+# define __uselocale(x) ((void)0)
+#endif
+
+/* Use a funky version in a probably vein attempt at preventing gdb
+ * from dlopen()'ing glibc's libthread_db library... */
+#define VERSION __stringify(__UCLIBC_MAJOR__) "." __stringify(__UCLIBC_MINOR__) "." __stringify(__UCLIBC_SUBLEVEL__)
+
+#endif
diff --git a/libpthread/nptl/sysdeps/pthread/unwind-forcedunwind.c b/libpthread/nptl/sysdeps/pthread/unwind-forcedunwind.c
new file mode 100644 (file)
index 0000000..273c8bb
--- /dev/null
@@ -0,0 +1,151 @@
+/* Copyright (C) 2003, 2005, 2006, 2009 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <dlfcn.h>
+#include <stdio.h>
+#include <unwind.h>
+#include <pthreadP.h>
+#include <sysdep.h>
+#include <libgcc_s.h>
+
+#define __libc_dlopen(x)        dlopen(x, (RTLD_LOCAL | RTLD_LAZY))
+#define __libc_dlsym            dlsym
+#define __libc_dlclose         dlclose
+
+static void *libgcc_s_handle;
+static void (*libgcc_s_resume) (struct _Unwind_Exception *exc);
+static _Unwind_Reason_Code (*libgcc_s_personality)
+  (int, _Unwind_Action, _Unwind_Exception_Class, struct _Unwind_Exception *,
+   struct _Unwind_Context *);
+static _Unwind_Reason_Code (*libgcc_s_forcedunwind)
+  (struct _Unwind_Exception *, _Unwind_Stop_Fn, void *);
+static _Unwind_Word (*libgcc_s_getcfa) (struct _Unwind_Context *);
+
+void
+__attribute_noinline__
+pthread_cancel_init (void)
+{
+  void *resume;
+  void *personality;
+  void *forcedunwind;
+  void *getcfa;
+  void *handle;
+
+  if (__builtin_expect (libgcc_s_handle != NULL, 1))
+    {
+      /* Force gcc to reload all values.  */
+      __asm__ volatile ("" ::: "memory");
+      return;
+    }
+
+  handle = __libc_dlopen (LIBGCC_S_SO);
+
+  if (handle == NULL
+      || (resume = __libc_dlsym (handle, "_Unwind_Resume")) == NULL
+      || (personality = __libc_dlsym (handle, "__gcc_personality_v0")) == NULL
+      || (forcedunwind = __libc_dlsym (handle, "_Unwind_ForcedUnwind"))
+        == NULL
+      || (getcfa = __libc_dlsym (handle, "_Unwind_GetCFA")) == NULL
+#ifdef ARCH_CANCEL_INIT
+      || ARCH_CANCEL_INIT (handle)
+#endif
+      )
+  {
+    printf (LIBGCC_S_SO " must be installed for pthread_cancel to work\n");
+    abort();
+  }
+
+  PTR_MANGLE (resume);
+  libgcc_s_resume = resume;
+  PTR_MANGLE (personality);
+  libgcc_s_personality = personality;
+  PTR_MANGLE (forcedunwind);
+  libgcc_s_forcedunwind = forcedunwind;
+  PTR_MANGLE (getcfa);
+  libgcc_s_getcfa = getcfa;
+  /* Make sure libgcc_s_handle is written last.  Otherwise,
+     pthread_cancel_init might return early even when the pointer the
+     caller is interested in is not initialized yet.  */
+  atomic_write_barrier ();
+  libgcc_s_handle = handle;
+}
+
+void
+__libc_freeres_fn_section
+__unwind_freeres (void)
+{
+  void *handle = libgcc_s_handle;
+  if (handle != NULL)
+    {
+      libgcc_s_handle = NULL;
+      __libc_dlclose (handle);
+    }
+}
+
+void
+_Unwind_Resume (struct _Unwind_Exception *exc)
+{
+  if (__builtin_expect (libgcc_s_handle == NULL, 0))
+    pthread_cancel_init ();
+
+  void (*resume) (struct _Unwind_Exception *exc) = libgcc_s_resume;
+  PTR_DEMANGLE (resume);
+  resume (exc);
+}
+
+_Unwind_Reason_Code
+__gcc_personality_v0 (int version, _Unwind_Action actions,
+                     _Unwind_Exception_Class exception_class,
+                      struct _Unwind_Exception *ue_header,
+                      struct _Unwind_Context *context)
+{
+  if (__builtin_expect (libgcc_s_handle == NULL, 0))
+    pthread_cancel_init ();
+
+  _Unwind_Reason_Code (*personality)
+    (int, _Unwind_Action, _Unwind_Exception_Class, struct _Unwind_Exception *,
+     struct _Unwind_Context *) = libgcc_s_personality;
+  PTR_DEMANGLE (personality);
+  return personality (version, actions, exception_class, ue_header, context);
+}
+
+_Unwind_Reason_Code
+_Unwind_ForcedUnwind (struct _Unwind_Exception *exc, _Unwind_Stop_Fn stop,
+                     void *stop_argument)
+{
+  if (__builtin_expect (libgcc_s_handle == NULL, 0))
+    pthread_cancel_init ();
+
+  _Unwind_Reason_Code (*forcedunwind)
+    (struct _Unwind_Exception *, _Unwind_Stop_Fn, void *)
+    = libgcc_s_forcedunwind;
+  PTR_DEMANGLE (forcedunwind);
+  return forcedunwind (exc, stop, stop_argument);
+}
+
+_Unwind_Word
+_Unwind_GetCFA (struct _Unwind_Context *context)
+{
+  if (__builtin_expect (libgcc_s_handle == NULL, 0))
+    pthread_cancel_init ();
+
+  _Unwind_Word (*getcfa) (struct _Unwind_Context *) = libgcc_s_getcfa;
+  PTR_DEMANGLE (getcfa);
+  return getcfa (context);
+}
diff --git a/libpthread/nptl/sysdeps/pthread/unwind-resume.c b/libpthread/nptl/sysdeps/pthread/unwind-resume.c
new file mode 100644 (file)
index 0000000..94da075
--- /dev/null
@@ -0,0 +1,76 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unwind.h>
+#include <libgcc_s.h>
+
+#define __libc_dlopen(x)        dlopen(x, (RTLD_LOCAL | RTLD_LAZY))
+#define __libc_dlsym            dlsym
+#define __libc_dlclose          dlclose
+
+static void (*libgcc_s_resume) (struct _Unwind_Exception *exc);
+static _Unwind_Reason_Code (*libgcc_s_personality)
+  (int, _Unwind_Action, _Unwind_Exception_Class, struct _Unwind_Exception *,
+   struct _Unwind_Context *);
+
+extern
+void abort(void);
+
+static void
+init (void)
+{
+  void *resume, *personality;
+  void *handle;
+  resume = personality = NULL;
+  handle = dlopen (LIBGCC_S_SO, (RTLD_LOCAL | RTLD_LAZY));
+
+  if (handle == NULL
+      || (resume = dlsym (handle, "_Unwind_Resume")) == NULL
+      || (personality = dlsym (handle, "__gcc_personality_v0")) == NULL)
+  {
+    printf (LIBGCC_S_SO " must be installed for pthread_cancel to work\n");
+    abort();
+  }
+
+  libgcc_s_resume = resume;
+  libgcc_s_personality = personality;
+}
+
+void
+_Unwind_Resume (struct _Unwind_Exception *exc)
+{
+  if (__builtin_expect (libgcc_s_resume == NULL, 0))
+    init ();
+  libgcc_s_resume (exc);
+}
+
+_Unwind_Reason_Code
+__gcc_personality_v0 (int version, _Unwind_Action actions,
+                     _Unwind_Exception_Class exception_class,
+                      struct _Unwind_Exception *ue_header,
+                      struct _Unwind_Context *context)
+{
+  if (__builtin_expect (libgcc_s_personality == NULL, 0))
+    init ();
+  return libgcc_s_personality (version, actions, exception_class,
+                              ue_header, context);
+}
diff --git a/libpthread/nptl/sysdeps/sh/Makefile b/libpthread/nptl/sysdeps/sh/Makefile
new file mode 100644 (file)
index 0000000..81bddf6
--- /dev/null
@@ -0,0 +1,3 @@
+ifeq ($(subdir),csu)
+gen-as-const-headers += tcb-offsets.sym
+endif
diff --git a/libpthread/nptl/sysdeps/sh/Makefile.arch b/libpthread/nptl/sysdeps/sh/Makefile.arch
new file mode 100644 (file)
index 0000000..541901c
--- /dev/null
@@ -0,0 +1,56 @@
+# Makefile for uClibc NPTL
+#
+# Copyright (C) 2005 Steven J. Hill <sjhill@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+libpthread_SSRC = pthread_spin_unlock.S pthread_spin_trylock.S
+libpthread_CSRC = pthread_spin_lock.c pthread_spin_init.c
+
+ASFLAGS-pthread_spin_unlock.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1
+ASFLAGS-pthread_spin_trylock.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1
+
+CFLAGS-pthread_spin_lock.c += -D_GNU_SOURCE
+
+CFLAGS-sh = $(SSP_ALL_CFLAGS)
+#CFLAGS:=$(CFLAGS:-O1=-O2)
+
+PTHREAD_ARCH_DIR := $(top_srcdir)libpthread/nptl/sysdeps/sh
+PTHREAD_ARCH_OUT := $(top_builddir)libpthread/nptl/sysdeps/sh
+PTHREAD_ARCH_OBJ := $(patsubst %.S,$(PTHREAD_ARCH_OUT)/%.o,$(libpthread_SSRC))
+PTHREAD_ARCH_OBJ += $(patsubst %.c,$(PTHREAD_ARCH_OUT)/%.o,$(libpthread_CSRC))
+
+ifeq ($(DOPIC),y)
+libpthread-a-y += $(PTHREAD_ARCH_OBJ:.o=.os)
+else
+libpthread-a-y += $(PTHREAD_ARCH_OBJ)
+endif
+libpthread-so-y += $(PTHREAD_ARCH_OBJ:.o=.oS)
+
+libpthread-nomulti-y += $(PTHREAD_ARCH_OBJ)
+
+objclean-y += nptl_arch_clean
+headers_clean-y += nptl_arch_headers_clean
+
+#
+# Create 'tcb-offsets.h' header file.
+#
+CFLAGS-tcb-offsets.c = -S
+
+$(PTHREAD_ARCH_OUT)/tcb-offsets.c: $(PTHREAD_ARCH_DIR)/tcb-offsets.sym
+       $(do_awk) $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@
+
+$(PTHREAD_ARCH_OUT)/tcb-offsets.s: $(PTHREAD_ARCH_OUT)/tcb-offsets.c
+       $(compile.c)
+
+$(PTHREAD_ARCH_OUT)/tcb-offsets.h: $(PTHREAD_ARCH_OUT)/tcb-offsets.s
+       $(do_sed) -n "s/^.*@@@name@@@\([^@]*\)@@@value@@@[^0-9Xxa-fA-F-]*\([0-9Xxa-fA-F-][0-9Xxa-fA-F-]*\).*@@@end@@@.*$\/#define \1 \2/p" $< > $@
+
+pregen-headers-$(UCLIBC_HAS_THREADS_NATIVE) += $(PTHREAD_ARCH_OUT)/tcb-offsets.h
+
+nptl_arch_headers_clean:
+       $(do_rm) $(addprefix $(PTHREAD_ARCH_OUT)/tcb-offsets., c s h)
+
+nptl_arch_clean:
+       $(do_rm) $(addprefix $(PTHREAD_ARCH_OUT)/*., o os oS)
diff --git a/libpthread/nptl/sysdeps/sh/dl-tls.h b/libpthread/nptl/sysdeps/sh/dl-tls.h
new file mode 100644 (file)
index 0000000..98e2f19
--- /dev/null
@@ -0,0 +1,29 @@
+/* Thread-local storage handling in the ELF dynamic linker.  SH 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.  */
+
+
+/* Type used for the representation of TLS information in the GOT.  */
+typedef struct
+{
+  unsigned long int ti_module;
+  unsigned long int ti_offset;
+} tls_index;
+
+
+extern void *__tls_get_addr (tls_index *ti);
diff --git a/libpthread/nptl/sysdeps/sh/jmpbuf-unwind.h b/libpthread/nptl/sysdeps/sh/jmpbuf-unwind.h
new file mode 100644 (file)
index 0000000..41c3c39
--- /dev/null
@@ -0,0 +1,33 @@
+/* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <setjmp.h>
+#include <stdint.h>
+#include <unwind.h>
+
+#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \
+  _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj)
+
+#define _JMPBUF_UNWINDS_ADJ(jmpbuf, address, adj) \
+  ((uintptr_t) (address) - (adj) < (uintptr_t) (jmpbuf)[0].__regs[7] - (adj))
+
+extern __typeof(longjmp) __libc_longjmp attribute_noreturn;
+
+/* We use the normal lobngjmp for unwinding.  */
+#define __libc_unwind_longjmp(buf, val) __libc_longjmp (buf, val)
diff --git a/libpthread/nptl/sysdeps/sh/pthread_spin_init.c b/libpthread/nptl/sysdeps/sh/pthread_spin_init.c
new file mode 100644 (file)
index 0000000..0a47981
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* Not needed.  pthread_spin_init is an alias for pthread_spin_unlock.  */
diff --git a/libpthread/nptl/sysdeps/sh/pthread_spin_lock.c b/libpthread/nptl/sysdeps/sh/pthread_spin_lock.c
new file mode 100644 (file)
index 0000000..d158183
--- /dev/null
@@ -0,0 +1,35 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+
+int
+pthread_spin_lock (lock)
+     pthread_spinlock_t *lock;
+{
+  unsigned int val;
+
+  do
+    __asm__ volatile ("tas.b @%1; movt %0"
+                 : "=&r" (val)
+                 : "r" (lock)
+                 : "memory");
+  while (val == 0);
+
+  return 0;
+}
diff --git a/libpthread/nptl/sysdeps/sh/pthread_spin_trylock.S b/libpthread/nptl/sysdeps/sh/pthread_spin_trylock.S
new file mode 100644 (file)
index 0000000..18112ba
--- /dev/null
@@ -0,0 +1,32 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread-errnos.h>
+
+       .globl  pthread_spin_trylock
+       .type   pthread_spin_trylock,@function
+       .align  5
+pthread_spin_trylock:
+       tas.b   @r4
+       bf/s    1f
+       mov     #EBUSY, r0
+       mov     #0, r0
+1:
+       rts
+        nop
+       .size   pthread_spin_trylock,.-pthread_spin_trylock
diff --git a/libpthread/nptl/sysdeps/sh/pthread_spin_unlock.S b/libpthread/nptl/sysdeps/sh/pthread_spin_unlock.S
new file mode 100644 (file)
index 0000000..c77acaf
--- /dev/null
@@ -0,0 +1,30 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+       .globl  pthread_spin_unlock
+       .type   pthread_spin_unlock,@function
+       .align  5
+pthread_spin_unlock:
+       mov     #0,r0
+       rts
+        mov.l  r0,@r4
+       .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/libpthread/nptl/sysdeps/sh/pthreaddef.h b/libpthread/nptl/sysdeps/sh/pthreaddef.h
new file mode 100644 (file)
index 0000000..c1902fb
--- /dev/null
@@ -0,0 +1,49 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+
+/* Default stack size.  */
+#define ARCH_STACK_DEFAULT_SIZE        (2 * 1024 * 1024)
+
+/* Required stack pointer alignment at beginning.  */
+#define STACK_ALIGN            8
+
+/* Minimal stack size after allocating thread descriptor and guard size.  */
+#define MINIMAL_REST_STACK     2048
+
+/* Alignment requirement for TCB.  */
+#define TCB_ALIGNMENT          8
+
+
+/* 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 ("mov #0,r4; mov %0,r3; trapa #0x11\n\t" SYSCALL_INST_PAD  \
+                  :: "i" (__NR_exit));  \
+    else                                                                     \
+      __asm__ volatile ("mov %1,r4; mov %0,r3; trapa #0x11\n\t" SYSCALL_INST_PAD  \
+                   :: "i" (__NR_exit), "r" (val));                           \
+  }
diff --git a/libpthread/nptl/sysdeps/sh/tcb-offsets.sym b/libpthread/nptl/sysdeps/sh/tcb-offsets.sym
new file mode 100644 (file)
index 0000000..753b72b
--- /dev/null
@@ -0,0 +1,15 @@
+#include <sysdep.h>
+#include <tls.h>
+
+RESULT                 offsetof (struct pthread, result)
+TID                    offsetof (struct pthread, tid)
+PID                    offsetof (struct pthread, pid)
+CANCELHANDLING         offsetof (struct pthread, cancelhandling)
+CLEANUP_JMP_BUF                offsetof (struct pthread, cleanup_jmp_buf)
+MULTIPLE_THREADS_OFFSET        offsetof (struct pthread, header.multiple_threads)
+TLS_PRE_TCB_SIZE       sizeof (struct pthread)
+MUTEX_FUTEX            offsetof (pthread_mutex_t, __data.__lock)
+POINTER_GUARD          offsetof (tcbhead_t, pointer_guard)
+#ifndef __ASSUME_PRIVATE_FUTEX
+PRIVATE_FUTEX          offsetof (struct pthread, header.private_futex)
+#endif
diff --git a/libpthread/nptl/sysdeps/sh/tls.h b/libpthread/nptl/sysdeps/sh/tls.h
new file mode 100644 (file)
index 0000000..2c538ed
--- /dev/null
@@ -0,0 +1,182 @@
+/* Definition for thread-local data handling.  NPTL/SH version.
+   Copyright (C) 2003, 2005, 2006, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _TLS_H
+#define _TLS_H
+
+#ifndef __ASSEMBLER__
+# include <stdbool.h>
+# include <stddef.h>
+# include <stdint.h>
+# include <stdlib.h>
+# include <list.h>
+# include <sysdep.h>
+# include <bits/kernel-features.h>
+
+/* Type for the dtv.  */
+typedef union dtv
+{
+  size_t counter;
+  struct
+  {
+    void *val;
+    bool is_static;
+  } pointer;
+} dtv_t;
+
+typedef struct
+{
+  dtv_t *dtv;
+  uintptr_t pointer_guard;
+} tcbhead_t;
+
+# define TLS_MULTIPLE_THREADS_IN_TCB 1
+
+#else /* __ASSEMBLER__ */
+# include <tcb-offsets.h>
+#endif /* __ASSEMBLER__ */
+
+
+/* We require TLS support in the tools.  */
+#define HAVE_TLS_SUPPORT
+#define HAVE___THREAD   1
+#define HAVE_TLS_MODEL_ATTRIBUTE       1
+/* Signal that TLS support is available.  */
+# define USE_TLS       1
+
+#ifndef __ASSEMBLER__
+
+/* Get system call information.  */
+# include <sysdep.h>
+
+/* This is the size of the initial TCB.  */
+# define TLS_INIT_TCB_SIZE sizeof (tcbhead_t)
+
+/* Alignment requirements for the initial TCB.  */
+# define TLS_INIT_TCB_ALIGN __alignof__ (tcbhead_t)
+
+/* This is the size of the TCB.  */
+# define TLS_TCB_SIZE sizeof (tcbhead_t)
+
+/* This is the size we need before TCB.  */
+# define TLS_PRE_TCB_SIZE sizeof (struct pthread)
+
+/* Alignment requirements for the TCB.  */
+# define TLS_TCB_ALIGN __alignof__ (struct pthread)
+
+/* The TLS blocks start right after the TCB.  */
+# define TLS_DTV_AT_TP 1
+
+/* Get the thread descriptor definition.  */
+# include <descr.h>
+
+/* Install the dtv pointer.  The pointer passed is to the element with
+   index -1 which contain the length.  */
+# define INSTALL_DTV(tcbp, dtvp) \
+  ((tcbhead_t *) (tcbp))->dtv = (dtvp) + 1
+
+/* Install new dtv for current thread.  */
+# define INSTALL_NEW_DTV(dtv) \
+  ({ tcbhead_t *__tcbp;                                                              \
+     __asm __volatile ("stc gbr,%0" : "=r" (__tcbp));                        \
+     __tcbp->dtv = (dtv);})
+
+/* Return dtv of given thread descriptor.  */
+# define GET_DTV(tcbp) \
+  (((tcbhead_t *) (tcbp))->dtv)
+
+/* Code to initially initialize the thread pointer.  This might need
+   special attention since 'errno' is not yet available and if the
+   operation can cause a failure 'errno' must not be touched.  */
+# define TLS_INIT_TP(tcbp, secondcall) \
+  ({ __asm __volatile ("ldc %0,gbr" : : "r" (tcbp)); 0; })
+
+/* Return the address of the dtv for the current thread.  */
+# define THREAD_DTV() \
+  ({ tcbhead_t *__tcbp;                                                              \
+     __asm __volatile ("stc gbr,%0" : "=r" (__tcbp));                        \
+     __tcbp->dtv;})
+
+/* Return the thread descriptor for the current thread.
+   The contained asm must *not* be marked volatile since otherwise
+   assignments like
+        struct pthread *self = thread_self();
+   do not get optimized away.  */
+# define THREAD_SELF \
+  ({ struct pthread *__self;                                                 \
+     __asm ("stc gbr,%0" : "=r" (__self));                                   \
+     __self - 1;})
+
+/* Magic for libthread_db to know how to do THREAD_SELF.  */
+# define DB_THREAD_SELF \
+  REGISTER (32, 32, REG_GBR * 4, -sizeof (struct pthread))
+
+/* Read member of the thread descriptor directly.  */
+# define THREAD_GETMEM(descr, member) (descr->member)
+
+/* Same as THREAD_GETMEM, but the member offset can be non-constant.  */
+# define THREAD_GETMEM_NC(descr, member, idx) (descr->member[idx])
+
+/* Set member of the thread descriptor directly.  */
+# define THREAD_SETMEM(descr, member, value) \
+    descr->member = (value)
+
+/* Same as THREAD_SETMEM, but the member offset can be non-constant.  */
+# define THREAD_SETMEM_NC(descr, member, idx, value) \
+    descr->member[idx] = (value)
+
+#define THREAD_GET_POINTER_GUARD() \
+  ({ tcbhead_t *__tcbp;                                                              \
+     __asm __volatile ("stc gbr,%0" : "=r" (__tcbp));                        \
+     __tcbp->pointer_guard;})
+ #define THREAD_SET_POINTER_GUARD(value) \
+  ({ tcbhead_t *__tcbp;                                                              \
+     __asm __volatile ("stc gbr,%0" : "=r" (__tcbp));                        \
+     __tcbp->pointer_guard = (value);})
+#define THREAD_COPY_POINTER_GUARD(descr) \
+  ({ tcbhead_t *__tcbp;                                                              \
+     __asm __volatile ("stc gbr,%0" : "=r" (__tcbp));                        \
+     ((tcbhead_t *) (descr + 1))->pointer_guard        = __tcbp->pointer_guard;})
+
+/* Get and set the global scope generation counter in struct pthread.  */
+#define THREAD_GSCOPE_FLAG_UNUSED 0
+#define THREAD_GSCOPE_FLAG_USED   1
+#define THREAD_GSCOPE_FLAG_WAIT   2
+#define THREAD_GSCOPE_RESET_FLAG() \
+  do                                                                        \
+    { int __res                                                                     \
+       = atomic_exchange_rel (&THREAD_SELF->header.gscope_flag,             \
+                              THREAD_GSCOPE_FLAG_UNUSED);                   \
+      if (__res == THREAD_GSCOPE_FLAG_WAIT)                                 \
+       lll_futex_wake (&THREAD_SELF->header.gscope_flag, 1, LLL_PRIVATE);   \
+    }                                                                       \
+  while (0)
+#define THREAD_GSCOPE_SET_FLAG() \
+  do                                                                        \
+    {                                                                       \
+      THREAD_SELF->header.gscope_flag = THREAD_GSCOPE_FLAG_USED;            \
+      atomic_write_barrier ();                                              \
+    }                                                                       \
+  while (0)
+#define THREAD_GSCOPE_WAIT() \
+  GL(dl_wait_lookup_done) ()
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* tls.h */
diff --git a/libpthread/nptl/sysdeps/sparc/Makefile b/libpthread/nptl/sysdeps/sparc/Makefile
new file mode 100644 (file)
index 0000000..81bddf6
--- /dev/null
@@ -0,0 +1,3 @@
+ifeq ($(subdir),csu)
+gen-as-const-headers += tcb-offsets.sym
+endif
diff --git a/libpthread/nptl/sysdeps/sparc/Makefile.arch b/libpthread/nptl/sysdeps/sparc/Makefile.arch
new file mode 100644 (file)
index 0000000..632b75b
--- /dev/null
@@ -0,0 +1,53 @@
+# Makefile for uClibc NPTL
+#
+# Copyright (C) 2005 Steven J. Hill <sjhill@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+libpthread_CSRC = sparc32/pthread_spin_lock.c \
+                                 sparc32/pthread_spin_trylock.c
+
+CFLAGS-pthread_spin_lock.c += -D_GNU_SOURCE
+
+CFLAGS-sparc = $(SSP_ALL_CFLAGS)
+#CFLAGS:=$(CFLAGS:-O1=-O2)
+
+PTHREAD_ARCH_DIR := $(top_srcdir)libpthread/nptl/sysdeps/sparc
+PTHREAD_ARCH_OUT := $(top_builddir)libpthread/nptl/sysdeps/sparc
+PTHREAD_ARCH_OBJ := $(patsubst %.S,$(PTHREAD_ARCH_OUT)/%.o,$(libpthread_SSRC))
+PTHREAD_ARCH_OBJ += $(patsubst %.c,$(PTHREAD_ARCH_OUT)/%.o,$(libpthread_CSRC))
+
+ifeq ($(DOPIC),y)
+libpthread-a-y += $(PTHREAD_ARCH_OBJ:.o=.os)
+else
+libpthread-a-y += $(PTHREAD_ARCH_OBJ)
+endif
+libpthread-so-y += $(PTHREAD_ARCH_OBJ:.o=.oS)
+
+libpthread-nomulti-y += $(PTHREAD_ARCH_OBJ)
+
+objclean-y += nptl_arch_clean
+headers_clean-y += nptl_arch_headers_clean
+
+#
+# Create 'tcb-offsets.h' header file.
+#
+CFLAGS-tcb-offsets.c = -S
+
+$(PTHREAD_ARCH_OUT)/tcb-offsets.c: $(PTHREAD_ARCH_DIR)/tcb-offsets.sym
+       $(do_awk) $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@
+
+$(PTHREAD_ARCH_OUT)/tcb-offsets.s: $(PTHREAD_ARCH_OUT)/tcb-offsets.c
+       $(compile.c)
+
+$(PTHREAD_ARCH_OUT)/tcb-offsets.h: $(PTHREAD_ARCH_OUT)/tcb-offsets.s
+       $(do_sed) -n "s/^.*@@@name@@@\([^@]*\)@@@value@@@[^0-9Xxa-fA-F-]*\([0-9Xxa-fA-F-][0-9Xxa-fA-F-]*\).*@@@end@@@.*$\/#define \1 \2/p" $< > $@
+
+pregen-headers-$(UCLIBC_HAS_THREADS_NATIVE) += $(PTHREAD_ARCH_OUT)/tcb-offsets.h
+
+nptl_arch_headers_clean:
+       $(do_rm) $(addprefix $(PTHREAD_ARCH_OUT)/tcb-offsets., c s h)
+
+nptl_arch_clean:
+       $(do_rm) $(addprefix $(PTHREAD_ARCH_OUT)/*., o os oS)
diff --git a/libpthread/nptl/sysdeps/sparc/dl-tls.h b/libpthread/nptl/sysdeps/sparc/dl-tls.h
new file mode 100644 (file)
index 0000000..6edf8d5
--- /dev/null
@@ -0,0 +1,29 @@
+/* Thread-local storage handling in the ELF dynamic linker.  SPARC version.
+   Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+
+/* Type used for the representation of TLS information in the GOT.  */
+typedef struct
+{
+  unsigned long int ti_module;
+  unsigned long int ti_offset;
+} tls_index;
+
+
+extern void *__tls_get_addr (tls_index *ti);
diff --git a/libpthread/nptl/sysdeps/sparc/jmpbuf-unwind.h b/libpthread/nptl/sysdeps/sparc/jmpbuf-unwind.h
new file mode 100644 (file)
index 0000000..6cbb37b
--- /dev/null
@@ -0,0 +1,5 @@
+#if defined(__arch64__)
+#include "sparc64/jmpbuf-unwind.h"
+#else
+#include "sparc32/jmpbuf-unwind.h"
+#endif
diff --git a/libpthread/nptl/sysdeps/sparc/pthreaddef.h b/libpthread/nptl/sysdeps/sparc/pthreaddef.h
new file mode 100644 (file)
index 0000000..d4695c4
--- /dev/null
@@ -0,0 +1,5 @@
+#if defined(__arch64__)
+#include "sparc64/pthreaddef.h"
+#else
+#include "sparc32/pthreaddef.h"
+#endif
diff --git a/libpthread/nptl/sysdeps/sparc/sparc32/jmpbuf-unwind.h b/libpthread/nptl/sysdeps/sparc/sparc32/jmpbuf-unwind.h
new file mode 100644 (file)
index 0000000..71a3582
--- /dev/null
@@ -0,0 +1,32 @@
+/* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <setjmp.h>
+#include <stdint.h>
+#include <unwind.h>
+
+#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \
+  _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj)
+
+#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \
+  ((uintptr_t) (_address) - (_adj) < (uintptr_t) (_jmpbuf)[JB_SP] - (_adj))
+
+/* We use the normal longjmp for unwinding.  */
+extern __typeof(longjmp) __libc_longjmp attribute_noreturn;
+#define __libc_unwind_longjmp(buf, val) __libc_longjmp (buf, val)
diff --git a/libpthread/nptl/sysdeps/sparc/sparc32/pthread_spin_lock.c b/libpthread/nptl/sysdeps/sparc/sparc32/pthread_spin_lock.c
new file mode 100644 (file)
index 0000000..d3c6e30
--- /dev/null
@@ -0,0 +1,40 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+
+int
+pthread_spin_lock (pthread_spinlock_t *lock)
+{
+  __asm __volatile
+    ("1: ldstub [%0], %%g2\n"
+     "   orcc   %%g2, 0x0, %%g0\n"
+     "   bne,a  2f\n"
+     "   ldub   [%0], %%g2\n"
+     ".subsection 2\n"
+     "2: orcc   %%g2, 0x0, %%g0\n"
+     "   bne,a  2b\n"
+     "   ldub   [%0], %%g2\n"
+     "   b,a    1b\n"
+     ".previous"
+     : /* no outputs */
+     : "r" (lock)
+     : "g2", "memory", "cc");
+  return 0;
+}
diff --git a/libpthread/nptl/sysdeps/sparc/sparc32/pthread_spin_trylock.c b/libpthread/nptl/sysdeps/sparc/sparc32/pthread_spin_trylock.c
new file mode 100644 (file)
index 0000000..bcc3158
--- /dev/null
@@ -0,0 +1,29 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include "pthreadP.h"
+
+int
+pthread_spin_trylock (pthread_spinlock_t *lock)
+{
+  int res;
+  __asm __volatile ("ldstub [%1], %0" : "=r" (res) : "r" (lock) : "memory");
+  return res == 0 ? 0 : EBUSY;
+}
diff --git a/libpthread/nptl/sysdeps/sparc/sparc32/pthreaddef.h b/libpthread/nptl/sysdeps/sparc/sparc32/pthreaddef.h
new file mode 100644 (file)
index 0000000..9908df9
--- /dev/null
@@ -0,0 +1,40 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* Default stack size.  */
+#define ARCH_STACK_DEFAULT_SIZE        (2 * 1024 * 1024)
+
+/* Required stack pointer alignment at beginning.  */
+#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
+
+
+/* Location of current stack frame.  */
+#define CURRENT_STACK_FRAME  (stack_pointer + (2 * 64))
+register char *stack_pointer __asm__("%sp");
+
+/* XXX Until we have a better place keep the definitions here.  */
+
+/* While there is no such syscall.  */
+#define __exit_thread_inline(val) \
+  INLINE_SYSCALL (exit, 1, (val))
diff --git a/libpthread/nptl/sysdeps/sparc/sparc32/sparcv9/pthread_spin_lock.c b/libpthread/nptl/sysdeps/sparc/sparc32/sparcv9/pthread_spin_lock.c
new file mode 100644 (file)
index 0000000..8880f53
--- /dev/null
@@ -0,0 +1,39 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+
+int
+pthread_spin_lock (pthread_spinlock_t *lock)
+{
+  __asm __volatile
+    ("1: ldstub  [%0], %%g2\n"
+     "   brnz,pn %%g2, 2f\n"
+     "    membar #StoreLoad | #StoreStore\n"
+     ".subsection 2\n"
+     "2: ldub    [%0], %%g2\n"
+     "   brnz,pt %%g2, 2b\n"
+     "    membar #LoadLoad\n"
+     "   b,a,pt  %%xcc, 1b\n"
+     ".previous"
+     : /* no outputs */
+     : "r" (lock)
+     : "g2", "memory");
+  return 0;
+}
diff --git a/libpthread/nptl/sysdeps/sparc/sparc32/sparcv9/pthread_spin_trylock.c b/libpthread/nptl/sysdeps/sparc/sparc32/sparcv9/pthread_spin_trylock.c
new file mode 100644 (file)
index 0000000..3b20a21
--- /dev/null
@@ -0,0 +1 @@
+#include <sparc64/pthread_spin_trylock.c>
diff --git a/libpthread/nptl/sysdeps/sparc/sparc32/sparcv9/pthread_spin_unlock.c b/libpthread/nptl/sysdeps/sparc/sparc32/sparcv9/pthread_spin_unlock.c
new file mode 100644 (file)
index 0000000..482cbe3
--- /dev/null
@@ -0,0 +1 @@
+#include <sparc64/pthread_spin_unlock.c>
diff --git a/libpthread/nptl/sysdeps/sparc/sparc64/jmpbuf-unwind.h b/libpthread/nptl/sysdeps/sparc/sparc64/jmpbuf-unwind.h
new file mode 100644 (file)
index 0000000..5cef8b1
--- /dev/null
@@ -0,0 +1,31 @@
+/* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <setjmp.h>
+#include <stdint.h>
+#include <unwind.h>
+
+#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \
+  _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj)
+
+#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \
+  ((uintptr_t) (_address) - (_adj) < (uintptr_t) (_jmpbuf)[JB_SP] - (_adj))
+
+/* We use the normal lobngjmp for unwinding.  */
+#define __libc_unwind_longjmp(buf, val) __libc_longjmp (buf, val)
diff --git a/libpthread/nptl/sysdeps/sparc/sparc64/pthread_spin_lock.c b/libpthread/nptl/sysdeps/sparc/sparc64/pthread_spin_lock.c
new file mode 100644 (file)
index 0000000..77171d9
--- /dev/null
@@ -0,0 +1,39 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+
+int
+pthread_spin_lock (pthread_spinlock_t *lock)
+{
+  __asm __volatile
+    ("1: ldstub  [%0], %%g5\n"
+     "   brnz,pn %%g5, 2f\n"
+     "    membar #StoreLoad | #StoreStore\n"
+     ".subsection 2\n"
+     "2: ldub    [%0], %%g5\n"
+     "   brnz,pt %%g5, 2b\n"
+     "    membar #LoadLoad\n"
+     "   b,a,pt  %%xcc, 1b\n"
+     ".previous"
+     : /* no outputs */
+     : "r" (lock)
+     : "g5", "memory");
+  return 0;
+}
diff --git a/libpthread/nptl/sysdeps/sparc/sparc64/pthread_spin_trylock.c b/libpthread/nptl/sysdeps/sparc/sparc64/pthread_spin_trylock.c
new file mode 100644 (file)
index 0000000..2bda809
--- /dev/null
@@ -0,0 +1,34 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include "pthreadP.h"
+
+int
+pthread_spin_trylock (pthread_spinlock_t *lock)
+{
+  int res;
+  __asm __volatile
+    ("ldstub [%1], %0\n"
+     "membar #StoreLoad | #StoreStore"
+     : "=r" (res)
+     : "r" (lock)
+     : "memory");
+  return res == 0 ? 0 : EBUSY;
+}
diff --git a/libpthread/nptl/sysdeps/sparc/sparc64/pthread_spin_unlock.c b/libpthread/nptl/sysdeps/sparc/sparc64/pthread_spin_unlock.c
new file mode 100644 (file)
index 0000000..7037675
--- /dev/null
@@ -0,0 +1,30 @@
+/* pthread_spin_unlock -- unlock a spin lock.  Generic version.
+   Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+#include <atomic.h>
+
+int
+pthread_spin_unlock (pthread_spinlock_t *lock)
+{
+  __asm __volatile ("membar #StoreStore | #LoadStore");
+  *lock = 0;
+  return 0;
+}
diff --git a/libpthread/nptl/sysdeps/sparc/sparc64/pthreaddef.h b/libpthread/nptl/sysdeps/sparc/sparc64/pthreaddef.h
new file mode 100644 (file)
index 0000000..ec76512
--- /dev/null
@@ -0,0 +1,40 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* Default stack size.  */
+#define ARCH_STACK_DEFAULT_SIZE        (4 * 1024 * 1024)
+
+/* Required stack pointer alignment at beginning.  */
+#define STACK_ALIGN            16
+
+/* Minimal stack size after allocating thread descriptor and guard size.  */
+#define MINIMAL_REST_STACK     4096
+
+/* Alignment requirement for TCB.  */
+#define TCB_ALIGNMENT          16
+
+
+/* Location of current stack frame.  */
+#define CURRENT_STACK_FRAME  (stack_pointer + (2 * 128))
+register char *stack_pointer __asm__("%sp");
+
+/* XXX Until we have a better place keep the definitions here.  */
+
+/* While there is no such syscall.  */
+#define __exit_thread_inline(val) \
+  INLINE_SYSCALL (exit, 1, (val))
diff --git a/libpthread/nptl/sysdeps/sparc/tcb-offsets.sym b/libpthread/nptl/sysdeps/sparc/tcb-offsets.sym
new file mode 100644 (file)
index 0000000..923af8a
--- /dev/null
@@ -0,0 +1,7 @@
+#include <sysdep.h>
+#include <tls.h>
+
+MULTIPLE_THREADS_OFFSET                offsetof (tcbhead_t, multiple_threads)
+POINTER_GUARD                  offsetof (tcbhead_t, pointer_guard)
+PID                            offsetof (struct pthread, pid)
+TID                            offsetof (struct pthread, tid)
diff --git a/libpthread/nptl/sysdeps/sparc/tls.h b/libpthread/nptl/sysdeps/sparc/tls.h
new file mode 100644 (file)
index 0000000..e93542c
--- /dev/null
@@ -0,0 +1,181 @@
+/* Definitions for thread-local data handling.  NPTL/sparc version.
+   Copyright (C) 2003, 2005, 2006, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _TLS_H
+#define _TLS_H
+
+#ifndef __ASSEMBLER__
+# include <stdbool.h>
+# include <stddef.h>
+# include <stdint.h>
+# include <stdlib.h>
+# include <list.h>
+# include <bits/kernel-features.h>
+
+/* Type for the dtv.  */
+typedef union dtv
+{
+  size_t counter;
+  struct
+  {
+    void *val;
+    bool is_static;
+  } pointer;
+} dtv_t;
+
+typedef struct
+{
+  void *tcb;           /* Pointer to the TCB.  Not necessary the
+                          thread descriptor used by libpthread.  */
+  dtv_t *dtv;
+  void *self;
+  int multiple_threads;
+#if __WORDSIZE == 64
+  int gscope_flag;
+#endif
+  uintptr_t sysinfo;
+  uintptr_t stack_guard;
+  uintptr_t pointer_guard;
+#if __WORDSIZE != 64
+  int gscope_flag;
+#endif
+#ifndef __ASSUME_PRIVATE_FUTEX
+  int private_futex;
+#endif
+} tcbhead_t;
+
+#else /* __ASSEMBLER__ */
+# include <tcb-offsets.h>
+#endif /* __ASSEMBLER__ */
+
+/* We require TLS support in the tools.  */
+#define HAVE_TLS_SUPPORT
+#define HAVE___THREAD 1
+#define HAVE_TLS_MODEL_ATTRIBUTE 1
+
+/* Signal that TLS support is available.  */
+#define USE_TLS        1
+
+#ifndef __ASSEMBLER__
+/* Get system call information.  */
+# include <sysdep.h>
+
+/* Get the thread descriptor definition.  */
+# include <descr.h>
+
+register struct pthread *__thread_self __asm__("%g7");
+
+/* This is the size of the initial TCB.  Can't be just sizeof (tcbhead_t),
+   because NPTL getpid, __libc_alloca_cutoff etc. need (almost) the whole
+   struct pthread even when not linked with -lpthread.  */
+# define TLS_INIT_TCB_SIZE sizeof (struct pthread)
+
+/* Alignment requirements for the initial TCB.  */
+# define TLS_INIT_TCB_ALIGN __alignof__ (struct pthread)
+
+/* 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) \
+  (((tcbhead_t *) __thread_self)->dtv = (DTV))
+
+/* Return dtv of given thread descriptor.  */
+# define GET_DTV(descr) \
+  (((tcbhead_t *) (descr))->dtv)
+
+/* Code to initially initialize the thread pointer.  */
+# define TLS_INIT_TP(descr, secondcall) \
+  (__thread_self = (__typeof (__thread_self)) (descr), NULL)
+
+/* Return the address of the dtv for the current thread.  */
+# define THREAD_DTV() \
+  (((tcbhead_t *) __thread_self)->dtv)
+
+/* Return the thread descriptor for the current thread.  */
+#define THREAD_SELF  __thread_self
+
+/* Magic for libthread_db to know how to do THREAD_SELF.  */
+# define DB_THREAD_SELF_INCLUDE <sys/ucontext.h>
+# define DB_THREAD_SELF \
+  REGISTER (32, 32, REG_G7 * 4, 0) REGISTER (64, 64, REG_G7 * 8, 0)
+
+/* Access to data in the thread descriptor is easy.  */
+#define THREAD_GETMEM(descr, member) \
+  descr->member
+#define THREAD_GETMEM_NC(descr, member, idx) \
+  descr->member[idx]
+#define THREAD_SETMEM(descr, member, value) \
+  descr->member = (value)
+#define THREAD_SETMEM_NC(descr, member, idx, value) \
+  descr->member[idx] = (value)
+
+/* Set the stack guard field in TCB head.  */
+#define THREAD_SET_STACK_GUARD(value) \
+  THREAD_SETMEM (THREAD_SELF, header.stack_guard, value)
+# define THREAD_COPY_STACK_GUARD(descr) \
+  ((descr)->header.stack_guard \
+   = THREAD_GETMEM (THREAD_SELF, header.stack_guard))
+
+/* Get/set the stack guard field in TCB head.  */
+#define THREAD_GET_POINTER_GUARD() \
+  THREAD_GETMEM (THREAD_SELF, header.pointer_guard)
+#define THREAD_SET_POINTER_GUARD(value) \
+  THREAD_SETMEM (THREAD_SELF, header.pointer_guard, value)
+# define THREAD_COPY_POINTER_GUARD(descr) \
+  ((descr)->header.pointer_guard = THREAD_GET_POINTER_GUARD ())
+
+/* Get and set the global scope generation counter in struct pthread.  */
+#define THREAD_GSCOPE_FLAG_UNUSED 0
+#define THREAD_GSCOPE_FLAG_USED   1
+#define THREAD_GSCOPE_FLAG_WAIT   2
+#define THREAD_GSCOPE_RESET_FLAG() \
+  do                                                                        \
+    { int __res                                                                     \
+       = atomic_exchange_rel (&THREAD_SELF->header.gscope_flag,             \
+                              THREAD_GSCOPE_FLAG_UNUSED);                   \
+      if (__res == THREAD_GSCOPE_FLAG_WAIT)                                 \
+       lll_futex_wake (&THREAD_SELF->header.gscope_flag, 1, LLL_PRIVATE);   \
+    }                                                                       \
+  while (0)
+#define THREAD_GSCOPE_SET_FLAG() \
+  do                                                                        \
+    {                                                                       \
+      THREAD_SELF->header.gscope_flag = THREAD_GSCOPE_FLAG_USED;            \
+      atomic_write_barrier ();                                              \
+    }                                                                       \
+  while (0)
+#define THREAD_GSCOPE_WAIT() \
+  GL(dl_wait_lookup_done) ()
+
+#endif /* !ASSEMBLER */
+
+#endif /* tls.h */
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/Makefile b/libpthread/nptl/sysdeps/unix/sysv/linux/Makefile
new file mode 100644 (file)
index 0000000..34d6475
--- /dev/null
@@ -0,0 +1,13 @@
+# Makefile for uClibc NPTL
+#
+# Copyright (C) 2005 Steven J. Hill <sjhill@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+top_srcdir=../../../../../../
+top_builddir=../../../../../../
+all: objs
+include $(top_builddir)Rules.mak
+include Makefile.in
+include $(top_srcdir)Makerules
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/Makefile.in b/libpthread/nptl/sysdeps/unix/sysv/linux/Makefile.in
new file mode 100644 (file)
index 0000000..ac642f2
--- /dev/null
@@ -0,0 +1,256 @@
+# Makefile for uClibc NPTL
+#
+# Copyright (C) 2006 Steven J. Hill <sjhill@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+libpthread_CSRC = pthread_attr_getaffinity.c                           \
+                 pthread_attr_setaffinity.c pthread_getaffinity.c      \
+                 pthread_getcpuclockid.c pthread_kill.c                \
+                 pthread_mutex_cond_lock.c pthread_setaffinity.c       \
+                 pthread_yield.c sem_post.c sem_timedwait.c            \
+                 pthread_sigqueue.c                                    \
+                 sem_trywait.c sem_wait.c pt-fork.c                    \
+                 sigtimedwait.c sigwaitinfo.c sigwait.c pt-sleep.c
+
+libpthread_SSRC = #ptw-close.S ptw-open.S ptw-waitid.S ptw-waidpid.S ptw-write.S
+
+libc_CSRC = libc_pthread_init.c libc_multiple_threads.c                        \
+           register-atfork.c unregister-atfork.c getpid.c              \
+           raise.c sleep.c jmp-unwind.c
+
+# These provide both a cancellable and a not cancellable implementation
+libc_SSRC = close.S open.S write.S read.S waitpid.S
+
+librt_CSRC := mq_notify.c timer_create.c timer_delete.c                         \
+             timer_getoverr.c timer_gettime.c timer_routines.c          \
+             timer_settime.c
+
+
+ifeq ($(TARGET_ARCH),alpha)
+libpthread_CSRC += lowlevellock.c
+libc_CSRC += libc-lowlevellock.c
+librt_CSRC := mq_notify.c
+endif
+
+ifeq ($(TARGET_ARCH),arm)
+libc_SSRC := $(filter-out waitpid.S,$(libc_SSRC))
+libpthread_CSRC += lowlevelrobustlock.c
+endif
+
+ifeq ($(TARGET_ARCH),mips)
+libpthread_CSRC += lowlevellock.c lowlevelrobustlock.c
+libc_CSRC += libc-lowlevellock.c
+endif
+
+ifeq ($(TARGET_ARCH),powerpc)
+libpthread_CSRC += lowlevellock.c
+libc_CSRC += libc-lowlevellock.c
+librt_CSRC := mq_notify.c
+endif
+
+ifeq ($(TARGET_ARCH),sparc)
+libpthread_CSRC += __syscall_error.c lowlevelrobustlock.c
+librt_CSRC += __syscall_error.c
+endif
+
+ifeq ($(TARGET_ARCH),sh)
+SH_PTHREAD_SPECIFIC := sem_post.c sem_wait.c sem_timedwait.c sem_trywait.c
+libpthread_CSRC := $(filter-out $(SH_PTHREAD_SPECIFIC),$(libpthread_CSRC))
+endif
+
+ifeq ($(TARGET_ARCH),i386)
+X86_PTHREAD_SPECIFIC := sem_post.c sem_wait.c sem_timedwait.c sem_trywait.c
+libpthread_CSRC := $(filter-out $(X86_PTHREAD_SPECIFIC),$(libpthread_CSRC))
+endif
+
+ifeq ($(TARGET_ARCH),x86_64)
+libc_SSRC := $(filter-out waitpid.S,$(libc_SSRC))
+X64_PTHREAD_SPECIFIC := sem_post.c sem_wait.c sem_timedwait.c sem_trywait.c
+libpthread_CSRC := $(filter-out $(X64_PTHREAD_SPECIFIC),$(libpthread_CSRC))
+endif
+
+CFLAGS-pthread_getcpuclockid.c = -I$(top_srcdir)librt
+CFLAGS-pt-pread_pwrite.c = -I$(top_srcdir)libc/sysdeps/linux/$(TARGET_ARCH) \
+                           -I$(top_srcdir)libc/sysdeps/linux/common
+CFLAGS-mq_notify.c = -I$(top_srcdir)librt -DIS_IN_librt=1
+CFLAGS-timer_create.c = -I$(top_srcdir)librt -DIS_IN_librt=1
+CFLAGS-timer_delete.c = -I$(top_srcdir)librt -DIS_IN_librt=1
+CFLAGS-timer_getoverr.c = -I$(top_srcdir)librt -DIS_IN_librt=1
+CFLAGS-timer_gettime.c = -I$(top_srcdir)librt -DIS_IN_librt=1
+CFLAGS-timer_routines.c = -I$(top_srcdir)librt -DIS_IN_librt=1
+CFLAGS-timer_settime.c = -I$(top_srcdir)librt -DIS_IN_librt=1
+
+CFLAGS-linux = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 $(SSP_ALL_CFLAGS)
+#CFLAGS:=$(CFLAGS:-O1=-O2)
+
+CFLAGS-OMIT-libc_pthread_init.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1
+CFLAGS-OMIT-libc_multiple_threads.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1
+CFLAGS-OMIT-register-atfork.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1
+CFLAGS-OMIT-unregister-atfork.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1
+CFLAGS-OMIT-getpid.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1
+CFLAGS-OMIT-raise.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1
+CFLAGS-OMIT-sleep.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1
+CFLAGS-OMIT-libc-lowlevellock.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1
+
+CFLAGS-OMIT-close.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1
+CFLAGS-OMIT-open.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1
+CFLAGS-OMIT-read.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1
+CFLAGS-OMIT-write.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1
+CFLAGS-OMIT-waitpid.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1
+
+CFLAGS-OMIT-mq_notify.c = -DIS_IN_libpthread=1
+CFLAGS-OMIT-timer_create.c = -DIS_IN_libpthread=1
+CFLAGS-OMIT-timer_delete.c = -DIS_IN_libpthread=1
+CFLAGS-OMIT-timer_getoverr.c = -DIS_IN_libpthread=1
+CFLAGS-OMIT-timer_gettime.c = -DIS_IN_libpthread=1
+CFLAGS-OMIT-timer_routines.c = -DIS_IN_libpthread=1
+CFLAGS-OMIT-timer_settime.c = -DIS_IN_libpthread=1
+
+PTHREAD_LINUX_DIR := $(top_srcdir)libpthread/nptl/sysdeps/unix/sysv/linux
+PTHREAD_LINUX_OUT := $(top_builddir)libpthread/nptl/sysdeps/unix/sysv/linux
+
+PTHREAD_LINUX_OBJ := $(patsubst %.c,$(PTHREAD_LINUX_OUT)/%.o,$(libpthread_CSRC))
+PTHREAD_LINUX_OBJ += $(patsubst %.S,$(PTHREAD_LINUX_OUT)/%.o,$(libpthread_SSRC))
+
+ifeq ($(DOPIC),y)
+libpthread-a-y += $(PTHREAD_LINUX_OBJ:.o=.os)
+else
+libpthread-a-y += $(PTHREAD_LINUX_OBJ)
+endif
+libpthread-so-y += $(PTHREAD_LINUX_OBJ:.o=.oS)
+libpthread-so-y += $(PTHREAD_LINUX_OUT)/pt-raise.oS
+libpthread-nomulti-y += $(PTHREAD_LINUX_OBJ)
+
+ASFLAGS-open.S = -D_LIBC_REENTRANT
+ASFLAGS-close.S = -D_LIBC_REENTRANT
+ASFLAGS-read.S = -D_LIBC_REENTRANT
+ASFLAGS-write.S = -D_LIBC_REENTRANT
+ASFLAGS-waitpid.S = -D_LIBC_REENTRANT
+
+LIBC_LINUX_OBJ := $(patsubst %.c,$(PTHREAD_LINUX_OUT)/%.o,$(libc_CSRC))
+LIBC_LINUX_OBJ += $(patsubst %.S,$(PTHREAD_LINUX_OUT)/%.o,$(libc_SSRC))
+
+libc-static-y += $(LIBC_LINUX_OBJ)
+libc-shared-y += $(LIBC_LINUX_OBJ:.o=.oS)
+libc-nomulti-y += $(LIBC_LINUX_OBJ)
+
+LIBRT_LINUX_OBJ := $(patsubst %.c,$(PTHREAD_LINUX_OUT)/%.o,$(librt_CSRC))
+
+librt-a-y += $(LIBRT_LINUX_OBJ)
+librt-so-y += $(LIBRT_LINUX_OBJ:.o=.oS)
+
+objclean-y += nptl_linux_clean
+headers_clean-y += nptl_linux_headers_clean
+
+#
+# Create header files.
+#
+CFLAGS-gen_lowlevelbarrier.c = -S
+CFLAGS-gen_lowlevelcond.c = -S
+CFLAGS-gen_lowlevelrwlock.c = -S
+CFLAGS-gen_lowlevelrobustlock.c = -S
+CFLAGS-gen_lunwindbuf.c = -S
+CFLAGS-gen_lstructsem.c = -S
+CFLAGS-gen_lpthread-pi-defines.c = -S
+
+$(PTHREAD_LINUX_OUT)/gen_lowlevelbarrier.c: $(PTHREAD_LINUX_DIR)/lowlevelbarrier.sym
+       $(do_awk) $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@
+
+$(PTHREAD_LINUX_OUT)/gen_lowlevelcond.c: $(PTHREAD_LINUX_DIR)/lowlevelcond.sym
+       $(do_awk) $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@
+
+$(PTHREAD_LINUX_OUT)/gen_lowlevelrwlock.c: $(PTHREAD_LINUX_DIR)/lowlevelrwlock.sym
+       $(do_awk) $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@
+
+$(PTHREAD_LINUX_OUT)/gen_lowlevelrobustlock.c: $(PTHREAD_LINUX_DIR)/lowlevelrobustlock.sym
+       $(do_awk) $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@
+
+$(PTHREAD_LINUX_OUT)/gen_lunwindbuf.c: $(PTHREAD_LINUX_DIR)/unwindbuf.sym
+       $(do_awk) $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@
+
+$(PTHREAD_LINUX_OUT)/gen_lstructsem.c: $(PTHREAD_LINUX_DIR)/structsem.sym
+       $(do_awk) $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@
+
+$(PTHREAD_LINUX_OUT)/gen_lpthread-pi-defines.c: $(PTHREAD_LINUX_DIR)/pthread-pi-defines.sym
+       $(do_awk) $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@
+
+
+$(PTHREAD_LINUX_OUT)/gen_lowlevelbarrier.s: $(PTHREAD_LINUX_OUT)/gen_lowlevelbarrier.c
+       $(compile.c)
+
+$(PTHREAD_LINUX_OUT)/gen_lowlevelcond.s: $(PTHREAD_LINUX_OUT)/gen_lowlevelcond.c
+       $(compile.c)
+
+$(PTHREAD_LINUX_OUT)/gen_lowlevelrwlock.s: $(PTHREAD_LINUX_OUT)/gen_lowlevelrwlock.c
+       $(compile.c)
+
+$(PTHREAD_LINUX_OUT)/gen_lowlevelrobustlock.s: $(PTHREAD_LINUX_OUT)/gen_lowlevelrobustlock.c
+       $(compile.c)
+
+$(PTHREAD_LINUX_OUT)/gen_lunwindbuf.s: $(PTHREAD_LINUX_OUT)/gen_lunwindbuf.c
+       $(compile.c)
+
+$(PTHREAD_LINUX_OUT)/gen_lstructsem.s: $(PTHREAD_LINUX_OUT)/gen_lstructsem.c
+       $(compile.c)
+
+$(PTHREAD_LINUX_OUT)/gen_lpthread-pi-defines.s: $(PTHREAD_LINUX_OUT)/gen_lpthread-pi-defines.c
+       $(compile.c)
+
+
+$(PTHREAD_LINUX_OUT)/lowlevelbarrier.h: $(PTHREAD_LINUX_OUT)/gen_lowlevelbarrier.s
+       $(do_sed) -n "s/^.*@@@name@@@\([^@]*\)@@@value@@@[^0-9Xxa-fA-F-]*\([0-9Xxa-fA-F-][0-9Xxa-fA-F-]*\).*@@@end@@@.*$\/#define \1 \2/p" $< > $@
+
+$(PTHREAD_LINUX_OUT)/lowlevelcond.h: $(PTHREAD_LINUX_OUT)/gen_lowlevelcond.s
+       $(do_sed) -n "s/^.*@@@name@@@\([^@]*\)@@@value@@@[^0-9Xxa-fA-F-]*\([0-9Xxa-fA-F-][0-9Xxa-fA-F-]*\).*@@@end@@@.*$\/#define \1 \2/p" $< > $@
+
+$(PTHREAD_LINUX_OUT)/lowlevelrwlock.h: $(PTHREAD_LINUX_OUT)/gen_lowlevelrwlock.s
+       $(do_sed) -n "s/^.*@@@name@@@\([^@]*\)@@@value@@@[^0-9Xxa-fA-F-]*\([0-9Xxa-fA-F-][0-9Xxa-fA-F-]*\).*@@@end@@@.*$\/#define \1 \2/p" $< > $@
+
+$(PTHREAD_LINUX_OUT)/lowlevelrobustlock.h: $(PTHREAD_LINUX_OUT)/gen_lowlevelrobustlock.s
+       $(do_sed) -n "s/^.*@@@name@@@\([^@]*\)@@@value@@@[^0-9Xxa-fA-F-]*\([0-9Xxa-fA-F-][0-9Xxa-fA-F-]*\).*@@@end@@@.*$\/#define \1 \2/p" $< > $@
+
+$(PTHREAD_LINUX_OUT)/unwindbuf.h: $(PTHREAD_LINUX_OUT)/gen_lunwindbuf.s
+       $(do_sed) -n "s/^.*@@@name@@@\([^@]*\)@@@value@@@[^0-9Xxa-fA-F-]*\([0-9Xxa-fA-F-][0-9Xxa-fA-F-]*\).*@@@end@@@.*$\/#define \1 \2/p" $< > $@
+
+$(PTHREAD_LINUX_OUT)/structsem.h: $(PTHREAD_LINUX_OUT)/gen_lstructsem.s
+       $(do_sed) -n "s/^.*@@@name@@@\([^@]*\)@@@value@@@[^0-9Xxa-fA-F-]*\([0-9Xxa-fA-F-][0-9Xxa-fA-F-]*\).*@@@end@@@.*$\/#define \1 \2/p" $< > $@
+
+$(PTHREAD_LINUX_OUT)/pthread-pi-defines.h: $(PTHREAD_LINUX_OUT)/gen_lpthread-pi-defines.s
+       $(do_sed) -n "s/^.*@@@name@@@\([^@]*\)@@@value@@@[^0-9Xxa-fA-F-]*\([0-9Xxa-fA-F-][0-9Xxa-fA-F-]*\).*@@@end@@@.*$\/#define \1 \2/p" $< > $@
+
+pregen-headers-$(UCLIBC_HAS_THREADS_NATIVE) += \
+                                       $(PTHREAD_LINUX_OUT)/lowlevelbarrier.h \
+                                       $(PTHREAD_LINUX_OUT)/lowlevelcond.h \
+                                       $(PTHREAD_LINUX_OUT)/lowlevelrwlock.h \
+                                       $(PTHREAD_LINUX_OUT)/lowlevelrobustlock.h \
+                                       $(PTHREAD_LINUX_OUT)/unwindbuf.h \
+                                       $(PTHREAD_LINUX_OUT)/structsem.h \
+                                       $(PTHREAD_LINUX_OUT)/pthread-pi-defines.h
+
+HEADERS_BITS_PTHREAD     := $(notdir $(wildcard $(PTHREAD_LINUX_DIR)/bits/*.h))
+ALL_HEADERS_BITS_PTHREAD := $(addprefix include/bits/,$(HEADERS_BITS_PTHREAD))
+
+$(ALL_HEADERS_BITS_PTHREAD):
+       $(do_ln) ../../$(PTHREAD_LINUX_DIR)/bits/$(@F) $(top_builddir)$@
+
+nptl_linux_headers_clean:
+       $(do_rm) $(addprefix $(PTHREAD_LINUX_OUT)/gen_lowlevelbarrier., c s) \
+       $(addprefix $(PTHREAD_LINUX_OUT)/gen_lowlevelcond., c s) \
+       $(addprefix $(PTHREAD_LINUX_OUT)/gen_lowlevelrwlock., c s) \
+       $(addprefix $(PTHREAD_LINUX_OUT)/gen_lowlevelrobustlock., c s) \
+       $(addprefix $(PTHREAD_LINUX_OUT)/gen_lunwindbuf., c s) \
+       $(addprefix $(PTHREAD_LINUX_OUT)/gen_lstructsem., c s) \
+       $(addprefix $(PTHREAD_LINUX_OUT)/gen_lpthread-pi-defines., c s) \
+       $(PTHREAD_LINUX_OUT)/lowlevelbarrier.h \
+       $(PTHREAD_LINUX_OUT)/lowlevelcond.h \
+       $(PTHREAD_LINUX_OUT)/lowlevelrwlock.h \
+       $(PTHREAD_LINUX_OUT)/lowlevelrobustlock.h \
+       $(PTHREAD_LINUX_OUT)/unwindbuf.h \
+       $(PTHREAD_LINUX_OUT)/structsem.h \
+       $(PTHREAD_LINUX_OUT)/pthread-pi-defines.h
+
+
+nptl_linux_clean:
+       $(do_rm) $(addprefix $(PTHREAD_LINUX_OUT)/*., o os oS)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/__syscall_error.c b/libpthread/nptl/sysdeps/unix/sysv/linux/__syscall_error.c
new file mode 100644 (file)
index 0000000..5e109a8
--- /dev/null
@@ -0,0 +1,18 @@
+/* Wrapper for setting errno.
+ *
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#include <errno.h>
+#include <features.h>
+
+/* This routine is jumped to by all the syscall handlers, to stash
+ * an error number into errno.  */
+int __syscall_error(int err_no) attribute_hidden;
+int __syscall_error(int err_no)
+{
+       __set_errno(err_no);
+       return -1;
+}
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/accept.S b/libpthread/nptl/sysdeps/unix/sysv/linux/accept.S
new file mode 100644 (file)
index 0000000..529763d
--- /dev/null
@@ -0,0 +1,12 @@
+#include <sysdep-cancel.h>
+#ifndef __NR_accept
+#error Missing definition of NR_accept needed for cancellation.
+#endif
+PSEUDO (__libc_accept, accept, 3)
+ret
+PSEUDO_END(__libc_accept)
+libc_hidden_def (__libc_accept)
+weak_alias (__libc_accept, __accept)
+libc_hidden_weak (__accept)
+weak_alias (__libc_accept, accept)
+libc_hidden_weak (accept)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/Makefile b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/Makefile
new file mode 100644 (file)
index 0000000..8c80840
--- /dev/null
@@ -0,0 +1,2 @@
+# pull in __syscall_error routine, __sigprocmask, __syscall_rt_sigaction
+libpthread-routines += ptw-sysdep ptw-sigprocmask ptw-rt_sigaction
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/bits/local_lim.h b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/bits/local_lim.h
new file mode 100644 (file)
index 0000000..a7c9740
--- /dev/null
@@ -0,0 +1,100 @@
+/* Minimum guaranteed maximum values for system limits.  Linux/Alpha version.
+   Copyright (C) 1993-1998,2000,2002-2004,2008 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+/* The kernel header pollutes the namespace with the NR_OPEN symbol
+   and defines LINK_MAX although filesystems have different maxima.  A
+   similar thing is true for OPEN_MAX: the limit can be changed at
+   runtime and therefore the macro must not be defined.  Remove this
+   after including the header if necessary.  */
+#ifndef NR_OPEN
+# define __undef_NR_OPEN
+#endif
+#ifndef LINK_MAX
+# define __undef_LINK_MAX
+#endif
+#ifndef OPEN_MAX
+# define __undef_OPEN_MAX
+#endif
+#ifndef ARG_MAX
+# define __undef_ARG_MAX
+#endif
+
+/* The kernel sources contain a file with all the needed information.  */
+#include <linux/limits.h>
+
+/* Have to remove NR_OPEN?  */
+#ifdef __undef_NR_OPEN
+# undef NR_OPEN
+# undef __undef_NR_OPEN
+#endif
+/* Have to remove LINK_MAX?  */
+#ifdef __undef_LINK_MAX
+# undef LINK_MAX
+# undef __undef_LINK_MAX
+#endif
+/* Have to remove OPEN_MAX?  */
+#ifdef __undef_OPEN_MAX
+# undef OPEN_MAX
+# undef __undef_OPEN_MAX
+#endif
+/* Have to remove ARG_MAX?  */
+#ifdef __undef_ARG_MAX
+# undef ARG_MAX
+# undef __undef_ARG_MAX
+#endif
+
+/* The number of data keys per process.  */
+#define _POSIX_THREAD_KEYS_MAX 128
+/* This is the value this implementation supports.  */
+#define PTHREAD_KEYS_MAX       1024
+
+/* Controlling the iterations of destructors for thread-specific data.  */
+#define _POSIX_THREAD_DESTRUCTOR_ITERATIONS    4
+/* Number of iterations this implementation does.  */
+#define PTHREAD_DESTRUCTOR_ITERATIONS  _POSIX_THREAD_DESTRUCTOR_ITERATIONS
+
+/* The number of threads per process.  */
+#define _POSIX_THREAD_THREADS_MAX      64
+/* We have no predefined limit on the number of threads.  */
+#undef PTHREAD_THREADS_MAX
+
+/* Maximum amount by which a process can descrease its asynchronous I/O
+   priority level.  */
+#define AIO_PRIO_DELTA_MAX     20
+
+/* Minimum size for a thread.  We are free to choose a reasonable value.  */
+#define PTHREAD_STACK_MIN      24576
+
+/* Maximum number of timer expiration overruns.  */
+#define DELAYTIMER_MAX 2147483647
+
+/* Maximum tty name length.  */
+#define TTY_NAME_MAX           32
+
+/* Maximum login name length.  This is arbitrary.  */
+#define LOGIN_NAME_MAX         256
+
+/* Maximum host name length.  */
+#define HOST_NAME_MAX          64
+
+/* Maximum message queue priority level.  */
+#define MQ_PRIO_MAX            32768
+
+/* Maximum value the semaphore can have.  */
+#define SEM_VALUE_MAX   (2147483647)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h
new file mode 100644 (file)
index 0000000..41c0be1
--- /dev/null
@@ -0,0 +1,168 @@
+/* Machine-specific pthread type layouts.  Alpha version.
+   Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _BITS_PTHREADTYPES_H
+#define _BITS_PTHREADTYPES_H   1
+
+#define __SIZEOF_PTHREAD_ATTR_T                56
+#define __SIZEOF_PTHREAD_MUTEX_T       40
+#define __SIZEOF_PTHREAD_MUTEXATTR_T   4
+#define __SIZEOF_PTHREAD_COND_T                48
+#define __SIZEOF_PTHREAD_CONDATTR_T    4
+#define __SIZEOF_PTHREAD_RWLOCK_T      56
+#define __SIZEOF_PTHREAD_RWLOCKATTR_T  8
+#define __SIZEOF_PTHREAD_BARRIER_T     32
+#define __SIZEOF_PTHREAD_BARRIERATTR_T 4
+
+
+/* Thread identifiers.  The structure of the attribute type is
+   deliberately not exposed.  */
+typedef unsigned long int pthread_t;
+
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_ATTR_T];
+  long int __align;
+} pthread_attr_t;
+
+
+typedef struct __pthread_internal_list
+{
+  struct __pthread_internal_list *__prev;
+  struct __pthread_internal_list *__next;
+} __pthread_list_t;
+
+
+/* Data structures for mutex handling.  The structure of the attribute
+   type is deliberately not exposed.  */
+typedef union
+{
+  struct __pthread_mutex_s
+  {
+    int __lock;
+    unsigned int __count;
+    int __owner;
+    unsigned int __nusers;
+    /* KIND must stay at this position in the structure to maintain
+       binary compatibility.  */
+    int __kind;
+    int __spins;
+    __pthread_list_t __list;
+#define __PTHREAD_MUTEX_HAVE_PREV      1
+  } __data;
+  char __size[__SIZEOF_PTHREAD_MUTEX_T];
+  long int __align;
+} pthread_mutex_t;
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_MUTEXATTR_T];
+  int __align;
+} pthread_mutexattr_t;
+
+
+/* Data structure for conditional variable handling.  The structure of
+   the attribute type is deliberately not exposed.  */
+typedef union
+{
+  struct
+  {
+    int __lock;
+    unsigned int __futex;
+    __extension__ unsigned long long int __total_seq;
+    __extension__ unsigned long long int __wakeup_seq;
+    __extension__ unsigned long long int __woken_seq;
+    void *__mutex;
+    unsigned int __nwaiters;
+    unsigned int __broadcast_seq;
+  } __data;
+  char __size[__SIZEOF_PTHREAD_COND_T];
+  __extension__ long long int __align;
+} pthread_cond_t;
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_CONDATTR_T];
+  int __align;
+} pthread_condattr_t;
+
+
+/* Keys for thread-specific data */
+typedef unsigned int pthread_key_t;
+
+
+/* Once-only execution */
+typedef int pthread_once_t;
+
+
+#if defined __USE_UNIX98 || defined __USE_XOPEN2K
+/* Data structure for read-write lock variable handling.  The
+   structure of the attribute type is deliberately not exposed.  */
+typedef union
+{
+  struct
+  {
+    int __lock;
+    unsigned int __nr_readers;
+    unsigned int __readers_wakeup;
+    unsigned int __writer_wakeup;
+    unsigned int __nr_readers_queued;
+    unsigned int __nr_writers_queued;
+    int __writer;
+    int __shared;
+    unsigned long int __pad1;
+    unsigned long int __pad2;
+    /* FLAGS must stay at this position in the structure to maintain
+       binary compatibility.  */
+    unsigned int __flags;
+  } __data;
+  char __size[__SIZEOF_PTHREAD_RWLOCK_T];
+  long int __align;
+} pthread_rwlock_t;
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_RWLOCKATTR_T];
+  long int __align;
+} pthread_rwlockattr_t;
+#endif
+
+
+#ifdef __USE_XOPEN2K
+/* POSIX spinlock data type.  */
+typedef volatile int pthread_spinlock_t;
+
+/* POSIX barriers data type.  The structure of the type is
+   deliberately not exposed.  */
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_BARRIER_T];
+  long int __align;
+} pthread_barrier_t;
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_BARRIERATTR_T];
+  int __align;
+} pthread_barrierattr_t;
+#endif
+
+
+#endif /* bits/pthreadtypes.h */
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/bits/semaphore.h b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/bits/semaphore.h
new file mode 100644 (file)
index 0000000..be4469c
--- /dev/null
@@ -0,0 +1,34 @@
+/* Machine-specific POSIX semaphore type layouts.  Alpha version.
+   Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _SEMAPHORE_H
+# error "Never use <bits/semaphore.h> directly; include <semaphore.h> instead."
+#endif
+
+# define __SIZEOF_SEM_T        32
+
+/* Value returned if `sem_open' failed.  */
+#define SEM_FAILED      ((sem_t *) 0)
+
+
+typedef union
+{
+  char __size[__SIZEOF_SEM_T];
+  long int __align;
+} sem_t;
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/clone.S b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/clone.S
new file mode 100644 (file)
index 0000000..eea1cbe
--- /dev/null
@@ -0,0 +1,2 @@
+#define RESET_PID
+#include <sysdeps/unix/sysv/linux/alpha/clone.S>
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/createthread.c b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/createthread.c
new file mode 100644 (file)
index 0000000..6a51e73
--- /dev/null
@@ -0,0 +1,23 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* Value passed to 'clone' for initialization of the thread register.  */
+#define TLS_VALUE (pd + 1)
+
+/* Get the real implementation.         */
+#include <nptl/sysdeps/pthread/createthread.c>
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/fork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/fork.c
new file mode 100644 (file)
index 0000000..ca85fc0
--- /dev/null
@@ -0,0 +1,30 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sched.h>
+#include <signal.h>
+#include <sysdep.h>
+#include <tls.h>
+
+
+#define ARCH_FORK()                                                    \
+  INLINE_SYSCALL (clone, 5,                                            \
+                 CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD,  \
+                 NULL, NULL, &THREAD_SELF->tid, NULL)
+
+#include "../fork.c"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/lowlevellock.h b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/lowlevellock.h
new file mode 100644 (file)
index 0000000..b7f4de3
--- /dev/null
@@ -0,0 +1,284 @@
+/* Copyright (C) 2003, 2004, 2006, 2007 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 Libr   \ary; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _LOWLEVELLOCK_H
+#define _LOWLEVELLOCK_H        1
+
+#include <time.h>
+#include <sys/param.h>
+#include <bits/pthreadtypes.h>
+#include <atomic.h>
+#include <sysdep.h>
+#include <bits/kernel-features.h>
+
+
+#define FUTEX_WAIT             0
+#define FUTEX_WAKE             1
+#define FUTEX_REQUEUE          3
+#define FUTEX_CMP_REQUEUE      4
+#define FUTEX_WAKE_OP          5
+#define FUTEX_OP_CLEAR_WAKE_IF_GT_ONE  ((4 << 24) | 1)
+#define FUTEX_LOCK_PI          6
+#define FUTEX_UNLOCK_PI                7
+#define FUTEX_TRYLOCK_PI       8
+#define FUTEX_WAIT_BITSET      9
+#define FUTEX_WAKE_BITSET      10
+#define FUTEX_PRIVATE_FLAG     128
+#define FUTEX_CLOCK_REALTIME   256
+
+#define FUTEX_BITSET_MATCH_ANY 0xffffffff
+
+/* Values for 'private' parameter of locking macros.  Yes, the
+   definition seems to be backwards.  But it is not.  The bit will be
+   reversed before passing to the system call.  */
+#define LLL_PRIVATE    0
+#define LLL_SHARED     FUTEX_PRIVATE_FLAG
+
+
+#if !defined NOT_IN_libc || defined IS_IN_rtld
+/* In libc.so or ld.so all futexes are private.  */
+# ifdef __ASSUME_PRIVATE_FUTEX
+#  define __lll_private_flag(fl, private) \
+  ((fl) | FUTEX_PRIVATE_FLAG)
+# else
+#  define __lll_private_flag(fl, private) \
+  ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex))
+# endif
+#else
+# ifdef __ASSUME_PRIVATE_FUTEX
+#  define __lll_private_flag(fl, private) \
+  (((fl) | FUTEX_PRIVATE_FLAG) ^ (private))
+# else
+#  define __lll_private_flag(fl, private) \
+  (__builtin_constant_p (private)                                            \
+   ? ((private) == 0                                                         \
+      ? ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex))           \
+      : (fl))                                                                \
+   : ((fl) | (((private) ^ FUTEX_PRIVATE_FLAG)                               \
+             & THREAD_GETMEM (THREAD_SELF, header.private_futex))))
+# endif              
+#endif
+
+
+#define lll_futex_wait(futexp, val, private) \
+  lll_futex_timed_wait (futexp, val, NULL, private)
+
+#define lll_futex_timed_wait(futexp, val, timespec, private) \
+  ({                                                                         \
+    INTERNAL_SYSCALL_DECL (__err);                                           \
+    long int __ret;                                                          \
+    __ret = INTERNAL_SYSCALL (futex, __err, 4, (futexp),                     \
+                             __lll_private_flag (FUTEX_WAIT, private),       \
+                             (val), (timespec));                             \
+    INTERNAL_SYSCALL_ERROR_P (__ret, __err)? -__ret : __ret;                 \
+  })
+
+#define lll_futex_wake(futexp, nr, private) \
+  ({                                                                         \
+    INTERNAL_SYSCALL_DECL (__err);                                           \
+    long int __ret;                                                          \
+    __ret = INTERNAL_SYSCALL (futex, __err, 4, (futexp),                     \
+                             __lll_private_flag (FUTEX_WAKE, private),       \
+                             (nr), 0);                                       \
+    INTERNAL_SYSCALL_ERROR_P (__ret, __err)? -__ret : __ret;                 \
+  })
+
+#define lll_robust_dead(futexv, private) \
+  do                                                                         \
+    {                                                                        \
+      int *__futexp = &(futexv);                                             \
+      atomic_or (__futexp, FUTEX_OWNER_DIED);                                \
+      lll_futex_wake (__futexp, 1, private);                                 \
+    }                                                                        \
+  while (0)
+
+/* Returns non-zero if error happened, zero if success.  */
+#define lll_futex_requeue(futexp, nr_wake, nr_move, mutex, val, private) \
+  ({                                                                         \
+    INTERNAL_SYSCALL_DECL (__err);                                           \
+    long int __ret;                                                          \
+    __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp),                     \
+                             __lll_private_flag (FUTEX_CMP_REQUEUE, private),\
+                             (nr_wake), (nr_move), (mutex), (val));          \
+    INTERNAL_SYSCALL_ERROR_P (__ret, __err);                                 \
+  })
+
+/* Returns non-zero if error happened, zero if success.  */
+#define lll_futex_wake_unlock(futexp, nr_wake, nr_wake2, futexp2, private) \
+  ({                                                                         \
+    INTERNAL_SYSCALL_DECL (__err);                                           \
+    long int __ret;                                                          \
+    __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp),                     \
+                             __lll_private_flag (FUTEX_WAKE_OP, private),    \
+                             (nr_wake), (nr_wake2), (futexp2),               \
+                             FUTEX_OP_CLEAR_WAKE_IF_GT_ONE);                 \
+    INTERNAL_SYSCALL_ERROR_P (__ret, __err);                                 \
+  })
+
+
+
+
+static inline int __attribute__((always_inline))
+__lll_trylock(int *futex)
+{
+  return atomic_compare_and_exchange_val_acq (futex, 1, 0) != 0;
+}
+#define lll_trylock(lock)      __lll_trylock (&(lock))
+
+
+static inline int __attribute__((always_inline))
+__lll_cond_trylock(int *futex)
+{
+  return atomic_compare_and_exchange_val_acq (futex, 2, 0) != 0;
+}
+#define lll_cond_trylock(lock) __lll_cond_trylock (&(lock))
+
+
+static inline int __attribute__((always_inline))
+__lll_robust_trylock(int *futex, int id)
+{
+  return atomic_compare_and_exchange_val_acq (futex, id, 0) != 0;
+}
+#define lll_robust_trylock(lock, id) \
+  __lll_robust_trylock (&(lock), id)
+
+extern void __lll_lock_wait_private (int *futex) attribute_hidden;
+extern void __lll_lock_wait (int *futex, int private) attribute_hidden;
+extern int __lll_robust_lock_wait (int *futex, int private) attribute_hidden;
+
+static inline void __attribute__((always_inline))
+__lll_lock(int *futex, int private)
+{
+  if (atomic_compare_and_exchange_bool_acq (futex, 1, 0) != 0)
+    {
+      if (__builtin_constant_p (private) && private == LLL_PRIVATE)
+       __lll_lock_wait_private (futex);
+      else
+       __lll_lock_wait (futex, private);
+    }
+}
+#define lll_lock(futex, private) __lll_lock (&(futex), private)
+
+
+static inline int __attribute__ ((always_inline))
+__lll_robust_lock (int *futex, int id, int private)
+{
+  int result = 0;
+  if (atomic_compare_and_exchange_bool_acq (futex, id, 0) != 0)
+    result = __lll_robust_lock_wait (futex, private);
+  return result;
+}
+#define lll_robust_lock(futex, id, private) \
+  __lll_robust_lock (&(futex), id, private)
+
+
+static inline void __attribute__ ((always_inline))
+__lll_cond_lock (int *futex, int private)
+{
+  if (atomic_compare_and_exchange_bool_acq (futex, 2, 0) != 0)
+    __lll_lock_wait (futex, private);
+}
+#define lll_cond_lock(futex, private) __lll_cond_lock (&(futex), private)
+
+
+#define lll_robust_cond_lock(futex, id, private) \
+  __lll_robust_lock (&(futex), (id) | FUTEX_WAITERS, private)
+
+
+extern int __lll_timedlock_wait (int *futex, const struct timespec *,
+                                int private) attribute_hidden;
+extern int __lll_robust_timedlock_wait (int *futex, const struct timespec *,
+                                       int private) attribute_hidden;
+
+static inline int __attribute__ ((always_inline))
+__lll_timedlock (int *futex, const struct timespec *abstime, int private)
+{
+  int result = 0;
+  if (atomic_compare_and_exchange_bool_acq (futex, 1, 0) != 0)
+    result = __lll_timedlock_wait (futex, abstime, private);
+  return result;
+}
+#define lll_timedlock(futex, abstime, private) \
+  __lll_timedlock (&(futex), abstime, private)
+
+
+static inline int __attribute__ ((always_inline))
+__lll_robust_timedlock (int *futex, const struct timespec *abstime,
+                       int id, int private)
+{
+  int result = 0;
+  if (atomic_compare_and_exchange_bool_acq (futex, id, 0) != 0)
+    result = __lll_robust_timedlock_wait (futex, abstime, private);
+  return result;
+}
+#define lll_robust_timedlock(futex, abstime, id, private) \
+  __lll_robust_timedlock (&(futex), abstime, id, private)
+
+
+#define __lll_unlock(futex, private) \
+  (void)                                                       \
+    ({ int *__futex = (futex);                                 \
+       int __oldval = atomic_exchange_rel (__futex, 0);                \
+       if (__builtin_expect (__oldval > 1, 0))                 \
+        lll_futex_wake (__futex, 1, private);                  \
+    })
+#define lll_unlock(futex, private) __lll_unlock(&(futex), private)
+
+
+#define __lll_robust_unlock(futex, private) \
+  (void)                                                       \
+    ({ int *__futex = (futex);                                 \
+       int __oldval = atomic_exchange_rel (__futex, 0);                \
+       if (__builtin_expect (__oldval & FUTEX_WAITERS, 0))     \
+        lll_futex_wake (__futex, 1, private);                  \
+    })
+#define lll_robust_unlock(futex, private) \
+  __lll_robust_unlock(&(futex), private)
+
+
+#define lll_islocked(futex) \
+  (futex != 0)
+
+/* Initializers for lock.  */
+#define LLL_LOCK_INITIALIZER           (0)
+#define LLL_LOCK_INITIALIZER_LOCKED    (1)
+
+
+/* The kernel notifies a process which uses CLONE_CLEARTID via futex
+   wakeup when the clone terminates.  The memory location contains the
+   thread ID while the clone is running and is reset to zero
+   afterwards. */
+#define lll_wait_tid(tid) \
+  do {                                                 \
+    __typeof (tid) __tid;                              \
+    while ((__tid = (tid)) != 0)                       \
+      lll_futex_wait (&(tid), __tid, LLL_SHARED);      \
+  } while (0)
+
+extern int __lll_timedwait_tid (int *, const struct timespec *)
+     attribute_hidden;
+
+#define lll_timedwait_tid(tid, abstime) \
+  ({                                                   \
+    int __res = 0;                                     \
+    if ((tid) != 0)                                    \
+      __res = __lll_timedwait_tid (&(tid), (abstime)); \
+    __res;                                             \
+  })
+
+#endif /* lowlevellock.h */
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/pt-vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/pt-vfork.S
new file mode 100644 (file)
index 0000000..ec5d175
--- /dev/null
@@ -0,0 +1,43 @@
+/* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <tcb-offsets.h>
+
+#undef PSEUDO_PREPARE_ARGS
+#define PSEUDO_PREPARE_ARGS                                            \
+       /* Load the current cached pid value across the vfork.  */      \
+       rduniq;                                                         \
+       ldl     a2, PID_OFFSET(v0);                                     \
+       mov     v0, a1;                                                 \
+       /* Write back its negation, to indicate that the pid value is   \
+          uninitialized in the the child, and in the window between    \
+          here and the point at which we restore the value.  */        \
+       negl    a2, t0;                                                 \
+       stl     t0, PID_OFFSET(v0);
+
+PSEUDO (__vfork, vfork, 0)
+
+       /* If we're back in the parent, restore the saved pid.  */
+       beq     v0, 1f
+       stl     a2, PID_OFFSET(a1)
+1:     ret
+
+PSEUDO_END (__vfork)
+
+weak_alias (__vfork, vfork)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/pthread_once.c b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/pthread_once.c
new file mode 100644 (file)
index 0000000..0e7e979
--- /dev/null
@@ -0,0 +1,96 @@
+/* Copyright (C) 2003, 2004, 2007 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 "pthreadP.h"
+#include <lowlevellock.h>
+
+
+unsigned long int __fork_generation attribute_hidden;
+
+static void
+clear_once_control (void *arg)
+{
+  pthread_once_t *once_control = (pthread_once_t *) arg;
+
+  *once_control = 0;
+  lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE);
+}
+
+int
+__pthread_once (pthread_once_t *once_control, void (*init_routine) (void))
+{
+  for (;;)
+    {
+      int oldval;
+      int newval;
+      int tmp;
+
+      /* Pseudo code:
+        newval = __fork_generation | 1;
+        oldval = *once_control;
+        if ((oldval & 2) == 0)
+          *once_control = newval;
+        Do this atomically.
+      */
+      newval = __fork_generation | 1;
+      __asm __volatile (
+               "1:     ldl_l   %0, %2\n"
+               "       and     %0, 2, %1\n"
+               "       bne     %1, 2f\n"
+               "       mov     %3, %1\n"
+               "       stl_c   %1, %2\n"
+               "       beq     %1, 1b\n"
+               "2:     mb"
+               : "=&r" (oldval), "=&r" (tmp), "=m" (*once_control)
+               : "r" (newval), "m" (*once_control));
+
+      /* Check if the initializer has already been done.  */
+      if ((oldval & 2) != 0)
+       return 0;
+
+      /* Check if another thread already runs the initializer. */
+      if ((oldval & 1) == 0)
+       break;
+
+      /* Check whether the initializer execution was interrupted by a fork.  */
+      if (oldval != newval)
+       break;
+
+      /* Same generation, some other thread was faster. Wait.  */
+      lll_futex_wait (once_control, oldval, LLL_PRIVATE);
+    }
+
+  /* This thread is the first here.  Do the initialization.
+     Register a cleanup handler so that in case the thread gets
+     interrupted the initialization can be restarted.  */
+  pthread_cleanup_push (clear_once_control, once_control);
+
+  init_routine ();
+
+  pthread_cleanup_pop (0);
+
+  /* Add one to *once_control to take the bottom 2 bits from 01 to 10.  */
+  atomic_increment (once_control);
+
+  /* Wake up all other threads.  */
+  lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE);
+
+  return 0;
+}
+weak_alias (__pthread_once, pthread_once)
+strong_alias (__pthread_once, __pthread_once_internal)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/sem_post.c b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/sem_post.c
new file mode 100644 (file)
index 0000000..27fd817
--- /dev/null
@@ -0,0 +1,5 @@
+/* ??? This is an ass-backwards way to do this.  We should simply define
+   the acquire/release semantics of atomic_exchange_and_add.  And even if
+   we don't do this, we should be using atomic_full_barrier or otherwise.  */
+#define __lll_rel_instr  "mb"
+#include "../sem_post.c"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/sysdep-cancel.h
new file mode 100644 (file)
index 0000000..7049b36
--- /dev/null
@@ -0,0 +1,177 @@
+/* Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <tls.h>
+#ifndef __ASSEMBLER__
+# include <nptl/pthreadP.h>
+#endif
+
+#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt
+
+# ifdef PROF
+#  define PSEUDO_PROF                          \
+       .set noat;                              \
+       lda     AT, _mcount;                    \
+       jsr     AT, (AT), _mcount;              \
+       .set at
+# else
+#  define PSEUDO_PROF
+# endif
+
+/* ??? Assumes that nothing comes between PSEUDO and PSEUDO_END
+   besides "ret".  */
+
+# undef PSEUDO
+# define PSEUDO(name, syscall_name, args)                      \
+       .globl name;                                            \
+       .align 4;                                               \
+       .type name, @function;                                  \
+       .usepv name, std;                                       \
+       cfi_startproc;                                          \
+__LABEL(name)                                                  \
+       ldgp    gp, 0(pv);                                      \
+       PSEUDO_PROF;                                            \
+       PSEUDO_PREPARE_ARGS                                     \
+       SINGLE_THREAD_P(t0);                                    \
+       bne     t0, $pseudo_cancel;                             \
+       lda     v0, SYS_ify(syscall_name);                      \
+       call_pal PAL_callsys;                                   \
+       bne     a3, SYSCALL_ERROR_LABEL;                        \
+__LABEL($pseudo_ret)                                           \
+       .subsection 2;                                          \
+       cfi_startproc;                                          \
+__LABEL($pseudo_cancel)                                                \
+       subq    sp, 64, sp;                                     \
+       cfi_def_cfa_offset(64);                                 \
+       stq     ra, 0(sp);                                      \
+       cfi_offset(ra, -64);                                    \
+       SAVE_ARGS_##args;                                       \
+       CENABLE;                                                \
+       LOAD_ARGS_##args;                                       \
+       /* Save the CENABLE return value in RA.  That register  \
+          is preserved across syscall and the real return      \
+          address is saved on the stack.  */                   \
+       mov     v0, ra;                                         \
+       lda     v0, SYS_ify(syscall_name);                      \
+       call_pal PAL_callsys;                                   \
+       stq     v0, 8(sp);                                      \
+       mov     ra, a0;                                         \
+       bne     a3, $multi_error;                               \
+       CDISABLE;                                               \
+       ldq     ra, 0(sp);                                      \
+       ldq     v0, 8(sp);                                      \
+       addq    sp, 64, sp;                                     \
+       cfi_remember_state;                                     \
+       cfi_restore(ra);                                        \
+       cfi_def_cfa_offset(0);                                  \
+       ret;                                                    \
+       cfi_restore_state;                                      \
+__LABEL($multi_error)                                          \
+       CDISABLE;                                               \
+       ldq     ra, 0(sp);                                      \
+       ldq     v0, 8(sp);                                      \
+       addq    sp, 64, sp;                                     \
+       cfi_restore(ra);                                        \
+       cfi_def_cfa_offset(0);                                  \
+__LABEL($syscall_error)                                                \
+       SYSCALL_ERROR_HANDLER;                                  \
+       cfi_endproc;                                            \
+       .previous
+
+# undef PSEUDO_END
+# define PSEUDO_END(sym)                                       \
+       cfi_endproc;                                            \
+       .subsection 2;                                          \
+       .size sym, .-sym
+
+# define SAVE_ARGS_0   /* Nothing.  */
+# define SAVE_ARGS_1   SAVE_ARGS_0; stq a0, 8(sp)
+# define SAVE_ARGS_2   SAVE_ARGS_1; stq a1, 16(sp)
+# define SAVE_ARGS_3   SAVE_ARGS_2; stq a2, 24(sp)
+# define SAVE_ARGS_4   SAVE_ARGS_3; stq a3, 32(sp)
+# define SAVE_ARGS_5   SAVE_ARGS_4; stq a4, 40(sp)
+# define SAVE_ARGS_6   SAVE_ARGS_5; stq a5, 48(sp)
+
+# define LOAD_ARGS_0   /* Nothing.  */
+# define LOAD_ARGS_1   LOAD_ARGS_0; ldq a0, 8(sp)
+# define LOAD_ARGS_2   LOAD_ARGS_1; ldq a1, 16(sp)
+# define LOAD_ARGS_3   LOAD_ARGS_2; ldq a2, 24(sp)
+# define LOAD_ARGS_4   LOAD_ARGS_3; ldq a3, 32(sp)
+# define LOAD_ARGS_5   LOAD_ARGS_4; ldq a4, 40(sp)
+# define LOAD_ARGS_6   LOAD_ARGS_5; ldq a5, 48(sp)
+
+# ifdef IS_IN_libpthread
+#  define __local_enable_asynccancel   __pthread_enable_asynccancel
+#  define __local_disable_asynccancel  __pthread_disable_asynccancel
+#  define __local_multiple_threads     __pthread_multiple_threads
+# elif !defined NOT_IN_libc
+#  define __local_enable_asynccancel   __libc_enable_asynccancel
+#  define __local_disable_asynccancel  __libc_disable_asynccancel
+#  define __local_multiple_threads     __libc_multiple_threads
+# elif defined IS_IN_librt
+#  define __local_enable_asynccancel   __librt_enable_asynccancel
+#  define __local_disable_asynccancel  __librt_disable_asynccancel
+# else
+#  error Unsupported library
+# endif
+
+# ifdef __PIC__
+#  define CENABLE      bsr ra, __local_enable_asynccancel !samegp
+#  define CDISABLE     bsr ra, __local_disable_asynccancel !samegp
+# else
+#  define CENABLE      jsr ra, __local_enable_asynccancel; ldgp ra, 0(gp)
+#  define CDISABLE     jsr ra, __local_disable_asynccancel; ldgp ra, 0(gp)
+# endif
+
+# if defined IS_IN_libpthread || !defined NOT_IN_libc
+#  ifndef __ASSEMBLER__
+extern int __local_multiple_threads attribute_hidden;
+#   define SINGLE_THREAD_P \
+       __builtin_expect (__local_multiple_threads == 0, 1)
+#  elif defined(__PIC__)
+#   define SINGLE_THREAD_P(reg)  ldl reg, __local_multiple_threads(gp) !gprel
+#  else
+#   define SINGLE_THREAD_P(reg)                                        \
+       ldah    reg, __local_multiple_threads(gp) !gprelhigh;   \
+       ldl     reg, __local_multiple_threads(reg) !gprellow
+#  endif
+# else
+#  ifndef __ASSEMBLER__
+#   define SINGLE_THREAD_P \
+       __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
+                                  header.multiple_threads) == 0, 1)
+#  else
+#   define SINGLE_THREAD_P(reg)                                        \
+       call_pal PAL_rduniq;                                    \
+       ldl reg, MULTIPLE_THREADS_OFFSET($0)
+#  endif
+# endif
+
+#else
+
+# define SINGLE_THREAD_P (1)
+# define NO_CANCELLATION 1
+
+#endif
+
+#ifndef __ASSEMBLER__
+# define RTLD_SINGLE_THREAD_P \
+  __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
+                                  header.multiple_threads) == 0, 1)
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_create.c b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_create.c
new file mode 100644 (file)
index 0000000..172223a
--- /dev/null
@@ -0,0 +1 @@
+#include "../x86_64/timer_create.c"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_delete.c b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_delete.c
new file mode 100644 (file)
index 0000000..537516e
--- /dev/null
@@ -0,0 +1 @@
+#include "../x86_64/timer_delete.c"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_getoverr.c b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_getoverr.c
new file mode 100644 (file)
index 0000000..3f21a73
--- /dev/null
@@ -0,0 +1 @@
+#include "../x86_64/timer_getoverr.c"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_gettime.c b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_gettime.c
new file mode 100644 (file)
index 0000000..a50143a
--- /dev/null
@@ -0,0 +1 @@
+#include "../x86_64/timer_gettime.c"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_settime.c b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_settime.c
new file mode 100644 (file)
index 0000000..37baeff
--- /dev/null
@@ -0,0 +1 @@
+#include "../x86_64/timer_settime.c"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/vfork.S
new file mode 100644 (file)
index 0000000..f4ed931
--- /dev/null
@@ -0,0 +1,46 @@
+/* Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <tcb-offsets.h>
+
+#undef PSEUDO_PREPARE_ARGS
+#define PSEUDO_PREPARE_ARGS                                            \
+       /* Load the current cached pid value across the vfork.  */      \
+       rduniq;                                                         \
+       ldl     a2, PID_OFFSET(v0);                                     \
+       mov     v0, a1;                                                 \
+       /* If the cached value is initialized (nonzero), then write     \
+          back its negation, or INT_MIN, to indicate that the pid      \
+          value is uninitialized in the the child, and in the window   \
+          between here and the point at which we restore the value.  */ \
+       ldah    t0, -0x8000;                                            \
+       negl    a2, t1;                                                 \
+       cmovne  a2, t1, t0;                                             \
+       stl     t0, PID_OFFSET(v0);
+
+PSEUDO (__vfork, vfork, 0)
+
+       /* If we're back in the parent, restore the saved pid.  */
+       beq     v0, 1f
+       stl     a2, PID_OFFSET(a1)
+1:     ret
+
+PSEUDO_END (__vfork)
+libc_hidden_def (__vfork)
+weak_alias (__vfork, vfork)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/Makefile b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/Makefile
new file mode 100644 (file)
index 0000000..43a6fad
--- /dev/null
@@ -0,0 +1,13 @@
+# Makefile for uClibc NPTL
+#
+# Copyright (C) 2005 Steven J. Hill <sjhill@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+top_srcdir=../../../../../../../
+top_builddir=../../../../../../../
+all: objs
+include $(top_builddir)Rules.mak
+include Makefile.arch
+include $(top_srcdir)Makerules
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/Makefile.arch b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/Makefile.arch
new file mode 100644 (file)
index 0000000..c585281
--- /dev/null
@@ -0,0 +1,58 @@
+# Makefile for uClibc NPTL
+#
+# Copyright (C) 2006 Steven J. Hill <sjhill@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+libpthread_SSRC = pt-vfork.S
+libpthread_CSRC = pthread_once.c lowlevellock.c \
+                  pt-__syscall_rt_sigaction.c pt-__syscall_error.c
+
+libc_a_CSRC = fork.c lowlevellock.c
+libc_a_SSRC = clone.S vfork.S
+
+ifeq ($(UCLIBC_HAS_STDIO_FUTEXES),y)
+CFLAGS-fork.c = -D__USE_STDIO_FUTEXES__
+endif
+CFLAGS-pthread_once.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1
+CFLAGS-pt-__syscall_rt_sigaction.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1
+CFLAGS-lowlevellock.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1
+CFLAGS-pt-__syscall_error.c =  -DNOT_IN_libc=1 -DIS_IN_libpthread=1
+
+ASFLAGS-pt-vfork.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 -marm
+# We always compile it in arm mode because of SAVE_PID macro
+# This macro should be alternatively implemented in THUMB
+# assembly.
+ASFLAGS-vfork.S = -marm
+
+CFLAGS += $(SSP_ALL_CFLAGS)
+#CFLAGS:=$(CFLAGS:-O1=-O2)
+
+LINUX_ARCH_DIR:=$(top_srcdir)libpthread/nptl/sysdeps/unix/sysv/linux/arm
+LINUX_ARCH_OUT:=$(top_builddir)libpthread/nptl/sysdeps/unix/sysv/linux/arm
+
+LINUX_ARCH_OBJ:=$(patsubst %.S,$(LINUX_ARCH_OUT)/%.o,$(libpthread_SSRC))
+LINUX_ARCH_OBJ+=$(patsubst %.c,$(LINUX_ARCH_OUT)/%.o,$(libpthread_CSRC))
+
+ifeq ($(DOPIC),y)
+libpthread-a-y += $(LINUX_ARCH_OBJ:.o=.os)
+else
+libpthread-a-y += $(LINUX_ARCH_OBJ)
+endif
+libpthread-so-y += $(LINUX_ARCH_OBJ:.o=.oS)
+
+libpthread-nomulti-y+=$(LINUX_ARCH_OBJ)
+
+LIBC_LINUX_ARCH_OBJ:=$(patsubst %.c,$(LINUX_ARCH_OUT)/%.o,$(libc_a_CSRC))
+LIBC_LINUX_ARCH_OBJ+=$(patsubst %.S,$(LINUX_ARCH_OUT)/%.o,$(libc_a_SSRC))
+
+libc-static-y+=$(LIBC_LINUX_ARCH_OBJ)
+libc-shared-y+=$(LIBC_LINUX_ARCH_OBJ:.o=.oS)
+
+libc-nomulti-y+=$(LIBC_LINUX_ARCH_OBJ)
+
+objclean-y+=pthread_linux_arch_objclean
+
+pthread_linux_arch_objclean:
+       $(RM) $(LINUX_ARCH_OUT)/*.{o,os,oS}
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/bits/atomic.h b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/bits/atomic.h
new file mode 100644 (file)
index 0000000..b0586ea
--- /dev/null
@@ -0,0 +1,122 @@
+/* Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stdint.h>
+#include <sysdep.h>
+
+
+typedef int8_t atomic8_t;
+typedef uint8_t uatomic8_t;
+typedef int_fast8_t atomic_fast8_t;
+typedef uint_fast8_t uatomic_fast8_t;
+
+typedef int32_t atomic32_t;
+typedef uint32_t uatomic32_t;
+typedef int_fast32_t atomic_fast32_t;
+typedef uint_fast32_t uatomic_fast32_t;
+
+typedef intptr_t atomicptr_t;
+typedef uintptr_t uatomicptr_t;
+typedef intmax_t atomic_max_t;
+typedef uintmax_t uatomic_max_t;
+
+void __arm_link_error (void);
+
+#ifdef __thumb2__
+#define atomic_full_barrier() \
+     __asm__ __volatile__                                                    \
+            ("movw\tip, #0x0fa0\n\t"                                         \
+             "movt\tip, #0xffff\n\t"                                         \
+             "blx\tip"                                                       \
+             : : : "ip", "lr", "cc", "memory");
+#else
+#define atomic_full_barrier() \
+     __asm__ __volatile__                                                    \
+            ("mov\tip, #0xffff0fff\n\t"                                      \
+             "mov\tlr, pc\n\t"                                               \
+             "add\tpc, ip, #(0xffff0fa0 - 0xffff0fff)"                       \
+             : : : "ip", "lr", "cc", "memory");
+#endif
+
+/* Atomic compare and exchange.  This sequence relies on the kernel to
+   provide a compare and exchange operation which is atomic on the
+   current architecture, either via cleverness on pre-ARMv6 or via
+   ldrex / strex on ARMv6.  */
+
+#define __arch_compare_and_exchange_val_8_acq(mem, newval, oldval) \
+  ({ __arm_link_error (); oldval; })
+
+#define __arch_compare_and_exchange_val_16_acq(mem, newval, oldval) \
+  ({ __arm_link_error (); oldval; })
+
+/* It doesn't matter what register is used for a_oldval2, but we must
+   specify one to work around GCC PR rtl-optimization/21223.  Otherwise
+   it may cause a_oldval or a_tmp to be moved to a different register.  */
+
+#ifdef __thumb2__
+/* Thumb-2 has ldrex/strex.  However it does not have barrier instructions,
+   so we still need to use the kernel helper.  */
+#define __arch_compare_and_exchange_val_32_acq(mem, newval, oldval) \
+  ({ register __typeof (oldval) a_oldval asm ("r0");                         \
+     register __typeof (oldval) a_newval asm ("r1") = (newval);                      \
+     register __typeof (mem) a_ptr asm ("r2") = (mem);                       \
+     register __typeof (oldval) a_tmp asm ("r3");                            \
+     register __typeof (oldval) a_oldval2 asm ("r4") = (oldval);             \
+     __asm__ __volatile__                                                    \
+            ("0:\tldr\t%[tmp],[%[ptr]]\n\t"                                  \
+             "cmp\t%[tmp], %[old2]\n\t"                                      \
+             "bne\t1f\n\t"                                                   \
+             "mov\t%[old], %[old2]\n\t"                                      \
+             "movw\t%[tmp], #0x0fc0\n\t"                                     \
+             "movt\t%[tmp], #0xffff\n\t"                                     \
+             "blx\t%[tmp]\n\t"                                               \
+             "bcc\t0b\n\t"                                                   \
+             "mov\t%[tmp], %[old2]\n\t"                                      \
+             "1:"                                                            \
+             : [old] "=&r" (a_oldval), [tmp] "=&r" (a_tmp)                   \
+             : [new] "r" (a_newval), [ptr] "r" (a_ptr),                      \
+               [old2] "r" (a_oldval2)                                        \
+             : "ip", "lr", "cc", "memory");                                  \
+     a_tmp; })
+#else
+#define __arch_compare_and_exchange_val_32_acq(mem, newval, oldval) \
+  ({ register __typeof (oldval) a_oldval asm ("r0");                         \
+     register __typeof (oldval) a_newval asm ("r1") = (newval);                      \
+     register __typeof (mem) a_ptr asm ("r2") = (mem);                       \
+     register __typeof (oldval) a_tmp asm ("r3");                            \
+     register __typeof (oldval) a_oldval2 asm ("r4") = (oldval);             \
+     __asm__ __volatile__                                                    \
+            ("0:\tldr\t%[tmp],[%[ptr]]\n\t"                                  \
+             "cmp\t%[tmp], %[old2]\n\t"                                      \
+             "bne\t1f\n\t"                                                   \
+             "mov\t%[old], %[old2]\n\t"                                      \
+             "mov\t%[tmp], #0xffff0fff\n\t"                                  \
+             "mov\tlr, pc\n\t"                                               \
+             "add\tpc, %[tmp], #(0xffff0fc0 - 0xffff0fff)\n\t"               \
+             "bcc\t0b\n\t"                                                   \
+             "mov\t%[tmp], %[old2]\n\t"                                      \
+             "1:"                                                            \
+             : [old] "=&r" (a_oldval), [tmp] "=&r" (a_tmp)                   \
+             : [new] "r" (a_newval), [ptr] "r" (a_ptr),                      \
+               [old2] "r" (a_oldval2)                                        \
+             : "ip", "lr", "cc", "memory");                                  \
+     a_tmp; })
+#endif
+
+#define __arch_compare_and_exchange_val_64_acq(mem, newval, oldval) \
+  ({ __arm_link_error (); oldval; })
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/bits/pthreadtypes.h b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/bits/pthreadtypes.h
new file mode 100644 (file)
index 0000000..e1b115c
--- /dev/null
@@ -0,0 +1,181 @@
+/* Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _BITS_PTHREADTYPES_H
+#define _BITS_PTHREADTYPES_H   1
+
+#include <endian.h>
+
+#define __SIZEOF_PTHREAD_ATTR_T 36
+#define __SIZEOF_PTHREAD_MUTEX_T 24
+#define __SIZEOF_PTHREAD_MUTEXATTR_T 4
+#define __SIZEOF_PTHREAD_COND_T 48
+#define __SIZEOF_PTHREAD_COND_COMPAT_T 12
+#define __SIZEOF_PTHREAD_CONDATTR_T 4
+#define __SIZEOF_PTHREAD_RWLOCK_T 32
+#define __SIZEOF_PTHREAD_RWLOCKATTR_T 8
+#define __SIZEOF_PTHREAD_BARRIER_T 20
+#define __SIZEOF_PTHREAD_BARRIERATTR_T 4
+
+
+/* Thread identifiers.  The structure of the attribute type is not
+   exposed on purpose.  */
+typedef unsigned long int pthread_t;
+
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_ATTR_T];
+  long int __align;
+} pthread_attr_t;
+
+
+typedef struct __pthread_internal_slist
+{
+  struct __pthread_internal_slist *__next;
+} __pthread_slist_t;
+
+
+/* Data structures for mutex handling.  The structure of the attribute
+   type is not exposed on purpose.  */
+typedef union
+{
+  struct __pthread_mutex_s
+  {
+    int __lock;
+    unsigned int __count;
+    int __owner;
+    /* KIND must stay at this position in the structure to maintain
+       binary compatibility.  */
+    int __kind;
+    unsigned int __nusers;
+    __extension__ union
+    {
+      int __spins;
+      __pthread_slist_t __list;
+    };
+  } __data;
+  char __size[__SIZEOF_PTHREAD_MUTEX_T];
+  long int __align;
+} pthread_mutex_t;
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_MUTEXATTR_T];
+  long int __align;
+} pthread_mutexattr_t;
+
+
+/* Data structure for conditional variable handling.  The structure of
+   the attribute type is not exposed on purpose.  */
+typedef union
+{
+  struct
+  {
+    int __lock;
+    unsigned int __futex;
+    __extension__ unsigned long long int __total_seq;
+    __extension__ unsigned long long int __wakeup_seq;
+    __extension__ unsigned long long int __woken_seq;
+    void *__mutex;
+    unsigned int __nwaiters;
+    unsigned int __broadcast_seq;
+  } __data;
+  char __size[__SIZEOF_PTHREAD_COND_T];
+  __extension__ long long int __align;
+} pthread_cond_t;
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_CONDATTR_T];
+  long int __align;
+} pthread_condattr_t;
+
+
+/* Keys for thread-specific data */
+typedef unsigned int pthread_key_t;
+
+
+/* Once-only execution */
+typedef int pthread_once_t;
+
+
+#if defined __USE_UNIX98 || defined __USE_XOPEN2K
+/* Data structure for read-write lock variable handling.  The
+   structure of the attribute type is not exposed on purpose.  */
+typedef union
+{
+  struct
+  {
+    int __lock;
+    unsigned int __nr_readers;
+    unsigned int __readers_wakeup;
+    unsigned int __writer_wakeup;
+    unsigned int __nr_readers_queued;
+    unsigned int __nr_writers_queued;
+#if __BYTE_ORDER == __BIG_ENDIAN
+    unsigned char __pad1;
+    unsigned char __pad2;
+    unsigned char __shared;
+    /* FLAGS must stay at this position in the structure to maintain
+       binary compatibility.  */
+    unsigned char __flags;
+#else
+    /* FLAGS must stay at this position in the structure to maintain
+       binary compatibility.  */
+    unsigned char __flags;
+    unsigned char __shared;
+    unsigned char __pad1;
+    unsigned char __pad2;
+#endif
+    int __writer;
+  } __data;
+  char __size[__SIZEOF_PTHREAD_RWLOCK_T];
+  long int __align;
+} pthread_rwlock_t;
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_RWLOCKATTR_T];
+  long int __align;
+} pthread_rwlockattr_t;
+#endif
+
+
+#ifdef __USE_XOPEN2K
+/* POSIX spinlock data type.  */
+typedef volatile int pthread_spinlock_t;
+
+
+/* POSIX barriers data type.  The structure of the type is
+   deliberately not exposed.  */
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_BARRIER_T];
+  long int __align;
+} pthread_barrier_t;
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_BARRIERATTR_T];
+  int __align;
+} pthread_barrierattr_t;
+#endif
+
+
+#endif /* bits/pthreadtypes.h */
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/bits/semaphore.h b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/bits/semaphore.h
new file mode 100644 (file)
index 0000000..dadfac2
--- /dev/null
@@ -0,0 +1,35 @@
+/* Copyright (C) 2002, 2005, 2007 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
+# error "Never use <bits/semaphore.h> directly; include <semaphore.h> instead."
+#endif
+
+
+#define __SIZEOF_SEM_T 16
+
+
+/* Value returned if `sem_open' failed.  */
+#define SEM_FAILED      ((sem_t *) 0)
+
+
+typedef union
+{
+  char __size[__SIZEOF_SEM_T];
+  long int __align;
+} sem_t;
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/clone.S b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/clone.S
new file mode 100644 (file)
index 0000000..23227eb
--- /dev/null
@@ -0,0 +1,3 @@
+#define RESET_PID
+#include <tcb-offsets.h>
+#include "../../../../../../../libc/sysdeps/linux/arm/clone.S"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/createthread.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/createthread.c
new file mode 100644 (file)
index 0000000..2d43559
--- /dev/null
@@ -0,0 +1,23 @@
+/* Copyright (C) 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* Value passed to 'clone' for initialization of the thread register.  */
+#define TLS_VALUE (pd + 1)
+
+/* Get the real implementation.         */
+#include <sysdeps/pthread/createthread.c>
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/fork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/fork.c
new file mode 100644 (file)
index 0000000..1c8f4c4
--- /dev/null
@@ -0,0 +1,31 @@
+/* Copyright (C) 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Phil Blundell <pb@nexus.co.uk>, 2005
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sched.h>
+#include <signal.h>
+#include <sysdep.h>
+#include <tls.h>
+
+
+#define ARCH_FORK()                                                    \
+  INLINE_SYSCALL (clone, 5,                                            \
+                 CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD,  \
+                 NULL, NULL, NULL, &THREAD_SELF->tid)
+
+#include "../fork.c"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/lowlevellock.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/lowlevellock.c
new file mode 100644 (file)
index 0000000..8c8955e
--- /dev/null
@@ -0,0 +1,134 @@
+/* low level locking for pthread library.  Generic futex-using version.
+   Copyright (C) 2003, 2005, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <sys/time.h>
+#include <tls.h>
+
+void
+__lll_lock_wait_private (int *futex)
+{
+  do
+    {
+      int oldval = atomic_compare_and_exchange_val_acq (futex, 2, 1);
+      if (oldval != 0)
+       lll_futex_wait (futex, 2, LLL_PRIVATE);
+    }
+  while (atomic_compare_and_exchange_bool_acq (futex, 2, 0) != 0);
+}
+
+
+/* These functions don't get included in libc.so  */
+#ifdef IS_IN_libpthread
+void
+__lll_lock_wait (int *futex, int private)
+{
+  do
+    {
+      int oldval = atomic_compare_and_exchange_val_acq (futex, 2, 1);
+      if (oldval != 0)
+       lll_futex_wait (futex, 2, private);
+    }
+  while (atomic_compare_and_exchange_bool_acq (futex, 2, 0) != 0);
+}
+
+
+int
+__lll_timedlock_wait (int *futex, const struct timespec *abstime, int private)
+{
+  struct timespec rt;
+
+  /* Reject invalid timeouts.  */
+  if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)
+    return EINVAL;
+
+  /* Upgrade the lock.  */
+  if (atomic_exchange_acq (futex, 2) == 0)
+    return 0;
+
+  do
+    {
+      struct timeval tv;
+
+      /* Get the current time.  */
+      (void) gettimeofday (&tv, NULL);
+
+      /* Compute relative timeout.  */
+      rt.tv_sec = abstime->tv_sec - tv.tv_sec;
+      rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000;
+      if (rt.tv_nsec < 0)
+       {
+         rt.tv_nsec += 1000000000;
+         --rt.tv_sec;
+       }
+
+      /* Already timed out?  */
+      if (rt.tv_sec < 0)
+       return ETIMEDOUT;
+
+      // XYZ: Lost the lock to check whether it was private.
+      lll_futex_timed_wait (futex, 2, &rt, private);
+    }
+  while (atomic_compare_and_exchange_bool_acq (futex, 2, 0) != 0);
+
+  return 0;
+}
+
+
+int
+__lll_timedwait_tid (int *tidp, const struct timespec *abstime)
+{
+  int tid;
+
+  if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)
+    return EINVAL;
+
+  /* Repeat until thread terminated.  */
+  while ((tid = *tidp) != 0)
+    {
+      struct timeval tv;
+      struct timespec rt;
+
+      /* Get the current time.  */
+      (void) gettimeofday (&tv, NULL);
+
+      /* Compute relative timeout.  */
+      rt.tv_sec = abstime->tv_sec - tv.tv_sec;
+      rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000;
+      if (rt.tv_nsec < 0)
+       {
+         rt.tv_nsec += 1000000000;
+         --rt.tv_sec;
+       }
+
+      /* Already timed out?  */
+      if (rt.tv_sec < 0)
+       return ETIMEDOUT;
+
+      /* Wait until thread terminates.  */
+      // XYZ: Lost the lock to check whether it was private.
+      if (lll_futex_timed_wait (tidp, tid, &rt, LLL_SHARED) == -ETIMEDOUT)
+       return ETIMEDOUT;
+    }
+
+  return 0;
+}
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/lowlevellock.h b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/lowlevellock.h
new file mode 100644 (file)
index 0000000..4c7d08c
--- /dev/null
@@ -0,0 +1,282 @@
+/* Copyright (C) 2005, 2006, 2007, 2008, 2009 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 _LOWLEVELLOCK_H
+#define _LOWLEVELLOCK_H        1
+
+#include <time.h>
+#include <sys/param.h>
+#include <bits/pthreadtypes.h>
+#include <atomic.h>
+#include <sysdep.h>
+#include <bits/kernel-features.h>
+
+#define FUTEX_WAIT             0
+#define FUTEX_WAKE             1
+#define FUTEX_REQUEUE          3
+#define FUTEX_CMP_REQUEUE      4
+#define FUTEX_WAKE_OP          5
+#define FUTEX_OP_CLEAR_WAKE_IF_GT_ONE  ((4 << 24) | 1)
+#define FUTEX_LOCK_PI          6
+#define FUTEX_UNLOCK_PI                7
+#define FUTEX_TRYLOCK_PI       8
+#define FUTEX_WAIT_BITSET      9
+#define FUTEX_WAKE_BITSET      10
+#define FUTEX_PRIVATE_FLAG     128
+#define FUTEX_CLOCK_REALTIME   256
+
+#define FUTEX_BITSET_MATCH_ANY 0xffffffff
+
+/* Values for 'private' parameter of locking macros.  Yes, the
+   definition seems to be backwards.  But it is not.  The bit will be
+   reversed before passing to the system call.  */
+#define LLL_PRIVATE    0
+#define LLL_SHARED     FUTEX_PRIVATE_FLAG
+
+
+#if !defined NOT_IN_libc || defined IS_IN_rtld
+/* In libc.so or ld.so all futexes are private.  */
+# ifdef __ASSUME_PRIVATE_FUTEX
+#  define __lll_private_flag(fl, private) \
+  ((fl) | FUTEX_PRIVATE_FLAG)
+# else
+#  define __lll_private_flag(fl, private) \
+  ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex))
+# endif
+#else
+# ifdef __ASSUME_PRIVATE_FUTEX
+#  define __lll_private_flag(fl, private) \
+  (((fl) | FUTEX_PRIVATE_FLAG) ^ (private))
+# else
+#  define __lll_private_flag(fl, private) \
+  (__builtin_constant_p (private)                                            \
+   ? ((private) == 0                                                         \
+      ? ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex))           \
+      : (fl))                                                                \
+   : ((fl) | (((private) ^ FUTEX_PRIVATE_FLAG)                               \
+             & THREAD_GETMEM (THREAD_SELF, header.private_futex))))
+# endif              
+#endif
+
+
+#define lll_futex_wait(futexp, val, private) \
+  lll_futex_timed_wait(futexp, val, NULL, private)
+
+#define lll_futex_timed_wait(futexp, val, timespec, private) \
+  ({                                                                         \
+    INTERNAL_SYSCALL_DECL (__err);                                           \
+    long int __ret;                                                          \
+    __ret = INTERNAL_SYSCALL (futex, __err, 4, (futexp),                     \
+                             __lll_private_flag (FUTEX_WAIT, private),       \
+                             (val), (timespec));                             \
+    __ret;                                                                   \
+  })
+
+#define lll_futex_wake(futexp, nr, private) \
+  ({                                                                         \
+    INTERNAL_SYSCALL_DECL (__err);                                           \
+    long int __ret;                                                          \
+    __ret = INTERNAL_SYSCALL (futex, __err, 4, (futexp),                     \
+                             __lll_private_flag (FUTEX_WAKE, private),       \
+                             (nr), 0);                                       \
+    __ret;                                                                   \
+  })
+
+#define lll_robust_dead(futexv, private) \
+  do                                                                         \
+    {                                                                        \
+      int *__futexp = &(futexv);                                             \
+      atomic_or (__futexp, FUTEX_OWNER_DIED);                                \
+      lll_futex_wake (__futexp, 1, private);                                 \
+    }                                                                        \
+  while (0)
+
+/* Returns non-zero if error happened, zero if success.  */
+#define lll_futex_requeue(futexp, nr_wake, nr_move, mutex, val, private) \
+  ({                                                                         \
+    INTERNAL_SYSCALL_DECL (__err);                                           \
+    long int __ret;                                                          \
+    __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp),                     \
+                             __lll_private_flag (FUTEX_CMP_REQUEUE, private),\
+                             (nr_wake), (nr_move), (mutex), (val));          \
+    INTERNAL_SYSCALL_ERROR_P (__ret, __err);                                 \
+  })
+
+
+/* Returns non-zero if error happened, zero if success.  */
+#define lll_futex_wake_unlock(futexp, nr_wake, nr_wake2, futexp2, private) \
+  ({                                                                         \
+    INTERNAL_SYSCALL_DECL (__err);                                           \
+    long int __ret;                                                          \
+    __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp),                     \
+                             __lll_private_flag (FUTEX_WAKE_OP, private),    \
+                             (nr_wake), (nr_wake2), (futexp2),               \
+                             FUTEX_OP_CLEAR_WAKE_IF_GT_ONE);                 \
+    INTERNAL_SYSCALL_ERROR_P (__ret, __err);                                 \
+  })
+
+
+#define lll_trylock(lock)      \
+  atomic_compare_and_exchange_val_acq(&(lock), 1, 0)
+
+#define lll_cond_trylock(lock) \
+  atomic_compare_and_exchange_val_acq(&(lock), 2, 0)
+
+#define __lll_robust_trylock(futex, id) \
+  (atomic_compare_and_exchange_val_acq (futex, id, 0) != 0)
+#define lll_robust_trylock(lock, id) \
+  __lll_robust_trylock (&(lock), id)
+
+extern void __lll_lock_wait_private (int *futex) attribute_hidden;
+extern void __lll_lock_wait (int *futex, int private) attribute_hidden;
+extern int __lll_robust_lock_wait (int *futex, int private) attribute_hidden;
+
+#define __lll_lock(futex, private)                                           \
+  ((void) ({                                                                 \
+    int *__futex = (futex);                                                  \
+    if (__builtin_expect (atomic_compare_and_exchange_val_acq (__futex,       \
+                                                               1, 0), 0))    \
+      {                                                                              \
+       if (__builtin_constant_p (private) && (private) == LLL_PRIVATE)       \
+         __lll_lock_wait_private (__futex);                                  \
+       else                                                                  \
+         __lll_lock_wait (__futex, private);                                 \
+      }                                                                              \
+  }))
+#define lll_lock(futex, private) __lll_lock (&(futex), private)
+
+
+#define __lll_robust_lock(futex, id, private)                                \
+  ({                                                                         \
+    int *__futex = (futex);                                                  \
+    int __val = 0;                                                           \
+                                                                             \
+    if (__builtin_expect (atomic_compare_and_exchange_bool_acq (__futex, id,  \
+                                                               0), 0))       \
+      __val = __lll_robust_lock_wait (__futex, private);                     \
+    __val;                                                                   \
+  })
+#define lll_robust_lock(futex, id, private) \
+  __lll_robust_lock (&(futex), id, private)
+
+
+#define __lll_cond_lock(futex, private)                                              \
+  ((void) ({                                                                 \
+    int *__futex = (futex);                                                  \
+    if (__builtin_expect (atomic_exchange_acq (__futex, 2), 0))                      \
+      __lll_lock_wait (__futex, private);                                    \
+  }))
+#define lll_cond_lock(futex, private) __lll_cond_lock (&(futex), private)
+
+
+#define lll_robust_cond_lock(futex, id, private) \
+  __lll_robust_lock (&(futex), (id) | FUTEX_WAITERS, private)
+
+
+extern int __lll_timedlock_wait (int *futex, const struct timespec *,
+                                int private) attribute_hidden;
+extern int __lll_robust_timedlock_wait (int *futex, const struct timespec *,
+                                       int private) attribute_hidden;
+
+#define __lll_timedlock(futex, abstime, private)                             \
+  ({                                                                         \
+     int *__futex = (futex);                                                 \
+     int __val = 0;                                                          \
+                                                                             \
+     if (__builtin_expect (atomic_exchange_acq (__futex, 1), 0))             \
+       __val = __lll_timedlock_wait (__futex, abstime, private);             \
+     __val;                                                                  \
+  })
+#define lll_timedlock(futex, abstime, private) \
+  __lll_timedlock (&(futex), abstime, private)
+
+
+#define __lll_robust_timedlock(futex, abstime, id, private)                  \
+  ({                                                                         \
+    int *__futex = (futex);                                                  \
+    int __val = 0;                                                           \
+                                                                             \
+    if (__builtin_expect (atomic_compare_and_exchange_bool_acq (__futex, id,  \
+                                                               0), 0))       \
+      __val = __lll_robust_timedlock_wait (__futex, abstime, private);       \
+    __val;                                                                   \
+  })
+#define lll_robust_timedlock(futex, abstime, id, private) \
+  __lll_robust_timedlock (&(futex), abstime, id, private)
+
+
+#define __lll_unlock(futex, private) \
+  (void)                                                       \
+    ({ int *__futex = (futex);                                 \
+       int __oldval = atomic_exchange_rel (__futex, 0);                \
+       if (__builtin_expect (__oldval > 1, 0))                 \
+        lll_futex_wake (__futex, 1, private);                  \
+    })
+#define lll_unlock(futex, private) __lll_unlock(&(futex), private)
+
+
+#define __lll_robust_unlock(futex, private) \
+  (void)                                                       \
+    ({ int *__futex = (futex);                                 \
+       int __oldval = atomic_exchange_rel (__futex, 0);                \
+       if (__builtin_expect (__oldval & FUTEX_WAITERS, 0))     \
+        lll_futex_wake (__futex, 1, private);                  \
+    })
+#define lll_robust_unlock(futex, private) \
+  __lll_robust_unlock(&(futex), private)
+
+
+#define lll_islocked(futex) \
+  (futex != 0)
+
+
+/* Our internal lock implementation is identical to the binary-compatible
+   mutex implementation. */
+
+/* Initializers for lock.  */
+#define LLL_LOCK_INITIALIZER           (0)
+#define LLL_LOCK_INITIALIZER_LOCKED    (1)
+
+/* The states of a lock are:
+    0  -  untaken
+    1  -  taken by one user
+   >1  -  taken by more users */
+
+/* The kernel notifies a process which uses CLONE_CLEARTID via futex
+   wakeup when the clone terminates.  The memory location contains the
+   thread ID while the clone is running and is reset to zero
+   afterwards. */
+#define lll_wait_tid(tid) \
+  do {                                 \
+    __typeof (tid) __tid;              \
+    while ((__tid = (tid)) != 0)       \
+      lll_futex_wait (&(tid), __tid, LLL_SHARED);\
+  } while (0)
+
+extern int __lll_timedwait_tid (int *, const struct timespec *)
+     attribute_hidden;
+
+#define lll_timedwait_tid(tid, abstime) \
+  ({                                                   \
+    int __res = 0;                                     \
+    if ((tid) != 0)                                    \
+      __res = __lll_timedwait_tid (&(tid), (abstime)); \
+    __res;                                             \
+  })
+
+#endif /* lowlevellock.h */
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/nptl-aeabi_unwind_cpp_pr1.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/nptl-aeabi_unwind_cpp_pr1.c
new file mode 100644 (file)
index 0000000..7b83522
--- /dev/null
@@ -0,0 +1 @@
+#include <aeabi_unwind_cpp_pr1.c>
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-__syscall_error.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-__syscall_error.c
new file mode 100644 (file)
index 0000000..5a48a9b
--- /dev/null
@@ -0,0 +1 @@
+#include <../../../../../../../libc/sysdeps/linux/arm/__syscall_error.c>
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-__syscall_rt_sigaction.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-__syscall_rt_sigaction.c
new file mode 100644 (file)
index 0000000..50137c8
--- /dev/null
@@ -0,0 +1 @@
+#include <../../../../../../../libc/sysdeps/linux/common/__syscall_rt_sigaction.c>
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-gettimeofday.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-gettimeofday.c
new file mode 100644 (file)
index 0000000..08710f1
--- /dev/null
@@ -0,0 +1,5 @@
+#include <sys/syscall.h>
+#include <sys/time.h>
+
+int gettimeofday (struct timeval *, struct timezone *) attribute_hidden;
+_syscall2(int, gettimeofday, struct timeval *, tv, struct timezone *, tz);
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-vfork.S
new file mode 100644 (file)
index 0000000..9764e9e
--- /dev/null
@@ -0,0 +1,38 @@
+/* Copyright (C) 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <tcb-offsets.h>
+
+/* Save the PID value.  */
+#define SAVE_PID \
+       str     lr, [sp, #-4]!;         /* Save LR.  */                 \
+       mov     r0, #0xffff0fff;        /* Point to the high page.  */  \
+       mov     lr, pc;                 /* Save our return address.  */ \
+       sub     pc, r0, #31;            /* Jump to the TLS entry.  */   \
+       ldr     lr, [sp], #4;           /* Restore LR.  */              \
+       mov     r2, r0;                 /* Save the TLS addr in r2.  */ \
+       ldr     r3, [r2, #PID_OFFSET];  /* Load the saved PID.  */      \
+       rsb     r0, r3, #0;             /* Negate it.  */               \
+       str     r0, [r2, #PID_OFFSET]   /* Store the temporary PID.  */
+
+/* Restore the old PID value in the parent.  */
+#define RESTORE_PID \
+       cmp     r0, #0;                 /* If we are the parent... */   \
+       strne   r3, [r2, #PID_OFFSET]   /* ... restore the saved PID.  */
+
+#INCLUDE <../../../../../../../LIBC/SYSDEPS/LINUX/ARM/VFORK.S>
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pthread_once.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pthread_once.c
new file mode 100644 (file)
index 0000000..d81ecd4
--- /dev/null
@@ -0,0 +1,99 @@
+/* Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+#include <lowlevellock.h>
+
+unsigned long int __fork_generation attribute_hidden;
+
+static void
+clear_once_control (void *arg)
+{
+  pthread_once_t *once_control = (pthread_once_t *) arg;
+
+  *once_control = 0;
+  lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE);
+}
+
+int
+__pthread_once (pthread_once_t *once_control, void (*init_routine) (void))
+{
+  for (;;)
+    {
+      int oldval;
+      int newval;
+
+      /* Pseudo code:
+        newval = __fork_generation | 1;
+        oldval = *once_control;
+        if ((oldval & 2) == 0)
+          *once_control = newval;
+        Do this atomically.
+      */
+      do
+       {
+         newval = __fork_generation | 1;
+         oldval = *once_control;
+         if (oldval & 2)
+           break;
+       } while (atomic_compare_and_exchange_val_acq (once_control, newval, oldval) != oldval);
+
+      /* Check if the initializer has already been done.  */
+      if ((oldval & 2) != 0)
+       return 0;
+
+      /* Check if another thread already runs the initializer. */
+      if ((oldval & 1) == 0)
+       break;
+
+      /* Check whether the initializer execution was interrupted by a fork.  */
+      if (oldval != newval)
+       break;
+
+      /* Same generation, some other thread was faster. Wait.  */
+      lll_futex_wait (once_control, oldval, LLL_PRIVATE);
+    }
+
+  /* This thread is the first here.  Do the initialization.
+     Register a cleanup handler so that in case the thread gets
+     interrupted the initialization can be restarted.  */
+  pthread_cleanup_push (clear_once_control, once_control);
+
+  init_routine ();
+
+  pthread_cleanup_pop (0);
+
+  /* Say that the initialisation is done.  */
+  *once_control = __fork_generation | 2;
+
+  /* Wake up all other threads.  */
+  lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE);
+
+  return 0;
+}
+weak_alias (__pthread_once, pthread_once)
+strong_alias (__pthread_once, __pthread_once_internal)
+
+#if defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__PIC__)
+/* When statically linked, if pthread_create is used, this file
+   will be brought in.  The exception handling code in GCC assumes
+   that if pthread_create is available, so are these.  */
+const void *include_pthread_getspecific attribute_hidden = pthread_getspecific;
+const void *include_pthread_setspecific attribute_hidden = pthread_setspecific;
+const void *include_pthread_key_create attribute_hidden = pthread_key_create;
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/sysdep-cancel.h
new file mode 100644 (file)
index 0000000..423c231
--- /dev/null
@@ -0,0 +1,137 @@
+/* Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <tcb-offsets.h>
+#ifndef __ASSEMBLER__
+# include <pthreadP.h>
+#endif
+
+#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt
+
+# undef PSEUDO
+# define PSEUDO(name, syscall_name, args)                              \
+  .section ".text";                                                    \
+    PSEUDO_PROLOGUE;                                                   \
+  .type __##syscall_name##_nocancel,%function;                         \
+  .globl __##syscall_name##_nocancel;                                  \
+  __##syscall_name##_nocancel:                                         \
+    DO_CALL (syscall_name, args);                                      \
+    PSEUDO_RET;                                                                \
+  .size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel;     \
+  ENTRY (name);                                                                \
+    SINGLE_THREAD_P;                                                   \
+    DOARGS_##args;                                                     \
+    bne .Lpseudo_cancel;                                               \
+    DO_CALL (syscall_name, 0);                                         \
+    UNDOARGS_##args;                                                   \
+    cmn r0, $4096;                                                     \
+    PSEUDO_RET;                                                                \
+  .Lpseudo_cancel:                                                     \
+    DOCARGS_##args;    /* save syscall args etc. around CENABLE.  */   \
+    CENABLE;                                                           \
+    mov ip, r0;                /* put mask in safe place.  */                  \
+    UNDOCARGS_##args;  /* restore syscall args.  */                    \
+    swi SYS_ify (syscall_name);        /* do the call.  */                     \
+    str r0, [sp, $-4]!; /* save syscall return value.  */              \
+    mov r0, ip;                /* get mask back.  */                           \
+    CDISABLE;                                                          \
+    ldmfd sp!, {r0, lr}; /* retrieve return value and address.  */     \
+    UNDOARGS_##args;                                                   \
+    cmn r0, $4096;
+
+# define DOCARGS_0     str lr, [sp, #-4]!;
+# define UNDOCARGS_0
+
+# define DOCARGS_1     stmfd sp!, {r0, lr};
+# define UNDOCARGS_1   ldr r0, [sp], #4;
+
+# define DOCARGS_2     stmfd sp!, {r0, r1, lr};
+# define UNDOCARGS_2   ldmfd sp!, {r0, r1};
+
+# define DOCARGS_3     stmfd sp!, {r0, r1, r2, lr};
+# define UNDOCARGS_3   ldmfd sp!, {r0, r1, r2};
+
+# define DOCARGS_4     stmfd sp!, {r0, r1, r2, r3, lr};
+# define UNDOCARGS_4   ldmfd sp!, {r0, r1, r2, r3};
+
+# define DOCARGS_5     DOCARGS_4
+# define UNDOCARGS_5   UNDOCARGS_4
+
+# define DOCARGS_6     DOCARGS_5
+# define UNDOCARGS_6   UNDOCARGS_5
+
+# ifdef IS_IN_libpthread
+#  define CENABLE      bl PLTJMP(__pthread_enable_asynccancel)
+#  define CDISABLE     bl PLTJMP(__pthread_disable_asynccancel)
+#  define __local_multiple_threads __pthread_multiple_threads
+# elif !defined NOT_IN_libc
+#  define CENABLE      bl PLTJMP(__libc_enable_asynccancel)
+#  define CDISABLE     bl PLTJMP(__libc_disable_asynccancel)
+#  define __local_multiple_threads __libc_multiple_threads
+# elif defined IS_IN_librt
+#  define CENABLE      bl PLTJMP(__librt_enable_asynccancel)
+#  define CDISABLE     bl PLTJMP(__librt_disable_asynccancel)
+# else
+#  error Unsupported library
+# endif
+
+# if defined IS_IN_libpthread || !defined NOT_IN_libc
+#  ifndef __ASSEMBLER__
+extern int __local_multiple_threads attribute_hidden;
+#   define SINGLE_THREAD_P __builtin_expect (__local_multiple_threads == 0, 1)
+#  else
+#   define SINGLE_THREAD_P                                             \
+  ldr ip, 1b;                                                          \
+2:                                                                     \
+  ldr ip, [pc, ip];                                                    \
+  teq ip, #0;
+#   define PSEUDO_PROLOGUE                                             \
+  1:  .word __local_multiple_threads - 2f - 8;
+#  endif
+# else
+/*  There is no __local_multiple_threads for librt, so use the TCB.  */
+#  ifndef __ASSEMBLER__
+#   define SINGLE_THREAD_P                                             \
+  __builtin_expect (THREAD_GETMEM (THREAD_SELF,                                \
+                                  header.multiple_threads) == 0, 1)
+#  else
+#   define PSEUDO_PROLOGUE
+#   define SINGLE_THREAD_P                                             \
+  stmfd        sp!, {r0, lr};                                                  \
+  bl   __aeabi_read_tp;                                                \
+  ldr  ip, [r0, #MULTIPLE_THREADS_OFFSET];                             \
+  ldmfd        sp!, {r0, lr};                                                  \
+  teq  ip, #0
+#   define SINGLE_THREAD_P_PIC(x) SINGLE_THREAD_P
+#  endif
+# endif
+
+#elif !defined __ASSEMBLER__
+
+/* For rtld, et cetera.  */
+# define SINGLE_THREAD_P 1
+# define NO_CANCELLATION 1
+
+#endif
+
+#ifndef __ASSEMBLER__
+# define RTLD_SINGLE_THREAD_P \
+  __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
+                                  header.multiple_threads) == 0, 1)
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind-forcedunwind.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind-forcedunwind.c
new file mode 100644 (file)
index 0000000..d095d30
--- /dev/null
@@ -0,0 +1,149 @@
+/* Copyright (C) 2003, 2009 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <dlfcn.h>
+#include <stdio.h>
+#include <unwind.h>
+#include <pthreadP.h>
+#define __libc_dlopen(x)        dlopen(x, (RTLD_LOCAL | RTLD_LAZY))
+#define __libc_dlsym            dlsym
+#define __libc_dlclose          dlclose
+
+static void *libgcc_s_handle;
+static void (*libgcc_s_resume) (struct _Unwind_Exception *exc);
+static _Unwind_Reason_Code (*libgcc_s_personality)
+  (int, _Unwind_Action, _Unwind_Exception_Class, struct _Unwind_Exception *,
+   struct _Unwind_Context *);
+static _Unwind_Reason_Code (*libgcc_s_forcedunwind)
+  (struct _Unwind_Exception *, _Unwind_Stop_Fn, void *);
+static _Unwind_Word (*libgcc_s_getcfa) (struct _Unwind_Context *);
+static void (*libgcc_s_sjlj_register) (struct SjLj_Function_Context *);
+static void (*libgcc_s_sjlj_unregister) (struct SjLj_Function_Context *);
+
+void
+__attribute_noinline__
+pthread_cancel_init (void)
+{
+  void *resume, *personality, *forcedunwind, *getcfa;
+  void *handle;
+  void *sjlj_register, *sjlj_unregister;
+
+  if (__builtin_expect (libgcc_s_handle != NULL, 1))
+    {
+      /* Force gcc to reload all values.  */
+      asm volatile ("" ::: "memory");
+      return;
+    }
+
+  handle = __libc_dlopen ("libgcc_s.so.1");
+
+  if (handle == NULL
+      || (sjlj_register = __libc_dlsym (handle, "_Unwind_SjLj_Register")) == NULL
+      || (sjlj_unregister = __libc_dlsym (handle, "_Unwind_SjLj_Unregister")) == NULL
+      || (resume = __libc_dlsym (handle, "_Unwind_SjLj_Resume")) == NULL
+      || (personality = __libc_dlsym (handle, "__gcc_personality_sj0")) == NULL
+      || (forcedunwind = __libc_dlsym (handle, "_Unwind_SjLj_ForcedUnwind"))
+        == NULL
+      || (getcfa = __libc_dlsym (handle, "_Unwind_GetCFA")) == NULL
+      )
+      fprintf(stderr, "libgcc_s.so.1 must be installed for pthread_cancel to work\n");
+
+  libgcc_s_resume = resume;
+  libgcc_s_personality = personality;
+  libgcc_s_forcedunwind = forcedunwind;
+  libgcc_s_sjlj_register = sjlj_register;
+  libgcc_s_sjlj_unregister = sjlj_unregister;
+  libgcc_s_getcfa = getcfa;
+  /* Make sure libgcc_s_getcfa is written last.  Otherwise,
+     pthread_cancel_init might return early even when the pointer the
+     caller is interested in is not initialized yet.  */
+  atomic_write_barrier ();
+  libgcc_s_handle = handle;
+}
+
+void
+__libc_freeres_fn_section
+__unwind_freeres (void)
+{
+  void *handle = libgcc_s_handle;
+  if (handle != NULL)
+    {
+      libgcc_s_handle = NULL;
+      __libc_dlclose (handle);
+    }
+}
+
+void
+_Unwind_Resume (struct _Unwind_Exception *exc)
+{
+  if (__builtin_expect (libgcc_s_resume == NULL, 0))
+    pthread_cancel_init ();
+
+  libgcc_s_resume (exc);
+}
+
+_Unwind_Reason_Code
+__gcc_personality_v0 (int version, _Unwind_Action actions,
+                     _Unwind_Exception_Class exception_class,
+                      struct _Unwind_Exception *ue_header,
+                      struct _Unwind_Context *context)
+{
+  if (__builtin_expect (libgcc_s_personality == NULL, 0))
+    pthread_cancel_init ();
+
+  return libgcc_s_personality (version, actions, exception_class,
+                              ue_header, context);
+}
+
+_Unwind_Reason_Code
+_Unwind_ForcedUnwind (struct _Unwind_Exception *exc, _Unwind_Stop_Fn stop,
+                     void *stop_argument)
+{
+  if (__builtin_expect (libgcc_s_forcedunwind == NULL, 0))
+    pthread_cancel_init ();
+
+  return libgcc_s_forcedunwind (exc, stop, stop_argument);
+}
+
+_Unwind_Word
+_Unwind_GetCFA (struct _Unwind_Context *context)
+{
+  if (__builtin_expect (libgcc_s_getcfa == NULL, 0))
+    pthread_cancel_init ();
+
+  return libgcc_s_getcfa (context);
+}
+
+void
+_Unwind_SjLj_Register (struct SjLj_Function_Context *fc)
+{
+  if (__builtin_expect (libgcc_s_sjlj_register == NULL, 0))
+    pthread_cancel_init ();
+
+  libgcc_s_sjlj_register (fc);
+}
+
+void
+_Unwind_SjLj_Unregister (struct SjLj_Function_Context *fc)
+{
+  if (__builtin_expect (libgcc_s_sjlj_unregister == NULL, 0))
+    pthread_cancel_init ();
+
+  libgcc_s_sjlj_unregister (fc);
+}
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind-resume.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind-resume.c
new file mode 100644 (file)
index 0000000..bf0348a
--- /dev/null
@@ -0,0 +1,90 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <dlfcn.h>
+#include <stdio.h>
+#include <unwind.h>
+#define __libc_dlopen(x)        dlopen(x, (RTLD_LOCAL | RTLD_LAZY))
+#define __libc_dlsym            dlsym
+#define __libc_dlclose         dlclose
+
+static void (*libgcc_s_resume) (struct _Unwind_Exception *exc);
+static _Unwind_Reason_Code (*libgcc_s_personality)
+  (int, _Unwind_Action, _Unwind_Exception_Class, struct _Unwind_Exception *,
+   struct _Unwind_Context *);
+static void (*libgcc_s_sjlj_register) (struct SjLj_Function_Context *);
+static void (*libgcc_s_sjlj_unregister) (struct SjLj_Function_Context *);
+
+static void
+init (void)
+{
+  void *resume, *personality;
+  void *handle;
+  void *sjlj_register, *sjlj_unregister;
+
+  handle = __libc_dlopen ("libgcc_s.so.1");
+
+  if (handle == NULL
+      || (sjlj_register = __libc_dlsym (handle, "_Unwind_SjLj_Register")) == NULL
+      || (sjlj_unregister = __libc_dlsym (handle, "_Unwind_SjLj_Unregister")) == NULL
+      || (resume = __libc_dlsym (handle, "_Unwind_SjLj_Resume")) == NULL
+      || (personality = __libc_dlsym (handle, "__gcc_personality_sj0")) == NULL)
+      fprintf(stderr, "libgcc_s.so.1 must be installed for pthread_cancel to work\n");
+
+  libgcc_s_resume = resume;
+  libgcc_s_personality = personality;
+  libgcc_s_sjlj_register = sjlj_register;
+  libgcc_s_sjlj_unregister = sjlj_unregister;
+}
+
+void
+_Unwind_Resume (struct _Unwind_Exception *exc)
+{
+  if (__builtin_expect (libgcc_s_resume == NULL, 0))
+    init ();
+  libgcc_s_resume (exc);
+}
+
+_Unwind_Reason_Code
+__gcc_personality_v0 (int version, _Unwind_Action actions,
+                     _Unwind_Exception_Class exception_class,
+                      struct _Unwind_Exception *ue_header,
+                      struct _Unwind_Context *context)
+{
+  if (__builtin_expect (libgcc_s_personality == NULL, 0))
+    init ();
+  return libgcc_s_personality (version, actions, exception_class,
+                              ue_header, context);
+}
+
+void
+_Unwind_SjLj_Register (struct SjLj_Function_Context *fc)
+{
+  if (__builtin_expect (libgcc_s_sjlj_register == NULL, 0))
+    init ();
+  libgcc_s_sjlj_register (fc);
+}
+
+void
+_Unwind_SjLj_Unregister (struct SjLj_Function_Context *fc)
+{
+  if (__builtin_expect (libgcc_s_sjlj_unregister == NULL, 0))
+    init ();
+  libgcc_s_sjlj_unregister (fc);
+}
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind.h b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind.h
new file mode 100644 (file)
index 0000000..eeb9cf8
--- /dev/null
@@ -0,0 +1,279 @@
+/* Header file for the ARM EABI unwinder
+   Copyright (C) 2003, 2004, 2005, 2009  Free Software Foundation, Inc.
+   Contributed by Paul Brook
+
+   This file is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 2, or (at your option) any
+   later version.
+
+   In addition to the permissions in the GNU General Public License, the
+   Free Software Foundation gives you unlimited permission to link the
+   compiled version of this file into combinations with other programs,
+   and to distribute those combinations without any restriction coming
+   from the use of this file.  (The General Public License restrictions
+   do apply in other respects; for example, they cover modification of
+   the file, and distribution when not linked into a combine
+   executable.)
+
+   This file is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; see the file COPYING.  If not, write to
+   the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+/* Language-independent unwinder header public defines.  This contains both
+   ABI defined objects, and GNU support routines.  */
+
+#ifndef UNWIND_ARM_H
+#define UNWIND_ARM_H
+
+#define __ARM_EABI_UNWINDER__ 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+  typedef unsigned _Unwind_Word __attribute__((__mode__(__word__)));
+  typedef signed _Unwind_Sword __attribute__((__mode__(__word__)));
+  typedef unsigned _Unwind_Ptr __attribute__((__mode__(__pointer__)));
+  typedef unsigned _Unwind_Internal_Ptr __attribute__((__mode__(__pointer__)));
+  typedef _Unwind_Word _uw;
+  typedef unsigned _uw64 __attribute__((mode(__DI__)));
+  typedef unsigned _uw16 __attribute__((mode(__HI__)));
+  typedef unsigned _uw8 __attribute__((mode(__QI__)));
+
+  typedef enum
+    {
+      _URC_OK = 0,       /* operation completed successfully */
+      _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
+      _URC_END_OF_STACK = 5,
+      _URC_HANDLER_FOUND = 6,
+      _URC_INSTALL_CONTEXT = 7,
+      _URC_CONTINUE_UNWIND = 8,
+      _URC_FAILURE = 9   /* unspecified failure of some kind */
+    }
+  _Unwind_Reason_Code;
+
+  typedef enum
+    {
+      _US_VIRTUAL_UNWIND_FRAME = 0,
+      _US_UNWIND_FRAME_STARTING = 1,
+      _US_UNWIND_FRAME_RESUME = 2,
+      _US_ACTION_MASK = 3,
+      _US_FORCE_UNWIND = 8,
+      _US_END_OF_STACK = 16
+    }
+  _Unwind_State;
+
+  /* Provided only for for compatibility with existing code.  */
+  typedef int _Unwind_Action;
+#define _UA_SEARCH_PHASE       1
+#define _UA_CLEANUP_PHASE      2
+#define _UA_HANDLER_FRAME      4
+#define _UA_FORCE_UNWIND       8
+#define _UA_END_OF_STACK       16
+#define _URC_NO_REASON         _URC_OK
+
+  typedef struct _Unwind_Control_Block _Unwind_Control_Block;
+  typedef struct _Unwind_Context _Unwind_Context;
+  typedef _uw _Unwind_EHT_Header;
+
+
+  /* UCB: */
+
+  struct _Unwind_Control_Block
+    {
+#ifdef _LIBC
+      /* For the benefit of code which assumes this is a scalar.  All
+        glibc ever does is clear it.  */
+      _uw64 exception_class;
+#else
+      char exception_class[8];
+#endif
+      void (*exception_cleanup)(_Unwind_Reason_Code, _Unwind_Control_Block *);
+      /* Unwinder cache, private fields for the unwinder's use */
+      struct
+       {
+         _uw reserved1;  /* Forced unwind stop fn, 0 if not forced */
+         _uw reserved2;  /* Personality routine address */
+         _uw reserved3;  /* Saved callsite address */
+         _uw reserved4;  /* Forced unwind stop arg */
+         _uw reserved5;
+       }
+      unwinder_cache;
+      /* Propagation barrier cache (valid after phase 1): */
+      struct
+       {
+         _uw sp;
+         _uw bitpattern[5];
+       }
+      barrier_cache;
+      /* Cleanup cache (preserved over cleanup): */
+      struct
+       {
+         _uw bitpattern[4];
+       }
+      cleanup_cache;
+      /* Pr cache (for pr's benefit): */
+      struct
+       {
+         _uw fnstart;                  /* function start address */
+         _Unwind_EHT_Header *ehtp;     /* pointer to EHT entry header word */
+         _uw additional;               /* additional data */
+         _uw reserved1;
+       }
+      pr_cache;
+      long long int :0;        /* Force alignment to 8-byte boundary */
+    };
+
+  /* Virtual Register Set*/
+
+  typedef enum
+    {
+      _UVRSC_CORE = 0,      /* integer register */
+      _UVRSC_VFP = 1,       /* vfp */
+      _UVRSC_FPA = 2,       /* fpa */
+      _UVRSC_WMMXD = 3,     /* Intel WMMX data register */
+      _UVRSC_WMMXC = 4      /* Intel WMMX control register */
+    }
+  _Unwind_VRS_RegClass;
+
+  typedef enum
+    {
+      _UVRSD_UINT32 = 0,
+      _UVRSD_VFPX = 1,
+      _UVRSD_FPAX = 2,
+      _UVRSD_UINT64 = 3,
+      _UVRSD_FLOAT = 4,
+      _UVRSD_DOUBLE = 5
+    }
+  _Unwind_VRS_DataRepresentation;
+
+  typedef enum
+    {
+      _UVRSR_OK = 0,
+      _UVRSR_NOT_IMPLEMENTED = 1,
+      _UVRSR_FAILED = 2
+    }
+  _Unwind_VRS_Result;
+
+  /* Frame unwinding state.  */
+  typedef struct
+    {
+      /* The current word (bytes packed msb first).  */
+      _uw data;
+      /* Pointer to the next word of data.  */
+      _uw *next;
+      /* The number of bytes left in this word.  */
+      _uw8 bytes_left;
+      /* The number of words pointed to by ptr.  */
+      _uw8 words_left;
+    }
+  __gnu_unwind_state;
+
+  typedef _Unwind_Reason_Code (*personality_routine) (_Unwind_State,
+      _Unwind_Control_Block *, _Unwind_Context *);
+
+  _Unwind_VRS_Result _Unwind_VRS_Set(_Unwind_Context *, _Unwind_VRS_RegClass,
+                                     _uw, _Unwind_VRS_DataRepresentation,
+                                     void *);
+
+  _Unwind_VRS_Result _Unwind_VRS_Get(_Unwind_Context *, _Unwind_VRS_RegClass,
+                                     _uw, _Unwind_VRS_DataRepresentation,
+                                     void *);
+
+  _Unwind_VRS_Result _Unwind_VRS_Pop(_Unwind_Context *, _Unwind_VRS_RegClass,
+                                     _uw, _Unwind_VRS_DataRepresentation);
+
+
+  /* Support functions for the PR.  */
+#define _Unwind_Exception _Unwind_Control_Block
+  typedef char _Unwind_Exception_Class[8];
+
+  void * _Unwind_GetLanguageSpecificData (_Unwind_Context *);
+  _Unwind_Ptr _Unwind_GetRegionStart (_Unwind_Context *);
+
+  /* These two should never be used.  */
+  _Unwind_Ptr _Unwind_GetDataRelBase (_Unwind_Context *);
+  _Unwind_Ptr _Unwind_GetTextRelBase (_Unwind_Context *);
+
+  /* Interface functions: */
+  _Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Control_Block *ucbp);
+  void __attribute__((noreturn)) _Unwind_Resume(_Unwind_Control_Block *ucbp);
+  _Unwind_Reason_Code _Unwind_Resume_or_Rethrow (_Unwind_Control_Block *ucbp);
+
+  typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn)
+       (int, _Unwind_Action, _Unwind_Exception_Class,
+       _Unwind_Control_Block *, struct _Unwind_Context *, void *);
+  _Unwind_Reason_Code _Unwind_ForcedUnwind (_Unwind_Control_Block *,
+                                           _Unwind_Stop_Fn, void *);
+  _Unwind_Word _Unwind_GetCFA (struct _Unwind_Context *);
+  void _Unwind_Complete(_Unwind_Control_Block *ucbp);
+  void _Unwind_DeleteException (_Unwind_Exception *);
+
+  _Unwind_Reason_Code __gnu_unwind_frame (_Unwind_Control_Block *,
+                                         _Unwind_Context *);
+  _Unwind_Reason_Code __gnu_unwind_execute (_Unwind_Context *,
+                                           __gnu_unwind_state *);
+
+  /* Decode an R_ARM_TARGET2 relocation.  */
+  static inline _Unwind_Word
+  _Unwind_decode_target2 (_Unwind_Word ptr)
+    {
+      _Unwind_Word tmp;
+
+      tmp = *(_Unwind_Word *) ptr;
+      /* Zero values are always NULL.  */
+      if (!tmp)
+       return 0;
+
+#if defined(linux) || defined(__NetBSD__)
+      /* Pc-relative indirect.  */
+      tmp += ptr;
+      tmp = *(_Unwind_Word *) tmp;
+#elif defined(__symbian__)
+      /* Absolute pointer.  Nothing more to do.  */
+#else
+      /* Pc-relative pointer.  */
+      tmp += ptr;
+#endif
+      return tmp;
+    }
+
+  static inline _Unwind_Word
+  _Unwind_GetGR (_Unwind_Context *context, int regno)
+    {
+      _uw val;
+      _Unwind_VRS_Get (context, _UVRSC_CORE, regno, _UVRSD_UINT32, &val);
+      return val;
+    }
+
+  /* Return the address of the instruction, not the actual IP value.  */
+#define _Unwind_GetIP(context) \
+  (_Unwind_GetGR (context, 15) & ~(_Unwind_Word)1)
+
+  static inline void
+  _Unwind_SetGR (_Unwind_Context *context, int regno, _Unwind_Word val)
+    {
+      _Unwind_VRS_Set (context, _UVRSC_CORE, regno, _UVRSD_UINT32, &val);
+    }
+
+  /* The dwarf unwinder doesn't understand arm/thumb state.  We assume the
+     landing pad uses the same instruction set as the call site.  */
+#define _Unwind_SetIP(context, val) \
+  _Unwind_SetGR (context, 15, val | (_Unwind_GetGR (context, 15) & 1))
+
+typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn)
+     (struct _Unwind_Context *, void *);
+
+extern _Unwind_Reason_Code _Unwind_Backtrace (_Unwind_Trace_Fn, void *);
+
+#ifdef __cplusplus
+}   /* extern "C" */
+#endif
+
+#endif /* defined UNWIND_ARM_H */
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/vfork.S
new file mode 100644 (file)
index 0000000..935a4e9
--- /dev/null
@@ -0,0 +1,39 @@
+/* Copyright (C) 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <tcb-offsets.h>
+
+/* Save the PID value.  */
+#define SAVE_PID \
+       str     lr, [sp, #-4]!;         /* Save LR.  */                 \
+       mov     r0, #0xffff0fff;        /* Point to the high page.  */  \
+       mov     lr, pc;                 /* Save our return address.  */ \
+       sub     pc, r0, #31;            /* Jump to the TLS entry.  */   \
+       ldr     lr, [sp], #4;           /* Restore LR.  */              \
+       mov     r2, r0;                 /* Save the TLS addr in r2.  */ \
+       ldr     r3, [r2, #PID_OFFSET];  /* Load the saved PID.  */      \
+       rsbs    r0, r3, #0;             /* Negate it.  */               \
+       moveq   r0, #0x80000000;        /* Use 0x80000000 if it was 0.  */ \
+       str     r0, [r2, #PID_OFFSET]   /* Store the temporary PID.  */
+
+/* Restore the old PID value in the parent.  */
+#define RESTORE_PID \
+       cmp     r0, #0;                 /* If we are the parent... */   \
+       strne   r3, [r2, #PID_OFFSET]   /* ... restore the saved PID.  */
+
+#include "../../../../../../../libc/sysdeps/linux/arm/vfork.S"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/bits/local_lim.h b/libpthread/nptl/sysdeps/unix/sysv/linux/bits/local_lim.h
new file mode 100644 (file)
index 0000000..8f0df4f
--- /dev/null
@@ -0,0 +1,100 @@
+/* Minimum guaranteed maximum values for system limits.  Linux version.
+   Copyright (C) 1993-1998,2000,2002-2004,2008 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+/* The kernel header pollutes the namespace with the NR_OPEN symbol
+   and defines LINK_MAX although filesystems have different maxima.  A
+   similar thing is true for OPEN_MAX: the limit can be changed at
+   runtime and therefore the macro must not be defined.  Remove this
+   after including the header if necessary.  */
+#ifndef NR_OPEN
+# define __undef_NR_OPEN
+#endif
+#ifndef LINK_MAX
+# define __undef_LINK_MAX
+#endif
+#ifndef OPEN_MAX
+# define __undef_OPEN_MAX
+#endif
+#ifndef ARG_MAX
+# define __undef_ARG_MAX
+#endif
+
+/* The kernel sources contain a file with all the needed information.  */
+#include <linux/limits.h>
+
+/* Have to remove NR_OPEN?  */
+#ifdef __undef_NR_OPEN
+# undef NR_OPEN
+# undef __undef_NR_OPEN
+#endif
+/* Have to remove LINK_MAX?  */
+#ifdef __undef_LINK_MAX
+# undef LINK_MAX
+# undef __undef_LINK_MAX
+#endif
+/* Have to remove OPEN_MAX?  */
+#ifdef __undef_OPEN_MAX
+# undef OPEN_MAX
+# undef __undef_OPEN_MAX
+#endif
+/* Have to remove ARG_MAX?  */
+#ifdef __undef_ARG_MAX
+# undef ARG_MAX
+# undef __undef_ARG_MAX
+#endif
+
+/* The number of data keys per process.  */
+#define _POSIX_THREAD_KEYS_MAX 128
+/* This is the value this implementation supports.  */
+#define PTHREAD_KEYS_MAX       1024
+
+/* Controlling the iterations of destructors for thread-specific data.  */
+#define _POSIX_THREAD_DESTRUCTOR_ITERATIONS    4
+/* Number of iterations this implementation does.  */
+#define PTHREAD_DESTRUCTOR_ITERATIONS  _POSIX_THREAD_DESTRUCTOR_ITERATIONS
+
+/* The number of threads per process.  */
+#define _POSIX_THREAD_THREADS_MAX      64
+/* We have no predefined limit on the number of threads.  */
+#undef PTHREAD_THREADS_MAX
+
+/* Maximum amount by which a process can descrease its asynchronous I/O
+   priority level.  */
+#define AIO_PRIO_DELTA_MAX     20
+
+/* Minimum size for a thread.  We are free to choose a reasonable value.  */
+#define PTHREAD_STACK_MIN      16384
+
+/* Maximum number of timer expiration overruns.  */
+#define DELAYTIMER_MAX 2147483647
+
+/* Maximum tty name length.  */
+#define TTY_NAME_MAX           32
+
+/* Maximum login name length.  This is arbitrary.  */
+#define LOGIN_NAME_MAX         256
+
+/* Maximum host name length.  */
+#define HOST_NAME_MAX          64
+
+/* Maximum message queue priority level.  */
+#define MQ_PRIO_MAX            32768
+
+/* Maximum value the semaphore can have.  */
+#define SEM_VALUE_MAX   (2147483647)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/bits/posix_opt.h b/libpthread/nptl/sysdeps/unix/sysv/linux/bits/posix_opt.h
new file mode 100644 (file)
index 0000000..2550355
--- /dev/null
@@ -0,0 +1,192 @@
+/* Define POSIX options for Linux.
+   Copyright (C) 1996-2004, 2006, 2008, 2009 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef        _BITS_POSIX_OPT_H
+#define        _BITS_POSIX_OPT_H       1
+
+/* Job control is supported.  */
+#define        _POSIX_JOB_CONTROL      1
+
+/* Processes have a saved set-user-ID and a saved set-group-ID.  */
+#define        _POSIX_SAVED_IDS        1
+
+/* Priority scheduling is supported.  */
+#define        _POSIX_PRIORITY_SCHEDULING      200809L
+
+/* Synchronizing file data is supported.  */
+#define        _POSIX_SYNCHRONIZED_IO  200809L
+
+/* The fsync function is present.  */
+#define        _POSIX_FSYNC    200809L
+
+/* Mapping of files to memory is supported.  */
+#define        _POSIX_MAPPED_FILES     200809L
+
+/* Locking of all memory is supported.  */
+#define        _POSIX_MEMLOCK  200809L
+
+/* Locking of ranges of memory is supported.  */
+#define        _POSIX_MEMLOCK_RANGE    200809L
+
+/* Setting of memory protections is supported.  */
+#define        _POSIX_MEMORY_PROTECTION        200809L
+
+/* Some filesystems allow all users to change file ownership.  */
+#define        _POSIX_CHOWN_RESTRICTED 0
+
+/* `c_cc' member of 'struct termios' structure can be disabled by
+   using the value _POSIX_VDISABLE.  */
+#define        _POSIX_VDISABLE '\0'
+
+/* Filenames are not silently truncated.  */
+#define        _POSIX_NO_TRUNC 1
+
+/* X/Open realtime support is available.  */
+#define _XOPEN_REALTIME        1
+
+/* X/Open thread realtime support is available.  */
+#define _XOPEN_REALTIME_THREADS        1
+
+/* XPG4.2 shared memory is supported.  */
+#define        _XOPEN_SHM      1
+
+/* Tell we have POSIX threads.  */
+#define _POSIX_THREADS 200809L
+
+/* We have the reentrant functions described in POSIX.  */
+#define _POSIX_REENTRANT_FUNCTIONS      1
+#define _POSIX_THREAD_SAFE_FUNCTIONS   200809L
+
+/* We provide priority scheduling for threads.  */
+#define _POSIX_THREAD_PRIORITY_SCHEDULING      200809L
+
+/* We support user-defined stack sizes.  */
+#define _POSIX_THREAD_ATTR_STACKSIZE   200809L
+
+/* We support user-defined stacks.  */
+#define _POSIX_THREAD_ATTR_STACKADDR   200809L
+
+/* We support priority inheritence.  */
+#define _POSIX_THREAD_PRIO_INHERIT     200809L
+
+/* We support priority protection, though only for non-robust
+   mutexes.  */
+#define _POSIX_THREAD_PRIO_PROTECT     200809L
+
+#ifdef __USE_XOPEN2K8
+/* We support priority inheritence for robust mutexes.  */
+# define _POSIX_THREAD_ROBUST_PRIO_INHERIT     200809L
+
+/* We do not support priority protection for robust mutexes.  */
+# define _POSIX_THREAD_ROBUST_PRIO_PROTECT     -1
+#endif
+
+/* We support POSIX.1b semaphores.  */
+#define _POSIX_SEMAPHORES      200809L
+
+/* Real-time signals are supported.  */
+#define _POSIX_REALTIME_SIGNALS        200809L
+
+/* We support asynchronous I/O.  */
+#define _POSIX_ASYNCHRONOUS_IO 200809L
+#define _POSIX_ASYNC_IO                1
+/* Alternative name for Unix98.  */
+#define _LFS_ASYNCHRONOUS_IO   1
+/* Support for prioritization is also available.  */
+#define _POSIX_PRIORITIZED_IO  200809L
+
+/* The LFS support in asynchronous I/O is also available.  */
+#define _LFS64_ASYNCHRONOUS_IO 1
+
+/* The rest of the LFS is also available.  */
+#define _LFS_LARGEFILE         1
+#define _LFS64_LARGEFILE       1
+#define _LFS64_STDIO           1
+
+/* POSIX shared memory objects are implemented.  */
+#define _POSIX_SHARED_MEMORY_OBJECTS   200809L
+
+/* CPU-time clocks support needs to be checked at runtime.  */
+#define _POSIX_CPUTIME 0
+
+/* Clock support in threads must be also checked at runtime.  */
+#define _POSIX_THREAD_CPUTIME  0
+
+/* GNU libc provides regular expression handling.  */
+#define _POSIX_REGEXP  1
+
+/* Reader/Writer locks are available.  */
+#define _POSIX_READER_WRITER_LOCKS     200809L
+
+/* We have a POSIX shell.  */
+#define _POSIX_SHELL   1
+
+/* We support the Timeouts option.  */
+#define _POSIX_TIMEOUTS        200809L
+
+/* We support spinlocks.  */
+#define _POSIX_SPIN_LOCKS      200809L
+
+/* The `spawn' function family is supported.  */
+#define _POSIX_SPAWN   200809L
+
+/* We have POSIX timers.  */
+#define _POSIX_TIMERS  200809L
+
+/* The barrier functions are available.  */
+#define _POSIX_BARRIERS        200809L
+
+/* POSIX message queues are available.  */
+#define        _POSIX_MESSAGE_PASSING  200809L
+
+/* Thread process-shared synchronization is supported.  */
+#define _POSIX_THREAD_PROCESS_SHARED   200809L
+
+/* The monotonic clock might be available.  */
+#define _POSIX_MONOTONIC_CLOCK 0
+
+/* The clock selection interfaces are available.  */
+#define _POSIX_CLOCK_SELECTION 200809L
+
+/* Advisory information interfaces are available.  */
+#define _POSIX_ADVISORY_INFO   200809L
+
+/* IPv6 support is available.  */
+#define _POSIX_IPV6    200809L
+
+/* Raw socket support is available.  */
+#define _POSIX_RAW_SOCKETS     200809L
+
+/* We have at least one terminal.  */
+#define _POSIX2_CHAR_TERM      200809L
+
+/* Neither process nor thread sporadic server interfaces is available.  */
+#define _POSIX_SPORADIC_SERVER -1
+#define _POSIX_THREAD_SPORADIC_SERVER  -1
+
+/* trace.h is not available.  */
+#define _POSIX_TRACE   -1
+#define _POSIX_TRACE_EVENT_FILTER      -1
+#define _POSIX_TRACE_INHERIT   -1
+#define _POSIX_TRACE_LOG       -1
+
+/* Typed memory objects are not available.  */
+#define _POSIX_TYPED_MEMORY_OBJECTS    -1
+
+#endif /* bits/posix_opt.h */
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/close.S b/libpthread/nptl/sysdeps/unix/sysv/linux/close.S
new file mode 100644 (file)
index 0000000..cf50a1e
--- /dev/null
@@ -0,0 +1,21 @@
+#include <sysdep-cancel.h>
+
+/*
+extern int __close_nocancel (int) attribute_hidden;
+*/
+#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt
+
+
+PSEUDO (__libc_close, close, 1)
+ret
+PSEUDO_END(__libc_close)
+
+libc_hidden_def (__close_nocancel)
+libc_hidden_def (__libc_close)
+weak_alias (__libc_close, __close)
+libc_hidden_weak (__close)
+weak_alias (__libc_close, close)
+libc_hidden_weak (close)
+
+
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/connect.S b/libpthread/nptl/sysdeps/unix/sysv/linux/connect.S
new file mode 100644 (file)
index 0000000..441843f
--- /dev/null
@@ -0,0 +1,12 @@
+#include <sysdep-cancel.h>
+#ifndef __NR_connect
+#error Missing definition of NR_connect needed for cancellation.
+#endif
+PSEUDO (__libc_connect, connect, 3)
+ret
+PSEUDO_END(__libc_connect)
+libc_hidden_def (__libc_connect)
+weak_alias (__libc_connect, __connect)
+libc_hidden_weak (__connect)
+weak_alias (__libc_connect, connect)
+libc_hidden_weak (connect)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/creat.S b/libpthread/nptl/sysdeps/unix/sysv/linux/creat.S
new file mode 100644 (file)
index 0000000..cd0e1b8
--- /dev/null
@@ -0,0 +1,7 @@
+#include <sysdep-cancel.h>
+PSEUDO (__libc_creat, creat, 2)
+ret
+PSEUDO_END(__libc_creat)
+libc_hidden_def (__libc_creat)
+weak_alias (__libc_creat, creat)
+libc_hidden_weak (creat)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/createthread.c b/libpthread/nptl/sysdeps/unix/sysv/linux/createthread.c
new file mode 100644 (file)
index 0000000..9149efe
--- /dev/null
@@ -0,0 +1,24 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* Value passed to 'clone' for initialization of the thread register.  */
+#define TLS_VALUE pd
+
+/* Get the real implementation.         */
+#include <sysdeps/pthread/createthread.c>
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/exit-thread.S b/libpthread/nptl/sysdeps/unix/sysv/linux/exit-thread.S
new file mode 100644 (file)
index 0000000..bb996fe
--- /dev/null
@@ -0,0 +1,23 @@
+/* Copyright (C) 1991,92,97,99,2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+
+PSEUDO (__exit_thread, exit, 1)
+       /* Shouldn't get here.  */
+PSEUDO_END(__exit_thread)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/fork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/fork.c
new file mode 100644 (file)
index 0000000..2d4cae2
--- /dev/null
@@ -0,0 +1,229 @@
+/* Copyright (C) 2002, 2003, 2007, 2008 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sysdep.h>
+#include <tls.h>
+#include "fork.h"
+#include <hp-timing.h>
+#include <ldsodefs.h>
+#include <atomic.h>
+#include <errno.h>
+
+unsigned long int *__fork_generation_pointer;
+
+
+
+/* The single linked list of all currently registered for handlers.  */
+struct fork_handler *__fork_handlers;
+
+
+static void
+fresetlockfiles (void)
+{
+  FILE *fp;
+#ifdef __USE_STDIO_FUTEXES__
+  for (fp = _stdio_openlist; fp != NULL; fp = fp->__nextopen)
+    STDIO_INIT_MUTEX(fp->__lock);
+#else
+  pthread_mutexattr_t attr;
+
+  pthread_mutexattr_init(&attr);
+  pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP);
+
+  for (fp = _stdio_openlist; fp != NULL; fp = fp->__nextopen)
+    pthread_mutex_init(&fp->__lock, &attr);
+
+  pthread_mutexattr_destroy(&attr);
+#endif
+}
+
+
+pid_t
+__libc_fork (void)
+{
+  pid_t pid;
+  struct used_handler
+  {
+    struct fork_handler *handler;
+    struct used_handler *next;
+  } *allp = NULL;
+
+  /* Run all the registered preparation handlers.  In reverse order.
+     While doing this we build up a list of all the entries.  */
+  struct fork_handler *runp;
+  while ((runp = __fork_handlers) != NULL)
+    {
+      /* Make sure we read from the current RUNP pointer.  */
+      atomic_full_barrier ();
+
+      unsigned int oldval = runp->refcntr;
+
+      if (oldval == 0)
+       /* This means some other thread removed the list just after
+          the pointer has been loaded.  Try again.  Either the list
+          is empty or we can retry it.  */
+       continue;
+
+      /* Bump the reference counter.  */
+      if (atomic_compare_and_exchange_bool_acq (&__fork_handlers->refcntr,
+                                               oldval + 1, oldval))
+       /* The value changed, try again.  */
+       continue;
+
+      /* We bumped the reference counter for the first entry in the
+        list.  That means that none of the following entries will
+        just go away.  The unloading code works in the order of the
+        list.
+
+         While executing the registered handlers we are building a
+         list of all the entries so that we can go backward later on.  */
+      while (1)
+       {
+         /* Execute the handler if there is one.  */
+         if (runp->prepare_handler != NULL)
+           runp->prepare_handler ();
+
+         /* Create a new element for the list.  */
+         struct used_handler *newp
+           = (struct used_handler *) alloca (sizeof (*newp));
+         newp->handler = runp;
+         newp->next = allp;
+         allp = newp;
+
+         /* Advance to the next handler.  */
+         runp = runp->next;
+         if (runp == NULL)
+           break;
+
+         /* Bump the reference counter for the next entry.  */
+         atomic_increment (&runp->refcntr);
+       }
+
+      /* We are done.  */
+      break;
+    }
+
+  __UCLIBC_IO_MUTEX_LOCK_CANCEL_UNSAFE(_stdio_openlist_add_lock);
+
+#ifndef NDEBUG
+  pid_t ppid = THREAD_GETMEM (THREAD_SELF, tid);
+#endif
+
+  /* We need to prevent the getpid() code to update the PID field so
+     that, if a signal arrives in the child very early and the signal
+     handler uses getpid(), the value returned is correct.  */
+  pid_t parentpid = THREAD_GETMEM (THREAD_SELF, pid);
+  THREAD_SETMEM (THREAD_SELF, pid, -parentpid);
+
+#ifdef ARCH_FORK
+  pid = ARCH_FORK ();
+#else
+# error "ARCH_FORK must be defined so that the CLONE_SETTID flag is used"
+  pid = INLINE_SYSCALL (fork, 0);
+#endif
+
+
+  if (pid == 0)
+    {
+      struct pthread *self = THREAD_SELF;
+
+      assert (THREAD_GETMEM (self, tid) != ppid);
+
+      if (__fork_generation_pointer != NULL)
+       *__fork_generation_pointer += 4;
+
+      /* Adjust the PID field for the new process.  */
+      THREAD_SETMEM (self, pid, THREAD_GETMEM (self, tid));
+
+#if HP_TIMING_AVAIL
+      /* The CPU clock of the thread and process have to be set to zero.  */
+      hp_timing_t now;
+      HP_TIMING_NOW (now);
+      THREAD_SETMEM (self, cpuclock_offset, now);
+      GL(dl_cpuclock_offset) = now;
+#endif
+
+      /* Reset the file list.  These are recursive mutexes.  */
+      fresetlockfiles ();
+
+      /* Reset locks in the I/O code.  */
+      STDIO_INIT_MUTEX(_stdio_openlist_add_lock);
+
+      /* XXX reset any locks in dynamic loader */
+
+      /* Run the handlers registered for the child.  */
+      while (allp != NULL)
+       {
+         if (allp->handler->child_handler != NULL)
+           allp->handler->child_handler ();
+
+         /* Note that we do not have to wake any possible waiter.
+            This is the only thread in the new process.  The count
+            may have been bumped up by other threads doing a fork.
+            We reset it to 1, to avoid waiting for non-existing
+            thread(s) to release the count.  */
+         allp->handler->refcntr = 1;
+
+         /* XXX We could at this point look through the object pool
+            and mark all objects not on the __fork_handlers list as
+            unused.  This is necessary in case the fork() happened
+            while another thread called dlclose() and that call had
+            to create a new list.  */
+
+         allp = allp->next;
+       }
+
+      /* Initialize the fork lock.  */
+      __fork_lock = LLL_LOCK_INITIALIZER;
+    }
+  else
+    {
+      assert (THREAD_GETMEM (THREAD_SELF, tid) == ppid);
+
+      /* Restore the PID value.  */
+      THREAD_SETMEM (THREAD_SELF, pid, parentpid);
+
+      /* We execute this even if the 'fork' call failed.  */
+      __UCLIBC_IO_MUTEX_UNLOCK_CANCEL_UNSAFE(_stdio_openlist_add_lock);
+
+      /* Run the handlers registered for the parent.  */
+      while (allp != NULL)
+       {
+         if (allp->handler->parent_handler != NULL)
+           allp->handler->parent_handler ();
+
+         if (atomic_decrement_and_test (&allp->handler->refcntr)
+             && allp->handler->need_signal)
+           lll_futex_wake (allp->handler->refcntr, 1, LLL_PRIVATE);
+
+         allp = allp->next;
+       }
+    }
+
+  return pid;
+}
+weak_alias(__libc_fork,__fork)
+libc_hidden_proto(fork)
+weak_alias(__libc_fork,fork)
+libc_hidden_weak(fork)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/fork.h b/libpthread/nptl/sysdeps/unix/sysv/linux/fork.h
new file mode 100644 (file)
index 0000000..a00cfab
--- /dev/null
@@ -0,0 +1,60 @@
+/* Copyright (C) 2002, 2003, 2006, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <lowlevellock.h>
+
+/* The fork generation counter, defined in libpthread.  */
+extern unsigned long int __fork_generation attribute_hidden;
+
+/* Pointer to the fork generation counter in the thread library.  */
+extern unsigned long int *__fork_generation_pointer attribute_hidden;
+
+/* Lock to protect allocation and deallocation of fork handlers.  */
+extern int __fork_lock attribute_hidden;
+
+/* Elements of the fork handler lists.  */
+struct fork_handler
+{
+  struct fork_handler *next;
+  void (*prepare_handler) (void);
+  void (*parent_handler) (void);
+  void (*child_handler) (void);
+  void *dso_handle;
+  unsigned int refcntr;
+  int need_signal;
+};
+
+/* The single linked list of all currently registered for handlers.  */
+extern struct fork_handler *__fork_handlers attribute_hidden;
+
+
+/* Function to call to unregister fork handlers.  */
+extern void __unregister_atfork (void *dso_handle) attribute_hidden;
+#define UNREGISTER_ATFORK(dso_handle) __unregister_atfork (dso_handle)
+
+
+/* C library side function to register new fork handlers.  */
+extern int __register_atfork (void (*__prepare) (void),
+                             void (*__parent) (void),
+                             void (*__child) (void),
+                             void *dso_handle);
+libc_hidden_proto (__register_atfork)
+
+/* Add a new element to the fork list.  */
+extern void __linkin_atfork (struct fork_handler *newp) attribute_hidden;
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/getpid.c b/libpthread/nptl/sysdeps/unix/sysv/linux/getpid.c
new file mode 100644 (file)
index 0000000..96e2bf4
--- /dev/null
@@ -0,0 +1,64 @@
+/* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <unistd.h>
+#include <tls.h>
+#include <sysdep.h>
+
+
+#ifndef NOT_IN_libc
+static inline __attribute__((always_inline)) pid_t really_getpid (pid_t oldval);
+
+static inline __attribute__((always_inline)) pid_t
+really_getpid (pid_t oldval)
+{
+  if (__builtin_expect (oldval == 0, 1))
+    {
+      pid_t selftid = THREAD_GETMEM (THREAD_SELF, tid);
+      if (__builtin_expect (selftid != 0, 1))
+       return selftid;
+    }
+
+  INTERNAL_SYSCALL_DECL (err);
+  pid_t result = INTERNAL_SYSCALL (getpid, err, 0);
+
+  /* We do not set the PID field in the TID here since we might be
+     called from a signal handler while the thread executes fork.  */
+  if (oldval == 0)
+    THREAD_SETMEM (THREAD_SELF, tid, result);
+  return result;
+}
+#endif
+
+pid_t
+__getpid (void)
+{
+#ifdef NOT_IN_libc
+  INTERNAL_SYSCALL_DECL (err);
+  pid_t result = INTERNAL_SYSCALL (getpid, err, 0);
+#else
+  pid_t result = THREAD_GETMEM (THREAD_SELF, pid);
+  if (__builtin_expect (result <= 0, 0))
+    result = really_getpid (result);
+#endif
+  return result;
+}
+libc_hidden_proto(getpid)
+weak_alias(__getpid, getpid)
+libc_hidden_weak(getpid)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/Makefile b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/Makefile
new file mode 100644 (file)
index 0000000..43a6fad
--- /dev/null
@@ -0,0 +1,13 @@
+# Makefile for uClibc NPTL
+#
+# Copyright (C) 2005 Steven J. Hill <sjhill@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+top_srcdir=../../../../../../../
+top_builddir=../../../../../../../
+all: objs
+include $(top_builddir)Rules.mak
+include Makefile.arch
+include $(top_srcdir)Makerules
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/Makefile.arch b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/Makefile.arch
new file mode 100644 (file)
index 0000000..570aa56
--- /dev/null
@@ -0,0 +1,71 @@
+# Makefile for uClibc NPTL
+#
+# Copyright (C) 2006 Steven J. Hill <sjhill@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+LINUX_ARCH_DIR:=$(top_srcdir)libpthread/nptl/sysdeps/unix/sysv/linux/i386
+LINUX_ARCH_OUT:=$(top_builddir)libpthread/nptl/sysdeps/unix/sysv/linux/i386
+
+ASFLAGS += -DUSE___THREAD
+
+libpthread_SSRC = pt-vfork.S clone.S pthread_spin_unlock.S pthread_once.S
+libpthread_CSRC = pthread_spin_init.c pt-__syscall_error.c
+
+libc_a_CSRC = fork.c
+libc_a_SSRC = clone.S vfork.S
+
+libpthread_SSRC += i486/lowlevellock.S i486/pthread_barrier_wait.S i486/pthread_cond_signal.S i486/pthread_cond_broadcast.S \
+                  i486/lowlevelrobustlock.S i486/sem_post.S i486/sem_timedwait.S \
+                  i486/sem_trywait.S i486/sem_wait.S i486/pthread_rwlock_rdlock.S i486/pthread_rwlock_wrlock.S \
+                  i486/pthread_rwlock_timedrdlock.S i486/pthread_rwlock_timedwrlock.S i486/pthread_rwlock_unlock.S
+#i486/pthread_cond_timedwait.S i486/pthread_cond_wait.S
+
+libc_a_SSRC += i486/libc-lowlevellock.S
+
+
+CFLAGS-OMIT-fork.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1
+CFLAGS-pt-__syscall_error.c =  -DNOT_IN_libc=1 -DIS_IN_libpthread=1
+
+ifeq ($(UCLIBC_HAS_STDIO_FUTEXES),y)
+CFLAGS-fork.c = -D__USE_STDIO_FUTEXES__
+endif
+
+ASFLAGS-pt-vfork.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 -D_LIBC_REENTRANT
+ASFLAGS-lowlevellock.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 -D_LIBC_REENTRANT
+ASFLAGS-lowlevelrobustlock.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 -D_LIBC_REENTRANT
+ASFLAGS-pthread_once.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 -D_LIBC_REENTRANT
+ASFLAGS-pthread_spin_unlock.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 -D_LIBC_REENTRANT
+
+
+ASFLAGS-clone.S = -D_LIBC_REENTRANT
+ASFLAGS-vfork.S = -D_LIBC_REENTRANT
+ASFLAGS-libc-lowlevellock.S = -D_LIBC_REENTRANT
+
+CFLAGS += $(SSP_ALL_CFLAGS)
+#CFLAGS:=$(CFLAGS:-O1=-O2)
+
+LINUX_ARCH_OBJ:=$(patsubst %.S,$(LINUX_ARCH_OUT)/%.o,$(libpthread_SSRC))
+LINUX_ARCH_OBJ+=$(patsubst %.c,$(LINUX_ARCH_OUT)/%.o,$(libpthread_CSRC))
+
+ifeq ($(DOPIC),y)
+libpthread-a-y += $(LINUX_ARCH_OBJ:.o=.os)
+else
+libpthread-a-y += $(LINUX_ARCH_OBJ)
+endif
+libpthread-so-y += $(LINUX_ARCH_OBJ:.o=.oS)
+
+libpthread-nomulti-y+=$(LINUX_ARCH_OBJS)
+
+LIBC_LINUX_ARCH_OBJ:=$(patsubst %.c,$(LINUX_ARCH_OUT)/%.o,$(libc_a_CSRC))
+LIBC_LINUX_ARCH_OBJ+=$(patsubst %.S,$(LINUX_ARCH_OUT)/%.o,$(libc_a_SSRC))
+
+libc-static-y+=$(LIBC_LINUX_ARCH_OBJ)
+libc-shared-y+=$(LIBC_LINUX_ARCH_OBJ:.o=.oS)
+
+libc-nomulti-y+=$(LIBC_LINUX_ARCH_OBJ)
+
+objclean-y+=nptl_linux_arch_clean
+
+nptl_linux_arch_clean:
+       $(do_rm) $(addprefix $(LINUX_ARCH_OUT)/*., o os oS)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h
new file mode 100644 (file)
index 0000000..9e3e016
--- /dev/null
@@ -0,0 +1,173 @@
+/* Copyright (C) 2002,2003,2004,2005,2006,2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _BITS_PTHREADTYPES_H
+#define _BITS_PTHREADTYPES_H   1
+
+#define __SIZEOF_PTHREAD_ATTR_T 36
+#define __SIZEOF_PTHREAD_MUTEX_T 24
+#define __SIZEOF_PTHREAD_MUTEXATTR_T 4
+#define __SIZEOF_PTHREAD_COND_T 48
+#define __SIZEOF_PTHREAD_COND_COMPAT_T 12
+#define __SIZEOF_PTHREAD_CONDATTR_T 4
+#define __SIZEOF_PTHREAD_RWLOCK_T 32
+#define __SIZEOF_PTHREAD_RWLOCKATTR_T 8
+#define __SIZEOF_PTHREAD_BARRIER_T 20
+#define __SIZEOF_PTHREAD_BARRIERATTR_T 4
+
+
+/* Thread identifiers.  The structure of the attribute type is not
+   exposed on purpose.  */
+typedef unsigned long int pthread_t;
+
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_ATTR_T];
+  long int __align;
+} pthread_attr_t;
+
+
+typedef struct __pthread_internal_slist
+{
+  struct __pthread_internal_slist *__next;
+} __pthread_slist_t;
+
+
+/* Data structures for mutex handling.  The structure of the attribute
+   type is not exposed on purpose.  */
+typedef union
+{
+  struct __pthread_mutex_s
+  {
+    int __lock;
+    unsigned int __count;
+    int __owner;
+    /* KIND must stay at this position in the structure to maintain
+       binary compatibility.  */
+    int __kind;
+    unsigned int __nusers;
+    __extension__ union
+    {
+      int __spins;
+      __pthread_slist_t __list;
+    };
+  } __data;
+  char __size[__SIZEOF_PTHREAD_MUTEX_T];
+  long int __align;
+} pthread_mutex_t;
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_MUTEXATTR_T];
+  long int __align;
+} pthread_mutexattr_t;
+
+
+/* Data structure for conditional variable handling.  The structure of
+   the attribute type is not exposed on purpose.  */
+typedef union
+{
+  struct
+  {
+    int __lock;
+    unsigned int __futex;
+    __extension__ unsigned long long int __total_seq;
+    __extension__ unsigned long long int __wakeup_seq;
+    __extension__ unsigned long long int __woken_seq;
+    void *__mutex;
+    unsigned int __nwaiters;
+    unsigned int __broadcast_seq;
+  } __data;
+  char __size[__SIZEOF_PTHREAD_COND_T];
+  __extension__ long long int __align;
+} pthread_cond_t;
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_CONDATTR_T];
+  long int __align;
+} pthread_condattr_t;
+
+
+/* Keys for thread-specific data */
+typedef unsigned int pthread_key_t;
+
+
+/* Once-only execution */
+typedef int pthread_once_t;
+
+
+#if defined __USE_UNIX98 || defined __USE_XOPEN2K
+/* Data structure for read-write lock variable handling.  The
+   structure of the attribute type is not exposed on purpose.  */
+typedef union
+{
+  struct
+  {
+    int __lock;
+    unsigned int __nr_readers;
+    unsigned int __readers_wakeup;
+    unsigned int __writer_wakeup;
+    unsigned int __nr_readers_queued;
+    unsigned int __nr_writers_queued;
+    /* FLAGS must stay at this position in the structure to maintain
+       binary compatibility.  */
+    unsigned char __flags;
+    unsigned char __shared;
+    unsigned char __pad1;
+    unsigned char __pad2;
+    int __writer;
+  } __data;
+  char __size[__SIZEOF_PTHREAD_RWLOCK_T];
+  long int __align;
+} pthread_rwlock_t;
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_RWLOCKATTR_T];
+  long int __align;
+} pthread_rwlockattr_t;
+#endif
+
+
+#ifdef __USE_XOPEN2K
+/* POSIX spinlock data type.  */
+typedef volatile int pthread_spinlock_t;
+
+
+/* POSIX barriers data type.  The structure of the type is
+   deliberately not exposed.  */
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_BARRIER_T];
+  long int __align;
+} pthread_barrier_t;
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_BARRIERATTR_T];
+  int __align;
+} pthread_barrierattr_t;
+#endif
+
+
+/* Extra attributes for the cleanup functions.  */
+#define __cleanup_fct_attribute __attribute__ ((__regparm__ (1)))
+
+#endif /* bits/pthreadtypes.h */
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/bits/semaphore.h b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/bits/semaphore.h
new file mode 100644 (file)
index 0000000..934493c
--- /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 _SEMAPHORE_H
+# error "Never use <bits/semaphore.h> directly; include <semaphore.h> instead."
+#endif
+
+
+#define __SIZEOF_SEM_T 16
+
+
+/* Value returned if `sem_open' failed.  */
+#define SEM_FAILED      ((sem_t *) 0)
+
+
+typedef union
+{
+  char __size[__SIZEOF_SEM_T];
+  long int __align;
+} sem_t;
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/clone.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/clone.S
new file mode 100644 (file)
index 0000000..9c7c464
--- /dev/null
@@ -0,0 +1,2 @@
+#define RESET_PID
+#include <libc/sysdeps/linux/i386/clone.S>
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/createthread.c b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/createthread.c
new file mode 100644 (file)
index 0000000..35719be
--- /dev/null
@@ -0,0 +1,49 @@
+/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* The "thread register" gets initialized from a segment descriptor.
+   Initialize such a descriptor first.  */
+#define PREPARE_CREATE \
+  union user_desc_init desc;                                                 \
+                                                                             \
+  /* Describe the thread-local storage segment.  */                          \
+                                                                             \
+  /* The 'entry_number' field.  The first three bits of the segment          \
+     register value select the GDT, ignore them.  We get the index           \
+     from the value of the %gs register in the current thread.  */           \
+  desc.vals[0] = TLS_GET_GS () >> 3;                                         \
+  /* The 'base_addr' field.  Pointer to the TCB.  */                         \
+  desc.vals[1] = (unsigned long int) pd;                                     \
+  /* The 'limit' field.  We use 4GB which is 0xfffff pages.  */                      \
+  desc.vals[2] = 0xfffff;                                                    \
+  /* Collapsed value of the bitfield:                                        \
+       .seg_32bit = 1                                                        \
+       .contents = 0                                                         \
+       .read_exec_only = 0                                                   \
+       .limit_in_pages = 1                                                   \
+       .seg_not_present = 0                                                  \
+       .useable = 1 */                                                       \
+  desc.vals[3] = 0x51
+
+/* Value passed to 'clone' for initialization of the thread register.  */
+#define TLS_VALUE &desc.desc
+
+
+/* Get the real implementation.  */
+#include <sysdeps/pthread/createthread.c>
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/fork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/fork.c
new file mode 100644 (file)
index 0000000..813e529
--- /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 <sched.h>
+#include <signal.h>
+#include <sysdep.h>
+#include <tls.h>
+
+
+#define ARCH_FORK() \
+  INLINE_SYSCALL (clone, 5,                                                  \
+                 CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD, 0,     \
+                 NULL, NULL, &THREAD_SELF->tid)
+
+#include "../fork.c"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S
new file mode 100644 (file)
index 0000000..ce8ad27
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright (C) 2002, 2003, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "lowlevellock.S"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S
new file mode 100644 (file)
index 0000000..00f8b56
--- /dev/null
@@ -0,0 +1,459 @@
+/* Copyright (C) 2002-2004, 2006, 2007, 2009 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <pthread-errnos.h>
+#include <bits/kernel-features.h>
+#include <lowlevellock.h>
+#include <tcb-offsets.h>
+
+       .text
+
+#ifdef __ASSUME_PRIVATE_FUTEX
+# define LOAD_PRIVATE_FUTEX_WAIT(reg) \
+       movl    $(FUTEX_WAIT | FUTEX_PRIVATE_FLAG), reg
+# define LOAD_PRIVATE_FUTEX_WAKE(reg) \
+       movl    $(FUTEX_WAKE | FUTEX_PRIVATE_FLAG), reg
+# define LOAD_FUTEX_WAIT(reg) \
+       xorl    $(FUTEX_WAIT | FUTEX_PRIVATE_FLAG), reg
+# define LOAD_FUTEX_WAIT_ABS(reg) \
+       xorl    $(FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME), reg
+# define LOAD_FUTEX_WAKE(reg) \
+       xorl    $(FUTEX_WAKE | FUTEX_PRIVATE_FLAG), reg
+#else
+# if FUTEX_WAIT == 0
+#  define LOAD_PRIVATE_FUTEX_WAIT(reg) \
+       movl    %gs:PRIVATE_FUTEX, reg
+# else
+#  define LOAD_PRIVATE_FUTEX_WAIT(reg) \
+       movl    %gs:PRIVATE_FUTEX, reg ; \
+       orl     $FUTEX_WAIT, reg
+# endif
+# define LOAD_PRIVATE_FUTEX_WAKE(reg) \
+       movl    %gs:PRIVATE_FUTEX, reg ; \
+       orl     $FUTEX_WAKE, reg
+# if FUTEX_WAIT == 0
+#  define LOAD_FUTEX_WAIT(reg) \
+       xorl    $FUTEX_PRIVATE_FLAG, reg ; \
+       andl    %gs:PRIVATE_FUTEX, reg
+# else
+#  define LOAD_FUTEX_WAIT(reg) \
+       xorl    $FUTEX_PRIVATE_FLAG, reg ; \
+       andl    %gs:PRIVATE_FUTEX, reg ; \
+       orl     $FUTEX_WAIT, reg
+# endif
+# define LOAD_FUTEX_WAIT_ABS(reg) \
+       xorl    $FUTEX_PRIVATE_FLAG, reg ; \
+       andl    %gs:PRIVATE_FUTEX, reg ; \
+       orl     $FUTEX_WAIT_BITSET | FUTEX_CLOCK_REALTIME, reg
+# define LOAD_FUTEX_WAKE(reg) \
+       xorl    $FUTEX_PRIVATE_FLAG, reg ; \
+       andl    %gs:PRIVATE_FUTEX, reg ; \
+       orl     $FUTEX_WAKE, reg
+#endif
+
+       .globl  __lll_lock_wait_private
+       .type   __lll_lock_wait_private,@function
+       .hidden __lll_lock_wait_private
+       .align  16
+__lll_lock_wait_private:
+       cfi_startproc
+       pushl   %edx
+       cfi_adjust_cfa_offset(4)
+       pushl   %ebx
+       cfi_adjust_cfa_offset(4)
+       pushl   %esi
+       cfi_adjust_cfa_offset(4)
+       cfi_offset(%edx, -8)
+       cfi_offset(%ebx, -12)
+       cfi_offset(%esi, -16)
+
+       movl    $2, %edx
+       movl    %ecx, %ebx
+       xorl    %esi, %esi      /* No timeout.  */
+       LOAD_PRIVATE_FUTEX_WAIT (%ecx)
+
+       cmpl    %edx, %eax      /* NB:   %edx == 2 */
+       jne 2f
+
+1:     movl    $SYS_futex, %eax
+       ENTER_KERNEL
+
+2:     movl    %edx, %eax
+       xchgl   %eax, (%ebx)    /* NB:   lock is implied */
+
+       testl   %eax, %eax
+       jnz     1b
+
+       popl    %esi
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%esi)
+       popl    %ebx
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%ebx)
+       popl    %edx
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%edx)
+       ret
+       cfi_endproc
+       .size   __lll_lock_wait_private,.-__lll_lock_wait_private
+
+#ifdef NOT_IN_libc
+       .globl  __lll_lock_wait
+       .type   __lll_lock_wait,@function
+       .hidden __lll_lock_wait
+       .align  16
+__lll_lock_wait:
+       cfi_startproc
+       pushl   %edx
+       cfi_adjust_cfa_offset(4)
+       pushl   %ebx
+       cfi_adjust_cfa_offset(4)
+       pushl   %esi
+       cfi_adjust_cfa_offset(4)
+       cfi_offset(%edx, -8)
+       cfi_offset(%ebx, -12)
+       cfi_offset(%esi, -16)
+
+       movl    %edx, %ebx
+       movl    $2, %edx
+       xorl    %esi, %esi      /* No timeout.  */
+       LOAD_FUTEX_WAIT (%ecx)
+
+       cmpl    %edx, %eax      /* NB:   %edx == 2 */
+       jne 2f
+
+1:     movl    $SYS_futex, %eax
+       ENTER_KERNEL
+
+2:     movl    %edx, %eax
+       xchgl   %eax, (%ebx)    /* NB:   lock is implied */
+
+       testl   %eax, %eax
+       jnz     1b
+
+       popl    %esi
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%esi)
+       popl    %ebx
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%ebx)
+       popl    %edx
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%edx)
+       ret
+       cfi_endproc
+       .size   __lll_lock_wait,.-__lll_lock_wait
+
+       /*      %ecx: futex
+               %esi: flags
+               %edx: timeout
+               %eax: futex value
+       */
+       .globl  __lll_timedlock_wait
+       .type   __lll_timedlock_wait,@function
+       .hidden __lll_timedlock_wait
+       .align  16
+__lll_timedlock_wait:
+       cfi_startproc
+       pushl   %ebp
+       cfi_adjust_cfa_offset(4)
+       cfi_rel_offset(%ebp, 0)
+       pushl   %ebx
+       cfi_adjust_cfa_offset(4)
+       cfi_rel_offset(%ebx, 0)
+
+# ifndef __ASSUME_FUTEX_CLOCK_REALTIME
+#  ifdef __PIC__
+       LOAD_PIC_REG (bx)
+       cmpl    $0, __have_futex_clock_realtime@GOTOFF(%ebx)
+#  else
+       cmpl    $0, __have_futex_clock_realtime
+#  endif
+       je      .Lreltmo
+# endif
+
+       movl    %ecx, %ebx
+       movl    %esi, %ecx
+       movl    %edx, %esi
+       movl    $0xffffffff, %ebp
+       LOAD_FUTEX_WAIT_ABS (%ecx)
+
+       movl    $2, %edx
+       cmpl    %edx, %eax
+       jne     2f
+
+1:     movl    $SYS_futex, %eax
+       movl    $2, %edx
+       ENTER_KERNEL
+
+2:     xchgl   %edx, (%ebx)    /* NB:   lock is implied */
+
+       testl   %edx, %edx
+       jz      3f
+
+       cmpl    $-ETIMEDOUT, %eax
+       je      4f
+       cmpl    $-EINVAL, %eax
+       jne     1b
+4:     movl    %eax, %edx
+       negl    %edx
+
+3:     movl    %edx, %eax
+7:     popl    %ebx
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%ebx)
+       popl    %ebp
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%ebp)
+       ret
+
+# ifndef __ASSUME_FUTEX_CLOCK_REALTIME
+.Lreltmo:
+       /* Check for a valid timeout value.  */
+       cmpl    $1000000000, 4(%edx)
+       jae     3f
+
+       pushl   %esi
+       cfi_adjust_cfa_offset(4)
+       cfi_rel_offset(%esi, 0)
+       pushl   %edi
+       cfi_adjust_cfa_offset(4)
+       cfi_rel_offset(%edi, 0)
+
+       /* Stack frame for the timespec and timeval structs.  */
+       subl    $8, %esp
+       cfi_adjust_cfa_offset(8)
+
+       movl    %ecx, %ebp
+       movl    %edx, %edi
+
+       movl    $2, %edx
+       xchgl   %edx, (%ebp)
+
+       test    %edx, %edx
+       je      6f
+
+1:
+       /* Get current time.  */
+       movl    %esp, %ebx
+       xorl    %ecx, %ecx
+       movl    $__NR_gettimeofday, %eax
+       ENTER_KERNEL
+
+       /* Compute relative timeout.  */
+       movl    4(%esp), %eax
+       movl    $1000, %edx
+       mul     %edx            /* Milli seconds to nano seconds.  */
+       movl    (%edi), %ecx
+       movl    4(%edi), %edx
+       subl    (%esp), %ecx
+       subl    %eax, %edx
+       jns     4f
+       addl    $1000000000, %edx
+       subl    $1, %ecx
+4:     testl   %ecx, %ecx
+       js      2f              /* Time is already up.  */
+
+       /* Store relative timeout.  */
+       movl    %ecx, (%esp)
+       movl    %edx, 4(%esp)
+
+       /* Futex call.  */
+       movl    %ebp, %ebx
+       movl    $2, %edx
+       movl    %esp, %esi
+       movl    16(%esp), %ecx
+       LOAD_FUTEX_WAIT (%ecx)
+       movl    $SYS_futex, %eax
+       ENTER_KERNEL
+
+       /* NB: %edx == 2 */
+       xchgl   %edx, (%ebp)
+
+       testl   %edx, %edx
+       je      6f
+
+       cmpl    $-ETIMEDOUT, %eax
+       jne     1b
+2:     movl    $ETIMEDOUT, %edx
+
+6:     addl    $8, %esp
+       cfi_adjust_cfa_offset(-8)
+       popl    %edi
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%edi)
+       popl    %esi
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%esi)
+7:     popl    %ebx
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%ebx)
+       popl    %ebp
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%ebp)
+       movl    %edx, %eax
+       ret
+
+3:     movl    $EINVAL, %edx
+       jmp     7b
+# endif
+       cfi_endproc
+       .size   __lll_timedlock_wait,.-__lll_timedlock_wait
+#endif
+
+       .globl  __lll_unlock_wake_private
+       .type   __lll_unlock_wake_private,@function
+       .hidden __lll_unlock_wake_private
+       .align  16
+__lll_unlock_wake_private:
+       cfi_startproc
+       pushl   %ebx
+       cfi_adjust_cfa_offset(4)
+       pushl   %ecx
+       cfi_adjust_cfa_offset(4)
+       pushl   %edx
+       cfi_adjust_cfa_offset(4)
+       cfi_offset(%ebx, -8)
+       cfi_offset(%ecx, -12)
+       cfi_offset(%edx, -16)
+
+       movl    %eax, %ebx
+       movl    $0, (%eax)
+       LOAD_PRIVATE_FUTEX_WAKE (%ecx)
+       movl    $1, %edx        /* Wake one thread.  */
+       movl    $SYS_futex, %eax
+       ENTER_KERNEL
+
+       popl    %edx
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%edx)
+       popl    %ecx
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%ecx)
+       popl    %ebx
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%ebx)
+       ret
+       cfi_endproc
+       .size   __lll_unlock_wake_private,.-__lll_unlock_wake_private
+
+#ifdef NOT_IN_libc
+       .globl  __lll_unlock_wake
+       .type   __lll_unlock_wake,@function
+       .hidden __lll_unlock_wake
+       .align  16
+__lll_unlock_wake:
+       cfi_startproc
+       pushl   %ebx
+       cfi_adjust_cfa_offset(4)
+       pushl   %ecx
+       cfi_adjust_cfa_offset(4)
+       pushl   %edx
+       cfi_adjust_cfa_offset(4)
+       cfi_offset(%ebx, -8)
+       cfi_offset(%ecx, -12)
+       cfi_offset(%edx, -16)
+
+       movl    %eax, %ebx
+       movl    $0, (%eax)
+       LOAD_FUTEX_WAKE (%ecx)
+       movl    $1, %edx        /* Wake one thread.  */
+       movl    $SYS_futex, %eax
+       ENTER_KERNEL
+
+       popl    %edx
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%edx)
+       popl    %ecx
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%ecx)
+       popl    %ebx
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%ebx)
+       ret
+       cfi_endproc
+       .size   __lll_unlock_wake,.-__lll_unlock_wake
+
+       .globl  __lll_timedwait_tid
+       .type   __lll_timedwait_tid,@function
+       .hidden __lll_timedwait_tid
+       .align  16
+__lll_timedwait_tid:
+       pushl   %edi
+       pushl   %esi
+       pushl   %ebx
+       pushl   %ebp
+
+       movl    %eax, %ebp
+       movl    %edx, %edi
+       subl    $8, %esp
+
+       /* Get current time.  */
+2:     movl    %esp, %ebx
+       xorl    %ecx, %ecx
+       movl    $__NR_gettimeofday, %eax
+       ENTER_KERNEL
+
+       /* Compute relative timeout.  */
+       movl    4(%esp), %eax
+       movl    $1000, %edx
+       mul     %edx            /* Milli seconds to nano seconds.  */
+       movl    (%edi), %ecx
+       movl    4(%edi), %edx
+       subl    (%esp), %ecx
+       subl    %eax, %edx
+       jns     5f
+       addl    $1000000000, %edx
+       subl    $1, %ecx
+5:     testl   %ecx, %ecx
+       js      6f              /* Time is already up.  */
+
+       movl    %ecx, (%esp)    /* Store relative timeout.  */
+       movl    %edx, 4(%esp)
+
+       movl    (%ebp), %edx
+       testl   %edx, %edx
+       jz      4f
+
+       movl    %esp, %esi
+       /* XXX The kernel so far uses global futex for the wakeup at
+          all times.  */
+       xorl    %ecx, %ecx      /* movl $FUTEX_WAIT, %ecx */
+       movl    %ebp, %ebx
+       movl    $SYS_futex, %eax
+       ENTER_KERNEL
+
+       cmpl    $0, (%ebx)
+       jne     1f
+4:     xorl    %eax, %eax
+
+3:     addl    $8, %esp
+       popl    %ebp
+       popl    %ebx
+       popl    %esi
+       popl    %edi
+       ret
+
+1:     cmpl    $-ETIMEDOUT, %eax
+       jne     2b
+6:     movl    $ETIMEDOUT, %eax
+       jmp     3b
+       .size   __lll_timedwait_tid,.-__lll_timedwait_tid
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevelrobustlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevelrobustlock.S
new file mode 100644 (file)
index 0000000..1d03800
--- /dev/null
@@ -0,0 +1,234 @@
+/* Copyright (C) 2002, 2003, 2004, 2006, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <pthread-errnos.h>
+#include <lowlevellock.h>
+#include <lowlevelrobustlock.h>
+#include <bits/kernel-features.h>
+#include <tls.h>
+
+       .text
+
+#define FUTEX_WAITERS          0x80000000
+#define FUTEX_OWNER_DIED       0x40000000
+
+#ifdef __ASSUME_PRIVATE_FUTEX
+# define LOAD_FUTEX_WAIT(reg) \
+       xorl    $(FUTEX_WAIT | FUTEX_PRIVATE_FLAG), reg
+#else
+# if FUTEX_WAIT == 0
+#  define LOAD_FUTEX_WAIT(reg) \
+       xorl    $FUTEX_PRIVATE_FLAG, reg ; \
+       andl    %gs:PRIVATE_FUTEX, reg
+# else
+#  define LOAD_FUTEX_WAIT(reg) \
+       xorl    $FUTEX_PRIVATE_FLAG, reg ; \
+       andl    %gs:PRIVATE_FUTEX, reg ; \
+       orl     $FUTEX_WAIT, reg
+# endif
+#endif
+
+       .globl  __lll_robust_lock_wait
+       .type   __lll_robust_lock_wait,@function
+       .hidden __lll_robust_lock_wait
+       .align  16
+__lll_robust_lock_wait:
+       cfi_startproc
+       pushl   %edx
+       cfi_adjust_cfa_offset(4)
+       pushl   %ebx
+       cfi_adjust_cfa_offset(4)
+       pushl   %esi
+       cfi_adjust_cfa_offset(4)
+       cfi_offset(%edx, -8)
+       cfi_offset(%ebx, -12)
+       cfi_offset(%esi, -16)
+
+       movl    %edx, %ebx
+       xorl    %esi, %esi      /* No timeout.  */
+       LOAD_FUTEX_WAIT (%ecx)
+
+4:     movl    %eax, %edx
+       orl     $FUTEX_WAITERS, %edx
+
+       testl   $FUTEX_OWNER_DIED, %eax
+       jnz     3f
+
+       cmpl    %edx, %eax      /* NB:   %edx == 2 */
+       je      1f
+
+       LOCK
+       cmpxchgl %edx, (%ebx)
+       jnz     2f
+
+1:     movl    $SYS_futex, %eax
+       ENTER_KERNEL
+
+       movl    (%ebx), %eax
+
+2:     test    %eax, %eax
+       jne     4b
+
+       movl    %gs:TID, %edx
+       orl     $FUTEX_WAITERS, %edx
+       LOCK
+       cmpxchgl %edx, (%ebx)
+       jnz     4b
+       /* NB:   %eax == 0 */
+
+3:     popl    %esi
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%esi)
+       popl    %ebx
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%ebx)
+       popl    %edx
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%edx)
+       ret
+       cfi_endproc
+       .size   __lll_robust_lock_wait,.-__lll_robust_lock_wait
+
+
+       .globl  __lll_robust_timedlock_wait
+       .type   __lll_robust_timedlock_wait,@function
+       .hidden __lll_robust_timedlock_wait
+       .align  16
+__lll_robust_timedlock_wait:
+       cfi_startproc
+       /* Check for a valid timeout value.  */
+       cmpl    $1000000000, 4(%edx)
+       jae     3f
+
+       pushl   %edi
+       cfi_adjust_cfa_offset(4)
+       pushl   %esi
+       cfi_adjust_cfa_offset(4)
+       pushl   %ebx
+       cfi_adjust_cfa_offset(4)
+       pushl   %ebp
+       cfi_adjust_cfa_offset(4)
+       cfi_offset(%edi, -8)
+       cfi_offset(%esi, -12)
+       cfi_offset(%ebx, -16)
+       cfi_offset(%ebp, -20)
+
+       /* Stack frame for the timespec and timeval structs.  */
+       subl    $12, %esp
+       cfi_adjust_cfa_offset(12)
+
+       movl    %ecx, %ebp
+       movl    %edx, %edi
+
+1:     movl    %eax, 8(%esp)
+
+       /* Get current time.  */
+       movl    %esp, %ebx
+       xorl    %ecx, %ecx
+       movl    $__NR_gettimeofday, %eax
+       ENTER_KERNEL
+
+       /* Compute relative timeout.  */
+       movl    4(%esp), %eax
+       movl    $1000, %edx
+       mul     %edx            /* Milli seconds to nano seconds.  */
+       movl    (%edi), %ecx
+       movl    4(%edi), %edx
+       subl    (%esp), %ecx
+       subl    %eax, %edx
+       jns     4f
+       addl    $1000000000, %edx
+       subl    $1, %ecx
+4:     testl   %ecx, %ecx
+       js      8f              /* Time is already up.  */
+
+       /* Store relative timeout.  */
+       movl    %ecx, (%esp)
+       movl    %edx, 4(%esp)
+
+       movl    %ebp, %ebx
+
+       movl    8(%esp), %edx
+       movl    %edx, %eax
+       orl     $FUTEX_WAITERS, %edx
+
+       testl   $FUTEX_OWNER_DIED, %eax
+       jnz     6f
+
+       cmpl    %eax, %edx
+       je      2f
+
+       LOCK
+       cmpxchgl %edx, (%ebx)
+       movl    $0, %ecx        /* Must use mov to avoid changing cc.  */
+       jnz     5f
+
+2:
+       /* Futex call.  */
+       movl    %esp, %esi
+       movl    20(%esp), %ecx
+       LOAD_FUTEX_WAIT (%ecx)
+       movl    $SYS_futex, %eax
+       ENTER_KERNEL
+       movl    %eax, %ecx
+
+       movl    (%ebx), %eax
+
+5:     testl   %eax, %eax
+       jne     7f
+
+       movl    %gs:TID, %edx
+       orl     $FUTEX_WAITERS, %edx
+       LOCK
+       cmpxchgl %edx, (%ebx)
+       jnz     7f
+
+6:     addl    $12, %esp
+       cfi_adjust_cfa_offset(-12)
+       popl    %ebp
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%ebp)
+       popl    %ebx
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%ebx)
+       popl    %esi
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%esi)
+       popl    %edi
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%edi)
+       ret
+
+3:     movl    $EINVAL, %eax
+       ret
+
+       cfi_adjust_cfa_offset(28)
+       cfi_offset(%edi, -8)
+       cfi_offset(%esi, -12)
+       cfi_offset(%ebx, -16)
+       cfi_offset(%ebp, -20)
+       /* Check whether the time expired.  */
+7:     cmpl    $-ETIMEDOUT, %ecx
+       jne     1b
+
+8:     movl    $ETIMEDOUT, %eax
+       jmp     6b
+       cfi_endproc
+       .size   __lll_robust_timedlock_wait,.-__lll_robust_timedlock_wait
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_barrier_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_barrier_wait.S
new file mode 100644 (file)
index 0000000..040d7f8
--- /dev/null
@@ -0,0 +1,187 @@
+/* Copyright (C) 2002, 2003, 2004, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <lowlevelbarrier.h>
+
+       .text
+
+       .globl  pthread_barrier_wait
+       .type   pthread_barrier_wait,@function
+       .align  16
+pthread_barrier_wait:
+       cfi_startproc
+       pushl   %ebx
+       cfi_adjust_cfa_offset(4)
+       cfi_offset(%ebx, -8)
+
+       movl    8(%esp), %ebx
+
+       /* Get the mutex.  */
+       movl    $1, %edx
+       xorl    %eax, %eax
+       LOCK
+       cmpxchgl %edx, MUTEX(%ebx)
+       jnz     1f
+
+       /* One less waiter.  If this was the last one needed wake
+          everybody.  */
+2:     subl    $1, LEFT(%ebx)
+       je      3f
+
+       /* There are more threads to come.  */
+       pushl   %esi
+       cfi_adjust_cfa_offset(4)
+       cfi_offset(%esi, -12)
+
+#if CURR_EVENT == 0
+       movl    (%ebx), %edx
+#else
+       movl    CURR_EVENT(%ebx), %edx
+#endif
+
+       /* Release the mutex.  */
+       LOCK
+       subl    $1, MUTEX(%ebx)
+       jne     6f
+
+       /* Wait for the remaining threads.  The call will return immediately
+          if the CURR_EVENT memory has meanwhile been changed.  */
+7:
+#if FUTEX_WAIT == 0
+       movl    PRIVATE(%ebx), %ecx
+#else
+       movl    $FUTEX_WAIT, %ecx
+       orl     PRIVATE(%ebx), %ecx
+#endif
+       xorl    %esi, %esi
+8:     movl    $SYS_futex, %eax
+       ENTER_KERNEL
+
+       /* Don't return on spurious wakeups.  The syscall does not change
+          any register except %eax so there is no need to reload any of
+          them.  */
+#if CURR_EVENT == 0
+       cmpl    %edx, (%ebx)
+#else
+       cmpl    %edx, CURR_EVENT(%ebx)
+#endif
+       je      8b
+
+       /* Increment LEFT.  If this brings the count back to the
+          initial count unlock the object.  */
+       movl    $1, %edx
+       movl    INIT_COUNT(%ebx), %ecx
+       LOCK
+       xaddl   %edx, LEFT(%ebx)
+       subl    $1, %ecx
+       cmpl    %ecx, %edx
+       jne     10f
+
+       /* Release the mutex.  We cannot release the lock before
+          waking the waiting threads since otherwise a new thread might
+          arrive and gets waken up, too.  */
+       LOCK
+       subl    $1, MUTEX(%ebx)
+       jne     9f
+
+       /* Note: %esi is still zero.  */
+10:    movl    %esi, %eax              /* != PTHREAD_BARRIER_SERIAL_THREAD */
+
+       popl    %esi
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%esi)
+       popl    %ebx
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%ebx)
+       ret
+
+       cfi_adjust_cfa_offset(4)
+       cfi_offset(%ebx, -8)
+       
+       /* The necessary number of threads arrived.  */
+3:
+#if CURR_EVENT == 0
+       addl    $1, (%ebx)
+#else
+       addl    $1, CURR_EVENT(%ebx)
+#endif
+
+       /* Wake up all waiters.  The count is a signed number in the kernel
+          so 0x7fffffff is the highest value.  */
+       movl    $0x7fffffff, %edx
+       movl    $FUTEX_WAKE, %ecx
+       orl     PRIVATE(%ebx), %ecx
+       movl    $SYS_futex, %eax
+       ENTER_KERNEL
+
+       /* Increment LEFT.  If this brings the count back to the
+          initial count unlock the object.  */
+       movl    $1, %edx
+       movl    INIT_COUNT(%ebx), %ecx
+       LOCK
+       xaddl   %edx, LEFT(%ebx)
+       subl    $1, %ecx
+       cmpl    %ecx, %edx
+       jne     5f
+
+       /* Release the mutex.  We cannot release the lock before
+          waking the waiting threads since otherwise a new thread might
+          arrive and gets waken up, too.  */
+       LOCK
+       subl    $1, MUTEX(%ebx)
+       jne     4f
+
+5:     orl     $-1, %eax               /* == PTHREAD_BARRIER_SERIAL_THREAD */
+
+       popl    %ebx
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%ebx)
+       ret
+
+       cfi_adjust_cfa_offset(4)
+       cfi_offset(%ebx, -8)
+1:     movl    PRIVATE(%ebx), %ecx
+       leal    MUTEX(%ebx), %edx
+       xorl    $LLL_SHARED, %ecx
+       call    __lll_lock_wait
+       jmp     2b
+
+4:     movl    PRIVATE(%ebx), %ecx
+       leal    MUTEX(%ebx), %eax
+       xorl    $LLL_SHARED, %ecx
+       call    __lll_unlock_wake
+       jmp     5b
+
+       cfi_adjust_cfa_offset(4)
+       cfi_offset(%esi, -12)
+6:     movl    PRIVATE(%ebx), %ecx
+       leal    MUTEX(%ebx), %eax
+       xorl    $LLL_SHARED, %ecx
+       call    __lll_unlock_wake
+       jmp     7b
+
+9:     movl    PRIVATE(%ebx), %ecx
+       leal    MUTEX(%ebx), %eax
+       xorl    $LLL_SHARED, %ecx
+       call    __lll_unlock_wake
+       jmp     10b
+       cfi_endproc
+       .size   pthread_barrier_wait,.-pthread_barrier_wait
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S
new file mode 100644 (file)
index 0000000..0413cc1
--- /dev/null
@@ -0,0 +1,238 @@
+/* Copyright (C) 2002,2003,2004,2006,2007,2009 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <lowlevelcond.h>
+#include <bits/kernel-features.h>
+#include <pthread-pi-defines.h>
+#include <pthread-errnos.h>
+#include <tls.h>
+
+       .text
+
+       /* int pthread_cond_broadcast (pthread_cond_t *cond) */
+       .globl  __pthread_cond_broadcast
+       .type   __pthread_cond_broadcast, @function
+       .align  16
+__pthread_cond_broadcast:
+       cfi_startproc
+       pushl   %ebx
+       cfi_adjust_cfa_offset(4)
+       cfi_rel_offset(%ebx, 0)
+       pushl   %esi
+       cfi_adjust_cfa_offset(4)
+       cfi_rel_offset(%esi, 0)
+       pushl   %edi
+       cfi_adjust_cfa_offset(4)
+       cfi_rel_offset(%edi, 0)
+       pushl   %ebp
+       cfi_adjust_cfa_offset(4)
+       cfi_rel_offset(%ebp, 0)
+       cfi_remember_state
+
+       movl    20(%esp), %ebx
+
+       /* Get internal lock.  */
+       movl    $1, %edx
+       xorl    %eax, %eax
+       LOCK
+#if cond_lock == 0
+       cmpxchgl %edx, (%ebx)
+#else
+       cmpxchgl %edx, cond_lock(%ebx)
+#endif
+       jnz     1f
+
+2:     addl    $cond_futex, %ebx
+       movl    total_seq+4-cond_futex(%ebx), %eax
+       movl    total_seq-cond_futex(%ebx), %ebp
+       cmpl    wakeup_seq+4-cond_futex(%ebx), %eax
+       ja      3f
+       jb      4f
+       cmpl    wakeup_seq-cond_futex(%ebx), %ebp
+       jna     4f
+
+       /* Cause all currently waiting threads to recognize they are
+          woken up.  */
+3:     movl    %ebp, wakeup_seq-cond_futex(%ebx)
+       movl    %eax, wakeup_seq-cond_futex+4(%ebx)
+       movl    %ebp, woken_seq-cond_futex(%ebx)
+       movl    %eax, woken_seq-cond_futex+4(%ebx)
+       addl    %ebp, %ebp
+       addl    $1, broadcast_seq-cond_futex(%ebx)
+       movl    %ebp, (%ebx)
+
+       /* Get the address of the mutex used.  */
+       movl    dep_mutex-cond_futex(%ebx), %edi
+
+       /* Unlock.  */
+       LOCK
+       subl    $1, cond_lock-cond_futex(%ebx)
+       jne     7f
+
+       /* Don't use requeue for pshared condvars.  */
+8:     cmpl    $-1, %edi
+       je      9f
+
+       /* Do not use requeue for pshared condvars.  */
+       testl   $PS_BIT, MUTEX_KIND(%edi)
+       jne     9f
+
+       /* Requeue to a non-robust PI mutex if the PI bit is set and
+          the robust bit is not set.  */
+       movl    MUTEX_KIND(%edi), %eax
+       andl    $(ROBUST_BIT|PI_BIT), %eax
+       cmpl    $PI_BIT, %eax
+       je      81f
+
+       /* Wake up all threads.  */
+#ifdef __ASSUME_PRIVATE_FUTEX
+       movl    $(FUTEX_CMP_REQUEUE|FUTEX_PRIVATE_FLAG), %ecx
+#else
+       movl    %gs:PRIVATE_FUTEX, %ecx
+       orl     $FUTEX_CMP_REQUEUE, %ecx
+#endif
+       movl    $SYS_futex, %eax
+       movl    $0x7fffffff, %esi
+       movl    $1, %edx
+       /* Get the address of the futex involved.  */
+# if MUTEX_FUTEX != 0
+       addl    $MUTEX_FUTEX, %edi
+# endif
+/* FIXME: Until Ingo fixes 4G/4G vDSO, 6 arg syscalls are broken for sysenter.
+       ENTER_KERNEL  */
+       int     $0x80
+
+       /* For any kind of error, which mainly is EAGAIN, we try again
+          with WAKE.  The general test also covers running on old
+          kernels.  */
+       cmpl    $0xfffff001, %eax
+       jae     9f
+
+6:     xorl    %eax, %eax
+       popl    %ebp
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%ebp)
+       popl    %edi
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%edi)
+       popl    %esi
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%esi)
+       popl    %ebx
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%ebx)
+       ret
+
+       cfi_restore_state
+
+81:    movl    $(FUTEX_CMP_REQUEUE_PI|FUTEX_PRIVATE_FLAG), %ecx
+       movl    $SYS_futex, %eax
+       movl    $0x7fffffff, %esi
+       movl    $1, %edx
+       /* Get the address of the futex involved.  */
+# if MUTEX_FUTEX != 0
+       addl    $MUTEX_FUTEX, %edi
+# endif
+       int     $0x80
+
+       /* For any kind of error, which mainly is EAGAIN, we try again
+       with WAKE.  The general test also covers running on old
+       kernels.  */
+       cmpl    $0xfffff001, %eax
+       jb      6b
+       jmp     9f
+
+       /* Initial locking failed.  */
+1:
+#if cond_lock == 0
+       movl    %ebx, %edx
+#else
+       leal    cond_lock(%ebx), %edx
+#endif
+#if (LLL_SHARED-LLL_PRIVATE) > 255
+       xorl    %ecx, %ecx
+#endif
+       cmpl    $-1, dep_mutex(%ebx)
+       setne   %cl
+       subl    $1, %ecx
+       andl    $(LLL_SHARED-LLL_PRIVATE), %ecx
+#if LLL_PRIVATE != 0
+       addl    $LLL_PRIVATE, %ecx
+#endif
+       call    __lll_lock_wait
+       jmp     2b
+
+       .align  16
+       /* Unlock.  */
+4:     LOCK
+       subl    $1, cond_lock-cond_futex(%ebx)
+       je      6b
+
+       /* Unlock in loop requires wakeup.  */
+5:     leal    cond_lock-cond_futex(%ebx), %eax
+#if (LLL_SHARED-LLL_PRIVATE) > 255
+       xorl    %ecx, %ecx
+#endif
+       cmpl    $-1, dep_mutex-cond_futex(%ebx)
+       setne   %cl
+       subl    $1, %ecx
+       andl    $(LLL_SHARED-LLL_PRIVATE), %ecx
+#if LLL_PRIVATE != 0
+       addl    $LLL_PRIVATE, %ecx
+#endif
+       call    __lll_unlock_wake
+       jmp     6b
+
+       /* Unlock in loop requires wakeup.  */
+7:     leal    cond_lock-cond_futex(%ebx), %eax
+#if (LLL_SHARED-LLL_PRIVATE) > 255
+       xorl    %ecx, %ecx
+#endif
+       cmpl    $-1, dep_mutex-cond_futex(%ebx)
+       setne   %cl
+       subl    $1, %ecx
+       andl    $(LLL_SHARED-LLL_PRIVATE), %ecx
+#if LLL_PRIVATE != 0
+       addl    $LLL_PRIVATE, %ecx
+#endif
+       call    __lll_unlock_wake
+       jmp     8b
+
+9:     /* The futex requeue functionality is not available.  */
+       movl    $0x7fffffff, %edx
+#if FUTEX_PRIVATE_FLAG > 255
+       xorl    %ecx, %ecx
+#endif
+       cmpl    $-1, dep_mutex-cond_futex(%ebx)
+       sete    %cl
+       subl    $1, %ecx
+#ifdef __ASSUME_PRIVATE_FUTEX
+       andl    $FUTEX_PRIVATE_FLAG, %ecx
+#else
+       andl    %gs:PRIVATE_FUTEX, %ecx
+#endif
+       addl    $FUTEX_WAKE, %ecx
+       movl    $SYS_futex, %eax
+       ENTER_KERNEL
+       jmp     6b
+       cfi_endproc
+       .size   __pthread_cond_broadcast, .-__pthread_cond_broadcast
+weak_alias(__pthread_cond_broadcast, pthread_cond_broadcast)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_signal.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_signal.S
new file mode 100644 (file)
index 0000000..2f3c9bc
--- /dev/null
@@ -0,0 +1,215 @@
+/* Copyright (C) 2002,2003,2004,2005,2007,2009 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <lowlevelcond.h>
+#include <bits/kernel-features.h>
+#include <pthread-pi-defines.h>
+#include <pthread-errnos.h>
+#include <tls.h>
+
+
+       .text
+
+       /* int pthread_cond_signal (pthread_cond_t *cond) */
+       .globl  __pthread_cond_signal
+       .type   __pthread_cond_signal, @function
+       .align  16
+__pthread_cond_signal:
+
+       cfi_startproc
+       pushl   %ebx
+       cfi_adjust_cfa_offset(4)
+       cfi_rel_offset(%ebx, 0)
+       pushl   %edi
+       cfi_adjust_cfa_offset(4)
+       cfi_rel_offset(%edi, 0)
+       cfi_remember_state
+
+       movl    12(%esp), %edi
+
+       /* Get internal lock.  */
+       movl    $1, %edx
+       xorl    %eax, %eax
+       LOCK
+#if cond_lock == 0
+       cmpxchgl %edx, (%edi)
+#else
+       cmpxchgl %edx, cond_lock(%edi)
+#endif
+       jnz     1f
+
+2:     leal    cond_futex(%edi), %ebx
+       movl    total_seq+4(%edi), %eax
+       movl    total_seq(%edi), %ecx
+       cmpl    wakeup_seq+4(%edi), %eax
+#if cond_lock != 0
+       /* Must use leal to preserve the flags.  */
+       leal    cond_lock(%edi), %edi
+#endif
+       ja      3f
+       jb      4f
+       cmpl    wakeup_seq-cond_futex(%ebx), %ecx
+       jbe     4f
+
+       /* Bump the wakeup number.  */
+3:     addl    $1, wakeup_seq-cond_futex(%ebx)
+       adcl    $0, wakeup_seq-cond_futex+4(%ebx)
+       addl    $1, (%ebx)
+
+       /* Wake up one thread.  */
+       pushl   %esi
+       cfi_adjust_cfa_offset(4)
+       cfi_rel_offset(%esi, 0)
+       pushl   %ebp
+       cfi_adjust_cfa_offset(4)
+       cfi_rel_offset(%ebp, 0)
+
+#if FUTEX_PRIVATE_FLAG > 255
+       xorl    %ecx, %ecx
+#endif
+       cmpl    $-1, dep_mutex-cond_futex(%ebx)
+       sete    %cl
+       je      8f
+
+       movl    dep_mutex-cond_futex(%ebx), %edx
+       /* Requeue to a non-robust PI mutex if the PI bit is set and
+          the robust bit is not set.  */
+       movl    MUTEX_KIND(%edx), %eax
+       andl    $(ROBUST_BIT|PI_BIT), %eax
+       cmpl    $PI_BIT, %eax
+       je      9f
+
+8:     subl    $1, %ecx
+#ifdef __ASSUME_PRIVATE_FUTEX
+       andl    $FUTEX_PRIVATE_FLAG, %ecx
+#else
+       andl    %gs:PRIVATE_FUTEX, %ecx
+#endif
+       addl    $FUTEX_WAKE_OP, %ecx
+       movl    $SYS_futex, %eax
+       movl    $1, %edx
+       movl    $1, %esi
+       movl    $FUTEX_OP_CLEAR_WAKE_IF_GT_ONE, %ebp
+       /* FIXME: Until Ingo fixes 4G/4G vDSO, 6 arg syscalls are broken for
+          sysenter.
+       ENTER_KERNEL  */
+       int     $0x80
+       popl    %ebp
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%ebp)
+       popl    %esi
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%esi)
+
+       /* For any kind of error, we try again with WAKE.
+          The general test also covers running on old kernels.  */
+       cmpl    $-4095, %eax
+       jae     7f
+
+6:     xorl    %eax, %eax
+       popl    %edi
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%edi)
+       popl    %ebx
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%ebx)
+       ret
+
+       cfi_restore_state
+
+9:     movl    $(FUTEX_CMP_REQUEUE_PI|FUTEX_PRIVATE_FLAG), %ecx
+       movl    $SYS_futex, %eax
+       movl    $1, %edx
+       xorl    %esi, %esi
+       movl    dep_mutex-cond_futex(%ebx), %edi
+       movl    (%ebx), %ebp
+       /* FIXME: Until Ingo fixes 4G/4G vDSO, 6 arg syscalls are broken for
+          sysenter.
+       ENTER_KERNEL  */
+       int     $0x80
+       popl    %ebp
+       popl    %esi
+
+       leal    -cond_futex(%ebx), %edi
+
+       /* For any kind of error, we try again with WAKE.
+          The general test also covers running on old kernels.  */
+       cmpl    $-4095, %eax
+       jb      4f
+
+7:
+#ifdef __ASSUME_PRIVATE_FUTEX
+       andl    $FUTEX_PRIVATE_FLAG, %ecx
+#else
+       andl    %gs:PRIVATE_FUTEX, %ecx
+#endif
+       orl     $FUTEX_WAKE, %ecx
+
+       xorl    $(FUTEX_WAKE ^ FUTEX_WAKE_OP), %ecx
+       movl    $SYS_futex, %eax
+       /* %edx should be 1 already from $FUTEX_WAKE_OP syscall.
+       movl    $1, %edx  */
+       ENTER_KERNEL
+
+       /* Unlock.  Note that at this point %edi always points to
+          cond_lock.  */
+4:     LOCK
+       subl    $1, (%edi)
+       je      6b
+
+       /* Unlock in loop requires wakeup.  */
+5:     movl    %edi, %eax
+#if (LLL_SHARED-LLL_PRIVATE) > 255
+       xorl    %ecx, %ecx
+#endif
+       cmpl    $-1, dep_mutex-cond_futex(%ebx)
+       setne   %cl
+       subl    $1, %ecx
+       andl    $(LLL_SHARED-LLL_PRIVATE), %ecx
+#if LLL_PRIVATE != 0
+       addl    $LLL_PRIVATE, %ecx
+#endif
+       call    __lll_unlock_wake
+       jmp     6b
+
+       /* Initial locking failed.  */
+1:
+#if cond_lock == 0
+       movl    %edi, %edx
+#else
+       leal    cond_lock(%edi), %edx
+#endif
+#if (LLL_SHARED-LLL_PRIVATE) > 255
+       xorl    %ecx, %ecx
+#endif
+       cmpl    $-1, dep_mutex(%edi)
+       setne   %cl
+       subl    $1, %ecx
+       andl    $(LLL_SHARED-LLL_PRIVATE), %ecx
+#if LLL_PRIVATE != 0
+       addl    $LLL_PRIVATE, %ecx
+#endif
+       call    __lll_lock_wait
+       jmp     2b
+
+       cfi_endproc
+       .size   __pthread_cond_signal, .-__pthread_cond_signal
+weak_alias(__pthread_cond_signal, pthread_cond_signal)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S
new file mode 100644 (file)
index 0000000..c56dd77
--- /dev/null
@@ -0,0 +1,693 @@
+/* Copyright (C) 2002-2004,2006-2007,2009,2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <lowlevelcond.h>
+#include <pthread-errnos.h>
+#include <pthread-pi-defines.h>
+#include <bits/kernel-features.h>
+
+
+       .text
+
+/* int pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex,
+                              const struct timespec *abstime)  */
+       .globl  __pthread_cond_timedwait
+       .type   __pthread_cond_timedwait, @function
+       .align  16
+__pthread_cond_timedwait:
+.LSTARTCODE:
+       cfi_startproc
+#ifdef SHARED
+       cfi_personality(DW_EH_PE_pcrel | DW_EH_PE_sdata4 | DW_EH_PE_indirect,
+                       DW.ref.__gcc_personality_v0)
+       cfi_lsda(DW_EH_PE_pcrel | DW_EH_PE_sdata4, .LexceptSTART)
+#else
+       cfi_personality(DW_EH_PE_udata4, __gcc_personality_v0)
+       cfi_lsda(DW_EH_PE_udata4, .LexceptSTART)
+#endif
+
+       pushl   %ebp
+       cfi_adjust_cfa_offset(4)
+       cfi_rel_offset(%ebp, 0)
+       pushl   %edi
+       cfi_adjust_cfa_offset(4)
+       cfi_rel_offset(%edi, 0)
+       pushl   %esi
+       cfi_adjust_cfa_offset(4)
+       cfi_rel_offset(%esi, 0)
+       pushl   %ebx
+       cfi_adjust_cfa_offset(4)
+       cfi_rel_offset(%ebx, 0)
+
+       movl    20(%esp), %ebx
+       movl    28(%esp), %ebp
+
+       cmpl    $1000000000, 4(%ebp)
+       movl    $EINVAL, %eax
+       jae     18f
+
+       /* Get internal lock.  */
+       movl    $1, %edx
+       xorl    %eax, %eax
+       LOCK
+#if cond_lock == 0
+       cmpxchgl %edx, (%ebx)
+#else
+       cmpxchgl %edx, cond_lock(%ebx)
+#endif
+       jnz     1f
+
+       /* Store the reference to the mutex.  If there is already a
+          different value in there this is a bad user bug.  */
+2:     cmpl    $-1, dep_mutex(%ebx)
+       movl    24(%esp), %eax
+       je      17f
+       movl    %eax, dep_mutex(%ebx)
+
+       /* Unlock the mutex.  */
+17:    xorl    %edx, %edx
+       call    __pthread_mutex_unlock_usercnt
+
+       testl   %eax, %eax
+       jne     16f
+
+       addl    $1, total_seq(%ebx)
+       adcl    $0, total_seq+4(%ebx)
+       addl    $1, cond_futex(%ebx)
+       addl    $(1 << nwaiters_shift), cond_nwaiters(%ebx)
+
+#define FRAME_SIZE 32
+       subl    $FRAME_SIZE, %esp
+       cfi_adjust_cfa_offset(FRAME_SIZE)
+       cfi_remember_state
+
+       /* Get and store current wakeup_seq value.  */
+       movl    wakeup_seq(%ebx), %edi
+       movl    wakeup_seq+4(%ebx), %edx
+       movl    broadcast_seq(%ebx), %eax
+       movl    %edi, 12(%esp)
+       movl    %edx, 16(%esp)
+       movl    %eax, 20(%esp)
+
+       /* Reset the pi-requeued flag.  */
+8:     movl    $0, 24(%esp)
+       /* Get the current time.  */
+       movl    %ebx, %edx
+#ifdef __NR_clock_gettime
+       /* Get the clock number.  */
+       movl    cond_nwaiters(%ebx), %ebx
+       andl    $((1 << nwaiters_shift) - 1), %ebx
+       /* Only clocks 0 and 1 are allowed so far.  Both are handled in the
+          kernel.  */
+       leal    4(%esp), %ecx
+       movl    $__NR_clock_gettime, %eax
+       ENTER_KERNEL
+# ifndef __ASSUME_POSIX_TIMERS
+       cmpl    $-ENOSYS, %eax
+       je      19f
+# endif
+       movl    %edx, %ebx
+
+       /* Compute relative timeout.  */
+       movl    (%ebp), %ecx
+       movl    4(%ebp), %edx
+       subl    4(%esp), %ecx
+       subl    8(%esp), %edx
+#else
+       /* Get the current time.  */
+       leal    4(%esp), %ebx
+       xorl    %ecx, %ecx
+       movl    $__NR_gettimeofday, %eax
+       ENTER_KERNEL
+       movl    %edx, %ebx
+
+       /* Compute relative timeout.  */
+       movl    8(%esp), %eax
+       movl    $1000, %edx
+       mul     %edx            /* Milli seconds to nano seconds.  */
+       movl    (%ebp), %ecx
+       movl    4(%ebp), %edx
+       subl    4(%esp), %ecx
+       subl    %eax, %edx
+#endif
+       jns     12f
+       addl    $1000000000, %edx
+       subl    $1, %ecx
+12:    testl   %ecx, %ecx
+       movl    $-ETIMEDOUT, %esi
+       js      6f
+
+       /* Store relative timeout.  */
+21:    movl    %ecx, 4(%esp)
+       movl    %edx, 8(%esp)
+
+       movl    cond_futex(%ebx), %edi
+       movl    %edi, 28(%esp)
+
+       /* Unlock.  */
+       LOCK
+#if cond_lock == 0
+       subl    $1, (%ebx)
+#else
+       subl    $1, cond_lock(%ebx)
+#endif
+       jne     3f
+
+.LcleanupSTART:
+4:     call    __pthread_enable_asynccancel
+       movl    %eax, (%esp)
+
+#if FUTEX_PRIVATE_FLAG > 255
+       xorl    %ecx, %ecx
+#endif
+       cmpl    $-1, dep_mutex(%ebx)
+       sete    %cl
+       je      40f
+
+       movl    dep_mutex(%ebx), %edi
+       /* Requeue to a non-robust PI mutex if the PI bit is set and
+          the robust bit is not set.  */
+       movl    MUTEX_KIND(%edi), %eax
+       andl    $(ROBUST_BIT|PI_BIT), %eax
+       cmpl    $PI_BIT, %eax
+       jne     40f
+
+       movl    $(FUTEX_WAIT_REQUEUE_PI|FUTEX_PRIVATE_FLAG), %ecx
+       /* The following only works like this because we only support
+          two clocks, represented using a single bit.  */
+       testl   $1, cond_nwaiters(%ebx)
+       /* XXX Need to implement using sete instead of a jump.  */
+       jne     42f
+       orl     $FUTEX_CLOCK_REALTIME, %ecx
+
+       /* Requeue-PI uses absolute timeout */
+42:    leal    (%ebp), %esi
+       movl    28(%esp), %edx
+       addl    $cond_futex, %ebx
+       movl    $SYS_futex, %eax
+       ENTER_KERNEL
+       subl    $cond_futex, %ebx
+       movl    %eax, %esi
+       /* Set the pi-requeued flag only if the kernel has returned 0. The
+          kernel does not hold the mutex on ETIMEDOUT or any other error.  */
+       cmpl    $0, %eax
+       sete    24(%esp)
+       je      41f
+
+       /* Normal and PI futexes dont mix. Use normal futex functions only
+          if the kernel does not support the PI futex functions.  */
+       cmpl    $-ENOSYS, %eax
+       jne     41f
+       xorl    %ecx, %ecx
+
+40:    subl    $1, %ecx
+#ifdef __ASSUME_PRIVATE_FUTEX
+       andl    $FUTEX_PRIVATE_FLAG, %ecx
+#else
+       andl    %gs:PRIVATE_FUTEX, %ecx
+#endif
+#if FUTEX_WAIT != 0
+       addl    $FUTEX_WAIT, %ecx
+#endif
+       leal    4(%esp), %esi
+       movl    28(%esp), %edx
+       addl    $cond_futex, %ebx
+.Ladd_cond_futex:
+       movl    $SYS_futex, %eax
+       ENTER_KERNEL
+       subl    $cond_futex, %ebx
+.Lsub_cond_futex:
+       movl    %eax, %esi
+
+41:    movl    (%esp), %eax
+       call    __pthread_disable_asynccancel
+.LcleanupEND:
+
+       /* Lock.  */
+       movl    $1, %edx
+       xorl    %eax, %eax
+       LOCK
+#if cond_lock == 0
+       cmpxchgl %edx, (%ebx)
+#else
+       cmpxchgl %edx, cond_lock(%ebx)
+#endif
+       jnz     5f
+
+6:     movl    broadcast_seq(%ebx), %eax
+       cmpl    20(%esp), %eax
+       jne     23f
+
+       movl    woken_seq(%ebx), %eax
+       movl    woken_seq+4(%ebx), %ecx
+
+       movl    wakeup_seq(%ebx), %edi
+       movl    wakeup_seq+4(%ebx), %edx
+
+       cmpl    16(%esp), %edx
+       jne     7f
+       cmpl    12(%esp), %edi
+       je      15f
+
+7:     cmpl    %ecx, %edx
+       jne     9f
+       cmp     %eax, %edi
+       jne     9f
+
+15:    cmpl    $-ETIMEDOUT, %esi
+       jne     8b
+
+       addl    $1, wakeup_seq(%ebx)
+       adcl    $0, wakeup_seq+4(%ebx)
+       addl    $1, cond_futex(%ebx)
+       movl    $ETIMEDOUT, %esi
+       jmp     14f
+
+23:    xorl    %esi, %esi
+       jmp     24f
+
+9:     xorl    %esi, %esi
+14:    addl    $1, woken_seq(%ebx)
+       adcl    $0, woken_seq+4(%ebx)
+
+24:    subl    $(1 << nwaiters_shift), cond_nwaiters(%ebx)
+
+       /* Wake up a thread which wants to destroy the condvar object.  */
+       movl    total_seq(%ebx), %eax
+       andl    total_seq+4(%ebx), %eax
+       cmpl    $0xffffffff, %eax
+       jne     25f
+       movl    cond_nwaiters(%ebx), %eax
+       andl    $~((1 << nwaiters_shift) - 1), %eax
+       jne     25f
+
+       addl    $cond_nwaiters, %ebx
+       movl    $SYS_futex, %eax
+#if FUTEX_PRIVATE_FLAG > 255
+       xorl    %ecx, %ecx
+#endif
+       cmpl    $-1, dep_mutex-cond_nwaiters(%ebx)
+       sete    %cl
+       subl    $1, %ecx
+#ifdef __ASSUME_PRIVATE_FUTEX
+       andl    $FUTEX_PRIVATE_FLAG, %ecx
+#else
+       andl    %gs:PRIVATE_FUTEX, %ecx
+#endif
+       addl    $FUTEX_WAKE, %ecx
+       movl    $1, %edx
+       ENTER_KERNEL
+       subl    $cond_nwaiters, %ebx
+
+25:    LOCK
+#if cond_lock == 0
+       subl    $1, (%ebx)
+#else
+       subl    $1, cond_lock(%ebx)
+#endif
+       jne     10f
+
+11:    movl    24+FRAME_SIZE(%esp), %eax
+       /* With requeue_pi, the mutex lock is held in the kernel.  */
+       movl    24(%esp), %ecx
+       testl   %ecx, %ecx
+       jnz     27f
+
+       call    __pthread_mutex_cond_lock
+26:    addl    $FRAME_SIZE, %esp
+       cfi_adjust_cfa_offset(-FRAME_SIZE);
+
+       /* We return the result of the mutex_lock operation if it failed.  */
+       testl   %eax, %eax
+#ifdef HAVE_CMOV
+       cmovel  %esi, %eax
+#else
+       jne     22f
+       movl    %esi, %eax
+22:
+#endif
+
+18:    popl    %ebx
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%ebx)
+       popl    %esi
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%esi)
+       popl    %edi
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%edi)
+       popl    %ebp
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%ebp)
+
+       ret
+
+       cfi_restore_state
+
+27:    call    __pthread_mutex_cond_lock_adjust
+       xorl    %eax, %eax
+       jmp     26b
+
+       cfi_adjust_cfa_offset(-FRAME_SIZE);
+       /* Initial locking failed.  */
+1:
+#if cond_lock == 0
+       movl    %ebx, %edx
+#else
+       leal    cond_lock(%ebx), %edx
+#endif
+#if (LLL_SHARED-LLL_PRIVATE) > 255
+       xorl    %ecx, %ecx
+#endif
+       cmpl    $-1, dep_mutex(%ebx)
+       setne   %cl
+       subl    $1, %ecx
+       andl    $(LLL_SHARED-LLL_PRIVATE), %ecx
+#if LLL_PRIVATE != 0
+       addl    $LLL_PRIVATE, %ecx
+#endif
+       call    __lll_lock_wait
+       jmp     2b
+
+       /* The initial unlocking of the mutex failed.  */
+16:
+       LOCK
+#if cond_lock == 0
+       subl    $1, (%ebx)
+#else
+       subl    $1, cond_lock(%ebx)
+#endif
+       jne     18b
+
+       movl    %eax, %esi
+#if cond_lock == 0
+       movl    %ebx, %eax
+#else
+       leal    cond_lock(%ebx), %eax
+#endif
+#if (LLL_SHARED-LLL_PRIVATE) > 255
+       xorl    %ecx, %ecx
+#endif
+       cmpl    $-1, dep_mutex(%ebx)
+       setne   %cl
+       subl    $1, %ecx
+       andl    $(LLL_SHARED-LLL_PRIVATE), %ecx
+#if LLL_PRIVATE != 0
+       addl    $LLL_PRIVATE, %ecx
+#endif
+       call    __lll_unlock_wake
+
+       movl    %esi, %eax
+       jmp     18b
+
+       cfi_adjust_cfa_offset(FRAME_SIZE)
+
+       /* Unlock in loop requires wakeup.  */
+3:
+#if cond_lock == 0
+       movl    %ebx, %eax
+#else
+       leal    cond_lock(%ebx), %eax
+#endif
+#if (LLL_SHARED-LLL_PRIVATE) > 255
+       xorl    %ecx, %ecx
+#endif
+       cmpl    $-1, dep_mutex(%ebx)
+       setne   %cl
+       subl    $1, %ecx
+       andl    $(LLL_SHARED-LLL_PRIVATE), %ecx
+#if LLL_PRIVATE != 0
+       addl    $LLL_PRIVATE, %ecx
+#endif
+       call    __lll_unlock_wake
+       jmp     4b
+
+       /* Locking in loop failed.  */
+5:
+#if cond_lock == 0
+       movl    %ebx, %edx
+#else
+       leal    cond_lock(%ebx), %edx
+#endif
+#if (LLL_SHARED-LLL_PRIVATE) > 255
+       xorl    %ecx, %ecx
+#endif
+       cmpl    $-1, dep_mutex(%ebx)
+       setne   %cl
+       subl    $1, %ecx
+       andl    $(LLL_SHARED-LLL_PRIVATE), %ecx
+#if LLL_PRIVATE != 0
+       addl    $LLL_PRIVATE, %ecx
+#endif
+       call    __lll_lock_wait
+       jmp     6b
+
+       /* Unlock after loop requires wakeup.  */
+10:
+#if cond_lock == 0
+       movl    %ebx, %eax
+#else
+       leal    cond_lock(%ebx), %eax
+#endif
+#if (LLL_SHARED-LLL_PRIVATE) > 255
+       xorl    %ecx, %ecx
+#endif
+       cmpl    $-1, dep_mutex(%ebx)
+       setne   %cl
+       subl    $1, %ecx
+       andl    $(LLL_SHARED-LLL_PRIVATE), %ecx
+#if LLL_PRIVATE != 0
+       addl    $LLL_PRIVATE, %ecx
+#endif
+       call    __lll_unlock_wake
+       jmp     11b
+
+#if defined __NR_clock_gettime && !defined __ASSUME_POSIX_TIMERS
+       /* clock_gettime not available.  */
+19:    leal    4(%esp), %ebx
+       xorl    %ecx, %ecx
+       movl    $__NR_gettimeofday, %eax
+       ENTER_KERNEL
+       movl    %edx, %ebx
+
+       /* Compute relative timeout.  */
+       movl    8(%esp), %eax
+       movl    $1000, %edx
+       mul     %edx            /* Milli seconds to nano seconds.  */
+       movl    (%ebp), %ecx
+       movl    4(%ebp), %edx
+       subl    4(%esp), %ecx
+       subl    %eax, %edx
+       jns     20f
+       addl    $1000000000, %edx
+       subl    $1, %ecx
+20:    testl   %ecx, %ecx
+       movl    $-ETIMEDOUT, %esi
+       js      6b
+       jmp     21b
+#endif
+       .size   __pthread_cond_timedwait, .-__pthread_cond_timedwait
+weak_alias(__pthread_cond_timedwait, pthread_cond_timedwait)
+
+
+       .type   __condvar_tw_cleanup2, @function
+__condvar_tw_cleanup2:
+       subl    $cond_futex, %ebx
+       .size   __condvar_tw_cleanup2, .-__condvar_tw_cleanup2
+       .type   __condvar_tw_cleanup, @function
+__condvar_tw_cleanup:
+       movl    %eax, %esi
+
+       /* Get internal lock.  */
+       movl    $1, %edx
+       xorl    %eax, %eax
+       LOCK
+#if cond_lock == 0
+       cmpxchgl %edx, (%ebx)
+#else
+       cmpxchgl %edx, cond_lock(%ebx)
+#endif
+       jz      1f
+
+#if cond_lock == 0
+       movl    %ebx, %edx
+#else
+       leal    cond_lock(%ebx), %edx
+#endif
+#if (LLL_SHARED-LLL_PRIVATE) > 255
+       xorl    %ecx, %ecx
+#endif
+       cmpl    $-1, dep_mutex(%ebx)
+       setne   %cl
+       subl    $1, %ecx
+       andl    $(LLL_SHARED-LLL_PRIVATE), %ecx
+#if LLL_PRIVATE != 0
+       addl    $LLL_PRIVATE, %ecx
+#endif
+       call    __lll_lock_wait
+
+1:     movl    broadcast_seq(%ebx), %eax
+       cmpl    20(%esp), %eax
+       jne     3f
+
+       /* We increment the wakeup_seq counter only if it is lower than
+          total_seq.  If this is not the case the thread was woken and
+          then canceled.  In this case we ignore the signal.  */
+       movl    total_seq(%ebx), %eax
+       movl    total_seq+4(%ebx), %edi
+       cmpl    wakeup_seq+4(%ebx), %edi
+       jb      6f
+       ja      7f
+       cmpl    wakeup_seq(%ebx), %eax
+       jbe     7f
+
+6:     addl    $1, wakeup_seq(%ebx)
+       adcl    $0, wakeup_seq+4(%ebx)
+       addl    $1, cond_futex(%ebx)
+
+7:     addl    $1, woken_seq(%ebx)
+       adcl    $0, woken_seq+4(%ebx)
+
+3:     subl    $(1 << nwaiters_shift), cond_nwaiters(%ebx)
+
+       /* Wake up a thread which wants to destroy the condvar object.  */
+       xorl    %edi, %edi
+       movl    total_seq(%ebx), %eax
+       andl    total_seq+4(%ebx), %eax
+       cmpl    $0xffffffff, %eax
+       jne     4f
+       movl    cond_nwaiters(%ebx), %eax
+       andl    $~((1 << nwaiters_shift) - 1), %eax
+       jne     4f
+
+       addl    $cond_nwaiters, %ebx
+       movl    $SYS_futex, %eax
+#if FUTEX_PRIVATE_FLAG > 255
+       xorl    %ecx, %ecx
+#endif
+       cmpl    $-1, dep_mutex-cond_nwaiters(%ebx)
+       sete    %cl
+       subl    $1, %ecx
+#ifdef __ASSUME_PRIVATE_FUTEX
+       andl    $FUTEX_PRIVATE_FLAG, %ecx
+#else
+       andl    %gs:PRIVATE_FUTEX, %ecx
+#endif
+       addl    $FUTEX_WAKE, %ecx
+       movl    $1, %edx
+       ENTER_KERNEL
+       subl    $cond_nwaiters, %ebx
+       movl    $1, %edi
+
+4:     LOCK
+#if cond_lock == 0
+       subl    $1, (%ebx)
+#else
+       subl    $1, cond_lock(%ebx)
+#endif
+       je      2f
+
+#if cond_lock == 0
+       movl    %ebx, %eax
+#else
+       leal    cond_lock(%ebx), %eax
+#endif
+#if (LLL_SHARED-LLL_PRIVATE) > 255
+       xorl    %ecx, %ecx
+#endif
+       cmpl    $-1, dep_mutex(%ebx)
+       setne   %cl
+       subl    $1, %ecx
+       andl    $(LLL_SHARED-LLL_PRIVATE), %ecx
+#if LLL_PRIVATE != 0
+       addl    $LLL_PRIVATE, %ecx
+#endif
+       call    __lll_unlock_wake
+
+       /* Wake up all waiters to make sure no signal gets lost.  */
+2:     testl   %edi, %edi
+       jnz     5f
+       addl    $cond_futex, %ebx
+#if FUTEX_PRIVATE_FLAG > 255
+       xorl    %ecx, %ecx
+#endif
+       cmpl    $-1, dep_mutex-cond_futex(%ebx)
+       sete    %cl
+       subl    $1, %ecx
+#ifdef __ASSUME_PRIVATE_FUTEX
+       andl    $FUTEX_PRIVATE_FLAG, %ecx
+#else
+       andl    %gs:PRIVATE_FUTEX, %ecx
+#endif
+       addl    $FUTEX_WAKE, %ecx
+       movl    $SYS_futex, %eax
+       movl    $0x7fffffff, %edx
+       ENTER_KERNEL
+
+5:     movl    24+FRAME_SIZE(%esp), %eax
+       call    __pthread_mutex_cond_lock
+
+       movl    %esi, (%esp)
+.LcallUR:
+       call    _Unwind_Resume
+       hlt
+.LENDCODE:
+       cfi_endproc
+       .size   __condvar_tw_cleanup, .-__condvar_tw_cleanup
+
+
+       .section .gcc_except_table,"a",@progbits
+.LexceptSTART:
+       .byte   DW_EH_PE_omit                   # @LPStart format (omit)
+       .byte   DW_EH_PE_omit                   # @TType format (omit)
+       .byte   DW_EH_PE_sdata4                 # call-site format
+                                               # DW_EH_PE_sdata4
+       .uleb128 .Lcstend-.Lcstbegin
+.Lcstbegin:
+       .long   .LcleanupSTART-.LSTARTCODE
+       .long   .Ladd_cond_futex-.LcleanupSTART
+       .long   __condvar_tw_cleanup-.LSTARTCODE
+       .uleb128  0
+       .long   .Ladd_cond_futex-.LSTARTCODE
+       .long   .Lsub_cond_futex-.Ladd_cond_futex
+       .long   __condvar_tw_cleanup2-.LSTARTCODE
+       .uleb128  0
+       .long   .Lsub_cond_futex-.LSTARTCODE
+       .long   .LcleanupEND-.Lsub_cond_futex
+       .long   __condvar_tw_cleanup-.LSTARTCODE
+       .uleb128  0
+       .long   .LcallUR-.LSTARTCODE
+       .long   .LENDCODE-.LcallUR
+       .long   0
+       .uleb128  0
+.Lcstend:
+
+
+#ifdef SHARED
+       .hidden DW.ref.__gcc_personality_v0
+       .weak   DW.ref.__gcc_personality_v0
+       .section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits
+       .align  4
+       .type   DW.ref.__gcc_personality_v0, @object
+       .size   DW.ref.__gcc_personality_v0, 4
+DW.ref.__gcc_personality_v0:
+       .long   __gcc_personality_v0
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S
new file mode 100644 (file)
index 0000000..6261805
--- /dev/null
@@ -0,0 +1,590 @@
+/* Copyright (C) 2002-2004,2006-2007,2009,2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <lowlevelcond.h>
+#include <tcb-offsets.h>
+#include <pthread-errnos.h>
+#include <pthread-pi-defines.h>
+#include <bits/kernel-features.h>
+
+
+       .text
+
+/* int pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex)  */
+       .globl  __pthread_cond_wait
+       .type   __pthread_cond_wait, @function
+       .align  16
+__pthread_cond_wait:
+.LSTARTCODE:
+       cfi_startproc
+#ifdef SHARED
+       cfi_personality(DW_EH_PE_pcrel | DW_EH_PE_sdata4 | DW_EH_PE_indirect,
+                       DW.ref.__gcc_personality_v0)
+       cfi_lsda(DW_EH_PE_pcrel | DW_EH_PE_sdata4, .LexceptSTART)
+#else
+       cfi_personality(DW_EH_PE_udata4, __gcc_personality_v0)
+       cfi_lsda(DW_EH_PE_udata4, .LexceptSTART)
+#endif
+
+       pushl   %ebp
+       cfi_adjust_cfa_offset(4)
+       cfi_rel_offset(%ebp, 0)
+       pushl   %edi
+       cfi_adjust_cfa_offset(4)
+       cfi_rel_offset(%edi, 0)
+       pushl   %esi
+       cfi_adjust_cfa_offset(4)
+       cfi_rel_offset(%esi, 0)
+       pushl   %ebx
+       cfi_adjust_cfa_offset(4)
+       cfi_rel_offset(%ebx, 0)
+
+       xorl    %esi, %esi
+       movl    20(%esp), %ebx
+
+       /* Get internal lock.  */
+       movl    $1, %edx
+       xorl    %eax, %eax
+       LOCK
+#if cond_lock == 0
+       cmpxchgl %edx, (%ebx)
+#else
+       cmpxchgl %edx, cond_lock(%ebx)
+#endif
+       jnz     1f
+
+       /* Store the reference to the mutex.  If there is already a
+          different value in there this is a bad user bug.  */
+2:     cmpl    $-1, dep_mutex(%ebx)
+       movl    24(%esp), %eax
+       je      15f
+       movl    %eax, dep_mutex(%ebx)
+
+       /* Unlock the mutex.  */
+15:    xorl    %edx, %edx
+       call    __pthread_mutex_unlock_usercnt
+
+       testl   %eax, %eax
+       jne     12f
+
+       addl    $1, total_seq(%ebx)
+       adcl    $0, total_seq+4(%ebx)
+       addl    $1, cond_futex(%ebx)
+       addl    $(1 << nwaiters_shift), cond_nwaiters(%ebx)
+
+#define FRAME_SIZE 20
+       subl    $FRAME_SIZE, %esp
+       cfi_adjust_cfa_offset(FRAME_SIZE)
+       cfi_remember_state
+
+       /* Get and store current wakeup_seq value.  */
+       movl    wakeup_seq(%ebx), %edi
+       movl    wakeup_seq+4(%ebx), %edx
+       movl    broadcast_seq(%ebx), %eax
+       movl    %edi, 4(%esp)
+       movl    %edx, 8(%esp)
+       movl    %eax, 12(%esp)
+
+       /* Reset the pi-requeued flag.  */
+8:     movl    $0, 16(%esp)
+       movl    cond_futex(%ebx), %ebp
+
+       /* Unlock.  */
+       LOCK
+#if cond_lock == 0
+       subl    $1, (%ebx)
+#else
+       subl    $1, cond_lock(%ebx)
+#endif
+       jne     3f
+
+.LcleanupSTART:
+4:     call    __pthread_enable_asynccancel
+       movl    %eax, (%esp)
+
+       xorl    %ecx, %ecx
+       cmpl    $-1, dep_mutex(%ebx)
+       sete    %cl
+       je      18f
+
+       movl    dep_mutex(%ebx), %edi
+       /* Requeue to a non-robust PI mutex if the PI bit is set and
+          the robust bit is not set.  */
+       movl    MUTEX_KIND(%edi), %eax
+       andl    $(ROBUST_BIT|PI_BIT), %eax
+       cmpl    $PI_BIT, %eax
+       jne     18f
+
+       movl    $(FUTEX_WAIT_REQUEUE_PI|FUTEX_PRIVATE_FLAG), %ecx
+       movl    %ebp, %edx
+       xorl    %esi, %esi
+       addl    $cond_futex, %ebx
+       movl    $SYS_futex, %eax
+       ENTER_KERNEL
+       subl    $cond_futex, %ebx
+       /* Set the pi-requeued flag only if the kernel has returned 0. The
+          kernel does not hold the mutex on error.  */
+       cmpl    $0, %eax
+       sete    16(%esp)
+       je      19f
+
+       /* Normal and PI futexes dont mix. Use normal futex functions only
+          if the kernel does not support the PI futex functions.  */
+       cmpl    $-ENOSYS, %eax
+       jne     19f
+       xorl    %ecx, %ecx
+
+18:    subl    $1, %ecx
+#ifdef __ASSUME_PRIVATE_FUTEX
+       andl    $FUTEX_PRIVATE_FLAG, %ecx
+#else
+       andl    %gs:PRIVATE_FUTEX, %ecx
+#endif
+#if FUTEX_WAIT != 0
+       addl    $FUTEX_WAIT, %ecx
+#endif
+       movl    %ebp, %edx
+       addl    $cond_futex, %ebx
+.Ladd_cond_futex:
+       movl    $SYS_futex, %eax
+       ENTER_KERNEL
+       subl    $cond_futex, %ebx
+.Lsub_cond_futex:
+
+19:    movl    (%esp), %eax
+       call    __pthread_disable_asynccancel
+.LcleanupEND:
+
+       /* Lock.  */
+       movl    $1, %edx
+       xorl    %eax, %eax
+       LOCK
+#if cond_lock == 0
+       cmpxchgl %edx, (%ebx)
+#else
+       cmpxchgl %edx, cond_lock(%ebx)
+#endif
+       jnz     5f
+
+6:     movl    broadcast_seq(%ebx), %eax
+       cmpl    12(%esp), %eax
+       jne     16f
+
+       movl    woken_seq(%ebx), %eax
+       movl    woken_seq+4(%ebx), %ecx
+
+       movl    wakeup_seq(%ebx), %edi
+       movl    wakeup_seq+4(%ebx), %edx
+
+       cmpl    8(%esp), %edx
+       jne     7f
+       cmpl    4(%esp), %edi
+       je      8b
+
+7:     cmpl    %ecx, %edx
+       jne     9f
+       cmp     %eax, %edi
+       je      8b
+
+9:     addl    $1, woken_seq(%ebx)
+       adcl    $0, woken_seq+4(%ebx)
+
+       /* Unlock */
+16:    subl    $(1 << nwaiters_shift), cond_nwaiters(%ebx)
+
+       /* Wake up a thread which wants to destroy the condvar object.  */
+       movl    total_seq(%ebx), %eax
+       andl    total_seq+4(%ebx), %eax
+       cmpl    $0xffffffff, %eax
+       jne     17f
+       movl    cond_nwaiters(%ebx), %eax
+       andl    $~((1 << nwaiters_shift) - 1), %eax
+       jne     17f
+
+       addl    $cond_nwaiters, %ebx
+       movl    $SYS_futex, %eax
+#if FUTEX_PRIVATE_FLAG > 255
+       xorl    %ecx, %ecx
+#endif
+       cmpl    $-1, dep_mutex-cond_nwaiters(%ebx)
+       sete    %cl
+       subl    $1, %ecx
+#ifdef __ASSUME_PRIVATE_FUTEX
+       andl    $FUTEX_PRIVATE_FLAG, %ecx
+#else
+       andl    %gs:PRIVATE_FUTEX, %ecx
+#endif
+       addl    $FUTEX_WAKE, %ecx
+       movl    $1, %edx
+       ENTER_KERNEL
+       subl    $cond_nwaiters, %ebx
+
+17:    LOCK
+#if cond_lock == 0
+       subl    $1, (%ebx)
+#else
+       subl    $1, cond_lock(%ebx)
+#endif
+       jne     10f
+
+       /* With requeue_pi, the mutex lock is held in the kernel.  */
+11:    movl    24+FRAME_SIZE(%esp), %eax
+       movl    16(%esp), %ecx
+       testl   %ecx, %ecx
+       jnz     21f
+
+       call    __pthread_mutex_cond_lock
+20:    addl    $FRAME_SIZE, %esp
+       cfi_adjust_cfa_offset(-FRAME_SIZE);
+
+14:    popl    %ebx
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%ebx)
+       popl    %esi
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%esi)
+       popl    %edi
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%edi)
+       popl    %ebp
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%ebp)
+
+       /* We return the result of the mutex_lock operation.  */
+       ret
+
+       cfi_restore_state
+
+21:    call    __pthread_mutex_cond_lock_adjust
+       xorl    %eax, %eax
+       jmp     20b
+
+       cfi_adjust_cfa_offset(-FRAME_SIZE);
+       /* Initial locking failed.  */
+1:
+#if cond_lock == 0
+       movl    %ebx, %edx
+#else
+       leal    cond_lock(%ebx), %edx
+#endif
+#if (LLL_SHARED-LLL_PRIVATE) > 255
+       xorl    %ecx, %ecx
+#endif
+       cmpl    $-1, dep_mutex(%ebx)
+       setne   %cl
+       subl    $1, %ecx
+       andl    $(LLL_SHARED-LLL_PRIVATE), %ecx
+#if LLL_PRIVATE != 0
+       addl    $LLL_PRIVATE, %ecx
+#endif
+       call    __lll_lock_wait
+       jmp     2b
+
+       /* The initial unlocking of the mutex failed.  */
+12:
+       LOCK
+#if cond_lock == 0
+       subl    $1, (%ebx)
+#else
+       subl    $1, cond_lock(%ebx)
+#endif
+       jne     14b
+
+       movl    %eax, %esi
+#if cond_lock == 0
+       movl    %ebx, %eax
+#else
+       leal    cond_lock(%ebx), %eax
+#endif
+#if (LLL_SHARED-LLL_PRIVATE) > 255
+       xorl    %ecx, %ecx
+#endif
+       cmpl    $-1, dep_mutex(%ebx)
+       setne   %cl
+       subl    $1, %ecx
+       andl    $(LLL_SHARED-LLL_PRIVATE), %ecx
+#if LLL_PRIVATE != 0
+       addl    $LLL_PRIVATE, %ecx
+#endif
+       call    __lll_unlock_wake
+
+       movl    %esi, %eax
+       jmp     14b
+
+       cfi_adjust_cfa_offset(FRAME_SIZE)
+
+       /* Unlock in loop requires wakeup.  */
+3:
+#if cond_lock == 0
+       movl    %ebx, %eax
+#else
+       leal    cond_lock(%ebx), %eax
+#endif
+#if (LLL_SHARED-LLL_PRIVATE) > 255
+       xorl    %ecx, %ecx
+#endif
+       cmpl    $-1, dep_mutex(%ebx)
+       setne   %cl
+       subl    $1, %ecx
+       andl    $(LLL_SHARED-LLL_PRIVATE), %ecx
+#if LLL_PRIVATE != 0
+       addl    $LLL_PRIVATE, %ecx
+#endif
+       call    __lll_unlock_wake
+       jmp     4b
+
+       /* Locking in loop failed.  */
+5:
+#if cond_lock == 0
+       movl    %ebx, %edx
+#else
+       leal    cond_lock(%ebx), %edx
+#endif
+#if (LLL_SHARED-LLL_PRIVATE) > 255
+       xorl    %ecx, %ecx
+#endif
+       cmpl    $-1, dep_mutex(%ebx)
+       setne   %cl
+       subl    $1, %ecx
+       andl    $(LLL_SHARED-LLL_PRIVATE), %ecx
+#if LLL_PRIVATE != 0
+       addl    $LLL_PRIVATE, %ecx
+#endif
+       call    __lll_lock_wait
+       jmp     6b
+
+       /* Unlock after loop requires wakeup.  */
+10:
+#if cond_lock == 0
+       movl    %ebx, %eax
+#else
+       leal    cond_lock(%ebx), %eax
+#endif
+#if (LLL_SHARED-LLL_PRIVATE) > 255
+       xorl    %ecx, %ecx
+#endif
+       cmpl    $-1, dep_mutex(%ebx)
+       setne   %cl
+       subl    $1, %ecx
+       andl    $(LLL_SHARED-LLL_PRIVATE), %ecx
+#if LLL_PRIVATE != 0
+       addl    $LLL_PRIVATE, %ecx
+#endif
+       call    __lll_unlock_wake
+       jmp     11b
+       .size   __pthread_cond_wait, .-__pthread_cond_wait
+weak_alias(__pthread_cond_wait, pthread_cond_wait)
+
+
+       .type   __condvar_w_cleanup2, @function
+__condvar_w_cleanup2:
+       subl    $cond_futex, %ebx
+       .size   __condvar_w_cleanup2, .-__condvar_w_cleanup2
+.LSbl4:
+       .type   __condvar_w_cleanup, @function
+__condvar_w_cleanup:
+       movl    %eax, %esi
+
+       /* Get internal lock.  */
+       movl    $1, %edx
+       xorl    %eax, %eax
+       LOCK
+#if cond_lock == 0
+       cmpxchgl %edx, (%ebx)
+#else
+       cmpxchgl %edx, cond_lock(%ebx)
+#endif
+       jz      1f
+
+#if cond_lock == 0
+       movl    %ebx, %edx
+#else
+       leal    cond_lock(%ebx), %edx
+#endif
+#if (LLL_SHARED-LLL_PRIVATE) > 255
+       xorl    %ecx, %ecx
+#endif
+       cmpl    $-1, dep_mutex(%ebx)
+       setne   %cl
+       subl    $1, %ecx
+       andl    $(LLL_SHARED-LLL_PRIVATE), %ecx
+#if LLL_PRIVATE != 0
+       addl    $LLL_PRIVATE, %ecx
+#endif
+       call    __lll_lock_wait
+
+1:     movl    broadcast_seq(%ebx), %eax
+       cmpl    12(%esp), %eax
+       jne     3f
+
+       /* We increment the wakeup_seq counter only if it is lower than
+          total_seq.  If this is not the case the thread was woken and
+          then canceled.  In this case we ignore the signal.  */
+       movl    total_seq(%ebx), %eax
+       movl    total_seq+4(%ebx), %edi
+       cmpl    wakeup_seq+4(%ebx), %edi
+       jb      6f
+       ja      7f
+       cmpl    wakeup_seq(%ebx), %eax
+       jbe     7f
+
+6:     addl    $1, wakeup_seq(%ebx)
+       adcl    $0, wakeup_seq+4(%ebx)
+       addl    $1, cond_futex(%ebx)
+
+7:     addl    $1, woken_seq(%ebx)
+       adcl    $0, woken_seq+4(%ebx)
+
+3:     subl    $(1 << nwaiters_shift), cond_nwaiters(%ebx)
+
+       /* Wake up a thread which wants to destroy the condvar object.  */
+       xorl    %edi, %edi
+       movl    total_seq(%ebx), %eax
+       andl    total_seq+4(%ebx), %eax
+       cmpl    $0xffffffff, %eax
+       jne     4f
+       movl    cond_nwaiters(%ebx), %eax
+       andl    $~((1 << nwaiters_shift) - 1), %eax
+       jne     4f
+
+       addl    $cond_nwaiters, %ebx
+       movl    $SYS_futex, %eax
+#if FUTEX_PRIVATE_FLAG > 255
+       xorl    %ecx, %ecx
+#endif
+       cmpl    $-1, dep_mutex-cond_nwaiters(%ebx)
+       sete    %cl
+       subl    $1, %ecx
+#ifdef __ASSUME_PRIVATE_FUTEX
+       andl    $FUTEX_PRIVATE_FLAG, %ecx
+#else
+       andl    %gs:PRIVATE_FUTEX, %ecx
+#endif
+       addl    $FUTEX_WAKE, %ecx
+       movl    $1, %edx
+       ENTER_KERNEL
+       subl    $cond_nwaiters, %ebx
+       movl    $1, %edi
+
+4:     LOCK
+#if cond_lock == 0
+       subl    $1, (%ebx)
+#else
+       subl    $1, cond_lock(%ebx)
+#endif
+       je      2f
+
+#if cond_lock == 0
+       movl    %ebx, %eax
+#else
+       leal    cond_lock(%ebx), %eax
+#endif
+#if (LLL_SHARED-LLL_PRIVATE) > 255
+       xorl    %ecx, %ecx
+#endif
+       cmpl    $-1, dep_mutex(%ebx)
+       setne   %cl
+       subl    $1, %ecx
+       andl    $(LLL_SHARED-LLL_PRIVATE), %ecx
+#if LLL_PRIVATE != 0
+       addl    $LLL_PRIVATE, %ecx
+#endif
+       call    __lll_unlock_wake
+
+       /* Wake up all waiters to make sure no signal gets lost.  */
+2:     testl   %edi, %edi
+       jnz     5f
+       addl    $cond_futex, %ebx
+#if FUTEX_PRIVATE_FLAG > 255
+       xorl    %ecx, %ecx
+#endif
+       cmpl    $-1, dep_mutex-cond_futex(%ebx)
+       sete    %cl
+       subl    $1, %ecx
+#ifdef __ASSUME_PRIVATE_FUTEX
+       andl    $FUTEX_PRIVATE_FLAG, %ecx
+#else
+       andl    %gs:PRIVATE_FUTEX, %ecx
+#endif
+       addl    $FUTEX_WAKE, %ecx
+       movl    $SYS_futex, %eax
+       movl    $0x7fffffff, %edx
+       ENTER_KERNEL
+
+5:     movl    24+FRAME_SIZE(%esp), %eax
+       call    __pthread_mutex_cond_lock
+
+       movl    %esi, (%esp)
+.LcallUR:
+       call    _Unwind_Resume
+       hlt
+.LENDCODE:
+       cfi_endproc
+       .size   __condvar_w_cleanup, .-__condvar_w_cleanup
+
+
+       .section .gcc_except_table,"a",@progbits
+.LexceptSTART:
+       .byte   DW_EH_PE_omit                   # @LPStart format (omit)
+       .byte   DW_EH_PE_omit                   # @TType format (omit)
+       .byte   DW_EH_PE_sdata4                 # call-site format
+                                               # DW_EH_PE_sdata4
+       .uleb128 .Lcstend-.Lcstbegin
+.Lcstbegin:
+       .long   .LcleanupSTART-.LSTARTCODE
+       .long   .Ladd_cond_futex-.LcleanupSTART
+       .long   __condvar_w_cleanup-.LSTARTCODE
+       .uleb128  0
+       .long   .Ladd_cond_futex-.LSTARTCODE
+       .long   .Lsub_cond_futex-.Ladd_cond_futex
+       .long   __condvar_w_cleanup2-.LSTARTCODE
+       .uleb128  0
+       .long   .Lsub_cond_futex-.LSTARTCODE
+       .long   .LcleanupEND-.Lsub_cond_futex
+       .long   __condvar_w_cleanup-.LSTARTCODE
+       .uleb128  0
+       .long   .LcallUR-.LSTARTCODE
+       .long   .LENDCODE-.LcallUR
+       .long   0
+       .uleb128  0
+.Lcstend:
+
+#ifdef __PIC__
+       .section .gnu.linkonce.t.__i686.get_pc_thunk.cx,"ax",@progbits
+       .globl  __i686.get_pc_thunk.cx
+       .hidden __i686.get_pc_thunk.cx
+       .type   __i686.get_pc_thunk.cx,@function
+__i686.get_pc_thunk.cx:
+       movl (%esp), %ecx;
+       ret
+       .size   __i686.get_pc_thunk.cx,.-__i686.get_pc_thunk.cx
+#endif
+
+#ifdef SHARED
+       .hidden DW.ref.__gcc_personality_v0
+       .weak   DW.ref.__gcc_personality_v0
+       .section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits
+       .align 4
+       .type   DW.ref.__gcc_personality_v0, @object
+       .size   DW.ref.__gcc_personality_v0, 4
+DW.ref.__gcc_personality_v0:
+       .long   __gcc_personality_v0
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_rdlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_rdlock.S
new file mode 100644 (file)
index 0000000..6205a60
--- /dev/null
@@ -0,0 +1,194 @@
+/* Copyright (C) 2002, 2003, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <lowlevelrwlock.h>
+#include <pthread-errnos.h>
+#include <bits/kernel-features.h>
+#include <tls.h>
+
+
+       .text
+
+       .globl  __pthread_rwlock_rdlock
+       .type   __pthread_rwlock_rdlock,@function
+       .align  16
+__pthread_rwlock_rdlock:
+       cfi_startproc
+       pushl   %esi
+       cfi_adjust_cfa_offset(4)
+       pushl   %ebx
+       cfi_adjust_cfa_offset(4)
+       cfi_offset(%esi, -8)
+       cfi_offset(%ebx, -12)
+
+       xorl    %esi, %esi
+       movl    12(%esp), %ebx
+
+       /* Get the lock.  */
+       movl    $1, %edx
+       xorl    %eax, %eax
+       LOCK
+#if MUTEX == 0
+       cmpxchgl %edx, (%ebx)
+#else
+       cmpxchgl %edx, MUTEX(%ebx)
+#endif
+       jnz     1f
+
+2:     movl    WRITER(%ebx), %eax
+       testl   %eax, %eax
+       jne     14f
+       cmpl    $0, WRITERS_QUEUED(%ebx)
+       je      5f
+       cmpb    $0, FLAGS(%ebx)
+       je      5f
+
+3:     addl    $1, READERS_QUEUED(%ebx)
+       je      4f
+
+       movl    READERS_WAKEUP(%ebx), %edx
+
+       LOCK
+#if MUTEX == 0
+       subl    $1, (%ebx)
+#else
+       subl    $1, MUTEX(%ebx)
+#endif
+       jne     10f
+
+11:
+#ifdef __ASSUME_PRIVATE_FUTEX
+       movzbl  PSHARED(%ebx), %ecx
+       xorl    $FUTEX_PRIVATE_FLAG|FUTEX_WAIT, %ecx
+#else
+       movzbl  PSHARED(%ebx), %ecx
+# if FUTEX_WAIT != 0
+       orl     $FUTEX_WAIT, %ecx
+# endif
+       xorl    %gs:PRIVATE_FUTEX, %ecx
+#endif
+       addl    $READERS_WAKEUP, %ebx
+       movl    $SYS_futex, %eax
+       ENTER_KERNEL
+
+       subl    $READERS_WAKEUP, %ebx
+
+       /* Reget the lock.  */
+       movl    $1, %edx
+       xorl    %eax, %eax
+       LOCK
+#if MUTEX == 0
+       cmpxchgl %edx, (%ebx)
+#else
+       cmpxchgl %edx, MUTEX(%ebx)
+#endif
+       jnz     12f
+
+13:    subl    $1, READERS_QUEUED(%ebx)
+       jmp     2b
+
+5:     xorl    %edx, %edx
+       addl    $1, NR_READERS(%ebx)
+       je      8f
+9:     LOCK
+#if MUTEX == 0
+       subl    $1, (%ebx)
+#else
+       subl    $1, MUTEX(%ebx)
+#endif
+       jne     6f
+7:
+
+       movl    %edx, %eax
+       popl    %ebx
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%ebx)
+       popl    %esi
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%esi)
+       ret
+
+       cfi_adjust_cfa_offset(8)
+       cfi_offset(%esi, -8)
+       cfi_offset(%ebx, -12)
+1:
+#if MUTEX == 0
+       movl    %ebx, %edx
+#else
+       leal    MUTEX(%ebx), %edx
+#endif
+       movzbl  PSHARED(%ebx), %ecx
+       call    __lll_lock_wait
+       jmp     2b
+
+14:    cmpl    %gs:TID, %eax
+       jne     3b
+       /* Deadlock detected.  */
+       movl    $EDEADLK, %edx
+       jmp     9b
+
+6:
+#if MUTEX == 0
+       movl    %ebx, %eax
+#else
+       leal    MUTEX(%ebx), %eax
+#endif
+       movzbl  PSHARED(%ebx), %ecx
+       call    __lll_unlock_wake
+       jmp     7b
+
+       /* Overflow.  */
+8:     subl    $1, NR_READERS(%ebx)
+       movl    $EAGAIN, %edx
+       jmp     9b
+
+       /* Overflow.  */
+4:     subl    $1, READERS_QUEUED(%ebx)
+       movl    $EAGAIN, %edx
+       jmp     9b
+
+10:
+#if MUTEX == 0
+       movl    %ebx, %eax
+#else
+       leal    MUTEX(%ebx), %eax
+#endif
+       movzbl  PSHARED(%ebx), %ecx
+       call    __lll_unlock_wake
+       jmp     11b
+
+12:
+#if MUTEX == 0
+       movl    %ebx, %edx
+#else
+       leal    MUTEX(%ebx), %edx
+#endif
+       movzbl  PSHARED(%ebx), %ecx
+       call    __lll_lock_wait
+       jmp     13b
+       cfi_endproc
+       .size   __pthread_rwlock_rdlock,.-__pthread_rwlock_rdlock
+
+       .globl  pthread_rwlock_rdlock
+pthread_rwlock_rdlock = __pthread_rwlock_rdlock
+
+       .globl  __pthread_rwlock_rdlock_internal
+__pthread_rwlock_rdlock_internal = __pthread_rwlock_rdlock
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedrdlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedrdlock.S
new file mode 100644 (file)
index 0000000..be4530e
--- /dev/null
@@ -0,0 +1,245 @@
+/* Copyright (C) 2002, 2003, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <lowlevelrwlock.h>
+#include <pthread-errnos.h>
+#include <bits/kernel-features.h>
+#include <tls.h>
+
+
+       .text
+
+       .globl  pthread_rwlock_timedrdlock
+       .type   pthread_rwlock_timedrdlock,@function
+       .align  16
+pthread_rwlock_timedrdlock:
+       cfi_startproc
+       pushl   %esi
+       cfi_adjust_cfa_offset(4)
+       pushl   %edi
+       cfi_adjust_cfa_offset(4)
+       pushl   %ebx
+       cfi_adjust_cfa_offset(4)
+       pushl   %ebp
+       cfi_adjust_cfa_offset(4)
+       cfi_offset(%esi, -8)
+       cfi_offset(%edi, -12)
+       cfi_offset(%ebx, -16)
+       cfi_offset(%ebp, -20)
+       subl    $8, %esp
+       cfi_adjust_cfa_offset(8)
+
+       movl    28(%esp), %ebp
+       movl    32(%esp), %edi
+
+       /* Get the lock.  */
+       movl    $1, %edx
+       xorl    %eax, %eax
+       LOCK
+#if MUTEX == 0
+       cmpxchgl %edx, (%ebp)
+#else
+       cmpxchgl %edx, MUTEX(%ebp)
+#endif
+       jnz     1f
+
+2:     movl    WRITER(%ebp), %eax
+       testl   %eax, %eax
+       jne     14f
+       cmpl    $0, WRITERS_QUEUED(%ebp)
+       je      5f
+       cmpb    $0, FLAGS(%ebp)
+       je      5f
+
+       /* Check the value of the timeout parameter.  */
+3:     cmpl    $1000000000, 4(%edi)
+       jae     19f
+
+       addl    $1, READERS_QUEUED(%ebp)
+       je      4f
+
+       movl    READERS_WAKEUP(%ebp), %esi
+
+       LOCK
+#if MUTEX == 0
+       subl    $1, (%ebp)
+#else
+       subl    $1, MUTEX(%ebp)
+#endif
+       jne     10f
+
+       /* Get current time.  */
+11:    movl    %esp, %ebx
+       xorl    %ecx, %ecx
+       movl    $__NR_gettimeofday, %eax
+       ENTER_KERNEL
+
+       /* Compute relative timeout.  */
+       movl    4(%esp), %eax
+       movl    $1000, %edx
+       mul     %edx            /* Milli seconds to nano seconds.  */
+       movl    (%edi), %ecx
+       movl    4(%edi), %edx
+       subl    (%esp), %ecx
+       subl    %eax, %edx
+       jns     15f
+       addl    $1000000000, %edx
+       subl    $1, %ecx
+15:    testl   %ecx, %ecx
+       js      16f             /* Time is already up.  */
+
+       /* Futex call.  */
+       movl    %ecx, (%esp)    /* Store relative timeout.  */
+       movl    %edx, 4(%esp)
+
+       movl    %esi, %edx
+#ifdef __ASSUME_PRIVATE_FUTEX
+       movzbl  PSHARED(%ebp), %ecx
+       xorl    $FUTEX_PRIVATE_FLAG|FUTEX_WAIT, %ecx
+#else
+       movzbl  PSHARED(%ebp), %ecx
+# if FUTEX_WAIT != 0
+       orl     $FUTEX_WAIT, %ecx
+# endif
+       xorl    %gs:PRIVATE_FUTEX, %ecx
+#endif
+       movl    %esp, %esi
+       leal    READERS_WAKEUP(%ebp), %ebx
+       movl    $SYS_futex, %eax
+       ENTER_KERNEL
+       movl    %eax, %esi
+17:
+
+       /* Reget the lock.  */
+       movl    $1, %edx
+       xorl    %eax, %eax
+       LOCK
+#if MUTEX == 0
+       cmpxchgl %edx, (%ebp)
+#else
+       cmpxchgl %edx, MUTEX(%ebp)
+#endif
+       jnz     12f
+
+13:    subl    $1, READERS_QUEUED(%ebp)
+       cmpl    $-ETIMEDOUT, %esi
+       jne     2b
+
+18:    movl    $ETIMEDOUT, %edx
+       jmp     9f
+
+
+5:     xorl    %edx, %edx
+       addl    $1, NR_READERS(%ebp)
+       je      8f
+9:     LOCK
+#if MUTEX == 0
+       subl    $1, (%ebp)
+#else
+       subl    $1, MUTEX(%ebp)
+#endif
+       jne     6f
+
+7:     movl    %edx, %eax
+
+       addl    $8, %esp
+       cfi_adjust_cfa_offset(-8)
+       popl    %ebp
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%ebp)
+       popl    %ebx
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%ebx)
+       popl    %edi
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%edi)
+       popl    %esi
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%esi)
+       ret
+
+       cfi_adjust_cfa_offset(24)
+       cfi_offset(%esi, -8)
+       cfi_offset(%edi, -12)
+       cfi_offset(%ebx, -16)
+       cfi_offset(%ebp, -20)
+1:
+#if MUTEX == 0
+       movl    %ebp, %edx
+#else
+       leal    MUTEX(%ebp), %edx
+#endif
+       movzbl  PSHARED(%ebp), %ecx
+       call    __lll_lock_wait
+       jmp     2b
+
+14:    cmpl    %gs:TID, %eax
+       jne     3b
+       movl    $EDEADLK, %edx
+       jmp     9b
+
+6:
+#if MUTEX == 0
+       movl    %ebp, %eax
+#else
+       leal    MUTEX(%ebp), %eax
+#endif
+       movzbl  PSHARED(%ebp), %ecx
+       call    __lll_unlock_wake
+       jmp     7b
+
+       /* Overflow.  */
+8:     subl    $1, NR_READERS(%ebp)
+       movl    $EAGAIN, %edx
+       jmp     9b
+
+       /* Overflow.  */
+4:     subl    $1, READERS_QUEUED(%ebp)
+       movl    $EAGAIN, %edx
+       jmp     9b
+
+10:
+#if MUTEX == 0
+       movl    %ebp, %eax
+#else
+       leal    MUTEX(%ebp), %eax
+#endif
+       movzbl  PSHARED(%ebp), %ecx
+       call    __lll_unlock_wake
+       jmp     11b
+
+12:
+#if MUTEX == 0
+       movl    %ebp, %edx
+#else
+       leal    MUTEX(%ebp), %edx
+#endif
+       movzbl  PSHARED(%ebp), %ecx
+       call    __lll_lock_wait
+       jmp     13b
+
+16:    movl    $-ETIMEDOUT, %esi
+       jmp     17b
+
+19:    movl    $EINVAL, %edx
+       jmp     9b
+       cfi_endproc
+       .size   pthread_rwlock_timedrdlock,.-pthread_rwlock_timedrdlock
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedwrlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedwrlock.S
new file mode 100644 (file)
index 0000000..61431ab
--- /dev/null
@@ -0,0 +1,238 @@
+/* Copyright (C) 2002, 2003, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <lowlevelrwlock.h>
+#include <pthread-errnos.h>
+#include <bits/kernel-features.h>
+#include <tls.h>
+
+
+       .text
+
+       .globl  pthread_rwlock_timedwrlock
+       .type   pthread_rwlock_timedwrlock,@function
+       .align  16
+pthread_rwlock_timedwrlock:
+       cfi_startproc
+       pushl   %esi
+       cfi_adjust_cfa_offset(4)
+       pushl   %edi
+       cfi_adjust_cfa_offset(4)
+       pushl   %ebx
+       cfi_adjust_cfa_offset(4)
+       pushl   %ebp
+       cfi_adjust_cfa_offset(4)
+       cfi_offset(%esi, -8)
+       cfi_offset(%edi, -12)
+       cfi_offset(%ebx, -16)
+       cfi_offset(%ebp, -20)
+       subl    $8, %esp
+       cfi_adjust_cfa_offset(8)
+
+       movl    28(%esp), %ebp
+       movl    32(%esp), %edi
+
+       /* Get the lock.  */
+       movl    $1, %edx
+       xorl    %eax, %eax
+       LOCK
+#if MUTEX == 0
+       cmpxchgl %edx, (%ebp)
+#else
+       cmpxchgl %edx, MUTEX(%ebp)
+#endif
+       jnz     1f
+
+2:     movl    WRITER(%ebp), %eax
+       testl   %eax, %eax
+       jne     14f
+       cmpl    $0, NR_READERS(%ebp)
+       je      5f
+
+       /* Check the value of the timeout parameter.  */
+3:     cmpl    $1000000000, 4(%edi)
+       jae     19f
+
+       addl    $1, WRITERS_QUEUED(%ebp)
+       je      4f
+
+       movl    WRITERS_WAKEUP(%ebp), %esi
+
+       LOCK
+#if MUTEX == 0
+       subl    $1, (%ebp)
+#else
+       subl    $1, MUTEX(%ebp)
+#endif
+       jne     10f
+
+       /* Get current time.  */
+11:    movl    %esp, %ebx
+       xorl    %ecx, %ecx
+       movl    $__NR_gettimeofday, %eax
+       ENTER_KERNEL
+
+       /* Compute relative timeout.  */
+       movl    4(%esp), %eax
+       movl    $1000, %edx
+       mul     %edx            /* Milli seconds to nano seconds.  */
+       movl    (%edi), %ecx
+       movl    4(%edi), %edx
+       subl    (%esp), %ecx
+       subl    %eax, %edx
+       jns     15f
+       addl    $1000000000, %edx
+       subl    $1, %ecx
+15:    testl   %ecx, %ecx
+       js      16f             /* Time is already up.  */
+
+       /* Futex call.  */
+       movl    %ecx, (%esp)    /* Store relative timeout.  */
+       movl    %edx, 4(%esp)
+
+       movl    %esi, %edx
+#ifdef __ASSUME_PRIVATE_FUTEX
+       movzbl  PSHARED(%ebp), %ecx
+       xorl    $FUTEX_PRIVATE_FLAG|FUTEX_WAIT, %ecx
+#else
+       movzbl  PSHARED(%ebp), %ecx
+# if FUTEX_WAIT != 0
+       orl     $FUTEX_WAIT, %ecx
+# endif
+       xorl    %gs:PRIVATE_FUTEX, %ecx
+#endif
+       movl    %esp, %esi
+       leal    WRITERS_WAKEUP(%ebp), %ebx
+       movl    $SYS_futex, %eax
+       ENTER_KERNEL
+       movl    %eax, %esi
+17:
+
+       /* Reget the lock.  */
+       movl    $1, %edx
+       xorl    %eax, %eax
+       LOCK
+#if MUTEX == 0
+       cmpxchgl %edx, (%ebp)
+#else
+       cmpxchgl %edx, MUTEX(%ebp)
+#endif
+       jnz     12f
+
+13:    subl    $1, WRITERS_QUEUED(%ebp)
+       cmpl    $-ETIMEDOUT, %esi
+       jne     2b
+
+18:    movl    $ETIMEDOUT, %edx
+       jmp     9f
+
+
+5:     xorl    %edx, %edx
+       movl    %gs:TID, %eax
+       movl    %eax, WRITER(%ebp)
+9:     LOCK
+#if MUTEX == 0
+       subl    $1, (%ebp)
+#else
+       subl    $1, MUTEX(%ebp)
+#endif
+       jne     6f
+
+7:     movl    %edx, %eax
+
+       addl    $8, %esp
+       cfi_adjust_cfa_offset(-8)
+       popl    %ebp
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%ebp)
+       popl    %ebx
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%ebx)
+       popl    %edi
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%edi)
+       popl    %esi
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%esi)
+       ret
+
+       cfi_adjust_cfa_offset(24)
+       cfi_offset(%esi, -8)
+       cfi_offset(%edi, -12)
+       cfi_offset(%ebx, -16)
+       cfi_offset(%ebp, -20)
+1:
+#if MUTEX == 0
+       movl    %ebp, %edx
+#else
+       leal    MUTEX(%ebp), %edx
+#endif
+       movzbl  PSHARED(%ebp), %ecx
+       call    __lll_lock_wait
+       jmp     2b
+
+14:    cmpl    %gs:TID, %eax
+       jne     3b
+20:    movl    $EDEADLK, %edx
+       jmp     9b
+
+6:
+#if MUTEX == 0
+       movl    %ebp, %eax
+#else
+       leal    MUTEX(%ebp), %eax
+#endif
+       movzbl  PSHARED(%ebp), %ecx
+       call    __lll_unlock_wake
+       jmp     7b
+
+       /* Overflow.  */
+4:     subl    $1, WRITERS_QUEUED(%ebp)
+       movl    $EAGAIN, %edx
+       jmp     9b
+
+10:
+#if MUTEX == 0
+       movl    %ebp, %eax
+#else
+       leal    MUTEX(%ebp), %eax
+#endif
+       movzbl  PSHARED(%ebp), %ecx
+       call    __lll_unlock_wake
+       jmp     11b
+
+12:
+#if MUTEX == 0
+       movl    %ebp, %edx
+#else
+       leal    MUTEX(%ebp), %edx
+#endif
+       movzbl  PSHARED(%ebp), %ecx
+       call    __lll_lock_wait
+       jmp     13b
+
+16:    movl    $-ETIMEDOUT, %esi
+       jmp     17b
+
+19:    movl    $EINVAL, %edx
+       jmp     9b
+       cfi_endproc
+       .size   pthread_rwlock_timedwrlock,.-pthread_rwlock_timedwrlock
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_unlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_unlock.S
new file mode 100644 (file)
index 0000000..426ffdc
--- /dev/null
@@ -0,0 +1,156 @@
+/* Copyright (C) 2002, 2003, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <lowlevelrwlock.h>
+#include <bits/kernel-features.h>
+#include <tls.h>
+
+
+       .text
+
+       .globl  __pthread_rwlock_unlock
+       .type   __pthread_rwlock_unlock,@function
+       .align  16
+__pthread_rwlock_unlock:
+       cfi_startproc
+       pushl   %ebx
+       cfi_adjust_cfa_offset(4)
+       pushl   %edi
+       cfi_adjust_cfa_offset(4)
+       cfi_offset(%ebx, -8)
+       cfi_offset(%edi, -12)
+
+       movl    12(%esp), %edi
+
+       /* Get the lock.  */
+       movl    $1, %edx
+       xorl    %eax, %eax
+       LOCK
+#if MUTEX == 0
+       cmpxchgl %edx, (%edi)
+#else
+       cmpxchgl %edx, MUTEX(%edi)
+#endif
+       jnz     1f
+
+2:     cmpl    $0, WRITER(%edi)
+       jne     5f
+       subl    $1, NR_READERS(%edi)
+       jnz     6f
+
+5:     movl    $0, WRITER(%edi)
+
+       movl    $1, %edx
+       leal    WRITERS_WAKEUP(%edi), %ebx
+       cmpl    $0, WRITERS_QUEUED(%edi)
+       jne     0f
+
+       /* If also no readers waiting nothing to do.  */
+       cmpl    $0, READERS_QUEUED(%edi)
+       je      6f
+
+       movl    $0x7fffffff, %edx
+       leal    READERS_WAKEUP(%edi), %ebx
+
+0:     addl    $1, (%ebx)
+       LOCK
+#if MUTEX == 0
+       subl    $1, (%edi)
+#else
+       subl    $1, MUTEX(%edi)
+#endif
+       jne     7f
+
+8:
+#ifdef __ASSUME_PRIVATE_FUTEX
+       movzbl  PSHARED(%edi), %ecx
+       xorl    $FUTEX_PRIVATE_FLAG|FUTEX_WAKE, %ecx
+#else
+       movzbl  PSHARED(%edi), %ecx
+       orl     $FUTEX_WAKE, %ecx
+       xorl    %gs:PRIVATE_FUTEX, %ecx
+#endif
+       movl    $SYS_futex, %eax
+       ENTER_KERNEL
+
+       xorl    %eax, %eax
+       popl    %edi
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%edi)
+       popl    %ebx
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%ebx)
+       ret
+
+       cfi_adjust_cfa_offset(8)
+       cfi_offset(%ebx, -8)
+       cfi_offset(%edi, -12)
+       .align  16
+6:     LOCK
+#if MUTEX == 0
+       subl    $1, (%edi)
+#else
+       subl    $1, MUTEX(%edi)
+#endif
+       jne     3f
+
+4:     xorl    %eax, %eax
+       popl    %edi
+       popl    %ebx
+       ret
+
+1:
+#if MUTEX == 0
+       movl    %edi, %edx
+#else
+       leal    MUTEX(%edi), %edx
+#endif
+       movzbl  PSHARED(%edi), %ecx
+       call    __lll_lock_wait
+       jmp     2b
+
+3:
+#if MUTEX == 0
+       movl    %edi, %eax
+#else
+       leal    MUTEX(%edi), %eax
+#endif
+       movzbl  PSHARED(%edi), %ecx
+       call    __lll_unlock_wake
+       jmp     4b
+
+7:
+#if MUTEX == 0
+       movl    %edi, %eax
+#else
+       leal    MUTEX(%edi), %eax
+#endif
+       movzbl  PSHARED(%edi), %ecx
+       call    __lll_unlock_wake
+       jmp     8b
+       cfi_endproc
+       .size   __pthread_rwlock_unlock,.-__pthread_rwlock_unlock
+
+       .globl  pthread_rwlock_unlock
+pthread_rwlock_unlock = __pthread_rwlock_unlock
+
+       .globl  __pthread_rwlock_unlock_internal
+__pthread_rwlock_unlock_internal = __pthread_rwlock_unlock
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_wrlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_wrlock.S
new file mode 100644 (file)
index 0000000..0414ba0
--- /dev/null
@@ -0,0 +1,185 @@
+/* Copyright (C) 2002, 2003, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <lowlevelrwlock.h>
+#include <pthread-errnos.h>
+#include <bits/kernel-features.h>
+#include <tls.h>
+
+
+       .text
+
+       .globl  __pthread_rwlock_wrlock
+       .type   __pthread_rwlock_wrlock,@function
+       .align  16
+__pthread_rwlock_wrlock:
+       cfi_startproc
+       pushl   %esi
+       cfi_adjust_cfa_offset(4)
+       pushl   %ebx
+       cfi_adjust_cfa_offset(4)
+       cfi_offset(%esi, -8)
+       cfi_offset(%ebx, -12)
+
+       xorl    %esi, %esi
+       movl    12(%esp), %ebx
+
+       /* Get the lock.  */
+       movl    $1, %edx
+       xorl    %eax, %eax
+       LOCK
+#if MUTEX == 0
+       cmpxchgl %edx, (%ebx)
+#else
+       cmpxchgl %edx, MUTEX(%ebx)
+#endif
+       jnz     1f
+
+2:     movl    WRITER(%ebx), %eax
+       testl   %eax, %eax
+       jne     14f
+       cmpl    $0, NR_READERS(%ebx)
+       je      5f
+
+3:     addl    $1, WRITERS_QUEUED(%ebx)
+       je      4f
+
+       movl    WRITERS_WAKEUP(%ebx), %edx
+
+       LOCK
+#if MUTEX == 0
+       subl    $1, (%ebx)
+#else
+       subl    $1, MUTEX(%ebx)
+#endif
+       jne     10f
+
+11:
+#ifdef __ASSUME_PRIVATE_FUTEX
+       movzbl  PSHARED(%ebx), %ecx
+       xorl    $FUTEX_PRIVATE_FLAG|FUTEX_WAIT, %ecx
+#else
+       movzbl  PSHARED(%ebx), %ecx
+# if FUTEX_WAIT != 0
+       orl     $FUTEX_WAIT, %ecx
+# endif
+       xorl    %gs:PRIVATE_FUTEX, %ecx
+#endif
+       addl    $WRITERS_WAKEUP, %ebx
+       movl    $SYS_futex, %eax
+       ENTER_KERNEL
+
+       subl    $WRITERS_WAKEUP, %ebx
+
+       /* Reget the lock.  */
+       movl    $1, %edx
+       xorl    %eax, %eax
+       LOCK
+#if MUTEX == 0
+       cmpxchgl %edx, (%ebx)
+#else
+       cmpxchgl %edx, MUTEX(%ebx)
+#endif
+       jnz     12f
+
+13:    subl    $1, WRITERS_QUEUED(%ebx)
+       jmp     2b
+
+5:     xorl    %edx, %edx
+       movl    %gs:TID, %eax
+       movl    %eax, WRITER(%ebx)
+9:     LOCK
+#if MUTEX == 0
+       subl    $1, (%ebx)
+#else
+       subl    $1, MUTEX(%ebx)
+#endif
+       jne     6f
+7:
+
+       movl    %edx, %eax
+       popl    %ebx
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%ebx)
+       popl    %esi
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%esi)
+       ret
+
+       cfi_adjust_cfa_offset(8)
+       cfi_offset(%esi, -8)
+       cfi_offset(%ebx, -12)
+1:
+#if MUTEX == 0
+       movl    %ebx, %edx
+#else
+       leal    MUTEX(%ebx), %edx
+#endif
+       movzbl  PSHARED(%ebx), %ecx
+       call    __lll_lock_wait
+       jmp     2b
+
+14:    cmpl    %gs:TID , %eax
+       jne     3b
+       movl    $EDEADLK, %edx
+       jmp     9b
+
+6:
+#if MUTEX == 0
+       movl    %ebx, %eax
+#else
+       leal    MUTEX(%ebx), %eax
+#endif
+       movzbl  PSHARED(%ebx), %ecx
+       call    __lll_unlock_wake
+       jmp     7b
+
+4:     subl    $1, WRITERS_QUEUED(%ebx)
+       movl    $EAGAIN, %edx
+       jmp     9b
+
+10:
+#if MUTEX == 0
+       movl    %ebx, %eax
+#else
+       leal    MUTEX(%ebx), %eax
+#endif
+       movzbl  PSHARED(%ebx), %ecx
+       call    __lll_unlock_wake
+       jmp     11b
+
+12:
+#if MUTEX == 0
+       movl    %ebx, %edx
+#else
+       leal    MUTEX(%ebx), %edx
+#endif
+       movzbl  PSHARED(%ebx), %ecx
+       call    __lll_lock_wait
+       jmp     13b
+       cfi_endproc
+       .size   __pthread_rwlock_wrlock,.-__pthread_rwlock_wrlock
+
+       .globl  pthread_rwlock_wrlock
+pthread_rwlock_wrlock = __pthread_rwlock_wrlock
+
+       .globl  __pthread_rwlock_wrlock_internal
+__pthread_rwlock_wrlock_internal = __pthread_rwlock_wrlock
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_post.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_post.S
new file mode 100644 (file)
index 0000000..b077a20
--- /dev/null
@@ -0,0 +1,142 @@
+/* Copyright (C) 2002, 2003, 2005, 2007, 2008 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <pthread-errnos.h>
+#include <structsem.h>
+#include <lowlevellock.h>
+
+
+       .text
+
+       .globl  __new_sem_post
+       .type   __new_sem_post,@function
+       .align  16
+__new_sem_post:
+       cfi_startproc
+       pushl   %ebx
+       cfi_adjust_cfa_offset(4)
+       cfi_offset(%ebx, -8)
+
+       movl    8(%esp), %ebx
+
+#if VALUE == 0
+       movl    (%ebx), %eax
+#else
+       movl    VALUE(%ebx), %eax
+#endif
+0:     cmpl    $SEM_VALUE_MAX, %eax
+       je      3f
+       leal    1(%eax), %edx
+       LOCK
+#if VALUE == 0
+       cmpxchgl %edx, (%ebx)
+#else
+       cmpxchgl %edx, VALUE(%ebx)
+#endif
+       jnz     0b
+
+       cmpl    $0, NWAITERS(%ebx)
+       je      2f
+
+       movl    $FUTEX_WAKE, %ecx
+       orl     PRIVATE(%ebx), %ecx
+       movl    $1, %edx
+       movl    $SYS_futex, %eax
+       ENTER_KERNEL
+
+       testl   %eax, %eax
+       js      1f
+
+2:     xorl    %eax, %eax
+       popl    %ebx
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%ebx)
+       ret
+
+       cfi_adjust_cfa_offset(4)
+       cfi_offset(%ebx, -8)
+1:
+#ifdef __PIC__
+       call    __x86.get_pc_thunk.bx
+#else
+       movl    $4f, %ebx
+4:
+#endif
+       addl    $_GLOBAL_OFFSET_TABLE_, %ebx
+#if USE___THREAD
+# ifdef NO_TLS_DIRECT_SEG_REFS
+       movl    errno@gotntpoff(%ebx), %edx
+       addl    %gs:0, %edx
+       movl    $EINVAL, (%edx)
+# else
+       movl    errno@gotntpoff(%ebx), %edx
+       movl    $EINVAL, %gs:(%edx)
+# endif
+#else
+       call    __errno_location@plt
+       movl    $EINVAL, (%eax)
+#endif
+
+       orl     $-1, %eax
+       popl    %ebx
+       ret
+
+3:
+#ifdef __PIC__
+       call    __x86.get_pc_thunk.bx
+#else
+       movl    $5f, %ebx
+5:
+#endif
+       addl    $_GLOBAL_OFFSET_TABLE_, %ebx
+#if USE___THREAD
+# ifdef NO_TLS_DIRECT_SEG_REFS
+       movl    errno@gotntpoff(%ebx), %edx
+       addl    %gs:0, %edx
+       movl    $EOVERFLOW, (%edx)
+# else
+       movl    errno@gotntpoff(%ebx), %edx
+       movl    $EOVERFLOW, %gs:(%edx)
+# endif
+#else
+       call    __errno_location@plt
+       movl    $EOVERFLOW, (%eax)
+#endif
+
+       orl     $-1, %eax
+       popl    %ebx
+       cfi_adjust_cfa_offset(-4)
+       cfi_restore(%ebx)
+       ret
+       cfi_endproc
+       .size   __new_sem_post,.-__new_sem_post
+weak_alias(__new_sem_post, sem_post)
+
+
+#ifdef __PIC__
+       .section .gnu.linkonce.t.__x86.get_pc_thunk.bx,"ax",@progbits
+       .globl  __x86.get_pc_thunk.bx
+       .hidden __x86.get_pc_thunk.bx
+       .type   __x86.get_pc_thunk.bx,@function
+__x86.get_pc_thunk.bx:
+       movl (%esp), %ebx;
+       ret
+       .size   __x86.get_pc_thunk.bx,.-__x86.get_pc_thunk.bx
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_timedwait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_timedwait.S
new file mode 100644 (file)
index 0000000..a1e3225
--- /dev/null
@@ -0,0 +1,329 @@
+/* Copyright (C) 2002, 2003, 2004, 2005, 2007, 2009 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <pthread-errnos.h>
+#include <structsem.h>
+#include <lowlevellock.h>
+
+
+#if VALUE != 0
+# error "code needs to be rewritten for VALUE != 0"
+#endif
+
+
+       .text
+
+       .globl  sem_timedwait
+       .type   sem_timedwait,@function
+       .align  16
+sem_timedwait:
+.LSTARTCODE:
+       movl    4(%esp), %ecx
+
+       movl    (%ecx), %eax
+2:     testl   %eax, %eax
+       je      1f
+
+       leal    -1(%eax), %edx
+       LOCK
+       cmpxchgl %edx, (%ecx)
+       jne     2b
+
+       xorl    %eax, %eax
+       ret
+
+       /* Check whether the timeout value is valid.  */
+1:     pushl   %esi
+.Lpush_esi:
+       pushl   %edi
+.Lpush_edi:
+       pushl   %ebx
+.Lpush_ebx:
+       subl    $12, %esp
+.Lsub_esp:
+
+       movl    32(%esp), %edi
+
+       /* Check for invalid nanosecond field.  */
+       cmpl    $1000000000, 4(%edi)
+       movl    $EINVAL, %esi
+       jae     6f
+
+       LOCK
+       incl    NWAITERS(%ecx)
+
+7:     xorl    %ecx, %ecx
+       movl    %esp, %ebx
+       movl    %ecx, %edx
+       movl    $__NR_gettimeofday, %eax
+       ENTER_KERNEL
+
+       /* Compute relative timeout.  */
+       movl    4(%esp), %eax
+       movl    $1000, %edx
+       mul     %edx            /* Milli seconds to nano seconds.  */
+       movl    (%edi), %ecx
+       movl    4(%edi), %edx
+       subl    (%esp), %ecx
+       subl    %eax, %edx
+       jns     5f
+       addl    $1000000000, %edx
+       subl    $1, %ecx
+5:     testl   %ecx, %ecx
+       movl    $ETIMEDOUT, %esi
+       js      6f              /* Time is already up.  */
+
+       movl    %ecx, (%esp)    /* Store relative timeout.  */
+       movl    %edx, 4(%esp)
+
+.LcleanupSTART:
+       call    __pthread_enable_asynccancel
+       movl    %eax, 8(%esp)
+
+       movl    28(%esp), %ebx  /* Load semaphore address.  */
+#if FUTEX_WAIT == 0
+       movl    PRIVATE(%ebx), %ecx
+#else
+       movl    $FUTEX_WAIT, %ecx
+       orl     PRIVATE(%ebx), %ecx
+#endif
+       movl    %esp, %esi
+       xorl    %edx, %edx
+       movl    $SYS_futex, %eax
+       ENTER_KERNEL
+       movl    %eax, %esi
+
+       movl    8(%esp), %eax
+       call    __pthread_disable_asynccancel
+.LcleanupEND:
+
+       testl   %esi, %esi
+       je      9f
+       cmpl    $-EWOULDBLOCK, %esi
+       jne     3f
+
+9:     movl    (%ebx), %eax
+8:     testl   %eax, %eax
+       je      7b
+
+       leal    -1(%eax), %ecx
+       LOCK
+       cmpxchgl %ecx, (%ebx)
+       jne     8b
+
+       xorl    %eax, %eax
+
+       LOCK
+       decl    NWAITERS(%ebx)
+
+10:    addl    $12, %esp
+.Ladd_esp:
+       popl    %ebx
+.Lpop_ebx:
+       popl    %edi
+.Lpop_edi:
+       popl    %esi
+.Lpop_esi:
+       ret
+
+.Lafter_ret:
+3:     negl    %esi
+6:
+#ifdef __PIC__
+       call    __x86.get_pc_thunk.bx
+#else
+       movl    $4f, %ebx
+4:
+#endif
+       addl    $_GLOBAL_OFFSET_TABLE_, %ebx
+#if USE___THREAD
+# ifdef NO_TLS_DIRECT_SEG_REFS
+       movl    errno@gotntpoff(%ebx), %edx
+       addl    %gs:0, %edx
+       movl    %esi, (%edx)
+# else
+       movl    errno@gotntpoff(%ebx), %edx
+       movl    %esi, %gs:(%edx)
+# endif
+#else
+       call    __errno_location@plt
+       movl    %esi, (%eax)
+#endif
+
+       movl    28(%esp), %ebx  /* Load semaphore address.  */
+       orl     $-1, %eax
+       jmp     10b
+       .size   sem_timedwait,.-sem_timedwait
+
+
+       .type   sem_wait_cleanup,@function
+sem_wait_cleanup:
+       LOCK
+       decl    NWAITERS(%ebx)
+       movl    %eax, (%esp)
+.LcallUR:
+       call    _Unwind_Resume@PLT
+       hlt
+.LENDCODE:
+       .size   sem_wait_cleanup,.-sem_wait_cleanup
+
+
+       .section .gcc_except_table,"a",@progbits
+.LexceptSTART:
+       .byte   0xff                            # @LPStart format (omit)
+       .byte   0xff                            # @TType format (omit)
+       .byte   0x01                            # call-site format
+                                               # DW_EH_PE_uleb128
+       .uleb128 .Lcstend-.Lcstbegin
+.Lcstbegin:
+       .uleb128 .LcleanupSTART-.LSTARTCODE
+       .uleb128 .LcleanupEND-.LcleanupSTART
+       .uleb128 sem_wait_cleanup-.LSTARTCODE
+       .uleb128  0
+       .uleb128 .LcallUR-.LSTARTCODE
+       .uleb128 .LENDCODE-.LcallUR
+       .uleb128 0
+       .uleb128  0
+.Lcstend:
+
+
+       .section .eh_frame,"a",@progbits
+.LSTARTFRAME:
+       .long   .LENDCIE-.LSTARTCIE             # Length of the CIE.
+.LSTARTCIE:
+       .long   0                               # CIE ID.
+       .byte   1                               # Version number.
+#ifdef SHARED
+       .string "zPLR"                          # NUL-terminated augmentation
+                                               # string.
+#else
+       .string "zPL"                           # NUL-terminated augmentation
+                                               # string.
+#endif
+       .uleb128 1                              # Code alignment factor.
+       .sleb128 -4                             # Data alignment factor.
+       .byte   8                               # Return address register
+                                               # column.
+#ifdef SHARED
+       .uleb128 7                              # Augmentation value length.
+       .byte   0x9b                            # Personality: DW_EH_PE_pcrel
+                                               # + DW_EH_PE_sdata4
+                                               # + DW_EH_PE_indirect
+       .long   DW.ref.__gcc_personality_v0-.
+       .byte   0x1b                            # LSDA Encoding: DW_EH_PE_pcrel
+                                               # + DW_EH_PE_sdata4.
+       .byte   0x1b                            # FDE Encoding: DW_EH_PE_pcrel
+                                               # + DW_EH_PE_sdata4.
+#else
+       .uleb128 6                              # Augmentation value length.
+       .byte   0x0                             # Personality: absolute
+       .long   __gcc_personality_v0
+       .byte   0x0                             # LSDA Encoding: absolute
+#endif
+       .byte 0x0c                              # DW_CFA_def_cfa
+       .uleb128 4
+       .uleb128 4
+       .byte   0x88                            # DW_CFA_offset, column 0x10
+       .uleb128 1
+       .align 4
+.LENDCIE:
+
+       .long   .LENDFDE-.LSTARTFDE             # Length of the FDE.
+.LSTARTFDE:
+       .long   .LSTARTFDE-.LSTARTFRAME         # CIE pointer.
+#ifdef SHARED
+       .long   .LSTARTCODE-.                   # PC-relative start address
+                                               # of the code.
+#else
+       .long   .LSTARTCODE                     # Start address of the code.
+#endif
+       .long   .LENDCODE-.LSTARTCODE           # Length of the code.
+       .uleb128 4                              # Augmentation size
+#ifdef SHARED
+       .long   .LexceptSTART-.
+#else
+       .long   .LexceptSTART
+#endif
+
+       .byte   4                               # DW_CFA_advance_loc4
+       .long   .Lpush_esi-.LSTARTCODE
+       .byte   14                              # DW_CFA_def_cfa_offset
+       .uleb128 8
+       .byte   0x86                            # DW_CFA_offset %esi
+       .uleb128 2
+       .byte   4                               # DW_CFA_advance_loc4
+       .long   .Lpush_edi-.Lpush_esi
+       .byte   14                              # DW_CFA_def_cfa_offset
+       .uleb128 12
+       .byte   0x87                            # DW_CFA_offset %edi
+       .uleb128 3
+       .byte   4                               # DW_CFA_advance_loc4
+       .long   .Lpush_ebx-.Lpush_edi
+       .byte   14                              # DW_CFA_def_cfa_offset
+       .uleb128 16
+       .byte   0x83                            # DW_CFA_offset %ebx
+       .uleb128 4
+       .byte   4                               # DW_CFA_advance_loc4
+       .long   .Lsub_esp-.Lpush_ebx
+       .byte   14                              # DW_CFA_def_cfa_offset
+       .uleb128 28
+       .byte   4                               # DW_CFA_advance_loc4
+       .long   .Ladd_esp-.Lsub_esp
+       .byte   14                              # DW_CFA_def_cfa_offset
+       .uleb128 16
+       .byte   4                               # DW_CFA_advance_loc4
+       .long   .Lpop_ebx-.Ladd_esp
+       .byte   14                              # DW_CFA_def_cfa_offset
+       .uleb128 12
+       .byte   0xc3                            # DW_CFA_restore %ebx
+       .byte   4                               # DW_CFA_advance_loc4
+       .long   .Lpop_edi-.Lpop_ebx
+       .byte   14                              # DW_CFA_def_cfa_offset
+       .uleb128 8
+       .byte   0xc7                            # DW_CFA_restore %edi
+       .byte   4                               # DW_CFA_advance_loc4
+       .long   .Lpop_esi-.Lpop_edi
+       .byte   14                              # DW_CFA_def_cfa_offset
+       .uleb128 4
+       .byte   0xc6                            # DW_CFA_restore %esi
+       .byte   4                               # DW_CFA_advance_loc4
+       .long   .Lafter_ret-.Lpop_esi
+       .byte   14                              # DW_CFA_def_cfa_offset
+       .uleb128 28
+       .byte   0x86                            # DW_CFA_offset %esi
+       .uleb128 2
+       .byte   0x87                            # DW_CFA_offset %edi
+       .uleb128 3
+       .byte   0x83                            # DW_CFA_offset %ebx
+       .uleb128 4
+       .align  4
+.LENDFDE:
+
+
+#ifdef SHARED
+       .hidden DW.ref.__gcc_personality_v0
+       .weak   DW.ref.__gcc_personality_v0
+       .section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits
+       .align  4
+       .type   DW.ref.__gcc_personality_v0, @object
+       .size   DW.ref.__gcc_personality_v0, 4
+DW.ref.__gcc_personality_v0:
+       .long   __gcc_personality_v0
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_trywait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_trywait.S
new file mode 100644 (file)
index 0000000..dad9685
--- /dev/null
@@ -0,0 +1,79 @@
+/* Copyright (C) 2002, 2003, 2005, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <pthread-errnos.h>
+#include <lowlevellock.h>
+
+       .text
+
+       .globl  __new_sem_trywait
+       .type   __new_sem_trywait,@function
+       .align  16
+__new_sem_trywait:
+       movl    4(%esp), %ecx
+
+       movl    (%ecx), %eax
+2:     testl   %eax, %eax
+       jz      1f
+
+       leal    -1(%eax), %edx
+       LOCK
+       cmpxchgl %edx, (%ecx)
+       jne     2b
+       xorl    %eax, %eax
+       ret
+
+1:
+#ifdef __PIC__
+       call    __x86.get_pc_thunk.cx
+#else
+       movl    $3f, %ecx
+3:
+#endif
+       addl    $_GLOBAL_OFFSET_TABLE_, %ecx
+#if USE___THREAD
+# ifdef NO_TLS_DIRECT_SEG_REFS
+       movl    errno@gotntpoff(%ecx), %edx
+       addl    %gs:0, %edx
+       movl    $EAGAIN, (%edx)
+# else
+       movl    errno@gotntpoff(%ecx), %edx
+       movl    $EAGAIN, %gs:(%edx)
+# endif
+#else
+       call    __errno_location@plt
+       movl    $EAGAIN, (%eax)
+#endif
+       orl     $-1, %eax
+       ret
+       .size   __new_sem_trywait,.-__new_sem_trywait
+weak_alias(__new_sem_trywait, sem_trywait)
+
+
+#ifdef __PIC__
+       .section .gnu.linkonce.t.__x86.get_pc_thunk.cx,"ax",@progbits
+       .globl  __x86.get_pc_thunk.cx
+       .hidden __x86.get_pc_thunk.cx
+       .type   __x86.get_pc_thunk.cx,@function
+__x86.get_pc_thunk.cx:
+       movl (%esp), %ecx;
+       ret
+       .size   __x86.get_pc_thunk.cx,.-__x86.get_pc_thunk.cx
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_wait.S
new file mode 100644 (file)
index 0000000..b1c32ee
--- /dev/null
@@ -0,0 +1,269 @@
+/* Copyright (C) 2002, 2003, 2005, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <pthread-errnos.h>
+#include <structsem.h>
+#include <lowlevellock.h>
+
+
+#if VALUE != 0
+# error "code needs to be rewritten for VALUE != 0"
+#endif
+
+       .text
+
+       .globl  __new_sem_wait
+       .type   __new_sem_wait,@function
+       .align  16
+__new_sem_wait:
+.LSTARTCODE:
+       pushl   %ebx
+.Lpush_ebx:
+       pushl   %esi
+.Lpush_esi:
+       subl    $4, %esp
+.Lsub_esp:
+
+       movl    16(%esp), %ebx
+
+       movl    (%ebx), %eax
+2:     testl   %eax, %eax
+       je      1f
+
+       leal    -1(%eax), %edx
+       LOCK
+       cmpxchgl %edx, (%ebx)
+       jne     2b
+7:     xorl    %eax, %eax
+
+9:     movl    4(%esp), %esi
+       movl    8(%esp), %ebx
+       addl    $12, %esp
+.Ladd_esp:
+       ret
+
+.Lafter_ret:
+1:     LOCK
+       incl    NWAITERS(%ebx)
+
+.LcleanupSTART:
+6:     call    __pthread_enable_asynccancel
+       movl    %eax, (%esp)
+
+#if FUTEX_WAIT == 0
+       movl    PRIVATE(%ebx), %ecx
+#else
+       movl    $FUTEX_WAIT, %ecx
+       orl     PRIVATE(%ebx), %ecx
+#endif
+       xorl    %esi, %esi
+       xorl    %edx, %edx
+       movl    $SYS_futex, %eax
+       ENTER_KERNEL
+       movl    %eax, %esi
+
+       movl    (%esp), %eax
+       call    __pthread_disable_asynccancel
+.LcleanupEND:
+
+       testl   %esi, %esi
+       je      3f
+       cmpl    $-EWOULDBLOCK, %esi
+       jne     4f
+
+3:
+       movl    (%ebx), %eax
+5:     testl   %eax, %eax
+       je      6b
+
+       leal    -1(%eax), %edx
+       LOCK
+       cmpxchgl %edx, (%ebx)
+       jne     5b
+
+       LOCK
+       decl    NWAITERS(%ebx)
+       jmp     7b
+
+4:     LOCK
+       decl    NWAITERS(%ebx)
+
+       negl    %esi
+#ifdef __PIC__
+       call    __x86.get_pc_thunk.bx
+#else
+       movl    $8f, %ebx
+8:
+#endif
+       addl    $_GLOBAL_OFFSET_TABLE_, %ebx
+#if USE___THREAD
+# ifdef NO_TLS_DIRECT_SEG_REFS
+       movl    errno@gotntpoff(%ebx), %edx
+       addl    %gs:0, %edx
+       movl    %esi, (%edx)
+# else
+       movl    errno@gotntpoff(%ebx), %edx
+       movl    %esi, %gs:(%edx)
+# endif
+#else
+       call    __errno_location@plt
+       movl    %esi, (%eax)
+#endif
+       orl     $-1, %eax
+
+       jmp     9b
+       .size   __new_sem_wait,.-__new_sem_wait
+weak_alias(__new_sem_wait, sem_wait)
+
+
+       .type   sem_wait_cleanup,@function
+sem_wait_cleanup:
+       LOCK
+       decl    NWAITERS(%ebx)
+       movl    %eax, (%esp)
+.LcallUR:
+       call    _Unwind_Resume@PLT
+       hlt
+.LENDCODE:
+       .size   sem_wait_cleanup,.-sem_wait_cleanup
+
+
+       .section .gcc_except_table,"a",@progbits
+.LexceptSTART:
+       .byte   0xff                            # @LPStart format (omit)
+       .byte   0xff                            # @TType format (omit)
+       .byte   0x01                            # call-site format
+                                               # DW_EH_PE_uleb128
+       .uleb128 .Lcstend-.Lcstbegin
+.Lcstbegin:
+       .uleb128 .LcleanupSTART-.LSTARTCODE
+       .uleb128 .LcleanupEND-.LcleanupSTART
+       .uleb128 sem_wait_cleanup-.LSTARTCODE
+       .uleb128  0
+       .uleb128 .LcallUR-.LSTARTCODE
+       .uleb128 .LENDCODE-.LcallUR
+       .uleb128 0
+       .uleb128  0
+.Lcstend:
+
+
+       .section .eh_frame,"a",@progbits
+.LSTARTFRAME:
+       .long   .LENDCIE-.LSTARTCIE             # Length of the CIE.
+.LSTARTCIE:
+       .long   0                               # CIE ID.
+       .byte   1                               # Version number.
+#ifdef SHARED
+       .string "zPLR"                          # NUL-terminated augmentation
+                                               # string.
+#else
+       .string "zPL"                           # NUL-terminated augmentation
+                                               # string.
+#endif
+       .uleb128 1                              # Code alignment factor.
+       .sleb128 -4                             # Data alignment factor.
+       .byte   8                               # Return address register
+                                               # column.
+#ifdef SHARED
+       .uleb128 7                              # Augmentation value length.
+       .byte   0x9b                            # Personality: DW_EH_PE_pcrel
+                                               # + DW_EH_PE_sdata4
+                                               # + DW_EH_PE_indirect
+       .long   DW.ref.__gcc_personality_v0-.
+       .byte   0x1b                            # LSDA Encoding: DW_EH_PE_pcrel
+                                               # + DW_EH_PE_sdata4.
+       .byte   0x1b                            # FDE Encoding: DW_EH_PE_pcrel
+                                               # + DW_EH_PE_sdata4.
+#else
+       .uleb128 6                              # Augmentation value length.
+       .byte   0x0                             # Personality: absolute
+       .long   __gcc_personality_v0
+       .byte   0x0                             # LSDA Encoding: absolute
+#endif
+       .byte 0x0c                              # DW_CFA_def_cfa
+       .uleb128 4
+       .uleb128 4
+       .byte   0x88                            # DW_CFA_offset, column 0x10
+       .uleb128 1
+       .align 4
+.LENDCIE:
+
+       .long   .LENDFDE-.LSTARTFDE             # Length of the FDE.
+.LSTARTFDE:
+       .long   .LSTARTFDE-.LSTARTFRAME         # CIE pointer.
+#ifdef SHARED
+       .long   .LSTARTCODE-.                   # PC-relative start address
+                                               # of the code.
+#else
+       .long   .LSTARTCODE                     # Start address of the code.
+#endif
+       .long   .LENDCODE-.LSTARTCODE           # Length of the code.
+       .uleb128 4                              # Augmentation size
+#ifdef SHARED
+       .long   .LexceptSTART-.
+#else
+       .long   .LexceptSTART
+#endif
+
+       .byte   4                               # DW_CFA_advance_loc4
+       .long   .Lpush_ebx-.LSTARTCODE
+       .byte   14                              # DW_CFA_def_cfa_offset
+       .uleb128 8
+       .byte   0x83                            # DW_CFA_offset %ebx
+        .uleb128 2
+       .byte   4                               # DW_CFA_advance_loc4
+       .long   .Lpush_esi-.Lpush_ebx
+       .byte   14                              # DW_CFA_def_cfa_offset
+       .uleb128 12
+       .byte   0x86                            # DW_CFA_offset %esi
+        .uleb128 3
+       .byte   4                               # DW_CFA_advance_loc4
+       .long   .Lsub_esp-.Lpush_esi
+       .byte   14                              # DW_CFA_def_cfa_offset
+       .uleb128 16
+       .byte   4                               # DW_CFA_advance_loc4
+       .long   .Ladd_esp-.Lsub_esp
+       .byte   14                              # DW_CFA_def_cfa_offset
+       .uleb128 4
+       .byte   0xc3                            # DW_CFA_restore %ebx
+       .byte   0xc6                            # DW_CFA_restore %esi
+       .byte   4                               # DW_CFA_advance_loc4
+       .long   .Lafter_ret-.Ladd_esp
+       .byte   14                              # DW_CFA_def_cfa_offset
+       .uleb128 16
+       .byte   0x83                            # DW_CFA_offset %ebx
+        .uleb128 2
+       .byte   0x86                            # DW_CFA_offset %esi
+        .uleb128 3
+       .align  4
+.LENDFDE:
+
+
+#ifdef SHARED
+       .hidden DW.ref.__gcc_personality_v0
+       .weak   DW.ref.__gcc_personality_v0
+       .section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits
+       .align  4
+       .type   DW.ref.__gcc_personality_v0, @object
+       .size   DW.ref.__gcc_personality_v0, 4
+DW.ref.__gcc_personality_v0:
+       .long   __gcc_personality_v0
+#endif
+
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/libc-lowlevellock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/libc-lowlevellock.S
new file mode 100644 (file)
index 0000000..f567c1d
--- /dev/null
@@ -0,0 +1 @@
+#include "../i486/libc-lowlevellock.S"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevellock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevellock.S
new file mode 100644 (file)
index 0000000..e60dea8
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "../i486/lowlevellock.S"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevelrobustlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevelrobustlock.S
new file mode 100644 (file)
index 0000000..f768e16
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright (C) 2002, 2006 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "../i486/lowlevelrobustlock.S"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_barrier_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_barrier_wait.S
new file mode 100644 (file)
index 0000000..6d20b9a
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "../i486/pthread_barrier_wait.S"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_cond_broadcast.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_cond_broadcast.S
new file mode 100644 (file)
index 0000000..5e1024e
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "../i486/pthread_cond_broadcast.S"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_cond_signal.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_cond_signal.S
new file mode 100644 (file)
index 0000000..da4e8cb
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "../i486/pthread_cond_signal.S"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_cond_timedwait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_cond_timedwait.S
new file mode 100644 (file)
index 0000000..c013155
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "../i486/pthread_cond_timedwait.S"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_cond_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_cond_wait.S
new file mode 100644 (file)
index 0000000..9b57fba
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "../i486/pthread_cond_wait.S"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_rdlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_rdlock.S
new file mode 100644 (file)
index 0000000..da2bc47
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "../i486/pthread_rwlock_rdlock.S"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_timedrdlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_timedrdlock.S
new file mode 100644 (file)
index 0000000..0f2ec16
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "../i486/pthread_rwlock_timedrdlock.S"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_timedwrlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_timedwrlock.S
new file mode 100644 (file)
index 0000000..2650159
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "../i486/pthread_rwlock_timedwrlock.S"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_unlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_unlock.S
new file mode 100644 (file)
index 0000000..5515e48
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "../i486/pthread_rwlock_unlock.S"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_wrlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_wrlock.S
new file mode 100644 (file)
index 0000000..04ac275
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "../i486/pthread_rwlock_wrlock.S"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/sem_post.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/sem_post.S
new file mode 100644 (file)
index 0000000..7317e15
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "../i486/sem_post.S"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/sem_timedwait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/sem_timedwait.S
new file mode 100644 (file)
index 0000000..f34539d
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "../i486/sem_timedwait.S"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/sem_trywait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/sem_trywait.S
new file mode 100644 (file)
index 0000000..64145c2
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "../i486/sem_trywait.S"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/sem_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/sem_wait.S
new file mode 100644 (file)
index 0000000..b3d4621
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "../i486/sem_wait.S"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/libc-lowlevellock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/libc-lowlevellock.S
new file mode 100644 (file)
index 0000000..f567c1d
--- /dev/null
@@ -0,0 +1 @@
+#include "../i486/libc-lowlevellock.S"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevellock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevellock.S
new file mode 100644 (file)
index 0000000..e60dea8
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "../i486/lowlevellock.S"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevelrobustlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevelrobustlock.S
new file mode 100644 (file)
index 0000000..f768e16
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright (C) 2002, 2006 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "../i486/lowlevelrobustlock.S"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_barrier_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_barrier_wait.S
new file mode 100644 (file)
index 0000000..6d20b9a
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "../i486/pthread_barrier_wait.S"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_cond_broadcast.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_cond_broadcast.S
new file mode 100644 (file)
index 0000000..5e1024e
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "../i486/pthread_cond_broadcast.S"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_cond_signal.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_cond_signal.S
new file mode 100644 (file)
index 0000000..da4e8cb
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "../i486/pthread_cond_signal.S"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_cond_timedwait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_cond_timedwait.S
new file mode 100644 (file)
index 0000000..07d481f
--- /dev/null
@@ -0,0 +1,21 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#define HAVE_CMOV 1
+#include "../i486/pthread_cond_timedwait.S"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_cond_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_cond_wait.S
new file mode 100644 (file)
index 0000000..9b57fba
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "../i486/pthread_cond_wait.S"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_rdlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_rdlock.S
new file mode 100644 (file)
index 0000000..da2bc47
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "../i486/pthread_rwlock_rdlock.S"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_timedrdlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_timedrdlock.S
new file mode 100644 (file)
index 0000000..0f2ec16
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "../i486/pthread_rwlock_timedrdlock.S"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_timedwrlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_timedwrlock.S
new file mode 100644 (file)
index 0000000..2650159
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "../i486/pthread_rwlock_timedwrlock.S"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_unlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_unlock.S
new file mode 100644 (file)
index 0000000..0894f05
--- /dev/null
@@ -0,0 +1,21 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#define HAVE_CMOV      1
+#include "../i486/pthread_rwlock_unlock.S"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_wrlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_wrlock.S
new file mode 100644 (file)
index 0000000..04ac275
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "../i486/pthread_rwlock_wrlock.S"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/sem_post.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/sem_post.S
new file mode 100644 (file)
index 0000000..7317e15
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "../i486/sem_post.S"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/sem_timedwait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/sem_timedwait.S
new file mode 100644 (file)
index 0000000..f34539d
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "../i486/sem_timedwait.S"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/sem_trywait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/sem_trywait.S
new file mode 100644 (file)
index 0000000..64145c2
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "../i486/sem_trywait.S"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/sem_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/sem_wait.S
new file mode 100644 (file)
index 0000000..b3d4621
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "../i486/sem_wait.S"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h
new file mode 100644 (file)
index 0000000..55add8b
--- /dev/null
@@ -0,0 +1,584 @@
+/* Copyright (C) 2002-2004, 2006-2008, 2009 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _LOWLEVELLOCK_H
+#define _LOWLEVELLOCK_H        1
+
+#ifndef __ASSEMBLER__
+# include <time.h>
+# include <sys/param.h>
+# include <bits/pthreadtypes.h>
+# include <bits/kernel-features.h>
+# include <tcb-offsets.h>
+
+# ifndef LOCK_INSTR
+#  ifdef UP
+#   define LOCK_INSTR  /* nothing */
+#  else
+#   define LOCK_INSTR "lock;"
+#  endif
+# endif
+#else
+# ifndef LOCK
+#  ifdef UP
+#   define LOCK
+#  else
+#   define LOCK lock
+#  endif
+# endif
+#endif
+
+#define FUTEX_WAIT             0
+#define FUTEX_WAKE             1
+#define FUTEX_CMP_REQUEUE      4
+#define FUTEX_WAKE_OP          5
+#define FUTEX_LOCK_PI          6
+#define FUTEX_UNLOCK_PI                7
+#define FUTEX_TRYLOCK_PI       8
+#define FUTEX_WAIT_BITSET      9
+#define FUTEX_WAKE_BITSET      10
+#define FUTEX_WAIT_REQUEUE_PI  11
+#define FUTEX_CMP_REQUEUE_PI   12
+#define FUTEX_PRIVATE_FLAG     128
+#define FUTEX_CLOCK_REALTIME   256
+
+#define FUTEX_BITSET_MATCH_ANY 0xffffffff
+
+#define FUTEX_OP_CLEAR_WAKE_IF_GT_ONE  ((4 << 24) | 1)
+
+/* Values for 'private' parameter of locking macros.  Yes, the
+   definition seems to be backwards.  But it is not.  The bit will be
+   reversed before passing to the system call.  */
+#define LLL_PRIVATE    0
+#define LLL_SHARED     FUTEX_PRIVATE_FLAG
+
+
+#if !defined NOT_IN_libc || defined IS_IN_rtld
+/* In libc.so or ld.so all futexes are private.  */
+# ifdef __ASSUME_PRIVATE_FUTEX
+#  define __lll_private_flag(fl, private) \
+  ((fl) | FUTEX_PRIVATE_FLAG)
+# else
+#  define __lll_private_flag(fl, private) \
+  ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex))
+# endif
+#else
+# ifdef __ASSUME_PRIVATE_FUTEX
+#  define __lll_private_flag(fl, private) \
+  (((fl) | FUTEX_PRIVATE_FLAG) ^ (private))
+# else
+#  define __lll_private_flag(fl, private) \
+  (__builtin_constant_p (private)                                            \
+   ? ((private) == 0                                                         \
+      ? ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex))           \
+      : (fl))                                                                \
+   : ({ unsigned int __fl = ((private) ^ FUTEX_PRIVATE_FLAG);                \
+       __asm__ ("andl %%gs:%P1, %0" : "+r" (__fl)                                    \
+            : "i" (offsetof (struct pthread, header.private_futex)));        \
+       __fl | (fl); }))
+# endif
+#endif
+
+#ifndef __ASSEMBLER__
+
+/* Initializer for compatibility lock.  */
+#define LLL_LOCK_INITIALIZER           (0)
+#define LLL_LOCK_INITIALIZER_LOCKED    (1)
+#define LLL_LOCK_INITIALIZER_WAITERS   (2)
+
+
+#ifdef __PIC__
+# define LLL_EBX_LOAD  "xchgl %2, %%ebx\n"
+# define LLL_EBX_REG   "D"
+#else
+# define LLL_EBX_LOAD
+# define LLL_EBX_REG   "b"
+#endif
+
+#ifdef I386_USE_SYSENTER
+# ifdef SHARED
+#  define LLL_ENTER_KERNEL     "call *%%gs:%P6\n\t"
+# else
+#  define LLL_ENTER_KERNEL     "call *_dl_sysinfo\n\t"
+# endif
+#else
+# define LLL_ENTER_KERNEL      "int $0x80\n\t"
+#endif
+
+/* Delay in spinlock loop.  */
+#define BUSY_WAIT_NOP  __asm__ ("rep; nop")
+
+
+#define LLL_STUB_UNWIND_INFO_START \
+       ".section       .eh_frame,\"a\",@progbits\n"            \
+"5:\t" ".long  7f-6f   # Length of Common Information Entry\n" \
+"6:\t" ".long  0x0     # CIE Identifier Tag\n\t"               \
+       ".byte  0x1     # CIE Version\n\t"                      \
+       ".ascii \"zR\\0\"       # CIE Augmentation\n\t"         \
+       ".uleb128 0x1   # CIE Code Alignment Factor\n\t"        \
+       ".sleb128 -4    # CIE Data Alignment Factor\n\t"        \
+       ".byte  0x8     # CIE RA Column\n\t"                    \
+       ".uleb128 0x1   # Augmentation size\n\t"                \
+       ".byte  0x1b    # FDE Encoding (pcrel sdata4)\n\t"      \
+       ".byte  0xc     # DW_CFA_def_cfa\n\t"                   \
+       ".uleb128 0x4\n\t"                                      \
+       ".uleb128 0x0\n\t"                                      \
+       ".align 4\n"                                            \
+"7:\t" ".long  17f-8f  # FDE Length\n"                         \
+"8:\t" ".long  8b-5b   # FDE CIE offset\n\t"                   \
+       ".long  1b-.    # FDE initial location\n\t"             \
+       ".long  4b-1b   # FDE address range\n\t"                \
+       ".uleb128 0x0   # Augmentation size\n\t"                \
+       ".byte  0x16    # DW_CFA_val_expression\n\t"            \
+       ".uleb128 0x8\n\t"                                      \
+       ".uleb128 10f-9f\n"                                     \
+"9:\t" ".byte  0x78    # DW_OP_breg8\n\t"                      \
+       ".sleb128 3b-1b\n"
+#define LLL_STUB_UNWIND_INFO_END \
+       ".byte  0x16    # DW_CFA_val_expression\n\t"            \
+       ".uleb128 0x8\n\t"                                      \
+       ".uleb128 12f-11f\n"                                    \
+"11:\t"        ".byte  0x78    # DW_OP_breg8\n\t"                      \
+       ".sleb128 3b-2b\n"                                      \
+"12:\t"        ".byte  0x40 + (3b-2b-1) # DW_CFA_advance_loc\n\t"      \
+       ".byte  0x16    # DW_CFA_val_expression\n\t"            \
+       ".uleb128 0x8\n\t"                                      \
+       ".uleb128 16f-13f\n"                                    \
+"13:\t"        ".byte  0x78    # DW_OP_breg8\n\t"                      \
+       ".sleb128 15f-14f\n\t"                                  \
+       ".byte  0x0d    # DW_OP_const4s\n"                      \
+"14:\t"        ".4byte 3b-.\n\t"                                       \
+       ".byte  0x1c    # DW_OP_minus\n\t"                      \
+       ".byte  0x0d    # DW_OP_const4s\n"                      \
+"15:\t"        ".4byte 18f-.\n\t"                                      \
+       ".byte  0x22    # DW_OP_plus\n"                         \
+"16:\t"        ".align 4\n"                                            \
+"17:\t"        ".previous\n"
+
+/* Unwind info for
+   1: lea ..., ...
+   2: call ...
+   3: jmp 18f
+   4:
+   snippet.  */
+#define LLL_STUB_UNWIND_INFO_3 \
+LLL_STUB_UNWIND_INFO_START                                     \
+"10:\t"        ".byte  0x40 + (2b-1b) # DW_CFA_advance_loc\n\t"        \
+LLL_STUB_UNWIND_INFO_END
+
+/* Unwind info for
+   1: lea ..., ...
+   0: movl ..., ...
+   2: call ...
+   3: jmp 18f
+   4:
+   snippet.  */
+#define LLL_STUB_UNWIND_INFO_4 \
+LLL_STUB_UNWIND_INFO_START                                     \
+"10:\t"        ".byte  0x40 + (0b-1b) # DW_CFA_advance_loc\n\t"        \
+       ".byte  0x16    # DW_CFA_val_expression\n\t"            \
+       ".uleb128 0x8\n\t"                                      \
+       ".uleb128 20f-19f\n"                                    \
+"19:\t"        ".byte  0x78    # DW_OP_breg8\n\t"                      \
+       ".sleb128 3b-0b\n"                                      \
+"20:\t"        ".byte  0x40 + (2b-0b) # DW_CFA_advance_loc\n\t"        \
+LLL_STUB_UNWIND_INFO_END
+
+
+#define lll_futex_wait(futex, val, private) \
+  lll_futex_timed_wait (futex, val, NULL, private)
+
+
+#define lll_futex_timed_wait(futex, val, timeout, private) \
+  ({                                                                         \
+    int __status;                                                            \
+    register __typeof (val) _val __asm__ ("edx") = (val);                            \
+    __asm__ __volatile (LLL_EBX_LOAD                                         \
+                     LLL_ENTER_KERNEL                                        \
+                     LLL_EBX_LOAD                                            \
+                     : "=a" (__status)                                       \
+                     : "0" (SYS_futex), LLL_EBX_REG (futex), "S" (timeout),  \
+                       "c" (__lll_private_flag (FUTEX_WAIT, private)),       \
+                       "d" (_val), "i" (offsetof (tcbhead_t, sysinfo))       \
+                     : "memory");                                            \
+    __status;                                                                \
+  })
+
+
+#define lll_futex_wake(futex, nr, private) \
+  do {                                                                       \
+    int __ignore;                                                            \
+    register __typeof (nr) _nr __asm__ ("edx") = (nr);                       \
+    __asm__ __volatile (LLL_EBX_LOAD                                         \
+                     LLL_ENTER_KERNEL                                        \
+                     LLL_EBX_LOAD                                            \
+                     : "=a" (__ignore)                                       \
+                     : "0" (SYS_futex), LLL_EBX_REG (futex),                 \
+                       "c" (__lll_private_flag (FUTEX_WAKE, private)),       \
+                       "d" (_nr),                                            \
+                       "i" (0) /* phony, to align next arg's number */,      \
+                       "i" (offsetof (tcbhead_t, sysinfo)));                 \
+  } while (0)
+
+
+/* NB: in the lll_trylock macro we simply return the value in %eax
+   after the cmpxchg instruction.  In case the operation succeded this
+   value is zero.  In case the operation failed, the cmpxchg instruction
+   has loaded the current value of the memory work which is guaranteed
+   to be nonzero.  */
+#if defined NOT_IN_libc || defined UP
+# define __lll_trylock_asm LOCK_INSTR "cmpxchgl %2, %1"
+#else
+# define __lll_trylock_asm "cmpl $0, %%gs:%P5\n\t" \
+                          "je 0f\n\t"                                        \
+                          "lock\n"                                           \
+                          "0:\tcmpxchgl %2, %1"
+#endif
+
+#define lll_trylock(futex) \
+  ({ int ret;                                                                \
+     __asm__ __volatile (__lll_trylock_asm                                   \
+                      : "=a" (ret), "=m" (futex)                             \
+                      : "r" (LLL_LOCK_INITIALIZER_LOCKED), "m" (futex),      \
+                        "0" (LLL_LOCK_INITIALIZER),                          \
+                        "i" (MULTIPLE_THREADS_OFFSET)                        \
+                      : "memory");                                           \
+     ret; })
+
+#define lll_robust_trylock(futex, id) \
+  ({ int ret;                                                                \
+     __asm__ __volatile (LOCK_INSTR "cmpxchgl %2, %1"                        \
+                      : "=a" (ret), "=m" (futex)                             \
+                      : "r" (id), "m" (futex),                               \
+                        "0" (LLL_LOCK_INITIALIZER)                           \
+                      : "memory");                                           \
+     ret; })
+
+
+#define lll_cond_trylock(futex) \
+  ({ int ret;                                                                \
+     __asm__ __volatile (LOCK_INSTR "cmpxchgl %2, %1"                        \
+                      : "=a" (ret), "=m" (futex)                             \
+                      : "r" (LLL_LOCK_INITIALIZER_WAITERS),                  \
+                        "m" (futex), "0" (LLL_LOCK_INITIALIZER)              \
+                      : "memory");                                           \
+     ret; })
+
+#if defined NOT_IN_libc || defined UP
+# define __lll_lock_asm_start LOCK_INSTR "cmpxchgl %1, %2\n\t"
+#else
+# define __lll_lock_asm_start "cmpl $0, %%gs:%P6\n\t"                        \
+                             "je 0f\n\t"                                     \
+                             "lock\n"                                        \
+                             "0:\tcmpxchgl %1, %2\n\t"
+#endif
+
+#define lll_lock(futex, private) \
+  (void)                                                                     \
+    ({ int ignore1, ignore2;                                                 \
+       if (__builtin_constant_p (private) && (private) == LLL_PRIVATE)       \
+        __asm__ __volatile (__lll_lock_asm_start                                     \
+                          "jnz _L_lock_%=\n\t"                               \
+                          ".subsection 1\n\t"                                \
+                          ".type _L_lock_%=,@function\n"                     \
+                          "_L_lock_%=:\n"                                    \
+                          "1:\tleal %2, %%ecx\n"                             \
+                          "2:\tcall __lll_lock_wait_private\n"               \
+                          "3:\tjmp 18f\n"                                    \
+                          "4:\t.size _L_lock_%=, 4b-1b\n\t"                  \
+                          ".previous\n"                                      \
+                          LLL_STUB_UNWIND_INFO_3                             \
+                          "18:"                                              \
+                          : "=a" (ignore1), "=c" (ignore2), "=m" (futex)     \
+                          : "0" (0), "1" (1), "m" (futex),                   \
+                            "i" (MULTIPLE_THREADS_OFFSET)                    \
+                          : "memory");                                       \
+       else                                                                  \
+        {                                                                    \
+          int ignore3;                                                       \
+          __asm__ __volatile (__lll_lock_asm_start                           \
+                            "jnz _L_lock_%=\n\t"                             \
+                            ".subsection 1\n\t"                              \
+                            ".type _L_lock_%=,@function\n"                   \
+                            "_L_lock_%=:\n"                                  \
+                            "1:\tleal %2, %%edx\n"                           \
+                            "0:\tmovl %8, %%ecx\n"                           \
+                            "2:\tcall __lll_lock_wait\n"                     \
+                            "3:\tjmp 18f\n"                                  \
+                            "4:\t.size _L_lock_%=, 4b-1b\n\t"                \
+                            ".previous\n"                                    \
+                            LLL_STUB_UNWIND_INFO_4                           \
+                            "18:"                                            \
+                            : "=a" (ignore1), "=c" (ignore2),                \
+                              "=m" (futex), "=&d" (ignore3)                  \
+                            : "1" (1), "m" (futex),                          \
+                              "i" (MULTIPLE_THREADS_OFFSET), "0" (0),        \
+                              "g" ((int) (private))                          \
+                            : "memory");                                     \
+        }                                                                    \
+    })
+
+#define lll_robust_lock(futex, id, private) \
+  ({ int __result, ignore1, ignore2;                                         \
+     __asm__ __volatile (LOCK_INSTR "cmpxchgl %1, %2\n\t"                            \
+                      "jnz _L_robust_lock_%=\n\t"                            \
+                      ".subsection 1\n\t"                                    \
+                      ".type _L_robust_lock_%=,@function\n"                  \
+                      "_L_robust_lock_%=:\n"                                 \
+                      "1:\tleal %2, %%edx\n"                                 \
+                      "0:\tmovl %7, %%ecx\n"                                 \
+                      "2:\tcall __lll_robust_lock_wait\n"                    \
+                      "3:\tjmp 18f\n"                                        \
+                      "4:\t.size _L_robust_lock_%=, 4b-1b\n\t"               \
+                      ".previous\n"                                          \
+                      LLL_STUB_UNWIND_INFO_4                                 \
+                      "18:"                                                  \
+                      : "=a" (__result), "=c" (ignore1), "=m" (futex),       \
+                        "=&d" (ignore2)                                      \
+                      : "0" (0), "1" (id), "m" (futex), "g" ((int) (private))\
+                      : "memory");                                           \
+     __result; })
+
+
+/* Special version of lll_lock which causes the unlock function to
+   always wakeup waiters.  */
+#define lll_cond_lock(futex, private) \
+  (void)                                                                     \
+    ({ int ignore1, ignore2, ignore3;                                        \
+       __asm__ __volatile (LOCK_INSTR "cmpxchgl %1, %2\n\t"                  \
+                        "jnz _L_cond_lock_%=\n\t"                            \
+                        ".subsection 1\n\t"                                  \
+                        ".type _L_cond_lock_%=,@function\n"                  \
+                        "_L_cond_lock_%=:\n"                                 \
+                        "1:\tleal %2, %%edx\n"                               \
+                        "0:\tmovl %7, %%ecx\n"                               \
+                        "2:\tcall __lll_lock_wait\n"                         \
+                        "3:\tjmp 18f\n"                                      \
+                        "4:\t.size _L_cond_lock_%=, 4b-1b\n\t"               \
+                        ".previous\n"                                        \
+                        LLL_STUB_UNWIND_INFO_4                               \
+                        "18:"                                                \
+                        : "=a" (ignore1), "=c" (ignore2), "=m" (futex),      \
+                          "=&d" (ignore3)                                    \
+                        : "0" (0), "1" (2), "m" (futex), "g" ((int) (private))\
+                        : "memory");                                         \
+    })
+
+
+#define lll_robust_cond_lock(futex, id, private) \
+  ({ int __result, ignore1, ignore2;                                         \
+     __asm__ __volatile (LOCK_INSTR "cmpxchgl %1, %2\n\t"                            \
+                      "jnz _L_robust_cond_lock_%=\n\t"                       \
+                      ".subsection 1\n\t"                                    \
+                      ".type _L_robust_cond_lock_%=,@function\n"             \
+                      "_L_robust_cond_lock_%=:\n"                            \
+                      "1:\tleal %2, %%edx\n"                                 \
+                      "0:\tmovl %7, %%ecx\n"                                 \
+                      "2:\tcall __lll_robust_lock_wait\n"                    \
+                      "3:\tjmp 18f\n"                                        \
+                      "4:\t.size _L_robust_cond_lock_%=, 4b-1b\n\t"          \
+                      ".previous\n"                                          \
+                      LLL_STUB_UNWIND_INFO_4                                 \
+                      "18:"                                                  \
+                      : "=a" (__result), "=c" (ignore1), "=m" (futex),       \
+                        "=&d" (ignore2)                                      \
+                      : "0" (0), "1" (id | FUTEX_WAITERS), "m" (futex),      \
+                        "g" ((int) (private))                                \
+                      : "memory");                                           \
+     __result; })
+
+
+#define lll_timedlock(futex, timeout, private) \
+  ({ int __result, ignore1, ignore2, ignore3;                                \
+     __asm__ __volatile (LOCK_INSTR "cmpxchgl %1, %3\n\t"                            \
+                      "jnz _L_timedlock_%=\n\t"                              \
+                      ".subsection 1\n\t"                                    \
+                      ".type _L_timedlock_%=,@function\n"                    \
+                      "_L_timedlock_%=:\n"                                   \
+                      "1:\tleal %3, %%ecx\n"                                 \
+                      "0:\tmovl %8, %%edx\n"                                 \
+                      "2:\tcall __lll_timedlock_wait\n"                      \
+                      "3:\tjmp 18f\n"                                        \
+                      "4:\t.size _L_timedlock_%=, 4b-1b\n\t"                 \
+                      ".previous\n"                                          \
+                      LLL_STUB_UNWIND_INFO_4                                 \
+                      "18:"                                                  \
+                      : "=a" (__result), "=c" (ignore1), "=&d" (ignore2),      \
+                        "=m" (futex), "=S" (ignore3)                         \
+                      : "0" (0), "1" (1), "m" (futex), "m" (timeout),        \
+                        "4" ((int) (private))                                \
+                      : "memory");                                           \
+     __result; })
+
+
+#define lll_robust_timedlock(futex, timeout, id, private) \
+  ({ int __result, ignore1, ignore2, ignore3;                                \
+     __asm__ __volatile (LOCK_INSTR "cmpxchgl %1, %3\n\t"                            \
+                      "jnz _L_robust_timedlock_%=\n\t"                       \
+                      ".subsection 1\n\t"                                    \
+                      ".type _L_robust_timedlock_%=,@function\n"             \
+                      "_L_robust_timedlock_%=:\n"                            \
+                      "1:\tleal %3, %%ecx\n"                                 \
+                      "0:\tmovl %8, %%edx\n"                                 \
+                      "2:\tcall __lll_robust_timedlock_wait\n"               \
+                      "3:\tjmp 18f\n"                                        \
+                      "4:\t.size _L_robust_timedlock_%=, 4b-1b\n\t"          \
+                      ".previous\n"                                          \
+                      LLL_STUB_UNWIND_INFO_4                                 \
+                      "18:"                                                  \
+                      : "=a" (__result), "=c" (ignore1), "=&d" (ignore2),      \
+                        "=m" (futex), "=S" (ignore3)                         \
+                      : "0" (0), "1" (id), "m" (futex), "m" (timeout),       \
+                        "4" ((int) (private))                                \
+                      : "memory");                                           \
+     __result; })
+
+#if defined NOT_IN_libc || defined UP
+# define __lll_unlock_asm LOCK_INSTR "subl $1, %0\n\t"
+#else
+# define __lll_unlock_asm "cmpl $0, %%gs:%P3\n\t"                            \
+                         "je 0f\n\t"                                         \
+                         "lock\n"                                            \
+                         "0:\tsubl $1,%0\n\t"
+#endif
+
+#define lll_unlock(futex, private) \
+  (void)                                                                     \
+    ({ int ignore;                                                           \
+       if (__builtin_constant_p (private) && (private) == LLL_PRIVATE)       \
+        __asm__ __volatile (__lll_unlock_asm                                 \
+                          "jne _L_unlock_%=\n\t"                             \
+                          ".subsection 1\n\t"                                \
+                          ".type _L_unlock_%=,@function\n"                   \
+                          "_L_unlock_%=:\n"                                  \
+                          "1:\tleal %0, %%eax\n"                             \
+                          "2:\tcall __lll_unlock_wake_private\n"             \
+                          "3:\tjmp 18f\n"                                    \
+                          "4:\t.size _L_unlock_%=, 4b-1b\n\t"                \
+                          ".previous\n"                                      \
+                          LLL_STUB_UNWIND_INFO_3                             \
+                          "18:"                                              \
+                          : "=m" (futex), "=&a" (ignore)                     \
+                          : "m" (futex), "i" (MULTIPLE_THREADS_OFFSET)       \
+                          : "memory");                                       \
+       else                                                                  \
+        {                                                                    \
+          int ignore2;                                                       \
+          __asm__ __volatile (__lll_unlock_asm                               \
+                            "jne _L_unlock_%=\n\t"                           \
+                            ".subsection 1\n\t"                              \
+                            ".type _L_unlock_%=,@function\n"                 \
+                            "_L_unlock_%=:\n"                                \
+                            "1:\tleal %0, %%eax\n"                           \
+                            "0:\tmovl %5, %%ecx\n"                           \
+                            "2:\tcall __lll_unlock_wake\n"                   \
+                            "3:\tjmp 18f\n"                                  \
+                            "4:\t.size _L_unlock_%=, 4b-1b\n\t"              \
+                            ".previous\n"                                    \
+                            LLL_STUB_UNWIND_INFO_4                           \
+                            "18:"                                            \
+                            : "=m" (futex), "=&a" (ignore), "=&c" (ignore2)  \
+                            : "i" (MULTIPLE_THREADS_OFFSET), "m" (futex),    \
+                              "g" ((int) (private))                          \
+                            : "memory");                                     \
+        }                                                                    \
+    })
+
+#define lll_robust_unlock(futex, private) \
+  (void)                                                                     \
+    ({ int ignore, ignore2;                                                  \
+       __asm__ __volatile (LOCK_INSTR "andl %3, %0\n\t"                              \
+                        "jne _L_robust_unlock_%=\n\t"                        \
+                        ".subsection 1\n\t"                                  \
+                        ".type _L_robust_unlock_%=,@function\n"              \
+                        "_L_robust_unlock_%=:\n\t"                           \
+                        "1:\tleal %0, %%eax\n"                               \
+                        "0:\tmovl %5, %%ecx\n"                               \
+                        "2:\tcall __lll_unlock_wake\n"                       \
+                        "3:\tjmp 18f\n"                                      \
+                        "4:\t.size _L_robust_unlock_%=, 4b-1b\n\t"           \
+                        ".previous\n"                                        \
+                        LLL_STUB_UNWIND_INFO_4                               \
+                        "18:"                                                \
+                        : "=m" (futex), "=&a" (ignore), "=&c" (ignore2)      \
+                        : "i" (FUTEX_WAITERS), "m" (futex),                  \
+                          "g" ((int) (private))                              \
+                        : "memory");                                         \
+    })
+
+
+#define lll_robust_dead(futex, private) \
+  (void)                                                                     \
+    ({ int __ignore;                                                         \
+       register int _nr __asm__ ("edx") = 1;                                 \
+       __asm__ __volatile (LOCK_INSTR "orl %5, (%2)\n\t"                             \
+                        LLL_EBX_LOAD                                         \
+                        LLL_ENTER_KERNEL                                     \
+                        LLL_EBX_LOAD                                         \
+                        : "=a" (__ignore)                                    \
+                        : "0" (SYS_futex), LLL_EBX_REG (&(futex)),           \
+                          "c" (__lll_private_flag (FUTEX_WAKE, private)),    \
+                          "d" (_nr), "i" (FUTEX_OWNER_DIED),                 \
+                          "i" (offsetof (tcbhead_t, sysinfo)));              \
+    })
+
+#define lll_islocked(futex) \
+  (futex != LLL_LOCK_INITIALIZER)
+
+/* The kernel notifies a process with uses CLONE_CLEARTID via futex
+   wakeup when the clone terminates.  The memory location contains the
+   thread ID while the clone is running and is reset to zero
+   afterwards.
+
+   The macro parameter must not have any side effect.  */
+#define lll_wait_tid(tid) \
+  do {                                                                       \
+    int __ignore;                                                            \
+    register __typeof (tid) _tid __asm__ ("edx") = (tid);                            \
+    if (_tid != 0)                                                           \
+      __asm__ __volatile (LLL_EBX_LOAD                                       \
+                       "1:\tmovl %1, %%eax\n\t"                              \
+                       LLL_ENTER_KERNEL                                      \
+                       "cmpl $0, (%%ebx)\n\t"                                \
+                       "jne 1b\n\t"                                          \
+                       LLL_EBX_LOAD                                          \
+                       : "=&a" (__ignore)                                    \
+                       : "i" (SYS_futex), LLL_EBX_REG (&tid), "S" (0),       \
+                         "c" (FUTEX_WAIT), "d" (_tid),                       \
+                         "i" (offsetof (tcbhead_t, sysinfo))                 \
+                       : "memory");                                          \
+  } while (0)
+
+extern int __lll_timedwait_tid (int *tid, const struct timespec *abstime)
+     __attribute__ ((regparm (2))) attribute_hidden;
+#define lll_timedwait_tid(tid, abstime) \
+  ({                                                                         \
+    int __result = 0;                                                        \
+    if (tid != 0)                                                            \
+      {                                                                              \
+       if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)           \
+         __result = EINVAL;                                                  \
+       else                                                                  \
+         __result = __lll_timedwait_tid (&tid, abstime);                     \
+      }                                                                              \
+    __result; })
+
+#endif  /* !__ASSEMBLER__ */
+
+#endif /* lowlevellock.h */
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/pt-__syscall_error.c b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/pt-__syscall_error.c
new file mode 100644 (file)
index 0000000..620640a
--- /dev/null
@@ -0,0 +1 @@
+#include <../../../../../../../libc/sysdeps/linux/i386/__syscall_error.c>
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/pt-vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/pt-vfork.S
new file mode 100644 (file)
index 0000000..aff926a
--- /dev/null
@@ -0,0 +1,68 @@
+/* Copyright (C) 1999, 2002, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Andreas Schwab <schwab@gnu.org>.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#define _ERRNO_H       1
+#include <bits/errno.h>
+#include <bits/kernel-features.h>
+#include <tcb-offsets.h>
+
+/* Save the PID value.  */
+#define SAVE_PID \
+       movl    %gs:PID, %edx;                                                \
+       movl    %edx, %eax;                                                   \
+       negl    %eax;                                                         \
+       movl    %eax, %gs:PID
+
+/* Restore the old PID value in the parent.  */
+#define RESTORE_PID \
+       testl   %eax, %eax;                                                   \
+       je      1f;                                                           \
+       movl    %edx, %gs:PID;                                                \
+1:
+
+/* Clone the calling process, but without copying the whole address space.
+   The calling process is suspended until the new process exits or is
+   replaced by a call to `execve'.  Return -1 for errors, 0 to the new process,
+   and the process ID of the new process to the old process.  */
+
+ENTRY (__vfork)
+       /* Pop the return PC value into ECX.  */
+       popl    %ecx
+
+       SAVE_PID
+
+       /* Stuff the syscall number in EAX and enter into the kernel.  */
+       movl    $SYS_ify (vfork), %eax
+       int     $0x80
+
+       RESTORE_PID
+
+       /* Jump to the return PC.  Don't jump directly since this
+          disturbs the branch target cache.  Instead push the return
+          address back on the stack.  */
+       pushl   %ecx
+
+       cmpl    $-4095, %eax
+       jae     SYSCALL_ERROR_LABEL     /* Branch forward if it failed.  */
+L(pseudo_end):
+       ret
+PSEUDO_END (__vfork)
+
+weak_alias (__vfork, vfork)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/pthread_once.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/pthread_once.S
new file mode 100644 (file)
index 0000000..409df15
--- /dev/null
@@ -0,0 +1,196 @@
+/* Copyright (C) 2002, 2003, 2007 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 <unwindbuf.h>
+#include <sysdep.h>
+#include <bits/kernel-features.h>
+#include <lowlevellock.h>
+#include <tls.h>
+
+
+       .comm   __fork_generation, 4, 4
+
+       .text
+
+
+       .globl  __pthread_once
+       .type   __pthread_once,@function
+       .align  16
+       cfi_startproc
+__pthread_once:
+       movl    4(%esp), %ecx
+       testl   $2, (%ecx)
+       jz      1f
+       xorl    %eax, %eax
+       ret
+
+1:     pushl   %ebx
+       cfi_adjust_cfa_offset (4)
+       cfi_rel_offset (3, 0)
+       pushl   %esi
+       cfi_adjust_cfa_offset (4)
+       cfi_rel_offset (6, 0)
+       movl    %ecx, %ebx
+       xorl    %esi, %esi
+
+       /* Not yet initialized or initialization in progress.
+          Get the fork generation counter now.  */
+6:     movl    (%ebx), %eax
+#ifdef __PIC__
+       call    __x86.get_pc_thunk.cx
+       addl    $_GLOBAL_OFFSET_TABLE_, %ecx
+#endif
+
+5:     movl    %eax, %edx
+
+       testl   $2, %eax
+       jnz     4f
+
+       andl    $3, %edx
+#ifdef __PIC__
+       orl     __fork_generation@GOTOFF(%ecx), %edx
+#else
+       orl     __fork_generation, %edx
+#endif
+       orl     $1, %edx
+
+       LOCK
+       cmpxchgl %edx, (%ebx)
+       jnz     5b
+
+       /* Check whether another thread already runs the initializer.  */
+       testl   $1, %eax
+       jz      3f      /* No -> do it.  */
+
+       /* Check whether the initializer execution was interrupted
+          by a fork.  */
+       xorl    %edx, %eax
+       testl   $0xfffffffc, %eax
+       jnz     3f      /* Different for generation -> run initializer.  */
+
+       /* Somebody else got here first.  Wait.  */
+#ifdef __ASSUME_PRIVATE_FUTEX
+       movl    $FUTEX_WAIT|FUTEX_PRIVATE_FLAG, %ecx
+#else
+# if FUTEX_WAIT == 0
+       movl    %gs:PRIVATE_FUTEX, %ecx
+# else
+       movl    $FUTEX_WAIT, %ecx
+       orl     %gs:PRIVATE_FUTEX, %ecx
+# endif
+#endif
+       movl    $SYS_futex, %eax
+       ENTER_KERNEL
+       jmp     6b
+
+3:     /* Call the initializer function after setting up the
+          cancellation handler.  Note that it is not possible here
+          to use the unwind-based cleanup handling.  This would require
+          that the user-provided function and all the code it calls
+          is compiled with exceptions.  Unfortunately this cannot be
+          guaranteed.  */
+       subl    $UNWINDBUFSIZE+8, %esp
+       cfi_adjust_cfa_offset (UNWINDBUFSIZE+8)
+       movl    %ecx, %ebx              /* PIC register value.  */
+
+       leal    8+UWJMPBUF(%esp), %eax
+       movl    $0, 4(%esp)
+       movl    %eax, (%esp)
+       call    __sigsetjmp@PLT
+       testl   %eax, %eax
+       jne     7f
+
+       leal    8(%esp), %eax
+       call    HIDDEN_JUMPTARGET(__pthread_register_cancel)
+
+       /* Call the user-provided initialization function.  */
+       call    *24+UNWINDBUFSIZE(%esp)
+
+       /* Pop the cleanup handler.  */
+       leal    8(%esp), %eax
+       call    HIDDEN_JUMPTARGET(__pthread_unregister_cancel)
+       addl    $UNWINDBUFSIZE+8, %esp
+       cfi_adjust_cfa_offset (-UNWINDBUFSIZE-8)
+
+       /* Sucessful run of the initializer.  Signal that we are done.  */
+       movl    12(%esp), %ebx
+       LOCK
+       addl    $1, (%ebx)
+
+       /* Wake up all other threads.  */
+       movl    $0x7fffffff, %edx
+#ifdef __ASSUME_PRIVATE_FUTEX
+       movl    $FUTEX_WAKE|FUTEX_PRIVATE_FLAG, %ecx
+#else
+       movl    $FUTEX_WAKE, %ecx
+       orl     %gs:PRIVATE_FUTEX, %ecx
+#endif
+       movl    $SYS_futex, %eax
+       ENTER_KERNEL
+
+4:     popl    %esi
+       cfi_adjust_cfa_offset (-4)
+       cfi_restore (6)
+       popl    %ebx
+       cfi_adjust_cfa_offset (-4)
+       cfi_restore (3)
+       xorl    %eax, %eax
+       ret
+
+7:     /* __sigsetjmp returned for the second time.  */
+       movl    20+UNWINDBUFSIZE(%esp), %ebx
+       cfi_adjust_cfa_offset (UNWINDBUFSIZE+16)
+       cfi_offset (3, -8)
+       cfi_offset (6, -12)
+       movl    $0, (%ebx)
+
+       movl    $0x7fffffff, %edx
+#ifdef __ASSUME_PRIVATE_FUTEX
+       movl    $FUTEX_WAKE|FUTEX_PRIVATE_FLAG, %ecx
+#else
+       movl    $FUTEX_WAKE, %ecx
+       orl     %gs:PRIVATE_FUTEX, %ecx
+#endif
+       movl    $SYS_futex, %eax
+       ENTER_KERNEL
+
+       leal    8(%esp), %eax
+       call    HIDDEN_JUMPTARGET (__pthread_unwind_next)
+       /* NOTREACHED */
+       hlt
+       cfi_endproc
+       .size   __pthread_once,.-__pthread_once
+
+       .globl  __pthread_once_internal
+__pthread_once_internal = __pthread_once
+
+       .globl  pthread_once
+pthread_once = __pthread_once
+
+
+#ifdef __PIC__
+       .section .gnu.linkonce.t.__x86.get_pc_thunk.cx,"ax",@progbits
+       .globl  __x86.get_pc_thunk.cx
+       .hidden __x86.get_pc_thunk.cx
+       .type   __x86.get_pc_thunk.cx,@function
+__x86.get_pc_thunk.cx:
+       movl (%esp), %ecx;
+       ret
+       .size   __x86.get_pc_thunk.cx,.-__x86.get_pc_thunk.cx
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/pthread_spin_init.c b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/pthread_spin_init.c
new file mode 100644 (file)
index 0000000..d36e537
--- /dev/null
@@ -0,0 +1 @@
+#include <sysdeps/i386/pthread_spin_init.c>
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/pthread_spin_unlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/pthread_spin_unlock.S
new file mode 100644 (file)
index 0000000..8bae0fd
--- /dev/null
@@ -0,0 +1 @@
+#include <sysdeps/i386/pthread_spin_unlock.S>
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/smp.h b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/smp.h
new file mode 100644 (file)
index 0000000..f68a0c0
--- /dev/null
@@ -0,0 +1,56 @@
+/* Determine whether the host has multiple processors.  Linux version.
+   Copyright (C) 1996, 2002, 2004, 2006 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/utsname.h>
+#include <not-cancel.h>
+
+/* Test whether the machine has more than one processor.  This is not the
+   best test but good enough.  More complicated tests would require `malloc'
+   which is not available at that time.  */
+static inline int
+is_smp_system (void)
+{
+  union
+  {
+    struct utsname uts;
+    char buf[512];
+  } u;
+  char *cp;
+
+  /* Try reading the number using `sysctl' first.  */
+  if (uname (&u.uts) == 0)
+    cp = u.uts.version;
+  else
+    {
+      /* This was not successful.  Now try reading the /proc filesystem.  */
+      int fd = open_not_cancel_2 ("/proc/sys/kernel/version", O_RDONLY);
+      if (__builtin_expect (fd, 0) == -1
+         || read_not_cancel (fd, u.buf, sizeof (u.buf)) <= 0)
+       /* This also didn't work.  We give up and say it's a UP machine.  */
+       u.buf[0] = '\0';
+
+      close_not_cancel_no_status (fd);
+      cp = u.buf;
+    }
+
+  return strstr (cp, "SMP") != NULL;
+}
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/sysdep-cancel.h
new file mode 100644 (file)
index 0000000..cb8d689
--- /dev/null
@@ -0,0 +1,155 @@
+/* Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <tls.h>
+#ifndef __ASSEMBLER__
+# include <pthreadP.h>
+#endif
+
+#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt
+
+# undef PSEUDO
+# define PSEUDO(name, syscall_name, args)                                    \
+  .text;                                                                     \
+  ENTRY (name)                                                               \
+    cmpl $0, %gs:MULTIPLE_THREADS_OFFSET;                                    \
+    jne L(pseudo_cancel);                                                    \
+  .type __##syscall_name##_nocancel,@function;                               \
+  .globl __##syscall_name##_nocancel;                                        \
+  __##syscall_name##_nocancel:                                               \
+    DO_CALL (syscall_name, args);                                            \
+    cmpl $-4095, %eax;                                                       \
+    jae SYSCALL_ERROR_LABEL;                                                 \
+    ret;                                                                     \
+  .size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel;           \
+  L(pseudo_cancel):                                                          \
+    CENABLE                                                                  \
+    SAVE_OLDTYPE_##args                                                              \
+    PUSHCARGS_##args                                                         \
+    DOCARGS_##args                                                           \
+    movl $SYS_ify (syscall_name), %eax;                                              \
+    ENTER_KERNEL;                                                            \
+    POPCARGS_##args;                                                         \
+    POPSTATE_##args                                                          \
+    cmpl $-4095, %eax;                                                       \
+    jae SYSCALL_ERROR_LABEL;                                                 \
+  L(pseudo_end):
+
+# define SAVE_OLDTYPE_0        movl %eax, %ecx;
+# define SAVE_OLDTYPE_1        SAVE_OLDTYPE_0
+# define SAVE_OLDTYPE_2        pushl %eax; cfi_adjust_cfa_offset (4);
+# define SAVE_OLDTYPE_3        SAVE_OLDTYPE_2
+# define SAVE_OLDTYPE_4        SAVE_OLDTYPE_2
+# define SAVE_OLDTYPE_5        SAVE_OLDTYPE_2
+# define SAVE_OLDTYPE_6        SAVE_OLDTYPE_2
+
+# define PUSHCARGS_0   /* No arguments to push.  */
+# define DOCARGS_0     /* No arguments to frob.  */
+# define POPCARGS_0    /* No arguments to pop.  */
+# define _PUSHCARGS_0  /* No arguments to push.  */
+# define _POPCARGS_0   /* No arguments to pop.  */
+
+# define PUSHCARGS_1   movl %ebx, %edx; cfi_register (ebx, edx); PUSHCARGS_0
+# define DOCARGS_1     _DOARGS_1 (4)
+# define POPCARGS_1    POPCARGS_0; movl %edx, %ebx; cfi_restore (ebx);
+# define _PUSHCARGS_1  pushl %ebx; cfi_adjust_cfa_offset (4); \
+                       cfi_rel_offset (ebx, 0); _PUSHCARGS_0
+# define _POPCARGS_1   _POPCARGS_0; popl %ebx; \
+                       cfi_adjust_cfa_offset (-4); cfi_restore (ebx);
+
+# define PUSHCARGS_2   PUSHCARGS_1
+# define DOCARGS_2     _DOARGS_2 (12)
+# define POPCARGS_2    POPCARGS_1
+# define _PUSHCARGS_2  _PUSHCARGS_1
+# define _POPCARGS_2   _POPCARGS_1
+
+# define PUSHCARGS_3   _PUSHCARGS_2
+# define DOCARGS_3     _DOARGS_3 (20)
+# define POPCARGS_3    _POPCARGS_3
+# define _PUSHCARGS_3  _PUSHCARGS_2
+# define _POPCARGS_3   _POPCARGS_2
+
+# define PUSHCARGS_4   _PUSHCARGS_4
+# define DOCARGS_4     _DOARGS_4 (28)
+# define POPCARGS_4    _POPCARGS_4
+# define _PUSHCARGS_4  pushl %esi; cfi_adjust_cfa_offset (4); \
+                       cfi_rel_offset (esi, 0); _PUSHCARGS_3
+# define _POPCARGS_4   _POPCARGS_3; popl %esi; \
+                       cfi_adjust_cfa_offset (-4); cfi_restore (esi);
+
+# define PUSHCARGS_5   _PUSHCARGS_5
+# define DOCARGS_5     _DOARGS_5 (36)
+# define POPCARGS_5    _POPCARGS_5
+# define _PUSHCARGS_5  pushl %edi; cfi_adjust_cfa_offset (4); \
+                       cfi_rel_offset (edi, 0); _PUSHCARGS_4
+# define _POPCARGS_5   _POPCARGS_4; popl %edi; \
+                       cfi_adjust_cfa_offset (-4); cfi_restore (edi);
+
+# define PUSHCARGS_6   _PUSHCARGS_6
+# define DOCARGS_6     _DOARGS_6 (44)
+# define POPCARGS_6    _POPCARGS_6
+# define _PUSHCARGS_6  pushl %ebp; cfi_adjust_cfa_offset (4); \
+                       cfi_rel_offset (ebp, 0); _PUSHCARGS_5
+# define _POPCARGS_6   _POPCARGS_5; popl %ebp; \
+                       cfi_adjust_cfa_offset (-4); cfi_restore (ebp);
+
+# ifdef IS_IN_libpthread
+#  define CENABLE      call __pthread_enable_asynccancel;
+#  define CDISABLE     call __pthread_disable_asynccancel
+# elif !defined NOT_IN_libc
+#  define CENABLE      call __libc_enable_asynccancel;
+#  define CDISABLE     call __libc_disable_asynccancel
+# elif defined IS_IN_librt
+#  define CENABLE      call __librt_enable_asynccancel;
+#  define CDISABLE     call __librt_disable_asynccancel
+# else
+#  error Unsupported library
+# endif
+# define POPSTATE_0 \
+ pushl %eax; cfi_adjust_cfa_offset (4); movl %ecx, %eax; \
+ CDISABLE; popl %eax; cfi_adjust_cfa_offset (-4);
+# define POPSTATE_1    POPSTATE_0
+# define POPSTATE_2    xchgl (%esp), %eax; CDISABLE; popl %eax; \
+                       cfi_adjust_cfa_offset (-4);
+# define POPSTATE_3    POPSTATE_2
+# define POPSTATE_4    POPSTATE_3
+# define POPSTATE_5    POPSTATE_4
+# define POPSTATE_6    POPSTATE_5
+
+# ifndef __ASSEMBLER__
+#  define SINGLE_THREAD_P \
+  __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
+                                  header.multiple_threads) == 0, 1)
+# else
+#  define SINGLE_THREAD_P cmpl $0, %gs:MULTIPLE_THREADS_OFFSET
+# endif
+
+#elif !defined __ASSEMBLER__
+
+# define SINGLE_THREAD_P (1)
+# define NO_CANCELLATION 1
+
+#endif
+
+#ifndef __ASSEMBLER__
+# define RTLD_SINGLE_THREAD_P \
+  __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
+                                  header.multiple_threads) == 0, 1)
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/vfork.S
new file mode 100644 (file)
index 0000000..b39099a
--- /dev/null
@@ -0,0 +1,38 @@
+/* Copyright (C) 1999,2002,2004,2006 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <tcb-offsets.h>
+
+/* Save the PID value.  */
+#define SAVE_PID \
+       movl    %gs:PID, %edx;                                                \
+       movl    %edx, %eax;                                                   \
+       negl    %eax;                                                         \
+       jne     1f;                                                           \
+       movl    $0x80000000, %eax;                                            \
+1:     movl    %eax, %gs:PID
+
+/* Restore the old PID value in the parent.  */
+#define RESTORE_PID \
+       testl   %eax, %eax;                                                   \
+       je      1f;                                                           \
+       movl    %edx, %gs:PID;                                                \
+1:
+
+
+#include <libc/sysdeps/linux/i386/vfork.S>
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/internaltypes.h b/libpthread/nptl/sysdeps/unix/sysv/linux/internaltypes.h
new file mode 100644 (file)
index 0000000..3466c7f
--- /dev/null
@@ -0,0 +1,162 @@
+/* Copyright (C) 2002, 2003, 2004, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _INTERNALTYPES_H
+#define _INTERNALTYPES_H       1
+
+#include <stdint.h>
+#include <sched.h>
+
+struct pthread_attr
+{
+  /* Scheduler parameters and priority.  */
+  struct sched_param schedparam;
+  int schedpolicy;
+  /* Various flags like detachstate, scope, etc.  */
+  int flags;
+  /* Size of guard area.  */
+  size_t guardsize;
+  /* Stack handling.  */
+  void *stackaddr;
+  size_t stacksize;
+  /* Affinity map.  */
+  cpu_set_t *cpuset;
+  size_t cpusetsize;
+};
+
+#define ATTR_FLAG_DETACHSTATE          0x0001
+#define ATTR_FLAG_NOTINHERITSCHED      0x0002
+#define ATTR_FLAG_SCOPEPROCESS         0x0004
+#define ATTR_FLAG_STACKADDR            0x0008
+#define ATTR_FLAG_OLDATTR              0x0010
+#define ATTR_FLAG_SCHED_SET            0x0020
+#define ATTR_FLAG_POLICY_SET           0x0040
+
+
+/* Mutex attribute data structure.  */
+struct pthread_mutexattr
+{
+  /* Identifier for the kind of mutex.
+
+     Bit 31 is set if the mutex is to be shared between processes.
+
+     Bit 0 to 30 contain one of the PTHREAD_MUTEX_ values to identify
+     the type of the mutex.  */
+  int mutexkind;
+};
+
+
+/* Conditional variable attribute data structure.  */
+struct pthread_condattr
+{
+  /* Combination of values:
+
+     Bit 0  : flag whether coditional variable will be shareable between
+             processes.
+
+     Bit 1-7: clock ID.  */
+  int value;
+};
+
+
+/* The __NWAITERS field is used as a counter and to house the number
+   of bits for other purposes.  COND_CLOCK_BITS is the number
+   of bits needed to represent the ID of the clock.  COND_NWAITERS_SHIFT
+   is the number of bits reserved for other purposes like the clock.  */
+#define COND_CLOCK_BITS                1
+#define COND_NWAITERS_SHIFT    1
+
+
+/* Read-write lock variable attribute data structure.  */
+struct pthread_rwlockattr
+{
+  int lockkind;
+  int pshared;
+};
+
+
+/* Barrier data structure.  */
+struct pthread_barrier
+{
+  unsigned int curr_event;
+  int lock;
+  unsigned int left;
+  unsigned int init_count;
+  int private;
+};
+
+
+/* Barrier variable attribute data structure.  */
+struct pthread_barrierattr
+{
+  int pshared;
+};
+
+
+/* Thread-local data handling.  */
+struct pthread_key_struct
+{
+  /* Sequence numbers.  Even numbers indicated vacant entries.  Note
+     that zero is even.  We use uintptr_t to not require padding on
+     32- and 64-bit machines.  On 64-bit machines it helps to avoid
+     wrapping, too.  */
+  uintptr_t seq;
+
+  /* Destructor for the data.  */
+  void (*destr) (void *);
+};
+
+/* Check whether an entry is unused.  */
+#define KEY_UNUSED(p) (((p) & 1) == 0)
+/* Check whether a key is usable.  We cannot reuse an allocated key if
+   the sequence counter would overflow after the next destroy call.
+   This would mean that we potentially free memory for a key with the
+   same sequence.  This is *very* unlikely to happen, A program would
+   have to create and destroy a key 2^31 times (on 32-bit platforms,
+   on 64-bit platforms that would be 2^63).  If it should happen we
+   simply don't use this specific key anymore.  */
+#define KEY_USABLE(p) (((uintptr_t) (p)) < ((uintptr_t) ((p) + 2)))
+
+
+/* Handling of read-write lock data.  */
+// XXX For now there is only one flag.  Maybe more in future.
+#define RWLOCK_RECURSIVE(rwlock) ((rwlock)->__data.__flags != 0)
+
+
+/* Semaphore variable structure.  */
+struct new_sem
+{
+  unsigned int value;
+  int private;
+  unsigned long int nwaiters;
+};
+
+struct old_sem
+{
+  unsigned int value;
+};
+
+
+/* Compatibility type for old conditional variable interfaces.  */
+typedef struct
+{
+  pthread_cond_t *cond;
+} pthread_cond_2_0_t;
+
+#endif /* internaltypes.h */
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/jmp-unwind.c b/libpthread/nptl/sysdeps/unix/sysv/linux/jmp-unwind.c
new file mode 100644 (file)
index 0000000..f279551
--- /dev/null
@@ -0,0 +1,39 @@
+/* Clean up stack frames unwound by longjmp.  Linux version.
+   Copyright (C) 1995, 1997, 2002, 2003, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <setjmp.h>
+#include <stddef.h>
+#include <pthreadP.h>
+
+extern void __pthread_cleanup_upto (__jmp_buf env, char *targetframe);
+#pragma weak __pthread_cleanup_upto
+
+
+void
+_longjmp_unwind (jmp_buf env, int val)
+{
+#ifdef SHARED
+  if (__libc_pthread_functions_init)
+    PTHFCT_CALL (ptr___pthread_cleanup_upto, (env->__jmpbuf,
+                                             CURRENT_STACK_FRAME));
+#else
+  if (__pthread_cleanup_upto != NULL)
+    __pthread_cleanup_upto (env->__jmpbuf, CURRENT_STACK_FRAME);
+#endif
+}
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/kernel-posix-timers.h b/libpthread/nptl/sysdeps/unix/sysv/linux/kernel-posix-timers.h
new file mode 100644 (file)
index 0000000..9be6302
--- /dev/null
@@ -0,0 +1 @@
+#include <../../../../../../librt/kernel-posix-timers.h>
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/libc-lowlevellock.c b/libpthread/nptl/sysdeps/unix/sysv/linux/libc-lowlevellock.c
new file mode 100644 (file)
index 0000000..b192822
--- /dev/null
@@ -0,0 +1,21 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* No difference to lowlevellock.c, except we lose a couple of functions.  */
+#include "lowlevellock.c"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/libc_multiple_threads.c b/libpthread/nptl/sysdeps/unix/sysv/linux/libc_multiple_threads.c
new file mode 100644 (file)
index 0000000..a96f174
--- /dev/null
@@ -0,0 +1,26 @@
+/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthreadP.h>
+
+#ifndef NOT_IN_libc
+# ifndef TLS_MULTIPLE_THREADS_IN_TCB
+int __libc_multiple_threads attribute_hidden;
+# endif
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/libc_pthread_init.c b/libpthread/nptl/sysdeps/unix/sysv/linux/libc_pthread_init.c
new file mode 100644 (file)
index 0000000..136b445
--- /dev/null
@@ -0,0 +1,74 @@
+/* Copyright (C) 2002,2003,2005,2006,2007,2009 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <unistd.h>
+#include <list.h>
+#include <fork.h>
+#include <dl-sysdep.h>
+#include <tls.h>
+#include <string.h>
+#include <pthreadP.h>
+#include <bits/libc-lock.h>
+#include <sysdep.h>
+#include <ldsodefs.h>
+
+
+#ifdef TLS_MULTIPLE_THREADS_IN_TCB
+void
+#else
+extern int __libc_multiple_threads attribute_hidden;
+
+int *
+#endif
+__libc_pthread_init (
+     unsigned long int *ptr,
+     void (*reclaim) (void),
+     const struct pthread_functions *functions)
+{
+  /* Remember the pointer to the generation counter in libpthread.  */
+  __fork_generation_pointer = ptr;
+
+  /* Called by a child after fork.  */
+  __register_atfork (NULL, NULL, reclaim, NULL);
+
+#ifdef SHARED
+  /* We copy the content of the variable pointed to by the FUNCTIONS
+     parameter to one in libc.so since this means access to the array
+     can be done with one memory access instead of two.
+   */
+   memcpy (&__libc_pthread_functions, functions,
+           sizeof (__libc_pthread_functions));
+  __libc_pthread_functions_init = 1;
+#endif
+
+#ifndef TLS_MULTIPLE_THREADS_IN_TCB
+  return &__libc_multiple_threads;
+#endif
+}
+
+#ifdef SHARED
+#if 0
+void
+libc_freeres_fn (freeres_libptread)
+{
+  if (__libc_pthread_functions_init)
+    PTHFCT_CALL (ptr_freeres, ());
+}
+#endif
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevelbarrier.sym b/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevelbarrier.sym
new file mode 100644 (file)
index 0000000..cfe22b0
--- /dev/null
@@ -0,0 +1,12 @@
+#include <stddef.h>
+#include <sched.h>
+#include <bits/pthreadtypes.h>
+#include "internaltypes.h"
+
+--
+
+CURR_EVENT             offsetof (struct pthread_barrier, curr_event)
+MUTEX                  offsetof (struct pthread_barrier, lock)
+LEFT                   offsetof (struct pthread_barrier, left)
+INIT_COUNT             offsetof (struct pthread_barrier, init_count)
+PRIVATE                        offsetof (struct pthread_barrier, private)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevelcond.sym b/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevelcond.sym
new file mode 100644 (file)
index 0000000..18e1ada
--- /dev/null
@@ -0,0 +1,16 @@
+#include <stddef.h>
+#include <sched.h>
+#include <bits/pthreadtypes.h>
+#include <internaltypes.h>
+
+--
+
+cond_lock      offsetof (pthread_cond_t, __data.__lock)
+cond_futex     offsetof (pthread_cond_t, __data.__futex)
+cond_nwaiters  offsetof (pthread_cond_t, __data.__nwaiters)
+total_seq      offsetof (pthread_cond_t, __data.__total_seq)
+wakeup_seq     offsetof (pthread_cond_t, __data.__wakeup_seq)
+woken_seq      offsetof (pthread_cond_t, __data.__woken_seq)
+dep_mutex      offsetof (pthread_cond_t, __data.__mutex)
+broadcast_seq  offsetof (pthread_cond_t, __data.__broadcast_seq)
+nwaiters_shift COND_NWAITERS_SHIFT
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevellock.c b/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevellock.c
new file mode 100644 (file)
index 0000000..e07d788
--- /dev/null
@@ -0,0 +1,127 @@
+/* low level locking for pthread library.  Generic futex-using version.
+   Copyright (C) 2003, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <sys/time.h>
+#include <tls.h>
+#include <tcb-offsets.h>
+
+
+void
+__lll_lock_wait_private (int *futex)
+{
+  if (*futex == 2)
+    lll_futex_wait (futex, 2, LLL_PRIVATE);
+
+  while (atomic_exchange_acq (futex, 2) != 0)
+    lll_futex_wait (futex, 2, LLL_PRIVATE);
+}
+
+
+/* These functions don't get included in libc.so  */
+#ifdef IS_IN_libpthread
+void
+__lll_lock_wait (int *futex, int private)
+{
+  if (*futex == 2)
+    lll_futex_wait (futex, 2, private);
+
+  while (atomic_exchange_acq (futex, 2) != 0)
+    lll_futex_wait (futex, 2, private);
+}
+
+
+int
+__lll_timedlock_wait (int *futex, const struct timespec *abstime, int private)
+{
+  /* Reject invalid timeouts.  */
+  if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)
+    return EINVAL;
+
+  /* Try locking.  */
+  while (atomic_exchange_acq (futex, 2) != 0)
+    {
+      struct timeval tv;
+
+      /* Get the current time.  */
+      (void) gettimeofday (&tv, NULL);
+
+      /* Compute relative timeout.  */
+      struct timespec rt;
+      rt.tv_sec = abstime->tv_sec - tv.tv_sec;
+      rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000;
+      if (rt.tv_nsec < 0)
+       {
+         rt.tv_nsec += 1000000000;
+         --rt.tv_sec;
+       }
+
+      if (rt.tv_sec < 0)
+       return ETIMEDOUT;
+
+      /* Wait.  */
+      lll_futex_timed_wait (futex, 2, &rt, private);
+    }
+
+  return 0;
+}
+
+
+int
+__lll_timedwait_tid (int *tidp, const struct timespec *abstime)
+{
+  int tid;
+
+  if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)
+    return EINVAL;
+
+  /* Repeat until thread terminated.  */
+  while ((tid = *tidp) != 0)
+    {
+      struct timeval tv;
+      struct timespec rt;
+
+      /* Get the current time.  */
+      (void) __gettimeofday (&tv, NULL);
+
+      /* Compute relative timeout.  */
+      rt.tv_sec = abstime->tv_sec - tv.tv_sec;
+      rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000;
+      if (rt.tv_nsec < 0)
+       {
+         rt.tv_nsec += 1000000000;
+         --rt.tv_sec;
+       }
+
+      /* Already timed out?  */
+      if (rt.tv_sec < 0)
+       return ETIMEDOUT;
+
+      /* Wait until thread terminates.  The kernel so far does not use
+        the private futex operations for this.  */
+      if (lll_futex_timed_wait (tidp, tid, &rt, LLL_SHARED) == -ETIMEDOUT)
+       return ETIMEDOUT;
+    }
+
+  return 0;
+}
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevelrobustlock.c b/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevelrobustlock.c
new file mode 100644 (file)
index 0000000..3830f94
--- /dev/null
@@ -0,0 +1,114 @@
+/* Copyright (C) 2006, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2006.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <sys/time.h>
+#include <pthreadP.h>
+
+
+int
+__lll_robust_lock_wait (int *futex, int private)
+{
+  int oldval = *futex;
+  int tid = THREAD_GETMEM (THREAD_SELF, tid);
+
+  /* If the futex changed meanwhile try locking again.  */
+  if (oldval == 0)
+    goto try;
+
+  do
+    {
+      if (__builtin_expect (oldval & FUTEX_OWNER_DIED, 0))
+       return oldval;
+
+      int newval = oldval | FUTEX_WAITERS;
+      if (oldval != newval
+         && atomic_compare_and_exchange_bool_acq (futex, newval, oldval))
+       continue;
+
+      lll_futex_wait (futex, newval, private);
+
+    try:
+      ;
+    }
+  while ((oldval = atomic_compare_and_exchange_val_acq (futex,
+                                                       tid | FUTEX_WAITERS,
+                                                       0)) != 0);
+  return 0;
+}
+
+
+int
+__lll_robust_timedlock_wait (int *futex, const struct timespec *abstime,
+                            int private)
+{
+  /* Reject invalid timeouts.  */
+  if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)
+    return EINVAL;
+
+  int tid = THREAD_GETMEM (THREAD_SELF, tid);
+  int oldval = *futex;
+
+  /* If the futex changed meanwhile try locking again.  */
+  if (oldval == 0)
+    goto try;
+
+  do
+    {
+      struct timeval tv;
+      struct timespec rt;
+
+      /* Get the current time.  */
+      (void) __gettimeofday (&tv, NULL);
+
+      /* Compute relative timeout.  */
+      rt.tv_sec = abstime->tv_sec - tv.tv_sec;
+      rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000;
+      if (rt.tv_nsec < 0)
+       {
+         rt.tv_nsec += 1000000000;
+         --rt.tv_sec;
+       }
+
+      /* Already timed out?  */
+      if (rt.tv_sec < 0)
+       return ETIMEDOUT;
+
+      /* Wait.  */
+      if (__builtin_expect (oldval & FUTEX_OWNER_DIED, 0))
+       return oldval;
+
+      int newval = oldval | FUTEX_WAITERS;
+      if (oldval != newval
+         && atomic_compare_and_exchange_bool_acq (futex, newval, oldval))
+       continue;
+
+      lll_futex_timed_wait (futex, newval, &rt, private);
+
+    try:
+      ;
+    }
+  while ((oldval = atomic_compare_and_exchange_val_acq (futex,
+                                                       tid | FUTEX_WAITERS,
+                                                       0)) != 0);
+
+  return 0;
+}
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevelrobustlock.sym b/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevelrobustlock.sym
new file mode 100644 (file)
index 0000000..2f1e9da
--- /dev/null
@@ -0,0 +1,6 @@
+#include <stddef.h>
+#include <pthreadP.h>
+
+--
+
+TID            offsetof (struct pthread, tid)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevelrwlock.sym b/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevelrwlock.sym
new file mode 100644 (file)
index 0000000..f50b25b
--- /dev/null
@@ -0,0 +1,16 @@
+#include <stddef.h>
+#include <stdio.h>
+#include <bits/pthreadtypes.h>
+#include <bits/wordsize.h>
+
+--
+
+MUTEX          offsetof (pthread_rwlock_t, __data.__lock)
+NR_READERS     offsetof (pthread_rwlock_t, __data.__nr_readers)
+READERS_WAKEUP offsetof (pthread_rwlock_t, __data.__readers_wakeup)
+WRITERS_WAKEUP offsetof (pthread_rwlock_t, __data.__writer_wakeup)
+READERS_QUEUED offsetof (pthread_rwlock_t, __data.__nr_readers_queued)
+WRITERS_QUEUED offsetof (pthread_rwlock_t, __data.__nr_writers_queued)
+FLAGS          offsetof (pthread_rwlock_t, __data.__flags)
+WRITER         offsetof (pthread_rwlock_t, __data.__writer)
+PSHARED                offsetof (pthread_rwlock_t, __data.__shared)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/lseek.S b/libpthread/nptl/sysdeps/unix/sysv/linux/lseek.S
new file mode 100644 (file)
index 0000000..70a920b
--- /dev/null
@@ -0,0 +1,7 @@
+#include <sysdep-cancel.h>
+PSEUDO (__libc_lseek, lseek, 3)
+ret
+PSEUDO_END (__libc_lseek)
+libc_hidden_def (__libc_lseek)
+weak_alias (__libc_lseek, lseek)
+libc_hidden_weak (lseek)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/Makefile b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/Makefile
new file mode 100644 (file)
index 0000000..43a6fad
--- /dev/null
@@ -0,0 +1,13 @@
+# Makefile for uClibc NPTL
+#
+# Copyright (C) 2005 Steven J. Hill <sjhill@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+top_srcdir=../../../../../../../
+top_builddir=../../../../../../../
+all: objs
+include $(top_builddir)Rules.mak
+include Makefile.arch
+include $(top_srcdir)Makerules
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/Makefile.arch b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/Makefile.arch
new file mode 100644 (file)
index 0000000..8e7917b
--- /dev/null
@@ -0,0 +1,50 @@
+# Makefile for uClibc NPTL
+#
+# Copyright (C) 2006 Steven J. Hill <sjhill@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+libpthread_SSRC = pt-vfork.S
+libpthread_CSRC = pthread_once.c pt-__syscall_rt_sigaction.c
+
+libc_a_CSRC = fork.c
+
+CFLAGS-OMIT-fork.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1
+ifeq ($(UCLIBC_HAS_STDIO_FUTEXES),y)
+CFLAGS-fork.c = -D__USE_STDIO_FUTEXES__
+endif
+CFLAGS-pthread_once.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1
+CFLAGS-pt-__syscall_rt_sigaction.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1
+
+ASFLAGS-pt-vfork.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1
+
+CFLAGS += $(SSP_ALL_CFLAGS)
+#CFLAGS:=$(CFLAGS:-O1=-O2)
+
+LINUX_ARCH_DIR:=$(top_srcdir)libpthread/nptl/sysdeps/unix/sysv/linux/mips
+LINUX_ARCH_OUT:=$(top_builddir)libpthread/nptl/sysdeps/unix/sysv/linux/mips
+
+LINUX_ARCH_OBJ:=$(patsubst %.S,$(LINUX_ARCH_OUT)/%.o,$(libpthread_SSRC))
+LINUX_ARCH_OBJ+=$(patsubst %.c,$(LINUX_ARCH_OUT)/%.o,$(libpthread_CSRC))
+
+ifeq ($(DOPIC),y)
+libpthread-a-y += $(LINUX_ARCH_OBJ:.o=.os)
+else
+libpthread-a-y += $(LINUX_ARCH_OBJ)
+endif
+libpthread-so-y += $(LINUX_ARCH_OBJ:.o=.oS)
+
+libpthread-nomulti-y+=$(LINUX_ARCH_OBJS)
+
+LIBC_LINUX_ARCH_OBJ:=$(patsubst %.c,$(LINUX_ARCH_OUT)/%.o,$(libc_a_CSRC))
+
+libc-static-y+=$(LIBC_LINUX_ARCH_OBJ)
+libc-shared-y+=$(LIBC_LINUX_ARCH_OBJ:.o=.oS)
+
+libc-nomulti-y+=$(LIBC_LINUX_ARCH_OBJ)
+
+objclean-y+=pthread_linux_arch_objclean
+
+pthread_linux_arch_objclean:
+       $(RM) $(LINUX_ARCH_OUT)/*.{o,os,oS}
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/bits/pthreadtypes.h b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/bits/pthreadtypes.h
new file mode 100644 (file)
index 0000000..166a6c6
--- /dev/null
@@ -0,0 +1,229 @@
+/* Machine-specific pthread type layouts.  MIPS version.
+   Copyright (C) 2005, 2006 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _BITS_PTHREADTYPES_H
+#define _BITS_PTHREADTYPES_H   1
+
+#include <endian.h>
+
+#if _MIPS_SIM == _ABI64
+# define __SIZEOF_PTHREAD_ATTR_T 56
+# define __SIZEOF_PTHREAD_MUTEX_T 40
+# define __SIZEOF_PTHREAD_MUTEXATTR_T 4
+# define __SIZEOF_PTHREAD_COND_T 48
+# define __SIZEOF_PTHREAD_CONDATTR_T 4
+# define __SIZEOF_PTHREAD_RWLOCK_T 56
+# define __SIZEOF_PTHREAD_RWLOCKATTR_T 8
+# define __SIZEOF_PTHREAD_BARRIER_T 32
+# define __SIZEOF_PTHREAD_BARRIERATTR_T 4
+#else
+# define __SIZEOF_PTHREAD_ATTR_T 36
+# define __SIZEOF_PTHREAD_MUTEX_T 24
+# define __SIZEOF_PTHREAD_MUTEXATTR_T 4
+# define __SIZEOF_PTHREAD_COND_T 48
+# define __SIZEOF_PTHREAD_CONDATTR_T 4
+# define __SIZEOF_PTHREAD_RWLOCK_T 32
+# define __SIZEOF_PTHREAD_RWLOCKATTR_T 8
+# define __SIZEOF_PTHREAD_BARRIER_T 20
+# define __SIZEOF_PTHREAD_BARRIERATTR_T 4
+#endif
+
+
+/* Thread identifiers.  The structure of the attribute type is
+   deliberately not exposed.  */
+typedef unsigned long int pthread_t;
+
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_ATTR_T];
+  long int __align;
+} pthread_attr_t;
+
+
+#if _MIPS_SIM == _ABI64
+typedef struct __pthread_internal_list
+{
+  struct __pthread_internal_list *__prev;
+  struct __pthread_internal_list *__next;
+} __pthread_list_t;
+#else
+typedef struct __pthread_internal_slist
+{
+  struct __pthread_internal_slist *__next;
+} __pthread_slist_t;
+#endif
+
+
+/* Data structures for mutex handling.  The structure of the attribute
+   type is deliberately not exposed.  */
+typedef union
+{
+  struct __pthread_mutex_s
+  {
+    int __lock;
+    unsigned int __count;
+    int __owner;
+#if _MIPS_SIM == _ABI64
+    unsigned int __nusers;
+#endif
+    /* KIND must stay at this position in the structure to maintain
+       binary compatibility.  */
+    int __kind;
+#if _MIPS_SIM == _ABI64
+    int __spins;
+    __pthread_list_t __list;
+# define __PTHREAD_MUTEX_HAVE_PREV     1
+#else
+    unsigned int __nusers;
+    __extension__ union
+    {
+      int __spins;
+      __pthread_slist_t __list;
+    };
+#endif
+  } __data;
+  char __size[__SIZEOF_PTHREAD_MUTEX_T];
+  long int __align;
+} pthread_mutex_t;
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_MUTEXATTR_T];
+  int __align;
+} pthread_mutexattr_t;
+
+
+/* Data structure for conditional variable handling.  The structure of
+   the attribute type is deliberately not exposed.  */
+typedef union
+{
+  struct
+  {
+    int __lock;
+    unsigned int __futex;
+    __extension__ unsigned long long int __total_seq;
+    __extension__ unsigned long long int __wakeup_seq;
+    __extension__ unsigned long long int __woken_seq;
+    void *__mutex;
+    unsigned int __nwaiters;
+    unsigned int __broadcast_seq;
+  } __data;
+  char __size[__SIZEOF_PTHREAD_COND_T];
+  __extension__ long long int __align;
+} pthread_cond_t;
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_CONDATTR_T];
+  int __align;
+} pthread_condattr_t;
+
+
+/* Keys for thread-specific data */
+typedef unsigned int pthread_key_t;
+
+
+/* Once-only execution */
+typedef int pthread_once_t;
+
+
+#if defined __USE_UNIX98 || defined __USE_XOPEN2K
+/* Data structure for read-write lock variable handling.  The
+   structure of the attribute type is deliberately not exposed.  */
+typedef union
+{
+# if _MIPS_SIM == _ABI64
+  struct
+  {
+    int __lock;
+    unsigned int __nr_readers;
+    unsigned int __readers_wakeup;
+    unsigned int __writer_wakeup;
+    unsigned int __nr_readers_queued;
+    unsigned int __nr_writers_queued;
+    int __writer;
+    int __shared;
+    unsigned long int __pad1;
+    unsigned long int __pad2;
+    /* FLAGS must stay at this position in the structure to maintain
+       binary compatibility.  */
+    unsigned int __flags;
+  } __data;
+# else
+  struct
+  {
+    int __lock;
+    unsigned int __nr_readers;
+    unsigned int __readers_wakeup;
+    unsigned int __writer_wakeup;
+    unsigned int __nr_readers_queued;
+    unsigned int __nr_writers_queued;
+#if __BYTE_ORDER == __BIG_ENDIAN
+    unsigned char __pad1;
+    unsigned char __pad2;
+    unsigned char __shared;
+    /* FLAGS must stay at this position in the structure to maintain
+       binary compatibility.  */
+    unsigned char __flags;
+#else
+    /* FLAGS must stay at this position in the structure to maintain
+       binary compatibility.  */
+    unsigned char __flags;
+    unsigned char __shared;
+    unsigned char __pad1;
+    unsigned char __pad2;
+#endif
+    int __writer;
+  } __data;
+# endif
+  char __size[__SIZEOF_PTHREAD_RWLOCK_T];
+  long int __align;
+} pthread_rwlock_t;
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_RWLOCKATTR_T];
+  long int __align;
+} pthread_rwlockattr_t;
+#endif
+
+
+#ifdef __USE_XOPEN2K
+/* POSIX spinlock data type.  */
+typedef volatile int pthread_spinlock_t;
+
+
+/* POSIX barriers data type.  The structure of the type is
+   deliberately not exposed.  */
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_BARRIER_T];
+  long int __align;
+} pthread_barrier_t;
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_BARRIERATTR_T];
+  int __align;
+} pthread_barrierattr_t;
+#endif
+
+
+#endif /* bits/pthreadtypes.h */
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/bits/semaphore.h b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/bits/semaphore.h
new file mode 100644 (file)
index 0000000..af43a60
--- /dev/null
@@ -0,0 +1,37 @@
+/* Copyright (C) 2002, 2005, 2007 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
+# error "Never use <bits/semaphore.h> directly; include <semaphore.h> instead."
+#endif
+
+#if _MIPS_SIM == _ABI64
+# define __SIZEOF_SEM_T        32
+#else
+# define __SIZEOF_SEM_T        16
+#endif
+
+/* Value returned if `sem_open' failed.  */
+#define SEM_FAILED      ((sem_t *) 0)
+
+
+typedef union
+{
+  char __size[__SIZEOF_SEM_T];
+  long int __align;
+} sem_t;
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/createthread.c b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/createthread.c
new file mode 100644 (file)
index 0000000..d8a7c55
--- /dev/null
@@ -0,0 +1,24 @@
+/* Copyright (C) 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* Value passed to 'clone' for initialization of the thread register.  */
+#define TLS_VALUE ((void *) (pd) \
+                  + TLS_TCB_OFFSET + TLS_PRE_TCB_SIZE)
+
+/* Get the real implementation.         */
+#include <sysdeps/pthread/createthread.c>
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/fork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/fork.c
new file mode 100644 (file)
index 0000000..06b7e1c
--- /dev/null
@@ -0,0 +1 @@
+#include "../i386/fork.c"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/lowlevellock.h b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/lowlevellock.h
new file mode 100644 (file)
index 0000000..01bcf41
--- /dev/null
@@ -0,0 +1,295 @@
+/* Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008,
+   2009 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 _LOWLEVELLOCK_H
+#define _LOWLEVELLOCK_H        1
+
+#include <time.h>
+#include <sys/param.h>
+#include <bits/pthreadtypes.h>
+#include <atomic.h>
+#include <sysdep.h>
+#include <bits/kernel-features.h>
+
+#define FUTEX_WAIT             0
+#define FUTEX_WAKE             1
+#define FUTEX_REQUEUE          3
+#define FUTEX_CMP_REQUEUE      4
+#define FUTEX_WAKE_OP          5
+#define FUTEX_OP_CLEAR_WAKE_IF_GT_ONE  ((4 << 24) | 1)
+#define FUTEX_LOCK_PI          6
+#define FUTEX_UNLOCK_PI                7
+#define FUTEX_TRYLOCK_PI       8
+#define FUTEX_WAIT_BITSET      9
+#define FUTEX_WAKE_BITSET      10
+#define FUTEX_PRIVATE_FLAG     128
+#define FUTEX_CLOCK_REALTIME   256
+
+#define FUTEX_BITSET_MATCH_ANY 0xffffffff
+
+/* Values for 'private' parameter of locking macros.  Yes, the
+   definition seems to be backwards.  But it is not.  The bit will be
+   reversed before passing to the system call.  */
+#define LLL_PRIVATE    0
+#define LLL_SHARED     FUTEX_PRIVATE_FLAG
+
+
+#if !defined NOT_IN_libc || defined IS_IN_rtld
+/* In libc.so or ld.so all futexes are private.  */
+# ifdef __ASSUME_PRIVATE_FUTEX
+#  define __lll_private_flag(fl, private) \
+  ((fl) | FUTEX_PRIVATE_FLAG)
+# else
+#  define __lll_private_flag(fl, private) \
+  ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex))
+# endif
+#else
+# ifdef __ASSUME_PRIVATE_FUTEX
+#  define __lll_private_flag(fl, private) \
+  (((fl) | FUTEX_PRIVATE_FLAG) ^ (private))
+# else
+#  define __lll_private_flag(fl, private) \
+  (__builtin_constant_p (private)                                            \
+   ? ((private) == 0                                                         \
+      ? ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex))           \
+      : (fl))                                                                \
+   : ((fl) | (((private) ^ FUTEX_PRIVATE_FLAG)                               \
+             & THREAD_GETMEM (THREAD_SELF, header.private_futex))))
+# endif              
+#endif
+
+
+#define lll_futex_wait(futexp, val, private) \
+  lll_futex_timed_wait(futexp, val, NULL, private)
+
+#define lll_futex_timed_wait(futexp, val, timespec, private) \
+  ({                                                                         \
+    INTERNAL_SYSCALL_DECL (__err);                                           \
+    long int __ret;                                                          \
+    __ret = INTERNAL_SYSCALL (futex, __err, 4, (long) (futexp),                      \
+                             __lll_private_flag (FUTEX_WAIT, private),       \
+                             (val), (timespec));                             \
+    INTERNAL_SYSCALL_ERROR_P (__ret, __err) ? -__ret : __ret;                \
+  })
+
+#define lll_futex_wake(futexp, nr, private) \
+  ({                                                                         \
+    INTERNAL_SYSCALL_DECL (__err);                                           \
+    long int __ret;                                                          \
+    __ret = INTERNAL_SYSCALL (futex, __err, 4, (long) (futexp),                      \
+                             __lll_private_flag (FUTEX_WAKE, private),       \
+                             (nr), 0);       \
+    INTERNAL_SYSCALL_ERROR_P (__ret, __err) ? -__ret : __ret;                \
+  })
+
+#define lll_robust_dead(futexv, private) \
+  do                                                                         \
+    {                                                                        \
+      int *__futexp = &(futexv);                                             \
+      atomic_or (__futexp, FUTEX_OWNER_DIED);                                \
+      lll_futex_wake (__futexp, 1, private);                                 \
+    }                                                                        \
+  while (0)
+
+/* Returns non-zero if error happened, zero if success.  */
+#define lll_futex_requeue(futexp, nr_wake, nr_move, mutex, val, private) \
+  ({                                                                         \
+    INTERNAL_SYSCALL_DECL (__err);                                           \
+    long int __ret;                                                          \
+    __ret = INTERNAL_SYSCALL (futex, __err, 6, (long) (futexp),                      \
+                             __lll_private_flag (FUTEX_CMP_REQUEUE, private),\
+                             (nr_wake), (nr_move), (mutex), (val));          \
+    INTERNAL_SYSCALL_ERROR_P (__ret, __err);                                 \
+  })
+
+/* Returns non-zero if error happened, zero if success.  */
+#define lll_futex_wake_unlock(futexp, nr_wake, nr_wake2, futexp2, private) \
+  ({                                                                         \
+    INTERNAL_SYSCALL_DECL (__err);                                           \
+    long int __ret;                                                          \
+                                                                             \
+    __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp),                     \
+                             __lll_private_flag (FUTEX_WAKE_OP, private),    \
+                             (nr_wake), (nr_wake2), (futexp2),               \
+                             FUTEX_OP_CLEAR_WAKE_IF_GT_ONE);                 \
+    INTERNAL_SYSCALL_ERROR_P (__ret, __err);                                 \
+  })
+
+static inline int __attribute__((always_inline))
+__lll_trylock(int *futex)
+{
+  return atomic_compare_and_exchange_val_acq (futex, 1, 0) != 0;
+}
+#define lll_trylock(lock)      __lll_trylock (&(lock))
+
+
+static inline int __attribute__((always_inline))
+__lll_cond_trylock(int *futex)
+{
+  return atomic_compare_and_exchange_val_acq (futex, 2, 0) != 0;
+}
+#define lll_cond_trylock(lock) __lll_cond_trylock (&(lock))
+
+
+static inline int __attribute__((always_inline))
+__lll_robust_trylock(int *futex, int id)
+{
+  return atomic_compare_and_exchange_val_acq (futex, id, 0) != 0;
+}
+#define lll_robust_trylock(lock, id) \
+  __lll_robust_trylock (&(lock), id)
+
+extern void __lll_lock_wait_private (int *futex) attribute_hidden;
+extern void __lll_lock_wait (int *futex, int private) attribute_hidden;
+extern int __lll_robust_lock_wait (int *futex, int private) attribute_hidden;
+
+#define __lll_lock(futex, private)                                           \
+  ((void) ({                                                                 \
+    int *__futex = (futex);                                                  \
+    if (__builtin_expect (atomic_compare_and_exchange_bool_acq (__futex,      \
+                                                               1, 0), 0))    \
+      {                                                                              \
+       if (__builtin_constant_p (private) && (private) == LLL_PRIVATE)       \
+         __lll_lock_wait_private (__futex);                                  \
+       else                                                                  \
+         __lll_lock_wait (__futex, private);                                 \
+      }                                                                              \
+  }))
+#define lll_lock(futex, private) __lll_lock (&(futex), private)
+
+
+#define __lll_robust_lock(futex, id, private)                                \
+  ({                                                                         \
+    int *__futex = (futex);                                                  \
+    int __val = 0;                                                           \
+                                                                             \
+    if (__builtin_expect (atomic_compare_and_exchange_bool_acq (__futex, id,  \
+                                                               0), 0))       \
+      __val = __lll_robust_lock_wait (__futex, private);                     \
+    __val;                                                                   \
+  })
+#define lll_robust_lock(futex, id, private) \
+  __lll_robust_lock (&(futex), id, private)
+
+
+static inline void __attribute__ ((always_inline))
+__lll_cond_lock (int *futex, int private)
+{
+  if (atomic_compare_and_exchange_bool_acq (futex, 2, 0) != 0)
+    __lll_lock_wait (futex, private);
+}
+#define lll_cond_lock(futex, private) __lll_cond_lock (&(futex), private)
+
+
+#define lll_robust_cond_lock(futex, id, private) \
+  __lll_robust_lock (&(futex), (id) | FUTEX_WAITERS, private)
+
+
+extern int __lll_timedlock_wait (int *futex, const struct timespec *,
+                                int private) attribute_hidden;
+extern int __lll_robust_timedlock_wait (int *futex, const struct timespec *,
+                                       int private) attribute_hidden;
+
+static inline int __attribute__ ((always_inline))
+__lll_timedlock (int *futex, const struct timespec *abstime, int private)
+{
+  int result = 0;
+  if (atomic_compare_and_exchange_bool_acq (futex, 1, 0) != 0)
+    result = __lll_timedlock_wait (futex, abstime, private);
+  return result;
+}
+#define lll_timedlock(futex, abstime, private) \
+  __lll_timedlock (&(futex), abstime, private)
+
+
+static inline int __attribute__ ((always_inline))
+__lll_robust_timedlock (int *futex, const struct timespec *abstime,
+                       int id, int private)
+{
+  int result = 0;
+  if (atomic_compare_and_exchange_bool_acq (futex, id, 0) != 0)
+    result = __lll_robust_timedlock_wait (futex, abstime, private);
+  return result;
+}
+#define lll_robust_timedlock(futex, abstime, id, private) \
+  __lll_robust_timedlock (&(futex), abstime, id, private)
+
+
+#define __lll_unlock(futex, private)                                         \
+  ((void) ({                                                                 \
+    int *__futex = (futex);                                                  \
+    int __val = atomic_exchange_rel (__futex, 0);                            \
+                                                                             \
+    if (__builtin_expect (__val > 1, 0))                                     \
+      lll_futex_wake (__futex, 1, private);                                  \
+  }))
+#define lll_unlock(futex, private) __lll_unlock(&(futex), private)
+
+
+#define __lll_robust_unlock(futex, private)                                  \
+  ((void) ({                                                                 \
+    int *__futex = (futex);                                                  \
+    int __val = atomic_exchange_rel (__futex, 0);                            \
+                                                                             \
+    if (__builtin_expect (__val & FUTEX_WAITERS, 0))                         \
+      lll_futex_wake (__futex, 1, private);                                  \
+  }))
+#define lll_robust_unlock(futex, private) \
+  __lll_robust_unlock(&(futex), private)
+
+
+#define lll_islocked(futex) \
+  (futex != 0)
+
+
+/* Our internal lock implementation is identical to the binary-compatible
+   mutex implementation. */
+
+/* Initializers for lock.  */
+#define LLL_LOCK_INITIALIZER           (0)
+#define LLL_LOCK_INITIALIZER_LOCKED    (1)
+
+/* The states of a lock are:
+    0  -  untaken
+    1  -  taken by one user
+   >1  -  taken by more users */
+
+/* The kernel notifies a process which uses CLONE_CLEARTID via futex
+   wakeup when the clone terminates.  The memory location contains the
+   thread ID while the clone is running and is reset to zero
+   afterwards. */
+#define lll_wait_tid(tid) \
+  do {                                                 \
+    __typeof (tid) __tid;                              \
+    while ((__tid = (tid)) != 0)                       \
+      lll_futex_wait (&(tid), __tid, LLL_SHARED);      \
+  } while (0)
+
+extern int __lll_timedwait_tid (int *, const struct timespec *)
+     attribute_hidden;
+
+#define lll_timedwait_tid(tid, abstime) \
+  ({                                                   \
+    int __res = 0;                                     \
+    if ((tid) != 0)                                    \
+      __res = __lll_timedwait_tid (&(tid), (abstime)); \
+    __res;                                             \
+  })
+
+#endif /* lowlevellock.h */
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pt-__syscall_rt_sigaction.c b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pt-__syscall_rt_sigaction.c
new file mode 100644 (file)
index 0000000..50137c8
--- /dev/null
@@ -0,0 +1 @@
+#include <../../../../../../../libc/sysdeps/linux/common/__syscall_rt_sigaction.c>
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pt-clone.S b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pt-clone.S
new file mode 100644 (file)
index 0000000..add4055
--- /dev/null
@@ -0,0 +1,2 @@
+#define RESET_PID
+#include <../../../../../../../libc/sysdeps/linux/mips/clone.S>
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pt-vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pt-vfork.S
new file mode 100644 (file)
index 0000000..c02ffca
--- /dev/null
@@ -0,0 +1,38 @@
+/* Copyright (C) 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <features.h>
+#include <tls.h>
+
+/* Save the PID value.  */
+#define SAVE_PID \
+       READ_THREAD_POINTER(v1);        /* Get the thread pointer.  */  \
+       lw      a2, PID_OFFSET(v1);     /* Load the saved PID.  */      \
+       subu    a2, $0, a2;             /* Negate it.  */               \
+       sw      a2, PID_OFFSET(v1);     /* Store the temporary PID.  */
+
+/* Restore the old PID value in the parent.  */
+#define RESTORE_PID \
+       beqz    v0, 1f;                 /* If we are the parent... */   \
+       READ_THREAD_POINTER(v1);        /* Get the thread pointer.  */  \
+       lw      a2, PID_OFFSET(v1);     /* Load the saved PID.  */      \
+       subu    a2, $0, a2;             /* Re-negate it.  */            \
+       sw      a2, PID_OFFSET(v1);     /* Restore the PID.  */         \
+1:
+
+#include <../../../../../../../libc/sysdeps/linux/mips/vfork.S>
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pthread_once.c b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pthread_once.c
new file mode 100644 (file)
index 0000000..ddfd32b
--- /dev/null
@@ -0,0 +1,94 @@
+/* Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+#include <lowlevellock.h>
+
+
+unsigned long int __fork_generation attribute_hidden;
+
+
+static void
+clear_once_control (void *arg)
+{
+  pthread_once_t *once_control = (pthread_once_t *) arg;
+
+  *once_control = 0;
+  lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE);
+}
+
+
+int
+__pthread_once (once_control, init_routine)
+     pthread_once_t *once_control;
+     void (*init_routine) (void);
+{
+  while (1)
+    {
+      int oldval, val, newval;
+
+      val = *once_control;
+      do
+       {
+         /* Check if the initialized has already been done.  */
+         if ((val & 2) != 0)
+           return 0;
+
+         oldval = val;
+         newval = (oldval & 3) | __fork_generation | 1;
+         val = atomic_compare_and_exchange_val_acq (once_control, newval,
+                                                    oldval);
+       }
+      while (__builtin_expect (val != oldval, 0));
+
+      /* Check if another thread already runs the initializer. */
+      if ((oldval & 1) != 0)
+       {
+         /* Check whether the initializer execution was interrupted
+            by a fork.  */
+         if (((oldval ^ newval) & -4) == 0)
+           {
+             /* Same generation, some other thread was faster. Wait.  */
+             lll_futex_wait (once_control, newval, LLL_PRIVATE);
+             continue;
+           }
+       }
+
+      /* This thread is the first here.  Do the initialization.
+        Register a cleanup handler so that in case the thread gets
+        interrupted the initialization can be restarted.  */
+      pthread_cleanup_push (clear_once_control, once_control);
+
+      init_routine ();
+
+      pthread_cleanup_pop (0);
+
+
+      /* Add one to *once_control.  */
+      atomic_increment (once_control);
+
+      /* Wake up all other threads.  */
+      lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE);
+      break;
+    }
+
+  return 0;
+}
+weak_alias (__pthread_once, pthread_once)
+strong_alias (__pthread_once, __pthread_once_internal)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/sysdep-cancel.h
new file mode 100644 (file)
index 0000000..1cf625f
--- /dev/null
@@ -0,0 +1,188 @@
+/* Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <tls.h>
+#ifndef __ASSEMBLER__
+# include <pthreadP.h>
+#endif
+
+#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt
+
+# ifdef __PIC__
+#  define PSEUDO_CPLOAD .cpload t9;
+#  define PSEUDO_ERRJMP la t9, __syscall_error; jr t9;
+#  define PSEUDO_SAVEGP sw gp, 32(sp); cfi_rel_offset (gp, 32);
+#  define PSEUDO_LOADGP lw gp, 32(sp);
+# else
+#  define PSEUDO_CPLOAD
+#  define PSEUDO_ERRJMP j __syscall_error;
+#  define PSEUDO_SAVEGP
+#  define PSEUDO_LOADGP
+# endif
+
+# undef PSEUDO
+# define PSEUDO(name, syscall_name, args)                                    \
+      .align 2;                                                                      \
+  L(pseudo_start):                                                           \
+      cfi_startproc;                                                         \
+  99: PSEUDO_ERRJMP                                                          \
+  .type __##syscall_name##_nocancel, @function;                                      \
+  .globl __##syscall_name##_nocancel;                                        \
+  __##syscall_name##_nocancel:                                               \
+    .set noreorder;                                                          \
+    PSEUDO_CPLOAD                                                            \
+    li v0, SYS_ify(syscall_name);                                            \
+    syscall;                                                                 \
+    .set reorder;                                                            \
+    bne a3, zero, 99b;                                                       \
+    ret;                                                                     \
+  .size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel;           \
+  ENTRY (name)                                                               \
+    .set noreorder;                                                          \
+    PSEUDO_CPLOAD                                                            \
+    .set reorder;                                                            \
+    SINGLE_THREAD_P(v1);                                                     \
+    bne zero, v1, L(pseudo_cancel);                                          \
+    .set noreorder;                                                          \
+    li v0, SYS_ify(syscall_name);                                            \
+    syscall;                                                                 \
+    .set reorder;                                                            \
+    bne a3, zero, 99b;                                                       \
+    ret;                                                                     \
+  L(pseudo_cancel):                                                          \
+    SAVESTK_##args;                                                          \
+    sw ra, 28(sp);                                                           \
+    cfi_rel_offset (ra, 28);                                                 \
+    PSEUDO_SAVEGP                                                            \
+    PUSHARGS_##args;                   /* save syscall args */               \
+    CENABLE;                                                                 \
+    PSEUDO_LOADGP                                                            \
+    sw v0, 44(sp);                     /* save mask */                       \
+    POPARGS_##args;                    /* restore syscall args */            \
+    .set noreorder;                                                          \
+    li v0, SYS_ify (syscall_name);                                           \
+    syscall;                                                                 \
+    .set reorder;                                                            \
+    sw v0, 36(sp);                     /* save syscall result */             \
+    sw a3, 40(sp);                     /* save syscall error flag */         \
+    lw a0, 44(sp);                     /* pass mask as arg1 */               \
+    CDISABLE;                                                                \
+    PSEUDO_LOADGP                                                            \
+    lw v0, 36(sp);                     /* restore syscall result */          \
+    lw a3, 40(sp);                     /* restore syscall error flag */      \
+    lw ra, 28(sp);                     /* restore return address */          \
+    .set noreorder;                                                          \
+    bne a3, zero, 99b;                                                       \
+     RESTORESTK;                                                             \
+  L(pseudo_end):                                                             \
+    .set reorder;
+
+# undef PSEUDO_END
+# define PSEUDO_END(sym) cfi_endproc; .end sym; .size sym,.-sym
+
+# define PUSHARGS_0    /* nothing to do */
+# define PUSHARGS_1    PUSHARGS_0 sw a0, 0(sp); cfi_rel_offset (a0, 0);
+# define PUSHARGS_2    PUSHARGS_1 sw a1, 4(sp); cfi_rel_offset (a1, 4);
+# define PUSHARGS_3    PUSHARGS_2 sw a2, 8(sp); cfi_rel_offset (a2, 8);
+# define PUSHARGS_4    PUSHARGS_3 sw a3, 12(sp); cfi_rel_offset (a3, 12);
+# define PUSHARGS_5    PUSHARGS_4 /* handled by SAVESTK_## */
+# define PUSHARGS_6    PUSHARGS_5
+# define PUSHARGS_7    PUSHARGS_6
+
+# define POPARGS_0     /* nothing to do */
+# define POPARGS_1     POPARGS_0 lw a0, 0(sp);
+# define POPARGS_2     POPARGS_1 lw a1, 4(sp);
+# define POPARGS_3     POPARGS_2 lw a2, 8(sp);
+# define POPARGS_4     POPARGS_3 lw a3, 12(sp);
+# define POPARGS_5     POPARGS_4 /* args already in new stackframe */
+# define POPARGS_6     POPARGS_5
+# define POPARGS_7     POPARGS_6
+
+
+# define STKSPACE      48
+# define SAVESTK_0     subu sp, STKSPACE; cfi_adjust_cfa_offset(STKSPACE)
+# define SAVESTK_1      SAVESTK_0
+# define SAVESTK_2      SAVESTK_1
+# define SAVESTK_3      SAVESTK_2
+# define SAVESTK_4      SAVESTK_3
+# define SAVESTK_5      lw t0, 16(sp);         \
+                       SAVESTK_0;              \
+                       sw t0, 16(sp)
+
+# define SAVESTK_6      lw t0, 16(sp);         \
+                       lw t1, 20(sp);          \
+                       SAVESTK_0;              \
+                       sw t0, 16(sp);          \
+                       sw t1, 20(sp)
+
+# define SAVESTK_7      lw t0, 16(sp);         \
+                       lw t1, 20(sp);          \
+                       lw t2, 24(sp);          \
+                       SAVESTK_0;              \
+                       sw t0, 16(sp);          \
+                       sw t1, 20(sp);          \
+                       sw t2, 24(sp)
+
+# define RESTORESTK    addu sp, STKSPACE; cfi_adjust_cfa_offset(-STKSPACE)
+
+
+# ifdef __PIC__
+/* We use jalr rather than jal.  This means that the assembler will not
+   automatically restore $gp (in case libc has multiple GOTs) so we must
+   do it manually - which we have to do anyway since we don't use .cprestore.
+   It also shuts up the assembler warning about not using .cprestore.  */
+#  define PSEUDO_JMP(sym) la t9, sym; jalr t9;
+# else
+#  define PSEUDO_JMP(sym) jal sym;
+# endif
+
+# ifdef IS_IN_libpthread
+#  define CENABLE      PSEUDO_JMP (__pthread_enable_asynccancel)
+#  define CDISABLE     PSEUDO_JMP (__pthread_disable_asynccancel)
+# elif defined IS_IN_librt
+#  define CENABLE      PSEUDO_JMP (__librt_enable_asynccancel)
+#  define CDISABLE     PSEUDO_JMP (__librt_disable_asynccancel)
+# else
+#  define CENABLE      PSEUDO_JMP (__libc_enable_asynccancel)
+#  define CDISABLE     PSEUDO_JMP (__libc_disable_asynccancel)
+# endif
+
+# ifndef __ASSEMBLER__
+#  define SINGLE_THREAD_P                                              \
+       __builtin_expect (THREAD_GETMEM (THREAD_SELF,                   \
+                                        header.multiple_threads)       \
+                         == 0, 1)
+# else
+#  define SINGLE_THREAD_P(reg)                                         \
+       READ_THREAD_POINTER(reg);                                       \
+       lw reg, MULTIPLE_THREADS_OFFSET(reg)
+#endif
+
+#elif !defined __ASSEMBLER__
+
+# define SINGLE_THREAD_P 1
+# define NO_CANCELLATION 1
+
+#endif
+
+#ifndef __ASSEMBLER__
+# define RTLD_SINGLE_THREAD_P \
+  __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
+                                  header.multiple_threads) == 0, 1)
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mq_notify.c b/libpthread/nptl/sysdeps/unix/sysv/linux/mq_notify.c
new file mode 100644 (file)
index 0000000..188040e
--- /dev/null
@@ -0,0 +1,286 @@
+/* Copyright (C) 2004, 2005, 2008 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contribute by Ulrich Drepper <drepper@redhat.com>, 2004.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with 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 <fcntl.h>
+#include <mqueue.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysdep.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <not-cancel.h>
+#include <bits/kernel-features.h>
+
+
+#ifdef __NR_mq_notify
+
+/* Defined in the kernel headers: */
+#define NOTIFY_COOKIE_LEN      32      /* Length of the cookie used.  */
+#define NOTIFY_WOKENUP         1       /* Code for notifcation.  */
+#define NOTIFY_REMOVED         2       /* Code for closed message queue
+                                          of de-notifcation.  */
+
+
+/* Data structure for the queued notification requests.  */
+union notify_data
+{
+  struct
+  {
+    void (*fct) (union sigval);        /* The function to run.  */
+    union sigval param;                /* The parameter to pass.  */
+    pthread_attr_t *attr;      /* Attributes to create the thread with.  */
+    /* NB: on 64-bit machines the struct as a size of 24 bytes.  Which means
+       byte 31 can still be used for returning the status.  */
+  };
+  char raw[NOTIFY_COOKIE_LEN];
+};
+
+
+/* Keep track of the initialization.  */
+static pthread_once_t once = PTHREAD_ONCE_INIT;
+
+
+/* The netlink socket.  */
+static int netlink_socket = -1;
+
+
+/* Barrier used to make sure data passed to the new thread is not
+   resused by the parent.  */
+static pthread_barrier_t notify_barrier;
+
+
+/* Modify the signal mask.  We move this into a separate function so
+   that the stack space needed for sigset_t is not deducted from what
+   the thread can use.  */
+static int
+__attribute__ ((noinline))
+change_sigmask (int how, sigset_t *oss)
+{
+  sigset_t ss;
+  sigfillset (&ss);
+  return pthread_sigmask (how, &ss, oss);
+}
+
+
+/* The function used for the notification.  */
+static void *
+notification_function (void *arg)
+{
+  /* Copy the function and parameter so that the parent thread can go
+     on with its life.  */
+  volatile union notify_data *data = (volatile union notify_data *) arg;
+  void (*fct) (union sigval) = data->fct;
+  union sigval param = data->param;
+
+  /* Let the parent go.  */
+  (void) pthread_barrier_wait (&notify_barrier);
+
+  /* Make the thread detached.  */
+  (void) pthread_detach (pthread_self ());
+
+  /* The parent thread has all signals blocked.  This is probably a
+     bit surprising for this thread.  So we unblock all of them.  */
+  (void) change_sigmask (SIG_UNBLOCK, NULL);
+
+  /* Now run the user code.  */
+  fct (param);
+
+  /* And we are done.  */
+  return NULL;
+}
+
+
+/* Helper thread.  */
+static void *
+helper_thread (void *arg)
+{
+  while (1)
+    {
+      union notify_data data;
+
+      ssize_t n = recv (netlink_socket, &data, sizeof (data),
+                       MSG_NOSIGNAL | MSG_WAITALL);
+      if (n < NOTIFY_COOKIE_LEN)
+       continue;
+
+      if (data.raw[NOTIFY_COOKIE_LEN - 1] == NOTIFY_WOKENUP)
+       {
+         /* Just create the thread as instructed.  There is no way to
+            report a problem with creating a thread.  */
+         pthread_t th;
+         if (__builtin_expect (pthread_create (&th, data.attr,
+                                               notification_function, &data)
+                               == 0, 0))
+           /* Since we passed a pointer to DATA to the new thread we have
+              to wait until it is done with it.  */
+           (void) pthread_barrier_wait (&notify_barrier);
+       }
+      else if (data.raw[NOTIFY_COOKIE_LEN - 1] == NOTIFY_REMOVED)
+       /* The only state we keep is the copy of the thread attributes.  */
+       free (data.attr);
+    }
+  return NULL;
+}
+
+
+static void
+reset_once (void)
+{
+  once = PTHREAD_ONCE_INIT;
+}
+
+
+static void
+init_mq_netlink (void)
+{
+  /* This code might be called a second time after fork().  The file
+     descriptor is inherited from the parent.  */
+  if (netlink_socket == -1)
+    {
+      /* Just a normal netlink socket, not bound.  */
+         netlink_socket = socket (AF_NETLINK, SOCK_RAW, 0);
+      /* No need to do more if we have no socket.  */
+      if (netlink_socket == -1)
+       return;
+
+      /* Make sure the descriptor is closed on exec.  */
+      if (fcntl (netlink_socket, F_SETFD, FD_CLOEXEC) != 0)
+       goto errout;
+    }
+
+  int err = 1;
+
+  /* Initialize the barrier.  */
+  if (__builtin_expect (pthread_barrier_init (&notify_barrier, NULL, 2) == 0,
+                       0))
+    {
+      /* Create the helper thread.  */
+      pthread_attr_t attr;
+      (void) pthread_attr_init (&attr);
+      (void) pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
+      /* We do not need much stack space, the bare minimum will be enough.  */
+      (void) pthread_attr_setstacksize (&attr, PTHREAD_STACK_MIN);
+
+      /* Temporarily block all signals so that the newly created
+        thread inherits the mask.  */
+      sigset_t oss;
+      int have_no_oss = change_sigmask (SIG_BLOCK, &oss);
+
+      pthread_t th;
+      err = pthread_create (&th, &attr, helper_thread, NULL);
+
+      /* Reset the signal mask.  */
+      if (!have_no_oss)
+       pthread_sigmask (SIG_SETMASK, &oss, NULL);
+
+      (void) pthread_attr_destroy (&attr);
+
+      if (err == 0)
+       {
+         static int added_atfork;
+
+         if (added_atfork == 0
+             && pthread_atfork (NULL, NULL, reset_once) != 0)
+           {
+             /* The child thread will call recv() which is a
+                cancellation point.  */
+             (void) pthread_cancel (th);
+             err = 1;
+           }
+         else
+           added_atfork = 1;
+       }
+    }
+
+  if (err != 0)
+    {
+    errout:
+      close_not_cancel_no_status (netlink_socket);
+      netlink_socket = -1;
+    }
+}
+
+
+/* Register notification upon message arrival to an empty message queue
+   MQDES.  */
+int
+mq_notify (mqd_t mqdes, const struct sigevent *notification)
+{
+  /* Make sure the type is correctly defined.  */
+  assert (sizeof (union notify_data) == NOTIFY_COOKIE_LEN);
+
+  /* Special treatment needed for SIGEV_THREAD.  */
+  if (notification == NULL || notification->sigev_notify != SIGEV_THREAD)
+    return INLINE_SYSCALL (mq_notify, 2, mqdes, notification);
+
+  /* The kernel cannot directly start threads.  This will have to be
+     done at userlevel.  Since we cannot start threads from signal
+     handlers we have to create a dedicated thread which waits for
+     notifications for arriving messages and creates threads in
+     response.  */
+
+  /* Initialize only once.  */
+  pthread_once (&once, init_mq_netlink);
+
+  /* If we cannot create the netlink socket we cannot provide
+     SIGEV_THREAD support.  */
+  if (__builtin_expect (netlink_socket == -1, 0))
+    {
+      __set_errno (ENOSYS);
+      return -1;
+    }
+
+  /* Create the cookie.  It will hold almost all the state.  */
+  union notify_data data;
+  memset (&data, '\0', sizeof (data));
+  data.fct = notification->sigev_notify_function;
+  data.param = notification->sigev_value;
+
+  if (notification->sigev_notify_attributes != NULL)
+    {
+      /* The thread attribute has to be allocated separately.  */
+      data.attr = (pthread_attr_t *) malloc (sizeof (pthread_attr_t));
+      if (data.attr == NULL)
+       return -1;
+
+      memcpy (data.attr, notification->sigev_notify_attributes,
+             sizeof (pthread_attr_t));
+    }
+
+  /* Construct the new request.  */
+  struct sigevent se;
+  se.sigev_notify = SIGEV_THREAD;
+  se.sigev_signo = netlink_socket;
+  se.sigev_value.sival_ptr = &data;
+
+  /* Tell the kernel.  */
+  int retval = INLINE_SYSCALL (mq_notify, 2, mqdes, &se);
+
+  /* If it failed, free the allocated memory.  */
+  if (__builtin_expect (retval != 0, 0))
+    free (data.attr);
+
+  return retval;
+}
+
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/msync.S b/libpthread/nptl/sysdeps/unix/sysv/linux/msync.S
new file mode 100644 (file)
index 0000000..074a0d7
--- /dev/null
@@ -0,0 +1,7 @@
+#include <sysdep-cancel.h>
+PSEUDO (__libc_msync, msync, 3)
+ret
+PSEUDO_END(__libc_msync)
+libc_hidden_def (__libc_msync)
+weak_alias (__libc_msync, msync)
+libc_hidden_weak (msync)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/nanosleep.S b/libpthread/nptl/sysdeps/unix/sysv/linux/nanosleep.S
new file mode 100644 (file)
index 0000000..71efe32
--- /dev/null
@@ -0,0 +1,9 @@
+#include <sysdep-cancel.h>
+PSEUDO (__libc_nanosleep, nanosleep, 3)
+ret
+PSEUDO_END (__libc_nanosleep)
+libc_hidden_def (__libc_nanosleep)
+weak_alias (__libc_nanosleep, __nanosleep)
+libc_hidden_weak (__nanosleep)
+weak_alias (__libc_nanosleep, nanosleep)
+libc_hidden_weak (nanosleep)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/not-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/not-cancel.h
new file mode 100644 (file)
index 0000000..80d33be
--- /dev/null
@@ -0,0 +1,105 @@
+/* Uncancelable versions of cancelable interfaces.  Linux version.
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sys/types.h>
+#include <sysdep.h>
+
+/* Uncancelable open.  */
+#define open_not_cancel(name, flags, mode) \
+   INLINE_SYSCALL (open, 3, (const char *) (name), (flags), (mode))
+#define open_not_cancel_2(name, flags) \
+   INLINE_SYSCALL (open, 2, (const char *) (name), (flags))
+
+/* Uncancelable openat.  */
+#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt
+extern int __openat_nocancel (int fd, const char *fname, int oflag,
+                             mode_t mode) attribute_hidden;
+extern int __openat64_nocancel (int fd, const char *fname, int oflag,
+                               mode_t mode) attribute_hidden;
+#else
+# define __openat_nocancel(fd, fname, oflag, mode) \
+  openat (fd, fname, oflag, mode)
+# define __openat64_nocancel(fd, fname, oflag, mode) \
+  openat64 (fd, fname, oflag, mode)
+#endif
+
+#define openat_not_cancel(fd, fname, oflag, mode) \
+  __openat_nocancel (fd, fname, oflag, mode)
+#define openat_not_cancel_3(fd, fname, oflag) \
+  __openat_nocancel (fd, fname, oflag, 0)
+#define openat64_not_cancel(fd, fname, oflag, mode) \
+  __openat64_nocancel (fd, fname, oflag, mode)
+#define openat64_not_cancel_3(fd, fname, oflag) \
+  __openat64_nocancel (fd, fname, oflag, 0)
+
+/* Uncancelable close.  */
+#define close_not_cancel(fd) \
+  INLINE_SYSCALL (close, 1, fd)
+#define close_not_cancel_no_status(fd) \
+  (void) ({ INTERNAL_SYSCALL_DECL (err);                                     \
+           INTERNAL_SYSCALL (close, err, 1, (fd)); })
+
+/* Uncancelable read.  */
+#define read_not_cancel(fd, buf, n) \
+  INLINE_SYSCALL (read, 3, (fd), (buf), (n))
+
+/* Uncancelable write.  */
+#define write_not_cancel(fd, buf, n) \
+  INLINE_SYSCALL (write, 3, (fd), (buf), (n))
+
+/* Uncancelable writev.  */
+#define writev_not_cancel_no_status(fd, iov, n) \
+  (void) ({ INTERNAL_SYSCALL_DECL (err);                                     \
+           INTERNAL_SYSCALL (writev, err, 3, (fd), (iov), (n)); })
+
+/* Uncancelable fcntl.  */
+#define fcntl_not_cancel(fd, cmd, val) \
+  __fcntl_nocancel (fd, cmd, val)
+
+/* Uncancelable waitpid.  */
+#ifdef __NR_waitpid
+# define waitpid_not_cancel(pid, stat_loc, options) \
+  INLINE_SYSCALL (waitpid, 3, pid, stat_loc, options)
+#else
+# define waitpid_not_cancel(pid, stat_loc, options) \
+  INLINE_SYSCALL (wait4, 4, pid, stat_loc, options, NULL)
+#endif
+
+/* Uncancelable pause.  */
+#ifdef __NR_pause
+# define pause_not_cancel() \
+  INLINE_SYSCALL (pause, 0)
+#else
+# define pause_not_cancel() \
+  __pause_nocancel ()
+#endif
+
+/* Uncancelable nanosleep.  */
+#ifdef __NR_nanosleep
+# define nanosleep_not_cancel(requested_time, remaining) \
+  INLINE_SYSCALL (nanosleep, 2, requested_time, remaining)
+#else
+# define nanosleep_not_cancel(requested_time, remaining) \
+  __nanosleep_nocancel (requested_time, remaining)
+#endif
+
+/* Uncancelable sigsuspend.  */
+#define sigsuspend_not_cancel(set) \
+  __sigsuspend_nocancel (set)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/open.S b/libpthread/nptl/sysdeps/unix/sysv/linux/open.S
new file mode 100644 (file)
index 0000000..486686a
--- /dev/null
@@ -0,0 +1,21 @@
+#include <sysdep-cancel.h>
+
+/*
+extern int __open_nocancel (const char *, int, ...) attribute_hidden;
+*/
+#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt
+
+PSEUDO (__libc_open, open, 3)
+ret
+PSEUDO_END(__libc_open)
+
+libc_hidden_def (__open_nocancel)
+libc_hidden_def (__libc_open)
+weak_alias (__libc_open, __open)
+libc_hidden_weak (__open)
+weak_alias (__libc_open, open)
+libc_hidden_weak (open)
+
+
+
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pause.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pause.S
new file mode 100644 (file)
index 0000000..3841018
--- /dev/null
@@ -0,0 +1,7 @@
+#include <sysdep-cancel.h>
+PSEUDO (__libc_pause, pause, 0)
+ret
+PSEUDO_END (__libc_pause)
+libc_hidden_def (__libc_pause)
+weak_alias (__libc_pause, pause)
+libc_hidden_weak (pause)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/Makefile b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/Makefile
new file mode 100644 (file)
index 0000000..e98c9bd
--- /dev/null
@@ -0,0 +1,2 @@
+# pull in __syscall_error routine
+libpthread-routines += sysdep
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h
new file mode 100644 (file)
index 0000000..c0b59c3
--- /dev/null
@@ -0,0 +1,221 @@
+/* Machine-specific pthread type layouts.  PowerPC version.
+   Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _BITS_PTHREADTYPES_H
+#define _BITS_PTHREADTYPES_H   1
+
+#include <bits/wordsize.h>
+
+#if __WORDSIZE == 64
+# define __SIZEOF_PTHREAD_ATTR_T 56
+# define __SIZEOF_PTHREAD_MUTEX_T 40
+# define __SIZEOF_PTHREAD_MUTEXATTR_T 4
+# define __SIZEOF_PTHREAD_COND_T 48
+# define __SIZEOF_PTHREAD_CONDATTR_T 4
+# define __SIZEOF_PTHREAD_RWLOCK_T 56
+# define __SIZEOF_PTHREAD_RWLOCKATTR_T 8
+# define __SIZEOF_PTHREAD_BARRIER_T 32
+# define __SIZEOF_PTHREAD_BARRIERATTR_T 4
+#else
+# define __SIZEOF_PTHREAD_ATTR_T 36
+# define __SIZEOF_PTHREAD_MUTEX_T 24
+# define __SIZEOF_PTHREAD_MUTEXATTR_T 4
+# define __SIZEOF_PTHREAD_COND_T 48
+# define __SIZEOF_PTHREAD_CONDATTR_T 4
+# define __SIZEOF_PTHREAD_RWLOCK_T 32
+# define __SIZEOF_PTHREAD_RWLOCKATTR_T 8
+# define __SIZEOF_PTHREAD_BARRIER_T 20
+# define __SIZEOF_PTHREAD_BARRIERATTR_T 4
+#endif
+
+
+/* Thread identifiers.  The structure of the attribute type is
+   deliberately not exposed.  */
+typedef unsigned long int pthread_t;
+
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_ATTR_T];
+  long int __align;
+} pthread_attr_t;
+
+
+#if __WORDSIZE == 64
+typedef struct __pthread_internal_list
+{
+  struct __pthread_internal_list *__prev;
+  struct __pthread_internal_list *__next;
+} __pthread_list_t;
+#else
+typedef struct __pthread_internal_slist
+{
+  struct __pthread_internal_slist *__next;
+} __pthread_slist_t;
+#endif
+
+
+/* Data structures for mutex handling.  The structure of the attribute
+   type is deliberately not exposed.  */
+typedef union
+{
+  struct __pthread_mutex_s
+  {
+    int __lock;
+    unsigned int __count;
+    int __owner;
+#if __WORDSIZE == 64
+    unsigned int __nusers;
+#endif
+    /* KIND must stay at this position in the structure to maintain
+       binary compatibility.  */
+    int __kind;
+#if __WORDSIZE == 64
+    int __spins;
+    __pthread_list_t __list;
+# define __PTHREAD_MUTEX_HAVE_PREV     1
+#else
+    unsigned int __nusers;
+    __extension__ union
+    {
+      int __spins;
+      __pthread_slist_t __list;
+    };
+#endif
+  } __data;
+  char __size[__SIZEOF_PTHREAD_MUTEX_T];
+  long int __align;
+} pthread_mutex_t;
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_MUTEXATTR_T];
+  int __align;
+} pthread_mutexattr_t;
+
+
+/* Data structure for conditional variable handling.  The structure of
+   the attribute type is deliberately not exposed.  */
+typedef union
+{
+  struct
+  {
+    int __lock;
+    unsigned int __futex;
+    __extension__ unsigned long long int __total_seq;
+    __extension__ unsigned long long int __wakeup_seq;
+    __extension__ unsigned long long int __woken_seq;
+    void *__mutex;
+    unsigned int __nwaiters;
+    unsigned int __broadcast_seq;
+  } __data;
+  char __size[__SIZEOF_PTHREAD_COND_T];
+  __extension__ long long int __align;
+} pthread_cond_t;
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_CONDATTR_T];
+  int __align;
+} pthread_condattr_t;
+
+
+/* Keys for thread-specific data */
+typedef unsigned int pthread_key_t;
+
+
+/* Once-only execution */
+typedef int pthread_once_t;
+
+
+#if defined __USE_UNIX98 || defined __USE_XOPEN2K
+/* Data structure for read-write lock variable handling.  The
+   structure of the attribute type is deliberately not exposed.  */
+typedef union
+{
+# if __WORDSIZE == 64
+  struct
+  {
+    int __lock;
+    unsigned int __nr_readers;
+    unsigned int __readers_wakeup;
+    unsigned int __writer_wakeup;
+    unsigned int __nr_readers_queued;
+    unsigned int __nr_writers_queued;
+    int __writer;
+    int __shared;
+    unsigned long int __pad1;
+    unsigned long int __pad2;
+    /* FLAGS must stay at this position in the structure to maintain
+       binary compatibility.  */
+    unsigned int __flags;
+  } __data;
+# else
+  struct
+  {
+    int __lock;
+    unsigned int __nr_readers;
+    unsigned int __readers_wakeup;
+    unsigned int __writer_wakeup;
+    unsigned int __nr_readers_queued;
+    unsigned int __nr_writers_queued;
+    unsigned char __pad1;
+    unsigned char __pad2;
+    unsigned char __shared;
+    /* FLAGS must stay at this position in the structure to maintain
+       binary compatibility.  */
+    unsigned char __flags;
+    int __writer;
+  } __data;
+# endif
+  char __size[__SIZEOF_PTHREAD_RWLOCK_T];
+  long int __align;
+} pthread_rwlock_t;
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_RWLOCKATTR_T];
+  long int __align;
+} pthread_rwlockattr_t;
+#endif
+
+
+#ifdef __USE_XOPEN2K
+/* POSIX spinlock data type.  */
+typedef volatile int pthread_spinlock_t;
+
+
+/* POSIX barriers data type.  The structure of the type is
+   deliberately not exposed.  */
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_BARRIER_T];
+  long int __align;
+} pthread_barrier_t;
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_BARRIERATTR_T];
+  int __align;
+} pthread_barrierattr_t;
+#endif
+
+
+#endif /* bits/pthreadtypes.h */
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/bits/semaphore.h b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/bits/semaphore.h
new file mode 100644 (file)
index 0000000..c7f121b
--- /dev/null
@@ -0,0 +1,41 @@
+/* Machine-specific POSIX semaphore type layouts.  PowerPC version.
+   Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _SEMAPHORE_H
+# error "Never use <bits/semaphore.h> directly; include <semaphore.h> instead."
+#endif
+
+#include <bits/wordsize.h>
+
+#if __WORDSIZE == 64
+# define __SIZEOF_SEM_T        32
+#else
+# define __SIZEOF_SEM_T        16
+#endif
+
+/* Value returned if `sem_open' failed.  */
+#define SEM_FAILED      ((sem_t *) 0)
+
+
+typedef union
+{
+  char __size[__SIZEOF_SEM_T];
+  long int __align;
+} sem_t;
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/createthread.c b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/createthread.c
new file mode 100644 (file)
index 0000000..e811ad7
--- /dev/null
@@ -0,0 +1,25 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Paul Mackerras <paulus@au.ibm.com>.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* Value passed to 'clone' for initialization of the thread register.  */
+#define TLS_VALUE ((void *) (pd) \
+                  + TLS_TCB_OFFSET + TLS_PRE_TCB_SIZE)
+
+/* Get the real implementation.         */
+#include <nptl/sysdeps/pthread/createthread.c>
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/fork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/fork.c
new file mode 100644 (file)
index 0000000..06b7e1c
--- /dev/null
@@ -0,0 +1 @@
+#include "../i386/fork.c"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/lowlevellock.h b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/lowlevellock.h
new file mode 100644 (file)
index 0000000..66c02cb
--- /dev/null
@@ -0,0 +1,314 @@
+/* Copyright (C) 2003, 2004, 2006-2008, 2009 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _LOWLEVELLOCK_H
+#define _LOWLEVELLOCK_H        1
+
+#include <time.h>
+#include <sys/param.h>
+#include <bits/pthreadtypes.h>
+#include <atomic.h>
+#include <kernel-features.h>
+
+#ifndef __NR_futex
+# define __NR_futex            221
+#endif
+#define FUTEX_WAIT             0
+#define FUTEX_WAKE             1
+#define FUTEX_REQUEUE          3
+#define FUTEX_CMP_REQUEUE      4
+#define FUTEX_WAKE_OP          5
+#define FUTEX_OP_CLEAR_WAKE_IF_GT_ONE  ((4 << 24) | 1)
+#define FUTEX_LOCK_PI          6
+#define FUTEX_UNLOCK_PI                7
+#define FUTEX_TRYLOCK_PI       8
+#define FUTEX_WAIT_BITSET      9
+#define FUTEX_WAKE_BITSET      10
+#define FUTEX_PRIVATE_FLAG     128
+#define FUTEX_CLOCK_REALTIME   256
+
+#define FUTEX_BITSET_MATCH_ANY 0xffffffff
+
+/* Values for 'private' parameter of locking macros.  Yes, the
+   definition seems to be backwards.  But it is not.  The bit will be
+   reversed before passing to the system call.  */
+#define LLL_PRIVATE    0
+#define LLL_SHARED     FUTEX_PRIVATE_FLAG
+
+#if !defined NOT_IN_libc || defined IS_IN_rtld
+/* In libc.so or ld.so all futexes are private.  */
+# ifdef __ASSUME_PRIVATE_FUTEX
+#  define __lll_private_flag(fl, private) \
+  ((fl) | FUTEX_PRIVATE_FLAG)
+# else
+#  define __lll_private_flag(fl, private) \
+  ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex))
+# endif
+#else
+# ifdef __ASSUME_PRIVATE_FUTEX
+#  define __lll_private_flag(fl, private) \
+  (((fl) | FUTEX_PRIVATE_FLAG) ^ (private))
+# else
+#  define __lll_private_flag(fl, private) \
+  (__builtin_constant_p (private)                                            \
+   ? ((private) == 0                                                         \
+      ? ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex))           \
+      : (fl))                                                                \
+   : ((fl) | (((private) ^ FUTEX_PRIVATE_FLAG)                               \
+             & THREAD_GETMEM (THREAD_SELF, header.private_futex))))
+# endif
+#endif
+
+#define lll_futex_wait(futexp, val, private) \
+  lll_futex_timed_wait (futexp, val, NULL, private)
+
+#define lll_futex_timed_wait(futexp, val, timespec, private) \
+  ({                                                                         \
+    INTERNAL_SYSCALL_DECL (__err);                                           \
+    long int __ret;                                                          \
+                                                                             \
+    __ret = INTERNAL_SYSCALL (futex, __err, 4, (futexp),                     \
+                             __lll_private_flag (FUTEX_WAIT, private),       \
+                             (val), (timespec));                             \
+    INTERNAL_SYSCALL_ERROR_P (__ret, __err) ? -__ret : __ret;                \
+  })
+
+#define lll_futex_wake(futexp, nr, private) \
+  ({                                                                         \
+    INTERNAL_SYSCALL_DECL (__err);                                           \
+    long int __ret;                                                          \
+                                                                             \
+    __ret = INTERNAL_SYSCALL (futex, __err, 4, (futexp),                     \
+                             __lll_private_flag (FUTEX_WAKE, private),       \
+                             (nr), 0);                                       \
+    INTERNAL_SYSCALL_ERROR_P (__ret, __err) ? -__ret : __ret;                \
+  })
+
+#define lll_robust_dead(futexv, private) \
+  do                                                                         \
+    {                                                                        \
+      INTERNAL_SYSCALL_DECL (__err);                                         \
+      int *__futexp = &(futexv);                                             \
+                                                                             \
+      atomic_or (__futexp, FUTEX_OWNER_DIED);                                \
+      INTERNAL_SYSCALL (futex, __err, 4, __futexp,                           \
+                       __lll_private_flag (FUTEX_WAKE, private), 1, 0);      \
+    }                                                                        \
+  while (0)
+
+/* Returns non-zero if error happened, zero if success.  */
+#define lll_futex_requeue(futexp, nr_wake, nr_move, mutex, val, private) \
+  ({                                                                         \
+    INTERNAL_SYSCALL_DECL (__err);                                           \
+    long int __ret;                                                          \
+                                                                             \
+    __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp),                     \
+                             __lll_private_flag (FUTEX_CMP_REQUEUE, private),\
+                             (nr_wake), (nr_move), (mutex), (val));          \
+    INTERNAL_SYSCALL_ERROR_P (__ret, __err);                                 \
+  })
+
+/* Returns non-zero if error happened, zero if success.  */
+#define lll_futex_wake_unlock(futexp, nr_wake, nr_wake2, futexp2, private) \
+  ({                                                                         \
+    INTERNAL_SYSCALL_DECL (__err);                                           \
+    long int __ret;                                                          \
+                                                                             \
+    __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp),                     \
+                             __lll_private_flag (FUTEX_WAKE_OP, private),    \
+                             (nr_wake), (nr_wake2), (futexp2),               \
+                             FUTEX_OP_CLEAR_WAKE_IF_GT_ONE);                 \
+    INTERNAL_SYSCALL_ERROR_P (__ret, __err);                                 \
+  })
+
+
+#ifdef UP
+# define __lll_acq_instr       ""
+# define __lll_rel_instr       ""
+#else
+# define __lll_acq_instr       "isync"
+# ifdef _ARCH_PWR4
+/*
+ * Newer powerpc64 processors support the new "light weight" sync (lwsync)
+ * So if the build is using -mcpu=[power4,power5,power5+,970] we can
+ * safely use lwsync.
+ */
+#  define __lll_rel_instr      "lwsync"
+# else
+/*
+ * Older powerpc32 processors don't support the new "light weight"
+ * sync (lwsync).  So the only safe option is to use normal sync
+ * for all powerpc32 applications.
+ */
+#  define __lll_rel_instr      "sync"
+# endif
+#endif
+
+/* Set *futex to ID if it is 0, atomically.  Returns the old value */
+#define __lll_robust_trylock(futex, id) \
+  ({ int __val;                                                                      \
+     __asm __volatile ("1:     lwarx   %0,0,%2" MUTEX_HINT_ACQ "\n"          \
+                      "        cmpwi   0,%0,0\n"                             \
+                      "        bne     2f\n"                                 \
+                      "        stwcx.  %3,0,%2\n"                            \
+                      "        bne-    1b\n"                                 \
+                      "2:      " __lll_acq_instr                             \
+                      : "=&r" (__val), "=m" (*futex)                         \
+                      : "r" (futex), "r" (id), "m" (*futex)                  \
+                      : "cr0", "memory");                                    \
+     __val;                                                                  \
+  })
+
+#define lll_robust_trylock(lock, id) __lll_robust_trylock (&(lock), id)
+
+/* Set *futex to 1 if it is 0, atomically.  Returns the old value */
+#define __lll_trylock(futex) __lll_robust_trylock (futex, 1)
+
+#define lll_trylock(lock)      __lll_trylock (&(lock))
+
+/* Set *futex to 2 if it is 0, atomically.  Returns the old value */
+#define __lll_cond_trylock(futex) __lll_robust_trylock (futex, 2)
+
+#define lll_cond_trylock(lock) __lll_cond_trylock (&(lock))
+
+
+extern void __lll_lock_wait_private (int *futex) attribute_hidden;
+extern void __lll_lock_wait (int *futex, int private) attribute_hidden;
+extern int __lll_robust_lock_wait (int *futex, int private) attribute_hidden;
+
+#define lll_lock(lock, private) \
+  (void) ({                                                                  \
+    int *__futex = &(lock);                                                  \
+    if (__builtin_expect (atomic_compare_and_exchange_val_acq (__futex, 1, 0),\
+                         0) != 0)                                            \
+      {                                                                              \
+       if (__builtin_constant_p (private) && (private) == LLL_PRIVATE)       \
+         __lll_lock_wait_private (__futex);                                  \
+       else                                                                  \
+         __lll_lock_wait (__futex, private);                                 \
+      }                                                                              \
+  })
+
+#define lll_robust_lock(lock, id, private) \
+  ({                                                                         \
+    int *__futex = &(lock);                                                  \
+    int __val = 0;                                                           \
+    if (__builtin_expect (atomic_compare_and_exchange_bool_acq (__futex, id,  \
+                                                               0), 0))       \
+      __val = __lll_robust_lock_wait (__futex, private);                     \
+    __val;                                                                   \
+  })
+
+#define lll_cond_lock(lock, private) \
+  (void) ({                                                                  \
+    int *__futex = &(lock);                                                  \
+    if (__builtin_expect (atomic_compare_and_exchange_val_acq (__futex, 2, 0),\
+                         0) != 0)                                            \
+      __lll_lock_wait (__futex, private);                                    \
+  })
+
+#define lll_robust_cond_lock(lock, id, private) \
+  ({                                                                         \
+    int *__futex = &(lock);                                                  \
+    int __val = 0;                                                           \
+    int __id = id | FUTEX_WAITERS;                                           \
+    if (__builtin_expect (atomic_compare_and_exchange_bool_acq (__futex, __id,\
+                                                               0), 0))       \
+      __val = __lll_robust_lock_wait (__futex, private);                     \
+    __val;                                                                   \
+  })
+
+
+extern int __lll_timedlock_wait
+  (int *futex, const struct timespec *, int private) attribute_hidden;
+extern int __lll_robust_timedlock_wait
+  (int *futex, const struct timespec *, int private) attribute_hidden;
+
+#define lll_timedlock(lock, abstime, private) \
+  ({                                                                         \
+    int *__futex = &(lock);                                                  \
+    int __val = 0;                                                           \
+    if (__builtin_expect (atomic_compare_and_exchange_val_acq (__futex, 1, 0),\
+                         0) != 0)                                            \
+      __val = __lll_timedlock_wait (__futex, abstime, private);                      \
+    __val;                                                                   \
+  })
+
+#define lll_robust_timedlock(lock, abstime, id, private) \
+  ({                                                                         \
+    int *__futex = &(lock);                                                  \
+    int __val = 0;                                                           \
+    if (__builtin_expect (atomic_compare_and_exchange_bool_acq (__futex, id,  \
+                                                               0), 0))       \
+      __val = __lll_robust_timedlock_wait (__futex, abstime, private);       \
+    __val;                                                                   \
+  })
+
+#define lll_unlock(lock, private) \
+  ((void) ({                                                                 \
+    int *__futex = &(lock);                                                  \
+    int __val = atomic_exchange_rel (__futex, 0);                            \
+    if (__builtin_expect (__val > 1, 0))                                     \
+      lll_futex_wake (__futex, 1, private);                                  \
+  }))
+
+#define lll_robust_unlock(lock, private) \
+  ((void) ({                                                                 \
+    int *__futex = &(lock);                                                  \
+    int __val = atomic_exchange_rel (__futex, 0);                            \
+    if (__builtin_expect (__val & FUTEX_WAITERS, 0))                         \
+      lll_futex_wake (__futex, 1, private);                                  \
+  }))
+
+#define lll_islocked(futex) \
+  (futex != 0)
+
+
+/* Initializers for lock.  */
+#define LLL_LOCK_INITIALIZER           (0)
+#define LLL_LOCK_INITIALIZER_LOCKED    (1)
+
+/* The states of a lock are:
+    0  -  untaken
+    1  -  taken by one user
+   >1  -  taken by more users */
+
+/* The kernel notifies a process which uses CLONE_CLEARTID via futex
+   wakeup when the clone terminates.  The memory location contains the
+   thread ID while the clone is running and is reset to zero
+   afterwards. */
+#define lll_wait_tid(tid) \
+  do {                                                                       \
+    __typeof (tid) __tid;                                                    \
+    while ((__tid = (tid)) != 0)                                             \
+      lll_futex_wait (&(tid), __tid, LLL_SHARED);                            \
+  } while (0)
+
+extern int __lll_timedwait_tid (int *, const struct timespec *)
+     attribute_hidden;
+
+#define lll_timedwait_tid(tid, abstime) \
+  ({                                                                         \
+    int __res = 0;                                                           \
+    if ((tid) != 0)                                                          \
+      __res = __lll_timedwait_tid (&(tid), (abstime));                       \
+    __res;                                                                   \
+  })
+
+#endif /* lowlevellock.h */
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/not-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/not-cancel.h
new file mode 100644 (file)
index 0000000..acf1a61
--- /dev/null
@@ -0,0 +1 @@
+#include "../i386/not-cancel.h"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc32/clone.S b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc32/clone.S
new file mode 100644 (file)
index 0000000..675a997
--- /dev/null
@@ -0,0 +1,9 @@
+/* We want an #include_next, but we are the main source file.
+   So, #include ourselves and in that incarnation we can use #include_next.  */
+#ifndef INCLUDED_SELF
+# define INCLUDED_SELF
+# include <clone.S>
+#else
+# define RESET_PID
+# include_next <clone.S>
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc32/pt-vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc32/pt-vfork.S
new file mode 100644 (file)
index 0000000..61651fd
--- /dev/null
@@ -0,0 +1,49 @@
+/* Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2004.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#define _ERRNO_H       1
+#include <bits/errno.h>
+#include <bits/kernel-features.h>
+#include <tcb-offsets.h>
+
+/* Clone the calling process, but without copying the whole address space.
+   The calling process is suspended until the new process exits or is
+   replaced by a call to `execve'.  Return -1 for errors, 0 to the new process,
+   and the process ID of the new process to the old process.  */
+
+ENTRY (__vfork)
+       lwz     0,PID(2)
+       neg     0,0
+       stw     0,PID(2)
+
+       DO_CALL (SYS_ify (vfork))
+
+       cmpwi   1,3,0
+       beqlr-  1
+
+       lwz     0,PID(2)
+       neg     0,0
+       stw     0,PID(2)
+
+       PSEUDO_RET
+
+PSEUDO_END (__vfork)
+
+weak_alias (__vfork, vfork)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h
new file mode 100644 (file)
index 0000000..88b24e7
--- /dev/null
@@ -0,0 +1,119 @@
+/* Cancellable system call stubs.  Linux/PowerPC version.
+   Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Franz Sirl <Franz.Sirl-kernel@lauterbach.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA
+   02110-1301 USA.  */
+
+#include <sysdep.h>
+#include <tls.h>
+#ifndef __ASSEMBLER__
+# include <nptl/pthreadP.h>
+#endif
+
+#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt
+
+# undef PSEUDO
+# define PSEUDO(name, syscall_name, args)                              \
+  .section ".text";                                                    \
+  ENTRY (name)                                                         \
+    SINGLE_THREAD_P;                                                   \
+    bne- .Lpseudo_cancel;                                              \
+  .type __##syscall_name##_nocancel,@function;                         \
+  .globl __##syscall_name##_nocancel;                                  \
+  __##syscall_name##_nocancel:                                         \
+    DO_CALL (SYS_ify (syscall_name));                                  \
+    PSEUDO_RET;                                                                \
+  .size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel;     \
+  .Lpseudo_cancel:                                                     \
+    stwu 1,-48(1);                                                     \
+    cfi_adjust_cfa_offset (48);                                                \
+    mflr 9;                                                            \
+    stw 9,52(1);                                                       \
+    cfi_offset (lr, 4);                                                        \
+    DOCARGS_##args;    /* save syscall args around CENABLE.  */        \
+    CENABLE;                                                           \
+    stw 3,16(1);       /* store CENABLE return value (MASK).  */       \
+    UNDOCARGS_##args;  /* restore syscall args.  */                    \
+    DO_CALL (SYS_ify (syscall_name));                                  \
+    mfcr 0;            /* save CR/R3 around CDISABLE.  */              \
+    stw 3,8(1);                                                                \
+    stw 0,12(1);                                                       \
+    lwz 3,16(1);       /* pass MASK to CDISABLE.  */                   \
+    CDISABLE;                                                          \
+    lwz 4,52(1);                                                       \
+    lwz 0,12(1);       /* restore CR/R3. */                            \
+    lwz 3,8(1);                                                                \
+    mtlr 4;                                                            \
+    mtcr 0;                                                            \
+    addi 1,1,48;
+
+# define DOCARGS_0
+# define UNDOCARGS_0
+
+# define DOCARGS_1     stw 3,20(1); DOCARGS_0
+# define UNDOCARGS_1   lwz 3,20(1); UNDOCARGS_0
+
+# define DOCARGS_2     stw 4,24(1); DOCARGS_1
+# define UNDOCARGS_2   lwz 4,24(1); UNDOCARGS_1
+
+# define DOCARGS_3     stw 5,28(1); DOCARGS_2
+# define UNDOCARGS_3   lwz 5,28(1); UNDOCARGS_2
+
+# define DOCARGS_4     stw 6,32(1); DOCARGS_3
+# define UNDOCARGS_4   lwz 6,32(1); UNDOCARGS_3
+
+# define DOCARGS_5     stw 7,36(1); DOCARGS_4
+# define UNDOCARGS_5   lwz 7,36(1); UNDOCARGS_4
+
+# define DOCARGS_6     stw 8,40(1); DOCARGS_5
+# define UNDOCARGS_6   lwz 8,40(1); UNDOCARGS_5
+
+# ifdef IS_IN_libpthread
+#  define CENABLE      bl __pthread_enable_asynccancel@local
+#  define CDISABLE     bl __pthread_disable_asynccancel@local
+# elif !defined NOT_IN_libc
+#  define CENABLE      bl __libc_enable_asynccancel@local
+#  define CDISABLE     bl __libc_disable_asynccancel@local
+# elif defined IS_IN_librt
+#  define CENABLE      bl __librt_enable_asynccancel@local
+#  define CDISABLE     bl __librt_disable_asynccancel@local
+# else
+#  error Unsupported library
+# endif
+
+# ifndef __ASSEMBLER__
+#  define SINGLE_THREAD_P                                              \
+  __builtin_expect (THREAD_GETMEM (THREAD_SELF,                                \
+                                  header.multiple_threads) == 0, 1)
+# else
+#  define SINGLE_THREAD_P                                              \
+  lwz 10,MULTIPLE_THREADS_OFFSET(2);                                   \
+  cmpwi 10,0
+# endif
+
+#elif !defined __ASSEMBLER__
+
+# define SINGLE_THREAD_P (1)
+# define NO_CANCELLATION 1
+
+#endif
+
+#ifndef __ASSEMBLER__
+# define RTLD_SINGLE_THREAD_P \
+  __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
+                                  header.multiple_threads) == 0, 1)
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc32/vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc32/vfork.S
new file mode 100644 (file)
index 0000000..eed2a8f
--- /dev/null
@@ -0,0 +1,57 @@
+/* Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2004.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#define _ERRNO_H       1
+#include <bits/errno.h>
+#include <bits/kernel-features.h>
+#include <tcb-offsets.h>
+
+/* Clone the calling process, but without copying the whole address space.
+   The calling process is suspended until the new process exits or is
+   replaced by a call to `execve'.  Return -1 for errors, 0 to the new process,
+   and the process ID of the new process to the old process.  */
+
+ENTRY (__vfork)
+       lwz     0,PID(2)
+       cmpwi   0,0,0
+       neg     0,0
+       bne-    0,1f
+       lis     0,0x8000
+1:     stw     0,PID(2)
+
+       DO_CALL (SYS_ify (vfork))
+
+       cmpwi   1,3,0
+       beqlr-  1
+
+       lwz     0,PID(2)
+       /* Cannot use clrlwi. here, because cr0 needs to be preserved
+          until PSEUDO_RET.  */
+       clrlwi  4,0,1
+       cmpwi   1,4,0
+       beq-    1,1f
+       neg     4,0
+1:     stw     4,PID(2)
+
+       PSEUDO_RET
+
+PSEUDO_END (__vfork)
+libc_hidden_def (__vfork)
+weak_alias (__vfork, vfork)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/clone.S b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/clone.S
new file mode 100644 (file)
index 0000000..675a997
--- /dev/null
@@ -0,0 +1,9 @@
+/* We want an #include_next, but we are the main source file.
+   So, #include ourselves and in that incarnation we can use #include_next.  */
+#ifndef INCLUDED_SELF
+# define INCLUDED_SELF
+# include <clone.S>
+#else
+# define RESET_PID
+# include_next <clone.S>
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/pt-vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/pt-vfork.S
new file mode 100644 (file)
index 0000000..e5b7b53
--- /dev/null
@@ -0,0 +1,49 @@
+/* Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2004.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#define _ERRNO_H       1
+#include <bits/errno.h>
+#include <bits/kernel-features.h>
+#include <tcb-offsets.h>
+
+/* Clone the calling process, but without copying the whole address space.
+   The calling process is suspended until the new process exits or is
+   replaced by a call to `execve'.  Return -1 for errors, 0 to the new process,
+   and the process ID of the new process to the old process.  */
+
+ENTRY (__vfork)
+       lwz     0,PID(13)
+       neg     0,0
+       stw     0,PID(13)
+
+       DO_CALL (SYS_ify (vfork))
+
+       cmpwi   1,3,0
+       beqlr-  1
+
+       lwz     0,PID(13)
+       neg     0,0
+       stw     0,PID(13)
+
+       PSEUDO_RET
+
+PSEUDO_END (__vfork)
+
+weak_alias (__vfork, vfork)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h
new file mode 100644 (file)
index 0000000..707765a
--- /dev/null
@@ -0,0 +1,125 @@
+/* Cancellable system call stubs.  Linux/PowerPC64 version.
+   Copyright (C) 2003, 2004, 2006 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Franz Sirl <Franz.Sirl-kernel@lauterbach.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA
+   02110-1301 USA.  */
+
+#include <sysdep.h>
+#include <tls.h>
+#ifndef __ASSEMBLER__
+# include <nptl/pthreadP.h>
+#endif
+
+#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt
+
+# ifdef HAVE_ASM_GLOBAL_DOT_NAME
+#  define DASHDASHPFX(str) .__##str
+# else
+#  define DASHDASHPFX(str) __##str
+# endif
+
+# undef PSEUDO
+# define PSEUDO(name, syscall_name, args)                              \
+  .section ".text";                                                    \
+  ENTRY (name)                                                         \
+    SINGLE_THREAD_P;                                                   \
+    bne- .Lpseudo_cancel;                                              \
+  .type DASHDASHPFX(syscall_name##_nocancel),@function;                        \
+  .globl DASHDASHPFX(syscall_name##_nocancel);                         \
+  DASHDASHPFX(syscall_name##_nocancel):                                        \
+    DO_CALL (SYS_ify (syscall_name));                                  \
+    PSEUDO_RET;                                                                \
+  .size DASHDASHPFX(syscall_name##_nocancel),.-DASHDASHPFX(syscall_name##_nocancel);   \
+  .Lpseudo_cancel:                                                     \
+    stdu 1,-128(1);                                                    \
+    cfi_adjust_cfa_offset (128);                                       \
+    mflr 9;                                                            \
+    std  9,128+16(1);                                                  \
+    cfi_offset (lr, 16);                                               \
+    DOCARGS_##args;    /* save syscall args around CENABLE.  */        \
+    CENABLE;                                                           \
+    std  3,72(1);      /* store CENABLE return value (MASK).  */       \
+    UNDOCARGS_##args;  /* restore syscall args.  */                    \
+    DO_CALL (SYS_ify (syscall_name));                                  \
+    mfcr 0;            /* save CR/R3 around CDISABLE.  */              \
+    std  3,64(1);                                                      \
+    std  0,8(1);                                                       \
+    ld   3,72(1);      /* pass MASK to CDISABLE.  */                   \
+    CDISABLE;                                                          \
+    ld   9,128+16(1);                                                  \
+    ld   0,8(1);       /* restore CR/R3. */                            \
+    ld   3,64(1);                                                      \
+    mtlr 9;                                                            \
+    mtcr 0;                                                            \
+    addi 1,1,128;
+
+# define DOCARGS_0
+# define UNDOCARGS_0
+
+# define DOCARGS_1     std 3,80(1); DOCARGS_0
+# define UNDOCARGS_1   ld 3,80(1); UNDOCARGS_0
+
+# define DOCARGS_2     std 4,88(1); DOCARGS_1
+# define UNDOCARGS_2   ld 4,88(1); UNDOCARGS_1
+
+# define DOCARGS_3     std 5,96(1); DOCARGS_2
+# define UNDOCARGS_3   ld 5,96(1); UNDOCARGS_2
+
+# define DOCARGS_4     std 6,104(1); DOCARGS_3
+# define UNDOCARGS_4   ld 6,104(1); UNDOCARGS_3
+
+# define DOCARGS_5     std 7,112(1); DOCARGS_4
+# define UNDOCARGS_5   ld 7,112(1); UNDOCARGS_4
+
+# define DOCARGS_6     std 8,120(1); DOCARGS_5
+# define UNDOCARGS_6   ld 8,120(1); UNDOCARGS_5
+
+# ifdef IS_IN_libpthread
+#  define CENABLE      bl JUMPTARGET(__pthread_enable_asynccancel)
+#  define CDISABLE     bl JUMPTARGET(__pthread_disable_asynccancel)
+# elif !defined NOT_IN_libc
+#  define CENABLE      bl JUMPTARGET(__libc_enable_asynccancel)
+#  define CDISABLE     bl JUMPTARGET(__libc_disable_asynccancel)
+# elif defined IS_IN_librt
+#  define CENABLE      bl JUMPTARGET(__librt_enable_asynccancel)
+#  define CDISABLE     bl JUMPTARGET(__librt_disable_asynccancel)
+# else
+#  error Unsupported library
+# endif
+
+# ifndef __ASSEMBLER__
+#  define SINGLE_THREAD_P                                              \
+  __builtin_expect (THREAD_GETMEM (THREAD_SELF,                                \
+                                  header.multiple_threads) == 0, 1)
+# else
+#   define SINGLE_THREAD_P                                             \
+  lwz   10,MULTIPLE_THREADS_OFFSET(13);                                \
+  cmpwi 10,0
+# endif
+
+#elif !defined __ASSEMBLER__
+
+# define SINGLE_THREAD_P (1)
+# define NO_CANCELLATION 1
+
+#endif
+
+#ifndef __ASSEMBLER__
+# define RTLD_SINGLE_THREAD_P \
+  __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
+                                  header.multiple_threads) == 0, 1)
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_create.c b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_create.c
new file mode 100644 (file)
index 0000000..172223a
--- /dev/null
@@ -0,0 +1 @@
+#include "../x86_64/timer_create.c"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_delete.c b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_delete.c
new file mode 100644 (file)
index 0000000..537516e
--- /dev/null
@@ -0,0 +1 @@
+#include "../x86_64/timer_delete.c"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_getoverr.c b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_getoverr.c
new file mode 100644 (file)
index 0000000..3f21a73
--- /dev/null
@@ -0,0 +1 @@
+#include "../x86_64/timer_getoverr.c"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_gettime.c b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_gettime.c
new file mode 100644 (file)
index 0000000..a50143a
--- /dev/null
@@ -0,0 +1 @@
+#include "../x86_64/timer_gettime.c"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_settime.c b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_settime.c
new file mode 100644 (file)
index 0000000..37baeff
--- /dev/null
@@ -0,0 +1 @@
+#include "../x86_64/timer_settime.c"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/vfork.S
new file mode 100644 (file)
index 0000000..26885bb
--- /dev/null
@@ -0,0 +1,55 @@
+/* Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2004.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#define _ERRNO_H       1
+#include <bits/errno.h>
+#include <bits/kernel-features.h>
+#include <tcb-offsets.h>
+
+/* Clone the calling process, but without copying the whole address space.
+   The calling process is suspended until the new process exits or is
+   replaced by a call to `execve'.  Return -1 for errors, 0 to the new process,
+   and the process ID of the new process to the old process.  */
+
+ENTRY (__vfork)
+       lwz     0,PID(13)
+       cmpwi   0,0,0
+       neg     0,0
+       bne-    0,1f
+       lis     0,0x8000
+1:     stw     0,PID(13)
+
+       DO_CALL (SYS_ify (vfork))
+
+       cmpwi   1,3,0
+       beqlr-  1
+
+       lwz     0,PID(13)
+       clrlwi  4,0,1
+       cmpwi   1,4,0
+       beq-    1,1f
+       neg     4,0
+1:     stw     4,PID(13)
+
+       PSEUDO_RET
+
+PSEUDO_END (__vfork)
+libc_hidden_def (__vfork)
+weak_alias (__vfork, vfork)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/pt-longjmp.c b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/pt-longjmp.c
new file mode 100644 (file)
index 0000000..b6d6b3d
--- /dev/null
@@ -0,0 +1,37 @@
+/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <setjmp.h>
+#include <stdlib.h>
+#include <bits/wordsize.h>
+#include "pthreadP.h"
+
+void
+__vmx_longjmp (jmp_buf env, int val)
+{
+  __libc_longjmp (env, val);
+}
+
+void
+__vmx_siglongjmp (jmp_buf env, int val)
+{
+  __libc_siglongjmp (env, val);
+}
+weak_alias(__vmx_longjmp, longjmp)
+weak_alias(__vmx_siglongjmp, siglongjmp)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/pthread_once.c b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/pthread_once.c
new file mode 100644 (file)
index 0000000..9690780
--- /dev/null
@@ -0,0 +1,100 @@
+/* Copyright (C) 2003, 2004, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+#include <lowlevellock.h>
+
+
+unsigned long int __fork_generation attribute_hidden;
+
+
+static void
+clear_once_control (void *arg)
+{
+  pthread_once_t *once_control = (pthread_once_t *) arg;
+
+  *once_control = 0;
+  lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE);
+}
+
+
+int
+__pthread_once (pthread_once_t *once_control, void (*init_routine) (void))
+{
+  for (;;)
+    {
+      int oldval;
+      int newval;
+      int tmp;
+
+      /* Pseudo code:
+        newval = __fork_generation | 1;
+        oldval = *once_control;
+        if ((oldval & 2) == 0)
+          *once_control = newval;
+        Do this atomically.
+      */
+      newval = __fork_generation | 1;
+      __asm __volatile ("1:    lwarx   %0,0,%3\n"
+                       "       andi.   %1,%0,2\n"
+                       "       bne     2f\n"
+                       "       stwcx.  %4,0,%3\n"
+                       "       bne     1b\n"
+                       "2:     isync"
+                       : "=&r" (oldval), "=&r" (tmp), "=m" (*once_control)
+                       : "r" (once_control), "r" (newval), "m" (*once_control)
+                       : "cr0");
+
+      /* Check if the initializer has already been done.  */
+      if ((oldval & 2) != 0)
+       return 0;
+
+      /* Check if another thread already runs the initializer. */
+      if ((oldval & 1) == 0)
+       break;
+
+      /* Check whether the initializer execution was interrupted by a fork.  */
+      if (oldval != newval)
+       break;
+
+      /* Same generation, some other thread was faster. Wait.  */
+      lll_futex_wait (once_control, oldval, LLL_PRIVATE);
+    }
+
+
+  /* This thread is the first here.  Do the initialization.
+     Register a cleanup handler so that in case the thread gets
+     interrupted the initialization can be restarted.  */
+  pthread_cleanup_push (clear_once_control, once_control);
+
+  init_routine ();
+
+  pthread_cleanup_pop (0);
+
+
+  /* Add one to *once_control to take the bottom 2 bits from 01 to 10.  */
+  atomic_increment (once_control);
+
+  /* Wake up all other threads.  */
+  lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE);
+
+  return 0;
+}
+weak_alias (__pthread_once, pthread_once)
+strong_alias (__pthread_once, __pthread_once_internal)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/pthread_spin_unlock.c b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/pthread_spin_unlock.c
new file mode 100644 (file)
index 0000000..90f2dc6
--- /dev/null
@@ -0,0 +1,29 @@
+/* pthread_spin_unlock -- unlock a spin lock.  PowerPC version.
+   Copyright (C) 2007 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 "pthreadP.h"
+#include <lowlevellock.h>
+
+int
+pthread_spin_unlock (pthread_spinlock_t *lock)
+{
+  __asm __volatile (__lll_rel_instr ::: "memory");
+  *lock = 0;
+  return 0;
+}
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/sem_post.c b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/sem_post.c
new file mode 100644 (file)
index 0000000..0082c57
--- /dev/null
@@ -0,0 +1,47 @@
+/* sem_post -- post to a POSIX semaphore.  Powerpc version.
+   Copyright (C) 2003, 2004, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <internaltypes.h>
+#include <semaphore.h>
+
+int
+__new_sem_post (sem_t *sem)
+{
+  struct new_sem *isem = (struct new_sem *) sem;
+
+  __asm __volatile (__lll_rel_instr ::: "memory");
+  atomic_increment (&isem->value);
+  __asm __volatile (__lll_acq_instr ::: "memory");
+  if (isem->nwaiters > 0)
+    {
+      int err = lll_futex_wake (&isem->value, 1,
+                               isem->private ^ FUTEX_PRIVATE_FLAG);
+      if (__builtin_expect (err, 0) < 0)
+       {
+         __set_errno (-err);
+         return -1;
+       }
+    }
+  return 0;
+}
+weak_alias(__new_sem_post, sem_post)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-accept.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-accept.S
new file mode 100644 (file)
index 0000000..2406210
--- /dev/null
@@ -0,0 +1,12 @@
+#include <sysdep-cancel.h>
+#ifndef __NR_accept
+#error Missing definition of NR_accept needed for cancellation.
+#endif
+PSEUDO (__libc_accept, accept, 3)
+ret
+PSEUDO_END(__libc_accept)
+libpthread_hidden_def (__libc_accept)
+weak_alias (__libc_accept, __accept)
+libpthread_hidden_weak (__accept)
+weak_alias (__libc_accept, accept)
+libpthread_hidden_weak (accept)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-close.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-close.S
new file mode 100644 (file)
index 0000000..ab32ca5
--- /dev/null
@@ -0,0 +1,9 @@
+#include <sysdep-cancel.h>
+PSEUDO (__libc_close, close, 1)
+ret
+PSEUDO_END (__libc_close)
+libpthread_hidden_def (__libc_close)
+weak_alias (__libc_close, __close)
+libpthread_hidden_weak (__close)
+weak_alias (__libc_close, close)
+libpthread_hidden_weak (close)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-connect.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-connect.S
new file mode 100644 (file)
index 0000000..b5124f8
--- /dev/null
@@ -0,0 +1,12 @@
+#include <sysdep-cancel.h>
+#ifndef __NR_connect
+#error Missing definition of NR_connect needed for cancellation.
+#endif
+PSEUDO (__libc_connect, connect, 3)
+ret
+PSEUDO_END(__libc_connect)
+libpthread_hidden_def (__libc_connect)
+weak_alias (__libc_connect, __connect)
+libpthread_hidden_weak (__connect)
+weak_alias (__libc_connect, connect)
+libpthread_hidden_weak (connect)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-fcntl.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-fcntl.c
new file mode 100644 (file)
index 0000000..0a8fd3c
--- /dev/null
@@ -0,0 +1 @@
+#include <../../../../../../libc/sysdeps/linux/common/__syscall_fcntl.c>
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-fork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-fork.c
new file mode 100644 (file)
index 0000000..3e1b70f
--- /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 <unistd.h>
+
+extern int __libc_fork (void);
+
+pid_t
+__fork (void)
+{
+  return __libc_fork ();
+}
+strong_alias (__fork, fork)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-fsync.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-fsync.c
new file mode 100644 (file)
index 0000000..6ec4821
--- /dev/null
@@ -0,0 +1,2 @@
+#include <pthreadP.h>
+#include <../../../../../../libc/sysdeps/linux/common/fsync.c>
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-llseek.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-llseek.c
new file mode 100644 (file)
index 0000000..1d0d578
--- /dev/null
@@ -0,0 +1,3 @@
+#include <pthreadP.h>
+#define libc_hidden libpthread_hidden
+#include <../../../../../../libc/sysdeps/linux/common/llseek.c>
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-lseek.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-lseek.S
new file mode 100644 (file)
index 0000000..4db7172
--- /dev/null
@@ -0,0 +1,7 @@
+#include <sysdep-cancel.h>
+PSEUDO (__libc_lseek, lseek, 3)
+ret
+PSEUDO_END (__libc_lseek)
+libpthread_hidden_def (__libc_lseek)
+weak_alias (__libc_lseek, lseek)
+libpthread_hidden_weak (lseek)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-msgrcv.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-msgrcv.c
new file mode 100644 (file)
index 0000000..3bb9d53
--- /dev/null
@@ -0,0 +1,2 @@
+#define L_msgrcv
+#include <../../../../../../libc/misc/sysvipc/msgq.c>
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-msgsnd.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-msgsnd.c
new file mode 100644 (file)
index 0000000..1566f65
--- /dev/null
@@ -0,0 +1,2 @@
+#define L_msgsnd
+#include <../../../../../../libc/misc/sysvipc/msgq.c>
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-msync.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-msync.S
new file mode 100644 (file)
index 0000000..640270a
--- /dev/null
@@ -0,0 +1,7 @@
+#include <sysdep-cancel.h>
+PSEUDO (__libc_msync, msync, 3)
+ret
+PSEUDO_END(__libc_msync)
+libpthread_hidden_def (__libc_msync)
+weak_alias (__libc_msync, msync)
+libpthread_hidden_weak (msync)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-nanosleep.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-nanosleep.S
new file mode 100644 (file)
index 0000000..08d8f01
--- /dev/null
@@ -0,0 +1,9 @@
+#include <sysdep-cancel.h>
+PSEUDO (__libc_nanosleep, nanosleep, 3)
+ret
+PSEUDO_END (__libc_nanosleep)
+libpthread_hidden_def (__libc_nanosleep)
+weak_alias (__libc_nanosleep, __nanosleep)
+libpthread_hidden_weak (__nanosleep)
+weak_alias (__libc_nanosleep, nanosleep)
+libpthread_hidden_weak (nanosleep)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-open.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-open.S
new file mode 100644 (file)
index 0000000..39ed92c
--- /dev/null
@@ -0,0 +1,9 @@
+#include <sysdep-cancel.h>
+PSEUDO (__libc_open, open, 3)
+ret
+PSEUDO_END (__libc_open)
+libpthread_hidden_def (__libc_open)
+weak_alias (__libc_open, __open)
+libpthread_hidden_weak (__open)
+weak_alias (__libc_open, open)
+libpthread_hidden_weak (open)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-open64.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-open64.c
new file mode 100644 (file)
index 0000000..2029539
--- /dev/null
@@ -0,0 +1 @@
+#include <../../../../../../libc/sysdeps/linux/common/open64.c>
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-pause.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-pause.S
new file mode 100644 (file)
index 0000000..c6cb571
--- /dev/null
@@ -0,0 +1,7 @@
+#include <sysdep-cancel.h>
+PSEUDO (__libc_pause, pause, 0)
+ret
+PSEUDO_END (__libc_pause)
+libpthread_hidden_def (__libc_pause)
+weak_alias (__libc_pause, pause)
+libpthread_hidden_weak (pause)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-pread_pwrite.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-pread_pwrite.c
new file mode 100644 (file)
index 0000000..f32c0a6
--- /dev/null
@@ -0,0 +1 @@
+#include "pread_write.c"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-raise.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-raise.c
new file mode 100644 (file)
index 0000000..d256ebc
--- /dev/null
@@ -0,0 +1,52 @@
+/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <signal.h>
+#include <sysdep.h>
+#include <tls.h>
+#include <bits/kernel-features.h>
+
+
+int
+raise (
+     int sig)
+{
+#if __ASSUME_TGKILL || defined __NR_tgkill
+  /* raise is an async-safe function.  It could be called while the
+     fork function temporarily invalidated the PID field.  Adjust for
+     that.  */
+  pid_t pid = THREAD_GETMEM (THREAD_SELF, pid);
+  if (__builtin_expect (pid < 0, 0))
+    pid = -pid;
+#endif
+
+#if __ASSUME_TGKILL
+  return INLINE_SYSCALL (tgkill, 3, pid, THREAD_GETMEM (THREAD_SELF, tid),
+                        sig);
+#else
+# ifdef __NR_tgkill
+  int res = INLINE_SYSCALL (tgkill, 3, pid, THREAD_GETMEM (THREAD_SELF, tid),
+                           sig);
+  if (res != -1 || errno != ENOSYS)
+    return res;
+# endif
+  return INLINE_SYSCALL (tkill, 2, THREAD_GETMEM (THREAD_SELF, tid), sig);
+#endif
+}
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-read.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-read.S
new file mode 100644 (file)
index 0000000..623ba27
--- /dev/null
@@ -0,0 +1,9 @@
+#include <sysdep-cancel.h>
+PSEUDO (__libc_read, read, 3)
+ret
+PSEUDO_END (__libc_read)
+libpthread_hidden_def (__libc_read)
+weak_alias (__libc_read, __read)
+libpthread_hidden_weak (__read)
+weak_alias (__libc_read, read)
+libpthread_hidden_weak (read)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-recv.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-recv.S
new file mode 100644 (file)
index 0000000..6d2e3c2
--- /dev/null
@@ -0,0 +1,12 @@
+#include <sysdep-cancel.h>
+#ifndef __NR_recv
+#error Missing definition of NR_recv needed for cancellation.
+#endif
+PSEUDO (__libc_recv, recv, 4)
+ret
+PSEUDO_END(__libc_recv)
+libpthread_hidden_def (__libc_recv)
+weak_alias (__libc_recv, __recv)
+libpthread_hidden_weak (__recv)
+weak_alias (__libc_recv, recv)
+libpthread_hidden_weak (recv)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-recvfrom.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-recvfrom.S
new file mode 100644 (file)
index 0000000..96aeeaa
--- /dev/null
@@ -0,0 +1,12 @@
+#include <sysdep-cancel.h>
+#ifndef __NR_recvfrom
+#error Missing definition of NR_recvfrom needed for cancellation.
+#endif
+PSEUDO (__libc_recvfrom, recvfrom, 6)
+ret
+PSEUDO_END(__libc_recvfrom)
+libpthread_hidden_def (__libc_recvfrom)
+weak_alias (__libc_recvfrom, __recvfrom)
+libpthread_hidden_weak (__recvfrom)
+weak_alias (__libc_recvfrom, recvfrom)
+libpthread_hidden_weak (recvfrom)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-recvmsg.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-recvmsg.S
new file mode 100644 (file)
index 0000000..f7161e4
--- /dev/null
@@ -0,0 +1,12 @@
+#include <sysdep-cancel.h>
+#ifndef __NR_recvmsg
+#error Missing definition of NR_recvmsg needed for cancellation.
+#endif
+PSEUDO (__libc_recvmsg, recvmsg, 3)
+ret
+PSEUDO_END(__libc_recvmsg)
+libpthread_hidden_def (__libc_recvmsg)
+weak_alias (__libc_recvmsg, __recvmsg)
+libpthread_hidden_weak (__recvmsg)
+weak_alias (__libc_recvmsg, recvmsg)
+libpthread_hidden_weak (recvmsg)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-send.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-send.S
new file mode 100644 (file)
index 0000000..76bed39
--- /dev/null
@@ -0,0 +1,12 @@
+#include <sysdep-cancel.h>
+#ifndef __NR_send
+#error Missing definition of NR_send needed for cancellation.
+#endif
+PSEUDO (__libc_send, send, 4)
+ret
+PSEUDO_END (__libc_send)
+libpthread_hidden_def (__libc_send)
+weak_alias (__libc_send, __send)
+libpthread_hidden_weak (__send)
+weak_alias (__libc_send, send)
+libpthread_hidden_weak (send)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-sendmsg.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-sendmsg.S
new file mode 100644 (file)
index 0000000..d17096e
--- /dev/null
@@ -0,0 +1,12 @@
+#include <sysdep-cancel.h>
+#ifndef __NR_sendmsg
+#error Missing definition of NR_sendmsg needed for cancellation.
+#endif
+PSEUDO (__libc_sendmsg, sendmsg, 3)
+ret
+PSEUDO_END(__libc_sendmsg)
+libpthread_hidden_def (__libc_sendmsg)
+weak_alias (__libc_sendmsg, __sendmsg)
+libpthread_hidden_weak (__sendmsg)
+weak_alias (__libc_sendmsg, sendmsg)
+libpthread_hidden_weak (sendmsg)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-sendto.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-sendto.S
new file mode 100644 (file)
index 0000000..d07a71f
--- /dev/null
@@ -0,0 +1,12 @@
+#include <sysdep-cancel.h>
+#ifndef __NR_sendto
+#error Missing definition of NR_sendto needed for cancellation.
+#endif
+PSEUDO (__libc_sendto, sendto, 6)
+ret
+PSEUDO_END(__libc_sendto)
+libpthread_hidden_def (__libc_sendto)
+weak_alias (__libc_sendto, __sendto)
+libpthread_hidden_weak (__sendto)
+weak_alias (__libc_sendto, sendto)
+libpthread_hidden_weak (sendto)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-sigwait.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-sigwait.c
new file mode 100644 (file)
index 0000000..bde0a92
--- /dev/null
@@ -0,0 +1,2 @@
+#include <pthreadP.h>
+#include "../../../../../../libc/signal/sigwait.c"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-sleep.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-sleep.c
new file mode 100644 (file)
index 0000000..9e948ad
--- /dev/null
@@ -0,0 +1,2 @@
+#include <pthreadP.h>
+#include <../../../../../../libc/unistd/sleep.c>
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-tcdrain.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-tcdrain.c
new file mode 100644 (file)
index 0000000..07c1f82
--- /dev/null
@@ -0,0 +1 @@
+#include <../../../../../../libc/termios/tcdrain.c>
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-wait.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-wait.c
new file mode 100644 (file)
index 0000000..a05c3eb
--- /dev/null
@@ -0,0 +1,2 @@
+#include <pthreadP.h>
+#include <../../../../../../libc/sysdeps/linux/common/wait.c>
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-waitpid.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-waitpid.c
new file mode 100644 (file)
index 0000000..8461c3f
--- /dev/null
@@ -0,0 +1 @@
+#include <../../../../../../libc/sysdeps/linux/common/waitpid.c>
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-write.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-write.S
new file mode 100644 (file)
index 0000000..6bc6667
--- /dev/null
@@ -0,0 +1,9 @@
+#include <sysdep-cancel.h>
+PSEUDO (__libc_write, write, 3)
+ret
+PSEUDO_END (__libc_write)
+libpthread_hidden_def (__libc_write)
+weak_alias (__libc_write, __write)
+libpthread_hidden_weak (__write)
+weak_alias (__libc_write, write)
+libpthread_hidden_weak (write)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pthread-pi-defines.sym b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread-pi-defines.sym
new file mode 100644 (file)
index 0000000..46fbd0d
--- /dev/null
@@ -0,0 +1,8 @@
+#include <pthreadP.h>
+
+-- These PI macros are used by assembly code.
+
+MUTEX_KIND     offsetof (pthread_mutex_t, __data.__kind)
+ROBUST_BIT     PTHREAD_MUTEX_ROBUST_NORMAL_NP
+PI_BIT         PTHREAD_MUTEX_PRIO_INHERIT_NP
+PS_BIT         PTHREAD_MUTEX_PSHARED_BIT
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_attr_getaffinity.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_attr_getaffinity.c
new file mode 100644 (file)
index 0000000..2ec2f3d
--- /dev/null
@@ -0,0 +1,54 @@
+/* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <assert.h>
+#include <errno.h>
+#include <pthreadP.h>
+#include <string.h>
+#include <sysdep.h>
+#include <sys/types.h>
+
+
+int
+pthread_attr_getaffinity_np(const pthread_attr_t *attr, size_t cpusetsize,
+                               cpu_set_t *cpuset)
+{
+  const struct pthread_attr *iattr;
+
+  assert (sizeof (*attr) >= sizeof (struct pthread_attr));
+  iattr = (const struct pthread_attr *) attr;
+
+  if (iattr->cpuset != NULL)
+    {
+      /* Check whether there are any bits set beyond the limits
+        the user requested.  */
+      for (size_t cnt = cpusetsize; cnt < iattr->cpusetsize; ++cnt)
+       if (((char *) iattr->cpuset)[cnt] != 0)
+         return EINVAL;
+
+      void *p = mempcpy (cpuset, iattr->cpuset, iattr->cpusetsize);
+      if (cpusetsize > iattr->cpusetsize)
+       memset (p, '\0', cpusetsize - iattr->cpusetsize);
+    }
+  else
+    /* We have no information.  */
+    memset (cpuset, -1, cpusetsize);
+
+  return 0;
+}
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_attr_setaffinity.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_attr_setaffinity.c
new file mode 100644 (file)
index 0000000..609ee2a
--- /dev/null
@@ -0,0 +1,80 @@
+/* Copyright (C) 2003, 2004, 2006 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthreadP.h>
+
+
+/* Defined in pthread_setaffinity.c.  */
+extern size_t __kernel_cpumask_size attribute_hidden;
+extern int __determine_cpumask_size (pid_t tid);
+libpthread_hidden_proto(__determine_cpumask_size)
+
+int
+pthread_attr_setaffinity_np (pthread_attr_t *attr, size_t cpusetsize,
+                               const cpu_set_t *cpuset)
+{
+  struct pthread_attr *iattr;
+
+  assert (sizeof (*attr) >= sizeof (struct pthread_attr));
+  iattr = (struct pthread_attr *) attr;
+
+  if (cpuset == NULL || cpusetsize == 0)
+    {
+      free (iattr->cpuset);
+      iattr->cpuset = NULL;
+      iattr->cpusetsize = 0;
+    }
+  else
+    {
+      if (__kernel_cpumask_size == 0)
+       {
+         int res = __determine_cpumask_size (THREAD_SELF->tid);
+         if (res != 0)
+           /* Some serious problem.  */
+           return res;
+       }
+
+      /* Check whether the new bitmask has any bit set beyond the
+        last one the kernel accepts.  */
+      for (size_t cnt = __kernel_cpumask_size; cnt < cpusetsize; ++cnt)
+       if (((char *) cpuset)[cnt] != '\0')
+         /* Found a nonzero byte.  This means the user request cannot be
+            fulfilled.  */
+         return EINVAL;
+
+      if (iattr->cpusetsize != cpusetsize)
+       {
+         void *newp = (cpu_set_t *) realloc (iattr->cpuset, cpusetsize);
+         if (newp == NULL)
+           return ENOMEM;
+
+         iattr->cpuset = newp;
+         iattr->cpusetsize = cpusetsize;
+       }
+
+      memcpy (iattr->cpuset, cpuset, cpusetsize);
+    }
+
+  return 0;
+}
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_getaffinity.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_getaffinity.c
new file mode 100644 (file)
index 0000000..affcc6a
--- /dev/null
@@ -0,0 +1,46 @@
+/* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <limits.h>
+#include <pthreadP.h>
+#include <string.h>
+#include <sysdep.h>
+#include <sys/param.h>
+#include <sys/types.h>
+
+
+int
+__pthread_getaffinity_np (pthread_t th, size_t cpusetsize, cpu_set_t *cpuset)
+{
+  const struct pthread *pd = (const struct pthread *) th;
+
+  INTERNAL_SYSCALL_DECL (err);
+  int res = INTERNAL_SYSCALL (sched_getaffinity, err, 3, pd->tid,
+                             MIN (INT_MAX, cpusetsize), cpuset);
+  if (INTERNAL_SYSCALL_ERROR_P (res, err))
+    return INTERNAL_SYSCALL_ERRNO (res, err);
+
+  /* Clean the rest of the memory the kernel didn't do.  */
+  memset ((char *) cpuset + res, '\0', cpusetsize - res);
+
+  return 0;
+}
+strong_alias(__pthread_getaffinity_np, pthread_getaffinity_np)
+
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_getcpuclockid.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_getcpuclockid.c
new file mode 100644 (file)
index 0000000..9e28f69
--- /dev/null
@@ -0,0 +1,57 @@
+/* Copyright (C) 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <errno.h>
+#include <pthreadP.h>
+#include <sys/time.h>
+#include <tls.h>
+
+
+int
+pthread_getcpuclockid (
+     pthread_t threadid,
+     clockid_t *clockid)
+{
+  struct pthread *pd = (struct pthread *) threadid;
+
+  /* Make sure the descriptor is valid.  */
+  if (INVALID_TD_P (pd))
+    /* Not a valid thread handle.  */
+    return ESRCH;
+
+#ifdef CLOCK_THREAD_CPUTIME_ID
+  /* We need to store the thread ID in the CLOCKID variable together
+     with a number identifying the clock.  We reserve the low 3 bits
+     for the clock ID and the rest for the thread ID.  This is
+     problematic if the thread ID is too large.  But 29 bits should be
+     fine.
+
+     If some day more clock IDs are needed the ID part can be
+     enlarged.  The IDs are entirely internal.  */
+  if (pd->tid >= 1 << (8 * sizeof (*clockid) - CLOCK_IDFIELD_SIZE))
+    return ERANGE;
+
+  /* Store the number.  */
+  *clockid = CLOCK_THREAD_CPUTIME_ID | (pd->tid << CLOCK_IDFIELD_SIZE);
+
+  return 0;
+#else
+  /* We don't have a timer for that.  */
+  return ENOENT;
+#endif
+}
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_kill.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_kill.c
new file mode 100644 (file)
index 0000000..3a70c37
--- /dev/null
@@ -0,0 +1,78 @@
+/* Copyright (C) 2002, 2003, 2004, 2006 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>
+#include <bits/kernel-features.h>
+
+
+int
+__pthread_kill (
+     pthread_t threadid,
+     int signo)
+{
+  struct pthread *pd = (struct pthread *) threadid;
+
+  /* Make sure the descriptor is valid.  */
+  if (DEBUGGING_P && INVALID_TD_P (pd))
+    /* Not a valid thread handle.  */
+    return ESRCH;
+
+  /* Force load of pd->tid into local variable or register.  Otherwise
+     if a thread exits between ESRCH test and tgkill, we might return
+     EINVAL, because pd->tid would be cleared by the kernel.  */
+  pid_t tid = atomic_forced_read (pd->tid);
+  if (__builtin_expect (tid <= 0, 0))
+    /* Not a valid thread handle.  */
+    return ESRCH;
+
+  /* Disallow sending the signal we use for cancellation, timers, for
+     for the setxid implementation.  */
+  if (signo == SIGCANCEL || signo == SIGTIMER || signo == SIGSETXID)
+    return EINVAL;
+
+  /* We have a special syscall to do the work.  */
+  INTERNAL_SYSCALL_DECL (err);
+
+  /* One comment: The PID field in the TCB can temporarily be changed
+     (in fork).  But this must not affect this code here.  Since this
+     function would have to be called while the thread is executing
+     fork, it would have to happen in a signal handler.  But this is
+     no allowed, pthread_kill is not guaranteed to be async-safe.  */
+  int val;
+#if __ASSUME_TGKILL
+  val = INTERNAL_SYSCALL (tgkill, err, 3, THREAD_GETMEM (THREAD_SELF, pid),
+                         tid, signo);
+#else
+# ifdef __NR_tgkill
+  val = INTERNAL_SYSCALL (tgkill, err, 3, THREAD_GETMEM (THREAD_SELF, pid),
+                         tid, signo);
+  if (INTERNAL_SYSCALL_ERROR_P (val, err)
+      && INTERNAL_SYSCALL_ERRNO (val, err) == ENOSYS)
+# endif
+    val = INTERNAL_SYSCALL (tkill, err, 2, tid, signo);
+#endif
+
+  return (INTERNAL_SYSCALL_ERROR_P (val, err)
+         ? INTERNAL_SYSCALL_ERRNO (val, err) : 0);
+}
+strong_alias (__pthread_kill, pthread_kill)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_mutex_cond_lock.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_mutex_cond_lock.c
new file mode 100644 (file)
index 0000000..804bfab
--- /dev/null
@@ -0,0 +1,14 @@
+#include <pthreadP.h>
+
+#define LLL_MUTEX_LOCK(mutex) \
+  lll_cond_lock ((mutex)->__data.__lock, PTHREAD_MUTEX_PSHARED (mutex))
+#define LLL_MUTEX_TRYLOCK(mutex) \
+  lll_cond_trylock ((mutex)->__data.__lock)
+#define LLL_ROBUST_MUTEX_LOCK(mutex, id) \
+  lll_robust_cond_lock ((mutex)->__data.__lock, id, \
+                       PTHREAD_ROBUST_MUTEX_PSHARED (mutex))
+#define __pthread_mutex_lock __pthread_mutex_cond_lock
+#define __pthread_mutex_lock_full __pthread_mutex_cond_lock_full
+#define NO_INCR
+
+#include <pthread_mutex_lock.c>
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_setaffinity.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_setaffinity.c
new file mode 100644 (file)
index 0000000..467e8ec
--- /dev/null
@@ -0,0 +1,91 @@
+/* Copyright (C) 2003, 2004, 2006, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <alloca.h>
+#include <errno.h>
+#include <pthreadP.h>
+#include <sysdep.h>
+#include <sys/types.h>
+
+
+size_t __kernel_cpumask_size attribute_hidden;
+
+
+/* Determine the current affinity.  As a side affect we learn
+   about the size of the cpumask_t in the kernel.  */
+extern int __determine_cpumask_size (pid_t tid);
+libpthread_hidden_proto(__determine_cpumask_size)
+int __determine_cpumask_size (pid_t tid)
+{
+  INTERNAL_SYSCALL_DECL (err);
+  int res;
+
+  size_t psize = 128;
+  void *p = alloca (psize);
+
+  while (res = INTERNAL_SYSCALL (sched_getaffinity, err, 3, tid, psize, p),
+        INTERNAL_SYSCALL_ERROR_P (res, err)
+        && INTERNAL_SYSCALL_ERRNO (res, err) == EINVAL)
+    p = extend_alloca (p, psize, 2 * psize);
+
+  if (res == 0 || INTERNAL_SYSCALL_ERROR_P (res, err))
+    return INTERNAL_SYSCALL_ERRNO (res, err);
+
+  __kernel_cpumask_size = res;
+
+  return 0;
+}
+libpthread_hidden_def(__determine_cpumask_size)
+
+int
+pthread_setaffinity_np (pthread_t th, size_t cpusetsize,
+                          const cpu_set_t *cpuset)
+{
+  const struct pthread *pd = (const struct pthread *) th;
+
+  INTERNAL_SYSCALL_DECL (err);
+  int res;
+
+  if (__builtin_expect (__kernel_cpumask_size == 0, 0))
+    {
+      res = __determine_cpumask_size (pd->tid);
+      if (res != 0)
+       return res;
+    }
+
+  /* We now know the size of the kernel cpumask_t.  Make sure the user
+     does not request to set a bit beyond that.  */
+  for (size_t cnt = __kernel_cpumask_size; cnt < cpusetsize; ++cnt)
+    if (((char *) cpuset)[cnt] != '\0')
+      /* Found a nonzero byte.  This means the user request cannot be
+        fulfilled.  */
+      return EINVAL;
+
+  res = INTERNAL_SYSCALL (sched_setaffinity, err, 3, pd->tid, cpusetsize,
+                         cpuset);
+
+#ifdef RESET_VGETCPU_CACHE
+  if (!INTERNAL_SYSCALL_ERROR_P (res, err))
+    RESET_VGETCPU_CACHE ();
+#endif
+
+  return (INTERNAL_SYSCALL_ERROR_P (res, err)
+         ? INTERNAL_SYSCALL_ERRNO (res, err)
+         : 0);
+}
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_sigqueue.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_sigqueue.c
new file mode 100644 (file)
index 0000000..9e49085
--- /dev/null
@@ -0,0 +1,83 @@
+/* Copyright (C) 2009 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2009.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with 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 <string.h>
+#include <unistd.h>
+#include <pthreadP.h>
+#include <tls.h>
+#include <sysdep.h>
+#include <bits/kernel-features.h>
+
+
+int
+pthread_sigqueue (
+     pthread_t threadid,
+     int signo,
+     const union sigval value)
+{
+#ifdef __NR_rt_tgsigqueueinfo
+  struct pthread *pd = (struct pthread *) threadid;
+
+  /* Make sure the descriptor is valid.  */
+  if (DEBUGGING_P && INVALID_TD_P (pd))
+    /* Not a valid thread handle.  */
+    return ESRCH;
+
+  /* Force load of pd->tid into local variable or register.  Otherwise
+     if a thread exits between ESRCH test and tgkill, we might return
+     EINVAL, because pd->tid would be cleared by the kernel.  */
+  pid_t tid = atomic_forced_read (pd->tid);
+  if (__builtin_expect (tid <= 0, 0))
+    /* Not a valid thread handle.  */
+    return ESRCH;
+
+  /* Disallow sending the signal we use for cancellation, timers, for
+     for the setxid implementation.  */
+  if (signo == SIGCANCEL || signo == SIGTIMER || signo == SIGSETXID)
+    return EINVAL;
+
+  /* Set up the siginfo_t structure.  */
+  siginfo_t info;
+  memset (&info, '\0', sizeof (siginfo_t));
+  info.si_signo = signo;
+  info.si_code = SI_QUEUE;
+  info.si_pid = THREAD_GETMEM (THREAD_SELF, pid);
+  info.si_uid = getuid ();
+  info.si_value = value;
+
+  /* We have a special syscall to do the work.  */
+  INTERNAL_SYSCALL_DECL (err);
+
+  /* One comment: The PID field in the TCB can temporarily be changed
+     (in fork).  But this must not affect this code here.  Since this
+     function would have to be called while the thread is executing
+     fork, it would have to happen in a signal handler.  But this is
+     no allowed, pthread_sigqueue is not guaranteed to be async-safe.  */
+  int val = INTERNAL_SYSCALL (rt_tgsigqueueinfo, err, 4,
+                             THREAD_GETMEM (THREAD_SELF, pid),
+                             tid, signo, &info);
+
+  return (INTERNAL_SYSCALL_ERROR_P (val, err)
+         ? INTERNAL_SYSCALL_ERRNO (val, err) : 0);
+#else
+  return ENOSYS;
+#endif
+}
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_yield.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_yield.c
new file mode 100644 (file)
index 0000000..5aecffc
--- /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 <pthread.h>
+#include <sched.h>
+
+
+/* With the 1-on-1 model we implement this function is equivalent to
+   the 'sched_yield' function.  */
+int
+pthread_yield (void)
+{
+  return sched_yield ();
+}
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/raise.c b/libpthread/nptl/sysdeps/unix/sysv/linux/raise.c
new file mode 100644 (file)
index 0000000..da35cfe
--- /dev/null
@@ -0,0 +1,74 @@
+/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <sysdep.h>
+#include <pthreadP.h>
+#include <bits/kernel-features.h>
+
+
+int
+raise (
+     int sig)
+{
+  struct pthread *pd = THREAD_SELF;
+#if __ASSUME_TGKILL || defined __NR_tgkill
+  pid_t pid = THREAD_GETMEM (pd, pid);
+#endif
+  pid_t selftid = THREAD_GETMEM (pd, tid);
+  if (selftid == 0)
+    {
+      /* This system call is not supposed to fail.  */
+#ifdef INTERNAL_SYSCALL
+      INTERNAL_SYSCALL_DECL (err);
+      selftid = INTERNAL_SYSCALL (gettid, err, 0);
+#else
+      selftid = INLINE_SYSCALL (gettid, 0);
+#endif
+      THREAD_SETMEM (pd, tid, selftid);
+
+#if __ASSUME_TGKILL || defined __NR_tgkill
+      /* We do not set the PID field in the TID here since we might be
+        called from a signal handler while the thread executes fork.  */
+      pid = selftid;
+#endif
+    }
+#if __ASSUME_TGKILL || defined __NR_tgkill
+  else
+    /* raise is an async-safe function.  It could be called while the
+       fork/vfork function temporarily invalidated the PID field.  Adjust for
+       that.  */
+    if (__builtin_expect (pid <= 0, 0))
+      pid = (pid & INT_MAX) == 0 ? selftid : -pid;
+#endif
+
+#if __ASSUME_TGKILL
+  return INLINE_SYSCALL (tgkill, 3, pid, selftid, sig);
+#else
+# ifdef __NR_tgkill
+  int res = INLINE_SYSCALL (tgkill, 3, pid, selftid, sig);
+  if (res != -1 || errno != ENOSYS)
+    return res;
+# endif
+  return INLINE_SYSCALL (tkill, 2, selftid, sig);
+#endif
+}
+libc_hidden_def (raise)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/read.S b/libpthread/nptl/sysdeps/unix/sysv/linux/read.S
new file mode 100644 (file)
index 0000000..d3adfa8
--- /dev/null
@@ -0,0 +1,19 @@
+#include <sysdep-cancel.h>
+
+/*
+extern int __read_nocancel (int, void *, size_t) attribute_hidden;
+*/
+#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt
+
+PSEUDO (__libc_read, read, 3)
+ret
+PSEUDO_END(__libc_read)
+
+libc_hidden_def (__read_nocancel)
+libc_hidden_def (__libc_read)
+weak_alias (__libc_read, __read)
+libc_hidden_weak (__read)
+weak_alias (__libc_read, read)
+libc_hidden_weak (read)
+
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/recv.S b/libpthread/nptl/sysdeps/unix/sysv/linux/recv.S
new file mode 100644 (file)
index 0000000..95fa651
--- /dev/null
@@ -0,0 +1,12 @@
+#include <sysdep-cancel.h>
+#ifndef __NR_recv
+#error Missing definition of NR_recv needed for cancellation.
+#endif
+PSEUDO (__libc_recv, recv, 4)
+ret
+PSEUDO_END(__libc_recv)
+libc_hidden_def (__libc_recv)
+weak_alias (__libc_recv, __recv)
+libc_hidden_weak (__recv)
+weak_alias (__libc_recv, recv)
+libc_hidden_weak (recv)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/recvfrom.S b/libpthread/nptl/sysdeps/unix/sysv/linux/recvfrom.S
new file mode 100644 (file)
index 0000000..d9cc1e9
--- /dev/null
@@ -0,0 +1,12 @@
+#include <sysdep-cancel.h>
+#ifndef __NR_recvfrom
+#error Missing definition of NR_recvfrom needed for cancellation.
+#endif
+PSEUDO (__libc_recvfrom, recvfrom, 6)
+ret
+PSEUDO_END(__libc_recvfrom)
+libc_hidden_def (__libc_recvfrom)
+weak_alias (__libc_recvfrom, __recvfrom)
+libc_hidden_weak (__recvfrom)
+weak_alias (__libc_recvfrom, recvfrom)
+libc_hidden_weak (recvfrom)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/recvmsg.S b/libpthread/nptl/sysdeps/unix/sysv/linux/recvmsg.S
new file mode 100644 (file)
index 0000000..c761b90
--- /dev/null
@@ -0,0 +1,12 @@
+#include <sysdep-cancel.h>
+#ifndef __NR_recvmsg
+#error Missing definition of NR_recvmsg needed for cancellation.
+#endif
+PSEUDO (__libc_recvmsg, recvmsg, 3)
+ret
+PSEUDO_END(__libc_recvmsg)
+libc_hidden_def (__libc_recvmsg)
+weak_alias (__libc_recvmsg, __recvmsg)
+libc_hidden_weak (__recvmsg)
+weak_alias (__libc_recvmsg, recvmsg)
+libc_hidden_weak (recvmsg)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/register-atfork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/register-atfork.c
new file mode 100644 (file)
index 0000000..f956ad5
--- /dev/null
@@ -0,0 +1,149 @@
+/* Copyright (C) 2002, 2003, 2005, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fork.h>
+#include <atomic.h>
+#include <tls.h>
+
+
+/* Lock to protect allocation and deallocation of fork handlers.  */
+int __fork_lock = LLL_LOCK_INITIALIZER;
+
+
+/* Number of pre-allocated handler entries.  */
+#define NHANDLER 48
+
+/* Memory pool for fork handler structures.  */
+static struct fork_handler_pool
+{
+  struct fork_handler_pool *next;
+  struct fork_handler mem[NHANDLER];
+} fork_handler_pool;
+
+
+static struct fork_handler *
+fork_handler_alloc (void)
+{
+  struct fork_handler_pool *runp = &fork_handler_pool;
+  struct fork_handler *result = NULL;
+  unsigned int i;
+
+  do
+    {
+      /* Search for an empty entry.  */
+      for (i = 0; i < NHANDLER; ++i)
+       if (runp->mem[i].refcntr == 0)
+         goto found;
+    }
+  while ((runp = runp->next) != NULL);
+
+  /* We have to allocate a new entry.  */
+  runp = (struct fork_handler_pool *) calloc (1, sizeof (*runp));
+  if (runp != NULL)
+    {
+      /* Enqueue the new memory pool into the list.  */
+      runp->next = fork_handler_pool.next;
+      fork_handler_pool.next = runp;
+
+      /* We use the last entry on the page.  This means when we start
+        searching from the front the next time we will find the first
+        entry unused.  */
+      i = NHANDLER - 1;
+
+    found:
+      result = &runp->mem[i];
+      result->refcntr = 1;
+      result->need_signal = 0;
+    }
+
+  return result;
+}
+
+
+int
+__register_atfork (
+     void (*prepare) (void),
+     void (*parent) (void),
+     void (*child) (void),
+     void *dso_handle)
+{
+  /* Get the lock to not conflict with other allocations.  */
+  lll_lock (__fork_lock, LLL_PRIVATE);
+
+  struct fork_handler *newp = fork_handler_alloc ();
+
+  if (newp != NULL)
+    {
+      /* Initialize the new record.  */
+      newp->prepare_handler = prepare;
+      newp->parent_handler = parent;
+      newp->child_handler = child;
+      newp->dso_handle = dso_handle;
+
+      __linkin_atfork (newp);
+    }
+
+  /* Release the lock.  */
+  lll_unlock (__fork_lock, LLL_PRIVATE);
+
+  return newp == NULL ? ENOMEM : 0;
+}
+libc_hidden_def (__register_atfork)
+
+
+void
+attribute_hidden
+__linkin_atfork (struct fork_handler *newp)
+{
+  do
+    newp->next = __fork_handlers;
+  while (catomic_compare_and_exchange_bool_acq (&__fork_handlers,
+                                               newp, newp->next) != 0);
+}
+
+#if 0
+libc_freeres_fn (free_mem)
+{
+  /* Get the lock to not conflict with running forks.  */
+  lll_lock (__fork_lock, LLL_PRIVATE);
+
+  /* No more fork handlers.  */
+  __fork_handlers = NULL;
+
+  /* Free eventually alloated memory blocks for the object pool.  */
+  struct fork_handler_pool *runp = fork_handler_pool.next;
+
+  memset (&fork_handler_pool, '\0', sizeof (fork_handler_pool));
+
+  /* Release the lock.  */
+  lll_unlock (__fork_lock, LLL_PRIVATE);
+
+  /* We can free the memory after releasing the lock.  */
+  while (runp != NULL)
+    {
+      struct fork_handler_pool *oldp = runp;
+      runp = runp->next;
+      free (oldp);
+    }
+}
+#endif
+
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sem_post.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sem_post.c
new file mode 100644 (file)
index 0000000..edb97c4
--- /dev/null
@@ -0,0 +1,58 @@
+/* sem_post -- post to a POSIX semaphore.  Generic futex-using version.
+   Copyright (C) 2003, 2004, 2007, 2008 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <internaltypes.h>
+#include <semaphore.h>
+#include <tls.h>
+
+int
+__new_sem_post (sem_t *sem)
+{
+  struct new_sem *isem = (struct new_sem *) sem;
+
+  __typeof (isem->value) cur;
+  do
+    {
+      cur = isem->value;
+      if (isem->value == SEM_VALUE_MAX)
+       {
+         __set_errno (EOVERFLOW);
+         return -1;
+       }
+    }
+  while (atomic_compare_and_exchange_bool_acq (&isem->value, cur + 1, cur));
+
+  atomic_full_barrier ();
+  if (isem->nwaiters > 0)
+    {
+      int err = lll_futex_wake (&isem->value, 1,
+                               isem->private ^ FUTEX_PRIVATE_FLAG);
+      if (__builtin_expect (err, 0) < 0)
+       {
+         __set_errno (-err);
+         return -1;
+       }
+    }
+  return 0;
+}
+weak_alias(__new_sem_post, sem_post)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sem_timedwait.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sem_timedwait.c
new file mode 100644 (file)
index 0000000..3e5e6dc
--- /dev/null
@@ -0,0 +1,111 @@
+/* sem_timedwait -- wait on a semaphore.  Generic futex-using version.
+   Copyright (C) 2003, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <internaltypes.h>
+#include <semaphore.h>
+
+#include <pthreadP.h>
+
+
+extern void __sem_wait_cleanup (void *arg) attribute_hidden;
+
+
+int
+sem_timedwait (sem_t *sem, const struct timespec *abstime)
+{
+  struct new_sem *isem = (struct new_sem *) sem;
+  int err;
+
+  if (atomic_decrement_if_positive (&isem->value) > 0)
+    return 0;
+
+  if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)
+    {
+      __set_errno (EINVAL);
+      return -1;
+    }
+
+  atomic_increment (&isem->nwaiters);
+
+  pthread_cleanup_push (__sem_wait_cleanup, isem);
+
+  while (1)
+    {
+      struct timeval tv;
+      struct timespec rt;
+      int sec, nsec;
+
+      /* Get the current time.  */
+      __gettimeofday (&tv, NULL);
+
+      /* Compute relative timeout.  */
+      sec = abstime->tv_sec - tv.tv_sec;
+      nsec = abstime->tv_nsec - tv.tv_usec * 1000;
+      if (nsec < 0)
+       {
+         nsec += 1000000000;
+         --sec;
+       }
+
+      /* Already timed out?  */
+      err = -ETIMEDOUT;
+      if (sec < 0)
+       {
+         __set_errno (ETIMEDOUT);
+         err = -1;
+         break;
+       }
+
+      /* Do wait.  */
+      rt.tv_sec = sec;
+      rt.tv_nsec = nsec;
+
+      /* Enable asynchronous cancellation.  Required by the standard.  */
+      int oldtype = __pthread_enable_asynccancel ();
+
+      err = lll_futex_timed_wait (&isem->value, 0, &rt,
+                                 isem->private ^ FUTEX_PRIVATE_FLAG);
+
+      /* Disable asynchronous cancellation.  */
+      __pthread_disable_asynccancel (oldtype);
+
+      if (err != 0 && err != -EWOULDBLOCK)
+       {
+         __set_errno (-err);
+         err = -1;
+         break;
+       }
+
+      if (atomic_decrement_if_positive (&isem->value) > 0)
+       {
+         err = 0;
+         break;
+       }
+    }
+
+  pthread_cleanup_pop (0);
+
+  atomic_decrement (&isem->nwaiters);
+
+  return err;
+}
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sem_trywait.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sem_trywait.c
new file mode 100644 (file)
index 0000000..3cf1d9a
--- /dev/null
@@ -0,0 +1,44 @@
+/* sem_trywait -- wait on a semaphore.  Generic futex-using version.
+   Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <internaltypes.h>
+#include <semaphore.h>
+
+
+int
+__new_sem_trywait (sem_t *sem)
+{
+  int *futex = (int *) sem;
+  int val;
+
+  if (*futex > 0)
+    {
+      val = atomic_decrement_if_positive (futex);
+      if (val > 0)
+       return 0;
+    }
+
+  __set_errno (EAGAIN);
+  return -1;
+}
+weak_alias(__new_sem_trywait, sem_trywait)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sem_wait.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sem_wait.c
new file mode 100644 (file)
index 0000000..e661e09
--- /dev/null
@@ -0,0 +1,84 @@
+/* sem_wait -- wait on a semaphore.  Generic futex-using version.
+   Copyright (C) 2003, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <internaltypes.h>
+#include <semaphore.h>
+
+#include <pthreadP.h>
+
+
+void
+attribute_hidden
+__sem_wait_cleanup (void *arg)
+{
+  struct new_sem *isem = (struct new_sem *) arg;
+
+  atomic_decrement (&isem->nwaiters);
+}
+
+
+int
+__new_sem_wait (sem_t *sem)
+{
+  struct new_sem *isem = (struct new_sem *) sem;
+  int err;
+
+  if (atomic_decrement_if_positive (&isem->value) > 0)
+    return 0;
+
+  atomic_increment (&isem->nwaiters);
+
+  pthread_cleanup_push (__sem_wait_cleanup, isem);
+
+  while (1)
+    {
+      /* Enable asynchronous cancellation.  Required by the standard.  */
+      int oldtype = __pthread_enable_asynccancel ();
+
+      err = lll_futex_wait (&isem->value, 0,
+                           isem->private ^ FUTEX_PRIVATE_FLAG);
+
+      /* Disable asynchronous cancellation.  */
+      __pthread_disable_asynccancel (oldtype);
+
+      if (err != 0 && err != -EWOULDBLOCK)
+       {
+         __set_errno (-err);
+         err = -1;
+         break;
+       }
+
+      if (atomic_decrement_if_positive (&isem->value) > 0)
+       {
+         err = 0;
+         break;
+       }
+    }
+
+  pthread_cleanup_pop (0);
+
+  atomic_decrement (&isem->nwaiters);
+
+  return err;
+}
+weak_alias(__new_sem_wait, sem_wait)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/send.S b/libpthread/nptl/sysdeps/unix/sysv/linux/send.S
new file mode 100644 (file)
index 0000000..eb744c7
--- /dev/null
@@ -0,0 +1,12 @@
+#include <sysdep-cancel.h>
+#ifndef __NR_send
+#error Missing definition of NR_send needed for cancellation.
+#endif
+PSEUDO (__libc_send, send, 4)
+ret
+PSEUDO_END (__libc_send)
+libc_hidden_def (__libc_send)
+weak_alias (__libc_send, __send)
+libc_hidden_weak (__send)
+weak_alias (__libc_send, send)
+libc_hidden_weak (send)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sendmsg.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sendmsg.S
new file mode 100644 (file)
index 0000000..4c41e01
--- /dev/null
@@ -0,0 +1,12 @@
+#include <sysdep-cancel.h>
+#ifndef __NR_sendmsg
+#error Missing definition of NR_sendmsg needed for cancellation.
+#endif
+PSEUDO (__libc_sendmsg, sendmsg, 3)
+ret
+PSEUDO_END(__libc_sendmsg)
+libc_hidden_def (__libc_sendmsg)
+weak_alias (__libc_sendmsg, __sendmsg)
+libc_hidden_weak (__sendmsg)
+weak_alias (__libc_sendmsg, sendmsg)
+libc_hidden_weak (sendmsg)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sendto.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sendto.S
new file mode 100644 (file)
index 0000000..7cb5278
--- /dev/null
@@ -0,0 +1,12 @@
+#include <sysdep-cancel.h>
+#ifndef __NR_sendto
+#error Missing definition of NR_sendto needed for cancellation.
+#endif
+PSEUDO (__libc_sendto, sendto, 6)
+ret
+PSEUDO_END(__libc_sendto)
+libc_hidden_def (__libc_sendto)
+weak_alias (__libc_sendto, __sendto)
+libc_hidden_weak (__sendto)
+weak_alias (__libc_sendto, sendto)
+libc_hidden_weak (sendto)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/Makefile b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/Makefile
new file mode 100644 (file)
index 0000000..43a6fad
--- /dev/null
@@ -0,0 +1,13 @@
+# Makefile for uClibc NPTL
+#
+# Copyright (C) 2005 Steven J. Hill <sjhill@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+top_srcdir=../../../../../../../
+top_builddir=../../../../../../../
+all: objs
+include $(top_builddir)Rules.mak
+include Makefile.arch
+include $(top_srcdir)Makerules
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/Makefile.arch b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/Makefile.arch
new file mode 100644 (file)
index 0000000..940bd62
--- /dev/null
@@ -0,0 +1,85 @@
+# Makefile for uClibc NPTL
+#
+# Copyright (C) 2006 Steven J. Hill <sjhill@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+libpthread_SSRC = pt-vfork.S pthread_once.S pthread_rwlock_wrlock.S \
+                       pthread_rwlock_rdlock.S pthread_rwlock_unlock.S \
+                       lowlevellock.S lowlevelrobustlock.S pthread_barrier_wait.S \
+                       pthread_cond_broadcast.S pthread_cond_signal.S \
+                       pthread_rwlock_timedwrlock.S pthread_rwlock_timedrdlock.S \
+                       sem_post.S sem_timedwait.S sem_trywait.S sem_wait.S
+
+libc_a_CSRC = fork.c
+libc_a_SSRC = libc-lowlevellock.S clone.S vfork.S
+
+ifeq ($(UCLIBC_HAS_STDIO_FUTEXES),y)
+CFLAGS-fork.c = -D__USE_STDIO_FUTEXES__
+endif
+
+ASFLAGS-pt-vfork.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 -D_LIBC_REENTRANT -DUSE___THREAD
+ASFLAGS-pthread_once.S = -D_LIBC_REENTRANT -DUSE___THREAD
+ASFLAGS-pthread_rwlock_wrlock.S = -D_LIBC_REENTRANT -DUSE___THREAD
+ASFLAGS-pthread_rwlock_rdlock.S = -D_LIBC_REENTRANT -DUSE___THREAD
+ASFLAGS-pthread_rwlock_unlock.S = -D_LIBC_REENTRANT -DUSE___THREAD
+ASFLAGS-pthread_rwlock_unlock.S = -D_LIBC_REENTRANT -DUSE___THREAD
+
+ASFLAGS-pthread_barrier_wait.S = -D_LIBC_REENTRANT -DUSE___THREAD
+ASFLAGS-pthread_cond_broadcast.S = -D_LIBC_REENTRANT -DUSE___THREAD
+ASFLAGS-pthread_cond_signal.S = -D_LIBC_REENTRANT -DUSE___THREAD
+ASFLAGS-pthread_cond_wait.S = -D_LIBC_REENTRANT -DUSE___THREAD
+ASFLAGS-pthread_cond_timedwait.S = -D_LIBC_REENTRANT -DUSE___THREAD
+
+ASFLAGS-pthread_rwlock_timedwrlock.S = -D_LIBC_REENTRANT -DUSE___THREAD
+ASFLAGS-pthread_rwlock_timedrdlock.S = -D_LIBC_REENTRANT -DUSE___THREAD
+
+ASFLAGS-sem_post.S = -D_LIBC_REENTRANT -DUSE___THREAD
+ASFLAGS-sem_timedwait.S = -D_LIBC_REENTRANT -DUSE___THREAD
+ASFLAGS-sem_trywait.S = -D_LIBC_REENTRANT -DUSE___THREAD
+ASFLAGS-sem_wait.S = -D_LIBC_REENTRANT -DUSE___THREAD
+
+ASFLAGS-libc-lowlevellock.S = -D_LIBC_REENTRANT  -DUSE___THREAD
+
+ASFLAGS-lowlevellock.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 -D_LIBC_REENTRANT -DUSE___THREAD
+ASFLAGS-lowlevelrobustlock.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 -D_LIBC_REENTRANT -DUSE___THREAD
+
+ASFLAGS-clone.S = -D_LIBC_REENTRANT
+ASFLAGS-vfork.S = -D_LIBC_REENTRANT
+
+ifeq ($(UCLIBC_HAS_THREADS_NATIVE),y)
+#Needed to use the correct SYSCALL_ERROR_HANDLER
+ASFLAGS-clone.S += -DUSE___THREAD
+ASFLAGS-vfork.S += -DUSE___THREAD
+endif
+
+CFLAGS += $(SSP_ALL_CFLAGS)
+#CFLAGS:=$(CFLAGS:-O1=-O2)
+
+LINUX_ARCH_DIR:=$(top_srcdir)libpthread/nptl/sysdeps/unix/sysv/linux/sh
+LINUX_ARCH_OUT:=$(top_builddir)libpthread/nptl/sysdeps/unix/sysv/linux/sh
+
+LINUX_ARCH_OBJ:=$(patsubst %.S,$(LINUX_ARCH_OUT)/%.o,$(libpthread_SSRC))
+
+ifeq ($(DOPIC),y)
+libpthread-a-y += $(LINUX_ARCH_OBJ:.o=.os)
+else
+libpthread-a-y += $(LINUX_ARCH_OBJ)
+endif
+libpthread-so-y += $(LINUX_ARCH_OBJ:.o=.oS)
+
+libpthread-nomulti-y+=$(LINUX_ARCH_OBJS)
+
+LIBC_LINUX_ARCH_OBJ:=$(patsubst %.c,$(LINUX_ARCH_OUT)/%.o,$(libc_a_CSRC))
+LIBC_LINUX_ARCH_OBJ+=$(patsubst %.S,$(LINUX_ARCH_OUT)/%.o,$(libc_a_SSRC))
+
+libc-static-y+=$(LIBC_LINUX_ARCH_OBJ)
+libc-shared-y+=$(LIBC_LINUX_ARCH_OBJ:.o=.oS)
+
+libc-nomulti-y+=$(LIBC_LINUX_ARCH_OBJ)
+
+objclean-y+=nptl_linux_arch_clean
+
+nptl_linux_arch_clean:
+       $(do_rm) $(addprefix $(LINUX_ARCH_OUT)/*., o os oS)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h
new file mode 100644 (file)
index 0000000..badcda5
--- /dev/null
@@ -0,0 +1,183 @@
+/* Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007
+   Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _BITS_PTHREADTYPES_H
+#define _BITS_PTHREADTYPES_H   1
+
+#include <endian.h>
+
+#define __SIZEOF_PTHREAD_ATTR_T 36
+#define __SIZEOF_PTHREAD_MUTEX_T 24
+#define __SIZEOF_PTHREAD_MUTEXATTR_T 4
+#define __SIZEOF_PTHREAD_COND_T 48
+#define __SIZEOF_PTHREAD_COND_COMPAT_T 12
+#define __SIZEOF_PTHREAD_CONDATTR_T 4
+#define __SIZEOF_PTHREAD_RWLOCK_T 32
+#define __SIZEOF_PTHREAD_RWLOCKATTR_T 8
+#define __SIZEOF_PTHREAD_BARRIER_T 20
+#define __SIZEOF_PTHREAD_BARRIERATTR_T 4
+
+
+/* Thread identifiers.  The structure of the attribute type is not
+   exposed on purpose.  */
+typedef unsigned long int pthread_t;
+
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_ATTR_T];
+  long int __align;
+} pthread_attr_t;
+
+
+typedef struct __pthread_internal_slist
+{
+  struct __pthread_internal_slist *__next;
+} __pthread_slist_t;
+
+
+/* Data structures for mutex handling.  The structure of the attribute
+   type is not exposed on purpose.  */
+typedef union
+{
+  struct __pthread_mutex_s
+  {
+    int __lock;
+    unsigned int __count;
+    int __owner;
+    /* KIND must stay at this position in the structure to maintain
+       binary compatibility.  */
+    int __kind;
+    unsigned int __nusers;
+    __extension__ union
+    {
+      int __spins;
+      __pthread_slist_t __list;
+    };
+  } __data;
+  char __size[__SIZEOF_PTHREAD_MUTEX_T];
+  long int __align;
+} pthread_mutex_t;
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_MUTEXATTR_T];
+  long int __align;
+} pthread_mutexattr_t;
+
+
+/* Data structure for conditional variable handling.  The structure of
+   the attribute type is not exposed on purpose.  */
+typedef union
+{
+  struct
+  {
+    int __lock;
+    unsigned int __futex;
+    __extension__ unsigned long long int __total_seq;
+    __extension__ unsigned long long int __wakeup_seq;
+    __extension__ unsigned long long int __woken_seq;
+    void *__mutex;
+    unsigned int __nwaiters;
+    unsigned int __broadcast_seq;
+  } __data;
+  char __size[__SIZEOF_PTHREAD_COND_T];
+  __extension__ long long int __align;
+} pthread_cond_t;
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_CONDATTR_T];
+  long int __align;
+} pthread_condattr_t;
+
+
+/* Keys for thread-specific data */
+typedef unsigned int pthread_key_t;
+
+
+/* Once-only execution */
+typedef int pthread_once_t;
+
+
+#if defined __USE_UNIX98 || defined __USE_XOPEN2K
+/* Data structure for read-write lock variable handling.  The
+   structure of the attribute type is not exposed on purpose.  */
+typedef union
+{
+  struct
+  {
+    int __lock;
+    unsigned int __nr_readers;
+    unsigned int __readers_wakeup;
+    unsigned int __writer_wakeup;
+    unsigned int __nr_readers_queued;
+    unsigned int __nr_writers_queued;
+#if __BYTE_ORDER == __BIG_ENDIAN
+    unsigned char __pad1;
+    unsigned char __pad2;
+    unsigned char __shared;
+    /* FLAGS must stay at this position in the structure to maintain
+       binary compatibility.  */
+    unsigned char __flags;
+#else
+    /* FLAGS must stay at this position in the structure to maintain
+       binary compatibility.  */
+    unsigned char __flags;
+    unsigned char __shared;
+    unsigned char __pad1;
+    unsigned char __pad2;
+#endif
+    pthread_t __writer;
+  } __data;
+  char __size[__SIZEOF_PTHREAD_RWLOCK_T];
+  long int __align;
+} pthread_rwlock_t;
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_RWLOCKATTR_T];
+  long int __align;
+} pthread_rwlockattr_t;
+#endif
+
+
+#ifdef __USE_XOPEN2K
+/* POSIX spinlock data type.  */
+typedef volatile int pthread_spinlock_t;
+
+
+/* POSIX barriers data type.  The structure of the type is
+   deliberately not exposed.  */
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_BARRIER_T];
+  long int __align;
+} pthread_barrier_t;
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_BARRIERATTR_T];
+  int __align;
+} pthread_barrierattr_t;
+#endif
+
+
+#endif /* bits/pthreadtypes.h */
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/bits/semaphore.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/bits/semaphore.h
new file mode 100644 (file)
index 0000000..934493c
--- /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 _SEMAPHORE_H
+# error "Never use <bits/semaphore.h> directly; include <semaphore.h> instead."
+#endif
+
+
+#define __SIZEOF_SEM_T 16
+
+
+/* Value returned if `sem_open' failed.  */
+#define SEM_FAILED      ((sem_t *) 0)
+
+
+typedef union
+{
+  char __size[__SIZEOF_SEM_T];
+  long int __align;
+} sem_t;
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/clone.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/clone.S
new file mode 100644 (file)
index 0000000..918d579
--- /dev/null
@@ -0,0 +1,2 @@
+#define RESET_PID
+#include <libc/sysdeps/linux/sh/clone.S>
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/createthread.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/createthread.c
new file mode 100644 (file)
index 0000000..e17c017
--- /dev/null
@@ -0,0 +1,24 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* Value passed to 'clone' for initialization of the thread register.  */
+#define TLS_VALUE (pd + 1)
+
+
+/* Get the real implementation.  */
+#include <sysdeps/pthread/createthread.c>
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/fork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/fork.c
new file mode 100644 (file)
index 0000000..6868b9b
--- /dev/null
@@ -0,0 +1,30 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sched.h>
+#include <signal.h>
+#include <sysdep.h>
+#include <tls.h>
+
+/* TLS pointer argument is passed as the 5-th argument.  */
+#define ARCH_FORK() \
+  INLINE_SYSCALL (clone, 5,                                                  \
+                 CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD, 0,     \
+                 NULL, &THREAD_SELF->tid, NULL)
+
+#include "../fork.c"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/libc-lowlevellock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/libc-lowlevellock.S
new file mode 100644 (file)
index 0000000..feb8211
--- /dev/null
@@ -0,0 +1,19 @@
+/* Copyright (C) 2003, 2007 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 "lowlevellock.S"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/lowlevel-atomic.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/lowlevel-atomic.h
new file mode 100644 (file)
index 0000000..c702836
--- /dev/null
@@ -0,0 +1,81 @@
+/* Copyright (C) 2003, 2004, 2008 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.  */
+
+#ifdef __ASSEMBLER__
+
+#define _IMP1 #1
+#define _IMM1 #-1
+#define _IMM4 #-4
+#define _IMM6 #-6
+#define _IMM8 #-8
+
+#define        INC(mem, reg) \
+       .align  2; \
+       mova    99f, r0; \
+       mov     r15, r1; \
+       mov     _IMM6, r15; \
+98:    mov.l   mem, reg; \
+       add     _IMP1, reg; \
+       mov.l   reg, mem; \
+99:    mov     r1, r15
+
+#define        DEC(mem, reg) \
+       .align  2; \
+       mova    99f, r0; \
+       mov     r15, r1; \
+       mov     _IMM6, r15; \
+98:    mov.l   mem, reg; \
+       add     _IMM1, reg; \
+       mov.l   reg, mem; \
+99:    mov     r1, r15
+
+#define        XADD(reg, mem, old, tmp) \
+       .align  2; \
+       mova    99f, r0; \
+       nop; \
+       mov     r15, r1; \
+       mov     _IMM8, r15; \
+98:    mov.l   mem, old; \
+       mov     reg, tmp; \
+       add     old, tmp; \
+       mov.l   tmp, mem; \
+99:    mov     r1, r15
+
+#define        XCHG(reg, mem, old) \
+       .align  2; \
+       mova    99f, r0; \
+       nop; \
+       mov     r15, r1; \
+       mov     _IMM4, r15; \
+98:    mov.l   mem, old; \
+       mov.l   reg, mem; \
+99:    mov     r1, r15
+
+#define        CMPXCHG(reg, mem, new, old) \
+       .align  2; \
+       mova    99f, r0; \
+       nop; \
+       mov     r15, r1; \
+       mov     _IMM8, r15; \
+98:    mov.l   mem, old; \
+       cmp/eq  old, reg; \
+       bf      99f; \
+       mov.l   new, mem; \
+99:    mov     r1, r15
+
+#endif  /* __ASSEMBLER__ */
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/lowlevellock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/lowlevellock.S
new file mode 100644 (file)
index 0000000..00edc75
--- /dev/null
@@ -0,0 +1,540 @@
+/* Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009
+   Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <pthread-errnos.h>
+#include <bits/kernel-features.h>
+#include <lowlevellock.h>
+#include <tcb-offsets.h>
+#include "lowlevel-atomic.h"
+
+       .text
+
+#ifdef __ASSUME_PRIVATE_FUTEX
+# define LOAD_PRIVATE_FUTEX_WAIT(reg,tmp,tmp2) \
+       mov     #(FUTEX_WAIT | FUTEX_PRIVATE_FLAG), reg; \
+       extu.b  reg, reg
+# define LOAD_PRIVATE_FUTEX_WAKE(reg,tmp,tmp2) \
+       mov     #(FUTEX_WAKE | FUTEX_PRIVATE_FLAG), reg; \
+       extu.b  reg, reg
+# define LOAD_FUTEX_WAIT(reg,tmp,tmp2) \
+       mov     #(FUTEX_WAIT | FUTEX_PRIVATE_FLAG), tmp; \
+       extu.b  tmp, tmp; \
+       xor     tmp, reg
+# define LOAD_FUTEX_WAIT_ABS(reg,tmp,tmp2) \
+       mov     #(FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG), tmp; \
+       extu.b  tmp, tmp; \
+       mov     #(FUTEX_CLOCK_REALTIME >> 8), tmp2; \
+       swap.b  tmp2, tmp2; \
+       or      tmp2, tmp; \
+       xor     tmp, reg
+# define LOAD_FUTEX_WAKE(reg,tmp,tmp2) \
+       mov     #(FUTEX_WAKE | FUTEX_PRIVATE_FLAG), tmp; \
+       extu.b  tmp, tmp; \
+       xor     tmp, reg
+#else
+# if FUTEX_WAIT == 0
+#  define LOAD_PRIVATE_FUTEX_WAIT(reg,tmp,tmp2) \
+       stc     gbr, tmp        ; \
+       mov.w   99f, reg        ; \
+       add     reg, tmp        ; \
+       bra     98f             ; \
+        mov.l  @tmp, reg       ; \
+99:    .word   PRIVATE_FUTEX - TLS_PRE_TCB_SIZE ; \
+98:
+# else
+#  define LOAD_PRIVATE_FUTEX_WAIT(reg,tmp,tmp2) \
+       stc     gbr, tmp        ; \
+       mov.w   99f, reg        ; \
+       add     reg, tmp        ; \
+       mov.l   @tmp, reg       ; \
+       bra     98f             ; \
+        mov    #FUTEX_WAIT, tmp ; \
+99:    .word   PRIVATE_FUTEX - TLS_PRE_TCB_SIZE ; \
+98:    or      tmp, reg
+# endif
+# define LOAD_PRIVATE_FUTEX_WAKE(reg,tmp,tmp2) \
+       stc     gbr, tmp        ; \
+       mov.w   99f, reg        ; \
+       add     reg, tmp        ; \
+       mov.l   @tmp, reg       ; \
+       bra     98f             ; \
+        mov    #FUTEX_WAKE, tmp ; \
+99:    .word   PRIVATE_FUTEX - TLS_PRE_TCB_SIZE ; \
+98:    or      tmp, reg
+# if FUTEX_WAIT == 0
+#  define LOAD_FUTEX_WAIT(reg,tmp,tmp2) \
+       stc     gbr, tmp        ; \
+       mov.w   99f, tmp2       ; \
+       add     tmp2, tmp       ; \
+       mov.l   @tmp, tmp2      ; \
+       bra     98f             ; \
+        mov    #FUTEX_PRIVATE_FLAG, tmp ; \
+99:    .word   PRIVATE_FUTEX - TLS_PRE_TCB_SIZE ; \
+98:    extu.b  tmp, tmp        ; \
+       xor     tmp, reg        ; \
+       and     tmp2, reg
+# else
+#  define LOAD_FUTEX_WAIT(reg,tmp,tmp2) \
+       stc     gbr, tmp        ; \
+       mov.w   99f, tmp2       ; \
+       add     tmp2, tmp       ; \
+       mov.l   @tmp, tmp2      ; \
+       bra     98f             ; \
+        mov    #FUTEX_PRIVATE_FLAG, tmp ; \
+99:    .word   PRIVATE_FUTEX - TLS_PRE_TCB_SIZE ; \
+98:    extu.b  tmp, tmp        ; \
+       xor     tmp, reg        ; \
+       and     tmp2, reg       ; \
+       mov     #FUTEX_WAIT, tmp ; \
+       or      tmp, reg
+# endif
+# define LOAD_FUTEX_WAIT_ABS(reg,tmp,tmp2) \
+       stc     gbr, tmp        ; \
+       mov.w   99f, tmp2       ; \
+       add     tmp2, tmp       ; \
+       mov.l   @tmp, tmp2      ; \
+       bra     98f             ; \
+        mov    #FUTEX_PRIVATE_FLAG, tmp ; \
+99:    .word   PRIVATE_FUTEX - TLS_PRE_TCB_SIZE ; \
+98:    extu.b  tmp, tmp        ; \
+       xor     tmp, reg        ; \
+       and     tmp2, reg       ; \
+       mov     #FUTEX_WAIT_BITSET, tmp ; \
+       mov     #(FUTEX_CLOCK_REALTIME >> 8), tmp2; \
+       swap.b  tmp2, tmp2; \
+       or      tmp2, tmp; \
+       or      tmp, reg
+# define LOAD_FUTEX_WAKE(reg,tmp,tmp2) \
+       stc     gbr, tmp        ; \
+       mov.w   99f, tmp2       ; \
+       add     tmp2, tmp       ; \
+       mov.l   @tmp, tmp2      ; \
+       bra     98f             ; \
+        mov    #FUTEX_PRIVATE_FLAG, tmp ; \
+99:    .word   PRIVATE_FUTEX - TLS_PRE_TCB_SIZE ; \
+98:    extu.b  tmp, tmp        ; \
+       xor     tmp, reg        ; \
+       and     tmp2, reg       ; \
+       mov     #FUTEX_WAKE, tmp ; \
+       or      tmp, reg
+#endif
+
+       .globl  __lll_lock_wait_private
+       .type   __lll_lock_wait_private,@function
+       .hidden __lll_lock_wait_private
+       .align  5
+       cfi_startproc
+__lll_lock_wait_private:
+       mov.l   r8, @-r15
+       cfi_adjust_cfa_offset(4)
+       cfi_rel_offset (r8, 0)
+       mov     r4, r6
+       mov     r5, r8
+       mov     #0, r7          /* No timeout.  */
+       LOAD_PRIVATE_FUTEX_WAIT (r5, r0, r1)
+
+       mov     #2, r4
+       cmp/eq  r4, r6
+       bf      2f
+
+1:
+       mov     r8, r4
+       mov     #SYS_futex, r3
+       extu.b  r3, r3
+       trapa   #0x14
+       SYSCALL_INST_PAD
+
+2:
+       mov     #2, r6
+       XCHG (r6, @r8, r2)
+       tst     r2, r2
+       bf      1b
+
+       mov.l   @r15+, r8
+       rts
+        mov    r2, r0
+       cfi_endproc
+       .size   __lll_lock_wait_private,.-__lll_lock_wait_private
+
+#ifdef NOT_IN_libc
+       .globl  __lll_lock_wait
+       .type   __lll_lock_wait,@function
+       .hidden __lll_lock_wait
+       .align  5
+       cfi_startproc
+__lll_lock_wait:
+       mov.l   r9, @-r15
+       cfi_adjust_cfa_offset(4)
+       cfi_rel_offset (r9, 0)
+       mov.l   r8, @-r15
+       cfi_adjust_cfa_offset(4)
+       cfi_rel_offset (r8, 0)
+       mov     r6, r9
+       mov     r4, r6
+       mov     r5, r8
+       mov     #0, r7          /* No timeout.  */
+       mov     r9, r5
+       LOAD_FUTEX_WAIT (r5, r0, r1)
+
+       mov     #2, r4
+       cmp/eq  r4, r6
+       bf      2f
+
+1:
+       mov     r8, r4
+       mov     #SYS_futex, r3
+       extu.b  r3, r3
+       trapa   #0x14
+       SYSCALL_INST_PAD
+
+2:
+       mov     #2, r6
+       XCHG (r6, @r8, r2)
+       tst     r2, r2
+       bf      1b
+
+       mov.l   @r15+, r8
+       mov.l   @r15+, r9
+       ret
+        mov    r2, r0
+       cfi_endproc
+       .size   __lll_lock_wait,.-__lll_lock_wait
+
+       /*      r5  (r8): futex
+               r7 (r11): flags
+               r6  (r9): timeout
+               r4 (r10): futex value
+       */
+       .globl  __lll_timedlock_wait
+       .type   __lll_timedlock_wait,@function
+       .hidden __lll_timedlock_wait
+       .align  5
+       cfi_startproc
+__lll_timedlock_wait:
+       mov.l   r12, @-r15
+       cfi_adjust_cfa_offset(4)
+       cfi_rel_offset (r12, 0)
+
+# ifndef __ASSUME_FUTEX_CLOCK_REALTIME
+       mov.l   .Lhave, r1
+#  ifdef __PIC__
+       mova    .Lgot, r0
+       mov.l   .Lgot, r12
+       add     r0, r12
+       add     r12, r1
+#  endif
+       mov.l   @r1, r0
+       tst     r0, r0
+       bt      .Lreltmo
+# endif
+
+       mov     r4, r2
+       mov     r5, r4
+       mov     r7, r5
+       mov     r6, r7
+       LOAD_FUTEX_WAIT_ABS (r5, r0, r1)
+
+       mov     #2, r6
+       cmp/eq  r6, r2
+       bf/s    2f
+        mov    r6, r2
+
+1:
+       mov     #2, r6
+       mov     #-1, r1
+       mov     #SYS_futex, r3
+       extu.b  r3, r3
+       trapa   #0x16
+       SYSCALL_INST_PAD
+       mov     r0, r6
+
+2:
+       XCHG    (r2, @r4, r3)   /* NB:   lock is implied */
+
+       tst     r3, r3
+       bt/s    3f
+        mov    r6, r0
+
+       cmp/eq  #-ETIMEDOUT, r0
+       bt      4f
+       cmp/eq  #-EINVAL, r0
+       bf      1b
+4:
+       neg     r0, r3
+3:
+       mov     r3, r0
+       rts
+        mov.l  @r15+, r12
+
+       .align  2
+# ifndef __ASSUME_FUTEX_CLOCK_REALTIME
+# ifdef __PIC__
+.Lgot:
+       .long   _GLOBAL_OFFSET_TABLE_
+.Lhave:
+       .long   __have_futex_clock_realtime@GOTOFF
+# else
+.Lhave:
+       .long   __have_futex_clock_realtime
+# endif
+
+.Lreltmo:
+       /* Check for a valid timeout value.  */
+       mov.l   @(4,r6), r1
+       mov.l   .L1g, r0
+       cmp/hs  r0, r1
+       bt      3f
+
+       mov.l   r11, @-r15
+       cfi_adjust_cfa_offset(4)
+       cfi_rel_offset (r11, 0)
+       mov.l   r10, @-r15
+       cfi_adjust_cfa_offset(4)
+       cfi_rel_offset (r10, 0)
+       mov.l   r9, @-r15
+       cfi_adjust_cfa_offset(4)
+       cfi_rel_offset (r9, 0)
+       mov.l   r8, @-r15
+       cfi_adjust_cfa_offset(4)
+       cfi_rel_offset (r8, 0)
+       mov     r7, r11
+       mov     r4, r10
+       mov     r6, r9
+       mov     r5, r8
+
+       /* Stack frame for the timespec and timeval structs.  */
+       add     #-8, r15
+       cfi_adjust_cfa_offset(8)
+
+       mov     #2, r2
+       XCHG (r2, @r8, r3)
+
+       tst     r3, r3
+       bt      6f
+
+1:
+       /* Get current time.  */
+       mov     r15, r4
+       mov     #0, r5
+       mov     #__NR_gettimeofday, r3
+       trapa   #0x12
+       SYSCALL_INST_PAD
+
+       /* Compute relative timeout.  */
+       mov.l   @(4,r15), r0
+       mov.w   .L1k, r1
+       dmulu.l r0, r1          /* Micro seconds to nano seconds.  */
+       mov.l   @r9, r2
+       mov.l   @(4,r9), r3
+       mov.l   @r15, r0
+       sts     macl, r1
+       sub     r0, r2
+       clrt
+       subc    r1, r3
+       bf      4f
+       mov.l   .L1g, r1
+       add     r1, r3
+       add     #-1, r2
+4:
+       cmp/pz  r2
+       bf      2f              /* Time is already up.  */
+
+       mov.l   r2, @r15        /* Store relative timeout.  */
+       mov.l   r3, @(4,r15)
+
+       mov     r8, r4
+       mov     r11, r5
+       LOAD_FUTEX_WAIT (r5, r0, r1)
+       mov     r10, r6
+       mov     r15, r7
+       mov     #SYS_futex, r3
+       extu.b  r3, r3
+       trapa   #0x14
+       SYSCALL_INST_PAD
+       mov     r0, r5
+
+       mov     #2, r2
+       XCHG (r2, @r8, r3)
+
+       tst     r3, r3
+       bt/s    6f
+        mov    #-ETIMEDOUT, r1
+       cmp/eq  r5, r1
+       bf      1b
+
+2:     mov     #ETIMEDOUT, r3
+
+6:
+       mov     r3, r0
+       add     #8, r15
+       mov.l   @r15+, r8
+       mov.l   @r15+, r9
+       mov.l   @r15+, r10
+       mov.l   @r15+, r11
+       rts
+        mov.l  @r15+, r12
+
+3:
+       mov.l   @r15+, r12
+       rts
+        mov    #EINVAL, r0
+# endif
+       cfi_endproc
+
+.L1k:
+       .word   1000
+       .align  2
+.L1g:
+       .long   1000000000
+
+       .size   __lll_timedlock_wait,.-__lll_timedlock_wait
+#endif
+
+       .globl  __lll_unlock_wake_private
+       .type   __lll_unlock_wake_private,@function
+       .hidden __lll_unlock_wake_private
+       .align  5
+       cfi_startproc
+__lll_unlock_wake_private:
+       LOAD_PRIVATE_FUTEX_WAKE (r5, r0, r1)
+       mov     #1, r6          /* Wake one thread.  */
+       mov     #0, r7
+       mov.l   r7, @r4         /* Stores 0.  */
+       mov     #SYS_futex, r3
+       extu.b  r3, r3
+       trapa   #0x14
+       SYSCALL_INST_PAD
+       rts
+        nop
+       cfi_endproc
+       .size   __lll_unlock_wake_private,.-__lll_unlock_wake_private
+
+#ifdef NOT_IN_libc
+       .globl  __lll_unlock_wake
+       .type   __lll_unlock_wake,@function
+       .hidden __lll_unlock_wake
+       .align  5
+       cfi_startproc
+__lll_unlock_wake:
+       LOAD_FUTEX_WAKE (r5, r0, r1)
+       mov     #1, r6          /* Wake one thread.  */
+       mov     #0, r7
+       mov.l   r7, @r4         /* Stores 0.  */
+       mov     #SYS_futex, r3
+       extu.b  r3, r3
+       trapa   #0x14
+       SYSCALL_INST_PAD
+       rts
+        nop
+       cfi_endproc
+       .size   __lll_unlock_wake,.-__lll_unlock_wake
+
+       .globl  __lll_timedwait_tid
+       .type   __lll_timedwait_tid,@function
+       .hidden __lll_timedwait_tid
+       .align  5
+       cfi_startproc
+__lll_timedwait_tid:
+       mov.l   r9, @-r15
+       cfi_adjust_cfa_offset(4)
+       cfi_rel_offset (r9, 0)
+       mov.l   r8, @-r15
+       cfi_adjust_cfa_offset(4)
+       cfi_rel_offset (r8, 0)
+       mov     r4, r8
+       mov     r5, r9
+
+       /* Stack frame for the timespec and timeval structs.  */
+       add     #-8, r15
+       cfi_adjust_cfa_offset(8)
+
+2:
+       /* Get current time.  */
+       mov     r15, r4
+       mov     #0, r5
+       mov     #__NR_gettimeofday, r3
+       trapa   #0x12
+       SYSCALL_INST_PAD
+
+       /* Compute relative timeout.  */
+       mov.l   @(4,r15), r0
+       mov.w   .L1k2, r1
+       dmulu.l r0, r1          /* Micro seconds to nano seconds.  */
+       mov.l   @r9, r2
+       mov.l   @(4,r9), r3
+       mov.l   @r15, r0
+       sts     macl, r1
+       sub     r0, r2
+       clrt
+       subc    r1, r3
+       bf      5f
+       mov.l   .L1g2, r1
+       add     r1, r3
+       add     #-1, r2
+5:
+       cmp/pz  r2
+       bf      6f              /* Time is already up.  */
+
+       mov.l   r2, @r15        /* Store relative timeout.  */
+       mov.l   r3, @(4,r15)
+
+       mov.l   @r8, r2
+       tst     r2, r2
+       bt      4f
+
+       mov     r8, r4
+       /* XXX The kernel so far uses global futex for the wakeup at
+          all times.  */
+       mov     #0, r5
+       extu.b  r5, r5
+       mov     r2, r6
+       mov     r15, r7
+       mov     #SYS_futex, r3
+       extu.b  r3, r3
+       trapa   #0x14
+       SYSCALL_INST_PAD
+
+       mov.l   @r8, r2
+       tst     r2, r2
+       bf      1f
+4:
+       mov     #0, r0
+3:
+       add     #8, r15
+       mov.l   @r15+, r8
+       rts
+        mov.l  @r15+, r9
+1:
+       /* Check whether the time expired.  */
+       mov     #-ETIMEDOUT, r1
+       cmp/eq  r0, r1
+       bf      2b
+6:
+       bra     3b
+        mov    #ETIMEDOUT, r0
+       cfi_endproc
+
+.L1k2:
+       .word   1000
+       .align  2
+.L1g2:
+       .long   1000000000
+       .size   __lll_timedwait_tid,.-__lll_timedwait_tid
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/lowlevellock.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/lowlevellock.h
new file mode 100644 (file)
index 0000000..19ce7fe
--- /dev/null
@@ -0,0 +1,420 @@
+/* Copyright (C) 2003, 2004, 2006, 2007, 2008, 2009
+   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 _LOWLEVELLOCK_H
+#define _LOWLEVELLOCK_H        1
+
+#ifndef __ASSEMBLER__
+#include <time.h>
+#include <sys/param.h>
+#include <bits/pthreadtypes.h>
+#include <bits/kernel-features.h>
+#endif
+
+#define FUTEX_WAIT             0
+#define FUTEX_WAKE             1
+#define FUTEX_CMP_REQUEUE      4
+#define FUTEX_WAKE_OP          5
+#define FUTEX_LOCK_PI          6
+#define FUTEX_UNLOCK_PI                7
+#define FUTEX_TRYLOCK_PI       8
+#define FUTEX_WAIT_BITSET      9
+#define FUTEX_WAKE_BITSET      10
+#define FUTEX_PRIVATE_FLAG     128
+#define FUTEX_CLOCK_REALTIME   256
+
+#define FUTEX_BITSET_MATCH_ANY 0xffffffff
+
+#define FUTEX_OP_CLEAR_WAKE_IF_GT_ONE  ((4 << 24) | 1)
+
+/* Values for 'private' parameter of locking macros.  Yes, the
+   definition seems to be backwards.  But it is not.  The bit will be
+   reversed before passing to the system call.  */
+#define LLL_PRIVATE    0
+#define LLL_SHARED     FUTEX_PRIVATE_FLAG
+
+
+#if !defined NOT_IN_libc || defined IS_IN_rtld
+/* In libc.so or ld.so all futexes are private.  */
+# ifdef __ASSUME_PRIVATE_FUTEX
+#  define __lll_private_flag(fl, private) \
+  ((fl) | FUTEX_PRIVATE_FLAG)
+# else
+#  define __lll_private_flag(fl, private) \
+  ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex))
+# endif
+#else
+# ifdef __ASSUME_PRIVATE_FUTEX
+#  define __lll_private_flag(fl, private) \
+  (((fl) | FUTEX_PRIVATE_FLAG) ^ (private))
+# else
+#  define __lll_private_flag(fl, private) \
+  (__builtin_constant_p (private)                                            \
+   ? ((private) == 0                                                         \
+      ? ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex))           \
+      : (fl))                                                                \
+   : ((fl) | (((private) ^ FUTEX_PRIVATE_FLAG)                               \
+             & THREAD_GETMEM (THREAD_SELF, header.private_futex))))
+# endif
+#endif
+
+#ifndef __ASSEMBLER__
+
+/* Initializer for compatibility lock.  */
+#define LLL_LOCK_INITIALIZER           (0)
+#define LLL_LOCK_INITIALIZER_LOCKED    (1)
+#define LLL_LOCK_INITIALIZER_WAITERS   (2)
+
+extern int __lll_lock_wait_private (int val, int *__futex)
+  attribute_hidden;
+extern int __lll_lock_wait (int val, int *__futex, int private)
+  attribute_hidden;
+extern int __lll_timedlock_wait (int val, int *__futex,
+                                const struct timespec *abstime, int private)
+  attribute_hidden;
+extern int __lll_robust_lock_wait (int val, int *__futex, int private)
+  attribute_hidden;
+extern int __lll_robust_timedlock_wait (int val, int *__futex,
+                                       const struct timespec *abstime,
+                                       int private)
+  attribute_hidden;
+extern int __lll_unlock_wake_private (int *__futex) attribute_hidden;
+extern int __lll_unlock_wake (int *__futex, int private) attribute_hidden;
+
+#define lll_trylock(futex) \
+  ({ unsigned char __result; \
+     __asm __volatile ("\
+       .align 2\n\
+       mova 1f,r0\n\
+       nop\n\
+       mov r15,r1\n\
+       mov #-8,r15\n\
+     0: mov.l @%1,r2\n\
+       cmp/eq r2,%3\n\
+       bf 1f\n\
+       mov.l %2,@%1\n\
+     1: mov r1,r15\n\
+       mov #-1,%0\n\
+       negc %0,%0"\
+       : "=r" (__result) \
+       : "r" (&(futex)), \
+         "r" (LLL_LOCK_INITIALIZER_LOCKED), \
+         "r" (LLL_LOCK_INITIALIZER) \
+       : "r0", "r1", "r2", "t", "memory"); \
+     __result; })
+
+#define lll_robust_trylock(futex, id)  \
+  ({ unsigned char __result; \
+     __asm __volatile ("\
+       .align 2\n\
+       mova 1f,r0\n\
+       nop\n\
+       mov r15,r1\n\
+       mov #-8,r15\n\
+     0: mov.l @%1,r2\n\
+       cmp/eq r2,%3\n\
+       bf 1f\n\
+       mov.l %2,@%1\n\
+     1: mov r1,r15\n\
+       mov #-1,%0\n\
+       negc %0,%0"\
+       : "=r" (__result) \
+       : "r" (&(futex)), \
+         "r" (id), \
+         "r" (LLL_LOCK_INITIALIZER) \
+       : "r0", "r1", "r2", "t", "memory"); \
+     __result; })
+
+#define lll_cond_trylock(futex) \
+  ({ unsigned char __result; \
+     __asm __volatile ("\
+       .align 2\n\
+       mova 1f,r0\n\
+       nop\n\
+       mov r15,r1\n\
+       mov #-8,r15\n\
+     0: mov.l @%1,r2\n\
+       cmp/eq r2,%3\n\
+       bf 1f\n\
+       mov.l %2,@%1\n\
+     1: mov r1,r15\n\
+       mov #-1,%0\n\
+       negc %0,%0"\
+       : "=r" (__result) \
+       : "r" (&(futex)), \
+         "r" (LLL_LOCK_INITIALIZER_WAITERS), \
+         "r" (LLL_LOCK_INITIALIZER) \
+       : "r0", "r1", "r2", "t", "memory"); \
+     __result; })
+
+#define lll_lock(futex, private) \
+  (void) ({ int __result, *__futex = &(futex); \
+           __asm __volatile ("\
+               .align 2\n\
+               mova 1f,r0\n\
+               nop\n\
+               mov r15,r1\n\
+               mov #-8,r15\n\
+            0: mov.l @%2,%0\n\
+               tst %0,%0\n\
+               bf 1f\n\
+               mov.l %1,@%2\n\
+            1: mov r1,r15"\
+               : "=&r" (__result) : "r" (1), "r" (__futex) \
+               : "r0", "r1", "t", "memory"); \
+           if (__result) \
+             { \
+               if (__builtin_constant_p (private) \
+                   && (private) == LLL_PRIVATE) \
+                 __lll_lock_wait_private (__result, __futex); \
+               else \
+                 __lll_lock_wait (__result, __futex, (private));       \
+             } \
+    })
+
+#define lll_robust_lock(futex, id, private) \
+  ({ int __result, *__futex = &(futex); \
+     __asm __volatile ("\
+       .align 2\n\
+       mova 1f,r0\n\
+       nop\n\
+       mov r15,r1\n\
+       mov #-8,r15\n\
+      0: mov.l @%2,%0\n\
+       tst %0,%0\n\
+       bf 1f\n\
+       mov.l %1,@%2\n\
+      1: mov r1,r15"\
+       : "=&r" (__result) : "r" (id), "r" (__futex) \
+       : "r0", "r1", "t", "memory"); \
+     if (__result) \
+       __result = __lll_robust_lock_wait (__result, __futex, private); \
+     __result; })
+
+/* Special version of lll_mutex_lock which causes the unlock function to
+   always wakeup waiters.  */
+#define lll_cond_lock(futex, private) \
+  (void) ({ int __result, *__futex = &(futex); \
+           __asm __volatile ("\
+               .align 2\n\
+               mova 1f,r0\n\
+               nop\n\
+               mov r15,r1\n\
+               mov #-8,r15\n\
+            0: mov.l @%2,%0\n\
+               tst %0,%0\n\
+               bf 1f\n\
+               mov.l %1,@%2\n\
+            1: mov r1,r15"\
+               : "=&r" (__result) : "r" (2), "r" (__futex) \
+               : "r0", "r1", "t", "memory"); \
+           if (__result) \
+             __lll_lock_wait (__result, __futex, private); })
+
+#define lll_robust_cond_lock(futex, id, private) \
+  ({ int __result, *__futex = &(futex); \
+     __asm __volatile ("\
+       .align 2\n\
+       mova 1f,r0\n\
+       nop\n\
+       mov r15,r1\n\
+       mov #-8,r15\n\
+     0: mov.l @%2,%0\n\
+       tst %0,%0\n\
+       bf 1f\n\
+       mov.l %1,@%2\n\
+     1: mov r1,r15"\
+       : "=&r" (__result) : "r" (id | FUTEX_WAITERS), "r" (__futex) \
+       : "r0", "r1", "t", "memory"); \
+      if (__result) \
+       __result = __lll_robust_lock_wait (__result, __futex, private); \
+      __result; })
+
+#define lll_timedlock(futex, timeout, private) \
+  ({ int __result, *__futex = &(futex); \
+     __asm __volatile ("\
+       .align 2\n\
+       mova 1f,r0\n\
+       nop\n\
+       mov r15,r1\n\
+       mov #-8,r15\n\
+     0: mov.l @%2,%0\n\
+       tst %0,%0\n\
+       bf 1f\n\
+       mov.l %1,@%2\n\
+     1: mov r1,r15"\
+       : "=&r" (__result) : "r" (1), "r" (__futex) \
+       : "r0", "r1", "t", "memory"); \
+    if (__result) \
+      __result = __lll_timedlock_wait (__result, __futex, timeout, private); \
+    __result; })
+
+#define lll_robust_timedlock(futex, timeout, id, private) \
+  ({ int __result, *__futex = &(futex); \
+     __asm __volatile ("\
+       .align 2\n\
+       mova 1f,r0\n\
+       nop\n\
+       mov r15,r1\n\
+       mov #-8,r15\n\
+     0: mov.l @%2,%0\n\
+       tst %0,%0\n\
+       bf 1f\n\
+       mov.l %1,@%2\n\
+     1: mov r1,r15"\
+       : "=&r" (__result) : "r" (id), "r" (__futex) \
+       : "r0", "r1", "t", "memory"); \
+    if (__result) \
+      __result = __lll_robust_timedlock_wait (__result, __futex, \
+                                             timeout, private); \
+    __result; })
+
+#define lll_unlock(futex, private) \
+  (void) ({ int __result, *__futex = &(futex); \
+           __asm __volatile ("\
+               .align 2\n\
+               mova 1f,r0\n\
+               mov r15,r1\n\
+               mov #-6,r15\n\
+            0: mov.l @%1,%0\n\
+               add #-1,%0\n\
+               mov.l %0,@%1\n\
+            1: mov r1,r15"\
+               : "=&r" (__result) : "r" (__futex) \
+               : "r0", "r1", "memory"); \
+           if (__result) \
+             { \
+               if (__builtin_constant_p (private) \
+                   && (private) == LLL_PRIVATE) \
+                 __lll_unlock_wake_private (__futex); \
+               else \
+                 __lll_unlock_wake (__futex, (private)); \
+             } \
+    })
+
+#define lll_robust_unlock(futex, private) \
+  (void) ({ int __result, *__futex = &(futex); \
+           __asm __volatile ("\
+               .align 2\n\
+               mova 1f,r0\n\
+               mov r15,r1\n\
+               mov #-6,r15\n\
+            0: mov.l @%1,%0\n\
+               and %2,%0\n\
+               mov.l %0,@%1\n\
+            1: mov r1,r15"\
+               : "=&r" (__result) : "r" (__futex), "r" (FUTEX_WAITERS) \
+               : "r0", "r1", "memory");        \
+           if (__result) \
+             __lll_unlock_wake (__futex, private); })
+
+#define lll_robust_dead(futex, private)                       \
+  (void) ({ int __ignore, *__futex = &(futex); \
+           __asm __volatile ("\
+               .align 2\n\
+               mova 1f,r0\n\
+               mov r15,r1\n\
+               mov #-6,r15\n\
+            0: mov.l @%1,%0\n\
+               or %2,%0\n\
+               mov.l %0,@%1\n\
+            1: mov r1,r15"\
+               : "=&r" (__ignore) : "r" (__futex), "r" (FUTEX_OWNER_DIED) \
+               : "r0", "r1", "memory");        \
+           lll_futex_wake (__futex, 1, private); })
+
+# ifdef NEED_SYSCALL_INST_PAD
+#  define SYSCALL_WITH_INST_PAD "\
+       trapa #0x14; or r0,r0; or r0,r0; or r0,r0; or r0,r0; or r0,r0"
+# else
+#  define SYSCALL_WITH_INST_PAD "\
+       trapa #0x14"
+# endif
+
+#define lll_futex_wait(futex, val, private) \
+  lll_futex_timed_wait (futex, val, NULL, private)
+
+
+#define lll_futex_timed_wait(futex, val, timeout, private) \
+  ({                                                                         \
+    int __status;                                                            \
+    register unsigned long __r3 __asm ("r3") = SYS_futex;                            \
+    register unsigned long __r4 __asm ("r4") = (unsigned long) (futex);              \
+    register unsigned long __r5 __asm ("r5")                                 \
+      = __lll_private_flag (FUTEX_WAIT, private);                            \
+    register unsigned long __r6 __asm ("r6") = (unsigned long) (val);        \
+    register unsigned long __r7 __asm ("r7") = (timeout);                            \
+    __asm __volatile (SYSCALL_WITH_INST_PAD                                  \
+                     : "=z" (__status)                                       \
+                     : "r" (__r3), "r" (__r4), "r" (__r5),                   \
+                       "r" (__r6), "r" (__r7)                                \
+                     : "memory", "t");                                       \
+    __status;                                                                \
+  })
+
+
+#define lll_futex_wake(futex, nr, private) \
+  do {                                                                       \
+    int __ignore;                                                            \
+    register unsigned long __r3 __asm ("r3") = SYS_futex;                            \
+    register unsigned long __r4 __asm ("r4") = (unsigned long) (futex);              \
+    register unsigned long __r5 __asm ("r5")                                 \
+      = __lll_private_flag (FUTEX_WAKE, private);                            \
+    register unsigned long __r6 __asm ("r6") = (unsigned long) (nr);         \
+    register unsigned long __r7 __asm ("r7") = 0;                                    \
+    __asm __volatile (SYSCALL_WITH_INST_PAD                                  \
+                     : "=z" (__ignore)                                       \
+                     : "r" (__r3), "r" (__r4), "r" (__r5),                   \
+                       "r" (__r6), "r" (__r7)                                \
+                     : "memory", "t");                                       \
+  } while (0)
+
+
+#define lll_islocked(futex) \
+  (futex != LLL_LOCK_INITIALIZER)
+
+/* The kernel notifies a process with uses CLONE_CLEARTID via futex
+   wakeup when the clone terminates.  The memory location contains the
+   thread ID while the clone is running and is reset to zero
+   afterwards.  */
+
+#define lll_wait_tid(tid) \
+  do {                                                                       \
+    __typeof (tid) *__tid = &(tid);                                          \
+    while (*__tid != 0)                                                              \
+      lll_futex_wait (__tid, *__tid, LLL_SHARED);                            \
+  } while (0)
+
+extern int __lll_timedwait_tid (int *tid, const struct timespec *abstime)
+     attribute_hidden;
+#define lll_timedwait_tid(tid, abstime) \
+  ({                                                                         \
+    int __result = 0;                                                        \
+    if (tid != 0)                                                            \
+      {                                                                              \
+       if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)           \
+         __result = EINVAL;                                                  \
+       else                                                                  \
+         __result = __lll_timedwait_tid (&tid, abstime);                     \
+      }                                                                              \
+    __result; })
+
+#endif  /* !__ASSEMBLER__ */
+
+#endif  /* lowlevellock.h */
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/lowlevelrobustlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/lowlevelrobustlock.S
new file mode 100644 (file)
index 0000000..1e05a56
--- /dev/null
@@ -0,0 +1,265 @@
+/* Copyright (C) 2003, 2004, 2005, 2006, 2007
+   Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <pthread-errnos.h>
+#include <lowlevellock.h>
+#include <lowlevelrobustlock.h>
+#include <bits/kernel-features.h>
+#include <tcb-offsets.h>
+#include "lowlevel-atomic.h"
+
+       .text
+
+#define FUTEX_WAITERS          0x80000000
+#define FUTEX_OWNER_DIED       0x40000000
+
+#ifdef __ASSUME_PRIVATE_FUTEX
+# define LOAD_FUTEX_WAIT(reg,tmp,tmp2) \
+       mov     #(FUTEX_WAIT | FUTEX_PRIVATE_FLAG), tmp; \
+       extu.b  tmp, tmp; \
+       xor     tmp, reg
+#else
+# if FUTEX_WAIT == 0
+#  define LOAD_FUTEX_WAIT(reg,tmp,tmp2) \
+       stc     gbr, tmp        ; \
+       mov.w   99f, tmp2       ; \
+       add     tmp2, tmp       ; \
+       mov.l   @tmp, tmp2      ; \
+       bra     98f             ; \
+        mov    #FUTEX_PRIVATE_FLAG, tmp ; \
+99:    .word   PRIVATE_FUTEX - TLS_PRE_TCB_SIZE ; \
+98:    extu.b  tmp, tmp        ; \
+       xor     tmp, reg        ; \
+       and     tmp2, reg
+# else
+#  define LOAD_FUTEX_WAIT(reg,tmp,tmp2) \
+       stc     gbr, tmp        ; \
+       mov.w   99f, tmp2       ; \
+       add     tmp2, tmp       ; \
+       mov.l   @tmp, tmp2      ; \
+       bra     98f             ; \
+        mov    #FUTEX_PRIVATE_FLAG, tmp ; \
+99:    .word   PRIVATE_FUTEX - TLS_PRE_TCB_SIZE ; \
+98:    extu.b  tmp, tmp        ; \
+       xor     tmp, reg        ; \
+       and     tmp2, reg       ; \
+       mov     #FUTEX_WAIT, tmp ; \
+       or      tmp, reg
+# endif
+#endif
+
+       .globl  __lll_robust_lock_wait
+       .type   __lll_robust_lock_wait,@function
+       .hidden __lll_robust_lock_wait
+       .align  5
+       cfi_startproc
+__lll_robust_lock_wait:
+       mov.l   r8, @-r15
+       cfi_adjust_cfa_offset(4)
+       cfi_rel_offset (r8, 0)
+       mov     r5, r8
+       mov     #0, r7          /* No timeout.  */
+       mov     r6, r5
+       LOAD_FUTEX_WAIT (r5, r0, r1)
+
+4:
+       mov     r4, r6
+       mov.l   .L_FUTEX_WAITERS, r0
+       or      r0, r6
+       shlr    r0              /* r0 = FUTEX_OWNER_DIED */
+       tst     r0, r4
+       bf/s    3f
+        cmp/eq r4, r6
+       bt      1f
+
+       CMPXCHG (r4, @r8, r6, r2)
+       bf      2f
+
+1:
+       mov     r8, r4
+       mov     #SYS_futex, r3
+       extu.b  r3, r3
+       trapa   #0x14
+       SYSCALL_INST_PAD
+
+       mov.l   @r8, r2
+
+2:
+       tst     r2, r2
+       bf/s    4b
+        mov    r2, r4
+
+       stc     gbr, r1
+       mov.w   .Ltidoff, r2
+       add     r2, r1
+       mov.l   @r1, r6
+       mov     #0, r3
+       CMPXCHG (r3, @r8, r6, r4)
+       bf      4b
+       mov     #0, r4
+
+3:
+       mov.l   @r15+, r8
+       ret
+        mov    r4, r0
+       cfi_endproc
+       .align  2
+.L_FUTEX_WAITERS:
+       .long   FUTEX_WAITERS
+.Ltidoff:
+       .word   TID - TLS_PRE_TCB_SIZE
+       .size   __lll_robust_lock_wait,.-__lll_robust_lock_wait
+
+
+       .globl  __lll_robust_timedlock_wait
+       .type   __lll_robust_timedlock_wait,@function
+       .hidden __lll_robust_timedlock_wait
+       .align  5
+       cfi_startproc
+__lll_robust_timedlock_wait:
+       /* Check for a valid timeout value.  */
+       mov.l   @(4,r6), r1
+       mov.l   .L1g, r0
+       cmp/hs  r0, r1
+       bt      3f
+
+       mov.l   r11, @-r15
+       cfi_adjust_cfa_offset(4)
+       cfi_rel_offset (r11, 0)
+       mov.l   r10, @-r15
+       cfi_adjust_cfa_offset(4)
+       cfi_rel_offset (r10, 0)
+       mov.l   r9, @-r15
+       cfi_adjust_cfa_offset(4)
+       cfi_rel_offset (r9, 0)
+       mov.l   r8, @-r15
+       cfi_adjust_cfa_offset(4)
+       cfi_rel_offset (r8, 0)
+       mov     r7, r11
+       mov     r4, r10
+       mov     r6, r9
+       mov     r5, r8
+
+       /* Stack frame for the timespec and timeval structs.  */
+       add     #-8, r15
+       cfi_adjust_cfa_offset(8)
+
+1:
+       /* Get current time.  */
+       mov     r15, r4
+       mov     #0, r5
+       mov     #__NR_gettimeofday, r3
+       trapa   #0x12
+       SYSCALL_INST_PAD
+
+       /* Compute relative timeout.  */
+       mov.l   @(4,r15), r0
+       mov.w   .L1k, r1
+       dmulu.l r0, r1          /* Micro seconds to nano seconds.  */
+       mov.l   @r9, r2
+       mov.l   @(4,r9), r3
+       mov.l   @r15, r0
+       sts     macl, r1
+       sub     r0, r2
+       clrt
+       subc    r1, r3
+       bf      4f
+       mov.l   .L1g, r1
+       add     r1, r3
+       add     #-1, r2
+4:
+       cmp/pz  r2
+       bf      8f              /* Time is already up.  */
+
+       mov.l   r2, @r15        /* Store relative timeout.  */
+       mov.l   r3, @(4,r15)
+
+       mov     r10, r6
+       mov.l   .L_FUTEX_WAITERS2, r0
+       or      r0, r6
+       shlr    r0              /* r0 = FUTEX_OWNER_DIED */
+       tst     r0, r4
+       bf/s    6f
+        cmp/eq r4, r6
+       bt      2f
+
+       CMPXCHG (r4, @r8, r6, r2)
+       bf/s    5f
+        mov    #0, r5
+
+2:
+       mov     r8, r4
+       mov     r11, r5
+       LOAD_FUTEX_WAIT (r5, r0, r1)
+       mov     r10, r6
+       mov     r15, r7
+       mov     #SYS_futex, r3
+       extu.b  r3, r3
+       trapa   #0x14
+       SYSCALL_INST_PAD
+       mov     r0, r5
+
+       mov.l   @r8, r2
+
+5:
+       tst     r2, r2
+       bf/s    7f
+        mov    r2, r10
+
+       stc     gbr, r1
+       mov.w   .Ltidoff2, r2
+       add     r2, r1
+       mov.l   @r1, r4
+       mov     #0, r3
+       CMPXCHG (r3, @r8, r4, r10)
+       bf      7f
+       mov     #0, r0
+
+6:
+       add     #8, r15
+       mov.l   @r15+, r8
+       mov.l   @r15+, r9
+       mov.l   @r15+, r10
+       rts
+        mov.l  @r15+, r11
+
+7:
+       /* Check whether the time expired.  */
+       mov     #-ETIMEDOUT, r1
+       cmp/eq  r5, r1
+       bf      1b
+
+8:
+       bra     6b
+        mov    #ETIMEDOUT, r0
+3:
+       rts
+        mov    #EINVAL, r0
+       cfi_endproc
+       .align  2
+.L_FUTEX_WAITERS2:
+       .long   FUTEX_WAITERS
+.L1g:
+       .long   1000000000
+.Ltidoff2:
+       .word   TID - TLS_PRE_TCB_SIZE
+.L1k:
+       .word   1000
+       .size   __lll_robust_timedlock_wait,.-__lll_robust_timedlock_wait
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pt-initfini.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pt-initfini.c
new file mode 100644 (file)
index 0000000..82c97c3
--- /dev/null
@@ -0,0 +1,126 @@
+/* Special .init and .fini section support for SH.  NPTL version.
+   Copyright (C) 2003, 2009 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it
+   and/or modify it under the terms of the GNU Library General Public
+   License as published by the Free Software Foundation; either
+   version 2 of the License, or (at your option) any later version.
+
+   In addition to the permissions in the GNU Library General Public
+   License, the Free Software Foundation gives you unlimited
+   permission to link the compiled version of this file with other
+   programs, and to distribute those programs without any restriction
+   coming from the use of this file.  (The Library General Public
+   License restrictions do apply in other respects; for example, they
+   cover modification of the file, and distribution when not linked
+   into another program.)
+
+   The GNU C Library is distributed in the hope that it will be
+   useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+   of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+/* This file is compiled into assembly code which is then munged by a sed
+   script into two files: crti.s and crtn.s.
+
+   * crti.s puts a function prologue at the beginning of the
+   .init and .fini sections and defines global symbols for
+   those addresses, so they can be called as functions.
+
+   * crtn.s puts the corresponding function epilogues
+   in the .init and .fini sections. */
+
+__asm__ ("\n\
+\n\
+#include \"defs.h\"\n\
+\n\
+/*@HEADER_ENDS*/\n\
+\n\
+/*@TESTS_BEGIN*/\n\
+\n\
+/*@TESTS_END*/\n\
+\n\
+/*@_init_PROLOG_BEGINS*/\n\
+       .section .init\n\
+       .align 5\n\
+       .global _init\n\
+       .type   _init,@function\n\
+_init:\n\
+       mov.l   r12,@-r15\n\
+       mov.l   r14,@-r15\n\
+       sts.l   pr,@-r15\n\
+       mova    .L22,r0\n\
+       mov.l   .L22,r12\n\
+       add     r0,r12\n\
+       mova    .L24,r0\n\
+       mov.l   .L24,r1\n\
+       add     r0,r1\n\
+       jsr     @r1\n\
+        mov    r15,r14\n\
+       bra     1f\n\
+        nop\n\
+       .align 2\n\
+.L22:\n\
+       .long   _GLOBAL_OFFSET_TABLE_\n\
+.L24:\n\
+       .long   __pthread_initialize_minimal_internal@PLT\n\
+1:\n\
+       ALIGN\n\
+       END_INIT\n\
+\n\
+/*@_init_PROLOG_ENDS*/\n\
+\n\
+/*@_init_EPILOG_BEGINS*/\n\
+       .section .init\n\
+       mov     r14,r15\n\
+       lds.l   @r15+,pr\n\
+       mov.l   @r15+,r14\n\
+       rts     \n\
+       mov.l   @r15+,r12\n\
+       END_INIT\n\
+       \n\
+/*@_init_EPILOG_ENDS*/\n\
+\n\
+/*@_fini_PROLOG_BEGINS*/\n\
+       .section .fini\n\
+       .align 5\n\
+       .global _fini\n\
+       .type   _fini,@function\n\
+_fini:\n\
+       mov.l   r12,@-r15\n\
+       mov.l   r14,@-r15\n\
+       sts.l   pr,@-r15\n\
+       mova    .L27,r0\n\
+       mov.l   .L27,r12\n\
+       add     r0,r12\n\
+       mov     r15,r14\n\
+       ALIGN\n\
+       END_FINI\n\
+       bra     1f\n\
+        nop\n\
+       .align  2\n\
+.L27:\n\
+       .long   _GLOBAL_OFFSET_TABLE_\n\
+1:\n\
+/*@_fini_PROLOG_ENDS*/\n\
+\n\
+/*@_fini_EPILOG_BEGINS*/\n\
+       .section .fini\n\
+       mov     r14,r15\n\
+       lds.l   @r15+,pr\n\
+       mov.l   @r15+,r14\n\
+       rts     \n\
+       mov.l   @r15+,r12\n\
+\n\
+       END_FINI\n\
+       \n\
+/*@_fini_EPILOG_ENDS*/\n\
+\n\
+/*@TRAILER_BEGINS*/\n\
+");
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pt-vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pt-vfork.S
new file mode 100644 (file)
index 0000000..54f2281
--- /dev/null
@@ -0,0 +1,65 @@
+/* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#define _ERRNO_H       1
+#include <bits/errno.h>
+#include <tcb-offsets.h>
+
+/* Clone the calling process, but without copying the whole address space.
+   The calling process is suspended until the new process exits or is
+   replaced by a call to `execve'.  Return -1 for errors, 0 to the new process,
+   and the process ID of the new process to the old process.  */
+
+ENTRY (__vfork)
+       /* Save the PID value.  */
+       stc     gbr, r2
+       mov.w   .L2, r0
+       mov.l   @(r0,r2), r4
+       neg     r4, r1
+       mov.l   r1, @(r0,r2)
+
+       mov.w   .L1, r3
+       trapa   #0x10
+       mov     r0, r1
+
+       /* Restore the old PID value in the parent.  */
+       tst     r0, r0
+       bt/s    2f
+        stc    gbr, r2
+       mov.w   .L2, r0
+       mov.l   r4, @(r0,r2)
+       mov     r1, r0
+2:
+       mov     #-12, r2
+       shad    r2, r1
+       not     r1, r1                  // r1=0 means r0 = -1 to -4095
+       tst     r1, r1                  // i.e. error in linux
+       bf      .Lpseudo_end
+       SYSCALL_ERROR_HANDLER
+.Lpseudo_end:
+       rts
+        nop
+.L1:
+       .word   __NR_vfork
+.L2:
+       .word   PID - TLS_PRE_TCB_SIZE
+
+PSEUDO_END (__vfork)
+
+weak_alias (__vfork, vfork)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_barrier_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_barrier_wait.S
new file mode 100644 (file)
index 0000000..4a6059a
--- /dev/null
@@ -0,0 +1,216 @@
+/* Copyright (C) 2003, 2004, 2007, 2008 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <lowlevelbarrier.h>
+#include "lowlevel-atomic.h"
+
+       .text
+
+       .globl  pthread_barrier_wait
+       .type   pthread_barrier_wait,@function
+       .align  5
+pthread_barrier_wait:
+       mov.l   r9, @-r15
+       mov.l   r8, @-r15
+       sts.l   pr, @-r15
+       mov     r4, r8
+
+       /* Get the mutex.  */
+       mov     #0, r3
+       mov     #1, r4
+       CMPXCHG (r3, @(MUTEX,r8), r4, r2)
+       bf      1f
+
+       /* One less waiter.  If this was the last one needed wake
+          everybody.  */
+2:
+       mov.l   @(LEFT,r8), r0
+       add     #-1, r0
+       mov.l   r0, @(LEFT,r8)
+       tst     r0, r0
+       bt      3f
+
+       /* There are more threads to come.  */
+       mov.l   @(CURR_EVENT,r8), r6
+
+       /* Release the mutex.  */
+       DEC (@(MUTEX,r8), r2)
+       tst     r2, r2
+       bf      6f
+7:
+       /* Wait for the remaining threads.  The call will return immediately
+          if the CURR_EVENT memory has meanwhile been changed.  */
+       mov     r8, r4
+#if CURR_EVENT != 0
+       add     #CURR_EVENT, r4
+#endif
+#if FUTEX_WAIT == 0
+       mov.l   @(PRIVATE,r8), r5
+#else
+       mov     #FUTEX_WAIT, r5
+       mov.l   @(PRIVATE,r8), r0
+       or      r0, r5
+#endif
+       mov     #0, r7
+8:
+       mov     #SYS_futex, r3
+       extu.b  r3, r3
+       trapa   #0x14
+       SYSCALL_INST_PAD
+
+       /* Don't return on spurious wakeups.  The syscall does not change
+          any register except r0 so there is no need to reload any of
+          them.  */
+       mov.l   @(CURR_EVENT,r8), r0
+       cmp/eq  r0, r6
+       bt      8b
+
+       /* Increment LEFT.  If this brings the count back to the
+          initial count unlock the object.  */
+       mov     #1, r3
+       mov.l   @(INIT_COUNT,r8), r4
+       XADD    (r3, @(LEFT,r8), r2, r5)
+       add     #-1, r4
+       cmp/eq  r2, r4
+       bf      10f
+
+       /* Release the mutex.  We cannot release the lock before
+          waking the waiting threads since otherwise a new thread might
+          arrive and gets waken up, too.  */
+       DEC (@(MUTEX,r8), r2)
+       tst     r2, r2
+       bf      9f
+
+10:
+       mov     #0, r0          /* != PTHREAD_BARRIER_SERIAL_THREAD */
+       lds.l   @r15+, pr
+       mov.l   @r15+, r8
+       rts
+        mov.l  @r15+, r9
+
+3:
+       /* The necessary number of threads arrived.  */
+       mov.l   @(CURR_EVENT,r8), r1
+       add     #1, r1
+       mov.l   r1, @(CURR_EVENT,r8)
+
+       /* Wake up all waiters.  The count is a signed number in the kernel
+          so 0x7fffffff is the highest value.  */
+       mov.l   .Lall, r6
+       mov     r8, r4
+#if CURR_EVENT != 0
+       add     #CURR_EVENT, r4
+#endif
+       mov     #0, r7
+       mov     #FUTEX_WAKE, r5
+       mov.l   @(PRIVATE,r8), r0
+       or      r0, r5
+       mov     #SYS_futex, r3
+       extu.b  r3, r3
+       trapa   #0x14
+       SYSCALL_INST_PAD
+
+       /* Increment LEFT.  If this brings the count back to the
+          initial count unlock the object.  */
+       mov     #1, r3
+       mov.l   @(INIT_COUNT,r8), r4
+       XADD    (r3, @(LEFT,r8), r2, r5)
+       add     #-1, r4
+       cmp/eq  r2, r4
+       bf      5f
+
+       /* Release the mutex.  */
+       DEC (@(MUTEX,r8), r2)
+       tst     r2, r2
+       bf      4f
+5:
+       mov     #-1, r0         /* == PTHREAD_BARRIER_SERIAL_THREAD */
+       lds.l   @r15+, pr
+       mov.l   @r15+, r8
+       rts
+        mov.l  @r15+, r9
+
+1:
+       mov.l   @(PRIVATE,r8), r6
+       mov     #LLL_SHARED, r0
+       extu.b  r0, r0
+       xor     r0, r6
+       mov     r2, r4
+       mov     r8, r5
+       mov.l   .Lwait0, r1
+       bsrf    r1
+        add    #MUTEX, r5
+.Lwait0b:
+       bra     2b
+        nop
+
+4:
+       mov.l   @(PRIVATE,r8), r5
+       mov     #LLL_SHARED, r0
+       extu.b  r0, r0
+       xor     r0, r5
+       mov     r8, r4
+       mov.l   .Lwake0, r1
+       bsrf    r1
+        add    #MUTEX, r4
+.Lwake0b:
+       bra     5b
+        nop
+
+6:
+       mov     r6, r9
+       mov.l   @(PRIVATE,r8), r5
+       mov     #LLL_SHARED, r0
+       extu.b  r0, r0
+       xor     r0, r5
+       mov     r8, r4
+       mov.l   .Lwake1, r1
+       bsrf    r1
+        add    #MUTEX, r4
+.Lwake1b:
+       bra     7b
+        mov    r9, r6
+
+9:     
+       mov     r6, r9
+       mov.l   @(PRIVATE,r8), r5
+       mov     #LLL_SHARED, r0
+       extu.b  r0, r0
+       xor     r0, r5
+       mov     r8, r4
+       mov.l   .Lwake2, r1
+       bsrf    r1
+        add    #MUTEX, r4
+.Lwake2b:
+       bra     10b
+        mov    r9, r6
+
+       .align  2
+.Lall:
+       .long   0x7fffffff
+.Lwait0:
+       .long   __lll_lock_wait-.Lwait0b
+.Lwake0:
+       .long   __lll_unlock_wake-.Lwake0b
+.Lwake1:
+       .long   __lll_unlock_wake-.Lwake1b
+.Lwake2:
+       .long   __lll_unlock_wake-.Lwake2b
+       .size   pthread_barrier_wait,.-pthread_barrier_wait
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_cond_broadcast.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_cond_broadcast.S
new file mode 100644 (file)
index 0000000..1242fc2
--- /dev/null
@@ -0,0 +1,262 @@
+/* Copyright (C) 2003, 2004, 2006, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <lowlevelcond.h>
+#include <bits/kernel-features.h>
+#include <pthread-pi-defines.h>
+#include <pthread-errnos.h>
+#include <tcb-offsets.h>
+#include "lowlevel-atomic.h"
+
+       .text
+
+       /* int pthread_cond_broadcast (pthread_cond_t *cond) */
+       .globl  __pthread_cond_broadcast
+       .type   __pthread_cond_broadcast, @function
+       .align  5
+__pthread_cond_broadcast:
+       mov.l   r10, @-r15
+       mov.l   r9, @-r15
+       mov.l   r8, @-r15
+       sts.l   pr, @-r15
+       mov     r4, r8
+
+       /* Get internal lock.  */
+       mov     #0, r3
+       mov     #1, r4
+#if cond_lock != 0
+       CMPXCHG (r3, @(cond_lock,r8), r4, r2)
+#else
+       CMPXCHG (r3, @r8, r4, r2)
+#endif
+       bf      1f
+2:
+       mov.l   @(total_seq+4,r8),r0
+       mov.l   @(total_seq,r8),r1
+       mov.l   @(wakeup_seq+4,r8), r2
+       cmp/hi  r2, r0
+       bt      3f
+       cmp/hi  r0, r2
+       bt      4f
+       mov.l   @(wakeup_seq,r8), r2
+       cmp/hi  r2, r1
+       bf      4f
+
+3:
+       /* Cause all currently waiting threads to recognize they are
+          woken up.  */
+       mov.l   r1, @(wakeup_seq,r8)
+       mov.l   r0, @(wakeup_seq+4,r8)
+       mov.l   r1, @(woken_seq,r8)
+       mov.l   r0, @(woken_seq+4,r8)
+       mov.l   @(broadcast_seq,r8), r2
+       add     #1, r2
+       mov.l   r2, @(broadcast_seq,r8)
+       add     r1, r1
+       mov     r1, r10
+       mov.l   r10, @(cond_futex,r8)
+
+       /* Get the address of the mutex used.  */
+       mov.l   @(dep_mutex,r8), r9
+
+       /* Unlock.  */
+#if cond_lock != 0
+       DEC (@(cond_lock,r8), r2)
+#else
+       DEC (@r8, r2)
+#endif
+       tst     r2, r2
+       bf      7f
+
+8:
+       /* Don't use requeue for pshared condvars.  */
+       mov     #-1, r0
+       cmp/eq  r0, r9
+       mov     r8, r4
+       bt/s    9f
+        add    #cond_futex, r4
+
+       /* XXX: The kernel only supports FUTEX_CMP_REQUEUE to the same
+          type of futex (private resp. shared).  */
+       mov.l   @(MUTEX_KIND,r9), r0
+       tst     #(PI_BIT|PS_BIT), r0
+       bf      9f
+
+       /* Wake up all threads.  */
+#ifdef __ASSUME_PRIVATE_FUTEX
+       mov     #(FUTEX_CMP_REQUEUE|FUTEX_PRIVATE_FLAG), r5
+       extu.b  r5, r5
+#else
+       stc     gbr, r1
+       mov.w   .Lpfoff, r2
+       add     r2, r1
+       mov.l   @r1, r5
+       mov     #FUTEX_CMP_REQUEUE, r0
+       or      r0, r5
+#endif
+       mov     #1, r6
+       mov     #-1, r7
+       shlr    r7              /* r7 = 0x7fffffff */
+       mov     r9, r0
+# if MUTEX_FUTEX != 0
+       add     #MUTEX_FUTEX, r0
+# endif
+       mov     r10, r1
+       mov     #SYS_futex, r3
+       extu.b  r3, r3
+       trapa   #0x16
+       SYSCALL_INST_PAD
+
+       /* For any kind of error, which mainly is EAGAIN, we try again
+          with WAKE.  The general test also covers running on old
+          kernels.  */
+       mov     r0, r1
+       mov     #-12, r2
+       shad    r2, r1
+       not     r1, r1
+       tst     r1, r1
+       mov     r8, r4
+       bt/s    9f
+        add    #cond_futex, r4
+
+10:
+       mov     #0, r0
+       lds.l   @r15+, pr
+       mov.l   @r15+, r8
+       mov.l   @r15+, r9
+       rts
+        mov.l  @r15+, r10
+
+4:
+       /* Unlock.  */
+#if cond_lock != 0
+       DEC (@(cond_lock,r8), r2)
+#else
+       DEC (@r8, r2)
+#endif
+       tst     r2, r2
+       bf      5f
+6:
+       mov     #0, r0
+       lds.l   @r15+, pr
+       mov.l   @r15+, r8
+       mov.l   @r15+, r9
+       rts
+        mov.l  @r15+, r10
+
+1:
+       /* Initial locking failed.  */
+       mov     r8, r5
+#if cond_lock != 0
+       add     #cond_lock, r5
+#endif
+       mov.l   @(dep_mutex,r8), r0
+       cmp/eq  #-1, r0
+       bf/s    99f
+        mov    #LLL_PRIVATE, r6
+       mov     #LLL_SHARED, r6
+99:
+       extu.b  r6, r6
+       mov.l   .Lwait5, r1
+       bsrf    r1
+        mov    r2, r4
+.Lwait5b:
+       bra     2b
+        nop
+
+5:
+       /* Unlock in loop requires wakeup.  */
+       mov     r8, r4
+#if cond_lock != 0
+       add     #cond_lock, r4
+#endif
+       mov.l   @(dep_mutex,r8), r0
+       cmp/eq  #-1, r0
+       bf/s    99f
+        mov    #LLL_PRIVATE, r5
+       mov     #LLL_SHARED, r5
+99:
+       mov.l   .Lwake5, r1
+       bsrf    r1
+        extu.b r5, r5
+.Lwake5b:
+       bra     6b
+        nop
+
+7:
+       /* Unlock in loop requires wakeup.  */
+       mov     r8, r4
+#if cond_lock != 0
+       add     #cond_lock, r4
+#endif
+       mov     #-1, r0
+       cmp/eq  r0, r9
+       bf/s    99f
+        mov    #LLL_PRIVATE, r5
+       mov     #LLL_SHARED, r5
+99:
+       mov.l   .Lwake6, r1
+       bsrf    r1
+        extu.b r5, r5
+.Lwake6b:
+       bra     8b
+        nop
+
+9:
+       mov     #-1, r0
+       cmp/eq  r0, r9
+       bt/s    99f
+        mov    #FUTEX_WAKE, r5
+#ifdef __ASSUME_PRIVATE_FUTEX
+       mov     #(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), r5
+       extu.b  r5, r5
+#else
+       stc     gbr, r1
+       mov.w   .Lpfoff, r2
+       add     r2, r1
+       mov.l   @r1, r5
+       mov     #FUTEX_WAKE, r0
+       or      r0, r5
+#endif
+99:
+       mov     #-1, r6
+       shlr    r6              /* r6 = 0x7fffffff */
+       mov     #0, r7
+       mov     #SYS_futex, r3
+       extu.b  r3, r3
+       trapa   #0x14
+       SYSCALL_INST_PAD
+       bra     10b
+        nop
+
+#ifndef __ASSUME_PRIVATE_FUTEX
+.Lpfoff:
+       .word   PRIVATE_FUTEX - TLS_PRE_TCB_SIZE
+#endif
+
+       .align  2
+.Lwait5:
+       .long   __lll_lock_wait-.Lwait5b
+.Lwake5:
+       .long   __lll_unlock_wake-.Lwake5b
+.Lwake6:
+       .long   __lll_unlock_wake-.Lwake6b
+       .size   __pthread_cond_broadcast, .-__pthread_cond_broadcast
+weak_alias (__pthread_cond_broadcast, pthread_cond_broadcast)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_cond_signal.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_cond_signal.S
new file mode 100644 (file)
index 0000000..1c3bacb
--- /dev/null
@@ -0,0 +1,189 @@
+/* Copyright (C) 2003, 2004, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <lowlevelcond.h>
+#include <bits/kernel-features.h>
+#include <pthread-errnos.h>
+#include <tcb-offsets.h>
+#include "lowlevel-atomic.h"
+
+       .text
+
+       /* int pthread_cond_signal (pthread_cond_t *cond) */
+       .globl  __pthread_cond_signal
+       .type   __pthread_cond_signal, @function
+       .align  5
+__pthread_cond_signal:
+       mov.l   r8, @-r15
+       sts.l   pr, @-r15
+       mov     r4, r8
+
+       /* Get internal lock.  */
+       mov     #0, r3
+       mov     #1, r4
+#if cond_lock != 0
+       CMPXCHG (r3, @(cond_lock,r8), r4, r2)
+#else
+       CMPXCHG (r3, @r8, r4, r2)
+#endif
+       bf      1f
+2:
+       mov.l   @(total_seq+4,r8),r0
+       mov.l   @(total_seq,r8),r1
+       mov.l   @(wakeup_seq+4,r8), r2
+       cmp/hi  r2, r0
+       bt      3f
+       cmp/hi  r0, r2
+       bt      4f
+       mov.l   @(wakeup_seq,r8), r2
+       cmp/hi  r2, r1
+       bf      4f
+
+3:
+       /* Bump the wakeup number.  */
+       mov     #1, r2
+       mov     #0, r3
+       clrt
+       mov.l   @(wakeup_seq,r8),r0
+       mov.l   @(wakeup_seq+4,r8),r1
+       addc    r2, r0
+       addc    r3, r1
+       mov.l   r0,@(wakeup_seq,r8)
+       mov.l   r1,@(wakeup_seq+4,r8)
+       mov.l   @(cond_futex,r8),r0
+       add     r2, r0
+       mov.l   r0,@(cond_futex,r8)
+
+       /* Wake up one thread.  */
+       mov     r8, r4
+       add     #cond_futex, r4
+       mov.l   @(dep_mutex,r8), r0
+       cmp/eq  #-1, r0
+       bt/s    99f
+        mov    #FUTEX_WAKE_OP, r5
+#ifdef __ASSUME_PRIVATE_FUTEX
+       mov     #(FUTEX_WAKE_OP|FUTEX_PRIVATE_FLAG), r5
+       extu.b  r5, r5
+#else
+       stc     gbr, r1
+       mov.w   .Lpfoff, r2
+       add     r2, r1
+       mov.l   @r1, r5
+       mov     #FUTEX_WAKE_OP, r0
+       or      r0, r5
+#endif
+99:
+       mov     #1, r6
+       mov     #0, r7
+       mov     r8, r0
+       add     #cond_lock, r0
+       mov.l   .Lfutexop, r1
+       mov     #SYS_futex, r3
+       extu.b  r3, r3
+       trapa   #0x14
+       SYSCALL_INST_PAD
+
+       /* For any kind of error, we try again with WAKE.
+          The general test also covers running on old kernels.  */
+       mov     r0, r1
+       mov     #-12, r2
+       shad    r2, r1
+       not     r1, r1
+       tst     r1, r1
+       bt      7f
+
+6:
+       mov     #0, r0
+       lds.l   @r15+, pr
+       rts
+        mov.l  @r15+, r8
+
+#ifndef __ASSUME_PRIVATE_FUTEX
+.Lpfoff:
+       .word   PRIVATE_FUTEX - TLS_PRE_TCB_SIZE
+#endif
+       .align  2
+.Lfutexop:
+       .long   FUTEX_OP_CLEAR_WAKE_IF_GT_ONE
+
+7:
+       /* r5 should be either FUTEX_WAKE_OP or
+          FUTEX_WAKE_OP|FUTEX_PRIVATE_FLAG from the previous syscall.  */
+       mov     #(FUTEX_WAKE ^ FUTEX_WAKE_OP), r0
+       xor     r0, r5
+       trapa   #0x14
+       SYSCALL_INST_PAD
+
+4:
+       /* Unlock.  */
+#if cond_lock != 0
+       DEC (@(cond_lock,r8), r2)
+#else
+       DEC (@r8, r2)
+#endif
+       tst     r2, r2
+       bt      6b
+
+5:
+       /* Unlock in loop requires wakeup.  */
+       mov     r8, r4
+#if cond_lock != 0
+       add     #cond_lock, r4
+#endif
+       mov.l   @(dep_mutex,r8), r0
+       cmp/eq  #-1, r0
+       bf/s    99f
+        mov    #LLL_PRIVATE, r5
+       mov     #LLL_SHARED, r5
+99:    
+       mov.l   .Lwake4, r1
+       bsrf    r1
+        extu.b r5, r5
+.Lwake4b:
+       bra     6b
+        nop
+
+1:
+       /* Initial locking failed.  */
+       mov     r8, r5
+#if cond_lock != 0
+       add     #cond_lock, r5
+#endif
+       mov.l   @(dep_mutex,r8), r0
+       cmp/eq  #-1, r0
+       bf/s    99f
+        mov    #LLL_PRIVATE, r6
+       mov     #LLL_SHARED, r6
+99:    
+       extu.b  r6, r6
+       mov.l   .Lwait4, r1
+       bsrf    r1
+        mov    r2, r4
+.Lwait4b:
+       bra     2b
+        nop
+
+       .align  2
+.Lwait4:
+       .long   __lll_lock_wait-.Lwait4b
+.Lwake4:
+       .long   __lll_unlock_wake-.Lwake4b
+       .size   __pthread_cond_signal, .-__pthread_cond_signal
+weak_alias (__pthread_cond_signal, pthread_cond_signal)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_cond_timedwait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_cond_timedwait.S
new file mode 100644 (file)
index 0000000..3e11756
--- /dev/null
@@ -0,0 +1,860 @@
+/* Copyright (C) 2003, 2004, 2006, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <lowlevelcond.h>
+#include <pthread-errnos.h>
+#include <bits/kernel-features.h>
+#include <tcb-offsets.h>
+#include "lowlevel-atomic.h"
+
+       .text
+
+/* int pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex,
+                              const struct timespec *abstime)  */
+       .globl  __pthread_cond_timedwait
+       .type   __pthread_cond_timedwait, @function
+       .align  5
+__pthread_cond_timedwait:
+.LSTARTCODE:
+       mov.l   r8, @-r15
+.Lpush_r8:
+       mov.l   r9, @-r15
+.Lpush_r9:
+       mov.l   r10, @-r15
+.Lpush_r10:
+       mov.l   r11, @-r15
+.Lpush_r11:
+       mov.l   r12, @-r15
+.Lpush_r12:
+       mov.l   r13, @-r15
+.Lpush_r13:
+       sts.l   pr, @-r15
+.Lpush_pr:
+       add     #-64, r15
+.Lalloc:
+       mov     r4, r8
+       mov     r5, r9
+       mov     r6, r13
+#ifdef __PIC__
+       mova    .Lgot0, r0
+       mov.l   .Lgot0, r12
+       add     r0, r12
+#endif
+
+       mov.l   @(4,r13), r0
+       mov.l   .L1g, r1
+       cmp/hs  r1, r0
+       bf      0f
+       bra     18f
+        mov    #EINVAL, r0
+0:
+       /* Get internal lock.  */
+       mov     #0, r3
+       mov     #1, r4
+#if cond_lock != 0
+       CMPXCHG (r3, @(cond_lock,r8), r4, r2)
+#else
+       CMPXCHG (r3, @r8, r4, r2)
+#endif
+       bt      2f
+       bra     1f
+        nop
+#ifdef __PIC__
+       .align  2
+.Lgot0:
+       .long   _GLOBAL_OFFSET_TABLE_
+#endif
+
+2:
+       /* Store the reference to the mutex.  If there is already a
+          different value in there this is a bad user bug.  */
+       mov.l   @(dep_mutex,r8),r0
+       cmp/eq  #-1, r0
+       bt      17f
+       mov.l   r9, @(dep_mutex,r8)
+
+17:
+       /* Unlock the mutex.  */
+       mov.l   .Lmunlock1, r1
+       mov     #0, r5
+       bsrf    r1
+        mov    r9, r4
+.Lmunlock1b:
+
+       tst     r0, r0
+       bt      0f
+       bra     16f
+        nop
+0:
+       mov     #1, r2
+       mov     #0, r3
+
+       clrt
+       mov.l   @(total_seq,r8),r0
+       mov.l   @(total_seq+4,r8),r1
+       addc    r2, r0
+       addc    r3, r1
+       mov.l   r0,@(total_seq,r8)
+       mov.l   r1,@(total_seq+4,r8)
+       mov.l   @(cond_futex,r8), r0
+       add     r2, r0
+       mov.l   r0, @(cond_futex,r8)
+       mov     #(1 << nwaiters_shift), r2
+       mov.l   @(cond_nwaiters,r8), r0
+       add     r2, r0
+       mov.l   r0, @(cond_nwaiters,r8)
+
+       /* Get and store current wakeup_seq value.  */
+       mov.l   @(wakeup_seq,r8), r10
+       mov.l   @(wakeup_seq+4,r8), r11
+       mov.l   @(broadcast_seq,r8), r0
+       mov.l   r0, @(4,r15)
+
+8:
+       /* Get current time.  */
+#ifdef __NR_clock_gettime
+       /* Get the clock number.         */
+       mov.l   @(cond_nwaiters,r8), r4
+       mov     #((1 << nwaiters_shift) - 1), r0
+       and     r0, r4
+       /* Only clocks 0 and 1 are allowed.  Both are handled in the
+          kernel.  */
+       mov     r15, r5
+       add     #16, r5
+       mov.w   .L__NR_clock_gettime, r3
+       trapa   #0x12
+       SYSCALL_INST_PAD
+# ifndef __ASSUME_POSIX_TIMERS
+       cmp/eq  #-ENOSYS, r0
+       bt      19f
+# endif
+
+       /* Compute relative timeout.  */
+       mov.l   @r13, r2
+       mov.l   @(4,r13), r3
+       mov.l   @(16,r15), r0
+       bra     0f
+        mov.l  @(20,r15), r1
+.L__NR_clock_gettime:
+       .word   __NR_clock_gettime
+
+# ifndef __ASSUME_POSIX_TIMERS
+19:
+       mov     r15, r4
+       add     #16, r4
+       mov     #0, r5
+       mov     #__NR_gettimeofday, r3
+       trapa   #0x12
+       SYSCALL_INST_PAD
+
+       /* Compute relative timeout.  */
+       mov.l   @(20,r15), r0
+       mov.w   .L1k, r1
+       dmulu.l r0, r1          /* Micro seconds to nano seconds.  */
+       mov.l   @r13, r2
+       mov.l   @(4,r13), r3
+       mov.l   @(16,r15), r0
+       sts     macl, r1
+#endif
+0:
+#else
+       mov     r15, r4
+       add     #16, r4
+       mov     #0, r5
+       mov     #__NR_gettimeofday, r3
+       trapa   #0x12
+       SYSCALL_INST_PAD
+
+       /* Compute relative timeout.  */
+       mov.l   @(20,r15), r0
+       mov.w   .L1k, r1
+       dmulu.l r0, r1          /* Micro seconds to nano seconds.  */
+       mov.l   @r13, r2
+       mov.l   @(4,r13), r3
+       mov.l   @(16,r15), r0
+       sts     macl, r1
+#endif
+       sub     r0, r2
+       clrt
+       subc    r1, r3
+       bf      12f
+       mov.l   .L1g, r1
+       add     r1, r3
+       add     #-1, r2
+12:
+       mov     #-ETIMEDOUT, r1
+       mov.l   r1, @(12,r15)
+       cmp/pz  r2
+       bf      6f              /* Time is already up.  */
+
+       /* Store relative timeout.  */
+       mov.l   r2, @(16,r15)
+       mov.l   r3, @(20,r15)
+       mov.l   @(cond_futex,r8), r1
+       mov.l   r1, @(8,r15)
+
+       /* Unlock.  */
+#if cond_lock != 0
+       DEC (@(cond_lock,r8), r2)
+#else
+       DEC (@r8, r2)
+#endif
+       tst     r2, r2
+       bt      4f
+       bra     3f
+        nop
+4:
+.LcleanupSTART:
+       mov.l   .Lenable1, r1
+       bsrf    r1
+        nop
+.Lenable1b:
+       mov.l   r0, @r15
+
+       mov     r15, r7
+       add     #16, r7
+       mov.l   @(dep_mutex,r8), r0
+       cmp/eq  #-1, r0
+       bt/s    99f
+        mov    #FUTEX_WAIT, r5
+#ifdef __ASSUME_PRIVATE_FUTEX
+       mov     #(FUTEX_WAIT|FUTEX_PRIVATE_FLAG), r5
+       extu.b  r5, r5
+#else
+       stc     gbr, r1
+       mov.w   .Lpfoff, r2
+       add     r2, r1
+       mov.l   @r1, r5
+       mov     #FUTEX_WAIT, r0
+       or      r0, r5
+#endif
+99:
+       mov.l   @(8,r15), r6
+       mov     r8, r4
+       add     #cond_futex, r4
+       mov     #SYS_futex, r3
+       extu.b  r3, r3
+       trapa   #0x14
+       SYSCALL_INST_PAD
+       mov.l   r0, @(12,r15)
+
+       mov.l   .Ldisable1, r1
+       bsrf    r1
+        mov.l  @r15, r4
+.Ldisable1b:
+.LcleanupEND:
+
+       /* Lock.  */
+       mov     #0, r3
+       mov     #1, r4
+#if cond_lock != 0
+       CMPXCHG (r3, @(cond_lock,r8), r4, r2)
+#else
+       CMPXCHG (r3, @r8, r4, r2)
+#endif
+       bf      5f
+6:
+       mov.l   @(broadcast_seq,r8), r0
+       mov.l   @(4,r15), r1
+       cmp/eq  r0, r1
+       bf      23f
+
+       mov.l   @(woken_seq,r8), r0
+       mov.l   @(woken_seq+4,r8), r1
+
+       mov.l   @(wakeup_seq,r8), r2
+       mov.l   @(wakeup_seq+4,r8), r3
+
+       cmp/eq  r3, r11
+       bf      7f
+       cmp/eq  r2, r10
+       bt      15f
+7:
+       cmp/eq  r1, r3
+       bf      9f
+       cmp/eq  r0, r2
+       bf      9f
+15:
+       mov.l   @(12,r15),r0
+       cmp/eq  #-ETIMEDOUT, r0
+       bf      8b
+
+       mov     #1, r2
+       mov     #0, r3
+
+       clrt
+       mov.l   @(wakeup_seq,r8),r0
+       mov.l   @(wakeup_seq+4,r8),r1
+       addc    r2, r0
+       addc    r3, r1
+       mov.l   r0,@(wakeup_seq,r8)
+       mov.l   r1,@(wakeup_seq+4,r8)
+       mov.l   @(cond_futex,r8),r0
+       add     r2, r0
+       mov.l   r0,@(cond_futex,r8)
+       mov     #ETIMEDOUT, r0
+       bra     14f
+        mov.l  r0, @(24,r15)
+
+23:
+       mov     #0, r0
+       bra     24f
+        mov.l  r0, @(24,r15)
+
+9:
+       mov     #0, r0
+       mov.l   r0, @(24,r15)
+14:
+       mov     #1, r2
+       mov     #0, r3
+
+       clrt
+       mov.l   @(woken_seq,r8),r0
+       mov.l   @(woken_seq+4,r8),r1
+       addc    r2, r0
+       addc    r3, r1
+       mov.l   r0,@(woken_seq,r8)
+       mov.l   r1,@(woken_seq+4,r8)
+
+24:
+       mov     #(1 << nwaiters_shift), r2
+       mov.l   @(cond_nwaiters,r8),r0
+       sub     r2, r0
+       mov.l   r0,@(cond_nwaiters,r8)
+
+       /* Wake up a thread which wants to destroy the condvar object.  */
+       mov.l   @(total_seq,r8),r0
+       mov.l   @(total_seq+4,r8),r1
+       and     r1, r0
+       not     r0, r0
+       cmp/eq  #0, r0
+       bf/s    25f
+        mov    #((1 << nwaiters_shift) - 1), r1
+       not     r1, r1
+       mov.l   @(cond_nwaiters,r8),r0
+       tst     r1, r0
+       bf      25f
+
+       mov     r8, r4
+       add     #cond_nwaiters, r4
+       mov.l   @(dep_mutex,r8), r0
+       cmp/eq  #-1, r0
+       bt/s    99f
+        mov    #FUTEX_WAKE, r5
+#ifdef __ASSUME_PRIVATE_FUTEX
+       mov     #(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), r5
+       extu.b  r5, r5
+#else
+       stc     gbr, r1
+       mov.w   .Lpfoff, r2
+       add     r2, r1
+       mov.l   @r1, r5
+       mov     #FUTEX_WAKE, r0
+       or      r0, r5
+#endif
+99:
+       mov     #1, r6
+       mov     #0, r7
+       mov     #SYS_futex, r3
+       extu.b  r3, r3
+       trapa   #0x14
+       SYSCALL_INST_PAD
+
+25:
+#if cond_lock != 0
+       DEC (@(cond_lock,r8), r2)
+#else
+       DEC (@r8, r2)
+#endif
+       tst     r2, r2
+       bf      10f
+
+11:
+       mov     r9, r4
+       mov.l   .Lmlocki1, r1
+       bsrf    r1
+        nop
+.Lmlocki1b:
+
+       /* We return the result of the mutex_lock operation if it failed.  */
+       tst     r0, r0
+       bf      18f
+       mov.l   @(24,r15), r0
+
+18:
+       add     #64, r15
+       lds.l   @r15+, pr
+       mov.l   @r15+, r13
+       mov.l   @r15+, r12
+       mov.l   @r15+, r11
+       mov.l   @r15+, r10
+       mov.l   @r15+, r9
+       rts
+        mov.l  @r15+, r8
+
+#ifndef __ASSUME_PRIVATE_FUTEX
+.Lpfoff:
+       .word   PRIVATE_FUTEX - TLS_PRE_TCB_SIZE
+#endif
+.L1k:
+       .word   1000
+       .align  2
+.Lmunlock1:
+       .long   __pthread_mutex_unlock_usercnt-.Lmunlock1b
+.Lenable1:
+       .long   __pthread_enable_asynccancel-.Lenable1b
+.Ldisable1:
+       .long   __pthread_disable_asynccancel-.Ldisable1b
+.Lmlocki1:
+       .long   __pthread_mutex_cond_lock-.Lmlocki1b
+.L1g:
+       .long   1000000000
+
+1:
+       /* Initial locking failed.  */
+       mov     r8, r5
+#if cond_lock != 0
+       add     #cond_lock, r5
+#endif
+       mov.l   @(dep_mutex,r8), r0
+       cmp/eq  #-1, r0
+       bf/s    99f
+        mov    #LLL_PRIVATE, r6
+       mov     #LLL_SHARED, r6
+99:
+       extu.b  r6, r6
+       mov.l   .Lwait2, r1
+       bsrf    r1
+        mov    r2, r4
+.Lwait2b:
+       bra     2b
+        nop
+
+3:
+       /* Unlock in loop requires wakeup.  */
+       mov     r8, r4
+#if cond_lock != 0
+       add     #cond_lock, r4
+#endif
+       mov.l   @(dep_mutex,r8), r0
+       cmp/eq  #-1, r0
+       bf/s    99f
+        mov    #LLL_PRIVATE, r5
+       mov     #LLL_SHARED, r5
+99:
+       mov.l   .Lmwait2, r1
+       bsrf    r1
+        extu.b r5, r5
+.Lmwait2b:
+       bra     4b
+        nop
+
+5:
+       /* Locking in loop failed.  */
+       mov     r8, r5
+#if cond_lock != 0
+       add     #cond_lock, r5
+#endif
+       mov.l   @(dep_mutex,r8), r0
+       cmp/eq  #-1, r0
+       bf/s    99f
+        mov    #LLL_PRIVATE, r6
+       mov     #LLL_SHARED, r6
+99:
+       extu.b  r6, r6
+       mov.l   .Lwait3, r1
+       bsrf    r1
+        mov    r2, r4
+.Lwait3b:
+       bra     6b
+        nop
+
+10:
+       /* Unlock after loop requires wakeup.  */
+       mov     r8, r4
+#if cond_lock != 0
+       add     #cond_lock, r4
+#endif
+       mov.l   @(dep_mutex,r8), r0
+       cmp/eq  #-1, r0
+       bf/s    99f
+        mov    #LLL_PRIVATE, r5
+       mov     #LLL_SHARED, r5
+99:
+       mov.l   .Lmwait3, r1
+       bsrf    r1
+        extu.b r5, r5
+.Lmwait3b:
+       bra     11b
+        nop
+
+16:
+       /* The initial unlocking of the mutex failed.  */
+       mov.l   r0, @(24,r15)
+#if cond_lock != 0
+       DEC (@(cond_lock,r8), r2)
+#else
+       DEC (@r8, r2)
+#endif
+       tst     r2, r2
+       bf      17f
+
+       mov     r8, r4
+#if cond_lock != 0
+       add     #cond_lock, r4
+#endif
+       mov.l   @(dep_mutex,r8), r0
+       cmp/eq  #-1, r0
+       bf/s    99f
+        mov    #LLL_PRIVATE, r5
+       mov     #LLL_SHARED, r5
+99:
+       mov.l   .Lmwait4, r1
+       bsrf    r1
+        extu.b r5, r5
+.Lmwait4b:
+17:
+       bra     18b
+        mov.l  @(24,r15), r0
+
+       .align  2
+.Lwait2:
+       .long   __lll_lock_wait-.Lwait2b
+.Lmwait2:
+       .long   __lll_unlock_wake-.Lmwait2b
+.Lwait3:
+       .long   __lll_lock_wait-.Lwait3b
+.Lmwait3:
+       .long   __lll_unlock_wake-.Lmwait3b
+.Lmwait4:
+       .long   __lll_unlock_wake-.Lmwait4b
+       .size   __pthread_cond_timedwait, .-__pthread_cond_timedwait
+weak_alias (__pthread_cond_timedwait, pthread_cond_timedwait)
+
+
+       .type   __condvar_tw_cleanup, @function
+__condvar_tw_cleanup:
+       mov     r4, r11
+
+       /* Get internal lock.  */
+       mov     #0, r3
+       mov     #1, r4
+#if cond_lock != 0
+       CMPXCHG (r3, @(cond_lock,r8), r4, r2)
+#else
+       CMPXCHG (r3, @r8, r4, r2)
+#endif
+       bt      1f
+        nop
+
+       mov     r8, r5
+#if cond_lock != 0
+       add     #cond_lock, r5
+#endif
+       mov.l   @(dep_mutex,r8), r0
+       cmp/eq  #-1, r0
+       bf/s    99f
+        mov    #LLL_PRIVATE, r6
+       mov     #LLL_SHARED, r6
+99:
+       extu.b  r6, r6
+       mov.l   .Lwait5, r1
+       bsrf    r1
+        mov    r2, r4
+.Lwait5b:
+
+1:
+       mov.l   @(broadcast_seq,r8), r0
+       mov.l   @(4,r15), r1
+       cmp/eq  r0, r1
+       bf      3f
+
+       mov     #1, r2
+       mov     #0, r3
+
+       /* We increment the wakeup_seq counter only if it is lower than
+          total_seq.  If this is not the case the thread was woken and
+          then canceled.  In this case we ignore the signal.  */
+       mov.l   @(total_seq+4,r8), r0
+       mov.l   @(wakeup_seq+4,r8), r1
+       cmp/hi  r1, r0
+       bt/s    6f
+        cmp/hi r0, r1
+       bt      7f
+       mov.l   @(total_seq,r8), r0
+       mov.l   @(wakeup_seq,r8), r1
+       cmp/hs  r0, r1
+       bt      7f
+
+6:
+       clrt
+       mov.l   @(wakeup_seq,r8),r0
+       mov.l   @(wakeup_seq+4,r8),r1
+       addc    r2, r0
+       addc    r3, r1
+       mov.l   r0,@(wakeup_seq,r8)
+       mov.l   r1,@(wakeup_seq+4,r8)
+       mov.l   @(cond_futex,r8),r0
+       add     r2, r0
+       mov.l   r0,@(cond_futex,r8)
+
+7:
+       clrt
+       mov.l   @(woken_seq,r8),r0
+       mov.l   @(woken_seq+4,r8),r1
+       addc    r2, r0
+       addc    r3, r1
+       mov.l   r0,@(woken_seq,r8)
+       mov.l   r1,@(woken_seq+4,r8)
+
+3:
+       mov     #(1 << nwaiters_shift), r2
+       mov.l   @(cond_nwaiters,r8),r0
+       sub     r2, r0
+       mov.l   r0,@(cond_nwaiters,r8)
+
+       /* Wake up a thread which wants to destroy the condvar object.  */
+       mov     #0, r10
+       mov.l   @(total_seq,r8),r0
+       mov.l   @(total_seq+4,r8),r1
+       and     r1, r0
+       not     r0, r0
+       cmp/eq  #0, r0
+       bf/s    4f
+        mov    #((1 << nwaiters_shift) - 1), r1
+       not     r1, r1
+       mov.l   @(cond_nwaiters,r8),r0
+       tst     r1, r0
+       bf      4f
+
+       mov     r8, r4
+       add     #cond_nwaiters, r4
+       mov     #FUTEX_WAKE, r5
+       mov     #1, r6
+       mov     #0, r7
+       mov     #SYS_futex, r3
+       extu.b  r3, r3
+       trapa   #0x14
+       SYSCALL_INST_PAD
+       mov     #1, r10
+
+4:
+#if cond_lock != 0
+       DEC (@(cond_lock,r8), r2)
+#else
+       DEC (@r8, r2)
+#endif
+       tst     r2, r2
+       bt      2f
+
+       mov     r8, r4
+#if cond_lock != 0
+       add     #cond_lock, r4
+#endif
+       mov.l   @(dep_mutex,r8), r0
+       cmp/eq  #-1, r0
+       bf/s    99f
+        mov    #LLL_PRIVATE, r5
+       mov     #LLL_SHARED, r5
+99:
+       mov.l   .Lmwait5, r1
+       bsrf    r1
+        extu.b r5, r5
+.Lmwait5b:
+
+2:
+       /* Wake up all waiters to make sure no signal gets lost.  */
+       tst     r10, r10
+       bf/s    5f
+        mov    r8, r4
+       add     #cond_futex, r4
+       mov     #FUTEX_WAKE, r5
+       mov     #-1, r6
+       shlr    r6              /* r6 = 0x7fffffff */
+       mov     #0, r7
+       mov     #SYS_futex, r3
+       extu.b  r3, r3
+       trapa   #0x14
+       SYSCALL_INST_PAD
+
+5:
+        mov.l   .Lmlocki5, r1
+        bsrf    r1
+         mov     r9, r4
+.Lmlocki5b:
+
+.LcallUR:
+       mov.l   .Lresume, r1
+#ifdef __PIC__
+       add     r12, r1
+#endif
+       jsr     @r1
+        mov    r11, r4
+       sleep
+
+       .align  2
+.Lwait5:
+       .long   __lll_lock_wait-.Lwait5b
+.Lmwait5:
+        .long   __lll_unlock_wake-.Lmwait5b
+.Lmlocki5:
+       .long   __pthread_mutex_cond_lock-.Lmlocki5b
+.Lresume:
+#ifdef __PIC__
+       .long   _Unwind_Resume@GOTOFF
+#else
+       .long   _Unwind_Resume
+#endif
+.LENDCODE:
+       .size   __condvar_tw_cleanup, .-__condvar_tw_cleanup
+
+
+       .section .gcc_except_table,"a",@progbits
+.LexceptSTART:
+       .byte   0xff                            ! @LPStart format (omit)
+       .byte   0xff                            ! @TType format (omit)
+       .byte   0x0b                            ! call-site format
+                                               ! DW_EH_PE_sdata4
+       .uleb128 .Lcstend-.Lcstbegin
+.Lcstbegin:
+       .ualong .LcleanupSTART-.LSTARTCODE
+       .ualong .LcleanupEND-.LcleanupSTART
+       .ualong __condvar_tw_cleanup-.LSTARTCODE
+       .uleb128  0
+       .ualong .LcallUR-.LSTARTCODE
+       .ualong .LENDCODE-.LcallUR
+       .ualong 0
+       .uleb128  0
+.Lcstend:
+
+       .section .eh_frame,"a",@progbits
+.LSTARTFRAME:
+       .ualong .LENDCIE-.LSTARTCIE             ! Length of the CIE.
+.LSTARTCIE:
+       .ualong 0                               ! CIE ID.
+       .byte   1                               ! Version number.
+#ifdef SHARED
+       .string "zPLR"                          ! NUL-terminated augmentation
+                                               ! string.
+#else
+       .string "zPL"                           ! NUL-terminated augmentation
+                                               ! string.
+#endif
+       .uleb128 1                              ! Code alignment factor.
+       .sleb128 -4                             ! Data alignment factor.
+       .byte   0x11                            ! Return address register
+                                               ! column.
+#ifdef SHARED
+       .uleb128 7                              ! Augmentation value length.
+       .byte   0x9b                            ! Personality: DW_EH_PE_pcrel
+                                               ! + DW_EH_PE_sdata4
+                                               ! + DW_EH_PE_indirect
+       .ualong DW.ref.__gcc_personality_v0-.
+       .byte   0x1b                            ! LSDA Encoding: DW_EH_PE_pcrel
+                                               ! + DW_EH_PE_sdata4.
+       .byte   0x1b                            ! FDE Encoding: DW_EH_PE_pcrel
+                                               ! + DW_EH_PE_sdata4.
+#else
+       .uleb128 6                              ! Augmentation value length.
+       .byte   0x0                             ! Personality: absolute
+       .ualong __gcc_personality_v0
+       .byte   0x0                             ! LSDA Encoding: absolute
+#endif
+       .byte 0x0c                              ! DW_CFA_def_cfa
+       .uleb128 0xf
+       .uleb128 0
+       .align 2
+.LENDCIE:
+
+       .ualong .LENDFDE-.LSTARTFDE             ! Length of the FDE.
+.LSTARTFDE:
+       .ualong .LSTARTFDE-.LSTARTFRAME         ! CIE pointer.
+#ifdef SHARED
+       .ualong .LSTARTCODE-.                   ! PC-relative start address
+                                               ! of the code.
+#else
+       .ualong .LSTARTCODE                     ! Start address of the code.
+#endif
+       .ualong .LENDCODE-.LSTARTCODE           ! Length of the code.
+       .uleb128 4                              ! Augmentation size
+#ifdef SHARED
+       .ualong .LexceptSTART-.
+#else
+       .ualong .LexceptSTART
+#endif
+       .byte   0x4
+       .ualong .Lpush_r8-.LSTARTCODE
+       .byte   0xe
+       .uleb128 4
+       .byte   0x88
+       .uleb128 1
+       .byte   0x4
+       .ualong .Lpush_r9-.Lpush_r8
+       .byte   0xe
+       .uleb128 8
+       .byte   0x89
+       .uleb128 2
+       .byte   0x4
+       .ualong .Lpush_r10-.Lpush_r9
+       .byte   0xe
+       .uleb128 12
+       .byte   0x8a
+       .uleb128 3
+       .byte   0x4
+       .ualong .Lpush_r11-.Lpush_r10
+       .byte   0xe
+       .uleb128 16
+       .byte   0x8b
+       .uleb128 4
+       .byte   0x4
+       .ualong .Lpush_r12-.Lpush_r11
+       .byte   0xe
+       .uleb128 20
+       .byte   0x8c
+       .uleb128 5
+       .byte   0x4
+       .ualong .Lpush_r13-.Lpush_r12
+       .byte   0xe
+       .uleb128 24
+       .byte   0x8d
+       .uleb128 6
+       .byte   0x4
+       .ualong .Lpush_pr-.Lpush_r13
+       .byte   0xe
+       .uleb128 28
+       .byte   0x91
+       .uleb128 7
+       .byte   0x4
+       .ualong .Lalloc-.Lpush_pr
+       .byte   0xe
+       .uleb128 92
+       .align  2
+.LENDFDE:
+
+#ifdef SHARED
+       .hidden DW.ref.__gcc_personality_v0
+       .weak   DW.ref.__gcc_personality_v0
+       .section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits
+       .align 4
+       .type   DW.ref.__gcc_personality_v0, @object
+       .size   DW.ref.__gcc_personality_v0, 4
+DW.ref.__gcc_personality_v0:
+       .long   __gcc_personality_v0
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_cond_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_cond_wait.S
new file mode 100644 (file)
index 0000000..5a897f6
--- /dev/null
@@ -0,0 +1,753 @@
+/* Copyright (C) 2003, 2004, 2006, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <lowlevelcond.h>
+#include <tcb-offsets.h>
+#include <bits/kernel-features.h>
+#include "lowlevel-atomic.h"
+
+       .text
+
+/* int pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex)  */
+       .globl  __pthread_cond_wait
+       .type   __pthread_cond_wait, @function
+       .align  5
+__pthread_cond_wait:
+.LSTARTCODE:
+       mov.l   r8, @-r15
+.Lpush_r8:
+       mov.l   r9, @-r15
+.Lpush_r9:
+       mov.l   r10, @-r15
+.Lpush_r10:
+       mov.l   r11, @-r15
+.Lpush_r11:
+       mov.l   r12, @-r15
+.Lpush_r12:
+       sts.l   pr, @-r15
+.Lpush_pr:
+       add     #-48, r15
+.Lalloc:
+       mov     r4, r8
+       mov     r5, r9
+#ifdef __PIC__
+       mova    .Lgot0, r0
+       mov.l   .Lgot0, r12
+       add     r0, r12
+#endif
+
+       /* Get internal lock.  */
+       mov     #0, r3
+       mov     #1, r4
+#if cond_lock != 0
+       CMPXCHG (r3, @(cond_lock,r8), r4, r2)
+#else
+       CMPXCHG (r3, @r8, r4, r2)
+#endif
+       bt      2f
+       bra     1f
+        nop
+#ifdef __PIC__
+       .align  2
+.Lgot0:
+       .long   _GLOBAL_OFFSET_TABLE_
+#endif
+
+2:
+       /* Store the reference to the mutex.  If there is already a
+          different value in there this is a bad user bug.  */
+       mov.l   @(dep_mutex,r8),r0
+       cmp/eq  #-1, r0
+       bt      15f
+       mov.l   r9, @(dep_mutex,r8)
+
+15:
+       /* Unlock the mutex.  */
+       mov.l   .Lmunlock0, r1
+       mov     #0, r5
+       bsrf    r1
+        mov    r9, r4
+.Lmunlock0b:
+
+       tst     r0, r0
+       bt      0f
+       bra     12f
+        nop
+0:
+       mov     #1, r2
+       mov     #0, r3
+
+       clrt
+       mov.l   @(total_seq,r8),r0
+       mov.l   @(total_seq+4,r8),r1
+       addc    r2, r0
+       addc    r3, r1
+       mov.l   r0,@(total_seq,r8)
+       mov.l   r1,@(total_seq+4,r8)
+       mov.l   @(cond_futex,r8),r0
+       add     r2, r0
+       mov.l   r0,@(cond_futex,r8)
+       mov     #(1 << nwaiters_shift), r2
+       mov.l   @(cond_nwaiters,r8), r0
+       add     r2, r0
+       mov.l   r0, @(cond_nwaiters,r8)
+
+       /* Get and store current wakeup_seq value.  */
+       mov.l   @(wakeup_seq,r8), r10
+       mov.l   @(wakeup_seq+4,r8), r11
+       mov.l   @(broadcast_seq,r8), r0
+       mov.l   r0, @(4,r15)
+
+8:
+       mov.l   @(cond_futex,r8),r0
+       mov.l   r0, @(8,r15)
+
+       /* Unlock.  */
+#if cond_lock != 0
+       DEC (@(cond_lock,r8), r2)
+#else
+       DEC (@r8, r2)
+#endif
+       tst     r2, r2
+       bf      3f
+4:
+.LcleanupSTART:
+       mov.l   .Lenable0, r1
+       bsrf    r1
+        nop
+.Lenable0b:
+       mov.l   r0, @r15
+
+       mov     #0, r7
+       mov.l   @(dep_mutex,r8), r0
+       cmp/eq  #-1, r0
+       bt/s    99f
+        mov    #FUTEX_WAIT, r5
+#ifdef __ASSUME_PRIVATE_FUTEX
+       mov     #(FUTEX_WAIT|FUTEX_PRIVATE_FLAG), r5
+       extu.b  r5, r5
+#else
+       stc     gbr, r1
+       mov.w   .Lpfoff0, r2
+       add     r2, r1
+       mov.l   @r1, r5
+       mov     #FUTEX_WAIT, r0
+       or      r0, r5
+#endif
+99:
+       mov.l   @(8,r15), r6
+       mov     r8, r4
+       add     #cond_futex, r4
+       mov     #SYS_futex, r3
+       extu.b  r3, r3
+       trapa   #0x14
+       SYSCALL_INST_PAD
+
+       mov.l   .Ldisable0, r1
+       bsrf    r1
+        mov.l  @r15, r4
+.Ldisable0b:
+.LcleanupEND:
+
+       /* Lock.  */
+       mov     #0, r3
+       mov     #1, r4
+#if cond_lock != 0
+       CMPXCHG (r3, @(cond_lock,r8), r4, r2)
+#else
+       CMPXCHG (r3, @r8, r4, r2)
+#endif
+       bf      5f
+6:
+       mov.l   @(broadcast_seq,r8), r0
+       mov.l   @(4,r15), r1
+       cmp/eq  r0, r1
+       bf      16f
+
+       mov.l   @(woken_seq,r8), r0
+       mov.l   @(woken_seq+4,r8), r1
+
+       mov.l   @(wakeup_seq,r8), r2
+       mov.l   @(wakeup_seq+4,r8), r3
+
+       cmp/eq  r3, r11
+       bf      7f
+       cmp/eq  r2, r10
+       bt      8b
+7:
+       cmp/eq  r1, r3
+       bf      9f
+       cmp/eq  r0, r2
+       bt      8b
+9:
+       mov     #1, r2
+       mov     #0, r3
+
+       clrt
+       mov.l   @(woken_seq,r8),r0
+       mov.l   @(woken_seq+4,r8),r1
+       addc    r2, r0
+       addc    r3, r1
+       mov.l   r0,@(woken_seq,r8)
+       mov.l   r1,@(woken_seq+4,r8)
+
+16:
+       mov     #(1 << nwaiters_shift), r2
+       mov.l   @(cond_nwaiters,r8),r0
+       sub     r2, r0
+       mov.l   r0,@(cond_nwaiters,r8)
+
+       /* Wake up a thread which wants to destroy the condvar object.  */
+       mov.l   @(total_seq,r8),r0
+       mov.l   @(total_seq+4,r8),r1
+       and     r1, r0
+       not     r0, r0
+       cmp/eq  #0, r0
+       bf/s    17f
+        mov    #((1 << nwaiters_shift) - 1), r1
+       not     r1, r1
+       mov.l   @(cond_nwaiters,r8),r0
+       tst     r1, r0
+       bf      17f
+
+       mov     r8, r4
+       add     #cond_nwaiters, r4
+       mov.l   @(dep_mutex,r8), r0
+       cmp/eq  #-1, r0
+       bt/s    99f
+        mov    #FUTEX_WAKE, r5
+#ifdef __ASSUME_PRIVATE_FUTEX
+       mov     #(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), r5
+       extu.b  r5, r5
+#else
+       stc     gbr, r1
+       mov.w   .Lpfoff0, r2
+       add     r2, r1
+       mov.l   @r1, r5
+       mov     #FUTEX_WAKE, r0
+       or      r0, r5
+#endif
+99:
+       mov     #1, r6
+       mov     #0, r7
+       mov     #SYS_futex, r3
+       extu.b  r3, r3
+       trapa   #0x14
+       SYSCALL_INST_PAD
+
+17:
+#if cond_lock != 0
+       DEC (@(cond_lock,r8), r2)
+#else
+       DEC (@r8, r2)
+#endif
+       tst     r2, r2
+       bf      10f
+
+11:
+       mov.l   .Lmlocki0, r1
+       bsrf    r1
+        mov    r9, r4
+.Lmlocki0b:
+       /* We return the result of the mutex_lock operation.  */
+
+14:
+       add     #48, r15
+       lds.l   @r15+, pr
+       mov.l   @r15+, r12
+       mov.l   @r15+, r11
+       mov.l   @r15+, r10
+       mov.l   @r15+, r9
+       rts
+        mov.l  @r15+, r8
+
+#ifndef __ASSUME_PRIVATE_FUTEX
+.Lpfoff0:
+       .word   PRIVATE_FUTEX - TLS_PRE_TCB_SIZE
+#endif
+       .align  2
+.Lmunlock0:
+       .long   __pthread_mutex_unlock_usercnt-.Lmunlock0b
+.Lenable0:
+       .long   __pthread_enable_asynccancel-.Lenable0b
+.Ldisable0:
+       .long   __pthread_disable_asynccancel-.Ldisable0b
+.Lmlocki0:
+       .long   __pthread_mutex_cond_lock-.Lmlocki0b
+
+1:
+       /* Initial locking failed.  */
+       mov     r8, r5
+#if cond_lock != 0
+       add     #cond_lock, r5
+#endif
+       mov.l   @(dep_mutex,r8), r0
+       cmp/eq  #-1, r0
+       bf/s    99f
+        mov    #LLL_PRIVATE, r6
+       mov     #LLL_SHARED, r6
+99:
+       extu.b  r6, r6
+       mov.l   .Lwait0, r1
+       bsrf    r1
+        mov    r2, r4
+.Lwait0b:
+       bra     2b
+        nop
+3:
+       /* Unlock in loop requires waekup.  */
+       mov     r8, r4
+#if cond_lock != 0
+       add     #cond_lock, r4
+#endif
+       mov.l   @(dep_mutex,r8), r0
+       cmp/eq  #-1, r0
+       bf/s    99f
+        mov    #LLL_PRIVATE, r5
+       mov     #LLL_SHARED, r5
+99:
+       mov.l   .Lwake0, r1
+       bsrf    r1
+        extu.b r5, r5
+.Lwake0b:
+       bra     4b
+        nop
+
+5:
+       /* Locking in loop failed.  */
+       mov     r8, r5
+#if cond_lock != 0
+       add     #cond_lock, r5
+#endif
+       mov.l   @(dep_mutex,r8), r0
+       cmp/eq  #-1, r0
+       bf/s    99f
+        mov    #LLL_PRIVATE, r6
+       mov     #LLL_SHARED, r6
+99:
+       extu.b  r6, r6
+       mov.l   .Lwait1, r1
+       bsrf    r1
+        mov    r2, r4
+.Lwait1b:
+       bra     6b
+        nop
+
+10:
+       /* Unlock after loop requires wakeup.  */
+       mov     r8, r4
+#if cond_lock != 0
+       add     #cond_lock, r4
+#endif
+       mov.l   @(dep_mutex,r8), r0
+       cmp/eq  #-1, r0
+       bf/s    99f
+        mov    #LLL_PRIVATE, r5
+       mov     #LLL_SHARED, r5
+99:
+       mov.l   .Lwake1, r1
+       bsrf    r1
+        extu.b r5, r5
+.Lwake1b:
+       bra     11b
+        nop
+
+12:
+       /* The initial unlocking of the mutex failed.  */
+       mov.l   r0, @(12,r15)
+#if cond_lock != 0
+       DEC (@(cond_lock,r8), r2)
+#else
+       DEC (@r8, r2)
+#endif
+       tst     r2, r2
+       bf      13f
+
+       mov     r8, r4
+#if cond_lock != 0
+       add     #cond_lock, r4
+#endif
+       mov.l   @(dep_mutex,r8), r0
+       cmp/eq  #-1, r0
+       bf/s    99f
+        mov    #LLL_PRIVATE, r5
+       mov     #LLL_SHARED, r5
+99:
+       mov.l   .Lwake2, r1
+       bsrf    r1
+        extu.b r5, r5
+.Lwake2b:
+
+13:
+       bra     14b
+        mov.l  @(12,r15), r0
+
+       .align  2
+.Lwait0:
+       .long   __lll_lock_wait-.Lwait0b
+.Lwake0:
+       .long   __lll_unlock_wake-.Lwake0b
+.Lwait1:
+       .long   __lll_lock_wait-.Lwait1b
+.Lwake1:
+       .long   __lll_unlock_wake-.Lwake1b
+.Lwake2:
+       .long   __lll_unlock_wake-.Lwake2b
+       .size   __pthread_cond_wait, .-__pthread_cond_wait
+weak_alias (__pthread_cond_wait, pthread_cond_wait)
+
+
+       .type   __condvar_w_cleanup, @function
+__condvar_w_cleanup:
+       mov     r4, r11
+
+       /* Get internal lock.  */
+       mov     #0, r3
+       mov     #1, r4
+#if cond_lock != 0
+       CMPXCHG (r3, @(cond_lock,r8), r4, r2)
+#else
+       CMPXCHG (r3, @r8, r4, r2)
+#endif
+       bt      1f
+        nop
+
+       mov     r8, r5
+#if cond_lock != 0
+       add     #cond_lock, r5
+#endif
+       mov.l   @(dep_mutex,r8), r0
+       cmp/eq  #-1, r0
+       bf/s    99f
+        mov    #LLL_PRIVATE, r6
+       mov     #LLL_SHARED, r6
+99:
+       extu.b  r6, r6
+       mov.l   .Lwait3, r1
+       bsrf    r1
+        mov    r2, r4
+.Lwait3b:
+
+1:
+       mov.l   @(broadcast_seq,r8), r0
+       mov.l   @(4,r15), r1
+       cmp/eq  r0, r1
+       bf      3f
+
+       mov     #1, r2
+       mov     #0, r3
+
+       /* We increment the wakeup_seq counter only if it is lower than
+          total_seq.  If this is not the case the thread was woken and
+          then canceled.  In this case we ignore the signal.  */
+       mov.l   @(total_seq+4,r8), r0
+       mov.l   @(wakeup_seq+4,r8), r1
+       cmp/hi  r1, r0
+       bt/s    6f
+        cmp/hi r0, r1
+       bt      7f
+       mov.l   @(total_seq,r8), r0
+       mov.l   @(wakeup_seq,r8), r1
+       cmp/hs  r0, r1
+       bt      7f
+
+6:
+       clrt
+       mov.l   @(wakeup_seq,r8),r0
+       mov.l   @(wakeup_seq+4,r8),r1
+       addc    r2, r0
+       addc    r3, r1
+       mov.l   r0,@(wakeup_seq,r8)
+       mov.l   r1,@(wakeup_seq+4,r8)
+       mov.l   @(cond_futex,r8),r0
+       add     r2, r0
+       mov.l   r0,@(cond_futex,r8)
+
+7:
+       clrt
+       mov.l   @(woken_seq,r8),r0
+       mov.l   @(woken_seq+4,r8),r1
+       addc    r2, r0
+       addc    r3, r1
+       mov.l   r0,@(woken_seq,r8)
+       mov.l   r1,@(woken_seq+4,r8)
+
+3:
+       mov     #(1 << nwaiters_shift), r2
+       mov.l   @(cond_nwaiters,r8),r0
+       sub     r2, r0
+       mov.l   r0,@(cond_nwaiters,r8)
+
+       /* Wake up a thread which wants to destroy the condvar object.  */
+       mov     #0, r10
+       mov.l   @(total_seq,r8),r0
+       mov.l   @(total_seq+4,r8),r1
+       and     r1, r0
+       not     r0, r0
+       cmp/eq  #0, r0
+       bf/s    4f
+        mov    #((1 << nwaiters_shift) - 1), r1
+       not     r1, r1
+       mov.l   @(cond_nwaiters,r8),r0
+       tst     r1, r0
+       bf      4f
+
+       mov     r8, r4
+       add     #cond_nwaiters, r4
+       mov.l   @(dep_mutex,r8), r0
+       cmp/eq  #-1, r0
+       bt/s    99f
+        mov    #FUTEX_WAKE, r5
+#ifdef __ASSUME_PRIVATE_FUTEX
+       mov     #(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), r5
+       extu.b  r5, r5
+#else
+       stc     gbr, r1
+       mov.w   .Lpfoff1, r2
+       add     r2, r1
+       mov.l   @r1, r5
+       mov     #FUTEX_WAKE, r0
+       or      r0, r5
+#endif
+99:
+       mov     #1, r6
+       mov     #0, r7
+       mov     #SYS_futex, r3
+       extu.b  r3, r3
+       trapa   #0x14
+       SYSCALL_INST_PAD
+       mov     #1, r10
+
+4:
+#if cond_lock != 0
+       DEC (@(cond_lock,r8), r2)
+#else
+       DEC (@r8, r2)
+#endif
+       tst     r2, r2
+       bt      2f
+
+       mov     r8, r4
+#if cond_lock != 0
+       add     #cond_lock, r4
+#endif
+       mov.l   @(dep_mutex,r8), r0
+       cmp/eq  #-1, r0
+       bf/s    99f
+        mov    #LLL_PRIVATE, r5
+       mov     #LLL_SHARED, r5
+99:
+       mov.l   .Lwake3, r1
+       bsrf    r1
+        extu.b r5, r5
+.Lwake3b:
+
+2:
+       /* Wake up all waiters to make sure no signal gets lost.  */
+       tst     r10, r10
+       bf/s    5f
+        mov    r8, r4
+       add     #cond_futex, r4
+       mov.l   @(dep_mutex,r8), r0
+       cmp/eq  #-1, r0
+       bt/s    99f
+        mov    #FUTEX_WAKE, r5
+#ifdef __ASSUME_PRIVATE_FUTEX
+       mov     #(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), r5
+       extu.b  r5, r5
+#else
+       stc     gbr, r1
+       mov.w   .Lpfoff1, r2
+       add     r2, r1
+       mov.l   @r1, r5
+       mov     #FUTEX_WAKE, r0
+       or      r0, r5
+#endif
+99:
+       mov     #-1, r6
+       shlr    r6              /* r6 = 0x7fffffff */
+       mov     #0, r7
+       mov     #SYS_futex, r3
+       extu.b  r3, r3
+       trapa   #0x14
+       SYSCALL_INST_PAD
+
+5:
+        mov.l   .Lmlocki3, r1
+        bsrf    r1
+         mov     r9, r4
+.Lmlocki3b:
+
+.LcallUR:
+       mov.l   .Lresume, r1
+#ifdef __PIC__
+       add     r12, r1
+#endif
+       jsr     @r1
+        mov    r11, r4
+       sleep
+
+#ifndef __ASSUME_PRIVATE_FUTEX
+.Lpfoff1:
+       .word   PRIVATE_FUTEX - TLS_PRE_TCB_SIZE
+#endif
+       .align  2
+.Lwait3:
+       .long   __lll_lock_wait-.Lwait3b
+.Lwake3:
+        .long   __lll_unlock_wake-.Lwake3b
+.Lmlocki3:
+       .long   __pthread_mutex_cond_lock-.Lmlocki3b
+.Lresume:
+#ifdef __PIC__
+       .long   _Unwind_Resume@GOTOFF
+#else
+       .long   _Unwind_Resume
+#endif
+.LENDCODE:
+       .size   __condvar_w_cleanup, .-__condvar_w_cleanup
+
+
+       .section .gcc_except_table,"a",@progbits
+.LexceptSTART:
+       .byte   0xff                            ! @LPStart format (omit)
+       .byte   0xff                            ! @TType format (omit)
+       .byte   0x0b                            ! call-site format
+                                               ! DW_EH_PE_sdata4
+       .uleb128 .Lcstend-.Lcstbegin
+.Lcstbegin:
+       .ualong .LcleanupSTART-.LSTARTCODE
+       .ualong .LcleanupEND-.LcleanupSTART
+       .ualong __condvar_w_cleanup-.LSTARTCODE
+       .uleb128  0
+       .ualong .LcallUR-.LSTARTCODE
+       .ualong .LENDCODE-.LcallUR
+       .ualong 0
+       .uleb128  0
+.Lcstend:
+
+       .section .eh_frame,"a",@progbits
+.LSTARTFRAME:
+       .ualong .LENDCIE-.LSTARTCIE             ! Length of the CIE.
+.LSTARTCIE:
+       .ualong 0                               ! CIE ID.
+       .byte   1                               ! Version number.
+#ifdef SHARED
+       .string "zPLR"                          ! NUL-terminated augmentation
+                                               ! string.
+#else
+       .string "zPL"                           ! NUL-terminated augmentation
+                                               ! string.
+#endif
+       .uleb128 1                              ! Code alignment factor.
+       .sleb128 -4                             ! Data alignment factor.
+       .byte   0x11                            ! Return address register
+                                               ! column.
+#ifdef SHARED
+       .uleb128 7                              ! Augmentation value length.
+       .byte   0x9b                            ! Personality: DW_EH_PE_pcrel
+                                               ! + DW_EH_PE_sdata4
+                                               ! + DW_EH_PE_indirect
+       .ualong DW.ref.__gcc_personality_v0-.
+       .byte   0x1b                            ! LSDA Encoding: DW_EH_PE_pcrel
+                                               ! + DW_EH_PE_sdata4.
+       .byte   0x1b                            ! FDE Encoding: DW_EH_PE_pcrel
+                                               ! + DW_EH_PE_sdata4.
+#else
+       .uleb128 6                              ! Augmentation value length.
+       .byte   0x0                             ! Personality: absolute
+       .ualong __gcc_personality_v0
+       .byte   0x0                             ! LSDA Encoding: absolute
+#endif
+       .byte 0x0c                              ! DW_CFA_def_cfa
+       .uleb128 0xf
+       .uleb128 0
+       .align 2
+.LENDCIE:
+
+       .ualong .LENDFDE-.LSTARTFDE             ! Length of the FDE.
+.LSTARTFDE:
+       .ualong .LSTARTFDE-.LSTARTFRAME         ! CIE pointer.
+#ifdef SHARED
+       .ualong .LSTARTCODE-.                   ! PC-relative start address
+                                               ! of the code.
+#else
+       .ualong .LSTARTCODE                     ! Start address of the code.
+#endif
+       .ualong .LENDCODE-.LSTARTCODE           ! Length of the code.
+       .uleb128 4                              ! Augmentation size
+#ifdef SHARED
+       .ualong .LexceptSTART-.
+#else
+       .ualong .LexceptSTART
+#endif
+       .byte   0x4
+       .ualong .Lpush_r8-.LSTARTCODE
+       .byte   0xe
+       .uleb128 4
+       .byte   0x88
+       .uleb128 1
+       .byte   0x4
+       .ualong .Lpush_r9-.Lpush_r8
+       .byte   0xe
+       .uleb128 8
+       .byte   0x89
+       .uleb128 2
+       .byte   0x4
+       .ualong .Lpush_r10-.Lpush_r9
+       .byte   0xe
+       .uleb128 12
+       .byte   0x8a
+       .uleb128 3
+       .byte   0x4
+       .ualong .Lpush_r11-.Lpush_r10
+       .byte   0xe
+       .uleb128 16
+       .byte   0x8b
+       .uleb128 4
+       .byte   0x4
+       .ualong .Lpush_r12-.Lpush_r11
+       .byte   0xe
+       .uleb128 20
+       .byte   0x8c
+       .uleb128 5
+       .byte   0x4
+       .ualong .Lpush_pr-.Lpush_r12
+       .byte   0xe
+       .uleb128 24
+       .byte   0x91
+       .uleb128 6
+       .byte   0x4
+       .ualong .Lalloc-.Lpush_pr
+       .byte   0xe
+       .uleb128 72
+       .align  2
+.LENDFDE:
+
+#ifdef SHARED
+       .hidden DW.ref.__gcc_personality_v0
+       .weak   DW.ref.__gcc_personality_v0
+       .section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits
+       .align 4
+       .type   DW.ref.__gcc_personality_v0, @object
+       .size   DW.ref.__gcc_personality_v0, 4
+DW.ref.__gcc_personality_v0:
+       .long   __gcc_personality_v0
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_once.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_once.S
new file mode 100644 (file)
index 0000000..a1477b3
--- /dev/null
@@ -0,0 +1,262 @@
+/* Copyright (C) 2003, 2004, 2007 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 <unwindbuf.h>
+#include <sysdep.h>
+#include <bits/kernel-features.h>
+#include <lowlevellock.h>
+#include <tcb-offsets.h>
+#include "lowlevel-atomic.h"
+
+
+       .comm   __fork_generation, 4, 4
+
+       .text
+       .globl  __pthread_once
+       .type   __pthread_once,@function
+       .align  5
+       cfi_startproc
+__pthread_once:
+       mov.l   @r4, r0
+       tst     #2, r0
+       bt      1f
+       rts
+        mov    #0, r0
+
+1:
+       mov.l   r12, @-r15
+       cfi_adjust_cfa_offset (4)
+       cfi_rel_offset (r12, 0)
+       mov.l   r9, @-r15
+       cfi_adjust_cfa_offset (4)
+       cfi_rel_offset (r9, 0)
+       mov.l   r8, @-r15
+       cfi_adjust_cfa_offset (4)
+       cfi_rel_offset (r8, 0)
+       sts.l   pr, @-r15
+       cfi_adjust_cfa_offset (4)
+       cfi_rel_offset (pr, 0)
+       mov     r5, r8
+       mov     r4, r9
+
+       /* Not yet initialized or initialization in progress.
+          Get the fork generation counter now.  */
+6:
+       mov.l   @r4, r1
+       mova    .Lgot, r0
+       mov.l   .Lgot, r12
+       add     r0, r12
+
+5:
+       mov     r1, r0
+
+       tst     #2, r0
+       bf      4f
+
+       and     #3, r0
+       mov.l   .Lfgen, r2
+#ifdef __PIC__
+       add     r12, r2
+#endif
+       mov.l   @r2, r3
+       or      r3, r0
+       or      #1, r0
+       mov     r0, r3
+       mov     r1, r5
+
+       CMPXCHG (r5, @r4, r3, r2)
+       bf      5b
+
+       /* Check whether another thread already runs the initializer.  */
+       mov     r2, r0
+       tst     #1, r0
+       bt      3f      /* No -> do it.  */
+
+       /* Check whether the initializer execution was interrupted
+          by a fork.  */
+       xor     r3, r0
+       mov     #-4, r1 /* -4 = 0xfffffffc */
+       tst     r1, r0
+       bf      3f      /* Different for generation -> run initializer.  */
+
+       /* Somebody else got here first.  Wait.  */
+#ifdef __ASSUME_PRIVATE_FUTEX
+       mov     #(FUTEX_PRIVATE_FLAG|FUTEX_WAIT), r5
+       extu.b  r5, r5
+#else
+       stc     gbr, r1
+       mov.w   .Lpfoff, r2
+       add     r2, r1
+       mov.l   @r1, r5
+# if FUTEX_WAIT != 0
+       mov     #FUTEX_WAIT, r0
+       or      r0, r5
+# endif
+#endif
+       mov     r3, r6
+       mov     #0, r7
+       mov     #SYS_futex, r3
+       extu.b  r3, r3
+       trapa   #0x14
+       SYSCALL_INST_PAD
+       bra     6b
+        nop
+
+       .align  2
+.Lgot:
+       .long   _GLOBAL_OFFSET_TABLE_
+#ifdef __PIC__
+.Lfgen:
+       .long   __fork_generation@GOTOFF
+#else
+.Lfgen:
+       .long   __fork_generation
+#endif
+
+3:
+       /* Call the initializer function after setting up the
+          cancellation handler.  Note that it is not possible here
+          to use the unwind-based cleanup handling.  This would require
+          that the user-provided function and all the code it calls
+          is compiled with exceptions.  Unfortunately this cannot be
+          guaranteed.  */
+       add     #-UNWINDBUFSIZE, r15
+       cfi_adjust_cfa_offset (UNWINDBUFSIZE)
+
+       mov.l   .Lsigsetjmp, r1
+       mov     #UWJMPBUF, r4
+       add     r15, r4
+       bsrf    r1
+        mov    #0, r5
+.Lsigsetjmp0:
+       tst     r0, r0
+       bf      7f
+
+       mov.l   .Lcpush, r1
+       bsrf    r1
+        mov    r15, r4
+.Lcpush0:
+
+       /* Call the user-provided initialization function.  */
+       jsr     @r8
+        nop
+
+       /* Pop the cleanup handler.  */
+       mov.l   .Lcpop, r1
+       bsrf    r1
+        mov    r15, r4
+.Lcpop0:
+
+       add     #UNWINDBUFSIZE, r15
+       cfi_adjust_cfa_offset (-UNWINDBUFSIZE)
+
+       /* Sucessful run of the initializer.  Signal that we are done.  */
+       INC (@r9, r2)
+       /* Wake up all other threads.  */
+       mov     r9, r4
+#ifdef __ASSUME_PRIVATE_FUTEX
+       mov     #(FUTEX_PRIVATE_FLAG|FUTEX_WAKE), r5
+       extu.b  r5, r5
+#else
+       stc     gbr, r1
+       mov.w   .Lpfoff, r2
+       add     r2, r1
+       mov.l   @r1, r5
+       mov     #FUTEX_WAKE, r0
+       or      r0, r5
+#endif
+       mov     #-1, r6
+       shlr    r6              /* r6 = 0x7fffffff */
+       mov     #0, r7
+       mov     #SYS_futex, r3
+       extu.b  r3, r3
+       trapa   #0x14
+       SYSCALL_INST_PAD
+
+4:
+       lds.l   @r15+, pr
+       cfi_adjust_cfa_offset (-4)
+       cfi_restore (pr)
+       mov.l   @r15+, r8
+       cfi_adjust_cfa_offset (-4)
+       cfi_restore (r8)
+       mov.l   @r15+, r9
+       cfi_adjust_cfa_offset (-4)
+       cfi_restore (r9)
+       mov.l   @r15+, r12
+       cfi_adjust_cfa_offset (-4)
+       cfi_restore (r12)
+       rts
+        mov    #0, r0
+
+7:
+       /* __sigsetjmp returned for the second time.  */
+       cfi_adjust_cfa_offset (UNWINDBUFSIZE+16)
+       cfi_offset (r12, -4)
+       cfi_offset (r9, -8)
+       cfi_offset (r8, -12)
+       cfi_offset (pr, -16)
+       mov     #0, r7
+       mov.l   r7, @r9
+       mov     r9, r4
+#ifdef __ASSUME_PRIVATE_FUTEX
+       mov     #(FUTEX_PRIVATE_FLAG|FUTEX_WAKE), r5
+#else
+       stc     gbr, r1
+       mov.w   .Lpfoff, r2
+       add     r2, r1
+       mov.l   @r1, r5
+       mov     #FUTEX_WAKE, r0
+       or      r0, r5
+#endif
+       extu.b  r5, r5
+       mov     #-1, r6
+       shlr    r6              /* r6 = 0x7fffffff */
+       mov     #SYS_futex, r3
+       extu.b  r3, r3
+       trapa   #0x14
+       SYSCALL_INST_PAD
+
+       mov.l   .Lunext, r1
+       bsrf    r1
+        mov    r15, r4
+.Lunext0:
+       /* NOTREACHED */
+       sleep
+       cfi_endproc
+
+#ifndef __ASSUME_PRIVATE_FUTEX
+.Lpfoff:
+       .word   PRIVATE_FUTEX - TLS_PRE_TCB_SIZE
+#endif
+       .align  2
+.Lsigsetjmp:
+       .long   __sigsetjmp@PLT-(.Lsigsetjmp0-.)
+.Lcpush:
+       .long   HIDDEN_JUMPTARGET(__pthread_register_cancel)-.Lcpush0
+.Lcpop:
+       .long   HIDDEN_JUMPTARGET(__pthread_unregister_cancel)-.Lcpop0
+.Lunext:
+       .long   HIDDEN_JUMPTARGET(__pthread_unwind_next)-.Lunext0
+       .size   __pthread_once,.-__pthread_once
+
+       .globl  __pthread_once_internal
+__pthread_once_internal = __pthread_once
+
+       .globl  pthread_once
+pthread_once = __pthread_once
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_rdlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_rdlock.S
new file mode 100644 (file)
index 0000000..52fe5de
--- /dev/null
@@ -0,0 +1,254 @@
+/* Copyright (C) 2003, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <lowlevelrwlock.h>
+#include <pthread-errnos.h>
+#include <tcb-offsets.h>
+#include <bits/kernel-features.h>
+#include "lowlevel-atomic.h"
+
+
+       .text
+
+       .globl  __pthread_rwlock_rdlock
+       .type   __pthread_rwlock_rdlock,@function
+       .align  5
+__pthread_rwlock_rdlock:
+       mov.l   r12, @-r15
+       mov.l   r9, @-r15
+       mov.l   r8, @-r15
+       sts.l   pr, @-r15
+       mov     r4, r8
+
+       /* Get the lock.  */
+       mov     #0, r3
+       mov     #1, r4
+#if MUTEX == 0
+       CMPXCHG (r3, @r8, r4, r2)
+#else
+       CMPXCHG (r3, @(MUTEX,r8), r4, r2)
+#endif
+       bf      1f
+2:
+       mov.l   @(WRITER,r8), r0
+       tst     r0, r0
+       bf      14f
+       mov.l   @(WRITERS_QUEUED,r8), r0
+       tst     r0, r0
+       bt      5f
+       mov     #FLAGS, r0
+       mov.b   @(r0,r8), r0
+       tst     r0, r0
+       bt      5f
+3:
+       mov.l   @(READERS_QUEUED,r8), r0
+       add     #1, r0
+       mov.l   r0, @(READERS_QUEUED,r8)
+       tst     r0, r0
+       bt      4f
+
+       mov.l   @(READERS_WAKEUP,r8), r9
+
+#if MUTEX == 0
+       DEC (@r8, r2)
+#else
+       DEC (@(MUTEX,r8), r2)
+#endif
+       tst     r2, r2
+       bf      10f
+11:
+#ifdef __ASSUME_PRIVATE_FUTEX
+       mov     #PSHARED, r0
+       mov.b   @(r0,r8), r5
+       mov     #(FUTEX_PRIVATE_FLAG|FUTEX_WAIT), r0
+       xor     r0, r5
+       extu.b  r5, r5
+#else
+       mov     #PSHARED, r0
+       mov.b   @(r0,r8), r5
+       extu.b  r5, r5
+# if FUTEX_WAIT != 0
+       mov     #FUTEX_WAIT, r0
+       or      r0, r5
+# endif
+       stc     gbr, r1
+       mov.w   .Lpfoff, r2
+       add     r2, r1
+       mov.l   @r1, r0
+       xor     r0, r5
+#endif
+       mov     r8, r4
+       add     #READERS_WAKEUP, r4
+       mov     r9, r6
+       mov     #0, r7
+       mov     #SYS_futex, r3
+       extu.b  r3, r3
+       trapa   #0x14
+       SYSCALL_INST_PAD
+
+       /* Reget the lock.  */
+       mov     #0, r3
+       mov     #1, r4
+#if MUTEX == 0
+       CMPXCHG (r3, @r8, r4, r2)
+#else
+       CMPXCHG (r3, @(MUTEX,r8), r4, r2)
+#endif
+       bf      12f
+13:
+       mov.l   @(READERS_QUEUED,r8), r0
+       add     #-1, r0
+       bra     2b
+        mov.l  r0, @(READERS_QUEUED,r8)
+
+5:
+       mov     #0, r3
+       mov.l   @(NR_READERS,r8), r0
+       add     #1, r0
+       mov.l   r0, @(NR_READERS,r8)
+       tst     r0, r0
+       bt      8f
+
+9:
+#if MUTEX == 0
+       DEC (@r8, r2)
+#else
+       DEC (@(MUTEX,r8), r2)
+#endif
+       tst     r2, r2
+       bf      6f
+7:
+       lds.l   @r15+, pr
+       mov.l   @r15+, r8
+       mov.l   @r15+, r9
+       mov.l   @r15+, r12
+       rts
+        mov    r3, r0
+
+#ifndef __ASSUME_PRIVATE_FUTEX
+.Lpfoff:
+       .word   PRIVATE_FUTEX - TLS_PRE_TCB_SIZE
+#endif
+
+1:
+       mov     r8, r5
+#if MUTEX != 0
+       add     #MUTEX, r5
+#endif
+       mov     #PSHARED, r0
+       mov.b   @(r0,r8), r6
+       extu.b  r6, r6
+       mov.l   .Lwait0, r1
+       bsrf    r1
+        mov    r2, r4
+.Lwait0b:
+       bra     2b
+        nop
+14:
+       stc     gbr, r1
+       mov.w   .Ltidoff, r2
+       add     r2, r1
+       mov.l   @r1, r1
+       cmp/eq  r1, r0
+       bf      3b
+       /* Deadlock detected.  */
+       bra     9b
+        mov    #EDEADLK, r3
+
+.Ltidoff:
+       .word   TID - TLS_PRE_TCB_SIZE
+
+6:
+       mov     r8, r4
+#if MUTEX != 0
+       add     #MUTEX, r4
+#endif
+       mov     #PSHARED, r0
+       mov.b   @(r0,r8), r5
+       extu.b  r5, r5
+       mov.l   .Lwake0, r1
+       bsrf    r1
+        nop
+.Lwake0b:
+       bra     7b
+        mov    #0, r3
+
+8:
+       /* Overflow.  */
+       mov.l   @(NR_READERS,r8), r1
+       add     #-1, r1
+       mov.l   r1, @(NR_READERS,r8)
+       bra     9b
+        mov    #EAGAIN, r3
+
+4:
+       /* Overflow.  */
+       mov.l   @(READERS_QUEUED,r8), r1
+       add     #-1, r1
+       mov.l   r1, @(READERS_QUEUED,r8)
+       bra     9b
+        mov    #EAGAIN, r3
+
+10:
+       mov     r8, r4
+#if MUTEX != 0
+       add     #MUTEX, r4
+#endif
+       mov     #PSHARED, r0
+       mov.b   @(r0,r8), r5
+       extu.b  r5, r5
+       mov.l   .Lwake1, r1
+       bsrf    r1
+        nop
+.Lwake1b:
+       bra     11b
+        nop
+
+12:
+       mov     r8, r5
+#if MUTEX != 0
+       add     #MUTEX, r5
+#endif
+       mov     #PSHARED, r0
+       mov.b   @(r0,r8), r6
+       extu.b  r6, r6
+       mov.l   .Lwait1, r1
+       bsrf    r1
+        mov    r2, r4
+.Lwait1b:
+       bra     13b
+        nop
+
+       .align  2
+.Lwait0:
+       .long   __lll_lock_wait-.Lwait0b
+.Lwake0:
+       .long   __lll_unlock_wake-.Lwake0b
+.Lwait1:
+       .long   __lll_lock_wait-.Lwait1b
+.Lwake1:
+       .long   __lll_unlock_wake-.Lwake1b
+       .size   __pthread_rwlock_rdlock,.-__pthread_rwlock_rdlock
+
+       .globl  pthread_rwlock_rdlock
+pthread_rwlock_rdlock = __pthread_rwlock_rdlock
+
+       .globl  __pthread_rwlock_rdlock_internal
+__pthread_rwlock_rdlock_internal = __pthread_rwlock_rdlock
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedrdlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedrdlock.S
new file mode 100644 (file)
index 0000000..6e7af21
--- /dev/null
@@ -0,0 +1,314 @@
+/* Copyright (C) 2003, 2007, 2008 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <lowlevelrwlock.h>
+#include <pthread-errnos.h>
+#include <tcb-offsets.h>
+#include <bits/kernel-features.h>
+#include "lowlevel-atomic.h"
+
+
+       .text
+
+       .globl  pthread_rwlock_timedrdlock
+       .type   pthread_rwlock_timedrdlock,@function
+       .align  5
+pthread_rwlock_timedrdlock:
+       mov.l   r12, @-r15
+       mov.l   r10, @-r15
+       mov.l   r9, @-r15
+       mov.l   r8, @-r15
+       sts.l   pr, @-r15
+       add     #-8, r15
+       mov     r4, r8
+       mov     r5, r9
+
+       /* Get the lock.  */
+       mov     #0, r3
+       mov     #1, r4
+#if MUTEX == 0
+       CMPXCHG (r3, @r8, r4, r2)
+#else
+       CMPXCHG (r3, @(MUTEX,r8), r4, r2)
+#endif
+       bf      1f
+2:
+       mov.l   @(WRITER,r8), r0
+       tst     r0, r0
+       bf      14f
+       mov.l   @(WRITERS_QUEUED,r8), r0
+       tst     r0, r0
+       bt      5f
+       mov     #FLAGS, r0
+       mov.b   @(r0,r8), r0
+       tst     r0, r0
+       bt      5f
+3:
+       /* Check the value of the timeout parameter.  */
+       mov.l   .L1g0, r1
+       mov.l   @(4,r9), r0
+       cmp/hs  r1, r0
+       bt      19f
+
+       mov.l   @(READERS_QUEUED,r8), r0
+       add     #1, r0
+       mov.l   r0, @(READERS_QUEUED,r8)
+       tst     r0, r0
+       bt      4f
+
+       mov.l   @(READERS_WAKEUP,r8), r10
+
+#if MUTEX == 0
+       DEC (@r8, r2)
+#else
+       DEC (@(MUTEX,r8), r2)
+#endif
+       tst     r2, r2
+       bf      10f
+
+11:
+       /* Get current time.  */
+       mov     r15, r4
+       mov     #0, r5
+       mov     #__NR_gettimeofday, r3
+       trapa   #0x12
+       SYSCALL_INST_PAD
+
+       mov.l   @(4,r15), r0
+       mov.w   .L1k0, r1
+       dmulu.l r0, r1          /* Milli seconds to nano seconds.  */
+       mov.l   @r9, r2
+       mov.l   @(4,r9), r3
+       mov.l   @r15, r0
+       sts     macl, r1
+       sub     r0, r2
+       clrt
+       subc    r1, r3
+       bf      15f
+       mov.l   .L1g0, r1
+       add     r1, r3
+       add     #-1, r2
+15:
+       cmp/pz  r2
+       bf      16f             /* Time is already up.  */
+
+       /* Store relative timeout.  */
+       mov.l   r2, @r15
+       mov.l   r3, @(4,r15)
+
+       /* Futex call.  */
+       mov     r15, r7
+#ifdef __ASSUME_PRIVATE_FUTEX
+       mov     #PSHARED, r0
+       mov.b   @(r0,r8), r5
+       mov     #(FUTEX_PRIVATE_FLAG|FUTEX_WAIT), r0
+       xor     r0, r5
+       extu.b  r5, r5
+#else
+       mov     #PSHARED, r0
+       mov.b   @(r0,r8), r5
+       extu.b  r5, r5
+# if FUTEX_WAIT != 0
+       mov     #FUTEX_WAIT, r0
+       or      r0, r5
+# endif
+       stc     gbr, r1
+       mov.w   .Lpfoff, r2
+       add     r2, r1
+       mov.l   @r1, r0
+       xor     r0, r5
+#endif
+       mov     r10, r6
+       mov     r8, r4
+       add     #READERS_WAKEUP, r4
+       mov     #SYS_futex, r3
+       extu.b  r3, r3
+       trapa   #0x14
+       SYSCALL_INST_PAD
+       mov     r0, r3
+
+17:
+       /* Reget the lock.  */
+       mov     #0, r5
+       mov     #1, r4
+#if MUTEX == 0
+       CMPXCHG (r5, @r8, r4, r2)
+#else
+       CMPXCHG (r5, @(MUTEX,r8), r4, r2)
+#endif
+       bf      12f
+
+13:
+       mov.l   @(READERS_QUEUED,r8), r0
+       add     #-1, r0
+       mov.l   r0, @(READERS_QUEUED,r8)
+       mov     #-ETIMEDOUT, r0
+       cmp/eq  r0, r3
+       bf      2b
+
+18:
+       bra     9f
+        mov    #ETIMEDOUT, r3
+
+5:
+       mov     #0, r3
+       mov.l   @(NR_READERS,r8), r0
+       add     #1, r0
+       mov.l   r0, @(NR_READERS,r8)
+       tst     r0, r0
+       bt      8f
+
+9:
+#if MUTEX == 0
+       DEC (@r8, r2)
+#else
+       DEC (@(MUTEX,r8), r2)
+#endif
+       tst     r2, r2
+       bf      6f
+7:
+       add     #8,r15
+       lds.l   @r15+, pr
+       mov.l   @r15+, r8
+       mov.l   @r15+, r9
+       mov.l   @r15+, r10
+       mov.l   @r15+, r12
+       rts
+        mov    r3, r0
+
+#ifndef __ASSUME_PRIVATE_FUTEX
+.Lpfoff:
+       .word   PRIVATE_FUTEX - TLS_PRE_TCB_SIZE
+#endif
+       .align  2
+.L1k0:
+       .long   1000
+.L1g0:
+       .long   1000000000
+
+1:
+       mov     r8, r5
+#if MUTEX != 0
+       add     #MUTEX, r5
+#endif
+       mov     #PSHARED, r0
+       mov.b   @(r0,r8), r6
+       extu.b  r6, r6
+       mov.l   .Lwait2, r1
+       bsrf    r1
+        mov    r2, r4
+.Lwait2b:
+       bra     2b
+        nop
+14:
+       stc     gbr, r1
+       mov.w   .Ltidoff, r2
+       add     r2, r1
+       mov.l   @r1, r1
+       cmp/eq  r1, r0
+       bf      3b
+       /* Deadlock detected.  */
+       bra     9b
+        mov    #EDEADLK, r3
+
+.Ltidoff:
+       .word   TID - TLS_PRE_TCB_SIZE
+
+6:
+       mov     r3, r10
+       mov     r8, r4
+#if MUTEX != 0
+       add     #MUTEX, r4
+#endif
+       mov     #PSHARED, r0
+       mov.b   @(r0,r8), r5
+       extu.b  r5, r5
+       mov.l   .Lwake2, r1
+       bsrf    r1
+        nop
+.Lwake2b:
+       bra     7b
+        mov    r10, r3
+
+8:
+       /* Overflow.  */
+       mov.l   @(NR_READERS,r8), r1
+       add     #-1, r1
+       mov.l   r1, @(NR_READERS,r8)
+       bra     9b
+        mov    #EAGAIN, r3
+
+4:
+       /* Overflow.  */
+       mov.l   @(READERS_QUEUED,r8), r1
+       add     #-1, r1
+       mov.l   r1, @(READERS_QUEUED,r8)
+       bra     9b
+        mov    #EAGAIN, r3
+
+10:
+       mov     r8, r4
+#if MUTEX != 0
+       add     #MUTEX, r4
+#endif
+       mov     #PSHARED, r0
+       mov.b   @(r0,r8), r5
+       extu.b  r5, r5
+       mov.l   .Lwake3, r1
+       bsrf    r1
+        nop
+.Lwake3b:
+       bra     11b
+        nop
+
+12:
+       mov     r3, r10
+       mov     r8, r5
+#if MUTEX != 0
+       add     #MUTEX, r5
+#endif
+       mov     #PSHARED, r0
+       mov.b   @(r0,r8), r6
+       extu.b  r6, r6
+       mov.l   .Lwait3, r1
+       bsrf    r1
+        mov    r2, r4
+.Lwait3b:
+       bra     13b
+        mov    r10, r3
+
+16:
+       bra     17b
+        mov    #-ETIMEDOUT, r3
+
+19:
+       bra     9b
+        mov    #EINVAL, r3
+
+       .align  2
+.Lwait2:
+       .long   __lll_lock_wait-.Lwait2b
+.Lwake2:
+       .long   __lll_unlock_wake-.Lwake2b
+.Lwait3:
+       .long   __lll_lock_wait-.Lwait3b
+.Lwake3:
+       .long   __lll_unlock_wake-.Lwake3b
+       .size   pthread_rwlock_timedrdlock,.-pthread_rwlock_timedrdlock
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedwrlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedwrlock.S
new file mode 100644 (file)
index 0000000..1cb7cbd
--- /dev/null
@@ -0,0 +1,298 @@
+/* Copyright (C) 2003, 2007, 2008 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <lowlevelrwlock.h>
+#include <pthread-errnos.h>
+#include <tcb-offsets.h>
+#include <bits/kernel-features.h>
+#include "lowlevel-atomic.h"
+
+
+       .text
+
+       .globl  pthread_rwlock_timedwrlock
+       .type   pthread_rwlock_timedwrlock,@function
+       .align  5
+pthread_rwlock_timedwrlock:
+       mov.l   r12, @-r15
+       mov.l   r10, @-r15
+       mov.l   r9, @-r15
+       mov.l   r8, @-r15
+       sts.l   pr, @-r15
+       add     #-8, r15
+       mov     r4, r8
+       mov     r5, r9
+
+       /* Get the lock.  */
+       mov     #0, r3
+       mov     #1, r4
+#if MUTEX == 0
+       CMPXCHG (r3, @r8, r4, r2)
+#else
+       CMPXCHG (r3, @(MUTEX,r8), r4, r2)
+#endif
+       bf      1f
+2:
+       mov.l   @(WRITER,r8), r0
+       tst     r0, r0
+       bf      14f
+       mov.l   @(NR_READERS,r8), r0
+       tst     r0, r0
+       bt      5f
+3:
+       /* Check the value of the timeout parameter.  */
+       mov.l   .L1g1, r1
+       mov.l   @(4,r9), r0
+       cmp/hs  r1, r0
+       bt      19f
+
+       mov.l   @(WRITERS_QUEUED,r8), r0
+       add     #1, r0
+       mov.l   r0, @(WRITERS_QUEUED,r8)
+       tst     r0, r0
+       bt      4f
+
+       mov.l   @(WRITERS_WAKEUP,r8), r10
+
+#if MUTEX == 0
+       DEC (@r8, r2)
+#else
+       DEC (@(MUTEX,r8), r2)
+#endif
+       tst     r2, r2
+       bf      10f
+
+11:
+       /* Get current time.  */
+       mov     r15, r4
+       mov     #0, r5
+       mov     #__NR_gettimeofday, r3
+       trapa   #0x12
+       SYSCALL_INST_PAD
+
+       mov.l   @(4,r15), r0
+       mov.w   .L1k1, r1
+       dmulu.l r0, r1          /* Milli seconds to nano seconds.  */
+       mov.l   @r9, r2
+       mov.l   @(4,r9), r3
+       mov.l   @r15, r0
+       sts     macl, r1
+       sub     r0, r2
+       clrt
+       subc    r1, r3
+       bf      15f
+       mov.l   .L1g1, r1
+       add     r1, r3
+       add     #-1, r2
+15:
+       cmp/pz  r2
+       bf      16f             /* Time is already up.  */
+
+       /* Store relative timeout.  */
+       mov.l   r2, @r15
+       mov.l   r3, @(4,r15)
+
+       /* Futex call.  */
+       mov     r15, r7
+#ifdef __ASSUME_PRIVATE_FUTEX
+       mov     #PSHARED, r0
+       mov.b   @(r0,r8), r5
+       mov     #(FUTEX_PRIVATE_FLAG|FUTEX_WAIT), r0
+       xor     r0, r5
+       extu.b  r5, r5
+#else
+       mov     #PSHARED, r0
+       mov.b   @(r0,r8), r5
+       extu.b  r5, r5
+# if FUTEX_WAIT != 0
+       mov     #FUTEX_WAIT, r0
+       or      r0, r5
+# endif
+       stc     gbr, r1
+       mov.w   .Lpfoff, r2
+       add     r2, r1
+       mov.l   @r1, r0
+       xor     r0, r5
+#endif
+       mov     r10, r6
+       mov     r8, r4
+       add     #WRITERS_WAKEUP, r4
+       mov     #SYS_futex, r3
+       extu.b  r3, r3
+       trapa   #0x14
+       SYSCALL_INST_PAD
+       mov     r0, r3
+
+17:
+       /* Reget the lock.  */
+       mov     #0, r5
+       mov     #1, r4
+#if MUTEX == 0
+       CMPXCHG (r5, @r8, r4, r2)
+#else
+       CMPXCHG (r5, @(MUTEX,r8), r4, r2)
+#endif
+       bf      12f
+
+13:
+       mov.l   @(WRITERS_QUEUED,r8), r0
+       add     #-1, r0
+       mov.l   r0, @(WRITERS_QUEUED,r8)
+       mov     #-ETIMEDOUT, r0
+       cmp/eq  r0, r3
+       bf      2b
+
+18:
+       bra     9f
+        mov    #ETIMEDOUT, r3
+
+19:
+       bra     9f
+        mov    #EINVAL, r3
+
+5:
+       mov     #0, r3
+       stc     gbr, r0
+       mov.w   .Ltidoff, r1
+       mov.l   @(r0,r1), r0
+       mov.l   r0, @(WRITER,r8)
+9:
+#if MUTEX == 0
+       DEC (@r8, r2)
+#else
+       DEC (@(MUTEX,r8), r2)
+#endif
+       tst     r2, r2
+       bf      6f
+7:
+       add     #8,r15
+       lds.l   @r15+, pr
+       mov.l   @r15+, r8
+       mov.l   @r15+, r9
+       mov.l   @r15+, r10
+       mov.l   @r15+, r12
+       rts
+        mov    r3, r0
+
+#ifndef __ASSUME_PRIVATE_FUTEX
+.Lpfoff:
+       .word   PRIVATE_FUTEX - TLS_PRE_TCB_SIZE
+#endif
+.L1k1:
+       .word   1000
+       .align  2
+.L1g1:
+       .long   1000000000
+
+1:
+       mov     r8, r5
+#if MUTEX != 0
+       add     #MUTEX, r5
+#endif
+       mov     #PSHARED, r0
+       mov.b   @(r0,r8), r6
+       extu.b  r6, r6
+       mov.l   .Lwait6, r1
+       bsrf    r1
+        mov    r2, r4
+.Lwait6b:
+       bra     2b
+        nop
+14:
+       stc     gbr, r1
+       mov.w   .Ltidoff, r2
+       add     r2, r1
+       mov.l   @r1, r1
+       cmp/eq  r1, r0
+       bf      3b
+       bra     9b
+        mov    #EDEADLK, r3
+6:
+       mov     r3, r10
+       mov     r8, r4
+#if MUTEX != 0
+       add     #MUTEX, r4
+#endif
+       mov     #PSHARED, r0
+       mov.b   @(r0,r8), r5
+       extu.b  r5, r5
+       mov.l   .Lwake6, r1
+       bsrf    r1
+        nop
+.Lwake6b:
+       bra     7b
+        mov    r10, r3
+
+.Ltidoff:
+       .word   TID - TLS_PRE_TCB_SIZE
+
+4:
+       /* Overflow.  */
+       mov.l   @(WRITERS_QUEUED,r8), r1
+       add     #-1, r1
+       mov.l   r1, @(WRITERS_QUEUED,r8)
+       bra     9b
+        mov    #EAGAIN, r3
+
+10:
+       mov     r8, r4
+#if MUTEX != 0
+       add     #MUTEX, r4
+#endif
+       mov     #PSHARED, r0
+       mov.b   @(r0,r8), r5
+       extu.b  r5, r5
+       mov.l   .Lwake7, r1
+       bsrf    r1
+        nop
+.Lwake7b:
+       bra     11b
+        nop
+
+12:
+       mov     r3, r10
+       mov     r8, r5
+#if MUTEX != 0
+       add     #MUTEX, r5
+#endif
+       mov     #PSHARED, r0
+       mov.b   @(r0,r8), r6
+       extu.b  r6, r6
+       mov.l   .Lwait7, r1
+       bsrf    r1
+        mov    r2, r4
+.Lwait7b:
+       bra     13b
+        mov    r10, r3
+
+16:
+       bra     17b
+        mov    #-ETIMEDOUT, r3
+
+       .align  2
+.Lwait6:
+       .long   __lll_lock_wait-.Lwait6b
+.Lwake6:
+       .long   __lll_unlock_wake-.Lwake6b
+.Lwait7:
+       .long   __lll_lock_wait-.Lwait7b
+.Lwake7:
+       .long   __lll_unlock_wake-.Lwake7b
+       .size   pthread_rwlock_timedwrlock,.-pthread_rwlock_timedwrlock
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_unlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_unlock.S
new file mode 100644 (file)
index 0000000..bc6c6c2
--- /dev/null
@@ -0,0 +1,198 @@
+/* Copyright (C) 2003, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <lowlevelrwlock.h>
+#include <bits/kernel-features.h>
+#include <tcb-offsets.h>
+#include "lowlevel-atomic.h"
+
+
+       .text
+
+       .globl  __pthread_rwlock_unlock
+       .type   __pthread_rwlock_unlock,@function
+       .align  5
+__pthread_rwlock_unlock:
+       mov.l   r12, @-r15
+       mov.l   r8, @-r15
+       sts.l   pr, @-r15
+       mov     r4, r8
+
+       /* Get the lock.  */
+       mov     #0, r3
+       mov     #1, r4
+#if MUTEX == 0
+       CMPXCHG (r3, @r8, r4, r2)
+#else
+       CMPXCHG (r3, @(MUTEX,r8), r4, r2)
+#endif
+       bf      1f
+2:
+       mov.l   @(WRITER,r8), r0
+       tst     r0, r0
+       bf      5f
+       mov.l   @(NR_READERS,r8), r0
+       add     #-1, r0
+       mov.l   r0, @(NR_READERS,r8)
+       tst     r0, r0
+       bf      6f
+5:
+       mov     #0, r0
+       mov.l   r0, @(WRITER,r8)
+       mov     #1, r6
+       mov     r8, r4
+       add     #WRITERS_WAKEUP, r4
+       mov.l   @(WRITERS_QUEUED,r8), r0
+       tst     r0, r0
+       bf      0f
+
+       /* If also no readers waiting nothing to do.  */
+       mov.l   @(READERS_QUEUED,r8), r0
+       tst     r0, r0
+       bt      6f
+
+       mov     #-1, r6
+       shlr    r6              /* r6 = 0x7fffffff */
+       mov     r8, r4
+       add     #READERS_WAKEUP, r4
+
+0:
+       mov.l   @r4, r0
+       add     #1, r0
+       mov.l   r0, @r4
+#if MUTEX == 0
+       DEC (@r8, r2)
+#else
+       DEC (@(MUTEX,r8), r2)
+#endif
+       tst     r2, r2
+       bf      7f
+
+8:
+#ifdef __ASSUME_PRIVATE_FUTEX
+       mov     #PSHARED, r0
+       mov.b   @(r0,r8), r5
+       mov     #(FUTEX_PRIVATE_FLAG|FUTEX_WAKE), r0
+       xor     r0, r5
+       extu.b  r5, r5
+#else
+       mov     #PSHARED, r0
+       mov.b   @(r0,r8), r5
+       extu.b  r5, r5
+       mov     #FUTEX_WAKE, r0
+       or      r0, r5
+       stc     gbr, r1
+       mov.w   .Lpfoff, r2
+       add     r2, r1
+       mov.l   @r1, r0
+       xor     r0, r5
+#endif
+       mov     #SYS_futex, r3
+       mov     #0, r7
+       extu.b  r3, r3
+       trapa   #0x14
+       SYSCALL_INST_PAD
+
+       lds.l   @r15+, pr
+       mov.l   @r15+, r8
+       mov.l   @r15+, r12
+       rts
+        mov    #0, r0
+6:
+#if MUTEX == 0
+       DEC (@r8, r2)
+#else
+       DEC (@(MUTEX,r8), r2)
+#endif
+       tst     r2, r2
+       bf      3f
+4:
+       lds.l   @r15+, pr
+       mov.l   @r15+, r8
+       mov.l   @r15+, r12
+       rts
+        mov    #0, r0
+
+1:
+       mov     r8, r5
+#if MUTEX != 0
+       add     #MUTEX, r5
+#endif
+       mov     #PSHARED, r0
+       mov.b   @(r0,r8), r6
+       extu.b  r6, r6
+       mov.l   .Lwait8, r1
+       bsrf    r1
+        mov    r2, r4
+.Lwait8b:
+       bra     2b
+        nop
+3:
+       mov     r8, r4
+#if MUTEX != 0
+       add     #MUTEX, r4
+#endif
+       mov     #PSHARED, r0
+       mov.b   @(r0,r8), r5
+       extu.b  r5, r5
+       mov.l   .Lwake8, r1
+       bsrf    r1
+        nop
+.Lwake8b:
+       bra     4b
+        nop
+
+7:
+       mov.l   r4, @-r15
+       mov.l   r6, @-r15
+       mov     r8, r4
+#if MUTEX != 0
+       add     #MUTEX, r4
+#endif
+       mov     #PSHARED, r0
+       mov.b   @(r0,r8), r5
+       extu.b  r5, r5
+       mov.l   .Lwake9, r1
+       bsrf    r1
+        nop
+.Lwake9b:
+
+       mov.l   @r15+, r6
+       bra     8b
+        mov.l  @r15+, r4
+
+#ifndef __ASSUME_PRIVATE_FUTEX
+.Lpfoff:
+       .word   PRIVATE_FUTEX - TLS_PRE_TCB_SIZE
+#endif
+       .align  2
+.Lwait8:
+       .long   __lll_lock_wait-.Lwait8b
+.Lwake8:
+       .long   __lll_unlock_wake-.Lwake8b
+.Lwake9:
+       .long   __lll_unlock_wake-.Lwake9b
+       .size   __pthread_rwlock_unlock,.-__pthread_rwlock_unlock
+
+       .globl  pthread_rwlock_unlock
+pthread_rwlock_unlock = __pthread_rwlock_unlock
+
+       .globl  __pthread_rwlock_unlock_internal
+__pthread_rwlock_unlock_internal = __pthread_rwlock_unlock
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_wrlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_wrlock.S
new file mode 100644 (file)
index 0000000..3d37fb4
--- /dev/null
@@ -0,0 +1,234 @@
+/* Copyright (C) 2003, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <lowlevelrwlock.h>
+#include <pthread-errnos.h>
+#include <tcb-offsets.h>
+#include <bits/kernel-features.h>
+#include "lowlevel-atomic.h"
+
+
+       .text
+
+       .globl  __pthread_rwlock_wrlock
+       .type   __pthread_rwlock_wrlock,@function
+       .align  5
+__pthread_rwlock_wrlock:
+       mov.l   r12, @-r15
+       mov.l   r9, @-r15
+       mov.l   r8, @-r15
+       sts.l   pr, @-r15
+       mov     r4, r8
+
+       /* Get the lock.  */
+       mov     #0, r3
+       mov     #1, r4
+#if MUTEX == 0
+       CMPXCHG (r3, @r8, r4, r2)
+#else
+       CMPXCHG (r3, @(MUTEX,r8), r4, r2)
+#endif
+       bf      1f
+2:
+       mov.l   @(WRITER,r8), r0
+       tst     r0, r0
+       bf      14f
+       mov.l   @(NR_READERS,r8), r0
+       tst     r0, r0
+       bt      5f
+3:
+       mov.l   @(WRITERS_QUEUED,r8), r0
+       add     #1, r0
+       mov.l   r0, @(WRITERS_QUEUED,r8)
+       tst     r0, r0
+       bt      4f
+
+       mov.l   @(WRITERS_WAKEUP,r8), r9
+
+#if MUTEX == 0
+       DEC (@r8, r2)
+#else
+       DEC (@(MUTEX,r8), r2)
+#endif
+       tst     r2, r2
+       bf      10f
+11:
+       mov     r8, r4
+       add     #WRITERS_WAKEUP, r4
+#ifdef __ASSUME_PRIVATE_FUTEX
+       mov     #PSHARED, r0
+       mov.b   @(r0,r8), r5
+       mov     #(FUTEX_PRIVATE_FLAG|FUTEX_WAIT), r0
+       xor     r0, r5
+       extu.b  r5, r5
+#else
+       mov     #PSHARED, r0
+       mov.b   @(r0,r8), r5
+       extu.b  r5, r5
+# if FUTEX_WAIT != 0
+       mov     #FUTEX_WAIT, r0
+       or      r0, r5
+# endif
+       stc     gbr, r1
+       mov.w   .Lpfoff, r2
+       add     r2, r1
+       mov.l   @r1, r0
+       xor     r0, r5
+#endif
+       mov     r9, r6
+       mov     #0, r7
+       mov     #SYS_futex, r3
+       extu.b  r3, r3
+       trapa   #0x14
+       SYSCALL_INST_PAD
+
+       /* Reget the lock.  */
+       mov     #0, r3
+       mov     #1, r4
+#if MUTEX == 0
+       CMPXCHG (r3, @r8, r4, r2)
+#else
+       CMPXCHG (r3, @(MUTEX,r8), r4, r2)
+#endif
+       bf      12f
+13:
+       mov.l   @(WRITERS_QUEUED,r8), r0
+       add     #-1, r0
+       bra     2b
+        mov.l  r0, @(WRITERS_QUEUED,r8)
+
+5:
+       mov     #0, r3
+       stc     gbr, r0
+       mov.w   .Ltidoff, r1
+       mov.l   @(r0,r1), r0
+       mov.l   r0, @(WRITER,r8)
+9:
+#if MUTEX == 0
+       DEC (@r8, r2)
+#else
+       DEC (@(MUTEX,r8), r2)
+#endif
+       tst     r2, r2
+       bf      6f
+7:
+       lds.l   @r15+, pr
+       mov.l   @r15+, r8
+       mov.l   @r15+, r9
+       mov.l   @r15+, r12
+       rts
+        mov    r3, r0
+
+1:
+       mov     r8, r5
+#if MUTEX != 0
+       add     #MUTEX, r5
+#endif
+       mov     #PSHARED, r0
+       mov.b   @(r0,r8), r6
+       extu.b  r6, r6
+       mov.l   .Lwait4, r1
+       bsrf    r1
+        mov    r2, r4
+.Lwait4b:
+       bra     2b
+        nop
+14:
+       stc     gbr, r1
+       mov.w   .Ltidoff, r2
+       add     r2, r1
+       mov.l   @r1, r1
+       cmp/eq  r1, r0
+       bf      3b
+       bra     9b
+        mov    #EDEADLK, r3
+6:
+       mov     r8, r4
+#if MUTEX != 0
+       add     #MUTEX, r4
+#endif
+       mov     #PSHARED, r0
+       mov.b   @(r0,r8), r5
+       extu.b  r5, r5
+       mov.l   .Lwake4, r1
+       bsrf    r1
+        nop
+.Lwake4b:
+       bra     7b
+        mov    #0, r3
+
+#ifndef __ASSUME_PRIVATE_FUTEX
+.Lpfoff:
+       .word   PRIVATE_FUTEX - TLS_PRE_TCB_SIZE
+#endif
+.Ltidoff:
+       .word   TID - TLS_PRE_TCB_SIZE
+
+4:
+       mov.l   @(WRITERS_QUEUED,r8), r1
+       add     #-1, r1
+       mov.l   r1, @(WRITERS_QUEUED,r8)
+       bra     9b
+        mov    #EAGAIN, r3
+
+10:
+       mov     r8, r4
+#if MUTEX != 0
+       add     #MUTEX, r4
+#endif
+       mov     #PSHARED, r0
+       mov.b   @(r0,r8), r5
+       extu.b  r5, r5
+       mov.l   .Lwake5, r1
+       bsrf    r1
+        nop
+.Lwake5b:
+       bra     11b
+        nop
+
+12:
+       mov     r8, r5
+#if MUTEX != 0
+       add     #MUTEX, r5
+#endif
+       mov     #PSHARED, r0
+       mov.b   @(r0,r8), r6
+       extu.b  r6, r6
+       mov.l   .Lwait5, r1
+       bsrf    r1
+        mov    r2, r4
+.Lwait5b:
+       bra     13b
+        nop
+
+       .align  2
+.Lwait4:
+       .long   __lll_lock_wait-.Lwait4b
+.Lwake4:
+       .long   __lll_unlock_wake-.Lwake4b
+.Lwait5:
+       .long   __lll_lock_wait-.Lwait5b
+.Lwake5:
+       .long   __lll_unlock_wake-.Lwake5b
+       .globl  pthread_rwlock_wrlock
+pthread_rwlock_wrlock = __pthread_rwlock_wrlock
+
+       .globl  __pthread_rwlock_wrlock_internal
+__pthread_rwlock_wrlock_internal = __pthread_rwlock_wrlock
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sem_post.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sem_post.S
new file mode 100644 (file)
index 0000000..f71cd93
--- /dev/null
@@ -0,0 +1,110 @@
+/* Copyright (C) 2003, 2004, 2007, 2008 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <pthread-errnos.h>
+#include <structsem.h>
+#include <lowlevellock.h>
+#include "lowlevel-atomic.h"
+
+
+       .text
+
+       .globl  __new_sem_post
+       .type   __new_sem_post,@function
+       .align  5
+__new_sem_post:
+       mov.l   @(VALUE,r4), r2
+0:
+       mov.l   .Lmax, r1
+       cmp/eq  r1, r2
+       bt/s    3f
+        mov    r2, r3
+       mov     r3, r5
+       add     #1, r5
+       CMPXCHG (r3, @(VALUE,r4), r5, r2)
+       bf      0b
+       mov.l   @(NWAITERS,r4), r2
+       tst     r2, r2
+       bt      2f
+       mov     #FUTEX_WAKE, r5
+       mov.l   @(PRIVATE,r4), r1
+       or      r1, r5
+       mov     #1, r6
+       mov     #0, r7
+       mov     #SYS_futex, r3
+       extu.b  r3, r3
+       trapa   #0x14
+       SYSCALL_INST_PAD
+
+       cmp/pz  r0
+       bf      1f
+2:
+       rts
+        mov    #0, r0
+
+1:
+       bra     4f
+        mov    #EINVAL, r2
+
+3:
+       mov     #EOVERFLOW, r2
+4:
+       mov.l   r12, @-r15
+       mov.l   r8, @-r15
+       sts.l   pr, @-r15
+       mova    .Lgot3, r0
+       mov.l   .Lgot3, r12
+       add     r0, r12
+
+#if USE___THREAD
+       mov.l   .Lerrno3, r0
+       stc     gbr, r1
+       mov.l   @(r0, r12), r0
+       bra     .Lexit
+        add    r1, r0
+       .align  2
+.Lerrno3:
+       .long   errno@GOTTPOFF
+.Lexit:
+       mov.l   r2, @r0
+#else
+       mov     r2, r8
+       mov.l   .Lerrloc3, r1
+       bsrf    r1
+        nop
+.Lerrloc3b:
+       mov     r8, @r0
+#endif
+       lds.l   @r15+, pr
+       mov.l   @r15+, r8
+       mov.l   @r15+, r12
+       rts
+        mov    #-1, r0
+
+       .align  2
+.Lmax:
+       .long   SEM_VALUE_MAX
+.Lgot3:
+       .long   _GLOBAL_OFFSET_TABLE_
+#if !USE___THREAD
+.Lerrloc3:
+       .long   __errno_location@PLT-(.Lerrloc3b-.)
+#endif
+       .size   __new_sem_post,.-__new_sem_post
+       weak_alias(__new_sem_post, sem_post)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sem_timedwait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sem_timedwait.S
new file mode 100644 (file)
index 0000000..7fb61b2
--- /dev/null
@@ -0,0 +1,358 @@
+/* Copyright (C) 2003, 2004, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <pthread-errnos.h>
+#include <tcb-offsets.h>
+#include <structsem.h>
+#include <lowlevellock.h>
+#include "lowlevel-atomic.h"
+
+
+#if VALUE != 0
+# error "code needs to be rewritten for VALUE != 0"
+#endif
+
+       .text
+
+       .globl  sem_timedwait
+       .type   sem_timedwait,@function
+       .align  5
+sem_timedwait:
+.LSTARTCODE:
+       mov.l   @r4, r0
+2:
+       tst     r0, r0
+       bt      1f
+       mov     r0, r3
+       mov     r0, r6
+       add     #-1, r3
+       CMPXCHG (r6, @r4, r3, r2)
+       bf/s    2b
+        mov    r2, r0
+       rts
+        mov    #0, r0
+
+1:
+       /* Check whether the timeout value is valid.  */
+       mov.l   r8, @-r15
+.Lpush_r8:
+       mov.l   r9, @-r15
+.Lpush_r9:
+       mov.l   r10, @-r15
+.Lpush_r10:
+       mov.l   r12, @-r15
+.Lpush_r12:
+       sts.l   pr, @-r15
+.Lpush_pr:
+       add     #-8, r15
+.Lalloc:
+       mov     r4, r8
+       mov     r5, r9
+
+       /* Check for invalid nanosecond field.  */
+       mov.l   @(4,r9), r0
+       mov.l   .L1g, r1
+       cmp/hs  r1, r0
+       bt/s    6f
+        mov    #EINVAL, r0
+       INC (@(NWAITERS,r8),r2)
+
+7:
+       /* Compute relative timeout.  */
+       mov     r15, r4
+       mov     #0, r5
+       mov     #__NR_gettimeofday, r3
+       trapa   #0x12
+       SYSCALL_INST_PAD
+
+       mov.l   @(4,r15), r0
+       mov.w   .L1k, r1
+       dmulu.l r0, r1          /* Milli seconds to nano seconds.  */
+       mov.l   @r9, r2
+       mov.l   @(4,r9), r3
+       mov.l   @r15, r0
+       sts     macl, r1
+       sub     r0, r2
+       clrt
+       subc    r1, r3
+       bf      5f
+       mov.l   .L1g, r1
+       add     r1, r3
+       add     #-1, r2
+5:
+       cmp/pz  r2
+       bf/s    6f              /* Time is already up.  */
+        mov    #ETIMEDOUT, r0
+
+       /* Store relative timeout.  */
+       mov.l   r2, @r15
+       mov.l   r3, @(4,r15)
+
+.LcleanupSTART:
+       mov.l   .Lenable0, r1
+       bsrf    r1
+        nop
+.Lenable0b:
+       mov     r0, r10
+
+       mov     r8, r4
+#if FUTEX_WAIT == 0
+       mov.l   @(PRIVATE,r8), r5
+#else
+       mov.l   @(PRIVATE,r8), r5
+       mov     #FUTEX_WAIT, r0
+       or      r0, r5
+#endif
+       mov     #0, r6
+       mov     r15, r7
+       mov     #SYS_futex, r3
+       extu.b  r3, r3
+       trapa   #0x14
+       SYSCALL_INST_PAD
+
+       mov.l   .Ldisable0, r1
+       mov     r10, r4
+       bsrf    r1
+        mov    r0, r10
+.Ldisable0b:
+       mov     r10, r0
+.LcleanupEND:
+
+       tst     r0, r0
+       bt      9f
+       cmp/eq  #-EWOULDBLOCK, r0
+       bf      3f
+9:
+       mov.l   @r8, r0
+8:
+       tst     r0, r0
+       bt      7b
+
+       mov     r0, r3
+       mov     r0, r4
+       add     #-1, r3
+       CMPXCHG (r4, @r8, r3, r2)
+       bf/s    8b
+        mov    r2, r0
+
+       DEC (@(NWAITERS,r8), r2)
+       mov     #0, r0
+
+10:
+       add     #8, r15
+       lds.l   @r15+, pr
+       mov.l   @r15+, r12
+       mov.l   @r15+, r10
+       mov.l   @r15+, r9
+       mov.l   @r15+, r8
+       rts
+        nop
+
+3:
+       neg     r0, r0
+6:
+       mov     r0, r10
+       mova    .Lgot2, r0
+       mov.l   .Lgot2, r12
+       add     r0, r12
+
+#if USE___THREAD
+       mov.l   .Lerrno2, r0
+       stc     gbr, r1
+       mov.l   @(r0, r12), r0
+       bra     .Lexit
+        add    r1, r0
+       .align  2
+.Lerrno2:
+       .long   errno@GOTTPOFF
+.Lexit:
+#else
+       mov.l   .Lerrloc2, r1
+       bsrf    r1
+        nop
+.Lerrloc2b:
+#endif
+       mov.l   r10, @r0
+       DEC (@(NWAITERS,r8), r2)
+       bra     10b
+        mov    #-1, r0
+
+.L1k:
+       .word   1000
+       .align  2
+.L1g:
+       .long   1000000000
+.Lgot2:
+       .long   _GLOBAL_OFFSET_TABLE_
+#if !USE___THREAD
+.Lerrloc2:
+       .long   __errno_location@PLT-(.Lerrloc2b-.)
+#endif
+.Lenable0:
+       .long   __pthread_enable_asynccancel-.Lenable0b
+.Ldisable0:
+       .long   __pthread_disable_asynccancel-.Ldisable0b
+       .size   sem_timedwait,.-sem_timedwait
+
+       .type   sem_wait_cleanup,@function
+sem_wait_cleanup:
+       DEC (@(NWAITERS,r8), r2)
+.LcallUR:
+       mov.l   .Lresume, r1
+#ifdef __PIC__
+       add     r12, r1
+#endif
+       jsr     @r1
+        nop
+       sleep
+
+       .align  2
+.Lresume:
+#ifdef __PIC__
+       .long   _Unwind_Resume@GOTOFF
+#else
+       .long   _Unwind_Resume
+#endif
+.LENDCODE:
+       .size   sem_wait_cleanup,.-sem_wait_cleanup
+
+
+       .section .gcc_except_table,"a",@progbits
+.LexceptSTART:
+       .byte   0xff                            ! @LPStart format (omit)
+       .byte   0xff                            ! @TType format (omit)
+       .byte   0x01                            ! call-site format
+                                               ! DW_EH_PE_uleb128
+       .uleb128 .Lcstend-.Lcstbegin
+.Lcstbegin:
+       .uleb128 .LcleanupSTART-.LSTARTCODE
+       .uleb128 .LcleanupEND-.LcleanupSTART
+       .uleb128 sem_wait_cleanup-.LSTARTCODE
+       .uleb128  0
+       .uleb128 .LcallUR-.LSTARTCODE
+       .uleb128 .LENDCODE-.LcallUR
+       .uleb128 0
+       .uleb128  0
+.Lcstend:
+
+
+       .section .eh_frame,"a",@progbits
+.LSTARTFRAME:
+       .ualong .LENDCIE-.LSTARTCIE             ! Length of the CIE.
+.LSTARTCIE:
+       .ualong 0                               ! CIE ID.
+       .byte   1                               ! Version number.
+#ifdef SHARED
+       .string "zPLR"                          ! NUL-terminated augmentation
+                                               ! string.
+#else
+       .string "zPL"                           ! NUL-terminated augmentation
+                                               ! string.
+#endif
+       .uleb128 1                              ! Code alignment factor.
+       .sleb128 -4                             ! Data alignment factor.
+       .byte   0x11                            ! Return address register
+                                               ! column.
+#ifdef SHARED
+       .uleb128 7                              ! Augmentation value length.
+       .byte   0x9b                            ! Personality: DW_EH_PE_pcrel
+                                               ! + DW_EH_PE_sdata4
+                                               ! + DW_EH_PE_indirect
+       .ualong DW.ref.__gcc_personality_v0-.
+       .byte   0x1b                            ! LSDA Encoding: DW_EH_PE_pcrel
+                                               ! + DW_EH_PE_sdata4.
+       .byte   0x1b                            ! FDE Encoding: DW_EH_PE_pcrel
+                                               ! + DW_EH_PE_sdata4.
+#else
+       .uleb128 6                              ! Augmentation value length.
+       .byte   0x0                             ! Personality: absolute
+       .ualong __gcc_personality_v0
+       .byte   0x0                             ! LSDA Encoding: absolute
+#endif
+       .byte 0x0c                              ! DW_CFA_def_cfa
+       .uleb128 0xf
+       .uleb128 0
+       .align 4
+.LENDCIE:
+
+       .ualong .LENDFDE-.LSTARTFDE             ! Length of the FDE.
+.LSTARTFDE:
+       .ualong .LSTARTFDE-.LSTARTFRAME         ! CIE pointer.
+#ifdef SHARED
+       .ualong .LSTARTCODE-.                   ! PC-relative start address
+                                               ! of the code.
+#else
+       .ualong .LSTARTCODE                     ! Start address of the code.
+#endif
+       .ualong .LENDCODE-.LSTARTCODE           ! Length of the code.
+       .uleb128 4                              ! Augmentation size
+#ifdef SHARED
+       .ualong .LexceptSTART-.
+#else
+       .ualong .LexceptSTART
+#endif
+
+       .byte   4                               ! DW_CFA_advance_loc4
+       .ualong .Lpush_r8-.LSTARTCODE
+       .byte   14                              ! DW_CFA_def_cfa_offset
+       .uleb128 4
+       .byte   0x88                            ! DW_CFA_offset r8
+        .uleb128 1
+       .byte   4                               ! DW_CFA_advance_loc4
+       .ualong .Lpush_r9-.Lpush_r8
+       .byte   14                              ! DW_CFA_def_cfa_offset
+       .uleb128 8
+       .byte   0x89                            ! DW_CFA_offset r9
+        .uleb128 2
+       .byte   4                               ! DW_CFA_advance_loc4
+       .ualong .Lpush_r10-.Lpush_r9
+       .byte   14                              ! DW_CFA_def_cfa_offset
+       .uleb128 12
+       .byte   0x8a                            ! DW_CFA_offset r10
+        .uleb128 3
+       .byte   4                               ! DW_CFA_advance_loc4
+       .ualong .Lpush_r12-.Lpush_r10
+       .byte   14                              ! DW_CFA_def_cfa_offset
+       .uleb128 16
+       .byte   0x8c                            ! DW_CFA_offset r12
+        .uleb128 4
+       .byte   4                               ! DW_CFA_advance_loc4
+       .ualong .Lpush_pr-.Lpush_r12
+       .byte   14                              ! DW_CFA_def_cfa_offset
+       .uleb128 20
+       .byte   0x91                            ! DW_CFA_offset pr
+       .uleb128 5
+       .byte   4                               ! DW_CFA_advance_loc4
+       .ualong .Lalloc-.Lpush_pr
+       .byte   14                              ! DW_CFA_def_cfa_offset
+       .uleb128 28
+       .align  4
+.LENDFDE:
+
+
+#ifdef SHARED
+       .hidden DW.ref.__gcc_personality_v0
+       .weak   DW.ref.__gcc_personality_v0
+       .section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits
+       .align  4
+       .type   DW.ref.__gcc_personality_v0, @object
+       .size   DW.ref.__gcc_personality_v0, 4
+DW.ref.__gcc_personality_v0:
+       .long   __gcc_personality_v0
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sem_trywait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sem_trywait.S
new file mode 100644 (file)
index 0000000..b46eb1a
--- /dev/null
@@ -0,0 +1,90 @@
+/* Copyright (C) 2003, 2004, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <pthread-errnos.h>
+#include <lowlevellock.h>
+#include "lowlevel-atomic.h"
+
+
+       .text
+
+       .globl  __new_sem_trywait
+       .type   __new_sem_trywait,@function
+       .align  5
+__new_sem_trywait:
+       mov.l   r12, @-r15
+       mov.l   r8, @-r15
+       sts.l   pr, @-r15
+       mov     r4, r8
+       mov.l   @r8, r0
+2:
+       tst     r0, r0
+       bt      1f
+
+       mov     r0, r3
+       mov     r0, r4
+       add     #-1, r3
+       CMPXCHG (r4, @r8, r3, r2)
+       bf/s    2b
+        mov    r2, r0
+
+       lds.l   @r15+, pr
+       mov.l   @r15+, r8
+       mov.l   @r15+, r12
+       rts
+        mov    #0, r0
+
+1:
+       mov     #EAGAIN, r8
+       mova    .Lgot1, r0
+       mov.l   .Lgot1, r12
+       add     r0, r12
+
+#if USE___THREAD
+       mov.l   .Lerrno1, r0
+       stc     gbr, r1
+       mov.l   @(r0, r12), r0
+       bra     .Lexit
+        add    r1, r0
+       .align  2
+.Lerrno1:
+       .long   errno@GOTTPOFF
+.Lexit:
+#else
+       mov.l   .Lerrloc1, r1
+       bsrf    r1
+        nop
+.Lerrloc1b:
+#endif
+       mov.l   r8, @r0
+       lds.l   @r15+, pr
+       mov.l   @r15+, r8
+       mov.l   @r15+, r12
+       rts
+        mov    #-1, r0
+
+       .align  2
+.Lgot1:
+       .long   _GLOBAL_OFFSET_TABLE_
+#if !USE___THREAD
+.Lerrloc1:
+       .long   __errno_location@PLT-(.Lerrloc1b-.)
+#endif
+       .size   __new_sem_trywait,.-__new_sem_trywait
+       weak_alias(__new_sem_trywait, sem_trywait)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sem_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sem_wait.S
new file mode 100644 (file)
index 0000000..00a125b
--- /dev/null
@@ -0,0 +1,303 @@
+/* Copyright (C) 2003, 2004, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <pthread-errnos.h>
+#include <tcb-offsets.h>
+#include <structsem.h>
+#include <lowlevellock.h>
+#include "lowlevel-atomic.h"
+
+
+#if VALUE != 0
+# error "code needs to be rewritten for VALUE != 0"
+#endif
+
+       .text
+
+       .globl  __new_sem_wait
+       .type   __new_sem_wait,@function
+       .align  5
+__new_sem_wait:
+.LSTARTCODE:
+       mov.l   r8, @-r15
+.Lpush_r8:
+       mov.l   r10, @-r15
+.Lpush_r10:
+       mov.l   r12, @-r15
+.Lpush_r12:
+       sts.l   pr, @-r15
+.Lpush_pr:
+       mov     r4, r8
+
+       mov.l   @r8, r0
+2:
+       tst     r0, r0
+       bt      1f
+       mov     r0, r3
+       mov     r0, r4
+       add     #-1, r3
+       CMPXCHG (r4, @r8, r3, r2)
+       bf/s    2b
+        mov    r2, r0
+7:
+       mov     #0, r0
+9:
+       lds.l   @r15+, pr
+       mov.l   @r15+, r12
+       mov.l   @r15+, r10
+       rts
+        mov.l  @r15+, r8
+
+.Lafter_ret:
+1:
+       INC (@(NWAITERS,r8),r2)
+
+.LcleanupSTART:
+6:
+       mov.l   .Lenable0, r1
+       bsrf    r1
+        nop
+.Lenable0b:
+       mov     r0, r10
+
+       mov     r8, r4
+#if FUTEX_WAIT == 0
+       mov.l   @(PRIVATE,r8), r5
+#else
+       mov.l   @(PRIVATE,r8), r5
+       mov     #FUTEX_WAIT, r0
+       or      r0, r5
+#endif
+       mov     #0, r6
+       mov     #0, r7
+       mov     #SYS_futex, r3
+       extu.b  r3, r3
+       trapa   #0x14
+       SYSCALL_INST_PAD
+
+       mov.l   .Ldisable0, r1
+       mov     r10, r4
+       bsrf    r1
+        mov    r0, r10
+.Ldisable0b:
+       mov     r10, r0
+.LcleanupEND:
+
+       tst     r0, r0
+       bt      3f
+       cmp/eq  #-EWOULDBLOCK, r0
+       bf      4f
+
+3:
+       mov.l   @r8, r0
+5:
+       tst     r0, r0
+       bt      6b
+
+       mov     r0, r3
+       mov     r0, r4
+       add     #-1, r3
+       CMPXCHG (r4, @r8, r3, r2)
+       bf/s    5b
+        mov    r2, r0
+
+       DEC (@(NWAITERS,r8), r2)
+       bra     7b
+        nop
+
+4:
+       neg     r0, r0
+       mov     r0, r4
+       DEC (@(NWAITERS,r8), r2)
+       mov     r4, r8
+       mova    .Lgot0, r0
+       mov.l   .Lgot0, r12
+       add     r0, r12
+
+#if USE___THREAD
+       mov.l   .Lerrno0, r0
+       stc     gbr, r1
+       mov.l   @(r0, r12), r0
+       bra     .Lexit
+        add    r1, r0
+       .align  2
+.Lerrno0:
+       .long   errno@GOTTPOFF
+.Lexit:
+#else
+       mov.l   .Lerrloc0, r1
+       bsrf    r1
+        nop
+.Lerrloc0b:
+#endif
+       mov.l   r8, @r0
+       bra     9b
+        mov    #-1, r0
+
+       .align  2
+.Lgot0:
+       .long   _GLOBAL_OFFSET_TABLE_
+#if !USE___THREAD
+.Lerrloc0:
+       .long   __errno_location@PLT-(.Lerrloc0b-.)
+#endif
+.Lenable0:
+       .long   __pthread_enable_asynccancel-.Lenable0b
+.Ldisable0:
+       .long   __pthread_disable_asynccancel-.Ldisable0b
+       .size   __new_sem_wait,.-__new_sem_wait
+       weak_alias(__new_sem_wait, sem_wait)
+
+
+       .type   sem_wait_cleanup,@function
+sem_wait_cleanup:
+       DEC (@(NWAITERS,r8), r2)
+.LcallUR:
+       mov.l   .Lresume, r1
+#ifdef __PIC__
+       add     r12, r1
+#endif
+       jsr     @r1
+        nop
+       sleep
+
+       .align  2
+.Lresume:
+#ifdef __PIC__
+       .long   _Unwind_Resume@GOTOFF
+#else
+       .long   _Unwind_Resume
+#endif
+.LENDCODE:
+       .size   sem_wait_cleanup,.-sem_wait_cleanup
+
+
+       .section .gcc_except_table,"a",@progbits
+.LexceptSTART:
+       .byte   0xff                            ! @LPStart format (omit)
+       .byte   0xff                            ! @TType format (omit)
+       .byte   0x01                            ! call-site format
+                                               ! DW_EH_PE_uleb128
+       .uleb128 .Lcstend-.Lcstbegin
+.Lcstbegin:
+       .uleb128 .LcleanupSTART-.LSTARTCODE
+       .uleb128 .LcleanupEND-.LcleanupSTART
+       .uleb128 sem_wait_cleanup-.LSTARTCODE
+       .uleb128  0
+       .uleb128 .LcallUR-.LSTARTCODE
+       .uleb128 .LENDCODE-.LcallUR
+       .uleb128 0
+       .uleb128  0
+.Lcstend:
+
+
+       .section .eh_frame,"a",@progbits
+.LSTARTFRAME:
+       .ualong .LENDCIE-.LSTARTCIE             ! Length of the CIE.
+.LSTARTCIE:
+       .ualong 0                               ! CIE ID.
+       .byte   1                               ! Version number.
+#ifdef SHARED
+       .string "zPLR"                          ! NUL-terminated augmentation
+                                               ! string.
+#else
+       .string "zPL"                           ! NUL-terminated augmentation
+                                               ! string.
+#endif
+       .uleb128 1                              ! Code alignment factor.
+       .sleb128 -4                             ! Data alignment factor.
+       .byte   0x11                            ! Return address register
+                                               ! column.
+#ifdef SHARED
+       .uleb128 7                              ! Augmentation value length.
+       .byte   0x9b                            ! Personality: DW_EH_PE_pcrel
+                                               ! + DW_EH_PE_sdata4
+                                               ! + DW_EH_PE_indirect
+       .ualong DW.ref.__gcc_personality_v0-.
+       .byte   0x1b                            ! LSDA Encoding: DW_EH_PE_pcrel
+                                               ! + DW_EH_PE_sdata4.
+       .byte   0x1b                            ! FDE Encoding: DW_EH_PE_pcrel
+                                               ! + DW_EH_PE_sdata4.
+#else
+       .uleb128 6                              ! Augmentation value length.
+       .byte   0x0                             ! Personality: absolute
+       .ualong __gcc_personality_v0
+       .byte   0x0                             ! LSDA Encoding: absolute
+#endif
+       .byte 0x0c                              ! DW_CFA_def_cfa
+       .uleb128 0xf
+       .uleb128 0
+       .align 4
+.LENDCIE:
+
+       .ualong .LENDFDE-.LSTARTFDE             ! Length of the FDE.
+.LSTARTFDE:
+       .ualong .LSTARTFDE-.LSTARTFRAME         ! CIE pointer.
+#ifdef SHARED
+       .ualong .LSTARTCODE-.                   ! PC-relative start address
+                                               ! of the code.
+#else
+       .ualong .LSTARTCODE                     ! Start address of the code.
+#endif
+       .ualong .LENDCODE-.LSTARTCODE           ! Length of the code.
+       .uleb128 4                              ! Augmentation size
+#ifdef SHARED
+       .ualong .LexceptSTART-.
+#else
+       .ualong .LexceptSTART
+#endif
+
+       .byte   4                               ! DW_CFA_advance_loc4
+       .ualong .Lpush_r8-.LSTARTCODE
+       .byte   14                              ! DW_CFA_def_cfa_offset
+       .uleb128 4
+       .byte   0x88                            ! DW_CFA_offset r8
+        .uleb128 1
+       .byte   4                               ! DW_CFA_advance_loc4
+       .ualong .Lpush_r10-.Lpush_r8
+       .byte   14                              ! DW_CFA_def_cfa_offset
+       .uleb128 8
+       .byte   0x8a                            ! DW_CFA_offset r10
+        .uleb128 2
+       .byte   4                               ! DW_CFA_advance_loc4
+       .ualong .Lpush_r12-.Lpush_r10
+       .byte   14                              ! DW_CFA_def_cfa_offset
+       .uleb128 12
+       .byte   0x8c                            ! DW_CFA_offset r12
+        .uleb128 3
+       .byte   4                               ! DW_CFA_advance_loc4
+       .ualong .Lpush_pr-.Lpush_r12
+       .byte   14                              ! DW_CFA_def_cfa_offset
+       .uleb128 16
+       .byte   0x91                            ! DW_CFA_offset pr
+        .uleb128 4
+       .align  4
+.LENDFDE:
+
+
+#ifdef SHARED
+       .hidden DW.ref.__gcc_personality_v0
+       .weak   DW.ref.__gcc_personality_v0
+       .section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits
+       .align  4
+       .type   DW.ref.__gcc_personality_v0, @object
+       .size   DW.ref.__gcc_personality_v0, 4
+DW.ref.__gcc_personality_v0:
+       .long   __gcc_personality_v0
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sh4/lowlevellock.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sh4/lowlevellock.h
new file mode 100644 (file)
index 0000000..8cdcac5
--- /dev/null
@@ -0,0 +1,4 @@
+/*  4 instruction cycles not accessing cache and TLB are needed after
+    trapa instruction to avoid an SH-4 silicon bug.  */
+#define NEED_SYSCALL_INST_PAD
+#include <sysdeps/unix/sysv/linux/sh/lowlevellock.h>
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/smp.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/smp.h
new file mode 100644 (file)
index 0000000..2c0cbe9
--- /dev/null
@@ -0,0 +1,24 @@
+/* Determine whether the host has multiple processors.  SH 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 Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+static inline int
+is_smp_system (void)
+{
+  return 0;
+}
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sysdep-cancel.h
new file mode 100644 (file)
index 0000000..ad2ca40
--- /dev/null
@@ -0,0 +1,169 @@
+/* Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <tls.h>
+#include <sysdep.h>
+#ifndef __ASSEMBLER__
+# include <pthreadP.h>
+#endif
+
+#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt
+
+# define _IMM12 #-12
+# define _IMM16 #-16
+# define _IMP16 #16
+# undef PSEUDO
+# define PSEUDO(name, syscall_name, args) \
+  .text; \
+  ENTRY (name); \
+  .Lpseudo_start: \
+    SINGLE_THREAD_P; \
+    bf .Lpseudo_cancel; \
+    .type __##syscall_name##_nocancel,@function; \
+    .globl __##syscall_name##_nocancel; \
+    __##syscall_name##_nocancel: \
+    DO_CALL (syscall_name, args); \
+    mov r0,r1; \
+    mov _IMM12,r2; \
+    shad r2,r1; \
+    not r1,r1; \
+    tst r1,r1; \
+    bt .Lsyscall_error; \
+    bra .Lpseudo_end; \
+     nop; \
+    .size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel; \
+ .Lpseudo_cancel: \
+    sts.l pr,@-r15; \
+    cfi_adjust_cfa_offset (4); \
+    cfi_rel_offset (pr, 0); \
+    add _IMM16,r15; \
+    cfi_adjust_cfa_offset (16); \
+    SAVE_ARGS_##args; \
+    CENABLE; \
+    LOAD_ARGS_##args; \
+    add _IMP16,r15; \
+    cfi_adjust_cfa_offset (-16); \
+    lds.l @r15+,pr; \
+    cfi_adjust_cfa_offset (-4); \
+    cfi_restore (pr); \
+    DO_CALL(syscall_name, args); \
+    SYSCALL_INST_PAD; \
+    sts.l pr,@-r15; \
+    cfi_adjust_cfa_offset (4); \
+    cfi_rel_offset (pr, 0); \
+    mov.l r0,@-r15; \
+    cfi_adjust_cfa_offset (4); \
+    cfi_rel_offset (r0, 0); \
+    CDISABLE; \
+    mov.l @r15+,r0; \
+    cfi_adjust_cfa_offset (-4); \
+    lds.l @r15+,pr; \
+    cfi_adjust_cfa_offset (-4); \
+    cfi_restore (pr); \
+    mov r0,r1; \
+    mov _IMM12,r2; \
+    shad r2,r1; \
+    not r1,r1; \
+    tst r1,r1; \
+    bf .Lpseudo_end; \
+ .Lsyscall_error: \
+    SYSCALL_ERROR_HANDLER; \
+ .Lpseudo_end:
+
+# undef PSEUDO_END
+# define PSEUDO_END(sym) \
+  END (sym)
+
+# define SAVE_ARGS_0   /* Nothing.  */
+# define SAVE_ARGS_1   SAVE_ARGS_0; mov.l r4,@(0,r15); cfi_offset (r4,-4)
+# define SAVE_ARGS_2   SAVE_ARGS_1; mov.l r5,@(4,r15); cfi_offset (r5,-8)
+# define SAVE_ARGS_3   SAVE_ARGS_2; mov.l r6,@(8,r15); cfi_offset (r6,-12)
+# define SAVE_ARGS_4   SAVE_ARGS_3; mov.l r7,@(12,r15); cfi_offset (r7,-16)
+# define SAVE_ARGS_5   SAVE_ARGS_4
+# define SAVE_ARGS_6   SAVE_ARGS_5
+
+# define LOAD_ARGS_0   /* Nothing.  */
+# define LOAD_ARGS_1   LOAD_ARGS_0; mov.l @(0,r15),r4
+# define LOAD_ARGS_2   LOAD_ARGS_1; mov.l @(4,r15),r5
+# define LOAD_ARGS_3   LOAD_ARGS_2; mov.l @(8,r15),r6
+# define LOAD_ARGS_4   LOAD_ARGS_3; mov.l @(12,r15),r7
+# define LOAD_ARGS_5   LOAD_ARGS_4
+# define LOAD_ARGS_6   LOAD_ARGS_5
+
+# ifdef IS_IN_libpthread
+#  define __local_enable_asynccancel   __pthread_enable_asynccancel
+#  define __local_disable_asynccancel  __pthread_disable_asynccancel
+# elif !defined NOT_IN_libc
+#  define __local_enable_asynccancel   __libc_enable_asynccancel
+#  define __local_disable_asynccancel  __libc_disable_asynccancel
+# elif defined IS_IN_librt
+#  define __local_enable_asynccancel   __librt_enable_asynccancel
+#  define __local_disable_asynccancel  __librt_disable_asynccancel
+# else
+#  error Unsupported library
+# endif
+
+# define CENABLE \
+       mov.l 1f,r0; \
+       bsrf r0; \
+        nop; \
+     0: bra 2f; \
+        mov r0,r2; \
+       .align 2; \
+     1: .long __local_enable_asynccancel - 0b; \
+     2:
+
+# define CDISABLE \
+       mov.l 1f,r0; \
+       bsrf r0; \
+        mov r2,r4; \
+     0: bra 2f; \
+        nop; \
+       .align 2; \
+     1: .long __local_disable_asynccancel - 0b; \
+     2:
+
+# ifndef __ASSEMBLER__
+#  define SINGLE_THREAD_P \
+  __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
+                                  header.multiple_threads) == 0, 1)
+# else
+#  define SINGLE_THREAD_P \
+       stc gbr,r0; \
+       mov.w 0f,r1; \
+       sub r1,r0; \
+       mov.l @(MULTIPLE_THREADS_OFFSET,r0),r0; \
+       bra 1f; \
+        tst r0,r0; \
+     0: .word TLS_PRE_TCB_SIZE; \
+     1:
+
+# endif
+
+#elif !defined __ASSEMBLER__
+
+# define SINGLE_THREAD_P (1)
+# define NO_CANCELLATION 1
+
+#endif
+
+#ifndef __ASSEMBLER__
+# define RTLD_SINGLE_THREAD_P \
+  __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
+                                  header.multiple_threads) == 0, 1)
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/vfork.S
new file mode 100644 (file)
index 0000000..a45c09f
--- /dev/null
@@ -0,0 +1,71 @@
+/* Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#define _ERRNO_H       1
+#include <bits/errno.h>
+#include <tcb-offsets.h>
+
+/* Clone the calling process, but without copying the whole address space.
+   The calling process is suspended until the new process exits or is
+   replaced by a call to `execve'.  Return -1 for errors, 0 to the new process,
+   and the process ID of the new process to the old process.  */
+
+ENTRY (__vfork)
+       /* Save the PID value.  */
+       stc     gbr, r2
+       mov.w   .L2, r0
+       mov.l   @(r0,r2), r4
+       neg     r4, r1
+       tst     r1, r1
+       bf      1f
+       mov     #1, r1
+       rotr    r1
+1:
+       mov.l   r1, @(r0,r2)
+
+       mov.w   .L1, r3
+       trapa   #0x10
+       mov     r0, r1
+
+       /* Restore the old PID value in the parent.  */
+       tst     r0, r0
+       bt.s    2f
+        stc    gbr, r2
+       mov.w   .L2, r0
+       mov.l   r4, @(r0,r2)
+       mov     r1, r0
+2:
+       mov     #-12, r2
+       shad    r2, r1
+       not     r1, r1                  // r1=0 means r0 = -1 to -4095
+       tst     r1, r1                  // i.e. error in linux
+       bf      .Lpseudo_end
+       SYSCALL_ERROR_HANDLER
+.Lpseudo_end:
+       rts
+        nop
+.L1:
+       .word   __NR_vfork
+.L2:
+       .word   PID - TLS_PRE_TCB_SIZE
+       .align  2
+PSEUDO_END (__vfork)
+hidden_def (vfork)
+
+weak_alias (__vfork, vfork)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sigtimedwait.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sigtimedwait.c
new file mode 100644 (file)
index 0000000..5159bf9
--- /dev/null
@@ -0,0 +1,88 @@
+/* Copyright (C) 1997,1998,2000,2002,2003,2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthreadP.h>
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+
+#include <sysdep-cancel.h>
+#include <sys/syscall.h>
+
+#ifdef __NR_rt_sigtimedwait
+
+static int
+do_sigtimedwait (const sigset_t *set, siginfo_t *info,
+                const struct timespec *timeout)
+{
+#ifdef SIGCANCEL
+  sigset_t tmpset;
+  if (set != NULL
+      && (__builtin_expect (__sigismember (set, SIGCANCEL), 0)
+# ifdef SIGSETXID
+         || __builtin_expect (__sigismember (set, SIGSETXID), 0)
+# endif
+         ))
+    {
+      /* Create a temporary mask without the bit for SIGCANCEL set.  */
+      // We are not copying more than we have to.
+      memcpy (&tmpset, set, _NSIG / 8);
+      __sigdelset (&tmpset, SIGCANCEL);
+# ifdef SIGSETXID
+      __sigdelset (&tmpset, SIGSETXID);
+# endif
+      set = &tmpset;
+    }
+#endif
+
+    /* XXX The size argument hopefully will have to be changed to the
+       real size of the user-level sigset_t.  */
+  int result = INLINE_SYSCALL (rt_sigtimedwait, 4, set,
+                              info, timeout, _NSIG / 8);
+
+  /* The kernel generates a SI_TKILL code in si_code in case tkill is
+     used.  tkill is transparently used in raise().  Since having
+     SI_TKILL as a code is useful in general we fold the results
+     here.  */
+  if (result != -1 && info != NULL && info->si_code == SI_TKILL)
+    info->si_code = SI_USER;
+
+  return result;
+}
+
+
+/* Return any pending signal or wait for one for the given time.  */
+int attribute_hidden
+__sigtimedwait (const sigset_t *set, siginfo_t *info,
+               const struct timespec *timeout)
+{
+  if (SINGLE_THREAD_P)
+    return do_sigtimedwait (set, info, timeout);
+
+  int oldtype = LIBC_CANCEL_ASYNC ();
+
+  /* XXX The size argument hopefully will have to be changed to the
+     real size of the user-level sigset_t.  */
+  int result = do_sigtimedwait (set, info, timeout);
+
+  LIBC_CANCEL_RESET (oldtype);
+
+  return result;
+}
+weak_alias (__sigtimedwait, sigtimedwait)
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sigwait.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sigwait.c
new file mode 100644 (file)
index 0000000..bde0a92
--- /dev/null
@@ -0,0 +1,2 @@
+#include <pthreadP.h>
+#include "../../../../../../libc/signal/sigwait.c"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sigwaitinfo.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sigwaitinfo.c
new file mode 100644 (file)
index 0000000..6c47fde
--- /dev/null
@@ -0,0 +1,88 @@
+/* Copyright (C) 1997,1998,2000,2002,2003,2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthreadP.h>
+#include <errno.h>
+#include <signal.h>
+#define __need_NULL
+#include <stddef.h>
+#include <string.h>
+
+#include <sysdep-cancel.h>
+#include <sys/syscall.h>
+
+#ifdef __NR_rt_sigtimedwait
+
+static int
+do_sigwaitinfo (const sigset_t *set, siginfo_t *info)
+{
+#ifdef SIGCANCEL
+  sigset_t tmpset;
+  if (set != NULL
+      && (__builtin_expect (__sigismember (set, SIGCANCEL), 0)
+# ifdef SIGSETXID
+         || __builtin_expect (__sigismember (set, SIGSETXID), 0)
+# endif
+         ))
+    {
+      /* Create a temporary mask without the bit for SIGCANCEL set.  */
+      // We are not copying more than we have to.
+      memcpy (&tmpset, set, _NSIG / 8);
+      __sigdelset (&tmpset, SIGCANCEL);
+# ifdef SIGSETXID
+      __sigdelset (&tmpset, SIGSETXID);
+# endif
+      set = &tmpset;
+    }
+#endif
+
+  /* XXX The size argument hopefully will have to be changed to the
+     real size of the user-level sigset_t.  */
+  int result = INLINE_SYSCALL (rt_sigtimedwait, 4, set,
+                              info, NULL, _NSIG / 8);
+
+  /* The kernel generates a SI_TKILL code in si_code in case tkill is
+     used.  tkill is transparently used in raise().  Since having
+     SI_TKILL as a code is useful in general we fold the results
+     here.  */
+  if (result != -1 && info != NULL && info->si_code == SI_TKILL)
+    info->si_code = SI_USER;
+
+  return result;
+}
+
+
+/* Return any pending signal or wait for one for the given time.  */
+int
+__sigwaitinfo (const sigset_t *set, siginfo_t *info)
+{
+  if (SINGLE_THREAD_P)
+    return do_sigwaitinfo (set, info);
+
+  int oldtype = LIBC_CANCEL_ASYNC ();
+
+  /* XXX The size argument hopefully will have to be changed to the
+     real size of the user-level sigset_t.  */
+  int result = do_sigwaitinfo (set, info);
+
+  LIBC_CANCEL_RESET (oldtype);
+
+  return result;
+}
+weak_alias (__sigwaitinfo, sigwaitinfo)
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sleep.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sleep.c
new file mode 100644 (file)
index 0000000..9e948ad
--- /dev/null
@@ -0,0 +1,2 @@
+#include <pthreadP.h>
+#include <../../../../../../libc/unistd/sleep.c>
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/smp.h b/libpthread/nptl/sysdeps/unix/sysv/linux/smp.h
new file mode 100644 (file)
index 0000000..fcc34f7
--- /dev/null
@@ -0,0 +1,28 @@
+/* Determine whether the host has multiple processors.  Linux version.
+   Copyright (C) 1996, 2002, 2004, 2006 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+/* Test whether the machine has more than one processor.  This is not the
+   best test but good enough.  More complicated tests would require `malloc'
+   which is not available at that time.  */
+static inline int
+is_smp_system (void)
+{
+  /* Assume all machines are SMP and/or CMT and/or SMT.  */
+  return 1;
+}
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/Makefile b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/Makefile
new file mode 100644 (file)
index 0000000..43a6fad
--- /dev/null
@@ -0,0 +1,13 @@
+# Makefile for uClibc NPTL
+#
+# Copyright (C) 2005 Steven J. Hill <sjhill@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+top_srcdir=../../../../../../../
+top_builddir=../../../../../../../
+all: objs
+include $(top_builddir)Rules.mak
+include Makefile.arch
+include $(top_srcdir)Makerules
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/Makefile.arch b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/Makefile.arch
new file mode 100644 (file)
index 0000000..1e4f544
--- /dev/null
@@ -0,0 +1,67 @@
+# Makefile for uClibc NPTL
+#
+# Copyright (C) 2006 Steven J. Hill <sjhill@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+libpthread_SSRC = pt-vfork.S clone.S
+libpthread_CSRC = pthread_once.c lowlevellock.c \
+                                 pthread_barrier_init.c pthread_barrier_wait.c pthread_barrier_destroy.c
+
+libc_a_CSRC = fork.c libc-lowlevellock.c
+libc_a_SSRC = clone.S vfork.S
+
+CFLAGS-OMIT-fork.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1
+CFLAGS-OMIT-libc-lowlevellock.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1
+
+ifeq ($(UCLIBC_HAS_STDIO_FUTEXES),y)
+CFLAGS-fork.c = -D__USE_STDIO_FUTEXES__
+endif
+
+ASFLAGS-pt-vfork.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 -D_LIBC_REENTRANT -DUSE___THREAD
+
+CFLAGS-pthread_once.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1
+CFLAGS-lowlevellock.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1
+
+
+ASFLAGS-clone.S = -D_LIBC_REENTRANT
+ASFLAGS-vfork.S = -D_LIBC_REENTRANT
+
+ifeq ($(UCLIBC_HAS_THREADS_NATIVE),y)
+#Needed to use the correct SYSCALL_ERROR_HANDLER
+ASFLAGS-clone.S += -DUSE___THREAD
+ASFLAGS-vfork.S += -DUSE___THREAD
+ASFLAGS-pt-vfork.S += -DUSE___THREAD
+endif
+
+CFLAGS += $(SSP_ALL_CFLAGS)
+#CFLAGS:=$(CFLAGS:-O1=-O2)
+
+LINUX_ARCH_DIR:=$(top_srcdir)libpthread/nptl/sysdeps/unix/sysv/linux/sparc
+LINUX_ARCH_OUT:=$(top_builddir)libpthread/nptl/sysdeps/unix/sysv/linux/sparc
+
+LINUX_ARCH_OBJ:=$(patsubst %.S,$(LINUX_ARCH_OUT)/%.o,$(libpthread_SSRC))
+LINUX_ARCH_OBJ+=$(patsubst %.c,$(LINUX_ARCH_OUT)/%.o,$(libpthread_CSRC))
+
+ifeq ($(DOPIC),y)
+libpthread-a-y += $(LINUX_ARCH_OBJ:.o=.os)
+else
+libpthread-a-y += $(LINUX_ARCH_OBJ)
+endif
+libpthread-so-y += $(LINUX_ARCH_OBJ:.o=.oS)
+
+libpthread-nomulti-y+=$(LINUX_ARCH_OBJS)
+
+LIBC_LINUX_ARCH_OBJ:=$(patsubst %.c,$(LINUX_ARCH_OUT)/%.o,$(libc_a_CSRC))
+LIBC_LINUX_ARCH_OBJ+=$(patsubst %.S,$(LINUX_ARCH_OUT)/%.o,$(libc_a_SSRC))
+
+libc-static-y+=$(LIBC_LINUX_ARCH_OBJ)
+libc-shared-y+=$(LIBC_LINUX_ARCH_OBJ:.o=.oS)
+
+libc-nomulti-y+=$(LIBC_LINUX_ARCH_OBJ)
+
+objclean-y+=nptl_linux_arch_clean
+
+nptl_linux_arch_clean:
+       $(do_rm) $(addprefix $(LINUX_ARCH_OUT)/*., o os oS)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/bits/local_lim.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/bits/local_lim.h
new file mode 100644 (file)
index 0000000..6e35603
--- /dev/null
@@ -0,0 +1,100 @@
+/* Minimum guaranteed maximum values for system limits.  Linux/SPARC version.
+   Copyright (C) 1993-1998,2000,2002-2004,2008 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+/* The kernel header pollutes the namespace with the NR_OPEN symbol
+   and defines LINK_MAX although filesystems have different maxima.  A
+   similar thing is true for OPEN_MAX: the limit can be changed at
+   runtime and therefore the macro must not be defined.  Remove this
+   after including the header if necessary.  */
+#ifndef NR_OPEN
+# define __undef_NR_OPEN
+#endif
+#ifndef LINK_MAX
+# define __undef_LINK_MAX
+#endif
+#ifndef OPEN_MAX
+# define __undef_OPEN_MAX
+#endif
+#ifndef ARG_MAX
+# define __undef_ARG_MAX
+#endif
+
+/* The kernel sources contain a file with all the needed information.  */
+#include <linux/limits.h>
+
+/* Have to remove NR_OPEN?  */
+#ifdef __undef_NR_OPEN
+# undef NR_OPEN
+# undef __undef_NR_OPEN
+#endif
+/* Have to remove LINK_MAX?  */
+#ifdef __undef_LINK_MAX
+# undef LINK_MAX
+# undef __undef_LINK_MAX
+#endif
+/* Have to remove OPEN_MAX?  */
+#ifdef __undef_OPEN_MAX
+# undef OPEN_MAX
+# undef __undef_OPEN_MAX
+#endif
+/* Have to remove ARG_MAX?  */
+#ifdef __undef_ARG_MAX
+# undef ARG_MAX
+# undef __undef_ARG_MAX
+#endif
+
+/* The number of data keys per process.  */
+#define _POSIX_THREAD_KEYS_MAX 128
+/* This is the value this implementation supports.  */
+#define PTHREAD_KEYS_MAX       1024
+
+/* Controlling the iterations of destructors for thread-specific data.  */
+#define _POSIX_THREAD_DESTRUCTOR_ITERATIONS    4
+/* Number of iterations this implementation does.  */
+#define PTHREAD_DESTRUCTOR_ITERATIONS  _POSIX_THREAD_DESTRUCTOR_ITERATIONS
+
+/* The number of threads per process.  */
+#define _POSIX_THREAD_THREADS_MAX      64
+/* We have no predefined limit on the number of threads.  */
+#undef PTHREAD_THREADS_MAX
+
+/* Maximum amount by which a process can descrease its asynchronous I/O
+   priority level.  */
+#define AIO_PRIO_DELTA_MAX     20
+
+/* Minimum size for a thread.  We are free to choose a reasonable value.  */
+#define PTHREAD_STACK_MIN      24576
+
+/* Maximum number of timer expiration overruns.  */
+#define DELAYTIMER_MAX 2147483647
+
+/* Maximum tty name length.  */
+#define TTY_NAME_MAX           32
+
+/* Maximum login name length.  This is arbitrary.  */
+#define LOGIN_NAME_MAX         256
+
+/* Maximum host name length.  */
+#define HOST_NAME_MAX          64
+
+/* Maximum message queue priority level.  */
+#define MQ_PRIO_MAX            32768
+
+/* Maximum value the semaphore can have.  */
+#define SEM_VALUE_MAX   (2147483647)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/bits/pthreadtypes.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/bits/pthreadtypes.h
new file mode 100644 (file)
index 0000000..faf0584
--- /dev/null
@@ -0,0 +1,221 @@
+/* Machine-specific pthread type layouts.  SPARC version.
+   Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _BITS_PTHREADTYPES_H
+#define _BITS_PTHREADTYPES_H   1
+
+#include <bits/wordsize.h>
+
+#if __WORDSIZE == 64
+# define __SIZEOF_PTHREAD_ATTR_T 56
+# define __SIZEOF_PTHREAD_MUTEX_T 40
+# define __SIZEOF_PTHREAD_MUTEXATTR_T 4
+# define __SIZEOF_PTHREAD_COND_T 48
+# define __SIZEOF_PTHREAD_CONDATTR_T 4
+# define __SIZEOF_PTHREAD_RWLOCK_T 56
+# define __SIZEOF_PTHREAD_RWLOCKATTR_T 8
+# define __SIZEOF_PTHREAD_BARRIER_T 32
+# define __SIZEOF_PTHREAD_BARRIERATTR_T 4
+#else
+# define __SIZEOF_PTHREAD_ATTR_T 36
+# define __SIZEOF_PTHREAD_MUTEX_T 24
+# define __SIZEOF_PTHREAD_MUTEXATTR_T 4
+# define __SIZEOF_PTHREAD_COND_T 48
+# define __SIZEOF_PTHREAD_CONDATTR_T 4
+# define __SIZEOF_PTHREAD_RWLOCK_T 32
+# define __SIZEOF_PTHREAD_RWLOCKATTR_T 8
+# define __SIZEOF_PTHREAD_BARRIER_T 20
+# define __SIZEOF_PTHREAD_BARRIERATTR_T 4
+#endif
+
+
+/* Thread identifiers.  The structure of the attribute type is
+   deliberately not exposed.  */
+typedef unsigned long int pthread_t;
+
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_ATTR_T];
+  long int __align;
+} pthread_attr_t;
+
+
+#if __WORDSIZE == 64
+typedef struct __pthread_internal_list
+{
+  struct __pthread_internal_list *__prev;
+  struct __pthread_internal_list *__next;
+} __pthread_list_t;
+#else
+typedef struct __pthread_internal_slist
+{
+  struct __pthread_internal_slist *__next;
+} __pthread_slist_t;
+#endif
+
+
+/* Data structures for mutex handling.  The structure of the attribute
+   type is deliberately not exposed.  */
+typedef union
+{
+  struct __pthread_mutex_s
+  {
+    int __lock;
+    unsigned int __count;
+    int __owner;
+#if __WORDSIZE == 64
+    unsigned int __nusers;
+#endif
+    /* KIND must stay at this position in the structure to maintain
+       binary compatibility.  */
+    int __kind;
+#if __WORDSIZE == 64
+    int __spins;
+    __pthread_list_t __list;
+# define __PTHREAD_MUTEX_HAVE_PREV     1
+#else
+    unsigned int __nusers;
+    __extension__ union
+    {
+      int __spins;
+      __pthread_slist_t __list;
+    };
+#endif
+  } __data;
+  char __size[__SIZEOF_PTHREAD_MUTEX_T];
+  long int __align;
+} pthread_mutex_t;
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_MUTEXATTR_T];
+  int __align;
+} pthread_mutexattr_t;
+
+
+/* Data structure for conditional variable handling.  The structure of
+   the attribute type is deliberately not exposed.  */
+typedef union
+{
+  struct
+  {
+    int __lock;
+    unsigned int __futex;
+    __extension__ unsigned long long int __total_seq;
+    __extension__ unsigned long long int __wakeup_seq;
+    __extension__ unsigned long long int __woken_seq;
+    void *__mutex;
+    unsigned int __nwaiters;
+    unsigned int __broadcast_seq;
+  } __data;
+  char __size[__SIZEOF_PTHREAD_COND_T];
+  __extension__ long long int __align;
+} pthread_cond_t;
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_CONDATTR_T];
+  int __align;
+} pthread_condattr_t;
+
+
+/* Keys for thread-specific data */
+typedef unsigned int pthread_key_t;
+
+
+/* Once-only execution */
+typedef int pthread_once_t;
+
+
+#if defined __USE_UNIX98 || defined __USE_XOPEN2K
+/* Data structure for read-write lock variable handling.  The
+   structure of the attribute type is deliberately not exposed.  */
+typedef union
+{
+# if __WORDSIZE == 64
+  struct
+  {
+    int __lock;
+    unsigned int __nr_readers;
+    unsigned int __readers_wakeup;
+    unsigned int __writer_wakeup;
+    unsigned int __nr_readers_queued;
+    unsigned int __nr_writers_queued;
+    int __writer;
+    int __shared;
+    unsigned long int __pad1;
+    unsigned long int __pad2;
+    /* FLAGS must stay at this position in the structure to maintain
+       binary compatibility.  */
+    unsigned int __flags;
+  } __data;
+# else
+  struct
+  {
+    int __lock;
+    unsigned int __nr_readers;
+    unsigned int __readers_wakeup;
+    unsigned int __writer_wakeup;
+    unsigned int __nr_readers_queued;
+    unsigned int __nr_writers_queued;
+    unsigned char __pad1;
+    unsigned char __pad2;
+    unsigned char __shared;
+    /* FLAGS must stay at this position in the structure to maintain
+       binary compatibility.  */
+    unsigned char __flags;
+    int __writer;
+  } __data;
+# endif
+  char __size[__SIZEOF_PTHREAD_RWLOCK_T];
+  long int __align;
+} pthread_rwlock_t;
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_RWLOCKATTR_T];
+  long int __align;
+} pthread_rwlockattr_t;
+#endif
+
+
+#ifdef __USE_XOPEN2K
+/* POSIX spinlock data type.  */
+typedef volatile int pthread_spinlock_t;
+
+
+/* POSIX barriers data type.  The structure of the type is
+   deliberately not exposed.  */
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_BARRIER_T];
+  long int __align;
+} pthread_barrier_t;
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_BARRIERATTR_T];
+  int __align;
+} pthread_barrierattr_t;
+#endif
+
+
+#endif /* bits/pthreadtypes.h */
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/bits/semaphore.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/bits/semaphore.h
new file mode 100644 (file)
index 0000000..8fd7d34
--- /dev/null
@@ -0,0 +1,41 @@
+/* Machine-specific POSIX semaphore type layouts.  SPARC version.
+   Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _SEMAPHORE_H
+# error "Never use <bits/semaphore.h> directly; include <semaphore.h> instead."
+#endif
+
+#include <bits/wordsize.h>
+
+#if __WORDSIZE == 64
+# define __SIZEOF_SEM_T        32
+#else
+# define __SIZEOF_SEM_T        16
+#endif
+
+/* Value returned if `sem_open' failed.  */
+#define SEM_FAILED      ((sem_t *) 0)
+
+
+typedef union
+{
+  char __size[__SIZEOF_SEM_T];
+  long int __align;
+} sem_t;
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/clone.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/clone.S
new file mode 100644 (file)
index 0000000..dfc5e82
--- /dev/null
@@ -0,0 +1,5 @@
+#if defined(__arch64__)
+#include "./sparc64/clone.S"
+#else
+#include "./sparc32/clone.S"
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/fork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/fork.c
new file mode 100644 (file)
index 0000000..1cd7911
--- /dev/null
@@ -0,0 +1,29 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sched.h>
+#include <signal.h>
+#include <sysdep.h>
+#include <tls.h>
+
+#define ARCH_FORK() \
+  INLINE_CLONE_SYSCALL (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD, \
+                       0, NULL, NULL, &THREAD_SELF->tid)
+
+#include "../fork.c"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/internaltypes.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/internaltypes.h
new file mode 100644 (file)
index 0000000..4f400a3
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef _INTERNALTYPES_H
+#include "../internaltypes.h"
+
+union sparc_pthread_barrier
+{
+  struct pthread_barrier b;
+  struct sparc_pthread_barrier_s
+    {
+      unsigned int curr_event;
+      int lock;
+      unsigned int left;
+      unsigned int init_count;
+      unsigned char left_lock;
+      unsigned char pshared;
+    } s;
+};
+
+struct sparc_new_sem
+{
+  unsigned int value;
+  unsigned char lock;
+  unsigned char private;
+  unsigned char pad[2];
+  unsigned long int nwaiters;
+};
+
+struct sparc_old_sem
+{
+  unsigned int value;
+  unsigned char lock;
+  unsigned char private;
+};
+
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/libc-lowlevellock.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/libc-lowlevellock.c
new file mode 100644 (file)
index 0000000..b192822
--- /dev/null
@@ -0,0 +1,21 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* No difference to lowlevellock.c, except we lose a couple of functions.  */
+#include "lowlevellock.c"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/lowlevellock.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/lowlevellock.c
new file mode 100644 (file)
index 0000000..0471d1f
--- /dev/null
@@ -0,0 +1,133 @@
+/* low level locking for pthread library.  SPARC version.
+   Copyright (C) 2003, 2006, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <sys/time.h>
+#include <tls.h>
+
+
+void
+__lll_lock_wait_private (int *futex)
+{
+  do
+    {
+      int oldval = atomic_compare_and_exchange_val_24_acq (futex, 2, 1);
+      if (oldval != 0)
+       lll_futex_wait (futex, 2, LLL_PRIVATE);
+    }
+  while (atomic_compare_and_exchange_val_24_acq (futex, 2, 0) != 0);
+}
+
+
+/* These functions don't get included in libc.so  */
+#ifdef IS_IN_libpthread
+void
+__lll_lock_wait (int *futex, int private)
+{
+  do
+    {
+      int oldval = atomic_compare_and_exchange_val_24_acq (futex, 2, 1);
+      if (oldval != 0)
+       lll_futex_wait (futex, 2, private);
+    }
+  while (atomic_compare_and_exchange_val_24_acq (futex, 2, 0) != 0);
+}
+
+
+int
+__lll_timedlock_wait (int *futex, const struct timespec *abstime, int private)
+{
+  /* Reject invalid timeouts.  */
+  if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)
+    return EINVAL;
+
+  do
+    {
+      struct timeval tv;
+      struct timespec rt;
+
+      /* Get the current time.  */
+      (void) gettimeofday (&tv, NULL);
+
+      /* Compute relative timeout.  */
+      rt.tv_sec = abstime->tv_sec - tv.tv_sec;
+      rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000;
+      if (rt.tv_nsec < 0)
+       {
+         rt.tv_nsec += 1000000000;
+         --rt.tv_sec;
+       }
+
+      /* Already timed out?  */
+      if (rt.tv_sec < 0)
+       return ETIMEDOUT;
+
+      /* Wait.  */
+      int oldval = atomic_compare_and_exchange_val_24_acq (futex, 2, 1);
+      if (oldval != 0)
+       lll_futex_timed_wait (futex, 2, &rt, private);
+    }
+  while (atomic_compare_and_exchange_val_24_acq (futex, 2, 0) != 0);
+
+  return 0;
+}
+
+
+int
+__lll_timedwait_tid (int *tidp, const struct timespec *abstime)
+{
+  int tid;
+
+  if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)
+    return EINVAL;
+
+  /* Repeat until thread terminated.  */
+  while ((tid = *tidp) != 0)
+    {
+      struct timeval tv;
+      struct timespec rt;
+
+      /* Get the current time.  */
+      (void) gettimeofday (&tv, NULL);
+
+      /* Compute relative timeout.  */
+      rt.tv_sec = abstime->tv_sec - tv.tv_sec;
+      rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000;
+      if (rt.tv_nsec < 0)
+       {
+         rt.tv_nsec += 1000000000;
+         --rt.tv_sec;
+       }
+
+      /* Already timed out?  */
+      if (rt.tv_sec < 0)
+       return ETIMEDOUT;
+
+      /* Wait until thread terminates.  The kernel so far does not use
+        the private futex operations for this.  */
+      if (lll_futex_timed_wait (tidp, tid, &rt, LLL_SHARED) == -ETIMEDOUT)
+       return ETIMEDOUT;
+    }
+
+  return 0;
+}
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/lowlevellock.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/lowlevellock.h
new file mode 100644 (file)
index 0000000..d8fe9be
--- /dev/null
@@ -0,0 +1,297 @@
+/* Copyright (C) 2003, 2004, 2006, 2007, 2008, 2009
+   Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Libr   \ary; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _LOWLEVELLOCK_H
+#define _LOWLEVELLOCK_H        1
+
+#include <time.h>
+#include <sys/param.h>
+#include <bits/pthreadtypes.h>
+#include <atomic.h>
+#include <sysdep.h>
+#include <bits/kernel-features.h>
+
+
+#define FUTEX_WAIT             0
+#define FUTEX_WAKE             1
+#define FUTEX_REQUEUE          3
+#define FUTEX_CMP_REQUEUE      4
+#define FUTEX_WAKE_OP          5
+#define FUTEX_OP_CLEAR_WAKE_IF_GT_ONE  ((4 << 24) | 1)
+#define FUTEX_LOCK_PI          6
+#define FUTEX_UNLOCK_PI                7
+#define FUTEX_TRYLOCK_PI       8
+#define FUTEX_WAIT_BITSET      9
+#define FUTEX_WAKE_BITSET      10
+#define FUTEX_PRIVATE_FLAG     128
+#define FUTEX_CLOCK_REALTIME   256
+
+#define FUTEX_BITSET_MATCH_ANY 0xffffffff
+
+
+/* Values for 'private' parameter of locking macros.  Yes, the
+   definition seems to be backwards.  But it is not.  The bit will be
+   reversed before passing to the system call.  */
+#define LLL_PRIVATE    0
+#define LLL_SHARED     FUTEX_PRIVATE_FLAG
+
+
+#if !defined NOT_IN_libc || defined IS_IN_rtld
+/* In libc.so or ld.so all futexes are private.  */
+# ifdef __ASSUME_PRIVATE_FUTEX
+#  define __lll_private_flag(fl, private) \
+  ((fl) | FUTEX_PRIVATE_FLAG)
+# else
+#  define __lll_private_flag(fl, private) \
+  ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex))
+# endif
+#else
+# ifdef __ASSUME_PRIVATE_FUTEX
+#  define __lll_private_flag(fl, private) \
+  (((fl) | FUTEX_PRIVATE_FLAG) ^ (private))
+# else
+#  define __lll_private_flag(fl, private) \
+  (__builtin_constant_p (private)                                            \
+   ? ((private) == 0                                                         \
+      ? ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex))           \
+      : (fl))                                                                \
+   : ((fl) | (((private) ^ FUTEX_PRIVATE_FLAG)                               \
+             & THREAD_GETMEM (THREAD_SELF, header.private_futex))))
+# endif
+#endif
+
+
+#define lll_futex_wait(futexp, val, private) \
+  lll_futex_timed_wait (futexp, val, NULL, private)
+
+#define lll_futex_timed_wait(futexp, val, timespec, private) \
+  ({                                                                         \
+    INTERNAL_SYSCALL_DECL (__err);                                           \
+    long int __ret;                                                          \
+                                                                             \
+    __ret = INTERNAL_SYSCALL (futex, __err, 4, (futexp),                     \
+                             __lll_private_flag (FUTEX_WAIT, private),       \
+                             (val), (timespec));                             \
+    __ret;                                                                   \
+  })
+
+#define lll_futex_wake(futexp, nr, private) \
+  ({                                                                         \
+    INTERNAL_SYSCALL_DECL (__err);                                           \
+    long int __ret;                                                          \
+                                                                             \
+    __ret = INTERNAL_SYSCALL (futex, __err, 4, (futexp),                     \
+                             __lll_private_flag (FUTEX_WAKE, private),       \
+                             (nr), 0);                                       \
+    __ret;                                                                   \
+  })
+
+/* Returns non-zero if error happened, zero if success.  */
+#define lll_futex_requeue(futexp, nr_wake, nr_move, mutex, val, private) \
+  ({                                                                         \
+    INTERNAL_SYSCALL_DECL (__err);                                           \
+    long int __ret;                                                          \
+                                                                             \
+    __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp),                     \
+                             __lll_private_flag (FUTEX_CMP_REQUEUE, private),\
+                             (nr_wake), (nr_move), (mutex), (val));          \
+    INTERNAL_SYSCALL_ERROR_P (__ret, __err);                                 \
+  })
+
+#define lll_robust_dead(futexv, private) \
+  do                                                                         \
+    {                                                                        \
+      int *__futexp = &(futexv);                                             \
+      atomic_or (__futexp, FUTEX_OWNER_DIED);                                \
+      lll_futex_wake (__futexp, 1, private);                                 \
+    }                                                                        \
+  while (0)
+
+/* Returns non-zero if error happened, zero if success.  */
+#ifdef __sparc32_atomic_do_lock
+/* Avoid FUTEX_WAKE_OP if supporting pre-v9 CPUs.  */
+# define lll_futex_wake_unlock(futexp, nr_wake, nr_wake2, futexp2, private) 1
+#else
+# define lll_futex_wake_unlock(futexp, nr_wake, nr_wake2, futexp2, private) \
+  ({                                                                         \
+    INTERNAL_SYSCALL_DECL (__err);                                           \
+    long int __ret;                                                          \
+                                                                             \
+    __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp),                     \
+                             __lll_private_flag (FUTEX_WAKE_OP, private),    \
+                             (nr_wake), (nr_wake2), (futexp2),               \
+                             FUTEX_OP_CLEAR_WAKE_IF_GT_ONE);                 \
+    INTERNAL_SYSCALL_ERROR_P (__ret, __err);                                 \
+  })
+#endif
+
+static inline int
+__attribute__ ((always_inline))
+__lll_trylock (int *futex)
+{
+  return atomic_compare_and_exchange_val_24_acq (futex, 1, 0) != 0;
+}
+#define lll_trylock(futex) __lll_trylock (&(futex))
+
+static inline int
+__attribute__ ((always_inline))
+__lll_cond_trylock (int *futex)
+{
+  return atomic_compare_and_exchange_val_24_acq (futex, 2, 0) != 0;
+}
+#define lll_cond_trylock(futex) __lll_cond_trylock (&(futex))
+
+static inline int
+__attribute__ ((always_inline))
+__lll_robust_trylock (int *futex, int id)
+{
+  return atomic_compare_and_exchange_val_acq (futex, id, 0) != 0;
+}
+#define lll_robust_trylock(futex, id) \
+  __lll_robust_trylock (&(futex), id)
+
+
+extern void __lll_lock_wait_private (int *futex) attribute_hidden;
+extern void __lll_lock_wait (int *futex, int private) attribute_hidden;
+extern int __lll_robust_lock_wait (int *futex, int private) attribute_hidden;
+
+static inline void
+__attribute__ ((always_inline))
+__lll_lock (int *futex, int private)
+{
+  int val = atomic_compare_and_exchange_val_24_acq (futex, 1, 0);
+
+  if (__builtin_expect (val != 0, 0))
+    {
+      if (__builtin_constant_p (private) && private == LLL_PRIVATE)
+       __lll_lock_wait_private (futex);
+      else
+       __lll_lock_wait (futex, private);
+    }
+}
+#define lll_lock(futex, private) __lll_lock (&(futex), private)
+
+static inline int
+__attribute__ ((always_inline))
+__lll_robust_lock (int *futex, int id, int private)
+{
+  int result = 0;
+  if (atomic_compare_and_exchange_bool_acq (futex, id, 0) != 0)
+    result = __lll_robust_lock_wait (futex, private);
+  return result;
+}
+#define lll_robust_lock(futex, id, private) \
+  __lll_robust_lock (&(futex), id, private)
+
+static inline void
+__attribute__ ((always_inline))
+__lll_cond_lock (int *futex, int private)
+{
+  int val = atomic_compare_and_exchange_val_24_acq (futex, 2, 0);
+
+  if (__builtin_expect (val != 0, 0))
+    __lll_lock_wait (futex, private);
+}
+#define lll_cond_lock(futex, private) __lll_cond_lock (&(futex), private)
+
+#define lll_robust_cond_lock(futex, id, private) \
+  __lll_robust_lock (&(futex), (id) | FUTEX_WAITERS, private)
+
+
+extern int __lll_timedlock_wait (int *futex, const struct timespec *,
+                                int private) attribute_hidden;
+extern int __lll_robust_timedlock_wait (int *futex, const struct timespec *,
+                                       int private) attribute_hidden;
+
+static inline int
+__attribute__ ((always_inline))
+__lll_timedlock (int *futex, const struct timespec *abstime, int private)
+{
+  int val = atomic_compare_and_exchange_val_24_acq (futex, 1, 0);
+  int result = 0;
+
+  if (__builtin_expect (val != 0, 0))
+    result = __lll_timedlock_wait (futex, abstime, private);
+  return result;
+}
+#define lll_timedlock(futex, abstime, private) \
+  __lll_timedlock (&(futex), abstime, private)
+
+static inline int
+__attribute__ ((always_inline))
+__lll_robust_timedlock (int *futex, const struct timespec *abstime,
+                       int id, int private)
+{
+  int result = 0;
+  if (atomic_compare_and_exchange_bool_acq (futex, id, 0) != 0)
+    result = __lll_robust_timedlock_wait (futex, abstime, private);
+  return result;
+}
+#define lll_robust_timedlock(futex, abstime, id, private) \
+  __lll_robust_timedlock (&(futex), abstime, id, private)
+
+#define lll_unlock(lock, private) \
+  ((void) ({                                                                 \
+    int *__futex = &(lock);                                                  \
+    int __val = atomic_exchange_24_rel (__futex, 0);                         \
+    if (__builtin_expect (__val > 1, 0))                                     \
+      lll_futex_wake (__futex, 1, private);                                  \
+  }))
+
+#define lll_robust_unlock(lock, private) \
+  ((void) ({                                                                 \
+    int *__futex = &(lock);                                                  \
+    int __val = atomic_exchange_rel (__futex, 0);                            \
+    if (__builtin_expect (__val & FUTEX_WAITERS, 0))                         \
+      lll_futex_wake (__futex, 1, private);                                  \
+  }))
+
+#define lll_islocked(futex) \
+  (futex != 0)
+
+/* Initializers for lock.  */
+#define LLL_LOCK_INITIALIZER           (0)
+#define LLL_LOCK_INITIALIZER_LOCKED    (1)
+
+/* The kernel notifies a process with uses CLONE_CLEARTID via futex
+   wakeup when the clone terminates.  The memory location contains the
+   thread ID while the clone is running and is reset to zero
+   afterwards. */
+#define lll_wait_tid(tid) \
+  do                                                   \
+    {                                                  \
+      __typeof (tid) __tid;                            \
+      while ((__tid = (tid)) != 0)                     \
+       lll_futex_wait (&(tid), __tid, LLL_SHARED);     \
+    }                                                  \
+  while (0)
+
+extern int __lll_timedwait_tid (int *, const struct timespec *)
+     attribute_hidden;
+
+#define lll_timedwait_tid(tid, abstime) \
+  ({                                                   \
+    int __res = 0;                                     \
+    if ((tid) != 0)                                    \
+      __res = __lll_timedwait_tid (&(tid), (abstime)); \
+    __res;                                             \
+  })
+
+#endif /* lowlevellock.h */
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/pt-vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/pt-vfork.S
new file mode 100644 (file)
index 0000000..e8705c5
--- /dev/null
@@ -0,0 +1,5 @@
+#if defined(__arch64__)
+#include "sparc64/pt-vfork.S"
+#else
+#include "sparc32/pt-vfork.S"
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/pthread_barrier_destroy.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/pthread_barrier_destroy.c
new file mode 100644 (file)
index 0000000..ca96379
--- /dev/null
@@ -0,0 +1,45 @@
+/* Copyright (C) 2002, 2007 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_barrier_destroy (
+     pthread_barrier_t *barrier)
+{
+  union sparc_pthread_barrier *ibarrier;
+  int result = EBUSY;
+
+  ibarrier = (union sparc_pthread_barrier *) barrier;
+
+  int private = ibarrier->s.pshared ? LLL_SHARED : LLL_PRIVATE;
+
+  lll_lock (ibarrier->b.lock, private);
+
+  if (__builtin_expect (ibarrier->b.left == ibarrier->b.init_count, 1))
+    /* The barrier is not used anymore.  */
+    result = 0;
+  else
+    /* Still used, return with an error.  */
+    lll_unlock (ibarrier->b.lock, private);
+
+  return result;
+}
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/pthread_barrier_init.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/pthread_barrier_init.c
new file mode 100644 (file)
index 0000000..8182f1c
--- /dev/null
@@ -0,0 +1,55 @@
+/* Copyright (C) 2002, 2006, 2007 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_barrier_init (
+     pthread_barrier_t *barrier,
+     const pthread_barrierattr_t *attr,
+     unsigned int count)
+{
+  union sparc_pthread_barrier *ibarrier;
+
+  if (__builtin_expect (count == 0, 0))
+    return EINVAL;
+
+  struct pthread_barrierattr *iattr = (struct pthread_barrierattr *) attr;
+  if (iattr != NULL)
+    {
+      if (iattr->pshared != PTHREAD_PROCESS_PRIVATE
+         && __builtin_expect (iattr->pshared != PTHREAD_PROCESS_SHARED, 0))
+       /* Invalid attribute.  */
+       return EINVAL;
+    }
+
+  ibarrier = (union sparc_pthread_barrier *) barrier;
+
+  /* Initialize the individual fields.  */
+  ibarrier->b.lock = LLL_LOCK_INITIALIZER;
+  ibarrier->b.left = count;
+  ibarrier->b.init_count = count;
+  ibarrier->b.curr_event = 0;
+  ibarrier->s.left_lock = 0;
+  ibarrier->s.pshared = (iattr && iattr->pshared == PTHREAD_PROCESS_SHARED);
+
+  return 0;
+}
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/pthread_barrier_wait.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/pthread_barrier_wait.c
new file mode 100644 (file)
index 0000000..73eaa69
--- /dev/null
@@ -0,0 +1 @@
+#include "sparc32/pthread_barrier_wait.c"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/pthread_once.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/pthread_once.c
new file mode 100644 (file)
index 0000000..22e2dd3
--- /dev/null
@@ -0,0 +1,94 @@
+/* Copyright (C) 2003, 2004, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+#include <lowlevellock.h>
+
+
+unsigned long int __fork_generation attribute_hidden;
+
+
+static void
+clear_once_control (void *arg)
+{
+  pthread_once_t *once_control = (pthread_once_t *) arg;
+
+  *once_control = 0;
+  lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE);
+}
+
+
+int
+__pthread_once (once_control, init_routine)
+     pthread_once_t *once_control;
+     void (*init_routine) (void);
+{
+  while (1)
+    {
+      int oldval, val, newval;
+
+      val = *once_control;
+      do
+       {
+         /* Check if the initialized has already been done.  */
+         if ((val & 2) != 0)
+           return 0;
+
+         oldval = val;
+         newval = (oldval & 3) | __fork_generation | 1;
+         val = atomic_compare_and_exchange_val_acq (once_control, newval,
+                                                    oldval);
+       }
+      while (__builtin_expect (val != oldval, 0));
+
+      /* Check if another thread already runs the initializer. */
+      if ((oldval & 1) != 0)
+       {
+         /* Check whether the initializer execution was interrupted
+            by a fork.  */
+         if (((oldval ^ newval) & -4) == 0)
+           {
+             /* Same generation, some other thread was faster. Wait.  */
+             lll_futex_wait (once_control, newval, LLL_PRIVATE);
+             continue;
+           }
+       }
+
+      /* This thread is the first here.  Do the initialization.
+        Register a cleanup handler so that in case the thread gets
+        interrupted the initialization can be restarted.  */
+      pthread_cleanup_push (clear_once_control, once_control);
+
+      init_routine ();
+
+      pthread_cleanup_pop (0);
+
+
+      /* Add one to *once_control.  */
+      atomic_increment (once_control);
+
+      /* Wake up all other threads.  */
+      lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE);
+      break;
+    }
+
+  return 0;
+}
+weak_alias (__pthread_once, pthread_once)
+strong_alias (__pthread_once, __pthread_once_internal)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sem_init.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sem_init.c
new file mode 100644 (file)
index 0000000..f694b5e
--- /dev/null
@@ -0,0 +1,57 @@
+/* Copyright (C) 2002, 2007 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 <string.h>
+#include <semaphore.h>
+#include <lowlevellock.h>
+#include "semaphoreP.h"
+#include <bits/kernel-features.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 sparc_new_sem *isem = (struct sparc_new_sem *) sem;
+
+  /* Use the values the user provided.  */
+  memset (isem, '\0', sizeof (*isem));
+  isem->value = value;
+#ifdef __ASSUME_PRIVATE_FUTEX
+  isem->private = pshared ? 0 : FUTEX_PRIVATE_FLAG;
+#else
+  isem->private = pshared ? 0 : THREAD_GETMEM (THREAD_SELF,
+                                              header.private_futex);
+#endif
+
+  return 0;
+}
+weak_alias(__new_sem_init, sem_init)
+
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/clone.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/clone.S
new file mode 100644 (file)
index 0000000..a6142aa
--- /dev/null
@@ -0,0 +1,2 @@
+#define RESET_PID
+#include <libc/sysdeps/linux/sparc/clone.S>
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/pt-vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/pt-vfork.S
new file mode 100644 (file)
index 0000000..fb01242
--- /dev/null
@@ -0,0 +1,45 @@
+/* Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2004.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <tcb-offsets.h>
+
+       .text
+       .globl          __syscall_error
+ENTRY(__vfork)
+       ld      [%g7 + PID], %o5
+       sub     %g0, %o5, %o4
+       st      %o4, [%g7 + PID]
+
+       LOADSYSCALL(vfork)
+       ta      0x10
+       bcc     2f
+        mov    %o7, %g1
+       st      %o5, [%g7 + PID]
+       call    __syscall_error
+        mov    %g1, %o7
+2:     sub     %o1, 1, %o1
+       andcc   %o0, %o1, %o0
+       bne,a   1f
+        st     %o5, [%g7 + PID]
+1:     retl
+        nop
+END(__vfork)
+
+weak_alias (__vfork, vfork)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/pthread_barrier_wait.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/pthread_barrier_wait.c
new file mode 100644 (file)
index 0000000..302d1b3
--- /dev/null
@@ -0,0 +1,94 @@
+/* Copyright (C) 2003, 2004, 2006, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <pthreadP.h>
+
+/* Wait on barrier.  */
+int
+pthread_barrier_wait (
+     pthread_barrier_t *barrier)
+{
+  union sparc_pthread_barrier *ibarrier
+    = (union sparc_pthread_barrier *) barrier;
+  int result = 0;
+  int private = ibarrier->s.pshared ? LLL_SHARED : LLL_PRIVATE;
+
+  /* Make sure we are alone.  */
+  lll_lock (ibarrier->b.lock, private);
+
+  /* One more arrival.  */
+  --ibarrier->b.left;
+
+  /* Are these all?  */
+  if (ibarrier->b.left == 0)
+    {
+      /* Yes. Increment the event counter to avoid invalid wake-ups and
+        tell the current waiters that it is their turn.  */
+      ++ibarrier->b.curr_event;
+
+      /* Wake up everybody.  */
+      lll_futex_wake (&ibarrier->b.curr_event, INT_MAX, private);
+
+      /* This is the thread which finished the serialization.  */
+      result = PTHREAD_BARRIER_SERIAL_THREAD;
+    }
+  else
+    {
+      /* The number of the event we are waiting for.  The barrier's event
+        number must be bumped before we continue.  */
+      unsigned int event = ibarrier->b.curr_event;
+
+      /* Before suspending, make the barrier available to others.  */
+      lll_unlock (ibarrier->b.lock, private);
+
+      /* Wait for the event counter of the barrier to change.  */
+      do
+       lll_futex_wait (&ibarrier->b.curr_event, event, private);
+      while (event == ibarrier->b.curr_event);
+    }
+
+  /* Make sure the init_count is stored locally or in a register.  */
+  unsigned int init_count = ibarrier->b.init_count;
+
+  /* If this was the last woken thread, unlock.  */
+  if (__atomic_is_v9 || ibarrier->s.pshared == 0)
+    {
+      if (atomic_increment_val (&ibarrier->b.left) == init_count)
+       /* We are done.  */
+       lll_unlock (ibarrier->b.lock, private);
+    }
+  else
+    {
+      unsigned int left;
+      /* Slightly more complicated.  On pre-v9 CPUs, atomic_increment_val
+        is only atomic for threads within the same process, not for
+        multiple processes.  */
+      __sparc32_atomic_do_lock24 (&ibarrier->s.left_lock);
+      left = ++ibarrier->b.left;
+      __sparc32_atomic_do_unlock24 (&ibarrier->s.left_lock);
+      if (left == init_count)
+        /* We are done.  */
+       lll_unlock (ibarrier->b.lock, private);
+    }
+
+  return result;
+}
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sem_post.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sem_post.c
new file mode 100644 (file)
index 0000000..940728e
--- /dev/null
@@ -0,0 +1,55 @@
+/* sem_post -- post to a POSIX semaphore.  SPARC version.
+   Copyright (C) 2003, 2004, 2006, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <internaltypes.h>
+#include <semaphore.h>
+
+int
+__new_sem_post (sem_t *sem)
+{
+  struct sparc_new_sem *isem = (struct sparc_new_sem *) sem;
+  int nr;
+
+  if (__atomic_is_v9)
+    nr = atomic_increment_val (&isem->value);
+  else
+    {
+      __sparc32_atomic_do_lock24 (&isem->lock);
+      nr = ++(isem->value);
+      __sparc32_atomic_do_unlock24 (&isem->lock);
+    }
+  atomic_full_barrier ();
+  if (isem->nwaiters > 0)
+    {
+      int err = lll_futex_wake (&isem->value, 1,
+                               isem->private ^ FUTEX_PRIVATE_FLAG);
+      if (__builtin_expect (err, 0) < 0)
+       {
+         __set_errno (-err);
+         return -1;
+       }
+    }
+  return 0;
+}
+weak_alias(__new_sem_post, sem_post)
+
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sem_timedwait.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sem_timedwait.c
new file mode 100644 (file)
index 0000000..aa5bd80
--- /dev/null
@@ -0,0 +1,148 @@
+/* sem_timedwait -- wait on a semaphore.  SPARC version.
+   Copyright (C) 2003, 2006, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <internaltypes.h>
+#include <semaphore.h>
+
+#include <pthreadP.h>
+
+
+extern void __sem_wait_cleanup (void *arg) attribute_hidden;
+
+
+int
+sem_timedwait (sem_t *sem, const struct timespec *abstime)
+{
+  struct sparc_new_sem *isem = (struct sparc_new_sem *) sem;
+  int err;
+  int val;
+
+  if (__atomic_is_v9)
+    val = atomic_decrement_if_positive (&isem->value);
+  else
+    {
+      __sparc32_atomic_do_lock24 (&isem->lock);
+      val = isem->value;
+      if (val > 0)
+        isem->value = val - 1;
+      __sparc32_atomic_do_unlock24 (&isem->lock);
+    }
+
+  if (val > 0)
+    return 0;
+
+  if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)
+    {
+      __set_errno (EINVAL);
+      return -1;
+    }
+
+  if (__atomic_is_v9)
+    atomic_increment (&isem->nwaiters);
+  else
+    {
+      __sparc32_atomic_do_lock24 (&isem->lock);
+      isem->nwaiters++;
+      __sparc32_atomic_do_unlock24 (&isem->lock);
+    }
+
+  pthread_cleanup_push (__sem_wait_cleanup, isem);
+
+  while (1)
+    {
+      struct timeval tv;
+      struct timespec rt;
+      int sec, nsec;
+
+      /* Get the current time.  */
+      __gettimeofday (&tv, NULL);
+
+      /* Compute relative timeout.  */
+      sec = abstime->tv_sec - tv.tv_sec;
+      nsec = abstime->tv_nsec - tv.tv_usec * 1000;
+      if (nsec < 0)
+       {
+         nsec += 1000000000;
+         --sec;
+       }
+
+      /* Already timed out?  */
+      err = -ETIMEDOUT;
+      if (sec < 0)
+       {
+         __set_errno (ETIMEDOUT);
+         err = -1;
+         break;
+       }
+
+      /* Do wait.  */
+      rt.tv_sec = sec;
+      rt.tv_nsec = nsec;
+
+      /* Enable asynchronous cancellation.  Required by the standard.  */
+      int oldtype = __pthread_enable_asynccancel ();
+
+      err = lll_futex_timed_wait (&isem->value, 0, &rt,
+                                 isem->private ^ FUTEX_PRIVATE_FLAG);
+
+      /* Disable asynchronous cancellation.  */
+      __pthread_disable_asynccancel (oldtype);
+
+      if (err != 0 && err != -EWOULDBLOCK)
+       {
+         __set_errno (-err);
+         err = -1;
+         break;
+       }
+
+      if (__atomic_is_v9)
+       val = atomic_decrement_if_positive (&isem->value);
+      else
+       {
+         __sparc32_atomic_do_lock24 (&isem->lock);
+         val = isem->value;
+         if (val > 0)
+           isem->value = val - 1;
+         __sparc32_atomic_do_unlock24 (&isem->lock);
+       }
+
+      if (val > 0)
+       {
+         err = 0;
+         break;
+       }
+    }
+
+  pthread_cleanup_pop (0);
+
+  if (__atomic_is_v9)
+    atomic_decrement (&isem->nwaiters);
+  else
+    {
+      __sparc32_atomic_do_lock24 (&isem->lock);
+      isem->nwaiters--;
+      __sparc32_atomic_do_unlock24 (&isem->lock);
+    }
+
+  return err;
+}
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sem_trywait.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sem_trywait.c
new file mode 100644 (file)
index 0000000..d4e8938
--- /dev/null
@@ -0,0 +1,54 @@
+/* sem_trywait -- wait on a semaphore.  SPARC version.
+   Copyright (C) 2003, 2006, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <internaltypes.h>
+#include <semaphore.h>
+
+
+int
+__new_sem_trywait (sem_t *sem)
+{
+  struct sparc_old_sem *isem = (struct sparc_old_sem *) sem;
+  int val;
+
+  if (isem->value > 0)
+    {
+      if (__atomic_is_v9)
+       val = atomic_decrement_if_positive (&isem->value);
+      else
+       {
+         __sparc32_atomic_do_lock24 (&isem->lock);
+         val = isem->value;
+         if (val > 0)
+           isem->value = val - 1;
+         __sparc32_atomic_do_unlock24 (&isem->lock);
+       }
+      if (val > 0)
+       return 0;
+    }
+
+  __set_errno (EAGAIN);
+  return -1;
+}
+weak_alias(__new_sem_trywait, sem_trywait)
+
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sem_wait.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sem_wait.c
new file mode 100644 (file)
index 0000000..cfe04a8
--- /dev/null
@@ -0,0 +1,127 @@
+/* sem_wait -- wait on a semaphore.  Generic futex-using version.
+   Copyright (C) 2003, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <internaltypes.h>
+#include <semaphore.h>
+
+#include <pthreadP.h>
+
+
+void
+attribute_hidden
+__sem_wait_cleanup (void *arg)
+{
+  struct sparc_new_sem *isem = (struct sparc_new_sem *) arg;
+
+  if (__atomic_is_v9)
+    atomic_decrement (&isem->nwaiters);
+  else
+    {
+      __sparc32_atomic_do_lock24 (&isem->lock);
+      isem->nwaiters--;
+      __sparc32_atomic_do_unlock24 (&isem->lock);
+    }
+}
+
+
+int
+__new_sem_wait (sem_t *sem)
+{
+  struct sparc_new_sem *isem = (struct sparc_new_sem *) sem;
+  int err;
+  int val;
+
+  if (__atomic_is_v9)
+    val = atomic_decrement_if_positive (&isem->value);
+  else
+    {
+      __sparc32_atomic_do_lock24 (&isem->lock);
+      val = isem->value;
+      if (val > 0)
+       isem->value = val - 1;
+      else
+       isem->nwaiters++;
+      __sparc32_atomic_do_unlock24 (&isem->lock);
+    }
+
+  if (val > 0)
+    return 0;
+
+  if (__atomic_is_v9)
+    atomic_increment (&isem->nwaiters);
+  else
+    /* Already done above while still holding isem->lock.  */;
+
+  pthread_cleanup_push (__sem_wait_cleanup, isem);
+
+  while (1)
+    {
+      /* Enable asynchronous cancellation.  Required by the standard.  */
+      int oldtype = __pthread_enable_asynccancel ();
+
+      err = lll_futex_wait (&isem->value, 0,
+                           isem->private ^ FUTEX_PRIVATE_FLAG);
+
+      /* Disable asynchronous cancellation.  */
+      __pthread_disable_asynccancel (oldtype);
+
+      if (err != 0 && err != -EWOULDBLOCK)
+       {
+         __set_errno (-err);
+         err = -1;
+         break;
+       }
+
+      if (__atomic_is_v9)
+       val = atomic_decrement_if_positive (&isem->value);
+      else
+       {
+         __sparc32_atomic_do_lock24 (&isem->lock);
+         val = isem->value;
+         if (val > 0)
+           isem->value = val - 1;
+         __sparc32_atomic_do_unlock24 (&isem->lock);
+       }
+
+      if (val > 0)
+       {
+         err = 0;
+         break;
+       }
+    }
+
+  pthread_cleanup_pop (0);
+
+  if (__atomic_is_v9)
+    atomic_decrement (&isem->nwaiters);
+  else
+    {
+      __sparc32_atomic_do_lock24 (&isem->lock);
+      isem->nwaiters--;
+      __sparc32_atomic_do_unlock24 (&isem->lock);
+    }
+
+  return err;
+}
+weak_alias(__new_sem_wait, sem_wait)
+
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sysdep-cancel.h
new file mode 100644 (file)
index 0000000..1f55bd6
--- /dev/null
@@ -0,0 +1,112 @@
+/* Copyright (C) 2002, 2003, 2004, 2006 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <tls.h>
+#include <sysdep.h>
+#ifndef __ASSEMBLER__
+# include <pthreadP.h>
+#endif
+
+#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt
+
+# undef PSEUDO
+# define PSEUDO(name, syscall_name, args)      \
+       .text;                                  \
+       .globl          __syscall_error;        \
+ENTRY(name)                                    \
+       ld [%g7 + MULTIPLE_THREADS_OFFSET], %g1;\
+       cmp %g1, 0;                             \
+       bne 1f;                                 \
+.type  __##syscall_name##_nocancel,@function;  \
+.globl __##syscall_name##_nocancel;            \
+__##syscall_name##_nocancel:                   \
+        mov SYS_ify(syscall_name), %g1;        \
+       ta 0x10;                                \
+       bcc 8f;                                 \
+        mov %o7, %g1;                          \
+       call __syscall_error;                   \
+        mov %g1, %o7;                          \
+8:     jmpl %o7 + 8, %g0;                      \
+        nop;                                   \
+.size  __##syscall_name##_nocancel,.-__##syscall_name##_nocancel;\
+1:     save %sp, -96, %sp;                     \
+       cfi_def_cfa_register(%fp);              \
+       cfi_window_save;                        \
+       cfi_register(%o7, %i7);                 \
+       CENABLE;                                \
+        nop;                                   \
+       mov %o0, %l0;                           \
+       COPY_ARGS_##args                        \
+       mov SYS_ify(syscall_name), %g1;         \
+       ta 0x10;                                \
+       bcc 1f;                                 \
+        mov %o0, %l1;                          \
+       CDISABLE;                               \
+        mov %l0, %o0;                          \
+       call __syscall_error;                   \
+        mov %l1, %o0;                          \
+       b 2f;                                   \
+        mov -1, %l1;                           \
+1:     CDISABLE;                               \
+        mov %l0, %o0;                          \
+2:     jmpl %i7 + 8, %g0;                      \
+        restore %g0, %l1, %o0;
+
+
+# ifdef IS_IN_libpthread
+#  define CENABLE      call __pthread_enable_asynccancel
+#  define CDISABLE     call __pthread_disable_asynccancel
+# elif !defined NOT_IN_libc
+#  define CENABLE      call __libc_enable_asynccancel
+#  define CDISABLE     call __libc_disable_asynccancel
+# elif defined IS_IN_librt
+#  define CENABLE      call __librt_enable_asynccancel
+#  define CDISABLE     call __librt_disable_asynccancel
+# else
+#  error Unsupported library
+# endif
+
+#define COPY_ARGS_0    /* Nothing */
+#define COPY_ARGS_1    COPY_ARGS_0 mov %i0, %o0;
+#define COPY_ARGS_2    COPY_ARGS_1 mov %i1, %o1;
+#define COPY_ARGS_3    COPY_ARGS_2 mov %i2, %o2;
+#define COPY_ARGS_4    COPY_ARGS_3 mov %i3, %o3;
+#define COPY_ARGS_5    COPY_ARGS_4 mov %i4, %o4;
+#define COPY_ARGS_6    COPY_ARGS_5 mov %i5, %o5;
+
+# ifndef __ASSEMBLER__
+#  define SINGLE_THREAD_P \
+  __builtin_expect (THREAD_GETMEM (THREAD_SELF,                                      \
+                                  header.multiple_threads) == 0, 1)
+# else
+#  define SINGLE_THREAD_P ld [%g7 + MULTIPLE_THREADS_OFFSET], %g1
+# endif
+
+#elif !defined __ASSEMBLER__
+
+# define SINGLE_THREAD_P (1)
+# define NO_CANCELLATION 1
+
+#endif
+
+#ifndef __ASSEMBLER__
+# define RTLD_SINGLE_THREAD_P \
+  __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
+                                  header.multiple_threads) == 0, 1)
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S
new file mode 100644 (file)
index 0000000..8ee9868
--- /dev/null
@@ -0,0 +1,49 @@
+/* Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2004.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <tcb-offsets.h>
+
+       .text
+       .globl          __syscall_error
+ENTRY(__vfork)
+       ld      [%g7 + PID], %o5
+       cmp     %o5, 0
+       bne     1f
+        sub    %g0, %o5, %o4
+       sethi   %hi(0x80000000), %o4
+1:     st      %o4, [%g7 + PID]
+
+       LOADSYSCALL(vfork)
+       ta      0x10
+       bcc     2f
+        mov    %o7, %g1
+       st      %o5, [%g7 + PID]
+       call    __syscall_error
+        mov    %g1, %o7
+2:     sub     %o1, 1, %o1
+       andcc   %o0, %o1, %o0
+       bne,a   1f
+        st     %o5, [%g7 + PID]
+1:     retl
+        nop
+END(__vfork)
+
+libc_hidden_def (vfork)
+weak_alias (__vfork, vfork)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/clone.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/clone.S
new file mode 100644 (file)
index 0000000..64e3bfc
--- /dev/null
@@ -0,0 +1,2 @@
+#define RESET_PID
+#include <libc/sysdeps/linux/sparc/sparcv9/clone.S>
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/pt-vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/pt-vfork.S
new file mode 100644 (file)
index 0000000..8941043
--- /dev/null
@@ -0,0 +1,45 @@
+/* Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2004.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <tcb-offsets.h>
+
+       .text
+       .globl  __syscall_error
+ENTRY(__vfork)
+       ld      [%g7 + PID], %o5
+       sub     %g0, %o5, %o4
+       st      %o4, [%g7 + PID]
+
+       LOADSYSCALL(vfork)
+       ta      0x6d
+       bcc,pt  %xcc, 2f
+        mov    %o7, %g1
+       st      %o5, [%g7 + PID]
+       call    __syscall_error
+        mov    %g1, %o7
+2:     sub     %o1, 1, %o1
+       andcc   %o0, %o1, %o0
+       bne,a,pt %icc, 1f
+        st     %o5, [%g7 + PID]
+1:     retl
+        nop
+END(__vfork)
+
+weak_alias (__vfork, vfork)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/sysdep-cancel.h
new file mode 100644 (file)
index 0000000..aec2d4a
--- /dev/null
@@ -0,0 +1,110 @@
+/* Copyright (C) 2002, 2003, 2004, 2006 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <tls.h>
+#ifndef __ASSEMBLER__
+# include <pthreadP.h>
+#endif
+
+#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt
+
+# undef PSEUDO
+# define PSEUDO(name, syscall_name, args)      \
+       .text;                                  \
+       .globl          __syscall_error;        \
+ENTRY(name)                                    \
+       ld [%g7 + MULTIPLE_THREADS_OFFSET], %g1;\
+       brnz,pn %g1, 1f;                        \
+.type  __##syscall_name##_nocancel,@function;  \
+.globl __##syscall_name##_nocancel;            \
+__##syscall_name##_nocancel:                   \
+        mov SYS_ify(syscall_name), %g1;        \
+       ta 0x6d;                                \
+       bcc,pt %xcc, 8f;                        \
+        mov %o7, %g1;                          \
+       call __syscall_error;                   \
+        mov %g1, %o7;                          \
+8:     jmpl %o7 + 8, %g0;                      \
+        nop;                                   \
+.size  __##syscall_name##_nocancel,.-__##syscall_name##_nocancel;\
+1:     save %sp, -192, %sp;                    \
+       cfi_def_cfa_register(%fp);              \
+       cfi_window_save;                        \
+       cfi_register(%o7, %i7);                 \
+       CENABLE;                                \
+        nop;                                   \
+       mov %o0, %l0;                           \
+       COPY_ARGS_##args                        \
+       mov SYS_ify(syscall_name), %g1;         \
+       ta 0x6d;                                \
+       bcc,pt %xcc, 1f;                        \
+        mov %o0, %l1;                          \
+       CDISABLE;                               \
+        mov %l0, %o0;                          \
+       call __syscall_error;                   \
+        mov %l1, %o0;                          \
+       ba,pt %xcc, 2f;                         \
+        mov -1, %l1;                           \
+1:     CDISABLE;                               \
+        mov %l0, %o0;                          \
+2:     jmpl %i7 + 8, %g0;                      \
+        restore %g0, %l1, %o0;
+
+# ifdef IS_IN_libpthread
+#  define CENABLE      call __pthread_enable_asynccancel
+#  define CDISABLE     call __pthread_disable_asynccancel
+# elif !defined NOT_IN_libc
+#  define CENABLE      call __libc_enable_asynccancel
+#  define CDISABLE     call __libc_disable_asynccancel
+# elif defined IS_IN_librt
+#  define CENABLE      call __librt_enable_asynccancel
+#  define CDISABLE     call __librt_disable_asynccancel
+# else
+#  error Unsupported library
+# endif
+
+#define COPY_ARGS_0    /* Nothing */
+#define COPY_ARGS_1    COPY_ARGS_0 mov %i0, %o0;
+#define COPY_ARGS_2    COPY_ARGS_1 mov %i1, %o1;
+#define COPY_ARGS_3    COPY_ARGS_2 mov %i2, %o2;
+#define COPY_ARGS_4    COPY_ARGS_3 mov %i3, %o3;
+#define COPY_ARGS_5    COPY_ARGS_4 mov %i4, %o4;
+#define COPY_ARGS_6    COPY_ARGS_5 mov %i5, %o5;
+
+# ifndef __ASSEMBLER__
+#  define SINGLE_THREAD_P \
+  __builtin_expect (THREAD_GETMEM (THREAD_SELF,                                      \
+                                  header.multiple_threads) == 0, 1)
+# else
+#  define SINGLE_THREAD_P ld [%g7 + MULTIPLE_THREADS_OFFSET], %g1
+# endif
+
+#elif !defined __ASSEMBLER__
+
+# define SINGLE_THREAD_P (1)
+# define NO_CANCELLATION 1
+
+#endif
+
+#ifndef __ASSEMBLER__
+# define RTLD_SINGLE_THREAD_P \
+  __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
+                                  header.multiple_threads) == 0, 1)
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_create.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_create.c
new file mode 100644 (file)
index 0000000..0a9c337
--- /dev/null
@@ -0,0 +1 @@
+#include "../../x86_64/timer_create.c"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_delete.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_delete.c
new file mode 100644 (file)
index 0000000..f0d4fd2
--- /dev/null
@@ -0,0 +1 @@
+#include "../../x86_64/timer_delete.c"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_getoverr.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_getoverr.c
new file mode 100644 (file)
index 0000000..82121a7
--- /dev/null
@@ -0,0 +1 @@
+#include "../../x86_64/timer_getoverr.c"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_gettime.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_gettime.c
new file mode 100644 (file)
index 0000000..313c05f
--- /dev/null
@@ -0,0 +1 @@
+#include "../../x86_64/timer_gettime.c"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_settime.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_settime.c
new file mode 100644 (file)
index 0000000..76f549c
--- /dev/null
@@ -0,0 +1 @@
+#include "../../x86_64/timer_settime.c"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S
new file mode 100644 (file)
index 0000000..b4e89ac
--- /dev/null
@@ -0,0 +1,49 @@
+/* Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2004.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <tcb-offsets.h>
+
+       .text
+       .globl  __syscall_error
+ENTRY(__vfork)
+       ld      [%g7 + PID], %o5
+       sethi   %hi(0x80000000), %o3
+       cmp     %o5, 0
+       sub     %g0, %o5, %o4
+       move    %icc, %o3, %o4
+       st      %o4, [%g7 + PID]
+
+       LOADSYSCALL(vfork)
+       ta      0x6d
+       bcc,pt  %xcc, 2f
+        mov    %o7, %g1
+       st      %o5, [%g7 + PID]
+       call    __syscall_error
+        mov    %g1, %o7
+2:     sub     %o1, 1, %o1
+       andcc   %o0, %o1, %o0
+       bne,a,pt %icc, 1f
+        st     %o5, [%g7 + PID]
+1:     retl
+        nop
+END(__vfork)
+
+hidden_def (vfork)
+weak_alias (__vfork, vfork)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sysdep-cancel.h
new file mode 100644 (file)
index 0000000..5be9beb
--- /dev/null
@@ -0,0 +1,5 @@
+#if defined(__arch64__)
+#include "sparc64/sysdep-cancel.h"
+#else
+#include "sparc32/sysdep-cancel.h"
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/vfork.S
new file mode 100644 (file)
index 0000000..160cd0b
--- /dev/null
@@ -0,0 +1,5 @@
+#if defined(__arch64__)
+#include "sparc64/vfork.S"
+#else
+#include "sparc32/vfork.S"
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/structsem.sym b/libpthread/nptl/sysdeps/unix/sysv/linux/structsem.sym
new file mode 100644 (file)
index 0000000..0e2a15f
--- /dev/null
@@ -0,0 +1,12 @@
+#include <limits.h>
+#include <stddef.h>
+#include <sched.h>
+#include <bits/pthreadtypes.h>
+#include "internaltypes.h"
+
+--
+
+VALUE          offsetof (struct new_sem, value)
+PRIVATE                offsetof (struct new_sem, private)
+NWAITERS       offsetof (struct new_sem, nwaiters)
+SEM_VALUE_MAX  SEM_VALUE_MAX
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/timer_create.c b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_create.c
new file mode 100644 (file)
index 0000000..a7da2a0
--- /dev/null
@@ -0,0 +1,243 @@
+/* Copyright (C) 2003,2004, 2007, 2009 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <sysdep.h>
+#include <bits/kernel-features.h>
+#include <internaltypes.h>
+#include <pthreadP.h>
+#include "kernel-posix-timers.h"
+#include "kernel-posix-cpu-timers.h"
+
+
+#ifdef __NR_timer_create
+# ifndef __ASSUME_POSIX_TIMERS
+static int compat_timer_create (clockid_t clock_id, struct sigevent *evp,
+                               timer_t *timerid);
+#  define timer_create static compat_timer_create
+#  include <nptl/sysdeps/pthread/timer_create.c>
+#  undef timer_create
+
+/* Nonzero if the system calls are not available.  */
+int __no_posix_timers attribute_hidden;
+# endif
+
+# ifdef timer_create_alias
+#  define timer_create timer_create_alias
+# endif
+
+
+int
+timer_create (
+     clockid_t clock_id,
+     struct sigevent *evp,
+     timer_t *timerid)
+{
+# undef timer_create
+# ifndef __ASSUME_POSIX_TIMERS
+  if  (__no_posix_timers >= 0)
+# endif
+    {
+      clockid_t syscall_clockid = (clock_id == CLOCK_PROCESS_CPUTIME_ID
+                                  ? MAKE_PROCESS_CPUCLOCK (0, CPUCLOCK_SCHED)
+                                  : clock_id == CLOCK_THREAD_CPUTIME_ID
+                                  ? MAKE_THREAD_CPUCLOCK (0, CPUCLOCK_SCHED)
+                                  : clock_id);
+
+      /* If the user wants notification via a thread we need to handle
+        this special.  */
+      if (evp == NULL
+         || __builtin_expect (evp->sigev_notify != SIGEV_THREAD, 1))
+       {
+         struct sigevent local_evp;
+
+         /* We avoid allocating too much memory by basically
+            using struct timer as a derived class with the
+            first two elements being in the superclass.  We only
+            need these two elements here.  */
+         struct timer *newp = (struct timer *) malloc (offsetof (struct timer,
+                                                                 thrfunc));
+         if (newp == NULL)
+           /* No more memory.  */
+           return -1;
+
+         if (evp == NULL)
+           {
+             /* The kernel has to pass up the timer ID which is a
+                userlevel object.  Therefore we cannot leave it up to
+                the kernel to determine it.  */
+             local_evp.sigev_notify = SIGEV_SIGNAL;
+             local_evp.sigev_signo = SIGALRM;
+             local_evp.sigev_value.sival_ptr = newp;
+
+             evp = &local_evp;
+           }
+
+         kernel_timer_t ktimerid;
+         int retval = INLINE_SYSCALL (timer_create, 3, syscall_clockid, evp,
+                                      &ktimerid);
+
+# ifndef __ASSUME_POSIX_TIMERS
+         if (retval != -1 || errno != ENOSYS)
+# endif
+           {
+# ifndef __ASSUME_POSIX_TIMERS
+             __no_posix_timers = 1;
+# endif
+
+             if (retval != -1)
+               {
+                 newp->sigev_notify = (evp != NULL
+                                       ? evp->sigev_notify : SIGEV_SIGNAL);
+                 newp->ktimerid = ktimerid;
+
+                 *timerid = (timer_t) newp;
+               }
+             else
+               {
+                 /* Cannot allocate the timer, fail.  */
+                 free (newp);
+                 retval = -1;
+               }
+
+             return retval;
+           }
+
+         free (newp);
+
+# ifndef __ASSUME_POSIX_TIMERS
+         /* When we come here the syscall does not exist.  Make sure we
+            do not try to use it again.  */
+         __no_posix_timers = -1;
+# endif
+       }
+      else
+       {
+# ifndef __ASSUME_POSIX_TIMERS
+         /* Make sure we have the necessary kernel support.  */
+         if (__no_posix_timers == 0)
+           {
+             INTERNAL_SYSCALL_DECL (err);
+             struct timespec ts;
+             int res;
+             res = INTERNAL_SYSCALL (clock_getres, err, 2,
+                                     CLOCK_REALTIME, &ts);
+             __no_posix_timers = (INTERNAL_SYSCALL_ERROR_P (res, err)
+                                  ? -1 : 1);
+           }
+
+         if (__no_posix_timers > 0)
+# endif
+           {
+             /* Create the helper thread.  */
+             pthread_once (&__helper_once, __start_helper_thread);
+             if (__helper_tid == 0)
+               {
+                 /* No resources to start the helper thread.  */
+                 __set_errno (EAGAIN);
+                 return -1;
+               }
+
+             struct timer *newp;
+             newp = (struct timer *) malloc (sizeof (struct timer));
+             if (newp == NULL)
+               return -1;
+
+             /* Copy the thread parameters the user provided.  */
+             newp->sival = evp->sigev_value;
+             newp->thrfunc = evp->sigev_notify_function;
+             newp->sigev_notify = SIGEV_THREAD;
+
+             /* We cannot simply copy the thread attributes since the
+                implementation might keep internal information for
+                each instance.  */
+             (void) pthread_attr_init (&newp->attr);
+             if (evp->sigev_notify_attributes != NULL)
+               {
+                 struct pthread_attr *nattr;
+                 struct pthread_attr *oattr;
+
+                 nattr = (struct pthread_attr *) &newp->attr;
+                 oattr = (struct pthread_attr *) evp->sigev_notify_attributes;
+
+                 nattr->schedparam = oattr->schedparam;
+                 nattr->schedpolicy = oattr->schedpolicy;
+                 nattr->flags = oattr->flags;
+                 nattr->guardsize = oattr->guardsize;
+                 nattr->stackaddr = oattr->stackaddr;
+                 nattr->stacksize = oattr->stacksize;
+               }
+
+             /* In any case set the detach flag.  */
+             (void) pthread_attr_setdetachstate (&newp->attr,
+                                                 PTHREAD_CREATE_DETACHED);
+
+             /* Create the event structure for the kernel timer.  */
+             struct sigevent sev =
+               { .sigev_value.sival_ptr = newp,
+                 .sigev_signo = SIGTIMER,
+                 .sigev_notify = SIGEV_SIGNAL | SIGEV_THREAD_ID,
+                 ._sigev_un = { ._pad = { [0] = __helper_tid } } };
+
+             /* Create the timer.  */
+             INTERNAL_SYSCALL_DECL (err);
+             int res;
+             res = INTERNAL_SYSCALL (timer_create, err, 3,
+                                     syscall_clockid, &sev, &newp->ktimerid);
+             if (! INTERNAL_SYSCALL_ERROR_P (res, err))
+               {
+                 /* Add to the queue of active timers with thread
+                    delivery.  */
+                 pthread_mutex_lock (&__active_timer_sigev_thread_lock);
+                 newp->next = __active_timer_sigev_thread;
+                 __active_timer_sigev_thread = newp;
+                 pthread_mutex_unlock (&__active_timer_sigev_thread_lock);
+
+                 *timerid = (timer_t) newp;
+                 return 0;
+               }
+
+             /* Free the resources.  */
+             free (newp);
+
+             __set_errno (INTERNAL_SYSCALL_ERRNO (res, err));
+
+             return -1;
+           }
+       }
+    }
+
+# ifndef __ASSUME_POSIX_TIMERS
+  /* Compatibility code.  */
+  return compat_timer_create (clock_id, evp, timerid);
+# endif
+}
+#else
+# ifdef timer_create_alias
+#  define timer_create timer_create_alias
+# endif
+/* The new system calls are not available.  Use the userlevel
+   implementation.  */
+# include <nptl/sysdeps/pthread/timer_create.c>
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/timer_delete.c b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_delete.c
new file mode 100644 (file)
index 0000000..5ad40b9
--- /dev/null
@@ -0,0 +1,115 @@
+/* Copyright (C) 2003, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sysdep.h>
+#include <bits/kernel-features.h>
+#include "kernel-posix-timers.h"
+
+
+#ifdef __NR_timer_delete
+# ifndef __ASSUME_POSIX_TIMERS
+static int compat_timer_delete (timer_t timerid);
+#  define timer_delete static compat_timer_delete
+#  include <nptl/sysdeps/pthread/timer_delete.c>
+#  undef timer_delete
+# endif
+
+# ifdef timer_delete_alias
+#  define timer_delete timer_delete_alias
+# endif
+
+
+int
+timer_delete (
+     timer_t timerid)
+{
+# undef timer_delete
+# ifndef __ASSUME_POSIX_TIMERS
+  if (__no_posix_timers >= 0)
+# endif
+    {
+      struct timer *kt = (struct timer *) timerid;
+
+      /* Delete the kernel timer object.  */
+      int res = INLINE_SYSCALL (timer_delete, 1, kt->ktimerid);
+
+      if (res == 0)
+       {
+         if (kt->sigev_notify == SIGEV_THREAD)
+           {
+             /* Remove the timer from the list.  */
+             pthread_mutex_lock (&__active_timer_sigev_thread_lock);
+             if (__active_timer_sigev_thread == kt)
+               __active_timer_sigev_thread = kt->next;
+             else
+               {
+                 struct timer *prevp = __active_timer_sigev_thread;
+                 while (prevp->next != NULL)
+                   if (prevp->next == kt)
+                     {
+                       prevp->next = kt->next;
+                       break;
+                     }
+                   else
+                     prevp = prevp->next;
+               }
+             pthread_mutex_unlock (&__active_timer_sigev_thread_lock);
+           }
+
+# ifndef __ASSUME_POSIX_TIMERS
+         /* We know the syscall support is available.  */
+         __no_posix_timers = 1;
+# endif
+
+         /* Free the memory.  */
+         (void) free (kt);
+
+         return 0;
+       }
+
+      /* The kernel timer is not known or something else bad happened.
+        Return the error.  */
+# ifndef __ASSUME_POSIX_TIMERS
+      if (errno != ENOSYS)
+       {
+         __no_posix_timers = 1;
+# endif
+         return -1;
+# ifndef __ASSUME_POSIX_TIMERS
+       }
+
+      __no_posix_timers = -1;
+# endif
+    }
+
+# ifndef __ASSUME_POSIX_TIMERS
+  return compat_timer_delete (timerid);
+# endif
+}
+#else
+# ifdef timer_delete_alias
+#  define timer_delete timer_delete_alias
+# endif
+/* The new system calls are not available.  Use the userlevel
+   implementation.  */
+# include <nptl/sysdeps/pthread/timer_delete.c>
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/timer_getoverr.c b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_getoverr.c
new file mode 100644 (file)
index 0000000..62a558a
--- /dev/null
@@ -0,0 +1,81 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <errno.h>
+#include <time.h>
+#include <sysdep.h>
+#include <bits/kernel-features.h>
+#include "kernel-posix-timers.h"
+
+
+#ifdef __NR_timer_getoverrun
+# ifndef __ASSUME_POSIX_TIMERS
+static int compat_timer_getoverrun (timer_t timerid);
+#  define timer_getoverrun static compat_timer_getoverrun
+#  include <nptl/sysdeps/pthread/timer_getoverr.c>
+#  undef timer_getoverrun
+# endif
+
+# ifdef timer_getoverrun_alias
+#  define timer_getoverrun timer_getoverrun_alias
+# endif
+
+
+int
+timer_getoverrun (
+     timer_t timerid)
+{
+# undef timer_getoverrun
+# ifndef __ASSUME_POSIX_TIMERS
+  if (__no_posix_timers >= 0)
+# endif
+    {
+      struct timer *kt = (struct timer *) timerid;
+
+      /* Get the information from the kernel.  */
+      int res = INLINE_SYSCALL (timer_getoverrun, 1, kt->ktimerid);
+
+# ifndef __ASSUME_POSIX_TIMERS
+      if (res != -1 || errno != ENOSYS)
+       {
+         /* We know the syscall support is available.  */
+         __no_posix_timers = 1;
+# endif
+         return res;
+# ifndef __ASSUME_POSIX_TIMERS
+       }
+# endif
+
+# ifndef __ASSUME_POSIX_TIMERS
+      __no_posix_timers = -1;
+# endif
+    }
+
+# ifndef __ASSUME_POSIX_TIMERS
+  return compat_timer_getoverrun (timerid);
+# endif
+}
+#else
+# ifdef timer_getoverrun_alias
+#  define timer_getoverrun timer_getoverrun_alias
+# endif
+/* The new system calls are not available.  Use the userlevel
+   implementation.  */
+# include <nptl/sysdeps/pthread/timer_getoverr.c>
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/timer_gettime.c b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_gettime.c
new file mode 100644 (file)
index 0000000..31401b1
--- /dev/null
@@ -0,0 +1,83 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sysdep.h>
+#include <bits/kernel-features.h>
+#include "kernel-posix-timers.h"
+
+
+#ifdef __NR_timer_gettime
+# ifndef __ASSUME_POSIX_TIMERS
+static int compat_timer_gettime (timer_t timerid, struct itimerspec *value);
+#  define timer_gettime static compat_timer_gettime
+#  include <nptl/sysdeps/pthread/timer_gettime.c>
+#  undef timer_gettime
+# endif
+
+# ifdef timer_gettime_alias
+#  define timer_gettime timer_gettime_alias
+# endif
+
+
+int
+timer_gettime (
+     timer_t timerid,
+     struct itimerspec *value)
+{
+# undef timer_gettime
+# ifndef __ASSUME_POSIX_TIMERS
+  if (__no_posix_timers >= 0)
+# endif
+    {
+      struct timer *kt = (struct timer *) timerid;
+
+      /* Delete the kernel timer object.  */
+      int res = INLINE_SYSCALL (timer_gettime, 2, kt->ktimerid, value);
+
+# ifndef __ASSUME_POSIX_TIMERS
+      if (res != -1 || errno != ENOSYS)
+       {
+         /* We know the syscall support is available.  */
+         __no_posix_timers = 1;
+# endif
+         return res;
+# ifndef __ASSUME_POSIX_TIMERS
+       }
+# endif
+
+# ifndef __ASSUME_POSIX_TIMERS
+      __no_posix_timers = -1;
+# endif
+    }
+
+# ifndef __ASSUME_POSIX_TIMERS
+  return compat_timer_gettime (timerid, value);
+# endif
+}
+#else
+# ifdef timer_gettime_alias
+#  define timer_gettime timer_gettime_alias
+# endif
+/* The new system calls are not available.  Use the userlevel
+   implementation.  */
+# include <nptl/sysdeps/pthread/timer_gettime.c>
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/timer_routines.c b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_routines.c
new file mode 100644 (file)
index 0000000..2681961
--- /dev/null
@@ -0,0 +1,204 @@
+/* Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <errno.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <sysdep.h>
+#include <bits/kernel-features.h>
+#include <pthreadP.h>
+#include "kernel-posix-timers.h"
+
+
+/* List of active SIGEV_THREAD timers.  */
+struct timer *__active_timer_sigev_thread;
+/* Lock for the __active_timer_sigev_thread.  */
+pthread_mutex_t __active_timer_sigev_thread_lock = PTHREAD_MUTEX_INITIALIZER;
+
+
+struct thread_start_data
+{
+  void (*thrfunc) (sigval_t);
+  sigval_t sival;
+};
+
+
+#ifdef __NR_timer_create
+/* Helper thread to call the user-provided function.  */
+static void *
+timer_sigev_thread (void *arg)
+{
+  /* The parent thread has all signals blocked.  This is a bit
+     surprising for user code, although valid.  We unblock all
+     signals.  */
+  sigset_t ss;
+  sigemptyset (&ss);
+  INTERNAL_SYSCALL_DECL (err);
+  INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_SETMASK, &ss, NULL, _NSIG / 8);
+
+  struct thread_start_data *td = (struct thread_start_data *) arg;
+
+  void (*thrfunc) (sigval_t) = td->thrfunc;
+  sigval_t sival = td->sival;
+
+  /* The TD object was allocated in timer_helper_thread.  */
+  free (td);
+
+  /* Call the user-provided function.  */
+  thrfunc (sival);
+
+  return NULL;
+}
+
+
+/* Helper function to support starting threads for SIGEV_THREAD.  */
+static void *
+timer_helper_thread (void *arg)
+{
+  /* Wait for the SIGTIMER signal, allowing the setXid signal, and
+     none else.  */
+  sigset_t ss;
+  sigemptyset (&ss);
+  __sigaddset (&ss, SIGTIMER);
+
+  /* Endless loop of waiting for signals.  The loop is only ended when
+     the thread is canceled.  */
+  while (1)
+    {
+      siginfo_t si;
+
+      /* sigwaitinfo cannot be used here, since it deletes
+        SIGCANCEL == SIGTIMER from the set.  */
+
+      int oldtype = LIBC_CANCEL_ASYNC ();
+
+      /* XXX The size argument hopefully will have to be changed to the
+        real size of the user-level sigset_t.  */
+      int result = INLINE_SYSCALL (rt_sigtimedwait, 4, &ss, &si, NULL,
+                                  _NSIG / 8);
+
+      LIBC_CANCEL_RESET (oldtype);
+
+      if (result > 0)
+       {
+         if (si.si_code == SI_TIMER)
+           {
+             struct timer *tk = (struct timer *) si.si_ptr;
+
+             /* Check the timer is still used and will not go away
+                while we are reading the values here.  */
+             pthread_mutex_lock (&__active_timer_sigev_thread_lock);
+
+             struct timer *runp = __active_timer_sigev_thread;
+             while (runp != NULL)
+               if (runp == tk)
+                 break;
+               else
+                 runp = runp->next;
+
+             if (runp != NULL)
+               {
+                 struct thread_start_data *td = malloc (sizeof (*td));
+
+                 /* There is not much we can do if the allocation fails.  */
+                 if (td != NULL)
+                   {
+                     /* This is the signal we are waiting for.  */
+                     td->thrfunc = tk->thrfunc;
+                     td->sival = tk->sival;
+
+                     pthread_t th;
+                     (void) pthread_create (&th, &tk->attr,
+                                            timer_sigev_thread, td);
+                   }
+               }
+
+             pthread_mutex_unlock (&__active_timer_sigev_thread_lock);
+           }
+         else if (si.si_code == SI_TKILL)
+           /* The thread is canceled.  */
+           pthread_exit (NULL);
+       }
+    }
+}
+
+
+/* Control variable for helper thread creation.  */
+pthread_once_t __helper_once attribute_hidden;
+
+
+/* TID of the helper thread.  */
+pid_t __helper_tid attribute_hidden;
+
+
+/* Reset variables so that after a fork a new helper thread gets started.  */
+static void
+reset_helper_control (void)
+{
+  __helper_once = PTHREAD_ONCE_INIT;
+  __helper_tid = 0;
+}
+
+
+void
+attribute_hidden
+__start_helper_thread (void)
+{
+  /* The helper thread needs only very little resources
+     and should go away automatically when canceled.  */
+  pthread_attr_t attr;
+  (void) pthread_attr_init (&attr);
+  (void) pthread_attr_setstacksize (&attr, PTHREAD_STACK_MIN);
+
+  /* Block all signals in the helper thread but SIGSETXID.  To do this
+     thoroughly we temporarily have to block all signals here.  The
+     helper can lose wakeups if SIGCANCEL is not blocked throughout,
+     but sigfillset omits it SIGSETXID.  So, we add SIGCANCEL back
+     explicitly here.  */
+  sigset_t ss;
+  sigset_t oss;
+  sigfillset (&ss);
+  __sigaddset (&ss, SIGCANCEL);
+  INTERNAL_SYSCALL_DECL (err);
+  INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_SETMASK, &ss, &oss, _NSIG / 8);
+
+  /* Create the helper thread for this timer.  */
+  pthread_t th;
+  int res = pthread_create (&th, &attr, timer_helper_thread, NULL);
+  if (res == 0)
+    /* We managed to start the helper thread.  */
+    __helper_tid = ((struct pthread *) th)->tid;
+
+  /* Restore the signal mask.  */
+  INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_SETMASK, &oss, NULL,
+                   _NSIG / 8);
+
+  /* No need for the attribute anymore.  */
+  (void) pthread_attr_destroy (&attr);
+
+  /* We have to make sure that after fork()ing a new helper thread can
+     be created.  */
+  pthread_atfork (NULL, NULL, reset_helper_control);
+}
+#endif
+
+#ifndef __ASSUME_POSIX_TIMERS
+# include <nptl/sysdeps/pthread/timer_routines.c>
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/timer_settime.c b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_settime.c
new file mode 100644 (file)
index 0000000..8c6ad91
--- /dev/null
@@ -0,0 +1,88 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sysdep.h>
+#include <bits/kernel-features.h>
+#include "kernel-posix-timers.h"
+
+
+#ifdef __NR_timer_settime
+# ifndef __ASSUME_POSIX_TIMERS
+static int compat_timer_settime (timer_t timerid, int flags,
+                                const struct itimerspec *value,
+                                struct itimerspec *ovalue);
+#  define timer_settime static compat_timer_settime
+#  include <nptl/sysdeps/pthread/timer_settime.c>
+#  undef timer_settime
+# endif
+
+# ifdef timer_settime_alias
+#  define timer_settime timer_settime_alias
+# endif
+
+
+int
+timer_settime (
+     timer_t timerid,
+     int flags,
+     const struct itimerspec *value,
+     struct itimerspec *ovalue)
+{
+# undef timer_settime
+# ifndef __ASSUME_POSIX_TIMERS
+  if (__no_posix_timers >= 0)
+# endif
+    {
+      struct timer *kt = (struct timer *) timerid;
+
+      /* Delete the kernel timer object.  */
+      int res = INLINE_SYSCALL (timer_settime, 4, kt->ktimerid, flags,
+                               value, ovalue);
+
+# ifndef __ASSUME_POSIX_TIMERS
+      if (res != -1 || errno != ENOSYS)
+       {
+         /* We know the syscall support is available.  */
+         __no_posix_timers = 1;
+# endif
+         return res;
+# ifndef __ASSUME_POSIX_TIMERS
+       }
+# endif
+
+# ifndef __ASSUME_POSIX_TIMERS
+      __no_posix_timers = -1;
+# endif
+    }
+
+# ifndef __ASSUME_POSIX_TIMERS
+  return compat_timer_settime (timerid, flags, value, ovalue);
+# endif
+}
+#else
+# ifdef timer_settime_alias
+#  define timer_settime timer_settime_alias
+# endif
+/* The new system calls are not available.  Use the userlevel
+   implementation.  */
+# include <nptl/sysdeps/pthread/timer_settime.c>
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/unregister-atfork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/unregister-atfork.c
new file mode 100644 (file)
index 0000000..7eb095f
--- /dev/null
@@ -0,0 +1,123 @@
+/* Copyright (C) 2002, 2003, 2005, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <fork.h>
+#include <atomic.h>
+#include <tls.h>
+
+
+void
+__unregister_atfork (
+     void *dso_handle)
+{
+  /* Check whether there is any entry in the list which we have to
+     remove.  It is likely that this is not the case so don't bother
+     getting the lock.
+
+     We do not worry about other threads adding entries for this DSO
+     right this moment.  If this happens this is a race and we can do
+     whatever we please.  The program will crash anyway seen.  */
+  struct fork_handler *runp = __fork_handlers;
+  struct fork_handler *lastp = NULL;
+
+  while (runp != NULL)
+    if (runp->dso_handle == dso_handle)
+      break;
+    else
+      {
+       lastp = runp;
+       runp = runp->next;
+      }
+
+  if (runp == NULL)
+    /* Nothing to do.  */
+    return;
+
+  /* Get the lock to not conflict with additions or deletions.  Note
+     that there couldn't have been another thread deleting something.
+     The __unregister_atfork function is only called from the
+     dlclose() code which itself serializes the operations.  */
+  lll_lock (__fork_lock, LLL_PRIVATE);
+
+  /* We have to create a new list with all the entries we don't remove.  */
+  struct deleted_handler
+  {
+    struct fork_handler *handler;
+    struct deleted_handler *next;
+  } *deleted = NULL;
+
+  /* Remove the entries for the DSO which is unloaded from the list.
+     It's a single linked list so readers are.  */
+  do
+    {
+    again:
+      if (runp->dso_handle == dso_handle)
+       {
+         if (lastp == NULL)
+           {
+             /* We have to use an atomic operation here because
+                __linkin_atfork also uses one.  */
+             if (catomic_compare_and_exchange_bool_acq (&__fork_handlers,
+                                                        runp->next, runp)
+                 != 0)
+               {
+                 runp = __fork_handlers;
+                 goto again;
+               }
+           }
+         else
+           lastp->next = runp->next;
+
+         /* We cannot overwrite the ->next element now.  Put the deleted
+            entries in a separate list.  */
+         struct deleted_handler *newp = alloca (sizeof (*newp));
+         newp->handler = runp;
+         newp->next = deleted;
+         deleted = newp;
+       }
+      else
+       lastp = runp;
+
+      runp = runp->next;
+    }
+  while (runp != NULL);
+
+  /* Release the lock.  */
+  lll_unlock (__fork_lock, LLL_PRIVATE);
+
+  /* Walk the list of all entries which have to be deleted.  */
+  while (deleted != NULL)
+    {
+      /* We need to be informed by possible current users.  */
+      deleted->handler->need_signal = 1;
+      /* Make sure this gets written out first.  */
+      atomic_write_barrier ();
+
+      /* Decrement the reference counter.  If it does not reach zero
+        wait for the last user.  */
+      atomic_decrement (&deleted->handler->refcntr);
+      unsigned int val;
+      while ((val = deleted->handler->refcntr) != 0)
+       lll_futex_wait (&deleted->handler->refcntr, val, LLL_PRIVATE);
+
+      deleted = deleted->next;
+    }
+}
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/unwindbuf.sym b/libpthread/nptl/sysdeps/unix/sysv/linux/unwindbuf.sym
new file mode 100644 (file)
index 0000000..8044b40
--- /dev/null
@@ -0,0 +1,7 @@
+#include <pthread.h>
+#include <stddef.h>
+
+--
+
+UNWINDBUFSIZE  sizeof (__pthread_unwind_buf_t)
+UWJMPBUF       offsetof (__pthread_unwind_buf_t, __cancel_jmp_buf)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/waitpid.S b/libpthread/nptl/sysdeps/unix/sysv/linux/waitpid.S
new file mode 100644 (file)
index 0000000..f55d346
--- /dev/null
@@ -0,0 +1,19 @@
+#include <sysdep-cancel.h>
+
+/*
+extern pid_t __waitpid_nocancel (pid_t, int *, int) attribute_hidden;
+*/
+#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt
+
+
+PSEUDO (__waitpid, waitpid, 3)
+ret
+PSEUDO_END(__waitpid)
+
+libc_hidden_def (__waitpid)
+weak_alias (__waitpid, waitpid)
+libc_hidden_weak (waitpid)
+weak_alias (__waitpid, __libc_waitpid)
+libc_hidden_weak (__libc_waitpid)
+
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/write.S b/libpthread/nptl/sysdeps/unix/sysv/linux/write.S
new file mode 100644 (file)
index 0000000..43de332
--- /dev/null
@@ -0,0 +1,19 @@
+#include <sysdep-cancel.h>
+
+/*
+extern int __write_nocancel (int, const void *, size_t) attribute_hidden;
+*/
+#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt
+
+PSEUDO (__libc_write, write, 3)
+ret
+PSEUDO_END(__libc_write)
+
+libc_hidden_def (__write_nocancel)
+libc_hidden_def (__libc_write)
+weak_alias (__libc_write, __write)
+libc_hidden_weak (__write)
+weak_alias (__libc_write, write)
+libc_hidden_weak (write)
+
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/Makefile b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/Makefile
new file mode 100644 (file)
index 0000000..43a6fad
--- /dev/null
@@ -0,0 +1,13 @@
+# Makefile for uClibc NPTL
+#
+# Copyright (C) 2005 Steven J. Hill <sjhill@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+top_srcdir=../../../../../../../
+top_builddir=../../../../../../../
+all: objs
+include $(top_builddir)Rules.mak
+include Makefile.arch
+include $(top_srcdir)Makerules
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/Makefile.arch b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/Makefile.arch
new file mode 100644 (file)
index 0000000..53a8772
--- /dev/null
@@ -0,0 +1,78 @@
+# Makefile for uClibc NPTL
+#
+# Copyright (C) 2006 Steven J. Hill <sjhill@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+LINUX_ARCH_DIR:=$(top_srcdir)libpthread/nptl/sysdeps/unix/sysv/linux/x86_64
+LINUX_ARCH_OUT:=$(top_builddir)libpthread/nptl/sysdeps/unix/sysv/linux/x86_64
+
+
+libpthread_SSRC = pt-vfork.S clone.S pthread_once.S
+libpthread_CSRC = pthread_spin_init.c pt-__syscall_error.c
+
+libc_a_CSRC = fork.c
+libc_a_SSRC = clone.S vfork.S
+
+libpthread_SSRC += lowlevellock.S pthread_barrier_wait.S pthread_cond_signal.S pthread_cond_broadcast.S \
+                  sem_post.S sem_timedwait.S lowlevelrobustlock.S \
+                  sem_trywait.S sem_wait.S pthread_rwlock_rdlock.S pthread_rwlock_wrlock.S \
+                  pthread_rwlock_timedrdlock.S pthread_rwlock_timedwrlock.S pthread_rwlock_unlock.S \
+                  pthread_spin_unlock.S
+# pthread_cond_timedwait.S pthread_cond_wait.S
+libc_a_SSRC += libc-lowlevellock.S
+
+
+CFLAGS-OMIT-fork.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1
+CFLAGS-pt-__syscall_error.c =  -DNOT_IN_libc=1 -DIS_IN_libpthread=1
+
+ifeq ($(UCLIBC_HAS_STDIO_FUTEXES),y)
+CFLAGS-fork.c = -D__USE_STDIO_FUTEXES__
+endif
+
+ASFLAGS-pt-vfork.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 -D_LIBC_REENTRANT -DUSE___THREAD
+ASFLAGS-lowlevellock.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 -D_LIBC_REENTRANT -DUSE___THREAD
+ASFLAGS-pthread_once.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 -D_LIBC_REENTRANT -DUSE___THREAD
+
+
+ASFLAGS-clone.S = -D_LIBC_REENTRANT
+ASFLAGS-vfork.S = -D_LIBC_REENTRANT
+ASFLAGS-libc-lowlevellock.S = -D_LIBC_REENTRANT
+
+ifeq ($(UCLIBC_HAS_THREADS_NATIVE),y)
+#Needed to use the correct SYSCALL_ERROR_HANDLER
+ASFLAGS-clone.S += -DUSE___THREAD
+ASFLAGS-vfork.S += -DUSE___THREAD
+ASFLAGS-sem_wait.S += -DUSE___THREAD
+ASFLAGS-sem_trywait.S += -DUSE___THREAD
+ASFLAGS-sem_timedwait.S += -DUSE___THREAD
+ASFLAGS-sem_post.S += -DUSE___THREAD
+endif
+
+CFLAGS += $(SSP_ALL_CFLAGS)
+#CFLAGS:=$(CFLAGS:-O1=-O2)
+
+LINUX_ARCH_OBJ:=$(patsubst %.S,$(LINUX_ARCH_OUT)/%.o,$(libpthread_SSRC))
+LINUX_ARCH_OBJ+=$(patsubst %.c,$(LINUX_ARCH_OUT)/%.o,$(libpthread_CSRC))
+
+ifeq ($(DOPIC),y)
+libpthread-a-y += $(LINUX_ARCH_OBJ:.o=.os)
+else
+libpthread-a-y += $(LINUX_ARCH_OBJ)
+endif
+libpthread-so-y += $(LINUX_ARCH_OBJ:.o=.oS)
+
+libpthread-nomulti-y+=$(LINUX_ARCH_OBJS)
+
+LIBC_LINUX_ARCH_OBJ:=$(patsubst %.c,$(LINUX_ARCH_OUT)/%.o,$(libc_a_CSRC))
+LIBC_LINUX_ARCH_OBJ+=$(patsubst %.S,$(LINUX_ARCH_OUT)/%.o,$(libc_a_SSRC))
+
+libc-static-y+=$(LIBC_LINUX_ARCH_OBJ)
+libc-shared-y+=$(LIBC_LINUX_ARCH_OBJ:.o=.oS)
+
+libc-nomulti-y+=$(LIBC_LINUX_ARCH_OBJ)
+
+objclean-y+=nptl_linux_arch_clean
+
+nptl_linux_arch_clean:
+       $(do_rm) $(addprefix $(LINUX_ARCH_OUT)/*., o os oS)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h
new file mode 100644 (file)
index 0000000..7a09c81
--- /dev/null
@@ -0,0 +1,225 @@
+/* Copyright (C) 2002,2003,2004,2005,2006,2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _BITS_PTHREADTYPES_H
+#define _BITS_PTHREADTYPES_H   1
+
+#include <bits/wordsize.h>
+
+#if __WORDSIZE == 64
+# define __SIZEOF_PTHREAD_ATTR_T 56
+# define __SIZEOF_PTHREAD_MUTEX_T 40
+# define __SIZEOF_PTHREAD_MUTEXATTR_T 4
+# define __SIZEOF_PTHREAD_COND_T 48
+# define __SIZEOF_PTHREAD_CONDATTR_T 4
+# define __SIZEOF_PTHREAD_RWLOCK_T 56
+# define __SIZEOF_PTHREAD_RWLOCKATTR_T 8
+# define __SIZEOF_PTHREAD_BARRIER_T 32
+# define __SIZEOF_PTHREAD_BARRIERATTR_T 4
+#else
+# define __SIZEOF_PTHREAD_ATTR_T 36
+# define __SIZEOF_PTHREAD_MUTEX_T 24
+# define __SIZEOF_PTHREAD_MUTEXATTR_T 4
+# define __SIZEOF_PTHREAD_COND_T 48
+# define __SIZEOF_PTHREAD_CONDATTR_T 4
+# define __SIZEOF_PTHREAD_RWLOCK_T 32
+# define __SIZEOF_PTHREAD_RWLOCKATTR_T 8
+# define __SIZEOF_PTHREAD_BARRIER_T 20
+# define __SIZEOF_PTHREAD_BARRIERATTR_T 4
+#endif
+
+
+/* Thread identifiers.  The structure of the attribute type is not
+   exposed on purpose.  */
+typedef unsigned long int pthread_t;
+
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_ATTR_T];
+  long int __align;
+} pthread_attr_t;
+
+
+#if __WORDSIZE == 64
+typedef struct __pthread_internal_list
+{
+  struct __pthread_internal_list *__prev;
+  struct __pthread_internal_list *__next;
+} __pthread_list_t;
+#else
+typedef struct __pthread_internal_slist
+{
+  struct __pthread_internal_slist *__next;
+} __pthread_slist_t;
+#endif
+
+
+/* Data structures for mutex handling.  The structure of the attribute
+   type is not exposed on purpose.  */
+typedef union
+{
+  struct __pthread_mutex_s
+  {
+    int __lock;
+    unsigned int __count;
+    int __owner;
+#if __WORDSIZE == 64
+    unsigned int __nusers;
+#endif
+    /* KIND must stay at this position in the structure to maintain
+       binary compatibility.  */
+    int __kind;
+#if __WORDSIZE == 64
+    int __spins;
+    __pthread_list_t __list;
+# define __PTHREAD_MUTEX_HAVE_PREV     1
+#else
+    unsigned int __nusers;
+    __extension__ union
+    {
+      int __spins;
+      __pthread_slist_t __list;
+    };
+#endif
+  } __data;
+  char __size[__SIZEOF_PTHREAD_MUTEX_T];
+  long int __align;
+} pthread_mutex_t;
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_MUTEXATTR_T];
+  int __align;
+} pthread_mutexattr_t;
+
+
+/* Data structure for conditional variable handling.  The structure of
+   the attribute type is not exposed on purpose.  */
+typedef union
+{
+  struct
+  {
+    int __lock;
+    unsigned int __futex;
+    __extension__ unsigned long long int __total_seq;
+    __extension__ unsigned long long int __wakeup_seq;
+    __extension__ unsigned long long int __woken_seq;
+    void *__mutex;
+    unsigned int __nwaiters;
+    unsigned int __broadcast_seq;
+  } __data;
+  char __size[__SIZEOF_PTHREAD_COND_T];
+  __extension__ long long int __align;
+} pthread_cond_t;
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_CONDATTR_T];
+  int __align;
+} pthread_condattr_t;
+
+
+/* Keys for thread-specific data */
+typedef unsigned int pthread_key_t;
+
+
+/* Once-only execution */
+typedef int pthread_once_t;
+
+
+#if defined __USE_UNIX98 || defined __USE_XOPEN2K
+/* Data structure for read-write lock variable handling.  The
+   structure of the attribute type is not exposed on purpose.  */
+typedef union
+{
+# if __WORDSIZE == 64
+  struct
+  {
+    int __lock;
+    unsigned int __nr_readers;
+    unsigned int __readers_wakeup;
+    unsigned int __writer_wakeup;
+    unsigned int __nr_readers_queued;
+    unsigned int __nr_writers_queued;
+    int __writer;
+    int __shared;
+    unsigned long int __pad1;
+    unsigned long int __pad2;
+    /* FLAGS must stay at this position in the structure to maintain
+       binary compatibility.  */
+    unsigned int __flags;
+  } __data;
+# else
+  struct
+  {
+    int __lock;
+    unsigned int __nr_readers;
+    unsigned int __readers_wakeup;
+    unsigned int __writer_wakeup;
+    unsigned int __nr_readers_queued;
+    unsigned int __nr_writers_queued;
+    /* FLAGS must stay at this position in the structure to maintain
+       binary compatibility.  */
+    unsigned char __flags;
+    unsigned char __shared;
+    unsigned char __pad1;
+    unsigned char __pad2;
+    int __writer;
+  } __data;
+# endif
+  char __size[__SIZEOF_PTHREAD_RWLOCK_T];
+  long int __align;
+} pthread_rwlock_t;
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_RWLOCKATTR_T];
+  long int __align;
+} pthread_rwlockattr_t;
+#endif
+
+
+#ifdef __USE_XOPEN2K
+/* POSIX spinlock data type.  */
+typedef volatile int pthread_spinlock_t;
+
+
+/* POSIX barriers data type.  The structure of the type is
+   deliberately not exposed.  */
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_BARRIER_T];
+  long int __align;
+} pthread_barrier_t;
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_BARRIERATTR_T];
+  int __align;
+} pthread_barrierattr_t;
+#endif
+
+
+#if __WORDSIZE == 32
+/* Extra attributes for the cleanup functions.  */
+# define __cleanup_fct_attribute __attribute__ ((__regparm__ (1)))
+#endif
+
+#endif /* bits/pthreadtypes.h */
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/bits/semaphore.h b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/bits/semaphore.h
new file mode 100644 (file)
index 0000000..e973bc5
--- /dev/null
@@ -0,0 +1,41 @@
+/* Copyright (C) 2002, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _SEMAPHORE_H
+# error "Never use <bits/semaphore.h> directly; include <semaphore.h> instead."
+#endif
+
+#include <bits/wordsize.h>
+
+#if __WORDSIZE == 64
+# define __SIZEOF_SEM_T        32
+#else
+# define __SIZEOF_SEM_T        16
+#endif
+
+
+/* Value returned if `sem_open' failed.  */
+#define SEM_FAILED      ((sem_t *) 0)
+
+
+typedef union
+{
+  char __size[__SIZEOF_SEM_T];
+  long int __align;
+} sem_t;
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/cancellation.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/cancellation.S
new file mode 100644 (file)
index 0000000..6806962
--- /dev/null
@@ -0,0 +1,116 @@
+/* Copyright (C) 2009 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2009.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <tcb-offsets.h>
+#include <kernel-features.h>
+#include "lowlevellock.h"
+
+#ifdef IS_IN_libpthread
+# ifdef SHARED
+#  define __pthread_unwind __GI___pthread_unwind
+# endif
+#else
+# ifndef SHARED
+       .weak __pthread_unwind
+# endif
+#endif
+
+
+#ifdef __ASSUME_PRIVATE_FUTEX
+# define LOAD_PRIVATE_FUTEX_WAIT(reg) \
+       movl    $(FUTEX_WAIT | FUTEX_PRIVATE_FLAG), reg
+#else
+# if FUTEX_WAIT == 0
+#  define LOAD_PRIVATE_FUTEX_WAIT(reg) \
+       movl    %fs:PRIVATE_FUTEX, reg
+# else
+#  define LOAD_PRIVATE_FUTEX_WAIT(reg) \
+       movl    %fs:PRIVATE_FUTEX, reg ; \
+       orl     $FUTEX_WAIT, reg
+# endif
+#endif
+
+/* It is crucial that the functions in this file don't modify registers
+   other than %rax and %r11.  The syscall wrapper code depends on this
+   because it doesn't explicitly save the other registers which hold
+   relevant values.  */
+       .text
+
+       .hidden __pthread_enable_asynccancel
+ENTRY(__pthread_enable_asynccancel)
+       movl    %fs:CANCELHANDLING, %eax
+2:     movl    %eax, %r11d
+       orl     $TCB_CANCELTYPE_BITMASK, %r11d
+       cmpl    %eax, %r11d
+       je      1f
+
+       lock
+       cmpxchgl %r11d, %fs:CANCELHANDLING
+       jnz     2b
+
+       andl    $(TCB_CANCELSTATE_BITMASK|TCB_CANCELTYPE_BITMASK|TCB_CANCELED_BITMASK|TCB_EXITING_BITMASK|TCB_CANCEL_RESTMASK|TCB_TERMINATED_BITMASK), %r11d
+       cmpl    $(TCB_CANCELTYPE_BITMASK|TCB_CANCELED_BITMASK), %r11d
+       je      3f
+
+1:     ret
+
+3:     movq    $TCB_PTHREAD_CANCELED, %fs:RESULT
+       lock
+       orl     $TCB_EXITING_BITMASK, %fs:CANCELHANDLING
+       movq    %fs:CLEANUP_JMP_BUF, %rdi
+#ifdef SHARED
+       call    __pthread_unwind@PLT
+#else
+       call    __pthread_unwind
+#endif
+       hlt
+END(__pthread_enable_asynccancel)
+
+
+       .hidden __pthread_disable_asynccancel
+ENTRY(__pthread_disable_asynccancel)
+       testl   $TCB_CANCELTYPE_BITMASK, %edi
+       jnz     1f
+
+       movl    %fs:CANCELHANDLING, %eax
+2:     movl    %eax, %r11d
+       andl    $~TCB_CANCELTYPE_BITMASK, %r11d
+       lock
+       cmpxchgl %r11d, %fs:CANCELHANDLING
+       jnz     2b
+
+       movl    %r11d, %eax
+3:     andl    $(TCB_CANCELING_BITMASK|TCB_CANCELED_BITMASK), %eax
+       cmpl    $TCB_CANCELING_BITMASK, %eax
+       je      4f
+1:     ret
+
+       /* Performance doesn't matter in this loop.  We will
+          delay until the thread is canceled.  And we will unlikely
+          enter the loop twice.  */
+4:     movq    %fs:0, %rdi
+       movl    $__NR_futex, %eax
+       xorq    %r10, %r10
+       addq    $CANCELHANDLING, %rdi
+       LOAD_PRIVATE_FUTEX_WAIT (%esi)
+       syscall
+       movl    %fs:CANCELHANDLING, %eax
+       jmp     3b
+END(__pthread_disable_asynccancel)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/clone.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/clone.S
new file mode 100644 (file)
index 0000000..efbaee3
--- /dev/null
@@ -0,0 +1,3 @@
+#include <tcb-offsets.h>
+#define RESET_PID
+#include <libc/sysdeps/linux/x86_64/clone.S>
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/compat-timer.h b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/compat-timer.h
new file mode 100644 (file)
index 0000000..02485da
--- /dev/null
@@ -0,0 +1,46 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <signal.h>
+#include <time.h>
+#include <sys/types.h>
+
+#define OLD_TIMER_MAX  256
+
+extern timer_t __compat_timer_list[OLD_TIMER_MAX] attribute_hidden;
+
+
+extern int __timer_create_new (clockid_t clock_id, struct sigevent *evp,
+                              timer_t *timerid);
+extern int __timer_delete_new (timer_t timerid);
+extern int __timer_getoverrun_new (timer_t timerid);
+extern int __timer_gettime_new (timer_t timerid, struct itimerspec *value);
+extern int __timer_settime_new (timer_t timerid, int flags,
+                               const struct itimerspec *value,
+                               struct itimerspec *ovalue);
+
+
+extern int __timer_create_old (clockid_t clock_id, struct sigevent *evp,
+                              int *timerid);
+extern int __timer_delete_old (int timerid);
+extern int __timer_getoverrun_old (int timerid);
+extern int __timer_gettime_old (int timerid, struct itimerspec *value);
+extern int __timer_settime_old (int timerid, int flags,
+                               const struct itimerspec *value,
+                               struct itimerspec *ovalue);
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/fork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/fork.c
new file mode 100644 (file)
index 0000000..c828e15
--- /dev/null
@@ -0,0 +1,31 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sched.h>
+#include <signal.h>
+#include <sysdep.h>
+#include <tls.h>
+
+
+#define ARCH_FORK() \
+  INLINE_SYSCALL (clone, 4,                                                  \
+                 CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD, 0,     \
+                 NULL, &THREAD_SELF->tid)
+
+#include "../fork.c"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/libc-cancellation.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/libc-cancellation.S
new file mode 100644 (file)
index 0000000..1100588
--- /dev/null
@@ -0,0 +1,22 @@
+/* Copyright (C) 2009 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2009.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along 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 __pthread_enable_asynccancel __libc_enable_asynccancel
+#define __pthread_disable_asynccancel __libc_disable_asynccancel
+#include "cancellation.S"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/libc-lowlevellock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/libc-lowlevellock.S
new file mode 100644 (file)
index 0000000..ce8ad27
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright (C) 2002, 2003, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "lowlevellock.S"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/librt-cancellation.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/librt-cancellation.S
new file mode 100644 (file)
index 0000000..ce4192b
--- /dev/null
@@ -0,0 +1,22 @@
+/* Copyright (C) 2009 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2009.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along 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 __pthread_enable_asynccancel __librt_enable_asynccancel
+#define __pthread_disable_asynccancel __librt_disable_asynccancel
+#include "cancellation.S"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S
new file mode 100644 (file)
index 0000000..f875323
--- /dev/null
@@ -0,0 +1,457 @@
+/* Copyright (C) 2002-2006, 2007, 2009 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <pthread-errnos.h>
+#include <bits/kernel-features.h>
+#include <lowlevellock.h>
+#include <tcb-offsets.h>
+
+       .text
+
+#ifdef __ASSUME_PRIVATE_FUTEX
+# define LOAD_PRIVATE_FUTEX_WAIT(reg) \
+       movl    $(FUTEX_WAIT | FUTEX_PRIVATE_FLAG), reg
+# define LOAD_PRIVATE_FUTEX_WAKE(reg) \
+       movl    $(FUTEX_WAKE | FUTEX_PRIVATE_FLAG), reg
+# define LOAD_FUTEX_WAIT(reg) \
+       xorl    $(FUTEX_WAIT | FUTEX_PRIVATE_FLAG), reg
+# define LOAD_FUTEX_WAIT_ABS(reg) \
+       xorl    $(FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME), reg
+# define LOAD_FUTEX_WAKE(reg) \
+       xorl    $(FUTEX_WAKE | FUTEX_PRIVATE_FLAG), reg
+#else
+# if FUTEX_WAIT == 0
+#  define LOAD_PRIVATE_FUTEX_WAIT(reg) \
+       movl    %fs:PRIVATE_FUTEX, reg
+# else
+#  define LOAD_PRIVATE_FUTEX_WAIT(reg) \
+       movl    %fs:PRIVATE_FUTEX, reg ; \
+       orl     $FUTEX_WAIT, reg
+# endif
+# define LOAD_PRIVATE_FUTEX_WAKE(reg) \
+       movl    %fs:PRIVATE_FUTEX, reg ; \
+       orl     $FUTEX_WAKE, reg
+# if FUTEX_WAIT == 0
+#  define LOAD_FUTEX_WAIT(reg) \
+       xorl    $FUTEX_PRIVATE_FLAG, reg ; \
+       andl    %fs:PRIVATE_FUTEX, reg
+# else
+#  define LOAD_FUTEX_WAIT(reg) \
+       xorl    $FUTEX_PRIVATE_FLAG, reg ; \
+       andl    %fs:PRIVATE_FUTEX, reg ; \
+       orl     $FUTEX_WAIT, reg
+# endif
+# define LOAD_FUTEX_WAIT_ABS(reg) \
+       xorl    $FUTEX_PRIVATE_FLAG, reg ; \
+       andl    %fs:PRIVATE_FUTEX, reg ; \
+       orl     $FUTEX_WAIT_BITSET | FUTEX_CLOCK_REALTIME, reg
+# define LOAD_FUTEX_WAKE(reg) \
+       xorl    $FUTEX_PRIVATE_FLAG, reg ; \
+       andl    %fs:PRIVATE_FUTEX, reg ; \
+       orl     $FUTEX_WAKE, reg
+#endif
+
+
+/* For the calculation see asm/vsyscall.h.  */
+#define VSYSCALL_ADDR_vgettimeofday    0xffffffffff600000
+
+
+       .globl  __lll_lock_wait_private
+       .type   __lll_lock_wait_private,@function
+       .hidden __lll_lock_wait_private
+       .align  16
+__lll_lock_wait_private:
+       cfi_startproc
+       pushq   %r10
+       cfi_adjust_cfa_offset(8)
+       pushq   %rdx
+       cfi_adjust_cfa_offset(8)
+       cfi_offset(%r10, -16)
+       cfi_offset(%rdx, -24)
+       xorq    %r10, %r10      /* No timeout.  */
+       movl    $2, %edx
+       LOAD_PRIVATE_FUTEX_WAIT (%esi)
+
+       cmpl    %edx, %eax      /* NB:   %edx == 2 */
+       jne     2f
+
+1:     movl    $SYS_futex, %eax
+       syscall
+
+2:     movl    %edx, %eax
+       xchgl   %eax, (%rdi)    /* NB:   lock is implied */
+
+       testl   %eax, %eax
+       jnz     1b
+
+       popq    %rdx
+       cfi_adjust_cfa_offset(-8)
+       cfi_restore(%rdx)
+       popq    %r10
+       cfi_adjust_cfa_offset(-8)
+       cfi_restore(%r10)
+       retq
+       cfi_endproc
+       .size   __lll_lock_wait_private,.-__lll_lock_wait_private
+
+#ifdef NOT_IN_libc
+       .globl  __lll_lock_wait
+       .type   __lll_lock_wait,@function
+       .hidden __lll_lock_wait
+       .align  16
+__lll_lock_wait:
+       cfi_startproc
+       pushq   %r10
+       cfi_adjust_cfa_offset(8)
+       pushq   %rdx
+       cfi_adjust_cfa_offset(8)
+       cfi_offset(%r10, -16)
+       cfi_offset(%rdx, -24)
+       xorq    %r10, %r10      /* No timeout.  */
+       movl    $2, %edx
+       LOAD_FUTEX_WAIT (%esi)
+
+       cmpl    %edx, %eax      /* NB:   %edx == 2 */
+       jne     2f
+
+1:     movl    $SYS_futex, %eax
+       syscall
+
+2:     movl    %edx, %eax
+       xchgl   %eax, (%rdi)    /* NB:   lock is implied */
+
+       testl   %eax, %eax
+       jnz     1b
+
+       popq    %rdx
+       cfi_adjust_cfa_offset(-8)
+       cfi_restore(%rdx)
+       popq    %r10
+       cfi_adjust_cfa_offset(-8)
+       cfi_restore(%r10)
+       retq
+       cfi_endproc
+       .size   __lll_lock_wait,.-__lll_lock_wait
+
+       /*      %rdi: futex
+               %rsi: flags
+               %rdx: timeout
+               %eax: futex value
+       */
+       .globl  __lll_timedlock_wait
+       .type   __lll_timedlock_wait,@function
+       .hidden __lll_timedlock_wait
+       .align  16
+__lll_timedlock_wait:
+       cfi_startproc
+# ifndef __ASSUME_FUTEX_CLOCK_REALTIME
+#  ifdef __PIC__
+       cmpl    $0, __have_futex_clock_realtime(%rip)
+#  else
+       cmpl    $0, __have_futex_clock_realtime
+#  endif
+       je      .Lreltmo
+# endif
+
+       pushq   %r9
+       cfi_adjust_cfa_offset(8)
+       cfi_rel_offset(%r9, 0)
+       movq    %rdx, %r10
+       movl    $0xffffffff, %r9d
+       LOAD_FUTEX_WAIT_ABS (%esi)
+
+       movl    $2, %edx
+       cmpl    %edx, %eax
+       jne     2f
+
+1:     movl    $SYS_futex, %eax
+       movl    $2, %edx
+       syscall
+
+2:     xchgl   %edx, (%rdi)    /* NB:   lock is implied */
+
+       testl   %edx, %edx
+       jz      3f
+
+       cmpl    $-ETIMEDOUT, %eax
+       je      4f
+       cmpl    $-EINVAL, %eax
+       jne     1b
+4:     movl    %eax, %edx
+       negl    %edx
+
+3:     movl    %edx, %eax
+       popq    %r9
+       cfi_adjust_cfa_offset(-8)
+       cfi_restore(%r9)
+       retq
+
+# ifndef __ASSUME_FUTEX_CLOCK_REALTIME
+.Lreltmo:
+       /* Check for a valid timeout value.  */
+       cmpq    $1000000000, 8(%rdx)
+       jae     3f
+
+       pushq   %r8
+       cfi_adjust_cfa_offset(8)
+       pushq   %r9
+       cfi_adjust_cfa_offset(8)
+       pushq   %r12
+       cfi_adjust_cfa_offset(8)
+       pushq   %r13
+       cfi_adjust_cfa_offset(8)
+       pushq   %r14
+       cfi_adjust_cfa_offset(8)
+       cfi_offset(%r8, -16)
+       cfi_offset(%r9, -24)
+       cfi_offset(%r12, -32)
+       cfi_offset(%r13, -40)
+       cfi_offset(%r14, -48)
+       pushq   %rsi
+       cfi_adjust_cfa_offset(8)
+
+       /* Stack frame for the timespec and timeval structs.  */
+       subq    $24, %rsp
+       cfi_adjust_cfa_offset(24)
+
+       movq    %rdi, %r12
+       movq    %rdx, %r13
+
+       movl    $2, %edx
+       xchgl   %edx, (%r12)
+
+       testl   %edx, %edx
+       je      6f
+
+1:
+       /* Get current time.  */
+       movq    %rsp, %rdi
+       xorl    %esi, %esi
+       movq    $VSYSCALL_ADDR_vgettimeofday, %rax
+       /* This is a regular function call, all caller-save registers
+          might be clobbered.  */
+       callq   *%rax
+
+       /* Compute relative timeout.  */
+       movq    8(%rsp), %rax
+       movl    $1000, %edi
+       mul     %rdi            /* Milli seconds to nano seconds.  */
+       movq    (%r13), %rdi
+       movq    8(%r13), %rsi
+       subq    (%rsp), %rdi
+       subq    %rax, %rsi
+       jns     4f
+       addq    $1000000000, %rsi
+       decq    %rdi
+4:     testq   %rdi, %rdi
+       js      2f              /* Time is already up.  */
+
+       /* Store relative timeout.  */
+       movq    %rdi, (%rsp)
+       movq    %rsi, 8(%rsp)
+
+       /* Futex call.  */
+       movl    $2, %edx
+       movl    $1, %eax
+       movq    %rsp, %r10
+       movl    24(%rsp), %esi
+       LOAD_FUTEX_WAIT (%esi)
+       movq    %r12, %rdi
+       movl    $SYS_futex, %eax
+       syscall
+
+       /* NB: %edx == 2 */
+       xchgl   %edx, (%r12)
+
+       testl   %edx, %edx
+       je      6f
+
+       cmpl    $-ETIMEDOUT, %eax
+       jne     1b
+2:     movl    $ETIMEDOUT, %edx
+
+6:     addq    $32, %rsp
+       cfi_adjust_cfa_offset(-32)
+       popq    %r14
+       cfi_adjust_cfa_offset(-8)
+       cfi_restore(%r14)
+       popq    %r13
+       cfi_adjust_cfa_offset(-8)
+       cfi_restore(%r13)
+       popq    %r12
+       cfi_adjust_cfa_offset(-8)
+       cfi_restore(%r12)
+       popq    %r9
+       cfi_adjust_cfa_offset(-8)
+       cfi_restore(%r9)
+       popq    %r8
+       cfi_adjust_cfa_offset(-8)
+       cfi_restore(%r8)
+       movl    %edx, %eax
+       retq
+
+3:     movl    $EINVAL, %eax
+       retq
+# endif
+       cfi_endproc
+       .size   __lll_timedlock_wait,.-__lll_timedlock_wait
+#endif
+
+
+       .globl  __lll_unlock_wake_private
+       .type   __lll_unlock_wake_private,@function
+       .hidden __lll_unlock_wake_private
+       .align  16
+__lll_unlock_wake_private:
+       cfi_startproc
+       pushq   %rsi
+       cfi_adjust_cfa_offset(8)
+       pushq   %rdx
+       cfi_adjust_cfa_offset(8)
+       cfi_offset(%rsi, -16)
+       cfi_offset(%rdx, -24)
+
+       movl    $0, (%rdi)
+       LOAD_PRIVATE_FUTEX_WAKE (%esi)
+       movl    $1, %edx        /* Wake one thread.  */
+       movl    $SYS_futex, %eax
+       syscall
+
+       popq    %rdx
+       cfi_adjust_cfa_offset(-8)
+       cfi_restore(%rdx)
+       popq    %rsi
+       cfi_adjust_cfa_offset(-8)
+       cfi_restore(%rsi)
+       retq
+       cfi_endproc
+       .size   __lll_unlock_wake_private,.-__lll_unlock_wake_private
+
+#ifdef NOT_IN_libc
+       .globl  __lll_unlock_wake
+       .type   __lll_unlock_wake,@function
+       .hidden __lll_unlock_wake
+       .align  16
+__lll_unlock_wake:
+       cfi_startproc
+       pushq   %rsi
+       cfi_adjust_cfa_offset(8)
+       pushq   %rdx
+       cfi_adjust_cfa_offset(8)
+       cfi_offset(%rsi, -16)
+       cfi_offset(%rdx, -24)
+
+       movl    $0, (%rdi)
+       LOAD_FUTEX_WAKE (%esi)
+       movl    $1, %edx        /* Wake one thread.  */
+       movl    $SYS_futex, %eax
+       syscall
+
+       popq    %rdx
+       cfi_adjust_cfa_offset(-8)
+       cfi_restore(%rdx)
+       popq    %rsi
+       cfi_adjust_cfa_offset(-8)
+       cfi_restore(%rsi)
+       retq
+       cfi_endproc
+       .size   __lll_unlock_wake,.-__lll_unlock_wake
+
+       .globl  __lll_timedwait_tid
+       .type   __lll_timedwait_tid,@function
+       .hidden __lll_timedwait_tid
+       .align  16
+__lll_timedwait_tid:
+       cfi_startproc
+       pushq   %r12
+       cfi_adjust_cfa_offset(8)
+       pushq   %r13
+       cfi_adjust_cfa_offset(8)
+       cfi_offset(%r12, -16)
+       cfi_offset(%r13, -24)
+
+       movq    %rdi, %r12
+       movq    %rsi, %r13
+
+       subq    $16, %rsp
+       cfi_adjust_cfa_offset(16)
+
+       /* Get current time.  */
+2:     movq    %rsp, %rdi
+       xorl    %esi, %esi
+       movq    $VSYSCALL_ADDR_vgettimeofday, %rax
+       callq   *%rax
+
+       /* Compute relative timeout.  */
+       movq    8(%rsp), %rax
+       movl    $1000, %edi
+       mul     %rdi            /* Milli seconds to nano seconds.  */
+       movq    (%r13), %rdi
+       movq    8(%r13), %rsi
+       subq    (%rsp), %rdi
+       subq    %rax, %rsi
+       jns     5f
+       addq    $1000000000, %rsi
+       decq    %rdi
+5:     testq   %rdi, %rdi
+       js      6f              /* Time is already up.  */
+
+       movq    %rdi, (%rsp)    /* Store relative timeout.  */
+       movq    %rsi, 8(%rsp)
+
+       movl    (%r12), %edx
+       testl   %edx, %edx
+       jz      4f
+
+       movq    %rsp, %r10
+       /* XXX The kernel so far uses global futex for the wakeup at
+          all times.  */
+#if FUTEX_WAIT == 0
+       xorl    %esi, %esi
+#else
+       movl    $FUTEX_WAIT, %esi
+#endif
+       movq    %r12, %rdi
+       movl    $SYS_futex, %eax
+       syscall
+
+       cmpl    $0, (%rdi)
+       jne     1f
+4:     xorl    %eax, %eax
+
+8:     addq    $16, %rsp
+       cfi_adjust_cfa_offset(-16)
+       popq    %r13
+       cfi_adjust_cfa_offset(-8)
+       cfi_restore(%r13)
+       popq    %r12
+       cfi_adjust_cfa_offset(-8)
+       cfi_restore(%r12)
+       retq
+
+       cfi_adjust_cfa_offset(32)
+1:     cmpq    $-ETIMEDOUT, %rax
+       jne     2b
+
+6:     movl    $ETIMEDOUT, %eax
+       jmp     8b
+       cfi_endproc
+       .size   __lll_timedwait_tid,.-__lll_timedwait_tid
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.h b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.h
new file mode 100644 (file)
index 0000000..7c042fc
--- /dev/null
@@ -0,0 +1,598 @@
+/* Copyright (C) 2002-2004, 2006-2008, 2009 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _LOWLEVELLOCK_H
+#define _LOWLEVELLOCK_H        1
+
+#ifndef __ASSEMBLER__
+# include <time.h>
+# include <sys/param.h>
+# include <bits/pthreadtypes.h>
+# include <bits/kernel-features.h>
+# include <tcb-offsets.h>
+
+# ifndef LOCK_INSTR
+#  ifdef UP
+#   define LOCK_INSTR  /* nothing */
+#  else
+#   define LOCK_INSTR "lock;"
+#  endif
+# endif
+#else
+# ifndef LOCK
+#  ifdef UP
+#   define LOCK
+#  else
+#   define LOCK lock
+#  endif
+# endif
+#endif
+
+#define FUTEX_WAIT             0
+#define FUTEX_WAKE             1
+#define FUTEX_CMP_REQUEUE      4
+#define FUTEX_WAKE_OP          5
+#define FUTEX_LOCK_PI          6
+#define FUTEX_UNLOCK_PI                7
+#define FUTEX_TRYLOCK_PI       8
+#define FUTEX_WAIT_BITSET      9
+#define FUTEX_WAKE_BITSET      10
+#define FUTEX_WAIT_REQUEUE_PI  11
+#define FUTEX_CMP_REQUEUE_PI   12
+#define FUTEX_PRIVATE_FLAG     128
+#define FUTEX_CLOCK_REALTIME   256
+
+#define FUTEX_BITSET_MATCH_ANY 0xffffffff
+
+#define FUTEX_OP_CLEAR_WAKE_IF_GT_ONE  ((4 << 24) | 1)
+
+/* Values for 'private' parameter of locking macros.  Yes, the
+   definition seems to be backwards.  But it is not.  The bit will be
+   reversed before passing to the system call.  */
+#define LLL_PRIVATE    0
+#define LLL_SHARED     FUTEX_PRIVATE_FLAG
+
+#ifndef __ASSEMBLER__
+
+#if !defined NOT_IN_libc || defined IS_IN_rtld
+/* In libc.so or ld.so all futexes are private.  */
+# ifdef __ASSUME_PRIVATE_FUTEX
+#  define __lll_private_flag(fl, private) \
+  ((fl) | FUTEX_PRIVATE_FLAG)
+# else
+#  define __lll_private_flag(fl, private) \
+  ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex))
+# endif
+#else
+# ifdef __ASSUME_PRIVATE_FUTEX
+#  define __lll_private_flag(fl, private) \
+  (((fl) | FUTEX_PRIVATE_FLAG) ^ (private))
+# else
+#  define __lll_private_flag(fl, private) \
+  (__builtin_constant_p (private)                                            \
+   ? ((private) == 0                                                         \
+      ? ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex))           \
+      : (fl))                                                                \
+   : ({ unsigned int __fl = ((private) ^ FUTEX_PRIVATE_FLAG);                \
+       __asm__ ("andl %%fs:%P1, %0" : "+r" (__fl)                                    \
+            : "i" (offsetof (struct pthread, header.private_futex)));        \
+       __fl | (fl); }))
+# endif
+#endif
+
+/* Initializer for lock.  */
+#define LLL_LOCK_INITIALIZER           (0)
+#define LLL_LOCK_INITIALIZER_LOCKED    (1)
+#define LLL_LOCK_INITIALIZER_WAITERS   (2)
+
+/* Delay in spinlock loop.  */
+#define BUSY_WAIT_NOP    __asm__ ("rep; nop")
+
+
+#define LLL_STUB_UNWIND_INFO_START \
+       ".section       .eh_frame,\"a\",@progbits\n"            \
+"7:\t" ".long  9f-8f   # Length of Common Information Entry\n" \
+"8:\t" ".long  0x0     # CIE Identifier Tag\n\t"               \
+       ".byte  0x1     # CIE Version\n\t"                      \
+       ".ascii \"zR\\0\"       # CIE Augmentation\n\t"         \
+       ".uleb128 0x1   # CIE Code Alignment Factor\n\t"        \
+       ".sleb128 -8    # CIE Data Alignment Factor\n\t"        \
+       ".byte  0x10    # CIE RA Column\n\t"                    \
+       ".uleb128 0x1   # Augmentation size\n\t"                \
+       ".byte  0x1b    # FDE Encoding (pcrel sdata4)\n\t"      \
+       ".byte  0x12    # DW_CFA_def_cfa_sf\n\t"                \
+       ".uleb128 0x7\n\t"                                      \
+       ".sleb128 16\n\t"                                       \
+       ".align 8\n"                                            \
+"9:\t" ".long  23f-10f # FDE Length\n"                         \
+"10:\t"        ".long  10b-7b  # FDE CIE offset\n\t"                   \
+       ".long  1b-.    # FDE initial location\n\t"             \
+       ".long  6b-1b   # FDE address range\n\t"                \
+       ".uleb128 0x0   # Augmentation size\n\t"                \
+       ".byte  0x16    # DW_CFA_val_expression\n\t"            \
+       ".uleb128 0x10\n\t"                                     \
+       ".uleb128 12f-11f\n"                                    \
+"11:\t"        ".byte  0x80    # DW_OP_breg16\n\t"                     \
+       ".sleb128 4b-1b\n"
+#define LLL_STUB_UNWIND_INFO_END \
+       ".byte  0x16    # DW_CFA_val_expression\n\t"            \
+       ".uleb128 0x10\n\t"                                     \
+       ".uleb128 14f-13f\n"                                    \
+"13:\t"        ".byte  0x80    # DW_OP_breg16\n\t"                     \
+       ".sleb128 4b-2b\n"                                      \
+"14:\t"        ".byte  0x40 + (3b-2b) # DW_CFA_advance_loc\n\t"        \
+       ".byte  0x0e    # DW_CFA_def_cfa_offset\n\t"            \
+       ".uleb128 0\n\t"                                        \
+       ".byte  0x16    # DW_CFA_val_expression\n\t"            \
+       ".uleb128 0x10\n\t"                                     \
+       ".uleb128 16f-15f\n"                                    \
+"15:\t"        ".byte  0x80    # DW_OP_breg16\n\t"                     \
+       ".sleb128 4b-3b\n"                                      \
+"16:\t"        ".byte  0x40 + (4b-3b-1) # DW_CFA_advance_loc\n\t"      \
+       ".byte  0x0e    # DW_CFA_def_cfa_offset\n\t"            \
+       ".uleb128 128\n\t"                                      \
+       ".byte  0x16    # DW_CFA_val_expression\n\t"            \
+       ".uleb128 0x10\n\t"                                     \
+       ".uleb128 20f-17f\n"                                    \
+"17:\t"        ".byte  0x80    # DW_OP_breg16\n\t"                     \
+       ".sleb128 19f-18f\n\t"                                  \
+       ".byte  0x0d    # DW_OP_const4s\n"                      \
+"18:\t"        ".4byte 4b-.\n\t"                                       \
+       ".byte  0x1c    # DW_OP_minus\n\t"                      \
+       ".byte  0x0d    # DW_OP_const4s\n"                      \
+"19:\t"        ".4byte 24f-.\n\t"                                      \
+       ".byte  0x22    # DW_OP_plus\n"                         \
+"20:\t"        ".byte  0x40 + (5b-4b+1) # DW_CFA_advance_loc\n\t"      \
+       ".byte  0x13    # DW_CFA_def_cfa_offset_sf\n\t"         \
+       ".sleb128 16\n\t"                                       \
+       ".byte  0x16    # DW_CFA_val_expression\n\t"            \
+       ".uleb128 0x10\n\t"                                     \
+       ".uleb128 22f-21f\n"                                    \
+"21:\t"        ".byte  0x80    # DW_OP_breg16\n\t"                     \
+       ".sleb128 4b-5b\n"                                      \
+"22:\t"        ".align 8\n"                                            \
+"23:\t"        ".previous\n"
+
+/* Unwind info for
+   1: leaq ..., %rdi
+   2: subq $128, %rsp
+   3: callq ...
+   4: addq $128, %rsp
+   5: jmp 24f
+   6:
+   snippet.  */
+#define LLL_STUB_UNWIND_INFO_5 \
+LLL_STUB_UNWIND_INFO_START                                     \
+"12:\t"        ".byte  0x40 + (2b-1b) # DW_CFA_advance_loc\n\t"        \
+LLL_STUB_UNWIND_INFO_END
+
+/* Unwind info for
+   1: leaq ..., %rdi
+   0: movq ..., %rdx
+   2: subq $128, %rsp
+   3: callq ...
+   4: addq $128, %rsp
+   5: jmp 24f
+   6:
+   snippet.  */
+#define LLL_STUB_UNWIND_INFO_6 \
+LLL_STUB_UNWIND_INFO_START                                     \
+"12:\t"        ".byte  0x40 + (0b-1b) # DW_CFA_advance_loc\n\t"        \
+       ".byte  0x16    # DW_CFA_val_expression\n\t"            \
+       ".uleb128 0x10\n\t"                                     \
+       ".uleb128 26f-25f\n"                                    \
+"25:\t"        ".byte  0x80    # DW_OP_breg16\n\t"                     \
+       ".sleb128 4b-0b\n"                                      \
+"26:\t"        ".byte  0x40 + (2b-0b) # DW_CFA_advance_loc\n\t"        \
+LLL_STUB_UNWIND_INFO_END
+
+
+#define lll_futex_wait(futex, val, private) \
+  lll_futex_timed_wait(futex, val, NULL, private)
+
+
+#define lll_futex_timed_wait(futex, val, timeout, private) \
+  ({                                                                         \
+    register const struct timespec *__to __asm__ ("r10") = timeout;          \
+    int __status;                                                            \
+    register __typeof (val) _val __asm__ ("edx") = (val);                            \
+    __asm__ __volatile ("syscall"                                                    \
+                     : "=a" (__status)                                       \
+                     : "0" (SYS_futex), "D" (futex),                         \
+                       "S" (__lll_private_flag (FUTEX_WAIT, private)),       \
+                       "d" (_val), "r" (__to)                                \
+                     : "memory", "cc", "r11", "cx");                         \
+    __status;                                                                \
+  })
+
+
+#define lll_futex_wake(futex, nr, private) \
+  do {                                                                       \
+    int __ignore;                                                            \
+    register __typeof (nr) _nr __asm__ ("edx") = (nr);                       \
+    __asm__ __volatile ("syscall"                                                    \
+                     : "=a" (__ignore)                                       \
+                     : "0" (SYS_futex), "D" (futex),                         \
+                       "S" (__lll_private_flag (FUTEX_WAKE, private)),       \
+                       "d" (_nr)                                             \
+                     : "memory", "cc", "r10", "r11", "cx");                  \
+  } while (0)
+
+
+/* NB: in the lll_trylock macro we simply return the value in %eax
+   after the cmpxchg instruction.  In case the operation succeded this
+   value is zero.  In case the operation failed, the cmpxchg instruction
+   has loaded the current value of the memory work which is guaranteed
+   to be nonzero.  */
+#if defined NOT_IN_libc || defined UP
+# define __lll_trylock_asm LOCK_INSTR "cmpxchgl %2, %1"
+#else
+# define __lll_trylock_asm "cmpl $0, __libc_multiple_threads(%%rip)\n\t"      \
+                          "je 0f\n\t"                                        \
+                          "lock; cmpxchgl %2, %1\n\t"                        \
+                          "jmp 1f\n\t"                                       \
+                          "0:\tcmpxchgl %2, %1\n\t"                          \
+                          "1:"
+#endif
+
+#define lll_trylock(futex) \
+  ({ int ret;                                                                \
+     __asm__ __volatile (__lll_trylock_asm                                   \
+                      : "=a" (ret), "=m" (futex)                             \
+                      : "r" (LLL_LOCK_INITIALIZER_LOCKED), "m" (futex),      \
+                        "0" (LLL_LOCK_INITIALIZER)                           \
+                      : "memory");                                           \
+     ret; })
+
+#define lll_robust_trylock(futex, id) \
+  ({ int ret;                                                                \
+     __asm__ __volatile (LOCK_INSTR "cmpxchgl %2, %1"                        \
+                      : "=a" (ret), "=m" (futex)                             \
+                      : "r" (id), "m" (futex), "0" (LLL_LOCK_INITIALIZER)    \
+                      : "memory");                                           \
+     ret; })
+
+#define lll_cond_trylock(futex) \
+  ({ int ret;                                                                \
+     __asm__ __volatile (LOCK_INSTR "cmpxchgl %2, %1"                        \
+                      : "=a" (ret), "=m" (futex)                             \
+                      : "r" (LLL_LOCK_INITIALIZER_WAITERS),                  \
+                        "m" (futex), "0" (LLL_LOCK_INITIALIZER)              \
+                      : "memory");                                           \
+     ret; })
+
+#if defined NOT_IN_libc || defined UP
+# define __lll_lock_asm_start LOCK_INSTR "cmpxchgl %4, %2\n\t"               \
+                             "jnz 1f\n\t"
+#else
+# define __lll_lock_asm_start "cmpl $0, __libc_multiple_threads(%%rip)\n\t"   \
+                             "je 0f\n\t"                                     \
+                             "lock; cmpxchgl %4, %2\n\t"                     \
+                             "jnz 1f\n\t"                                    \
+                             "jmp 24f\n"                                     \
+                             "0:\tcmpxchgl %4, %2\n\t"                       \
+                             "jnz 1f\n\t"
+#endif
+
+#define lll_lock(futex, private) \
+  (void)                                                                     \
+    ({ int ignore1, ignore2, ignore3;                                        \
+       if (__builtin_constant_p (private) && (private) == LLL_PRIVATE)       \
+        __asm__ __volatile (__lll_lock_asm_start                                     \
+                          ".subsection 1\n\t"                                \
+                          ".type _L_lock_%=, @function\n"                    \
+                          "_L_lock_%=:\n"                                    \
+                          "1:\tleaq %2, %%rdi\n"                             \
+                          "2:\tsubq $128, %%rsp\n"                           \
+                          "3:\tcallq __lll_lock_wait_private\n"              \
+                          "4:\taddq $128, %%rsp\n"                           \
+                          "5:\tjmp 24f\n"                                    \
+                          "6:\t.size _L_lock_%=, 6b-1b\n\t"                  \
+                          ".previous\n"                                      \
+                          LLL_STUB_UNWIND_INFO_5                             \
+                          "24:"                                              \
+                          : "=S" (ignore1), "=&D" (ignore2), "=m" (futex),   \
+                            "=a" (ignore3)                                   \
+                          : "0" (1), "m" (futex), "3" (0)                    \
+                          : "cx", "r11", "cc", "memory");                    \
+       else                                                                  \
+        __asm__ __volatile (__lll_lock_asm_start                                     \
+                          ".subsection 1\n\t"                                \
+                          ".type _L_lock_%=, @function\n"                    \
+                          "_L_lock_%=:\n"                                    \
+                          "1:\tleaq %2, %%rdi\n"                             \
+                          "2:\tsubq $128, %%rsp\n"                           \
+                          "3:\tcallq __lll_lock_wait\n"                      \
+                          "4:\taddq $128, %%rsp\n"                           \
+                          "5:\tjmp 24f\n"                                    \
+                          "6:\t.size _L_lock_%=, 6b-1b\n\t"                  \
+                          ".previous\n"                                      \
+                          LLL_STUB_UNWIND_INFO_5                             \
+                          "24:"                                              \
+                          : "=S" (ignore1), "=D" (ignore2), "=m" (futex),    \
+                            "=a" (ignore3)                                   \
+                          : "1" (1), "m" (futex), "3" (0), "0" (private)     \
+                          : "cx", "r11", "cc", "memory");                    \
+    })                                                                       \
+
+#define lll_robust_lock(futex, id, private) \
+  ({ int result, ignore1, ignore2;                                           \
+    __asm__ __volatile (LOCK_INSTR "cmpxchgl %4, %2\n\t"                             \
+                     "jnz 1f\n\t"                                            \
+                     ".subsection 1\n\t"                                     \
+                     ".type _L_robust_lock_%=, @function\n"                  \
+                     "_L_robust_lock_%=:\n"                                  \
+                     "1:\tleaq %2, %%rdi\n"                                  \
+                     "2:\tsubq $128, %%rsp\n"                                \
+                     "3:\tcallq __lll_robust_lock_wait\n"                    \
+                     "4:\taddq $128, %%rsp\n"                                \
+                     "5:\tjmp 24f\n"                                         \
+                     "6:\t.size _L_robust_lock_%=, 6b-1b\n\t"                \
+                     ".previous\n"                                           \
+                     LLL_STUB_UNWIND_INFO_5                                  \
+                     "24:"                                                   \
+                     : "=S" (ignore1), "=D" (ignore2), "=m" (futex),         \
+                       "=a" (result)                                         \
+                     : "1" (id), "m" (futex), "3" (0), "0" (private)         \
+                     : "cx", "r11", "cc", "memory");                         \
+    result; })
+
+#define lll_cond_lock(futex, private) \
+  (void)                                                                     \
+    ({ int ignore1, ignore2, ignore3;                                        \
+       __asm__ __volatile (LOCK_INSTR "cmpxchgl %4, %2\n\t"                  \
+                        "jnz 1f\n\t"                                         \
+                        ".subsection 1\n\t"                                  \
+                        ".type _L_cond_lock_%=, @function\n"                 \
+                        "_L_cond_lock_%=:\n"                                 \
+                        "1:\tleaq %2, %%rdi\n"                               \
+                        "2:\tsubq $128, %%rsp\n"                             \
+                        "3:\tcallq __lll_lock_wait\n"                        \
+                        "4:\taddq $128, %%rsp\n"                             \
+                        "5:\tjmp 24f\n"                                      \
+                        "6:\t.size _L_cond_lock_%=, 6b-1b\n\t"               \
+                        ".previous\n"                                        \
+                        LLL_STUB_UNWIND_INFO_5                               \
+                        "24:"                                                \
+                        : "=S" (ignore1), "=D" (ignore2), "=m" (futex),      \
+                          "=a" (ignore3)                                     \
+                        : "1" (2), "m" (futex), "3" (0), "0" (private)       \
+                        : "cx", "r11", "cc", "memory");                      \
+    })
+
+#define lll_robust_cond_lock(futex, id, private) \
+  ({ int result, ignore1, ignore2;                                           \
+    __asm__ __volatile (LOCK_INSTR "cmpxchgl %4, %2\n\t"                             \
+                     "jnz 1f\n\t"                                            \
+                     ".subsection 1\n\t"                                     \
+                     ".type _L_robust_cond_lock_%=, @function\n"             \
+                     "_L_robust_cond_lock_%=:\n"                             \
+                     "1:\tleaq %2, %%rdi\n"                                  \
+                     "2:\tsubq $128, %%rsp\n"                                \
+                     "3:\tcallq __lll_robust_lock_wait\n"                    \
+                     "4:\taddq $128, %%rsp\n"                                \
+                     "5:\tjmp 24f\n"                                         \
+                     "6:\t.size _L_robust_cond_lock_%=, 6b-1b\n\t"           \
+                     ".previous\n"                                           \
+                     LLL_STUB_UNWIND_INFO_5                                  \
+                     "24:"                                                   \
+                     : "=S" (ignore1), "=D" (ignore2), "=m" (futex),         \
+                       "=a" (result)                                         \
+                     : "1" (id | FUTEX_WAITERS), "m" (futex), "3" (0),       \
+                       "0" (private)                                         \
+                     : "cx", "r11", "cc", "memory");                         \
+    result; })
+
+#define lll_timedlock(futex, timeout, private) \
+  ({ int result, ignore1, ignore2, ignore3;                                  \
+     __asm__ __volatile (LOCK_INSTR "cmpxchgl %1, %4\n\t"                            \
+                      "jnz 1f\n\t"                                           \
+                      ".subsection 1\n\t"                                    \
+                      ".type _L_timedlock_%=, @function\n"                   \
+                      "_L_timedlock_%=:\n"                                   \
+                      "1:\tleaq %4, %%rdi\n"                                 \
+                      "0:\tmovq %8, %%rdx\n"                                 \
+                      "2:\tsubq $128, %%rsp\n"                               \
+                      "3:\tcallq __lll_timedlock_wait\n"                     \
+                      "4:\taddq $128, %%rsp\n"                               \
+                      "5:\tjmp 24f\n"                                        \
+                      "6:\t.size _L_timedlock_%=, 6b-1b\n\t"                 \
+                      ".previous\n"                                          \
+                      LLL_STUB_UNWIND_INFO_6                                 \
+                      "24:"                                                  \
+                      : "=a" (result), "=D" (ignore1), "=S" (ignore2),       \
+                        "=&d" (ignore3), "=m" (futex)                        \
+                      : "0" (0), "1" (1), "m" (futex), "m" (timeout),        \
+                        "2" (private)                                        \
+                      : "memory", "cx", "cc", "r10", "r11");                 \
+     result; })
+
+#define lll_robust_timedlock(futex, timeout, id, private) \
+  ({ int result, ignore1, ignore2, ignore3;                                  \
+     __asm__ __volatile (LOCK_INSTR "cmpxchgl %1, %4\n\t"                            \
+                      "jnz 1f\n\t"                                           \
+                      ".subsection 1\n\t"                                    \
+                      ".type _L_robust_timedlock_%=, @function\n"            \
+                      "_L_robust_timedlock_%=:\n"                            \
+                      "1:\tleaq %4, %%rdi\n"                                 \
+                      "0:\tmovq %8, %%rdx\n"                                 \
+                      "2:\tsubq $128, %%rsp\n"                               \
+                      "3:\tcallq __lll_robust_timedlock_wait\n"              \
+                      "4:\taddq $128, %%rsp\n"                               \
+                      "5:\tjmp 24f\n"                                        \
+                      "6:\t.size _L_robust_timedlock_%=, 6b-1b\n\t"          \
+                      ".previous\n"                                          \
+                      LLL_STUB_UNWIND_INFO_6                                 \
+                      "24:"                                                  \
+                      : "=a" (result), "=D" (ignore1), "=S" (ignore2),       \
+                        "=&d" (ignore3), "=m" (futex)                        \
+                      : "0" (0), "1" (id), "m" (futex), "m" (timeout),       \
+                        "2" (private)                                        \
+                      : "memory", "cx", "cc", "r10", "r11");                 \
+     result; })
+
+#if defined NOT_IN_libc || defined UP
+# define __lll_unlock_asm_start LOCK_INSTR "decl %0\n\t"                     \
+                               "jne 1f\n\t"
+#else
+# define __lll_unlock_asm_start "cmpl $0, __libc_multiple_threads(%%rip)\n\t" \
+                               "je 0f\n\t"                                   \
+                               "lock; decl %0\n\t"                           \
+                               "jne 1f\n\t"                                  \
+                               "jmp 24f\n\t"                                 \
+                               "0:\tdecl %0\n\t"                             \
+                               "jne 1f\n\t"
+#endif
+
+#define lll_unlock(futex, private) \
+  (void)                                                                     \
+    ({ int ignore;                                                           \
+       if (__builtin_constant_p (private) && (private) == LLL_PRIVATE)       \
+        __asm__ __volatile (__lll_unlock_asm_start                           \
+                          ".subsection 1\n\t"                                \
+                          ".type _L_unlock_%=, @function\n"                  \
+                          "_L_unlock_%=:\n"                                  \
+                          "1:\tleaq %0, %%rdi\n"                             \
+                          "2:\tsubq $128, %%rsp\n"                           \
+                          "3:\tcallq __lll_unlock_wake_private\n"            \
+                          "4:\taddq $128, %%rsp\n"                           \
+                          "5:\tjmp 24f\n"                                    \
+                          "6:\t.size _L_unlock_%=, 6b-1b\n\t"                \
+                          ".previous\n"                                      \
+                          LLL_STUB_UNWIND_INFO_5                             \
+                          "24:"                                              \
+                          : "=m" (futex), "=&D" (ignore)                     \
+                          : "m" (futex)                                      \
+                          : "ax", "cx", "r11", "cc", "memory");              \
+       else                                                                  \
+        __asm__ __volatile (__lll_unlock_asm_start                           \
+                          ".subsection 1\n\t"                                \
+                          ".type _L_unlock_%=, @function\n"                  \
+                          "_L_unlock_%=:\n"                                  \
+                          "1:\tleaq %0, %%rdi\n"                             \
+                          "2:\tsubq $128, %%rsp\n"                           \
+                          "3:\tcallq __lll_unlock_wake\n"                    \
+                          "4:\taddq $128, %%rsp\n"                           \
+                          "5:\tjmp 24f\n"                                    \
+                          "6:\t.size _L_unlock_%=, 6b-1b\n\t"                \
+                          ".previous\n"                                      \
+                          LLL_STUB_UNWIND_INFO_5                             \
+                          "24:"                                              \
+                          : "=m" (futex), "=&D" (ignore)                     \
+                          : "m" (futex), "S" (private)                       \
+                          : "ax", "cx", "r11", "cc", "memory");              \
+    })
+
+#define lll_robust_unlock(futex, private) \
+  do                                                                         \
+    {                                                                        \
+      int ignore;                                                            \
+      __asm__ __volatile (LOCK_INSTR "andl %2, %0\n\t"                       \
+                       "jne 1f\n\t"                                          \
+                       ".subsection 1\n\t"                                   \
+                       ".type _L_robust_unlock_%=, @function\n"              \
+                       "_L_robust_unlock_%=:\n"                              \
+                       "1:\tleaq %0, %%rdi\n"                                \
+                       "2:\tsubq $128, %%rsp\n"                              \
+                       "3:\tcallq __lll_unlock_wake\n"                       \
+                       "4:\taddq $128, %%rsp\n"                              \
+                       "5:\tjmp 24f\n"                                       \
+                       "6:\t.size _L_robust_unlock_%=, 6b-1b\n\t"            \
+                       ".previous\n"                                         \
+                       LLL_STUB_UNWIND_INFO_5                                \
+                       "24:"                                                 \
+                       : "=m" (futex), "=&D" (ignore)                        \
+                       : "i" (FUTEX_WAITERS), "m" (futex),                   \
+                         "S" (private)                                       \
+                       : "ax", "cx", "r11", "cc", "memory");                 \
+    }                                                                        \
+  while (0)
+
+#define lll_robust_dead(futex, private) \
+  do                                                                         \
+    {                                                                        \
+      int ignore;                                                            \
+      __asm__ __volatile (LOCK_INSTR "orl %3, (%2)\n\t"                              \
+                       "syscall"                                             \
+                       : "=m" (futex), "=a" (ignore)                         \
+                       : "D" (&(futex)), "i" (FUTEX_OWNER_DIED),             \
+                         "S" (__lll_private_flag (FUTEX_WAKE, private)),     \
+                         "1" (__NR_futex), "d" (1)                           \
+                       : "cx", "r11", "cc", "memory");                       \
+    }                                                                        \
+  while (0)
+
+/* Returns non-zero if error happened, zero if success.  */
+#define lll_futex_requeue(ftx, nr_wake, nr_move, mutex, val, private) \
+  ({ int __res;                                                                      \
+     register int __nr_move __asm__ ("r10") = nr_move;                       \
+     register void *__mutex __asm__ ("r8") = mutex;                          \
+     register int __val __asm__ ("r9") = val;                                \
+     __asm__ __volatile ("syscall"                                           \
+                      : "=a" (__res)                                         \
+                      : "0" (__NR_futex), "D" ((void *) ftx),                \
+                        "S" (__lll_private_flag (FUTEX_CMP_REQUEUE,          \
+                                                 private)), "d" (nr_wake),   \
+                        "r" (__nr_move), "r" (__mutex), "r" (__val)          \
+                      : "cx", "r11", "cc", "memory");                        \
+     __res < 0; })
+
+#define lll_islocked(futex) \
+  (futex != LLL_LOCK_INITIALIZER)
+
+
+/* The kernel notifies a process with uses CLONE_CLEARTID via futex
+   wakeup when the clone terminates.  The memory location contains the
+   thread ID while the clone is running and is reset to zero
+   afterwards.
+
+   The macro parameter must not have any side effect.  */
+#define lll_wait_tid(tid) \
+  do {                                                                       \
+    int __ignore;                                                            \
+    register __typeof (tid) _tid __asm__ ("edx") = (tid);                            \
+    if (_tid != 0)                                                           \
+      __asm__ __volatile ("xorq %%r10, %%r10\n\t"                                    \
+                       "1:\tmovq %2, %%rax\n\t"                              \
+                       "syscall\n\t"                                         \
+                       "cmpl $0, (%%rdi)\n\t"                                \
+                       "jne 1b"                                              \
+                       : "=&a" (__ignore)                                    \
+                       : "S" (FUTEX_WAIT), "i" (SYS_futex), "D" (&tid),      \
+                         "d" (_tid)                                          \
+                       : "memory", "cc", "r10", "r11", "cx");                \
+  } while (0)
+
+extern int __lll_timedwait_tid (int *tid, const struct timespec *abstime)
+     attribute_hidden;
+#define lll_timedwait_tid(tid, abstime) \
+  ({                                                                         \
+    int __result = 0;                                                        \
+    if (tid != 0)                                                            \
+      {                                                                              \
+       if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)           \
+         __result = EINVAL;                                                  \
+       else                                                                  \
+         __result = __lll_timedwait_tid (&tid, abstime);                     \
+      }                                                                              \
+    __result; })
+
+#endif  /* !__ASSEMBLER__ */
+
+#endif /* lowlevellock.h */
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevelrobustlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevelrobustlock.S
new file mode 100644 (file)
index 0000000..2eb8e29
--- /dev/null
@@ -0,0 +1,306 @@
+/* Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2009
+   Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <pthread-errnos.h>
+#include <lowlevellock.h>
+#include <lowlevelrobustlock.h>
+#include <bits/kernel-features.h>
+
+       .text
+
+#define FUTEX_WAITERS          0x80000000
+#define FUTEX_OWNER_DIED       0x40000000
+
+#ifdef __ASSUME_PRIVATE_FUTEX
+# define LOAD_FUTEX_WAIT(reg) \
+       xorl    $(FUTEX_WAIT | FUTEX_PRIVATE_FLAG), reg
+# define LOAD_FUTEX_WAIT_ABS(reg) \
+       xorl    $(FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME), reg
+#else
+# if FUTEX_WAIT == 0
+#  define LOAD_FUTEX_WAIT(reg) \
+       xorl    $FUTEX_PRIVATE_FLAG, reg ; \
+       andl    %fs:PRIVATE_FUTEX, reg
+# else
+#  define LOAD_FUTEX_WAIT(reg) \
+       xorl    $FUTEX_PRIVATE_FLAG, reg ; \
+       andl    %fs:PRIVATE_FUTEX, reg ; \
+       orl     $FUTEX_WAIT, reg
+# endif
+# define LOAD_FUTEX_WAIT_ABS(reg) \
+       xorl    $FUTEX_PRIVATE_FLAG, reg ; \
+       andl    %fs:PRIVATE_FUTEX, reg ; \
+       orl     $FUTEX_WAIT_BITSET | FUTEX_CLOCK_REALTIME, reg
+#endif
+
+/* For the calculation see asm/vsyscall.h.  */
+#define VSYSCALL_ADDR_vgettimeofday    0xffffffffff600000
+
+
+       .globl  __lll_robust_lock_wait
+       .type   __lll_robust_lock_wait,@function
+       .hidden __lll_robust_lock_wait
+       .align  16
+__lll_robust_lock_wait:
+       cfi_startproc
+       pushq   %r10
+       cfi_adjust_cfa_offset(8)
+       pushq   %rdx
+       cfi_adjust_cfa_offset(8)
+       cfi_offset(%r10, -16)
+       cfi_offset(%rdx, -24)
+
+       xorq    %r10, %r10      /* No timeout.  */
+       LOAD_FUTEX_WAIT (%esi)
+
+4:     movl    %eax, %edx
+       orl     $FUTEX_WAITERS, %edx
+
+       testl   $FUTEX_OWNER_DIED, %eax
+       jnz     3f
+
+       cmpl    %edx, %eax
+       je      1f
+
+       LOCK
+       cmpxchgl %edx, (%rdi)
+       jnz     2f
+
+1:     movl    $SYS_futex, %eax
+       syscall
+
+       movl    (%rdi), %eax
+
+2:     testl   %eax, %eax
+       jne     4b
+
+       movl    %fs:TID, %edx
+       orl     $FUTEX_WAITERS, %edx
+       LOCK
+       cmpxchgl %edx, (%rdi)
+       jnz     4b
+       /* NB:   %rax == 0 */
+
+3:     popq    %rdx
+       cfi_adjust_cfa_offset(-8)
+       cfi_restore(%rdx)
+       popq    %r10
+       cfi_adjust_cfa_offset(-8)
+       cfi_restore(%r10)
+       retq
+       cfi_endproc
+       .size   __lll_robust_lock_wait,.-__lll_robust_lock_wait
+
+
+       .globl  __lll_robust_timedlock_wait
+       .type   __lll_robust_timedlock_wait,@function
+       .hidden __lll_robust_timedlock_wait
+       .align  16
+__lll_robust_timedlock_wait:
+       cfi_startproc
+# ifndef __ASSUME_FUTEX_CLOCK_REALTIME
+#  ifdef __PIC__
+       cmpl    $0, __have_futex_clock_realtime(%rip)
+#  else
+       cmpl    $0, __have_futex_clock_realtime
+#  endif
+       je      .Lreltmo
+# endif
+
+       pushq   %r9
+       cfi_adjust_cfa_offset(8)
+       cfi_rel_offset(%r9, 0)
+       movq    %rdx, %r10
+       movl    $0xffffffff, %r9d
+       LOAD_FUTEX_WAIT_ABS (%esi)
+
+1:     testl   $FUTEX_OWNER_DIED, %eax
+       jnz     3f
+
+       movl    %eax, %edx
+       orl     $FUTEX_WAITERS, %edx
+
+       cmpl    %eax, %edx
+       je      5f
+
+       LOCK
+       cmpxchgl %edx, (%rdi)
+       movq    $0, %rcx        /* Must use mov to avoid changing cc.  */
+       jnz     6f
+
+5:     movl    $SYS_futex, %eax
+       syscall
+       movl    %eax, %ecx
+
+       movl    (%rdi), %eax
+
+6:     testl   %eax, %eax
+       jne     2f
+
+       movl    %fs:TID, %edx
+       orl     $FUTEX_WAITERS, %edx
+       LOCK
+       cmpxchgl %edx, (%rdi)
+       jnz     2f
+
+3:     popq    %r9
+       cfi_adjust_cfa_offset(-8)
+       cfi_restore(%r9)
+       retq
+
+       cfi_adjust_cfa_offset(8)
+       cfi_rel_offset(%r9, 0)
+       /* Check whether the time expired.  */
+2:     cmpl    $-ETIMEDOUT, %ecx
+       je      4f
+       cmpl    $-EINVAL, %ecx
+       jne     1b
+
+4:     movl    %ecx, %eax
+       negl    %eax
+       jmp     3b
+       cfi_adjust_cfa_offset(-8)
+       cfi_restore(%r9)
+
+
+# ifndef __ASSUME_FUTEX_CLOCK_REALTIME
+.Lreltmo:
+       /* Check for a valid timeout value.  */
+       cmpq    $1000000000, 8(%rdx)
+       jae     3f
+
+       pushq   %r8
+       cfi_adjust_cfa_offset(8)
+       pushq   %r9
+       cfi_adjust_cfa_offset(8)
+       pushq   %r12
+       cfi_adjust_cfa_offset(8)
+       pushq   %r13
+       cfi_adjust_cfa_offset(8)
+       cfi_offset(%r8, -16)
+       cfi_offset(%r9, -24)
+       cfi_offset(%r12, -32)
+       cfi_offset(%r13, -40)
+       pushq   %rsi
+       cfi_adjust_cfa_offset(8)
+
+       /* Stack frame for the timespec and timeval structs.  */
+       subq    $32, %rsp
+       cfi_adjust_cfa_offset(32)
+
+       movq    %rdi, %r12
+       movq    %rdx, %r13
+
+1:     movq    %rax, 16(%rsp)
+
+       /* Get current time.  */
+       movq    %rsp, %rdi
+       xorl    %esi, %esi
+       movq    $VSYSCALL_ADDR_vgettimeofday, %rax
+       /* This is a regular function call, all caller-save registers
+          might be clobbered.  */
+       callq   *%rax
+
+       /* Compute relative timeout.  */
+       movq    8(%rsp), %rax
+       movl    $1000, %edi
+       mul     %rdi            /* Milli seconds to nano seconds.  */
+       movq    (%r13), %rdi
+       movq    8(%r13), %rsi
+       subq    (%rsp), %rdi
+       subq    %rax, %rsi
+       jns     4f
+       addq    $1000000000, %rsi
+       decq    %rdi
+4:     testq   %rdi, %rdi
+       js      8f              /* Time is already up.  */
+
+       /* Futex call.  */
+       movq    %rdi, (%rsp)    /* Store relative timeout.  */
+       movq    %rsi, 8(%rsp)
+
+       movq    16(%rsp), %rdx
+       movl    %edx, %eax
+       orl     $FUTEX_WAITERS, %edx
+
+       testl   $FUTEX_OWNER_DIED, %eax
+       jnz     6f
+
+       cmpl    %eax, %edx
+       je      2f
+
+       LOCK
+       cmpxchgl %edx, (%r12)
+       movq    $0, %rcx        /* Must use mov to avoid changing cc.  */
+       jnz     5f
+
+2:     movq    %rsp, %r10
+       movl    32(%rsp), %esi
+       LOAD_FUTEX_WAIT (%esi)
+       movq    %r12, %rdi
+       movl    $SYS_futex, %eax
+       syscall
+       movq    %rax, %rcx
+
+       movl    (%r12), %eax
+
+5:     testl   %eax, %eax
+       jne     7f
+
+       movl    %fs:TID, %edx
+       orl     $FUTEX_WAITERS, %edx
+       LOCK
+       cmpxchgl %edx, (%r12)
+       jnz     7f
+
+6:     addq    $40, %rsp
+       cfi_adjust_cfa_offset(-40)
+       popq    %r13
+       cfi_adjust_cfa_offset(-8)
+       cfi_restore(%r13)
+       popq    %r12
+       cfi_adjust_cfa_offset(-8)
+       cfi_restore(%r12)
+       popq    %r9
+       cfi_adjust_cfa_offset(-8)
+       cfi_restore(%r9)
+       popq    %r8
+       cfi_adjust_cfa_offset(-8)
+       cfi_restore(%r8)
+       retq
+
+3:     movl    $EINVAL, %eax
+       retq
+
+       cfi_adjust_cfa_offset(72)
+       cfi_offset(%r8, -16)
+       cfi_offset(%r9, -24)
+       cfi_offset(%r12, -32)
+       cfi_offset(%r13, -40)
+       /* Check whether the time expired.  */
+7:     cmpl    $-ETIMEDOUT, %ecx
+       jne     1b
+
+8:     movl    $ETIMEDOUT, %eax
+       jmp     6b
+#endif
+       cfi_endproc
+       .size   __lll_robust_timedlock_wait,.-__lll_robust_timedlock_wait
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pt-__syscall_error.c b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pt-__syscall_error.c
new file mode 100644 (file)
index 0000000..2ab8149
--- /dev/null
@@ -0,0 +1 @@
+#include <../../../../../../../libc/sysdeps/linux/x86_64/__syscall_error.c>
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pt-vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pt-vfork.S
new file mode 100644 (file)
index 0000000..df49496
--- /dev/null
@@ -0,0 +1,33 @@
+/* Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <tcb-offsets.h>
+
+#define SAVE_PID \
+       movl    %fs:PID, %esi;                                                \
+       movl    %esi, %edx;                                                   \
+       negl    %edx;                                                         \
+       movl    %edx, %fs:PID
+
+#define RESTORE_PID \
+       testq   %rax, %rax;                                                   \
+       je      1f;                                                           \
+       movl    %esi, %fs:PID;                                                \
+1:
+
+#include <../../../../../../../libc/sysdeps/linux/x86_64/vfork.S>
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_barrier_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_barrier_wait.S
new file mode 100644 (file)
index 0000000..15ad534
--- /dev/null
@@ -0,0 +1,161 @@
+/* Copyright (C) 2002, 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <lowlevelbarrier.h>
+
+
+       .text
+
+       .globl  pthread_barrier_wait
+       .type   pthread_barrier_wait,@function
+       .align  16
+pthread_barrier_wait:
+       /* Get the mutex.  */
+       xorl    %eax, %eax
+       movl    $1, %esi
+       LOCK
+       cmpxchgl %esi, MUTEX(%rdi)
+       jnz     1f
+
+       /* One less waiter.  If this was the last one needed wake
+          everybody.  */
+2:     decl    LEFT(%rdi)
+       je      3f
+
+       /* There are more threads to come.  */
+#if CURR_EVENT == 0
+       movl    (%rdi), %edx
+#else
+       movl    CURR_EVENT(%rdi), %edx
+#endif
+
+       /* Release the mutex.  */
+       LOCK
+       decl    MUTEX(%rdi)
+       jne     6f
+
+       /* Wait for the remaining threads.  The call will return immediately
+          if the CURR_EVENT memory has meanwhile been changed.  */
+7:
+#if FUTEX_WAIT == 0
+       movl    PRIVATE(%rdi), %esi
+#else
+       movl    $FUTEX_WAIT, %esi
+       orl     PRIVATE(%rdi), %esi
+#endif
+       xorq    %r10, %r10
+8:     movl    $SYS_futex, %eax
+       syscall
+
+       /* Don't return on spurious wakeups.  The syscall does not change
+          any register except %eax so there is no need to reload any of
+          them.  */
+#if CURR_EVENT == 0
+       cmpl    %edx, (%rdi)
+#else
+       cmpl    %edx, CURR_EVENT(%rdi)
+#endif
+       je      8b
+
+       /* Increment LEFT.  If this brings the count back to the
+          initial count unlock the object.  */
+       movl    $1, %edx
+       movl    INIT_COUNT(%rdi), %eax
+       LOCK
+       xaddl   %edx, LEFT(%rdi)
+       subl    $1, %eax
+       cmpl    %eax, %edx
+       jne,pt  10f
+
+       /* Release the mutex.  We cannot release the lock before
+          waking the waiting threads since otherwise a new thread might
+          arrive and gets waken up, too.  */
+       LOCK
+       decl    MUTEX(%rdi)
+       jne     9f
+
+10:    xorl    %eax, %eax              /* != PTHREAD_BARRIER_SERIAL_THREAD */
+
+       retq
+
+       /* The necessary number of threads arrived.  */
+3:
+#if CURR_EVENT == 0
+       incl    (%rdi)
+#else
+       incl    CURR_EVENT(%rdi)
+#endif
+
+       /* Wake up all waiters.  The count is a signed number in the kernel
+          so 0x7fffffff is the highest value.  */
+       movl    $0x7fffffff, %edx
+       movl    $FUTEX_WAKE, %esi
+       orl     PRIVATE(%rdi), %esi
+       movl    $SYS_futex, %eax
+       syscall
+
+       /* Increment LEFT.  If this brings the count back to the
+          initial count unlock the object.  */
+       movl    $1, %edx
+       movl    INIT_COUNT(%rdi), %eax
+       LOCK
+       xaddl   %edx, LEFT(%rdi)
+       subl    $1, %eax
+       cmpl    %eax, %edx
+       jne,pt  5f
+
+       /* Release the mutex.  We cannot release the lock before
+          waking the waiting threads since otherwise a new thread might
+          arrive and gets waken up, too.  */
+       LOCK
+       decl    MUTEX(%rdi)
+       jne     4f
+
+5:     orl     $-1, %eax               /* == PTHREAD_BARRIER_SERIAL_THREAD */
+
+       retq
+
+1:     movl    PRIVATE(%rdi), %esi
+       addq    $MUTEX, %rdi
+       xorl    $LLL_SHARED, %esi
+       callq   __lll_lock_wait
+       subq    $MUTEX, %rdi
+       jmp     2b
+
+4:     movl    PRIVATE(%rdi), %esi
+       addq    $MUTEX, %rdi
+       xorl    $LLL_SHARED, %esi
+       callq   __lll_unlock_wake
+       jmp     5b
+
+6:     movl    PRIVATE(%rdi), %esi
+       addq    $MUTEX, %rdi
+       xorl    $LLL_SHARED, %esi
+       callq   __lll_unlock_wake
+       subq    $MUTEX, %rdi
+       jmp     7b
+
+9:     movl    PRIVATE(%rdi), %esi
+       addq    $MUTEX, %rdi
+       xorl    $LLL_SHARED, %esi
+       callq   __lll_unlock_wake
+       jmp     10b
+       .size   pthread_barrier_wait,.-pthread_barrier_wait
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S
new file mode 100644 (file)
index 0000000..0f8037b
--- /dev/null
@@ -0,0 +1,177 @@
+/* Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2009
+   Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <lowlevelcond.h>
+#include <bits/kernel-features.h>
+#include <pthread-pi-defines.h>
+#include <pthread-errnos.h>
+
+
+       .text
+
+       /* int pthread_cond_broadcast (pthread_cond_t *cond) */
+       .globl  __pthread_cond_broadcast
+       .type   __pthread_cond_broadcast, @function
+       .align  16
+__pthread_cond_broadcast:
+
+       /* Get internal lock.  */
+       movl    $1, %esi
+       xorl    %eax, %eax
+       LOCK
+#if cond_lock == 0
+       cmpxchgl %esi, (%rdi)
+#else
+       cmpxchgl %esi, cond_lock(%rdi)
+#endif
+       jnz     1f
+
+2:     addq    $cond_futex, %rdi
+       movq    total_seq-cond_futex(%rdi), %r9
+       cmpq    wakeup_seq-cond_futex(%rdi), %r9
+       jna     4f
+
+       /* Cause all currently waiting threads to recognize they are
+          woken up.  */
+       movq    %r9, wakeup_seq-cond_futex(%rdi)
+       movq    %r9, woken_seq-cond_futex(%rdi)
+       addq    %r9, %r9
+       movl    %r9d, (%rdi)
+       incl    broadcast_seq-cond_futex(%rdi)
+
+       /* Get the address of the mutex used.  */
+       movq    dep_mutex-cond_futex(%rdi), %r8
+
+       /* Unlock.  */
+       LOCK
+       decl    cond_lock-cond_futex(%rdi)
+       jne     7f
+
+8:     cmpq    $-1, %r8
+       je      9f
+
+       /* Do not use requeue for pshared condvars.  */
+       testl   $PS_BIT, MUTEX_KIND(%r8)
+       jne     9f
+
+       /* Requeue to a PI mutex if the PI bit is set.  */
+       movl    MUTEX_KIND(%r8), %eax
+       andl    $(ROBUST_BIT|PI_BIT), %eax
+       cmpl    $PI_BIT, %eax
+       je      81f
+
+       /* Wake up all threads.  */
+#ifdef __ASSUME_PRIVATE_FUTEX
+       movl    $(FUTEX_CMP_REQUEUE|FUTEX_PRIVATE_FLAG), %esi
+#else
+       movl    %fs:PRIVATE_FUTEX, %esi
+       orl     $FUTEX_CMP_REQUEUE, %esi
+#endif
+       movl    $SYS_futex, %eax
+       movl    $1, %edx
+       movl    $0x7fffffff, %r10d
+       syscall
+
+       /* For any kind of error, which mainly is EAGAIN, we try again
+          with WAKE.  The general test also covers running on old
+          kernels.  */
+       cmpq    $-4095, %rax
+       jae     9f
+
+10:    xorl    %eax, %eax
+       retq
+
+       /* Wake up all threads.  */
+81:    movl    $(FUTEX_CMP_REQUEUE_PI|FUTEX_PRIVATE_FLAG), %esi
+       movl    $SYS_futex, %eax
+       movl    $1, %edx
+       movl    $0x7fffffff, %r10d
+       syscall
+
+       /* For any kind of error, which mainly is EAGAIN, we try again
+          with WAKE.  The general test also covers running on old
+          kernels.  */
+       cmpq    $-4095, %rax
+       jb      10b
+       jmp     9f
+
+       .align  16
+       /* Unlock.  */
+4:     LOCK
+       decl    cond_lock-cond_futex(%rdi)
+       jne     5f
+
+6:     xorl    %eax, %eax
+       retq
+
+       /* Initial locking failed.  */
+1:
+#if cond_lock != 0
+       addq    $cond_lock, %rdi
+#endif
+       cmpq    $-1, dep_mutex-cond_lock(%rdi)
+       movl    $LLL_PRIVATE, %eax
+       movl    $LLL_SHARED, %esi
+       cmovne  %eax, %esi
+       callq   __lll_lock_wait
+#if cond_lock != 0
+       subq    $cond_lock, %rdi
+#endif
+       jmp     2b
+
+       /* Unlock in loop requires wakeup.  */
+5:     addq    $cond_lock-cond_futex, %rdi
+       cmpq    $-1, dep_mutex-cond_lock(%rdi)
+       movl    $LLL_PRIVATE, %eax
+       movl    $LLL_SHARED, %esi
+       cmovne  %eax, %esi
+       callq   __lll_unlock_wake
+       jmp     6b
+
+       /* Unlock in loop requires wakeup.  */
+7:     addq    $cond_lock-cond_futex, %rdi
+       cmpq    $-1, %r8
+       movl    $LLL_PRIVATE, %eax
+       movl    $LLL_SHARED, %esi
+       cmovne  %eax, %esi
+       callq   __lll_unlock_wake
+       subq    $cond_lock-cond_futex, %rdi
+       jmp     8b
+
+9:     /* The futex requeue functionality is not available.  */
+       cmpq    $-1, %r8
+       movl    $0x7fffffff, %edx
+#ifdef __ASSUME_PRIVATE_FUTEX
+       movl    $FUTEX_WAKE, %eax
+       movl    $(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), %esi
+       cmove   %eax, %esi
+#else
+       movl    $0, %eax
+       movl    %fs:PRIVATE_FUTEX, %esi
+       cmove   %eax, %esi
+       orl     $FUTEX_WAKE, %esi
+#endif
+       movl    $SYS_futex, %eax
+       syscall
+       jmp     10b
+       .size   __pthread_cond_broadcast, .-__pthread_cond_broadcast
+weak_alias(__pthread_cond_broadcast, pthread_cond_broadcast)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_signal.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_signal.S
new file mode 100644 (file)
index 0000000..568c984
--- /dev/null
@@ -0,0 +1,160 @@
+/* Copyright (C) 2002-2005, 2007, 2009 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <lowlevelcond.h>
+#include <pthread-pi-defines.h>
+#include <bits/kernel-features.h>
+#include <pthread-errnos.h>
+
+
+       .text
+
+       /* int pthread_cond_signal (pthread_cond_t *cond) */
+       .globl  __pthread_cond_signal
+       .type   __pthread_cond_signal, @function
+       .align  16
+__pthread_cond_signal:
+
+       /* Get internal lock.  */
+       movq    %rdi, %r8
+       movl    $1, %esi
+       xorl    %eax, %eax
+       LOCK
+#if cond_lock == 0
+       cmpxchgl %esi, (%rdi)
+#else
+       cmpxchgl %esi, cond_lock(%rdi)
+#endif
+       jnz     1f
+
+2:     addq    $cond_futex, %rdi
+       movq    total_seq(%r8), %rcx
+       cmpq    wakeup_seq(%r8), %rcx
+       jbe     4f
+
+       /* Bump the wakeup number.  */
+       addq    $1, wakeup_seq(%r8)
+       addl    $1, (%rdi)
+
+       /* Wake up one thread.  */
+       cmpq    $-1, dep_mutex(%r8)
+       movl    $FUTEX_WAKE_OP, %esi
+       movl    $1, %edx
+       movl    $SYS_futex, %eax
+       je      8f
+
+       /* Get the address of the mutex used.  */
+       movq    dep_mutex(%r8), %rcx
+       movl    MUTEX_KIND(%rcx), %r11d
+       andl    $(ROBUST_BIT|PI_BIT), %r11d
+       cmpl    $PI_BIT, %r11d
+       je      9f
+
+#ifdef __ASSUME_PRIVATE_FUTEX
+       movl    $(FUTEX_WAKE_OP|FUTEX_PRIVATE_FLAG), %esi
+#else
+       orl     %fs:PRIVATE_FUTEX, %esi
+#endif
+
+8:     movl    $1, %r10d
+#if cond_lock != 0
+       addq    $cond_lock, %r8
+#endif
+       movl    $FUTEX_OP_CLEAR_WAKE_IF_GT_ONE, %r9d
+       syscall
+#if cond_lock != 0
+       subq    $cond_lock, %r8
+#endif
+       /* For any kind of error, we try again with WAKE.
+          The general test also covers running on old kernels.  */
+       cmpq    $-4095, %rax
+       jae     7f
+
+       xorl    %eax, %eax
+       retq
+
+       /* Wake up one thread and requeue none in the PI Mutex case.  */
+9:     movl    $(FUTEX_CMP_REQUEUE_PI|FUTEX_PRIVATE_FLAG), %esi
+       movq    %rcx, %r8
+       xorq    %r10, %r10
+       movl    (%rdi), %r9d    // XXX Can this be right?
+       syscall
+
+       leaq    -cond_futex(%rdi), %r8
+
+       /* For any kind of error, we try again with WAKE.
+          The general test also covers running on old kernels.  */
+       cmpq    $-4095, %rax
+       jb      4f
+
+7:
+#ifdef __ASSUME_PRIVATE_FUTEX
+       andl    $FUTEX_PRIVATE_FLAG, %esi
+#else
+       andl    %fs:PRIVATE_FUTEX, %esi
+#endif
+       orl     $FUTEX_WAKE, %esi
+       movl    $SYS_futex, %eax
+       /* %rdx should be 1 already from $FUTEX_WAKE_OP syscall.
+       movl    $1, %edx  */
+       syscall
+
+       /* Unlock.  */
+4:     LOCK
+#if cond_lock == 0
+       decl    (%r8)
+#else
+       decl    cond_lock(%r8)
+#endif
+       jne     5f
+
+6:     xorl    %eax, %eax
+       retq
+
+       /* Initial locking failed.  */
+1:
+#if cond_lock != 0
+       addq    $cond_lock, %rdi
+#endif
+       cmpq    $-1, dep_mutex-cond_lock(%rdi)
+       movl    $LLL_PRIVATE, %eax
+       movl    $LLL_SHARED, %esi
+       cmovne  %eax, %esi
+       callq   __lll_lock_wait
+#if cond_lock != 0
+       subq    $cond_lock, %rdi
+#endif
+       jmp     2b
+
+       /* Unlock in loop requires wakeup.  */
+5:
+       movq    %r8, %rdi
+#if cond_lock != 0
+       addq    $cond_lock, %rdi
+#endif
+       cmpq    $-1, dep_mutex-cond_lock(%rdi)
+       movl    $LLL_PRIVATE, %eax
+       movl    $LLL_SHARED, %esi
+       cmovne  %eax, %esi
+       callq   __lll_unlock_wake
+       jmp     6b
+       .size   __pthread_cond_signal, .-__pthread_cond_signal
+weak_alias(__pthread_cond_signal, pthread_cond_signal)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S
new file mode 100644 (file)
index 0000000..bc5c0b3
--- /dev/null
@@ -0,0 +1,803 @@
+/* Copyright (C) 2002-2005, 2007, 2009 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <lowlevelcond.h>
+#include <pthread-pi-defines.h>
+#include <pthread-errnos.h>
+#include <bits/kernel-features.h>
+#include <tcb-offsets.h>
+
+/* For the calculation see asm/vsyscall.h.  */
+#define VSYSCALL_ADDR_vgettimeofday    0xffffffffff600000
+
+
+       .text
+
+
+/* int pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex,
+                              const struct timespec *abstime)  */
+       .globl  __pthread_cond_timedwait
+       .type   __pthread_cond_timedwait, @function
+       .align  16
+__pthread_cond_timedwait:
+.LSTARTCODE:
+       cfi_startproc
+
+       pushq   %r12
+       cfi_adjust_cfa_offset(8)
+       cfi_rel_offset(%r12, 0)
+       pushq   %r13
+       cfi_adjust_cfa_offset(8)
+       cfi_rel_offset(%r13, 0)
+       pushq   %r14
+       cfi_adjust_cfa_offset(8)
+       cfi_rel_offset(%r14, 0)
+       pushq   %r15
+       cfi_adjust_cfa_offset(8)
+       cfi_rel_offset(%r15, 0)
+#ifdef __ASSUME_FUTEX_CLOCK_REALTIME
+# define FRAME_SIZE 32
+#else
+# define FRAME_SIZE 48
+#endif
+       subq    $FRAME_SIZE, %rsp
+       cfi_adjust_cfa_offset(FRAME_SIZE)
+       cfi_remember_state
+
+       cmpq    $1000000000, 8(%rdx)
+       movl    $EINVAL, %eax
+       jae     48f
+
+       /* Stack frame:
+
+          rsp + 48
+                   +--------------------------+
+          rsp + 32 | timeout value            |
+                   +--------------------------+
+          rsp + 24 | old wake_seq value       |
+                   +--------------------------+
+          rsp + 16 | mutex pointer            |
+                   +--------------------------+
+          rsp +  8 | condvar pointer          |
+                   +--------------------------+
+          rsp +  4 | old broadcast_seq value  |
+                   +--------------------------+
+          rsp +  0 | old cancellation mode    |
+                   +--------------------------+
+       */
+
+       cmpq    $-1, dep_mutex(%rdi)
+
+       /* Prepare structure passed to cancellation handler.  */
+       movq    %rdi, 8(%rsp)
+       movq    %rsi, 16(%rsp)
+       movq    %rdx, %r13
+
+       je      22f
+       movq    %rsi, dep_mutex(%rdi)
+
+22:
+#ifndef __ASSUME_FUTEX_CLOCK_REALTIME
+#  ifdef __PIC__
+       cmpl    $0, __have_futex_clock_realtime(%rip)
+#  else
+       cmpl    $0, __have_futex_clock_realtime
+#  endif
+       je      .Lreltmo
+#endif
+
+       /* Get internal lock.  */
+       movl    $1, %esi
+       xorl    %eax, %eax
+       LOCK
+#if cond_lock == 0
+       cmpxchgl %esi, (%rdi)
+#else
+       cmpxchgl %esi, cond_lock(%rdi)
+#endif
+       jnz     31f
+
+       /* Unlock the mutex.  */
+32:    movq    16(%rsp), %rdi
+       xorl    %esi, %esi
+       callq   __pthread_mutex_unlock_usercnt
+
+       testl   %eax, %eax
+       jne     46f
+
+       movq    8(%rsp), %rdi
+       incq    total_seq(%rdi)
+       incl    cond_futex(%rdi)
+       addl    $(1 << nwaiters_shift), cond_nwaiters(%rdi)
+
+       /* Get and store current wakeup_seq value.  */
+       movq    8(%rsp), %rdi
+       movq    wakeup_seq(%rdi), %r9
+       movl    broadcast_seq(%rdi), %edx
+       movq    %r9, 24(%rsp)
+       movl    %edx, 4(%rsp)
+
+38:    movl    cond_futex(%rdi), %r12d
+
+       /* Unlock.  */
+       LOCK
+#if cond_lock == 0
+       decl    (%rdi)
+#else
+       decl    cond_lock(%rdi)
+#endif
+       jne     33f
+
+.LcleanupSTART1:
+34:    callq   __pthread_enable_asynccancel
+       movl    %eax, (%rsp)
+
+       movq    %r13, %r10
+       movl    $FUTEX_WAIT_BITSET, %esi
+       cmpq    $-1, dep_mutex(%rdi)
+       je      60f
+
+       movq    dep_mutex(%rdi), %r8
+       /* Requeue to a non-robust PI mutex if the PI bit is set and
+       the robust bit is not set.  */
+       movl    MUTEX_KIND(%r8), %eax
+       andl    $(ROBUST_BIT|PI_BIT), %eax
+       cmpl    $PI_BIT, %eax
+       jne     61f
+
+       movl    $(FUTEX_WAIT_REQUEUE_PI|FUTEX_PRIVATE_FLAG), %esi
+       xorl    %eax, %eax
+       /* The following only works like this because we only support
+          two clocks, represented using a single bit.  */
+       testl   $1, cond_nwaiters(%rdi)
+       movl    $FUTEX_CLOCK_REALTIME, %edx
+       cmove   %edx, %eax
+       orl     %eax, %esi
+       movq    %r12, %rdx
+       addq    $cond_futex, %rdi
+       movl    $SYS_futex, %eax
+       syscall
+
+       movl    $1, %r15d
+#ifdef __ASSUME_REQUEUE_PI
+       jmp     62f
+#else
+       cmpq    $-4095, %rax
+       jnae    62f
+
+       subq    $cond_futex, %rdi
+#endif
+
+61:    movl    $(FUTEX_WAIT_BITSET|FUTEX_PRIVATE_FLAG), %esi
+60:    xorl    %r15d, %r15d
+       xorl    %eax, %eax
+       /* The following only works like this because we only support
+          two clocks, represented using a single bit.  */
+       testl   $1, cond_nwaiters(%rdi)
+       movl    $FUTEX_CLOCK_REALTIME, %edx
+       movl    $0xffffffff, %r9d
+       cmove   %edx, %eax
+       orl     %eax, %esi
+       movq    %r12, %rdx
+       addq    $cond_futex, %rdi
+       movl    $SYS_futex, %eax
+       syscall
+62:    movq    %rax, %r14
+
+       movl    (%rsp), %edi
+       callq   __pthread_disable_asynccancel
+.LcleanupEND1:
+
+       /* Lock.  */
+       movq    8(%rsp), %rdi
+       movl    $1, %esi
+       xorl    %eax, %eax
+       LOCK
+#if cond_lock == 0
+       cmpxchgl %esi, (%rdi)
+#else
+       cmpxchgl %esi, cond_lock(%rdi)
+#endif
+       jne     35f
+
+36:    movl    broadcast_seq(%rdi), %edx
+
+       movq    woken_seq(%rdi), %rax
+
+       movq    wakeup_seq(%rdi), %r9
+
+       cmpl    4(%rsp), %edx
+       jne     53f
+
+       cmpq    24(%rsp), %r9
+       jbe     45f
+
+       cmpq    %rax, %r9
+       ja      39f
+
+45:    cmpq    $-ETIMEDOUT, %r14
+       jne     38b
+
+99:    incq    wakeup_seq(%rdi)
+       incl    cond_futex(%rdi)
+       movl    $ETIMEDOUT, %r14d
+       jmp     44f
+
+53:    xorq    %r14, %r14
+       jmp     54f
+
+39:    xorq    %r14, %r14
+44:    incq    woken_seq(%rdi)
+
+54:    subl    $(1 << nwaiters_shift), cond_nwaiters(%rdi)
+
+       /* Wake up a thread which wants to destroy the condvar object.  */
+       cmpq    $0xffffffffffffffff, total_seq(%rdi)
+       jne     55f
+       movl    cond_nwaiters(%rdi), %eax
+       andl    $~((1 << nwaiters_shift) - 1), %eax
+       jne     55f
+
+       addq    $cond_nwaiters, %rdi
+       cmpq    $-1, dep_mutex-cond_nwaiters(%rdi)
+       movl    $1, %edx
+#ifdef __ASSUME_PRIVATE_FUTEX
+       movl    $FUTEX_WAKE, %eax
+       movl    $(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), %esi
+       cmove   %eax, %esi
+#else
+       movl    $0, %eax
+       movl    %fs:PRIVATE_FUTEX, %esi
+       cmove   %eax, %esi
+       orl     $FUTEX_WAKE, %esi
+#endif
+       movl    $SYS_futex, %eax
+       syscall
+       subq    $cond_nwaiters, %rdi
+
+55:    LOCK
+#if cond_lock == 0
+       decl    (%rdi)
+#else
+       decl    cond_lock(%rdi)
+#endif
+       jne     40f
+
+       /* If requeue_pi is used the kernel performs the locking of the
+          mutex. */
+41:    movq    16(%rsp), %rdi
+       testl   %r15d, %r15d
+       jnz     64f
+
+       callq   __pthread_mutex_cond_lock
+
+63:    testq   %rax, %rax
+       cmoveq  %r14, %rax
+
+48:    addq    $FRAME_SIZE, %rsp
+       cfi_adjust_cfa_offset(-FRAME_SIZE)
+       popq    %r15
+       cfi_adjust_cfa_offset(-8)
+       cfi_restore(%r15)
+       popq    %r14
+       cfi_adjust_cfa_offset(-8)
+       cfi_restore(%r14)
+       popq    %r13
+       cfi_adjust_cfa_offset(-8)
+       cfi_restore(%r13)
+       popq    %r12
+       cfi_adjust_cfa_offset(-8)
+       cfi_restore(%r12)
+
+       retq
+
+       cfi_restore_state
+
+64:    callq   __pthread_mutex_cond_lock_adjust
+       movq    %r14, %rax
+       jmp     48b
+
+       /* Initial locking failed.  */
+31:
+#if cond_lock != 0
+       addq    $cond_lock, %rdi
+#endif
+       cmpq    $-1, dep_mutex-cond_lock(%rdi)
+       movl    $LLL_PRIVATE, %eax
+       movl    $LLL_SHARED, %esi
+       cmovne  %eax, %esi
+       callq   __lll_lock_wait
+       jmp     32b
+
+       /* Unlock in loop requires wakeup.  */
+33:
+#if cond_lock != 0
+       addq    $cond_lock, %rdi
+#endif
+       cmpq    $-1, dep_mutex-cond_lock(%rdi)
+       movl    $LLL_PRIVATE, %eax
+       movl    $LLL_SHARED, %esi
+       cmovne  %eax, %esi
+       callq   __lll_unlock_wake
+       jmp     34b
+
+       /* Locking in loop failed.  */
+35:
+#if cond_lock != 0
+       addq    $cond_lock, %rdi
+#endif
+       cmpq    $-1, dep_mutex-cond_lock(%rdi)
+       movl    $LLL_PRIVATE, %eax
+       movl    $LLL_SHARED, %esi
+       cmovne  %eax, %esi
+       callq   __lll_lock_wait
+#if cond_lock != 0
+       subq    $cond_lock, %rdi
+#endif
+       jmp     36b
+
+       /* Unlock after loop requires wakeup.  */
+40:
+#if cond_lock != 0
+       addq    $cond_lock, %rdi
+#endif
+       cmpq    $-1, dep_mutex-cond_lock(%rdi)
+       movl    $LLL_PRIVATE, %eax
+       movl    $LLL_SHARED, %esi
+       cmovne  %eax, %esi
+       callq   __lll_unlock_wake
+       jmp     41b
+
+       /* The initial unlocking of the mutex failed.  */
+46:    movq    8(%rsp), %rdi
+       movq    %rax, (%rsp)
+       LOCK
+#if cond_lock == 0
+       decl    (%rdi)
+#else
+       decl    cond_lock(%rdi)
+#endif
+       jne     47f
+
+#if cond_lock != 0
+       addq    $cond_lock, %rdi
+#endif
+       cmpq    $-1, dep_mutex-cond_lock(%rdi)
+       movl    $LLL_PRIVATE, %eax
+       movl    $LLL_SHARED, %esi
+       cmovne  %eax, %esi
+       callq   __lll_unlock_wake
+
+47:    movq    (%rsp), %rax
+       jmp     48b
+
+
+#ifndef __ASSUME_FUTEX_CLOCK_REALTIME
+.Lreltmo:
+       xorl    %r15d, %r15d
+
+       /* Get internal lock.  */
+       movl    $1, %esi
+       xorl    %eax, %eax
+       LOCK
+# if cond_lock == 0
+       cmpxchgl %esi, (%rdi)
+# else
+       cmpxchgl %esi, cond_lock(%rdi)
+# endif
+       jnz     1f
+
+       /* Unlock the mutex.  */
+2:     movq    16(%rsp), %rdi
+       xorl    %esi, %esi
+       callq   __pthread_mutex_unlock_usercnt
+
+       testl   %eax, %eax
+       jne     46b
+
+       movq    8(%rsp), %rdi
+       incq    total_seq(%rdi)
+       incl    cond_futex(%rdi)
+       addl    $(1 << nwaiters_shift), cond_nwaiters(%rdi)
+
+       /* Get and store current wakeup_seq value.  */
+       movq    8(%rsp), %rdi
+       movq    wakeup_seq(%rdi), %r9
+       movl    broadcast_seq(%rdi), %edx
+       movq    %r9, 24(%rsp)
+       movl    %edx, 4(%rsp)
+
+       /* Get the current time.  */
+8:
+# ifdef __NR_clock_gettime
+       /* Get the clock number.  Note that the field in the condvar
+          structure stores the number minus 1.  */
+       movq    8(%rsp), %rdi
+       movl    cond_nwaiters(%rdi), %edi
+       andl    $((1 << nwaiters_shift) - 1), %edi
+       /* Only clocks 0 and 1 are allowed so far.  Both are handled in the
+          kernel.  */
+       leaq    32(%rsp), %rsi
+#  ifdef SHARED
+       movq    __vdso_clock_gettime@GOTPCREL(%rip), %rax
+       movq    (%rax), %rax
+       PTR_DEMANGLE (%rax)
+       jz      26f
+       call    *%rax
+       jmp     27f
+#  endif
+26:    movl    $__NR_clock_gettime, %eax
+       syscall
+27:
+#  ifndef __ASSUME_POSIX_TIMERS
+       cmpq    $-ENOSYS, %rax
+       je      19f
+#  endif
+
+       /* Compute relative timeout.  */
+       movq    (%r13), %rcx
+       movq    8(%r13), %rdx
+       subq    32(%rsp), %rcx
+       subq    40(%rsp), %rdx
+# else
+       leaq    24(%rsp), %rdi
+       xorl    %esi, %esi
+       movq    $VSYSCALL_ADDR_vgettimeofday, %rax
+       callq   *%rax
+
+       /* Compute relative timeout.  */
+       movq    40(%rsp), %rax
+       movl    $1000, %edx
+       mul     %rdx            /* Milli seconds to nano seconds.  */
+       movq    (%r13), %rcx
+       movq    8(%r13), %rdx
+       subq    32(%rsp), %rcx
+       subq    %rax, %rdx
+# endif
+       jns     12f
+       addq    $1000000000, %rdx
+       decq    %rcx
+12:    testq   %rcx, %rcx
+       movq    8(%rsp), %rdi
+       movq    $-ETIMEDOUT, %r14
+       js      6f
+
+       /* Store relative timeout.  */
+21:    movq    %rcx, 32(%rsp)
+       movq    %rdx, 40(%rsp)
+
+       movl    cond_futex(%rdi), %r12d
+
+       /* Unlock.  */
+       LOCK
+# if cond_lock == 0
+       decl    (%rdi)
+# else
+       decl    cond_lock(%rdi)
+# endif
+       jne     3f
+
+.LcleanupSTART2:
+4:     callq   __pthread_enable_asynccancel
+       movl    %eax, (%rsp)
+
+       leaq    32(%rsp), %r10
+       cmpq    $-1, dep_mutex(%rdi)
+       movq    %r12, %rdx
+# ifdef __ASSUME_PRIVATE_FUTEX
+       movl    $FUTEX_WAIT, %eax
+       movl    $(FUTEX_WAIT|FUTEX_PRIVATE_FLAG), %esi
+       cmove   %eax, %esi
+# else
+       movl    $0, %eax
+       movl    %fs:PRIVATE_FUTEX, %esi
+       cmove   %eax, %esi
+#  if FUTEX_WAIT != 0
+       orl     $FUTEX_WAIT, %esi
+#  endif
+# endif
+       addq    $cond_futex, %rdi
+       movl    $SYS_futex, %eax
+       syscall
+       movq    %rax, %r14
+
+       movl    (%rsp), %edi
+       callq   __pthread_disable_asynccancel
+.LcleanupEND2:
+
+       /* Lock.  */
+       movq    8(%rsp), %rdi
+       movl    $1, %esi
+       xorl    %eax, %eax
+       LOCK
+# if cond_lock == 0
+       cmpxchgl %esi, (%rdi)
+# else
+       cmpxchgl %esi, cond_lock(%rdi)
+# endif
+       jne     5f
+
+6:     movl    broadcast_seq(%rdi), %edx
+
+       movq    woken_seq(%rdi), %rax
+
+       movq    wakeup_seq(%rdi), %r9
+
+       cmpl    4(%rsp), %edx
+       jne     53b
+
+       cmpq    24(%rsp), %r9
+       jbe     15f
+
+       cmpq    %rax, %r9
+       ja      39b
+
+15:    cmpq    $-ETIMEDOUT, %r14
+       jne     8b
+
+       jmp     99b
+
+       /* Initial locking failed.  */
+1:
+# if cond_lock != 0
+       addq    $cond_lock, %rdi
+# endif
+       cmpq    $-1, dep_mutex-cond_lock(%rdi)
+       movl    $LLL_PRIVATE, %eax
+       movl    $LLL_SHARED, %esi
+       cmovne  %eax, %esi
+       callq   __lll_lock_wait
+       jmp     2b
+
+       /* Unlock in loop requires wakeup.  */
+3:
+# if cond_lock != 0
+       addq    $cond_lock, %rdi
+# endif
+       cmpq    $-1, dep_mutex-cond_lock(%rdi)
+       movl    $LLL_PRIVATE, %eax
+       movl    $LLL_SHARED, %esi
+       cmovne  %eax, %esi
+       callq   __lll_unlock_wake
+       jmp     4b
+
+       /* Locking in loop failed.  */
+5:
+# if cond_lock != 0
+       addq    $cond_lock, %rdi
+# endif
+       cmpq    $-1, dep_mutex-cond_lock(%rdi)
+       movl    $LLL_PRIVATE, %eax
+       movl    $LLL_SHARED, %esi
+       cmovne  %eax, %esi
+       callq   __lll_lock_wait
+# if cond_lock != 0
+       subq    $cond_lock, %rdi
+# endif
+       jmp     6b
+
+# if defined __NR_clock_gettime && !defined __ASSUME_POSIX_TIMERS
+       /* clock_gettime not available.  */
+19:    leaq    32(%rsp), %rdi
+       xorl    %esi, %esi
+       movq    $VSYSCALL_ADDR_vgettimeofday, %rax
+       callq   *%rax
+
+       /* Compute relative timeout.  */
+       movq    40(%rsp), %rax
+       movl    $1000, %edx
+       mul     %rdx            /* Milli seconds to nano seconds.  */
+       movq    (%r13), %rcx
+       movq    8(%r13), %rdx
+       subq    32(%rsp), %rcx
+       subq    %rax, %rdx
+       jns     20f
+       addq    $1000000000, %rdx
+       decq    %rcx
+20:    testq   %rcx, %rcx
+       movq    8(%rsp), %rdi
+       movq    $-ETIMEDOUT, %r14
+       js      6b
+       jmp     21b
+# endif
+#endif
+       .size   __pthread_cond_timedwait, .-__pthread_cond_timedwait
+weak_alias(__pthread_cond_timedwait, pthread_cond_timedwait)
+
+
+       .align  16
+       .type   __condvar_cleanup2, @function
+__condvar_cleanup2:
+       /* Stack frame:
+
+          rsp + 72
+                   +--------------------------+
+          rsp + 64 | %r12                     |
+                   +--------------------------+
+          rsp + 56 | %r13                     |
+                   +--------------------------+
+          rsp + 48 | %r14                     |
+                   +--------------------------+
+          rsp + 24 | unused                   |
+                   +--------------------------+
+          rsp + 16 | mutex pointer            |
+                   +--------------------------+
+          rsp +  8 | condvar pointer          |
+                   +--------------------------+
+          rsp +  4 | old broadcast_seq value  |
+                   +--------------------------+
+          rsp +  0 | old cancellation mode    |
+                   +--------------------------+
+       */
+
+       movq    %rax, 24(%rsp)
+
+       /* Get internal lock.  */
+       movq    8(%rsp), %rdi
+       movl    $1, %esi
+       xorl    %eax, %eax
+       LOCK
+#if cond_lock == 0
+       cmpxchgl %esi, (%rdi)
+#else
+       cmpxchgl %esi, cond_lock(%rdi)
+#endif
+       jz      1f
+
+#if cond_lock != 0
+       addq    $cond_lock, %rdi
+#endif
+       cmpq    $-1, dep_mutex-cond_lock(%rdi)
+       movl    $LLL_PRIVATE, %eax
+       movl    $LLL_SHARED, %esi
+       cmovne  %eax, %esi
+       callq   __lll_lock_wait
+#if cond_lock != 0
+       subq    $cond_lock, %rdi
+#endif
+
+1:     movl    broadcast_seq(%rdi), %edx
+       cmpl    4(%rsp), %edx
+       jne     3f
+
+       /* We increment the wakeup_seq counter only if it is lower than
+          total_seq.  If this is not the case the thread was woken and
+          then canceled.  In this case we ignore the signal.  */
+       movq    total_seq(%rdi), %rax
+       cmpq    wakeup_seq(%rdi), %rax
+       jbe     6f
+       incq    wakeup_seq(%rdi)
+       incl    cond_futex(%rdi)
+6:     incq    woken_seq(%rdi)
+
+3:     subl    $(1 << nwaiters_shift), cond_nwaiters(%rdi)
+
+       /* Wake up a thread which wants to destroy the condvar object.  */
+       xorq    %r12, %r12
+       cmpq    $0xffffffffffffffff, total_seq(%rdi)
+       jne     4f
+       movl    cond_nwaiters(%rdi), %eax
+       andl    $~((1 << nwaiters_shift) - 1), %eax
+       jne     4f
+
+       cmpq    $-1, dep_mutex(%rdi)
+       leaq    cond_nwaiters(%rdi), %rdi
+       movl    $1, %edx
+#ifdef __ASSUME_PRIVATE_FUTEX
+       movl    $FUTEX_WAKE, %eax
+       movl    $(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), %esi
+       cmove   %eax, %esi
+#else
+       movl    $0, %eax
+       movl    %fs:PRIVATE_FUTEX, %esi
+       cmove   %eax, %esi
+       orl     $FUTEX_WAKE, %esi
+#endif
+       movl    $SYS_futex, %eax
+       syscall
+       subq    $cond_nwaiters, %rdi
+       movl    $1, %r12d
+
+4:     LOCK
+#if cond_lock == 0
+       decl    (%rdi)
+#else
+       decl    cond_lock(%rdi)
+#endif
+       je      2f
+#if cond_lock != 0
+       addq    $cond_lock, %rdi
+#endif
+       cmpq    $-1, dep_mutex-cond_lock(%rdi)
+       movl    $LLL_PRIVATE, %eax
+       movl    $LLL_SHARED, %esi
+       cmovne  %eax, %esi
+       callq   __lll_unlock_wake
+
+       /* Wake up all waiters to make sure no signal gets lost.  */
+2:     testq   %r12, %r12
+       jnz     5f
+       addq    $cond_futex, %rdi
+       cmpq    $-1, dep_mutex-cond_futex(%rdi)
+       movl    $0x7fffffff, %edx
+#ifdef __ASSUME_PRIVATE_FUTEX
+       movl    $FUTEX_WAKE, %eax
+       movl    $(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), %esi
+       cmove   %eax, %esi
+#else
+       movl    $0, %eax
+       movl    %fs:PRIVATE_FUTEX, %esi
+       cmove   %eax, %esi
+       orl     $FUTEX_WAKE, %esi
+#endif
+       movl    $SYS_futex, %eax
+       syscall
+
+5:     movq    16(%rsp), %rdi
+       callq   __pthread_mutex_cond_lock
+
+       movq    24(%rsp), %rdi
+       movq    FRAME_SIZE(%rsp), %r15
+       movq    FRAME_SIZE+8(%rsp), %r14
+       movq    FRAME_SIZE+16(%rsp), %r13
+       movq    FRAME_SIZE+24(%rsp), %r12
+.LcallUR:
+       call    _Unwind_Resume@PLT
+       hlt
+.LENDCODE:
+       cfi_endproc
+       .size   __condvar_cleanup2, .-__condvar_cleanup2
+
+
+       .section .gcc_except_table,"a",@progbits
+.LexceptSTART:
+       .byte   DW_EH_PE_omit                   # @LPStart format
+       .byte   DW_EH_PE_omit                   # @TType format
+       .byte   DW_EH_PE_uleb128                # call-site format
+       .uleb128 .Lcstend-.Lcstbegin
+.Lcstbegin:
+       .uleb128 .LcleanupSTART1-.LSTARTCODE
+       .uleb128 .LcleanupEND1-.LcleanupSTART1
+       .uleb128 __condvar_cleanup2-.LSTARTCODE
+       .uleb128  0
+#ifndef __ASSUME_FUTEX_CLOCK_REALTIME
+       .uleb128 .LcleanupSTART2-.LSTARTCODE
+       .uleb128 .LcleanupEND2-.LcleanupSTART2
+       .uleb128 __condvar_cleanup2-.LSTARTCODE
+       .uleb128  0
+#endif
+       .uleb128 .LcallUR-.LSTARTCODE
+       .uleb128 .LENDCODE-.LcallUR
+       .uleb128 0
+       .uleb128  0
+.Lcstend:
+
+
+#ifdef SHARED
+       .hidden DW.ref.__gcc_personality_v0
+       .weak   DW.ref.__gcc_personality_v0
+       .section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits
+       .align  8
+       .type   DW.ref.__gcc_personality_v0, @object
+       .size   DW.ref.__gcc_personality_v0, 8
+DW.ref.__gcc_personality_v0:
+       .quad   __gcc_personality_v0
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S
new file mode 100644 (file)
index 0000000..a44e7a7
--- /dev/null
@@ -0,0 +1,486 @@
+/* Copyright (C) 2002-2007, 2009 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <lowlevelcond.h>
+#include <tcb-offsets.h>
+#include <pthread-pi-defines.h>
+
+#include <bits/kernel-features.h>
+
+
+       .text
+
+/* int pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex)  */
+       .globl  __pthread_cond_wait
+       .type   __pthread_cond_wait, @function
+       .align  16
+__pthread_cond_wait:
+.LSTARTCODE:
+       cfi_startproc
+
+#define FRAME_SIZE 32
+       leaq    -FRAME_SIZE(%rsp), %rsp
+       cfi_adjust_cfa_offset(FRAME_SIZE)
+
+       /* Stack frame:
+
+          rsp + 32
+                   +--------------------------+
+          rsp + 24 | old wake_seq value       |
+                   +--------------------------+
+          rsp + 16 | mutex pointer            |
+                   +--------------------------+
+          rsp +  8 | condvar pointer          |
+                   +--------------------------+
+          rsp +  4 | old broadcast_seq value  |
+                   +--------------------------+
+          rsp +  0 | old cancellation mode    |
+                   +--------------------------+
+       */
+
+       cmpq    $-1, dep_mutex(%rdi)
+
+               /* Prepare structure passed to cancellation handler.  */
+       movq    %rdi, 8(%rsp)
+       movq    %rsi, 16(%rsp)
+
+       je      15f
+       movq    %rsi, dep_mutex(%rdi)
+
+       /* Get internal lock.  */
+15:    movl    $1, %esi
+       xorl    %eax, %eax
+       LOCK
+#if cond_lock == 0
+       cmpxchgl %esi, (%rdi)
+#else
+       cmpxchgl %esi, cond_lock(%rdi)
+#endif
+       jne     1f
+
+       /* Unlock the mutex.  */
+2:     movq    16(%rsp), %rdi
+       xorl    %esi, %esi
+       callq   __pthread_mutex_unlock_usercnt
+
+       testl   %eax, %eax
+       jne     12f
+
+       movq    8(%rsp), %rdi
+       incq    total_seq(%rdi)
+       incl    cond_futex(%rdi)
+       addl    $(1 << nwaiters_shift), cond_nwaiters(%rdi)
+
+       /* Get and store current wakeup_seq value.  */
+       movq    8(%rsp), %rdi
+       movq    wakeup_seq(%rdi), %r9
+       movl    broadcast_seq(%rdi), %edx
+       movq    %r9, 24(%rsp)
+       movl    %edx, 4(%rsp)
+
+       /* Unlock.  */
+8:     movl    cond_futex(%rdi), %edx
+       LOCK
+#if cond_lock == 0
+       decl    (%rdi)
+#else
+       decl    cond_lock(%rdi)
+#endif
+       jne     3f
+
+.LcleanupSTART:
+4:     callq   __pthread_enable_asynccancel
+       movl    %eax, (%rsp)
+
+       xorq    %r10, %r10
+       cmpq    $-1, dep_mutex(%rdi)
+       leaq    cond_futex(%rdi), %rdi
+       movl    $FUTEX_WAIT, %esi
+       je      60f
+
+       movq    dep_mutex-cond_futex(%rdi), %r8
+       /* Requeue to a non-robust PI mutex if the PI bit is set and
+       the robust bit is not set.  */
+       movl    MUTEX_KIND(%r8), %eax
+       andl    $(ROBUST_BIT|PI_BIT), %eax
+       cmpl    $PI_BIT, %eax
+       jne     61f
+
+       movl    $(FUTEX_WAIT_REQUEUE_PI|FUTEX_PRIVATE_FLAG), %esi
+       movl    $SYS_futex, %eax
+       syscall
+
+       movl    $1, %r8d
+#ifdef __ASSUME_REQUEUE_PI
+       jmp     62f
+#else
+       cmpq    $-4095, %rax
+       jnae    62f
+
+# ifndef __ASSUME_PRIVATE_FUTEX
+       movl    $FUTEX_WAIT, %esi
+# endif
+#endif
+
+61:
+#ifdef __ASSUME_PRIVATE_FUTEX
+       movl    $(FUTEX_WAIT|FUTEX_PRIVATE_FLAG), %esi
+#else
+       orl     %fs:PRIVATE_FUTEX, %esi
+#endif
+60:    xorl    %r8d, %r8d
+       movl    $SYS_futex, %eax
+       syscall
+
+62:    movl    (%rsp), %edi
+       callq   __pthread_disable_asynccancel
+.LcleanupEND:
+
+       /* Lock.  */
+       movq    8(%rsp), %rdi
+       movl    $1, %esi
+       xorl    %eax, %eax
+       LOCK
+#if cond_lock == 0
+       cmpxchgl %esi, (%rdi)
+#else
+       cmpxchgl %esi, cond_lock(%rdi)
+#endif
+       jnz     5f
+
+6:     movl    broadcast_seq(%rdi), %edx
+
+       movq    woken_seq(%rdi), %rax
+
+       movq    wakeup_seq(%rdi), %r9
+
+       cmpl    4(%rsp), %edx
+       jne     16f
+
+       cmpq    24(%rsp), %r9
+       jbe     8b
+
+       cmpq    %rax, %r9
+       jna     8b
+
+       incq    woken_seq(%rdi)
+
+       /* Unlock */
+16:    subl    $(1 << nwaiters_shift), cond_nwaiters(%rdi)
+
+       /* Wake up a thread which wants to destroy the condvar object.  */
+       cmpq    $0xffffffffffffffff, total_seq(%rdi)
+       jne     17f
+       movl    cond_nwaiters(%rdi), %eax
+       andl    $~((1 << nwaiters_shift) - 1), %eax
+       jne     17f
+
+       addq    $cond_nwaiters, %rdi
+       cmpq    $-1, dep_mutex-cond_nwaiters(%rdi)
+       movl    $1, %edx
+#ifdef __ASSUME_PRIVATE_FUTEX
+       movl    $FUTEX_WAKE, %eax
+       movl    $(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), %esi
+       cmove   %eax, %esi
+#else
+       movl    $0, %eax
+       movl    %fs:PRIVATE_FUTEX, %esi
+       cmove   %eax, %esi
+       orl     $FUTEX_WAKE, %esi
+#endif
+       movl    $SYS_futex, %eax
+       syscall
+       subq    $cond_nwaiters, %rdi
+
+17:    LOCK
+#if cond_lock == 0
+       decl    (%rdi)
+#else
+       decl    cond_lock(%rdi)
+#endif
+       jne     10f
+
+       /* If requeue_pi is used the kernel performs the locking of the
+          mutex. */
+11:    movq    16(%rsp), %rdi
+       testl   %r8d, %r8d
+       jnz     18f
+
+       callq   __pthread_mutex_cond_lock
+
+14:    leaq    FRAME_SIZE(%rsp), %rsp
+       cfi_adjust_cfa_offset(-FRAME_SIZE)
+
+       /* We return the result of the mutex_lock operation.  */
+       retq
+
+       cfi_adjust_cfa_offset(FRAME_SIZE)
+
+18:    callq   __pthread_mutex_cond_lock_adjust
+       xorl    %eax, %eax
+       jmp     14b
+
+       /* Initial locking failed.  */
+1:
+#if cond_lock != 0
+       addq    $cond_lock, %rdi
+#endif
+       cmpq    $-1, dep_mutex-cond_lock(%rdi)
+       movl    $LLL_PRIVATE, %eax
+       movl    $LLL_SHARED, %esi
+       cmovne  %eax, %esi
+       callq   __lll_lock_wait
+       jmp     2b
+
+       /* Unlock in loop requires wakeup.  */
+3:
+#if cond_lock != 0
+       addq    $cond_lock, %rdi
+#endif
+       cmpq    $-1, dep_mutex-cond_lock(%rdi)
+       movl    $LLL_PRIVATE, %eax
+       movl    $LLL_SHARED, %esi
+       cmovne  %eax, %esi
+       /* The call preserves %rdx.  */
+       callq   __lll_unlock_wake
+#if cond_lock != 0
+       subq    $cond_lock, %rdi
+#endif
+       jmp     4b
+
+       /* Locking in loop failed.  */
+5:
+#if cond_lock != 0
+       addq    $cond_lock, %rdi
+#endif
+       cmpq    $-1, dep_mutex-cond_lock(%rdi)
+       movl    $LLL_PRIVATE, %eax
+       movl    $LLL_SHARED, %esi
+       cmovne  %eax, %esi
+       callq   __lll_lock_wait
+#if cond_lock != 0
+       subq    $cond_lock, %rdi
+#endif
+       jmp     6b
+
+       /* Unlock after loop requires wakeup.  */
+10:
+#if cond_lock != 0
+       addq    $cond_lock, %rdi
+#endif
+       cmpq    $-1, dep_mutex-cond_lock(%rdi)
+       movl    $LLL_PRIVATE, %eax
+       movl    $LLL_SHARED, %esi
+       cmovne  %eax, %esi
+       callq   __lll_unlock_wake
+       jmp     11b
+
+       /* The initial unlocking of the mutex failed.  */
+12:    movq    %rax, %r10
+       movq    8(%rsp), %rdi
+       LOCK
+#if cond_lock == 0
+       decl    (%rdi)
+#else
+       decl    cond_lock(%rdi)
+#endif
+       je      13f
+
+#if cond_lock != 0
+       addq    $cond_lock, %rdi
+#endif
+       cmpq    $-1, dep_mutex-cond_lock(%rdi)
+       movl    $LLL_PRIVATE, %eax
+       movl    $LLL_SHARED, %esi
+       cmovne  %eax, %esi
+       callq   __lll_unlock_wake
+
+13:    movq    %r10, %rax
+       jmp     14b
+       .size   __pthread_cond_wait, .-__pthread_cond_wait
+weak_alias(__pthread_cond_wait, pthread_cond_wait)
+
+
+       .align  16
+       .type   __condvar_cleanup1, @function
+       .globl  __condvar_cleanup1
+       .hidden __condvar_cleanup1
+__condvar_cleanup1:
+       /* Stack frame:
+
+          rsp + 32
+                   +--------------------------+
+          rsp + 24 | unused                   |
+                   +--------------------------+
+          rsp + 16 | mutex pointer            |
+                   +--------------------------+
+          rsp +  8 | condvar pointer          |
+                   +--------------------------+
+          rsp +  4 | old broadcast_seq value  |
+                   +--------------------------+
+          rsp +  0 | old cancellation mode    |
+                   +--------------------------+
+       */
+
+       movq    %rax, 24(%rsp)
+
+       /* Get internal lock.  */
+       movq    8(%rsp), %rdi
+       movl    $1, %esi
+       xorl    %eax, %eax
+       LOCK
+#if cond_lock == 0
+       cmpxchgl %esi, (%rdi)
+#else
+       cmpxchgl %esi, cond_lock(%rdi)
+#endif
+       jz      1f
+
+#if cond_lock != 0
+       addq    $cond_lock, %rdi
+#endif
+       cmpq    $-1, dep_mutex-cond_lock(%rdi)
+       movl    $LLL_PRIVATE, %eax
+       movl    $LLL_SHARED, %esi
+       cmovne  %eax, %esi
+       callq   __lll_lock_wait
+#if cond_lock != 0
+       subq    $cond_lock, %rdi
+#endif
+
+1:     movl    broadcast_seq(%rdi), %edx
+       cmpl    4(%rsp), %edx
+       jne     3f
+
+       /* We increment the wakeup_seq counter only if it is lower than
+          total_seq.  If this is not the case the thread was woken and
+          then canceled.  In this case we ignore the signal.  */
+       movq    total_seq(%rdi), %rax
+       cmpq    wakeup_seq(%rdi), %rax
+       jbe     6f
+       incq    wakeup_seq(%rdi)
+       incl    cond_futex(%rdi)
+6:     incq    woken_seq(%rdi)
+
+3:     subl    $(1 << nwaiters_shift), cond_nwaiters(%rdi)
+
+       /* Wake up a thread which wants to destroy the condvar object.  */
+       xorl    %ecx, %ecx
+       cmpq    $0xffffffffffffffff, total_seq(%rdi)
+       jne     4f
+       movl    cond_nwaiters(%rdi), %eax
+       andl    $~((1 << nwaiters_shift) - 1), %eax
+       jne     4f
+
+       cmpq    $-1, dep_mutex(%rdi)
+       leaq    cond_nwaiters(%rdi), %rdi
+       movl    $1, %edx
+#ifdef __ASSUME_PRIVATE_FUTEX
+       movl    $FUTEX_WAKE, %eax
+       movl    $(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), %esi
+       cmove   %eax, %esi
+#else
+       movl    $0, %eax
+       movl    %fs:PRIVATE_FUTEX, %esi
+       cmove   %eax, %esi
+       orl     $FUTEX_WAKE, %esi
+#endif
+       movl    $SYS_futex, %eax
+       syscall
+       subq    $cond_nwaiters, %rdi
+       movl    $1, %ecx
+
+4:     LOCK
+#if cond_lock == 0
+       decl    (%rdi)
+#else
+       decl    cond_lock(%rdi)
+#endif
+       je      2f
+#if cond_lock != 0
+       addq    $cond_lock, %rdi
+#endif
+       cmpq    $-1, dep_mutex-cond_lock(%rdi)
+       movl    $LLL_PRIVATE, %eax
+       movl    $LLL_SHARED, %esi
+       cmovne  %eax, %esi
+       /* The call preserves %rcx.  */
+       callq   __lll_unlock_wake
+
+       /* Wake up all waiters to make sure no signal gets lost.  */
+2:     testl   %ecx, %ecx
+       jnz     5f
+       addq    $cond_futex, %rdi
+       cmpq    $-1, dep_mutex-cond_futex(%rdi)
+       movl    $0x7fffffff, %edx
+#ifdef __ASSUME_PRIVATE_FUTEX
+       movl    $FUTEX_WAKE, %eax
+       movl    $(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), %esi
+       cmove   %eax, %esi
+#else
+       movl    $0, %eax
+       movl    %fs:PRIVATE_FUTEX, %esi
+       cmove   %eax, %esi
+       orl     $FUTEX_WAKE, %esi
+#endif
+       movl    $SYS_futex, %eax
+       syscall
+
+5:     movq    16(%rsp), %rdi
+       callq   __pthread_mutex_cond_lock
+
+       movq    24(%rsp), %rdi
+.LcallUR:
+       call    _Unwind_Resume@PLT
+       hlt
+.LENDCODE:
+       cfi_endproc
+       .size   __condvar_cleanup1, .-__condvar_cleanup1
+
+
+       .section .gcc_except_table,"a",@progbits
+.LexceptSTART:
+       .byte   DW_EH_PE_omit                   # @LPStart format
+       .byte   DW_EH_PE_omit                   # @TType format
+       .byte   DW_EH_PE_uleb128                # call-site format
+       .uleb128 .Lcstend-.Lcstbegin
+.Lcstbegin:
+       .uleb128 .LcleanupSTART-.LSTARTCODE
+       .uleb128 .LcleanupEND-.LcleanupSTART
+       .uleb128 __condvar_cleanup1-.LSTARTCODE
+       .uleb128  0
+       .uleb128 .LcallUR-.LSTARTCODE
+       .uleb128 .LENDCODE-.LcallUR
+       .uleb128 0
+       .uleb128  0
+.Lcstend:
+
+
+#ifdef SHARED
+       .hidden DW.ref.__gcc_personality_v0
+       .weak   DW.ref.__gcc_personality_v0
+       .section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits
+       .align  8
+       .type   DW.ref.__gcc_personality_v0, @object
+       .size   DW.ref.__gcc_personality_v0, 8
+DW.ref.__gcc_personality_v0:
+       .quad   __gcc_personality_v0
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_once.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_once.S
new file mode 100644 (file)
index 0000000..a808b9d
--- /dev/null
@@ -0,0 +1,189 @@
+/* Copyright (C) 2002, 2003, 2005, 2007, 2009 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <bits/kernel-features.h>
+#include <tcb-offsets.h>
+#include <lowlevellock.h>
+
+
+       .comm   __fork_generation, 4, 4
+
+       .text
+
+
+       .globl  __pthread_once
+       .type   __pthread_once,@function
+       .align  16
+__pthread_once:
+.LSTARTCODE:
+       cfi_startproc
+       testl   $2, (%rdi)
+       jz      1f
+       xorl    %eax, %eax
+       retq
+
+       /* Preserve the function pointer.  */
+1:     pushq   %rsi
+       cfi_adjust_cfa_offset(8)
+       xorq    %r10, %r10
+
+       /* Not yet initialized or initialization in progress.
+          Get the fork generation counter now.  */
+6:     movl    (%rdi), %eax
+
+5:     movl    %eax, %edx
+
+       testl   $2, %eax
+       jnz     4f
+
+       andl    $3, %edx
+       orl     __fork_generation(%rip), %edx
+       orl     $1, %edx
+
+       LOCK
+       cmpxchgl %edx, (%rdi)
+       jnz     5b
+
+       /* Check whether another thread already runs the initializer.  */
+       testl   $1, %eax
+       jz      3f      /* No -> do it.  */
+
+       /* Check whether the initializer execution was interrupted
+          by a fork.  */
+       xorl    %edx, %eax
+       testl   $0xfffffffc, %eax
+       jnz     3f      /* Different for generation -> run initializer.  */
+
+       /* Somebody else got here first.  Wait.  */
+#ifdef __ASSUME_PRIVATE_FUTEX
+       movl    $FUTEX_WAIT|FUTEX_PRIVATE_FLAG, %esi
+#else
+# if FUTEX_WAIT == 0
+       movl    %fs:PRIVATE_FUTEX, %esi
+# else
+       movl    $FUTEX_WAIT, %esi
+       orl     %fs:PRIVATE_FUTEX, %esi
+# endif
+#endif
+       movl    $SYS_futex, %eax
+       syscall
+       jmp     6b
+
+       /* Preserve the pointer to the control variable.  */
+3:     pushq   %rdi
+       cfi_adjust_cfa_offset(8)
+       pushq   %rdi
+       cfi_adjust_cfa_offset(8)
+
+.LcleanupSTART:
+       callq   *16(%rsp)
+.LcleanupEND:
+
+       /* Get the control variable address back.  */
+       popq    %rdi
+       cfi_adjust_cfa_offset(-8)
+
+       /* Sucessful run of the initializer.  Signal that we are done.  */
+       LOCK
+       incl    (%rdi)
+
+       addq    $8, %rsp
+       cfi_adjust_cfa_offset(-8)
+
+       /* Wake up all other threads.  */
+       movl    $0x7fffffff, %edx
+#ifdef __ASSUME_PRIVATE_FUTEX
+       movl    $FUTEX_WAKE|FUTEX_PRIVATE_FLAG, %esi
+#else
+       movl    $FUTEX_WAKE, %esi
+       orl     %fs:PRIVATE_FUTEX, %esi
+#endif
+       movl    $SYS_futex, %eax
+       syscall
+
+4:     addq    $8, %rsp
+       cfi_adjust_cfa_offset(-8)
+       xorl    %eax, %eax
+       retq
+       .size   __pthread_once,.-__pthread_once
+
+
+       .globl  __pthread_once_internal
+__pthread_once_internal = __pthread_once
+
+       .globl  pthread_once
+pthread_once = __pthread_once
+
+
+       .type   clear_once_control,@function
+       .align  16
+clear_once_control:
+       cfi_adjust_cfa_offset(3 * 8)
+       movq    (%rsp), %rdi
+       movq    %rax, %r8
+       movl    $0, (%rdi)
+
+       movl    $0x7fffffff, %edx
+#ifdef __ASSUME_PRIVATE_FUTEX
+       movl    $FUTEX_WAKE|FUTEX_PRIVATE_FLAG, %esi
+#else
+       movl    $FUTEX_WAKE, %esi
+       orl     %fs:PRIVATE_FUTEX, %esi
+#endif
+       movl    $SYS_futex, %eax
+       syscall
+
+       movq    %r8, %rdi
+.LcallUR:
+       call    _Unwind_Resume@PLT
+       hlt
+.LENDCODE:
+       cfi_endproc
+       .size   clear_once_control,.-clear_once_control
+
+
+       .section .gcc_except_table,"a",@progbits
+.LexceptSTART:
+       .byte   DW_EH_PE_omit                   # @LPStart format
+       .byte   DW_EH_PE_omit                   # @TType format
+       .byte   DW_EH_PE_uleb128                # call-site format
+       .uleb128 .Lcstend-.Lcstbegin
+.Lcstbegin:
+       .uleb128 .LcleanupSTART-.LSTARTCODE
+       .uleb128 .LcleanupEND-.LcleanupSTART
+       .uleb128 clear_once_control-.LSTARTCODE
+       .uleb128  0
+       .uleb128 .LcallUR-.LSTARTCODE
+       .uleb128 .LENDCODE-.LcallUR
+       .uleb128 0
+       .uleb128  0
+.Lcstend:
+
+
+#ifdef SHARED
+       .hidden DW.ref.__gcc_personality_v0
+       .weak   DW.ref.__gcc_personality_v0
+       .section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits
+       .align  8
+       .type   DW.ref.__gcc_personality_v0, @object
+       .size   DW.ref.__gcc_personality_v0, 8
+DW.ref.__gcc_personality_v0:
+       .quad   __gcc_personality_v0
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_rdlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_rdlock.S
new file mode 100644 (file)
index 0000000..f36e7a7
--- /dev/null
@@ -0,0 +1,179 @@
+/* Copyright (C) 2002, 2003, 2005, 2007, 2009 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <lowlevelrwlock.h>
+#include <pthread-errnos.h>
+#include <bits/kernel-features.h>
+#include <tcb-offsets.h>
+
+
+       .text
+
+       .globl  __pthread_rwlock_rdlock
+       .type   __pthread_rwlock_rdlock,@function
+       .align  16
+__pthread_rwlock_rdlock:
+       cfi_startproc
+       xorq    %r10, %r10
+
+       /* Get the lock.  */
+       movl    $1, %esi
+       xorl    %eax, %eax
+       LOCK
+#if MUTEX == 0
+       cmpxchgl %esi, (%rdi)
+#else
+       cmpxchgl %esi, MUTEX(%rdi)
+#endif
+       jnz     1f
+
+2:     movl    WRITER(%rdi), %eax
+       testl   %eax, %eax
+       jne     14f
+       cmpl    $0, WRITERS_QUEUED(%rdi)
+       je      5f
+       cmpl    $0, FLAGS(%rdi)
+       je      5f
+
+3:     incl    READERS_QUEUED(%rdi)
+       je      4f
+
+       movl    READERS_WAKEUP(%rdi), %edx
+
+       LOCK
+#if MUTEX == 0
+       decl    (%rdi)
+#else
+       decl    MUTEX(%rdi)
+#endif
+       jne     10f
+
+11:
+#ifdef __ASSUME_PRIVATE_FUTEX
+       movl    $FUTEX_PRIVATE_FLAG|FUTEX_WAIT, %esi
+       xorl    PSHARED(%rdi), %esi
+#else
+# if FUTEX_WAIT == 0
+       movl    PSHARED(%rdi), %esi
+# else
+       movl    $FUTEX_WAIT, %esi
+       orl     PSHARED(%rdi), %esi
+# endif
+       xorl    %fs:PRIVATE_FUTEX, %esi
+#endif
+       addq    $READERS_WAKEUP, %rdi
+       movl    $SYS_futex, %eax
+       syscall
+
+       subq    $READERS_WAKEUP, %rdi
+
+       /* Reget the lock.  */
+       movl    $1, %esi
+       xorl    %eax, %eax
+       LOCK
+#if MUTEX == 0
+       cmpxchgl %esi, (%rdi)
+#else
+       cmpxchgl %esi, MUTEX(%rdi)
+#endif
+       jnz     12f
+
+13:    decl    READERS_QUEUED(%rdi)
+       jmp     2b
+
+5:     xorl    %edx, %edx
+       incl    NR_READERS(%rdi)
+       je      8f
+9:     LOCK
+#if MUTEX == 0
+       decl    (%rdi)
+#else
+       decl    MUTEX(%rdi)
+#endif
+       jne     6f
+7:
+
+       movq    %rdx, %rax
+       retq
+
+1:     movl    PSHARED(%rdi), %esi
+#if MUTEX != 0
+       addq    $MUTEX, %rdi
+#endif
+       callq   __lll_lock_wait
+#if MUTEX != 0
+       subq    $MUTEX, %rdi
+#endif
+       jmp     2b
+
+14:    cmpl    %fs:TID, %eax
+       jne     3b
+       /* Deadlock detected.  */
+       movl    $EDEADLK, %edx
+       jmp     9b
+
+6:     movl    PSHARED(%rdi), %esi
+#if MUTEX != 0
+       addq    $MUTEX, %rdi
+#endif
+       callq   __lll_unlock_wake
+#if MUTEX != 0
+       subq    $MUTEX, %rdi
+#endif
+       jmp     7b
+
+       /* Overflow.  */
+8:     decl    NR_READERS(%rdi)
+       movl    $EAGAIN, %edx
+       jmp     9b
+
+       /* Overflow.  */
+4:     decl    READERS_QUEUED(%rdi)
+       movl    $EAGAIN, %edx
+       jmp     9b
+
+10:    movl    PSHARED(%rdi), %esi
+#if MUTEX != 0
+       addq    $MUTEX, %rdi
+#endif
+       callq   __lll_unlock_wake
+#if MUTEX != 0
+       subq    $MUTEX, %rdi
+#endif
+       jmp     11b
+
+12:    movl    PSHARED(%rdi), %esi
+#if MUTEX == 0
+       addq    $MUTEX, %rdi
+#endif
+       callq   __lll_lock_wait
+#if MUTEX != 0
+       subq    $MUTEX, %rdi
+#endif
+       jmp     13b
+       cfi_endproc
+       .size   __pthread_rwlock_rdlock,.-__pthread_rwlock_rdlock
+
+       .globl  pthread_rwlock_rdlock
+pthread_rwlock_rdlock = __pthread_rwlock_rdlock
+
+       .globl  __pthread_rwlock_rdlock_internal
+__pthread_rwlock_rdlock_internal = __pthread_rwlock_rdlock
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedrdlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedrdlock.S
new file mode 100644 (file)
index 0000000..3629ffb
--- /dev/null
@@ -0,0 +1,276 @@
+/* Copyright (C) 2002-2005, 2007, 2009 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <lowlevelrwlock.h>
+#include <pthread-errnos.h>
+#include <bits/kernel-features.h>
+#include <tcb-offsets.h>
+
+
+/* For the calculation see asm/vsyscall.h.  */
+#define VSYSCALL_ADDR_vgettimeofday    0xffffffffff600000
+
+       .text
+
+       .globl  pthread_rwlock_timedrdlock
+       .type   pthread_rwlock_timedrdlock,@function
+       .align  16
+pthread_rwlock_timedrdlock:
+       cfi_startproc
+       pushq   %r12
+       cfi_adjust_cfa_offset(8)
+       cfi_rel_offset(%r12, 0)
+       pushq   %r13
+       cfi_adjust_cfa_offset(8)
+       cfi_rel_offset(%r13, 0)
+#ifdef __ASSUME_FUTEX_CLOCK_REALTIME
+# define VALREG        %edx
+#else
+       pushq   %r14
+       cfi_adjust_cfa_offset(8)
+       cfi_rel_offset(%r14, 0)
+
+       subq    $16, %rsp
+       cfi_adjust_cfa_offset(16)
+# define VALREG %r14d
+#endif
+
+       movq    %rdi, %r12
+       movq    %rsi, %r13
+
+       /* Get the lock.  */
+       movl    $1, %esi
+       xorl    %eax, %eax
+       LOCK
+#if MUTEX == 0
+       cmpxchgl %esi, (%rdi)
+#else
+       cmpxchgl %esi, MUTEX(%rdi)
+#endif
+       jnz     1f
+
+2:     movl    WRITER(%r12), %eax
+       testl   %eax, %eax
+       jne     14f
+       cmpl    $0, WRITERS_QUEUED(%r12)
+       je      5f
+       cmpl    $0, FLAGS(%r12)
+       je      5f
+
+       /* Check the value of the timeout parameter.  */
+3:     cmpq    $1000000000, 8(%r13)
+       jae     19f
+
+       incl    READERS_QUEUED(%r12)
+       je      4f
+
+       movl    READERS_WAKEUP(%r12), VALREG
+
+       /* Unlock.  */
+       LOCK
+#if MUTEX == 0
+       decl    (%r12)
+#else
+       decl    MUTEX(%r12)
+#endif
+       jne     10f
+
+11:
+#ifndef __ASSUME_FUTEX_CLOCK_REALTIME
+#  ifdef __PIC__
+       cmpl    $0, __have_futex_clock_realtime(%rip)
+#  else
+       cmpl    $0, __have_futex_clock_realtime
+#  endif
+       je      .Lreltmo
+#endif
+
+       movl    $FUTEX_PRIVATE_FLAG|FUTEX_WAIT_BITSET|FUTEX_CLOCK_REALTIME, %esi
+       xorl    PSHARED(%r12), %esi
+       movq    %r13, %r10
+       movl    $0xffffffff, %r9d
+#ifndef __ASSUME_FUTEX_CLOCK_REALTIME
+       movl    %r14d, %edx
+#endif
+21:    leaq    READERS_WAKEUP(%r12), %rdi
+       movl    $SYS_futex, %eax
+       syscall
+       movq    %rax, %rdx
+
+#ifndef __ASSUME_FUTEX_CLOCK_REALTIME
+       .subsection 2
+.Lreltmo:
+       /* Get current time.  */
+       movq    %rsp, %rdi
+       xorl    %esi, %esi
+       movq    $VSYSCALL_ADDR_vgettimeofday, %rax
+       callq   *%rax
+
+       /* Compute relative timeout.  */
+       movq    8(%rsp), %rax
+       movl    $1000, %edi
+       mul     %rdi            /* Milli seconds to nano seconds.  */
+       movq    (%r13), %rcx
+       movq    8(%r13), %rdi
+       subq    (%rsp), %rcx
+       subq    %rax, %rdi
+       jns     15f
+       addq    $1000000000, %rdi
+       decq    %rcx
+15:    testq   %rcx, %rcx
+       js      16f             /* Time is already up.  */
+
+       /* Futex call.  */
+       movq    %rcx, (%rsp)    /* Store relative timeout.  */
+       movq    %rdi, 8(%rsp)
+
+# ifdef __ASSUME_PRIVATE_FUTEX
+       movl    $FUTEX_PRIVATE_FLAG|FUTEX_WAIT, %esi
+       xorl    PSHARED(%r12), %esi
+# else
+#  if FUTEX_WAIT == 0
+       movl    PSHARED(%r12), %esi
+#  else
+       movl    $FUTEX_WAIT, %esi
+       orl     PSHARED(%r12), %esi
+#  endif
+       xorl    %fs:PRIVATE_FUTEX, %esi
+# endif
+       movq    %rsp, %r10
+       movl    %r14d, %edx
+
+       jmp     21b
+       .previous
+#endif
+
+17:    /* Reget the lock.  */
+       movl    $1, %esi
+       xorl    %eax, %eax
+       LOCK
+#if MUTEX == 0
+       cmpxchgl %esi, (%r12)
+#else
+       cmpxchgl %esi, MUTEX(%r12)
+#endif
+       jnz     12f
+
+13:    decl    READERS_QUEUED(%r12)
+       cmpq    $-ETIMEDOUT, %rdx
+       jne     2b
+
+18:    movl    $ETIMEDOUT, %edx
+       jmp     9f
+
+
+5:     xorl    %edx, %edx
+       incl    NR_READERS(%r12)
+       je      8f
+9:     LOCK
+#if MUTEX == 0
+       decl    (%r12)
+#else
+       decl    MUTEX(%r12)
+#endif
+       jne     6f
+
+7:     movq    %rdx, %rax
+
+#ifndef __ASSUME_FUTEX_CLOCK_REALTIME
+       addq    $16, %rsp
+       cfi_adjust_cfa_offset(-16)
+       popq    %r14
+       cfi_adjust_cfa_offset(-8)
+       cfi_restore(%r14)
+#endif
+       popq    %r13
+       cfi_adjust_cfa_offset(-8)
+       cfi_restore(%r13)
+       popq    %r12
+       cfi_adjust_cfa_offset(-8)
+       cfi_restore(%r12)
+       retq
+
+#ifdef __ASSUME_PRIVATE_FUTEX
+       cfi_adjust_cfa_offset(16)
+       cfi_rel_offset(%r12, 8)
+       cfi_rel_offset(%r13, 0)
+#else
+       cfi_adjust_cfa_offset(40)
+       cfi_offset(%r12, -16)
+       cfi_offset(%r13, -24)
+       cfi_offset(%r14, -32)
+#endif
+1:     movl    PSHARED(%rdi), %esi
+#if MUTEX != 0
+       addq    $MUTEX, %rdi
+#endif
+       callq   __lll_lock_wait
+       jmp     2b
+
+14:    cmpl    %fs:TID, %eax
+       jne     3b
+       movl    $EDEADLK, %edx
+       jmp     9b
+
+6:     movl    PSHARED(%r12), %esi
+#if MUTEX == 0
+       movq    %r12, %rdi
+#else
+       leal    MUTEX(%r12), %rdi
+#endif
+       callq   __lll_unlock_wake
+       jmp     7b
+
+       /* Overflow.  */
+8:     decl    NR_READERS(%r12)
+       movl    $EAGAIN, %edx
+       jmp     9b
+
+       /* Overflow.  */
+4:     decl    READERS_QUEUED(%r12)
+       movl    $EAGAIN, %edx
+       jmp     9b
+
+10:    movl    PSHARED(%r12), %esi
+#if MUTEX == 0
+       movq    %r12, %rdi
+#else
+       leaq    MUTEX(%r12), %rdi
+#endif
+       callq   __lll_unlock_wake
+       jmp     11b
+
+12:    movl    PSHARED(%r12), %esi
+#if MUTEX == 0
+       movq    %r12, %rdi
+#else
+       leaq    MUTEX(%r12), %rdi
+#endif
+       callq   __lll_lock_wait
+       jmp     13b
+
+16:    movq    $-ETIMEDOUT, %rdx
+       jmp     17b
+
+19:    movl    $EINVAL, %edx
+       jmp     9b
+       cfi_endproc
+       .size   pthread_rwlock_timedrdlock,.-pthread_rwlock_timedrdlock
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedwrlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedwrlock.S
new file mode 100644 (file)
index 0000000..23e1ee1
--- /dev/null
@@ -0,0 +1,268 @@
+/* Copyright (C) 2002, 2003, 2005, 2007, 2009 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <lowlevelrwlock.h>
+#include <pthread-errnos.h>
+#include <bits/kernel-features.h>
+#include <tcb-offsets.h>
+
+
+/* For the calculation see asm/vsyscall.h.  */
+#define VSYSCALL_ADDR_vgettimeofday    0xffffffffff600000
+
+       .text
+
+       .globl  pthread_rwlock_timedwrlock
+       .type   pthread_rwlock_timedwrlock,@function
+       .align  16
+pthread_rwlock_timedwrlock:
+       cfi_startproc
+       pushq   %r12
+       cfi_adjust_cfa_offset(8)
+       cfi_rel_offset(%r12, 0)
+       pushq   %r13
+       cfi_adjust_cfa_offset(8)
+       cfi_rel_offset(%r13, 0)
+#ifdef __ASSUME_FUTEX_CLOCK_REALTIME
+# define VALREG        %edx
+#else
+       pushq   %r14
+       cfi_adjust_cfa_offset(8)
+       cfi_rel_offset(%r14, 0)
+
+       subq    $16, %rsp
+       cfi_adjust_cfa_offset(16)
+# define VALREG %r14d
+#endif
+
+       movq    %rdi, %r12
+       movq    %rsi, %r13
+
+       /* Get the lock.  */
+       movl    $1, %esi
+       xorl    %eax, %eax
+       LOCK
+#if MUTEX == 0
+       cmpxchgl %esi, (%rdi)
+#else
+       cmpxchgl %esi, MUTEX(%rdi)
+#endif
+       jnz     1f
+
+2:     movl    WRITER(%r12), %eax
+       testl   %eax, %eax
+       jne     14f
+       cmpl    $0, NR_READERS(%r12)
+       je      5f
+
+       /* Check the value of the timeout parameter.  */
+3:     cmpq    $1000000000, 8(%r13)
+       jae     19f
+
+       incl    WRITERS_QUEUED(%r12)
+       je      4f
+
+       movl    WRITERS_WAKEUP(%r12), VALREG
+
+       LOCK
+#if MUTEX == 0
+       decl    (%r12)
+#else
+       decl    MUTEX(%r12)
+#endif
+       jne     10f
+
+11:
+#ifndef __ASSUME_FUTEX_CLOCK_REALTIME
+#  ifdef __PIC__
+       cmpl    $0, __have_futex_clock_realtime(%rip)
+#  else
+       cmpl    $0, __have_futex_clock_realtime
+#  endif
+       je      .Lreltmo
+#endif
+
+       movl    $FUTEX_PRIVATE_FLAG|FUTEX_WAIT_BITSET|FUTEX_CLOCK_REALTIME, %esi
+       xorl    PSHARED(%r12), %esi
+       movq    %r13, %r10
+       movl    $0xffffffff, %r9d
+#ifndef __ASSUME_FUTEX_CLOCK_REALTIME
+       movl    %r14d, %edx
+#endif
+21:    leaq    WRITERS_WAKEUP(%r12), %rdi
+       movl    $SYS_futex, %eax
+       syscall
+       movq    %rax, %rdx
+
+#ifndef __ASSUME_FUTEX_CLOCK_REALTIME
+       .subsection 2
+.Lreltmo:
+       /* Get current time.  */
+       movq    %rsp, %rdi
+       xorl    %esi, %esi
+       movq    $VSYSCALL_ADDR_vgettimeofday, %rax
+       callq   *%rax
+
+       /* Compute relative timeout.  */
+       movq    8(%rsp), %rax
+       movl    $1000, %edi
+       mul     %rdi            /* Milli seconds to nano seconds.  */
+       movq    (%r13), %rcx
+       movq    8(%r13), %rdi
+       subq    (%rsp), %rcx
+       subq    %rax, %rdi
+       jns     15f
+       addq    $1000000000, %rdi
+       decq    %rcx
+15:    testq   %rcx, %rcx
+       js      16f             /* Time is already up.  */
+
+       /* Futex call.  */
+       movq    %rcx, (%rsp)    /* Store relative timeout.  */
+       movq    %rdi, 8(%rsp)
+
+# ifdef __ASSUME_PRIVATE_FUTEX
+       movl    $FUTEX_PRIVATE_FLAG|FUTEX_WAIT, %esi
+       xorl    PSHARED(%r12), %esi
+# else
+#  if FUTEX_WAIT == 0
+       movl    PSHARED(%r12), %esi
+#  else
+       movl    $FUTEX_WAIT, %esi
+       orl     PSHARED(%r12), %esi
+#  endif
+       xorl    %fs:PRIVATE_FUTEX, %esi
+# endif
+       movq    %rsp, %r10
+       movl    %r14d, %edx
+
+       jmp     21b
+       .previous
+#endif
+
+17:    /* Reget the lock.  */
+       movl    $1, %esi
+       xorl    %eax, %eax
+       LOCK
+#if MUTEX == 0
+       cmpxchgl %esi, (%r12)
+#else
+       cmpxchgl %esi, MUTEX(%r12)
+#endif
+       jnz     12f
+
+13:    decl    WRITERS_QUEUED(%r12)
+       cmpq    $-ETIMEDOUT, %rdx
+       jne     2b
+
+18:    movl    $ETIMEDOUT, %edx
+       jmp     9f
+
+
+5:     xorl    %edx, %edx
+       movl    %fs:TID, %eax
+       movl    %eax, WRITER(%r12)
+9:     LOCK
+#if MUTEX == 0
+       decl    (%r12)
+#else
+       decl    MUTEX(%r12)
+#endif
+       jne     6f
+
+7:     movq    %rdx, %rax
+
+#ifndef __ASSUME_PRIVATE_FUTEX
+       addq    $16, %rsp
+       cfi_adjust_cfa_offset(-16)
+       popq    %r14
+       cfi_adjust_cfa_offset(-8)
+       cfi_restore(%r14)
+#endif
+       popq    %r13
+       cfi_adjust_cfa_offset(-8)
+       cfi_restore(%r13)
+       popq    %r12
+       cfi_adjust_cfa_offset(-8)
+       cfi_restore(%r12)
+       retq
+
+#ifdef __ASSUME_PRIVATE_FUTEX
+       cfi_adjust_cfa_offset(16)
+       cfi_rel_offset(%r12, 8)
+       cfi_rel_offset(%r13, 0)
+#else
+       cfi_adjust_cfa_offset(40)
+       cfi_offset(%r12, -16)
+       cfi_offset(%r13, -24)
+       cfi_offset(%r14, -32)
+#endif
+1:     movl    PSHARED(%rdi), %esi
+#if MUTEX != 0
+       addq    $MUTEX, %rdi
+#endif
+       callq   __lll_lock_wait
+       jmp     2b
+
+14:    cmpl    %fs:TID, %eax
+       jne     3b
+20:    movl    $EDEADLK, %edx
+       jmp     9b
+
+6:     movl    PSHARED(%r12), %esi
+#if MUTEX == 0
+       movq    %r12, %rdi
+#else
+       leal    MUTEX(%r12), %rdi
+#endif
+       callq   __lll_unlock_wake
+       jmp     7b
+
+       /* Overflow.  */
+4:     decl    WRITERS_QUEUED(%r12)
+       movl    $EAGAIN, %edx
+       jmp     9b
+
+10:    movl    PSHARED(%r12), %esi
+#if MUTEX == 0
+       movq    %r12, %rdi
+#else
+       leaq    MUTEX(%r12), %rdi
+#endif
+       callq   __lll_unlock_wake
+       jmp     11b
+
+12:    movl    PSHARED(%r12), %esi
+#if MUTEX == 0
+       movq    %r12, %rdi
+#else
+       leaq    MUTEX(%r12), %rdi
+#endif
+       callq   __lll_lock_wait
+       jmp     13b
+
+16:    movq    $-ETIMEDOUT, %rdx
+       jmp     17b
+
+19:    movl    $EINVAL, %edx
+       jmp     9b
+       cfi_endproc
+       .size   pthread_rwlock_timedwrlock,.-pthread_rwlock_timedwrlock
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_unlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_unlock.S
new file mode 100644 (file)
index 0000000..cfcc7a1
--- /dev/null
@@ -0,0 +1,130 @@
+/* Copyright (C) 2002, 2003, 2005, 2007, 2009 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <lowlevelrwlock.h>
+#include <bits/kernel-features.h>
+
+
+       .text
+
+       .globl  __pthread_rwlock_unlock
+       .type   __pthread_rwlock_unlock,@function
+       .align  16
+__pthread_rwlock_unlock:
+       cfi_startproc
+       /* Get the lock.  */
+       movl    $1, %esi
+       xorl    %eax, %eax
+       LOCK
+#if MUTEX == 0
+       cmpxchgl %esi, (%rdi)
+#else
+       cmpxchgl %esi, MUTEX(%rdi)
+#endif
+       jnz     1f
+
+2:     cmpl    $0, WRITER(%rdi)
+       jne     5f
+       decl    NR_READERS(%rdi)
+       jnz     6f
+
+5:     movl    $0, WRITER(%rdi)
+
+       movl    $1, %edx
+       leaq    WRITERS_WAKEUP(%rdi), %r10
+       cmpl    $0, WRITERS_QUEUED(%rdi)
+       jne     0f
+
+       /* If also no readers waiting nothing to do.  */
+       cmpl    $0, READERS_QUEUED(%rdi)
+       je      6f
+
+       movl    $0x7fffffff, %edx
+       leaq    READERS_WAKEUP(%rdi), %r10
+
+0:     incl    (%r10)
+       LOCK
+#if MUTEX == 0
+       decl    (%rdi)
+#else
+       decl    MUTEX(%rdi)
+#endif
+       jne     7f
+
+8:
+#ifdef __ASSUME_PRIVATE_FUTEX
+       movl    $FUTEX_PRIVATE_FLAG|FUTEX_WAKE, %esi
+       xorl    PSHARED(%rdi), %esi
+#else
+       movl    $FUTEX_WAKE, %esi
+       orl     PSHARED(%rdi), %esi
+       xorl    %fs:PRIVATE_FUTEX, %esi
+#endif
+       movl    $SYS_futex, %eax
+       movq    %r10, %rdi
+       syscall
+
+       xorl    %eax, %eax
+       retq
+
+       .align  16
+6:     LOCK
+#if MUTEX == 0
+       decl    (%rdi)
+#else
+       decl    MUTEX(%rdi)
+#endif
+       jne     3f
+
+4:     xorl    %eax, %eax
+       retq
+
+1:     movl    PSHARED(%rdi), %esi
+#if MUTEX != 0
+       addq    $MUTEX, %rdi
+#endif
+       callq   __lll_lock_wait
+#if MUTEX != 0
+       subq    $MUTEX, %rdi
+#endif
+       jmp     2b
+
+3:     movl    PSHARED(%rdi), %esi
+#if MUTEX != 0
+       addq    $MUTEX, %rdi
+#endif
+       callq   __lll_unlock_wake
+       jmp     4b
+
+7:     movl    PSHARED(%rdi), %esi
+#if MUTEX != 0
+       addq    $MUTEX, %rdi
+#endif
+       callq   __lll_unlock_wake
+       jmp     8b
+       cfi_endproc
+       .size   __pthread_rwlock_unlock,.-__pthread_rwlock_unlock
+
+       .globl  pthread_rwlock_unlock
+pthread_rwlock_unlock = __pthread_rwlock_unlock
+
+       .globl  __pthread_rwlock_unlock_internal
+__pthread_rwlock_unlock_internal = __pthread_rwlock_unlock
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_wrlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_wrlock.S
new file mode 100644 (file)
index 0000000..ccfc11b
--- /dev/null
@@ -0,0 +1,167 @@
+/* Copyright (C) 2002, 2003, 2005, 2007, 2009 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <lowlevelrwlock.h>
+#include <pthread-errnos.h>
+#include <bits/kernel-features.h>
+#include <tcb-offsets.h>
+
+
+       .text
+
+       .globl  __pthread_rwlock_wrlock
+       .type   __pthread_rwlock_wrlock,@function
+       .align  16
+__pthread_rwlock_wrlock:
+       cfi_startproc
+       xorq    %r10, %r10
+
+       /* Get the lock.  */
+       movl    $1, %esi
+       xorl    %eax, %eax
+       LOCK
+#if MUTEX == 0
+       cmpxchgl %esi, (%rdi)
+#else
+       cmpxchgl %esi, MUTEX(%rdi)
+#endif
+       jnz     1f
+
+2:     movl    WRITER(%rdi), %eax
+       testl   %eax, %eax
+       jne     14f
+       cmpl    $0, NR_READERS(%rdi)
+       je      5f
+
+3:     incl    WRITERS_QUEUED(%rdi)
+       je      4f
+
+       movl    WRITERS_WAKEUP(%rdi), %edx
+
+       LOCK
+#if MUTEX == 0
+       decl    (%rdi)
+#else
+       decl    MUTEX(%rdi)
+#endif
+       jne     10f
+
+11:
+#ifdef __ASSUME_PRIVATE_FUTEX
+       movl    $FUTEX_PRIVATE_FLAG|FUTEX_WAIT, %esi
+       xorl    PSHARED(%rdi), %esi
+#else
+# if FUTEX_WAIT == 0
+       movl    PSHARED(%rdi), %esi
+# else
+       movl    $FUTEX_WAIT, %esi
+       orl     PSHARED(%rdi), %esi
+# endif
+       xorl    %fs:PRIVATE_FUTEX, %esi
+#endif
+       addq    $WRITERS_WAKEUP, %rdi
+       movl    $SYS_futex, %eax
+       syscall
+
+       subq    $WRITERS_WAKEUP, %rdi
+
+       /* Reget the lock.  */
+       movl    $1, %esi
+       xorl    %eax, %eax
+       LOCK
+#if MUTEX == 0
+       cmpxchgl %esi, (%rdi)
+#else
+       cmpxchgl %esi, MUTEX(%rdi)
+#endif
+       jnz     12f
+
+13:    decl    WRITERS_QUEUED(%rdi)
+       jmp     2b
+
+5:     xorl    %edx, %edx
+       movl    %fs:TID, %eax
+       movl    %eax, WRITER(%rdi)
+9:     LOCK
+#if MUTEX == 0
+       decl    (%rdi)
+#else
+       decl    MUTEX(%rdi)
+#endif
+       jne     6f
+7:
+
+       movq    %rdx, %rax
+       retq
+
+1:     movl    PSHARED(%rdi), %esi
+#if MUTEX != 0
+       addq    $MUTEX, %rdi
+#endif
+       callq   __lll_lock_wait
+#if MUTEX != 0
+       subq    $MUTEX, %rdi
+#endif
+       jmp     2b
+
+14:    cmpl    %fs:TID, %eax
+       jne     3b
+       movl    $EDEADLK, %edx
+       jmp     9b
+
+6:     movl    PSHARED(%rdi), %esi
+#if MUTEX != 0
+       addq    $MUTEX, %rdi
+#endif
+       callq   __lll_unlock_wake
+       jmp     7b
+
+4:     decl    WRITERS_QUEUED(%rdi)
+       movl    $EAGAIN, %edx
+       jmp     9b
+
+10:    movl    PSHARED(%rdi), %esi
+#if MUTEX != 0
+       addq    $MUTEX, %rdi
+#endif
+       callq   __lll_unlock_wake
+#if MUTEX != 0
+       subq    $MUTEX, %rdi
+#endif
+       jmp     11b
+
+12:    movl    PSHARED(%rdi), %esi
+#if MUTEX != 0
+       addq    $MUTEX, %rdi
+#endif
+       callq   __lll_lock_wait
+#if MUTEX != 0
+       subq    $MUTEX, %rdi
+#endif
+       jmp     13b
+       cfi_endproc
+       .size   __pthread_rwlock_wrlock,.-__pthread_rwlock_wrlock
+
+       .globl  pthread_rwlock_wrlock
+pthread_rwlock_wrlock = __pthread_rwlock_wrlock
+
+       .globl  __pthread_rwlock_wrlock_internal
+__pthread_rwlock_wrlock_internal = __pthread_rwlock_wrlock
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_setaffinity.c b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_setaffinity.c
new file mode 100644 (file)
index 0000000..640d304
--- /dev/null
@@ -0,0 +1,14 @@
+#include <tls.h>
+
+#define RESET_VGETCPU_CACHE() \
+  do {                       \
+    asm volatile ("movl %0, %%fs:%P1\n\t"                                    \
+                 "movl %0, %%fs:%P2"                                         \
+                 :                                                           \
+                 : "ir" (0), "i" (offsetof (struct pthread,                  \
+                                            header.vgetcpu_cache[0])),       \
+                   "i" (offsetof (struct pthread,                            \
+                                  header.vgetcpu_cache[1])));          \
+  } while (0)
+
+#include "../pthread_setaffinity.c"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_spin_init.c b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_spin_init.c
new file mode 100644 (file)
index 0000000..483de8c
--- /dev/null
@@ -0,0 +1 @@
+#include <sysdeps/x86_64/pthread_spin_init.c>
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_spin_unlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_spin_unlock.S
new file mode 100644 (file)
index 0000000..e8e2ba2
--- /dev/null
@@ -0,0 +1 @@
+#include <sysdeps/x86_64/pthread_spin_unlock.S>
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sem_post.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sem_post.S
new file mode 100644 (file)
index 0000000..7af6524
--- /dev/null
@@ -0,0 +1,89 @@
+/* Copyright (C) 2002, 2003, 2005, 2007, 2008 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <pthread-errnos.h>
+#include <structsem.h>
+
+
+       .text
+
+       .globl  sem_post
+       .type   sem_post,@function
+       .align  16
+sem_post:
+#if VALUE == 0
+       movl    (%rdi), %eax
+#else
+       movl    VALUE(%rdi), %eax
+#endif
+0:     cmpl    $SEM_VALUE_MAX, %eax
+       je      3f
+       leal    1(%rax), %esi
+       LOCK
+#if VALUE == 0
+       cmpxchgl %esi, (%rdi)
+#else
+       cmpxchgl %esi, VALUE(%rdi)
+#endif
+       jnz     0b
+
+       cmpq    $0, NWAITERS(%rdi)
+       je      2f
+
+       movl    $SYS_futex, %eax
+       movl    $FUTEX_WAKE, %esi
+       orl     PRIVATE(%rdi), %esi
+       movl    $1, %edx
+       syscall
+
+       testq   %rax, %rax
+       js      1f
+
+2:     xorl    %eax, %eax
+       retq
+
+1:
+#if USE___THREAD
+       movl    $EINVAL, %eax
+#else
+       callq   __errno_location@plt
+       movl    $EINVAL, %edx
+#endif
+       jmp     4f
+
+3:
+#if USE___THREAD
+       movl    $EOVERFLOW, %eax
+#else
+       callq   __errno_location@plt
+       movl    $EOVERFLOW, %edx
+#endif
+
+4:
+#if USE___THREAD
+       movq    errno@gottpoff(%rip), %rdx
+       movl    %eax, %fs:(%rdx)
+#else
+       movl    %edx, (%rax)
+#endif
+       orl     $-1, %eax
+       retq
+       .size   sem_post,.-sem_post
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S
new file mode 100644 (file)
index 0000000..704a222
--- /dev/null
@@ -0,0 +1,379 @@
+/* Copyright (C) 2002, 2003, 2005, 2007, 2009 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <bits/kernel-features.h>
+#include <lowlevellock.h>
+#include <pthread-errnos.h>
+#include <structsem.h>
+
+
+/* For the calculation see asm/vsyscall.h.  */
+#define VSYSCALL_ADDR_vgettimeofday    0xffffffffff600000
+
+       .text
+
+       .globl  sem_timedwait
+       .type   sem_timedwait,@function
+       .align  16
+sem_timedwait:
+.LSTARTCODE:
+       cfi_startproc
+#if VALUE == 0
+       movl    (%rdi), %eax
+#else
+       movl    VALUE(%rdi), %eax
+#endif
+2:     testl   %eax, %eax
+       je      1f
+
+       leaq    -1(%rax), %rdx
+       LOCK
+#if VALUE == 0
+       cmpxchgl %edx, (%rdi)
+#else
+       cmpxchgl %edx, VALUE(%rdi)
+#endif
+       jne     2b
+
+       xorl    %eax, %eax
+       retq
+
+       /* Check whether the timeout value is valid.  */
+1:     cmpq    $1000000000, 8(%rsi)
+       jae     6f
+
+#ifndef __ASSUME_FUTEX_CLOCK_REALTIME
+#  ifdef __PIC__
+       cmpl    $0, __have_futex_clock_realtime(%rip)
+#  else
+       cmpl    $0, __have_futex_clock_realtime
+#  endif
+       je      .Lreltmo
+#endif
+
+       /* This push is only needed to store the sem_t pointer for the
+          exception handler.  */
+       pushq   %rdi
+       cfi_adjust_cfa_offset(8)
+
+       movq    %rsi, %r10
+
+       LOCK
+       addq    $1, NWAITERS(%rdi)
+
+.LcleanupSTART:
+13:    call    __pthread_enable_asynccancel
+       movl    %eax, %r8d
+
+#if VALUE != 0
+       leaq    VALUE(%rdi), %rdi
+#endif
+       movl    $0xffffffff, %r9d
+       movl    $FUTEX_WAIT_BITSET|FUTEX_CLOCK_REALTIME, %esi
+       orl     PRIVATE(%rdi), %esi
+       movl    $SYS_futex, %eax
+       xorl    %edx, %edx
+       syscall
+       movq    %rax, %r9
+#if VALUE != 0
+       leaq    -VALUE(%rdi), %rdi
+#endif
+
+       xchgq   %r8, %rdi
+       call    __pthread_disable_asynccancel
+.LcleanupEND:
+       movq    %r8, %rdi
+
+       testq   %r9, %r9
+       je      11f
+       cmpq    $-EWOULDBLOCK, %r9
+       jne     3f
+
+11:
+#if VALUE == 0
+       movl    (%rdi), %eax
+#else
+       movl    VALUE(%rdi), %eax
+#endif
+14:    testl   %eax, %eax
+       je      13b
+
+       leaq    -1(%rax), %rcx
+       LOCK
+#if VALUE == 0
+       cmpxchgl %ecx, (%rdi)
+#else
+       cmpxchgl %ecx, VALUE(%rdi)
+#endif
+       jne     14b
+
+       xorl    %eax, %eax
+
+15:    LOCK
+       subq    $1, NWAITERS(%rdi)
+
+       leaq    8(%rsp), %rsp
+       cfi_adjust_cfa_offset(-8)
+       retq
+
+       cfi_adjust_cfa_offset(8)
+3:     negq    %r9
+#if USE___THREAD
+       movq    errno@gottpoff(%rip), %rdx
+       movl    %r9d, %fs:(%rdx)
+#else
+       callq   __errno_location@plt
+       movl    %r9d, (%rax)
+#endif
+
+       orl     $-1, %eax
+       jmp     15b
+
+       cfi_adjust_cfa_offset(-8)
+6:
+#if USE___THREAD
+       movq    errno@gottpoff(%rip), %rdx
+       movl    $EINVAL, %fs:(%rdx)
+#else
+       callq   __errno_location@plt
+       movl    $EINVAL, (%rax)
+#endif
+
+       orl     $-1, %eax
+
+       retq
+
+#ifndef __ASSUME_FUTEX_CLOCK_REALTIME
+.Lreltmo:
+       pushq   %r12
+       cfi_adjust_cfa_offset(8)
+       cfi_rel_offset(%r12, 0)
+       pushq   %r13
+       cfi_adjust_cfa_offset(8)
+       cfi_rel_offset(%r13, 0)
+       pushq   %r14
+       cfi_adjust_cfa_offset(8)
+       cfi_rel_offset(%r14, 0)
+
+#ifdef __ASSUME_FUTEX_CLOCK_REALTIME
+# define STACKFRAME 8
+#else
+# define STACKFRAME 24
+#endif
+       subq    $STACKFRAME, %rsp
+       cfi_adjust_cfa_offset(STACKFRAME)
+
+       movq    %rdi, %r12
+       movq    %rsi, %r13
+
+       LOCK
+       addq    $1, NWAITERS(%r12)
+
+7:     xorl    %esi, %esi
+       movq    %rsp, %rdi
+       movq    $VSYSCALL_ADDR_vgettimeofday, %rax
+       callq   *%rax
+
+       /* Compute relative timeout.  */
+       movq    8(%rsp), %rax
+       movl    $1000, %edi
+       mul     %rdi            /* Milli seconds to nano seconds.  */
+       movq    (%r13), %rdi
+       movq    8(%r13), %rsi
+       subq    (%rsp), %rdi
+       subq    %rax, %rsi
+       jns     5f
+       addq    $1000000000, %rsi
+       decq    %rdi
+5:     testq   %rdi, %rdi
+       movl    $ETIMEDOUT, %r14d
+       js      36f             /* Time is already up.  */
+
+       movq    %rdi, (%rsp)    /* Store relative timeout.  */
+       movq    %rsi, 8(%rsp)
+
+.LcleanupSTART2:
+       call    __pthread_enable_asynccancel
+       movl    %eax, 16(%rsp)
+
+       movq    %rsp, %r10
+# if VALUE == 0
+       movq    %r12, %rdi
+# else
+       leaq    VALUE(%r12), %rdi
+# endif
+# if FUTEX_WAIT == 0
+       movl    PRIVATE(%rdi), %esi
+# else
+       movl    $FUTEX_WAIT, %esi
+       orl     PRIVATE(%rdi), %esi
+# endif
+       movl    $SYS_futex, %eax
+       xorl    %edx, %edx
+       syscall
+       movq    %rax, %r14
+
+       movl    16(%rsp), %edi
+       call    __pthread_disable_asynccancel
+.LcleanupEND2:
+
+       testq   %r14, %r14
+       je      9f
+       cmpq    $-EWOULDBLOCK, %r14
+       jne     33f
+
+9:
+# if VALUE == 0
+       movl    (%r12), %eax
+# else
+       movl    VALUE(%r12), %eax
+# endif
+8:     testl   %eax, %eax
+       je      7b
+
+       leaq    -1(%rax), %rcx
+       LOCK
+# if VALUE == 0
+       cmpxchgl %ecx, (%r12)
+# else
+       cmpxchgl %ecx, VALUE(%r12)
+# endif
+       jne     8b
+
+       xorl    %eax, %eax
+
+45:    LOCK
+       subq    $1, NWAITERS(%r12)
+
+       addq    $STACKFRAME, %rsp
+       cfi_adjust_cfa_offset(-STACKFRAME)
+       popq    %r14
+       cfi_adjust_cfa_offset(-8)
+       cfi_restore(%r14)
+       popq    %r13
+       cfi_adjust_cfa_offset(-8)
+       cfi_restore(%r13)
+       popq    %r12
+       cfi_adjust_cfa_offset(-8)
+       cfi_restore(%r12)
+       retq
+
+       cfi_adjust_cfa_offset(STACKFRAME + 3 * 8)
+       cfi_rel_offset(%r12, STACKFRAME + 2 * 8)
+       cfi_rel_offset(%r13, STACKFRAME + 1 * 8)
+       cfi_rel_offset(%r14, STACKFRAME)
+33:    negq    %r14
+36:
+#if USE___THREAD
+       movq    errno@gottpoff(%rip), %rdx
+       movl    %r14d, %fs:(%rdx)
+#else
+       callq   __errno_location@plt
+       movl    %r14d, (%rax)
+#endif
+
+       orl     $-1, %eax
+       jmp     45b
+#endif
+       cfi_endproc
+       .size   sem_timedwait,.-sem_timedwait
+
+
+       .type   sem_timedwait_cleanup,@function
+sem_timedwait_cleanup:
+       cfi_startproc
+       cfi_adjust_cfa_offset(8)
+
+       movq    (%rsp), %rdi
+       LOCK
+       subq    $1, NWAITERS(%rdi)
+       movq    %rax, %rdi
+.LcallUR:
+       call    _Unwind_Resume@PLT
+       hlt
+.LENDCODE:
+       cfi_endproc
+       .size   sem_timedwait_cleanup,.-sem_timedwait_cleanup
+
+
+#ifndef __ASSUME_FUTEX_CLOCK_REALTIME
+       .type   sem_timedwait_cleanup2,@function
+sem_timedwait_cleanup2:
+       cfi_startproc
+       cfi_adjust_cfa_offset(STACKFRAME + 3 * 8)
+       cfi_rel_offset(%r12, STACKFRAME + 2 * 8)
+       cfi_rel_offset(%r13, STACKFRAME + 1 * 8)
+       cfi_rel_offset(%r14, STACKFRAME)
+
+       LOCK
+       subq    $1, NWAITERS(%r12)
+       movq    %rax, %rdi
+       movq    STACKFRAME(%rsp), %r14
+       movq    STACKFRAME+8(%rsp), %r13
+       movq    STACKFRAME+16(%rsp), %r12
+.LcallUR2:
+       call    _Unwind_Resume@PLT
+       hlt
+.LENDCODE2:
+       cfi_endproc
+       .size   sem_timedwait_cleanup2,.-sem_timedwait_cleanup2
+#endif
+
+
+       .section .gcc_except_table,"a",@progbits
+.LexceptSTART:
+       .byte   DW_EH_PE_omit                   # @LPStart format
+       .byte   DW_EH_PE_omit                   # @TType format
+       .byte   DW_EH_PE_uleb128                # call-site format
+       .uleb128 .Lcstend-.Lcstbegin
+.Lcstbegin:
+       .uleb128 .LcleanupSTART-.LSTARTCODE
+       .uleb128 .LcleanupEND-.LcleanupSTART
+       .uleb128 sem_timedwait_cleanup-.LSTARTCODE
+       .uleb128  0
+#ifndef __ASSUME_FUTEX_CLOCK_REALTIME
+       .uleb128 .LcleanupSTART2-.LSTARTCODE
+       .uleb128 .LcleanupEND2-.LcleanupSTART2
+       .uleb128 sem_timedwait_cleanup2-.LSTARTCODE
+       .uleb128  0
+#endif
+       .uleb128 .LcallUR-.LSTARTCODE
+       .uleb128 .LENDCODE-.LcallUR
+       .uleb128 0
+       .uleb128  0
+#ifndef __ASSUME_FUTEX_CLOCK_REALTIME
+       .uleb128 .LcallUR2-.LSTARTCODE
+       .uleb128 .LENDCODE2-.LcallUR2
+       .uleb128 0
+       .uleb128  0
+#endif
+.Lcstend:
+
+
+#ifdef SHARED
+       .hidden DW.ref.__gcc_personality_v0
+       .weak   DW.ref.__gcc_personality_v0
+       .section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits
+       .align  8
+       .type   DW.ref.__gcc_personality_v0, @object
+       .size   DW.ref.__gcc_personality_v0, 8
+DW.ref.__gcc_personality_v0:
+       .quad   __gcc_personality_v0
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sem_trywait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sem_trywait.S
new file mode 100644 (file)
index 0000000..7b7f63d
--- /dev/null
@@ -0,0 +1,52 @@
+/* Copyright (C) 2002, 2003, 2005, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <pthread-errnos.h>
+
+       .text
+
+       .globl  sem_trywait
+       .type   sem_trywait,@function
+       .align  16
+sem_trywait:
+       movl    (%rdi), %eax
+2:     testl   %eax, %eax
+       jz      1f
+
+       leal    -1(%rax), %edx
+       LOCK
+       cmpxchgl %edx, (%rdi)
+       jne     2b
+
+       xorl    %eax, %eax
+       retq
+
+1:
+#if USE___THREAD
+       movq    errno@gottpoff(%rip), %rdx
+       movl    $EAGAIN, %fs:(%rdx)
+#else
+       callq   __errno_location@plt
+       movl    $EAGAIN, (%rax)
+#endif
+       orl     $-1, %eax
+       retq
+       .size   sem_trywait,.-sem_trywait
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sem_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sem_wait.S
new file mode 100644 (file)
index 0000000..f6b39bd
--- /dev/null
@@ -0,0 +1,174 @@
+/* Copyright (C) 2002, 2003, 2005, 2007, 2009 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <pthread-errnos.h>
+#include <structsem.h>
+
+
+       .text
+
+       .globl  sem_wait
+       .type   sem_wait,@function
+       .align  16
+sem_wait:
+.LSTARTCODE:
+       cfi_startproc
+
+#if VALUE == 0
+       movl    (%rdi), %eax
+#else
+       movl    VALUE(%rdi), %eax
+#endif
+2:     testl   %eax, %eax
+       je      1f
+
+       leal    -1(%rax), %edx
+       LOCK
+#if VALUE == 0
+       cmpxchgl %edx, (%rdi)
+#else
+       cmpxchgl %edx, VALUE(%rdi)
+#endif
+       jne     2b
+
+       xorl    %eax, %eax
+       retq
+
+       /* This push is only needed to store the sem_t pointer for the
+          exception handler.  */
+1:     pushq   %rdi
+       cfi_adjust_cfa_offset(8)
+
+       LOCK
+       addq    $1, NWAITERS(%rdi)
+
+.LcleanupSTART:
+6:     call    __pthread_enable_asynccancel
+       movl    %eax, %r8d
+
+       xorq    %r10, %r10
+       movl    $SYS_futex, %eax
+#if FUTEX_WAIT == 0
+       movl    PRIVATE(%rdi), %esi
+#else
+       movl    $FUTEX_WAIT, %esi
+       orl     PRIVATE(%rdi), %esi
+#endif
+       xorl    %edx, %edx
+       syscall
+       movq    %rax, %rcx
+
+       xchgq   %r8, %rdi
+       call    __pthread_disable_asynccancel
+.LcleanupEND:
+       movq    %r8, %rdi
+
+       testq   %rcx, %rcx
+       je      3f
+       cmpq    $-EWOULDBLOCK, %rcx
+       jne     4f
+
+3:
+#if VALUE == 0
+       movl    (%rdi), %eax
+#else
+       movl    VALUE(%rdi), %eax
+#endif
+5:     testl   %eax, %eax
+       je      6b
+
+       leal    -1(%rax), %edx
+       LOCK
+#if VALUE == 0
+       cmpxchgl %edx, (%rdi)
+#else
+       cmpxchgl %edx, VALUE(%rdi)
+#endif
+       jne     5b
+
+       xorl    %eax, %eax
+
+9:     LOCK
+       subq    $1, NWAITERS(%rdi)
+
+       leaq    8(%rsp), %rsp
+       cfi_adjust_cfa_offset(-8)
+
+       retq
+
+       cfi_adjust_cfa_offset(8)
+4:     negq    %rcx
+#if USE___THREAD
+       movq    errno@gottpoff(%rip), %rdx
+       movl    %ecx, %fs:(%rdx)
+#else
+# error "not supported.  %rcx and %rdi must be preserved"
+       callq   __errno_location@plt
+       movl    %ecx, (%rax)
+#endif
+       orl     $-1, %eax
+
+       jmp 9b
+       .size   sem_wait,.-sem_wait
+
+
+       .type   sem_wait_cleanup,@function
+sem_wait_cleanup:
+       movq    (%rsp), %rdi
+       LOCK
+       subq    $1, NWAITERS(%rdi)
+       movq    %rax, %rdi
+.LcallUR:
+       call    _Unwind_Resume@PLT
+       hlt
+.LENDCODE:
+       cfi_endproc
+       .size   sem_wait_cleanup,.-sem_wait_cleanup
+
+
+       .section .gcc_except_table,"a",@progbits
+.LexceptSTART:
+       .byte   DW_EH_PE_omit                   # @LPStart format
+       .byte   DW_EH_PE_omit                   # @TType format
+       .byte   DW_EH_PE_uleb128                # call-site format
+       .uleb128 .Lcstend-.Lcstbegin
+.Lcstbegin:
+       .uleb128 .LcleanupSTART-.LSTARTCODE
+       .uleb128 .LcleanupEND-.LcleanupSTART
+       .uleb128 sem_wait_cleanup-.LSTARTCODE
+       .uleb128  0
+       .uleb128 .LcallUR-.LSTARTCODE
+       .uleb128 .LENDCODE-.LcallUR
+       .uleb128 0
+       .uleb128  0
+.Lcstend:
+
+
+#ifdef SHARED
+       .hidden DW.ref.__gcc_personality_v0
+       .weak   DW.ref.__gcc_personality_v0
+       .section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits
+       .align  8
+       .type   DW.ref.__gcc_personality_v0, @object
+       .size   DW.ref.__gcc_personality_v0, 8
+DW.ref.__gcc_personality_v0:
+       .quad   __gcc_personality_v0
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h
new file mode 100644 (file)
index 0000000..1c93952
--- /dev/null
@@ -0,0 +1,111 @@
+/* Copyright (C) 2002-2006, 2009 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <tls.h>
+#ifndef __ASSEMBLER__
+# include <pthreadP.h>
+#endif
+
+#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt
+
+/* The code to disable cancellation depends on the fact that the called
+   functions are special.  They don't modify registers other than %rax
+   and %r11 if they return.  Therefore we don't have to preserve other
+   registers around these calls.  */
+# undef PSEUDO
+# define PSEUDO(name, syscall_name, args)                                    \
+  .text;                                                                     \
+  ENTRY (name)                                                               \
+    SINGLE_THREAD_P;                                                         \
+    jne L(pseudo_cancel);                                                    \
+  .type __##syscall_name##_nocancel,@function;                               \
+  .globl __##syscall_name##_nocancel;                                        \
+  __##syscall_name##_nocancel:                                               \
+    DO_CALL (syscall_name, args);                                            \
+    cmpq $-4095, %rax;                                                       \
+    jae SYSCALL_ERROR_LABEL;                                                 \
+    ret;                                                                     \
+  .size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel;           \
+  L(pseudo_cancel):                                                          \
+    /* We always have to align the stack before calling a function.  */              \
+    subq $8, %rsp; cfi_adjust_cfa_offset (8);                                \
+    CENABLE                                                                  \
+    /* The return value from CENABLE is argument for CDISABLE.  */           \
+    movq %rax, (%rsp);                                                       \
+    DO_CALL (syscall_name, args);                                            \
+    movq (%rsp), %rdi;                                                       \
+    /* Save %rax since it's the error code from the syscall.  */             \
+    movq %rax, %rdx;                                                         \
+    CDISABLE                                                                 \
+    movq %rdx, %rax;                                                         \
+    addq $8,%rsp; cfi_adjust_cfa_offset (-8);                                \
+    cmpq $-4095, %rax;                                                       \
+    jae SYSCALL_ERROR_LABEL;                                                 \
+  L(pseudo_end):
+
+
+# ifdef IS_IN_libpthread
+#  define CENABLE      call __pthread_enable_asynccancel;
+#  define CDISABLE     call __pthread_disable_asynccancel;
+#  define __local_multiple_threads __pthread_multiple_threads
+# elif !defined NOT_IN_libc
+#  define CENABLE      call __libc_enable_asynccancel;
+#  define CDISABLE     call __libc_disable_asynccancel;
+#  define __local_multiple_threads __libc_multiple_threads
+# elif defined IS_IN_librt
+#  define CENABLE      call __librt_enable_asynccancel;
+#  define CDISABLE     call __librt_disable_asynccancel;
+# else
+#  error Unsupported library
+# endif
+
+# if defined IS_IN_libpthread || !defined NOT_IN_libc
+#  ifndef __ASSEMBLER__
+extern int __local_multiple_threads attribute_hidden;
+#   define SINGLE_THREAD_P \
+  __builtin_expect (__local_multiple_threads == 0, 1)
+#  else
+#   define SINGLE_THREAD_P cmpl $0, __local_multiple_threads(%rip)
+#  endif
+
+# else
+
+#  ifndef __ASSEMBLER__
+#   define SINGLE_THREAD_P \
+  __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
+                                  header.multiple_threads) == 0, 1)
+#  else
+#   define SINGLE_THREAD_P cmpl $0, %fs:MULTIPLE_THREADS_OFFSET
+#  endif
+
+# endif
+
+#elif !defined __ASSEMBLER__
+
+# define SINGLE_THREAD_P (1)
+# define NO_CANCELLATION 1
+
+#endif
+
+#ifndef __ASSEMBLER__
+# define RTLD_SINGLE_THREAD_P \
+  __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
+                                  header.multiple_threads) == 0, 1)
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/vfork.S
new file mode 100644 (file)
index 0000000..9a9912c
--- /dev/null
@@ -0,0 +1,43 @@
+/* Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* We want an #include_next, but we are the main source file.
+   So, #include ourselves and in that incarnation we can use #include_next.  */
+#ifndef INCLUDED_SELF
+# define INCLUDED_SELF
+# include <vfork.S>
+#else
+
+# include <tcb-offsets.h>
+
+# define SAVE_PID \
+       movl    %fs:PID, %esi;                                                \
+       movl    $0x80000000, %ecx;                                            \
+       movl    %esi, %edx;                                                   \
+       negl    %edx;                                                         \
+       cmove   %ecx, %edx;                                                   \
+       movl    %edx, %fs:PID
+
+# define RESTORE_PID \
+       testq   %rax, %rax;                                                   \
+       je      1f;                                                           \
+       movl    %esi, %fs:PID;                                                \
+1:
+
+# include_next <vfork.S>
+#endif
diff --git a/libpthread/nptl/sysdeps/x86_64/Makefile.arch b/libpthread/nptl/sysdeps/x86_64/Makefile.arch
new file mode 100644 (file)
index 0000000..8ba9e9e
--- /dev/null
@@ -0,0 +1,53 @@
+# Makefile for uClibc NPTL
+#
+# Copyright (C) 2005 Steven J. Hill <sjhill@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+libpthread_CSRC = pthread_spin_lock.c
+libpthread_SSRC = pthread_spin_trylock.S
+
+CFLAGS-pthread_spin_lock.c += -D_GNU_SOURCE
+
+CFLAGS-x86_64 = $(SSP_ALL_CFLAGS)
+#CFLAGS:=$(CFLAGS:-O1=-O2)
+
+PTHREAD_ARCH_DIR := $(top_srcdir)libpthread/nptl/sysdeps/x86_64
+PTHREAD_ARCH_OUT := $(top_builddir)libpthread/nptl/sysdeps/x86_64
+PTHREAD_ARCH_OBJ := $(patsubst %.S,$(PTHREAD_ARCH_OUT)/%.o,$(libpthread_SSRC))
+PTHREAD_ARCH_OBJ += $(patsubst %.c,$(PTHREAD_ARCH_OUT)/%.o,$(libpthread_CSRC))
+
+ifeq ($(DOPIC),y)
+libpthread-a-y += $(PTHREAD_ARCH_OBJ:.o=.os)
+else
+libpthread-a-y += $(PTHREAD_ARCH_OBJ)
+endif
+libpthread-so-y += $(PTHREAD_ARCH_OBJ:.o=.oS)
+
+libpthread-nomulti-y += $(PTHREAD_ARCH_OBJ)
+
+objclean-y += nptl_arch_clean
+headers_clean-y += nptl_arch_headers_clean
+
+#
+# Create 'tcb-offsets.h' header file.
+#
+CFLAGS-tcb-offsets.c = -S
+
+$(PTHREAD_ARCH_OUT)/tcb-offsets.c: $(PTHREAD_ARCH_DIR)/tcb-offsets.sym
+       $(do_awk) $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@
+
+$(PTHREAD_ARCH_OUT)/tcb-offsets.s: $(PTHREAD_ARCH_OUT)/tcb-offsets.c
+       $(compile.c)
+
+$(PTHREAD_ARCH_OUT)/tcb-offsets.h: $(PTHREAD_ARCH_OUT)/tcb-offsets.s
+       $(do_sed) -n "s/^.*@@@name@@@\([^@]*\)@@@value@@@[^0-9Xxa-fA-F-]*\([0-9Xxa-fA-F-][0-9Xxa-fA-F-]*\).*@@@end@@@.*$\/#define \1 \2/p" $< > $@
+
+pregen-headers-$(UCLIBC_HAS_THREADS_NATIVE) += $(PTHREAD_ARCH_OUT)/tcb-offsets.h
+
+nptl_arch_headers_clean:
+       $(do_rm) $(addprefix $(PTHREAD_ARCH_OUT)/tcb-offsets., c s h)
+
+nptl_arch_clean:
+       $(do_rm) $(addprefix $(PTHREAD_ARCH_OUT)/*., o os oS)
diff --git a/libpthread/nptl/sysdeps/x86_64/dl-tls.h b/libpthread/nptl/sysdeps/x86_64/dl-tls.h
new file mode 100644 (file)
index 0000000..3e4768d
--- /dev/null
@@ -0,0 +1,29 @@
+/* Thread-local storage handling in the ELF dynamic linker.  x86-64 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.  */
+
+
+/* Type used for the representation of TLS information in the GOT.  */
+typedef struct
+{
+  unsigned long int ti_module;
+  unsigned long int ti_offset;
+} tls_index;
+
+
+extern void *__tls_get_addr (tls_index *ti);
diff --git a/libpthread/nptl/sysdeps/x86_64/jmpbuf-unwind.h b/libpthread/nptl/sysdeps/x86_64/jmpbuf-unwind.h
new file mode 100644 (file)
index 0000000..345ed55
--- /dev/null
@@ -0,0 +1,31 @@
+/* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <setjmp.h>
+#include <stdint.h>
+#include <unwind.h>
+
+#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \
+  _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj)
+
+#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \
+  ((uintptr_t) (_address) - (_adj) < (uintptr_t) (_jmpbuf)[JB_RSP] - (_adj))
+
+/* We use the normal lobngjmp for unwinding.  */
+#define __libc_unwind_longjmp(buf, val) __libc_longjmp (buf, val)
diff --git a/libpthread/nptl/sysdeps/x86_64/pthread_spin_init.c b/libpthread/nptl/sysdeps/x86_64/pthread_spin_init.c
new file mode 100644 (file)
index 0000000..5569620
--- /dev/null
@@ -0,0 +1 @@
+#include "../i386/pthread_spin_init.c"
diff --git a/libpthread/nptl/sysdeps/x86_64/pthread_spin_lock.c b/libpthread/nptl/sysdeps/x86_64/pthread_spin_lock.c
new file mode 100644 (file)
index 0000000..7cf0e0e
--- /dev/null
@@ -0,0 +1 @@
+#include "../i386/pthread_spin_lock.c"
diff --git a/libpthread/nptl/sysdeps/x86_64/pthread_spin_trylock.S b/libpthread/nptl/sysdeps/x86_64/pthread_spin_trylock.S
new file mode 100644 (file)
index 0000000..9b51335
--- /dev/null
@@ -0,0 +1,40 @@
+/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread-errnos.h>
+
+
+#ifdef UP
+# define LOCK
+#else
+# define LOCK lock
+#endif
+
+       .globl  pthread_spin_trylock
+       .type   pthread_spin_trylock,@function
+       .align  16
+pthread_spin_trylock:
+       movl    $1, %eax
+       xorl    %ecx, %ecx
+       LOCK
+       cmpxchgl %ecx, (%rdi)
+       movl    $EBUSY, %eax
+       cmovel  %ecx, %eax
+       retq
+       .size   pthread_spin_trylock,.-pthread_spin_trylock
diff --git a/libpthread/nptl/sysdeps/x86_64/pthread_spin_unlock.S b/libpthread/nptl/sysdeps/x86_64/pthread_spin_unlock.S
new file mode 100644 (file)
index 0000000..d3e13bd
--- /dev/null
@@ -0,0 +1,31 @@
+/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+       .globl  pthread_spin_unlock
+       .type   pthread_spin_unlock,@function
+       .align  16
+pthread_spin_unlock:
+       movl    $1, (%rdi)
+       xorl    %eax, %eax
+       retq
+       .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/libpthread/nptl/sysdeps/x86_64/pthreaddef.h b/libpthread/nptl/sysdeps/x86_64/pthreaddef.h
new file mode 100644 (file)
index 0000000..b33c186
--- /dev/null
@@ -0,0 +1,43 @@
+/* Copyright (C) 2002, 2003, 2007 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
+
+
+/* Location of current stack frame.  The frame pointer is not usable.  */
+#define CURRENT_STACK_FRAME \
+  ({ char *frame; __asm__ ("movq %%rsp, %0" : "=r" (frame)); frame; })
+
+
+/* XXX Until we have a better place keep the definitions here.  */
+
+/* While there is no such syscall.  */
+#define __exit_thread_inline(val) \
+  __asm__ volatile ("syscall" :: "a" (__NR_exit), "D" (val))
diff --git a/libpthread/nptl/sysdeps/x86_64/tcb-offsets.sym b/libpthread/nptl/sysdeps/x86_64/tcb-offsets.sym
new file mode 100644 (file)
index 0000000..cf86375
--- /dev/null
@@ -0,0 +1,28 @@
+#include <sysdep.h>
+#include <tls.h>
+
+RESULT                 offsetof (struct pthread, result)
+TID                    offsetof (struct pthread, tid)
+PID                    offsetof (struct pthread, pid)
+CANCELHANDLING         offsetof (struct pthread, cancelhandling)
+CLEANUP_JMP_BUF                offsetof (struct pthread, cleanup_jmp_buf)
+CLEANUP                        offsetof (struct pthread, cleanup)
+CLEANUP_PREV           offsetof (struct _pthread_cleanup_buffer, __prev)
+MUTEX_FUTEX            offsetof (pthread_mutex_t, __data.__lock)
+MULTIPLE_THREADS_OFFSET        offsetof (tcbhead_t, multiple_threads)
+POINTER_GUARD          offsetof (tcbhead_t, pointer_guard)
+VGETCPU_CACHE_OFFSET   offsetof (tcbhead_t, vgetcpu_cache)
+#ifndef __ASSUME_PRIVATE_FUTEX
+PRIVATE_FUTEX          offsetof (tcbhead_t, private_futex)
+#endif
+RTLD_SAVESPACE_SSE     offsetof (tcbhead_t, rtld_savespace_sse)
+
+-- Not strictly offsets, but these values are also used in the TCB.
+TCB_CANCELSTATE_BITMASK         CANCELSTATE_BITMASK
+TCB_CANCELTYPE_BITMASK  CANCELTYPE_BITMASK
+TCB_CANCELING_BITMASK   CANCELING_BITMASK
+TCB_CANCELED_BITMASK    CANCELED_BITMASK
+TCB_EXITING_BITMASK     EXITING_BITMASK
+TCB_CANCEL_RESTMASK     CANCEL_RESTMASK
+TCB_TERMINATED_BITMASK  TERMINATED_BITMASK
+TCB_PTHREAD_CANCELED    PTHREAD_CANCELED
diff --git a/libpthread/nptl/sysdeps/x86_64/tls.h b/libpthread/nptl/sysdeps/x86_64/tls.h
new file mode 100644 (file)
index 0000000..396ad42
--- /dev/null
@@ -0,0 +1,438 @@
+/* Definition for thread-local data handling.  nptl/x86_64 version.
+   Copyright (C) 2002-2007, 2008, 2009 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 <asm/prctl.h>        /* For ARCH_SET_FS.  */
+# include <stdbool.h>
+# include <stddef.h>
+# include <stdint.h>
+# include <stdlib.h>
+# include <sysdep.h>
+# include <bits/kernel-features.h>
+# include <bits/wordsize.h>
+# include <xmmintrin.h>
+
+
+/* Type for the dtv.  */
+typedef union dtv
+{
+  size_t counter;
+  struct
+  {
+    void *val;
+    bool is_static;
+  } pointer;
+} dtv_t;
+
+
+typedef struct
+{
+  void *tcb;           /* Pointer to the TCB.  Not necessarily the
+                          thread descriptor used by libpthread.  */
+  dtv_t *dtv;
+  void *self;          /* Pointer to the thread descriptor.  */
+  int multiple_threads;
+  int gscope_flag;
+  uintptr_t sysinfo;
+  uintptr_t stack_guard;
+  uintptr_t pointer_guard;
+  unsigned long int vgetcpu_cache[2];
+# ifndef __ASSUME_PRIVATE_FUTEX
+  int private_futex;
+# else
+  int __unused1;
+# endif
+# if __WORDSIZE == 64
+  int rtld_must_xmm_save;
+# endif
+  /* Reservation of some values for the TM ABI.  */
+  void *__private_tm[5];
+# if __WORDSIZE == 64
+  long int __unused2;
+  /* Have space for the post-AVX register size.  */
+  __m128 rtld_savespace_sse[8][4];
+
+  void *__padding[8];
+# endif
+} tcbhead_t;
+
+#else /* __ASSEMBLER__ */
+# include <tcb-offsets.h>
+#endif
+
+
+/* We require TLS support in the tools.  */
+#define HAVE_TLS_SUPPORT                1
+#define HAVE___THREAD 1
+#define HAVE_TLS_MODEL_ATTRIBUTE 1
+
+/* Signal that TLS support is available.  */
+#define USE_TLS        1
+
+/* Alignment requirement for the stack.  */
+#define STACK_ALIGN    16
+
+
+#ifndef __ASSEMBLER__
+/* Get system call information.  */
+# include <sysdep.h>
+
+
+/* Get the thread descriptor definition.  */
+# include <descr.h>
+
+#ifndef LOCK_PREFIX
+# ifdef UP
+#  define LOCK_PREFIX  /* nothing */
+# else
+#  define LOCK_PREFIX  "lock;"
+# endif
+#endif
+
+/* This is the size of the initial TCB.  Can't be just sizeof (tcbhead_t),
+   because NPTL getpid, __libc_alloca_cutoff etc. need (almost) the whole
+   struct pthread even when not linked with -lpthread.  */
+# define TLS_INIT_TCB_SIZE sizeof (struct pthread)
+
+/* Alignment requirements for the initial TCB.  */
+# define TLS_INIT_TCB_ALIGN __alignof__ (struct pthread)
+
+/* 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)
+// Normally the above would be correct  But we have to store post-AVX
+// vector registers in the TCB and we want the storage to be aligned.
+// unfortunately there isn't yet a type for these values and hence no
+// 32-byte alignment requirement.  Make this explicit, for now.
+# define TLS_TCB_ALIGN 32
+
+/* 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(dtvp) \
+  ({ struct pthread *__pd;                                                   \
+     THREAD_SETMEM (__pd, header.dtv, (dtvp)); })
+
+/* Return dtv of given thread descriptor.  */
+# define GET_DTV(descr) \
+  (((tcbhead_t *) (descr))->dtv)
+
+
+/* Macros to load from and store into segment registers.  */
+# define TLS_GET_FS() \
+  ({ int __seg; __asm__ ("movl %%fs, %0" : "=q" (__seg)); __seg; })
+# define TLS_SET_FS(val) \
+  __asm__ ("movl %0, %%fs" :: "q" (val))
+
+
+/* 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.
+
+   We have to make the syscall for both uses of the macro since the
+   address might be (and probably is) different.  */
+# define TLS_INIT_TP(thrdescr, secondcall) \
+  ({ void *_thrdescr = (thrdescr);                                           \
+     tcbhead_t *_head = _thrdescr;                                           \
+     int _result;                                                            \
+                                                                             \
+     _head->tcb = _thrdescr;                                                 \
+     /* For now the thread descriptor is at the same address.  */            \
+     _head->self = _thrdescr;                                                \
+                                                                             \
+     /* It is a simple syscall to set the %fs value for the thread.  */              \
+     __asm__ volatile ("syscall"                                                     \
+                  : "=a" (_result)                                           \
+                  : "0" ((unsigned long int) __NR_arch_prctl),               \
+                    "D" ((unsigned long int) ARCH_SET_FS),                   \
+                    "S" (_thrdescr)                                          \
+                  : "memory", "cc", "r11", "cx");                            \
+                                                                             \
+    _result ? "cannot set %fs base address for thread-local storage" : 0;     \
+  })
+
+
+/* Return the address of the dtv for the current thread.  */
+# define THREAD_DTV() \
+  ({ struct pthread *__pd;                                                   \
+     THREAD_GETMEM (__pd, header.dtv); })
+
+
+/* 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__ ("movq %%fs:%c1,%q0" : "=r" (__self)                                    \
+         : "i" (offsetof (struct pthread, header.self)));                    \
+     __self;})
+
+/* Magic for libthread_db to know how to do THREAD_SELF.  */
+# define DB_THREAD_SELF_INCLUDE  <sys/reg.h> /* For the FS constant.  */
+# define DB_THREAD_SELF CONST_THREAD_AREA (64, FS)
+
+/* Read member of the thread descriptor directly.  */
+# define THREAD_GETMEM(descr, member) \
+  ({ __typeof (descr->member) __value;                                       \
+     if (sizeof (__value) == 1)                                                      \
+       __asm__ volatile ("movb %%fs:%P2,%b0"                                 \
+                    : "=q" (__value)                                         \
+                    : "0" (0), "i" (offsetof (struct pthread, member)));     \
+     else if (sizeof (__value) == 4)                                         \
+       __asm__ volatile ("movl %%fs:%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__ volatile ("movq %%fs:%P1,%q0"                                \
+                      : "=r" (__value)                                       \
+                      : "i" (offsetof (struct pthread, member)));            \
+       }                                                                     \
+     __value; })
+
+
+/* Same as THREAD_GETMEM, but the member offset can be non-constant.  */
+# define THREAD_GETMEM_NC(descr, member, idx) \
+  ({ __typeof (descr->member[0]) __value;                                    \
+     if (sizeof (__value) == 1)                                                      \
+       __asm__ volatile ("movb %%fs:%P2(%q3),%b0"                                    \
+                    : "=q" (__value)                                         \
+                    : "0" (0), "i" (offsetof (struct pthread, member[0])),   \
+                      "r" (idx));                                            \
+     else if (sizeof (__value) == 4)                                         \
+       __asm__ volatile ("movl %%fs:%P1(,%q2,4),%0"                                  \
+                    : "=r" (__value)                                         \
+                    : "i" (offsetof (struct pthread, member[0])), "r" (idx));\
+     else                                                                    \
+       {                                                                     \
+        if (sizeof (__value) != 8)                                           \
+          /* There should not be any value with a size other than 1,         \
+             4 or 8.  */                                                     \
+          abort ();                                                          \
+                                                                             \
+        __asm__ volatile ("movq %%fs:%P1(,%q2,8),%q0"                        \
+                      : "=r" (__value)                                       \
+                      : "i" (offsetof (struct pthread, member[0])),          \
+                        "r" (idx));                                          \
+       }                                                                     \
+     __value; })
+
+
+/* Loading addresses of objects on x86-64 needs to be treated special
+   when generating PIC code.  */
+#ifdef __pic__
+# define IMM_MODE "nr"
+#else
+# define IMM_MODE "ir"
+#endif
+
+
+/* Same as THREAD_SETMEM, but the member offset can be non-constant.  */
+# define THREAD_SETMEM(descr, member, value) \
+  ({ if (sizeof (descr->member) == 1)                                        \
+       __asm__ volatile ("movb %b0,%%fs:%P1" :                               \
+                    : "iq" (value),                                          \
+                      "i" (offsetof (struct pthread, member)));              \
+     else if (sizeof (descr->member) == 4)                                   \
+       __asm__ volatile ("movl %0,%%fs:%P1" :                                \
+                    : IMM_MODE (value),                                      \
+                      "i" (offsetof (struct pthread, member)));              \
+     else                                                                    \
+       {                                                                     \
+        if (sizeof (descr->member) != 8)                                     \
+          /* There should not be any value with a size other than 1,         \
+             4 or 8.  */                                                     \
+          abort ();                                                          \
+                                                                             \
+        __asm__ volatile ("movq %q0,%%fs:%P1" :                                      \
+                      : IMM_MODE ((unsigned long int) value),                \
+                        "i" (offsetof (struct pthread, member)));            \
+       }})
+
+
+/* Set member of the thread descriptor directly.  */
+# define THREAD_SETMEM_NC(descr, member, idx, value) \
+  ({ if (sizeof (descr->member[0]) == 1)                                     \
+       __asm__ volatile ("movb %b0,%%fs:%P1(%q2)" :                                  \
+                    : "iq" (value),                                          \
+                      "i" (offsetof (struct pthread, member[0])),            \
+                      "r" (idx));                                            \
+     else if (sizeof (descr->member[0]) == 4)                                \
+       __asm__ volatile ("movl %0,%%fs:%P1(,%q2,4)" :                        \
+                    : IMM_MODE (value),                                      \
+                      "i" (offsetof (struct pthread, member[0])),            \
+                      "r" (idx));                                            \
+     else                                                                    \
+       {                                                                     \
+        if (sizeof (descr->member[0]) != 8)                                  \
+          /* There should not be any value with a size other than 1,         \
+             4 or 8.  */                                                     \
+          abort ();                                                          \
+                                                                             \
+        __asm__ volatile ("movq %q0,%%fs:%P1(,%q2,8)" :                              \
+                      : IMM_MODE ((unsigned long int) value),                \
+                        "i" (offsetof (struct pthread, member[0])),          \
+                        "r" (idx));                                          \
+       }})
+
+
+/* Atomic compare and exchange on TLS, returning old value.  */
+# define THREAD_ATOMIC_CMPXCHG_VAL(descr, member, newval, oldval) \
+  ({ __typeof (descr->member) __ret;                                         \
+     __typeof (oldval) __old = (oldval);                                     \
+     if (sizeof (descr->member) == 4)                                        \
+       __asm__ volatile (LOCK_PREFIX "cmpxchgl %2, %%fs:%P3"                 \
+                    : "=a" (__ret)                                           \
+                    : "0" (__old), "r" (newval),                             \
+                      "i" (offsetof (struct pthread, member)));              \
+     else                                                                    \
+       /* Not necessary for other sizes in the moment.  */                   \
+       abort ();                                                             \
+     __ret; })
+
+
+/* Atomic logical and.  */
+# define THREAD_ATOMIC_AND(descr, member, val) \
+  (void) ({ if (sizeof ((descr)->member) == 4)                               \
+             __asm__ volatile (LOCK_PREFIX "andl %1, %%fs:%P0"               \
+                           :: "i" (offsetof (struct pthread, member)),       \
+                              "ir" (val));                                   \
+           else                                                              \
+             /* Not necessary for other sizes in the moment.  */             \
+             abort (); })
+
+
+/* Atomic set bit.  */
+# define THREAD_ATOMIC_BIT_SET(descr, member, bit) \
+  (void) ({ if (sizeof ((descr)->member) == 4)                               \
+             __asm__ volatile (LOCK_PREFIX "orl %1, %%fs:%P0"                \
+                           :: "i" (offsetof (struct pthread, member)),       \
+                              "ir" (1 << (bit)));                            \
+           else                                                              \
+             /* Not necessary for other sizes in the moment.  */             \
+             abort (); })
+
+
+# define CALL_THREAD_FCT(descr) \
+  ({ void *__res;                                                            \
+     __asm__ volatile ("movq %%fs:%P2, %%rdi\n\t"                                    \
+                  "callq *%%fs:%P1"                                          \
+                  : "=a" (__res)                                             \
+                  : "i" (offsetof (struct pthread, start_routine)),          \
+                    "i" (offsetof (struct pthread, arg))                     \
+                  : "di", "si", "cx", "dx", "r8", "r9", "r10", "r11",        \
+                    "memory", "cc");                                         \
+     __res; })
+
+
+/* Set the stack guard field in TCB head.  */
+# define THREAD_SET_STACK_GUARD(value) \
+    THREAD_SETMEM (THREAD_SELF, header.stack_guard, value)
+# define THREAD_COPY_STACK_GUARD(descr) \
+    ((descr)->header.stack_guard                                             \
+     = THREAD_GETMEM (THREAD_SELF, header.stack_guard))
+
+
+/* Set the pointer guard field in the TCB head.  */
+# define THREAD_SET_POINTER_GUARD(value) \
+  THREAD_SETMEM (THREAD_SELF, header.pointer_guard, value)
+# define THREAD_COPY_POINTER_GUARD(descr) \
+  ((descr)->header.pointer_guard                                             \
+   = THREAD_GETMEM (THREAD_SELF, header.pointer_guard))
+
+
+/* Get and set the global scope generation counter in the TCB head.  */
+# define THREAD_GSCOPE_FLAG_UNUSED 0
+# define THREAD_GSCOPE_FLAG_USED   1
+# define THREAD_GSCOPE_FLAG_WAIT   2
+# define THREAD_GSCOPE_RESET_FLAG() \
+  do                                                                         \
+    { int __res;                                                             \
+      __asm__ volatile ("xchgl %0, %%fs:%P1"                                 \
+                   : "=r" (__res)                                            \
+                   : "i" (offsetof (struct pthread, header.gscope_flag)),    \
+                     "0" (THREAD_GSCOPE_FLAG_UNUSED));                       \
+      if (__res == THREAD_GSCOPE_FLAG_WAIT)                                  \
+       lll_futex_wake (&THREAD_SELF->header.gscope_flag, 1, LLL_PRIVATE);    \
+    }                                                                        \
+  while (0)
+# define THREAD_GSCOPE_SET_FLAG() \
+  THREAD_SETMEM (THREAD_SELF, header.gscope_flag, THREAD_GSCOPE_FLAG_USED)
+# define THREAD_GSCOPE_WAIT() \
+  GL(dl_wait_lookup_done) ()
+
+
+# ifdef SHARED
+/* Defined in dl-trampoline.S.  */
+extern void _dl_x86_64_save_sse (void);
+extern void _dl_x86_64_restore_sse (void);
+
+# define RTLD_CHECK_FOREIGN_CALL \
+  (THREAD_GETMEM (THREAD_SELF, header.rtld_must_xmm_save) != 0)
+
+/* NB: Don't use the xchg operation because that would imply a lock
+   prefix which is expensive and unnecessary.  The cache line is also
+   not contested at all.  */
+#  define RTLD_ENABLE_FOREIGN_CALL \
+  int old_rtld_must_xmm_save = THREAD_GETMEM (THREAD_SELF,                   \
+                                             header.rtld_must_xmm_save);     \
+  THREAD_SETMEM (THREAD_SELF, header.rtld_must_xmm_save, 1)
+
+#  define RTLD_PREPARE_FOREIGN_CALL \
+  do if (THREAD_GETMEM (THREAD_SELF, header.rtld_must_xmm_save))             \
+    {                                                                        \
+      _dl_x86_64_save_sse ();                                                \
+      THREAD_SETMEM (THREAD_SELF, header.rtld_must_xmm_save, 0);             \
+    }                                                                        \
+  while (0)
+
+#  define RTLD_FINALIZE_FOREIGN_CALL \
+  do {                                                                       \
+    if (THREAD_GETMEM (THREAD_SELF, header.rtld_must_xmm_save) == 0)         \
+      _dl_x86_64_restore_sse ();                                             \
+    THREAD_SETMEM (THREAD_SELF, header.rtld_must_xmm_save,                   \
+                  old_rtld_must_xmm_save);                                   \
+  } while (0)
+# endif
+
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* tls.h */
diff --git a/libpthread/nptl/unwind.c b/libpthread/nptl/unwind.c
new file mode 100644 (file)
index 0000000..9a35695
--- /dev/null
@@ -0,0 +1,176 @@
+/* Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>
+   and Richard Henderson <rth@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <setjmp.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "pthreadP.h"
+#include <jmpbuf-unwind.h>
+
+#ifdef HAVE_FORCED_UNWIND
+
+#ifdef _STACK_GROWS_DOWN
+# define FRAME_LEFT(frame, other, adj) \
+  ((uintptr_t) frame - adj >= (uintptr_t) other - adj)
+#elif _STACK_GROWS_UP
+# define FRAME_LEFT(frame, other, adj) \
+  ((uintptr_t) frame - adj <= (uintptr_t) other - adj)
+#else
+# error "Define either _STACK_GROWS_DOWN or _STACK_GROWS_UP"
+#endif
+
+static _Unwind_Reason_Code
+unwind_stop (int version, _Unwind_Action actions,
+            _Unwind_Exception_Class exc_class,
+            struct _Unwind_Exception *exc_obj,
+            struct _Unwind_Context *context, void *stop_parameter)
+{
+  struct pthread_unwind_buf *buf = stop_parameter;
+  struct pthread *self = THREAD_SELF;
+  struct _pthread_cleanup_buffer *curp = THREAD_GETMEM (self, cleanup);
+  int do_longjump = 0;
+
+  /* Adjust all pointers used in comparisons, so that top of thread's
+     stack is at the top of address space.  Without that, things break
+     if stack is allocated above the main stack.  */
+  uintptr_t adj = (uintptr_t) self->stackblock + self->stackblock_size;
+
+  /* Do longjmp if we're at "end of stack", aka "end of unwind data".
+     We assume there are only C frame without unwind data in between
+     here and the jmp_buf target.  Otherwise simply note that the CFA
+     of a function is NOT within it's stack frame; it's the SP of the
+     previous frame.  */
+  if ((actions & _UA_END_OF_STACK)
+      || ! _JMPBUF_CFA_UNWINDS_ADJ (buf->cancel_jmp_buf[0].jmp_buf, context,
+                                   adj))
+    do_longjump = 1;
+
+  if (__builtin_expect (curp != NULL, 0))
+    {
+      /* Handle the compatibility stuff.  Execute all handlers
+        registered with the old method which would be unwound by this
+        step.  */
+      struct _pthread_cleanup_buffer *oldp = buf->priv.data.cleanup;
+      void *cfa = (void *) _Unwind_GetCFA (context);
+
+      if (curp != oldp && (do_longjump || FRAME_LEFT (cfa, curp, adj)))
+       {
+         do
+           {
+             /* Pointer to the next element.  */
+             struct _pthread_cleanup_buffer *nextp = curp->__prev;
+
+             /* Call the handler.  */
+             curp->__routine (curp->__arg);
+
+             /* To the next.  */
+             curp = nextp;
+           }
+         while (curp != oldp
+                && (do_longjump || FRAME_LEFT (cfa, curp, adj)));
+
+         /* Mark the current element as handled.  */
+         THREAD_SETMEM (self, cleanup, curp);
+       }
+    }
+
+  if (do_longjump)
+    __libc_unwind_longjmp ((struct __jmp_buf_tag *) buf->cancel_jmp_buf, 1);
+
+  return _URC_NO_REASON;
+}
+
+
+static void
+unwind_cleanup (_Unwind_Reason_Code reason, struct _Unwind_Exception *exc)
+{
+  /* When we get here a C++ catch block didn't rethrow the object.  We
+     cannot handle this case and therefore abort.  */
+# define STR_N_LEN(str) str, strlen (str)
+  INTERNAL_SYSCALL_DECL (err);
+  INTERNAL_SYSCALL (write, err, 3, STDERR_FILENO,
+                   STR_N_LEN ("FATAL: exception not rethrown\n"));
+  abort ();
+}
+
+#endif /* have forced unwind */
+
+
+void
+__cleanup_fct_attribute __attribute ((noreturn))
+__pthread_unwind (__pthread_unwind_buf_t *buf)
+{
+  struct pthread_unwind_buf *ibuf = (struct pthread_unwind_buf *) buf;
+  struct pthread *self = THREAD_SELF;
+
+#ifdef HAVE_FORCED_UNWIND
+  /* This is not a catchable exception, so don't provide any details about
+     the exception type.  We do need to initialize the field though.  */
+  THREAD_SETMEM (self, exc.exception_class, 0);
+  THREAD_SETMEM (self, exc.exception_cleanup, unwind_cleanup);
+
+  _Unwind_ForcedUnwind (&self->exc, unwind_stop, ibuf);
+#else
+  /* Handle the compatibility stuff first.  Execute all handlers
+     registered with the old method.  We don't execute them in order,
+     instead, they will run first.  */
+  struct _pthread_cleanup_buffer *oldp = ibuf->priv.data.cleanup;
+  struct _pthread_cleanup_buffer *curp = THREAD_GETMEM (self, cleanup);
+
+  if (curp != oldp)
+    {
+      do
+       {
+         /* Pointer to the next element.  */
+         struct _pthread_cleanup_buffer *nextp = curp->__prev;
+
+         /* Call the handler.  */
+         curp->__routine (curp->__arg);
+
+         /* To the next.  */
+         curp = nextp;
+       }
+      while (curp != oldp);
+
+      /* Mark the current element as handled.  */
+      THREAD_SETMEM (self, cleanup, curp);
+    }
+
+  /* We simply jump to the registered setjmp buffer.  */
+  __libc_unwind_longjmp ((struct __jmp_buf_tag *) ibuf->cancel_jmp_buf, 1);
+#endif
+  /* NOTREACHED */
+
+  /* We better do not get here.  */
+  abort ();
+}
+hidden_def (__pthread_unwind)
+
+
+void
+__cleanup_fct_attribute __attribute ((noreturn))
+__pthread_unwind_next (__pthread_unwind_buf_t *buf)
+{
+  struct pthread_unwind_buf *ibuf = (struct pthread_unwind_buf *) buf;
+
+  __pthread_unwind ((__pthread_unwind_buf_t *) ibuf->priv.data.prev);
+}
+hidden_def (__pthread_unwind_next)
diff --git a/libpthread/nptl/vars.c b/libpthread/nptl/vars.c
new file mode 100644 (file)
index 0000000..1e1a3cf
--- /dev/null
@@ -0,0 +1,43 @@
+/* Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthreadP.h>
+#include <stdlib.h>
+#include <tls.h>
+#include <unistd.h>
+
+/* Default stack size.  */
+size_t __default_stacksize attribute_hidden
+#ifdef SHARED
+;
+#else
+  = PTHREAD_STACK_MIN;
+#endif
+
+/* Flag whether the machine is SMP or not.  */
+int __is_smp attribute_hidden;
+
+#ifndef TLS_MULTIPLE_THREADS_IN_TCB
+/* Variable set to a nonzero value if more than one thread runs or ran.  */
+int __pthread_multiple_threads attribute_hidden;
+#endif
+
+/* Table of the key information.  */
+struct pthread_key_struct __pthread_keys[PTHREAD_KEYS_MAX]
+  __attribute__ ((nocommon));
+hidden_data_def (__pthread_keys)
diff --git a/libpthread/nptl/version.c b/libpthread/nptl/version.c
new file mode 100644 (file)
index 0000000..b69556e
--- /dev/null
@@ -0,0 +1,45 @@
+/* Copyright (C) 2002, 2003, 2005, 2006 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <unistd.h>
+#include <sysdep.h>
+
+
+static const char banner[] =
+#include "banner.h"
+"Copyright (C) 2006 Free Software Foundation, Inc.\n\
+This is free software; see the source for copying conditions.\n\
+There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A\n\
+PARTICULAR PURPOSE.\n"
+#ifdef HAVE_FORCED_UNWIND
+"Forced unwind support included.\n"
+#endif
+;
+
+
+extern void __nptl_main (void) __attribute__ ((noreturn));
+void
+__nptl_main (void)
+{
+  INTERNAL_SYSCALL_DECL (err);
+  INTERNAL_SYSCALL (write, err, 3, STDOUT_FILENO, (const char *) banner,
+                   sizeof banner - 1);
+
+  _exit (0);
+}
diff --git a/libpthread/nptl/version.h b/libpthread/nptl/version.h
new file mode 100644 (file)
index 0000000..f294f5c
--- /dev/null
@@ -0,0 +1 @@
+#define VERSION __stringify(__UCLIBC_MAJOR__) "." __stringify(__UCLIBC_MINOR__) "." __stringify(__UCLIBC_SUBLEVEL__)
diff --git a/libpthread/nptl_db/ChangeLog b/libpthread/nptl_db/ChangeLog
new file mode 100644 (file)
index 0000000..52c8491
--- /dev/null
@@ -0,0 +1,207 @@
+2004-09-09  Roland McGrath  <roland@redhat.com>
+
+       * td_ta_map_lwp2thr.c (td_ta_map_lwp2thr): Don't abort if inferior's
+       descriptor is bogus.
+
+2004-05-27  Roland McGrath  <roland@redhat.com>
+
+       * td_thr_validate.c: When we find no threads and the inferior appears
+       uninitialized, validate the main thread as a special case.
+
+2004-05-01  Jakub Jelinek  <jakub@redhat.com>
+
+       * thread_dbP.h (LOG): Use write instead of __libc_write.
+
+2004-04-03  Ulrich Drepper  <drepper@redhat.com>
+
+       * td_ta_set_event.c (td_ta_set_event): Initialize copy to avoid
+       warnings.
+
+       * td_ta_thr_iter.c (td_ta_thr_iter): Initialize list to avoid warning.
+       * td_ta_clear_event.c (td_ta_clear_event): Initialize eventmask to
+       avoid warning.
+       * td_ta_set_event.c (td_ta_set_event): Likewise.
+
+2004-03-24  Roland McGrath  <roland@redhat.com>
+
+       * fetch-value.c (_td_locate_field): Cast DB_DESC_OFFSET to int32_t.
+       * thread_dbP.h (DB_DESC_OFFSET): Remove cast from definition.
+
+2004-03-13  Jakub Jelinek  <jakub@redhat.com>
+
+       * db_info.c: Don't use TLS_TP_OFFSET in the #if, but
+       TLS_TCB_SIZE == 0 ?: in the DESC macro.
+
+2004-03-12  Roland McGrath  <roland@redhat.com>
+
+       * db_info.c [TLS_DTV_AT_TP && TLS_TP_OFFSET > 0]
+       (_thread_db_pthread_dtvp): Define differently for this case (PowerPC).
+
+2003-12-11  Ulrich Weigand  <uweigand@de.ibm.com>
+
+       * db_info.c (REGISTER): Add bit size of thread register as second
+       parameter to REGISTER macro.
+
+2003-12-02  Roland McGrath  <roland@redhat.com>
+
+       * thread_dbP.h (DB_FUNCTION): New macro.
+       * structs.def: Use it for __nptl_create_event and __nptl_death_event.
+       * db_info.c (DB_FUNCTION): New macro.
+       * td_symbol_list.c (DB_FUNCTION): New macro, prepend "." to symbol
+       name under [HAVE_ASM_GLOBAL_DOT_NAME].
+       (td_lookup) [HAVE_ASM_GLOBAL_DOT_NAME]: If lookup fails with PS_NOSYM
+       and name starts with a dot, try it without the dot.
+
+2003-09-08  Roland McGrath  <roland@redhat.com>
+
+       * td_thr_get_info.c (td_thr_get_info): Cast th_unique to thread_t.
+
+2003-08-22  Roland McGrath  <roland@redhat.com>
+
+       * fetch-value.c (_td_check_sizeof, _td_locate_field): Return
+       TD_NOCAPAB for PS_NOSYM, instead of vanilla TD_ERR.
+       * td_thr_tls_get_addr.c (td_thr_tls_get_addr): Return TD_NOAPLIC when
+       DB_GET_FIELD returns TD_NOCAPAB.
+
+       * thread_db.h (td_thr_tls_get_addr): Use psaddr_t in signature.
+       * structs.def [USE_TLS]: Add DB_STRUCT_FIELD (link_map, l_tls_modid).
+       * db_info.c (link_map): Typedef it.
+       * td_thr_tls_get_addr.c (td_thr_tls_get_addr): Rewritten.
+
+2003-08-14  Roland McGrath  <roland@redhat.com>
+
+       * thread_dbP.h: Mostly rewritten with many new macros and decls.
+       * td_ta_new.c (td_ta_new): Don't cache a lot of symbol values.
+       * structs.def: New file.
+       * db_info.c: New file.
+       * td_symbol_list.c (symbol_list_arr): Define with structs.def macros.
+       * td_ta_clear_event.c: Rewritten.
+       * td_ta_event_addr.c: Rewritten.
+       * td_ta_event_getmsg.c: Rewritten.
+       * td_ta_get_nthreads.c: Rewritten.
+       * td_ta_map_lwp2thr.c: New file.
+       * td_ta_set_event.c: Rewritten.
+       * td_ta_thr_iter.c: Rewritten.
+       * td_ta_tsd_iter.c: Rewritten.
+       * td_thr_clear_event.c: Rewritten.
+       * td_thr_event_enable.c: Rewritten.
+       * td_thr_event_getmsg.c: Rewritten.
+       * td_thr_get_info.c: Rewritten.
+       * td_thr_getfpregs.c: Rewritten.
+       * td_thr_getgregs.c: Rewritten.
+       * td_thr_set_event.c: Rewritten.
+       * td_thr_setfpregs.c: Rewritten.
+       * td_thr_setgregs.c: Rewritten.
+       * td_thr_tlsbase.c: Rewritten.
+       * td_thr_tsd.c: Rewritten.
+       * td_thr_validate.c: Rewritten.
+       * Makefile (distribute): Add them.
+       * fetch-value.c: New file.
+       * Makefile (libthread_db-routines): Add it.
+
+       * thread_db.h (td_err_e): Comment fix.
+
+2003-08-05  Roland McGrath  <roland@redhat.com>
+
+       * thread_dbP.h (td_lookup): Add attribute_hidden to decl.
+
+2003-08-04  Roland McGrath  <roland@redhat.com>
+
+       * td_ta_clear_event.c (td_ta_clear_event): Fix sizes in ps_* calls.
+
+2003-06-23  Roland McGrath  <roland@redhat.com>
+
+       * proc_service.h: Cosmetic and comment fixes.
+
+2003-06-19  Roland McGrath  <roland@redhat.com>
+
+       * td_thr_event_enable.c (td_thr_event_enable): Use proper type `bool'
+       for value written into inferior's `report_events'.
+
+2003-03-18  Roland McGrath  <roland@redhat.com>
+
+       * td_thr_event_getmsg.c (td_thr_event_getmsg): Splice the thread out
+       of the ->nextevent linkage.
+
+       * td_ta_event_getmsg.c (td_ta_event_getmsg): Runtime error instead of
+       assert for reading TD_EVENT_NONE.  Clear the event buffer after
+       reading it.  Add a sanity check for foo->nextevent = foo.
+
+2003-03-15  Roland McGrath  <roland@redhat.com>
+
+       * thread_db.h (td_err_e): Add TD_NOTLS and TD_TLSDEFER.
+       (td_thr_tlsbase): Declare it.
+       * td_thr_tlsbase.c: New file.
+       * Makefile (libthread_db-routines): Add it.
+       * Versions (libthread_db: GLIBC_2.3.3): New set, add td_thr_tlsbase.
+       * td_thr_tls_get_addr.c (td_thr_tls_get_addr): Use td_thr_tlsbase.
+
+2003-03-14  Roland McGrath  <roland@redhat.com>
+
+       * td_thr_tls_get_addr.c (td_thr_tls_get_addr): Use `header.' prefix.
+
+2003-03-10  Roland McGrath  <roland@redhat.com>
+
+       * td_ta_thr_iter.c (iterate_thread_list): Don't use `header.data.'
+       prefix for `struct pthread' members.
+       * td_thr_validate.c (check_thread_list): Likewise.
+       * td_thr_tls_get_addr.c (td_thr_tls_get_addr): Likewise.
+
+2003-03-03  Roland McGrath  <roland@redhat.com>
+
+       * td_thr_tls_get_addr.c (td_thr_tls_get_addr): Handle TLS_DTV_AT_TP.
+
+2003-02-15  Ulrich Drepper  <drepper@redhat.com>
+
+       * td_symbol_list.c: New symbol name for SYM_PTHREAD_NTHREADS.
+
+2003-01-07  Jakub Jelinek  <jakub@redhat.com>
+
+       * td_ta_event_getmsg.c: Include assert.h.
+
+-2003-01-05  Ulrich Drepper  <drepper@redhat.com>
+
+       * Makefile (libthread_db.so-no-z-defs): Define.
+
+2003-01-03  Roland McGrath  <roland@redhat.com>
+
+       * td_thr_setgregs.c (td_thr_setgregs): *_BIT -> *_BITMASK
+       * td_thr_setfpregs.c (td_thr_setfpregs): Likewise.
+       * td_thr_get_info.c (td_thr_get_info): Likewise.
+       * td_thr_getgregs.c (td_thr_getgregs): Likewise.
+       * td_thr_getfpregs.c (td_thr_getfpregs): Likewise.
+       * td_ta_thr_iter.c (iterate_thread_list): Likewise.
+
+2002-12-12  Roland McGrath  <roland@redhat.com>
+
+       * td_ta_thr_iter.c (iterate_thread_list): Handle special case of
+       uninitialized __stack_user (zeros), hard-wire just the main thread.
+
+       * td_thr_get_info.c (td_thr_get_info): Fix ti_lid initialization.
+
+2002-12-06  Roland McGrath  <roland@redhat.com>
+
+       * td_ta_event_getmsg.c (td_ta_event_getmsg): Write the NEXT pointer
+       into the inferior's __pthread_last_event variable, not a word from
+       an inferior address used in the parent.  Pass the address of a
+       null word to ps_pdwrite, not a null pointer.
+
+2002-12-04  Roland McGrath  <roland@redhat.com>
+
+       * td_thr_get_info.c (td_thr_get_info): ti_tid is pthread_t, not a PID.
+
+       * thread_db.h (td_thrinfo_t): Comment fix.
+
+       * td_ta_map_lwp2thr.c: Moved to ../nptl/sysdeps/i386/.
+
+2002-12-04  Ulrich Drepper  <drepper@redhat.com>
+
+       * td_ta_thr_iter.c (iterate_thread_list): At end of iteration read
+       pointer to the next element from inferior.
+
+2002-12-02  Roland McGrath  <roland@redhat.com>
+
+       * td_symbol_list.c (symbol_list_arr): pthread_keys -> __pthread_keys
+
+       * td_ta_map_lwp2thr.c (td_ta_map_lwp2thr): Fetch inferior registers to
+       see its %gs value, not our own.
diff --git a/libpthread/nptl_db/Makefile b/libpthread/nptl_db/Makefile
new file mode 100644 (file)
index 0000000..f910021
--- /dev/null
@@ -0,0 +1,13 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000-2005 Erik Andersen <andersen@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+top_srcdir=../../
+top_builddir=../../
+include $(top_builddir)Rules.mak
+all: libs
+include Makefile.in
+include $(top_srcdir)Makerules
diff --git a/libpthread/nptl_db/Makefile.in b/libpthread/nptl_db/Makefile.in
new file mode 100644 (file)
index 0000000..3eaded5
--- /dev/null
@@ -0,0 +1,71 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000-2005 Erik Andersen <andersen@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+subdirs += libpthread/nptl/nptl_db
+
+# Get the thread include dependencies and shared object name
+CFLAGS-nptl_db := -DLIBPTHREAD_SO="\"libpthread.so.$(MAJOR_VERSION)\""
+CFLAGS-nptl_db += -I$(top_srcdir)libpthread/nptl -D_GNU_SOURCE
+CFLAGS-nptl_db += -DIS_IN_libthread_db=1 -std=gnu99 -I$(top_srcdir)ldso/include
+
+LDFLAGS-libthread_db.so := $(LDFLAGS_NOSTRIP) -s --warn-unresolved-symbols
+
+LIBS-libthread_db.so := $(LIBS)
+
+libthread_db_FULL_NAME := libthread_db-$(VERSION).so
+
+libthread_db_DIR := $(top_srcdir)libpthread/nptl_db
+libthread_db_OUT := $(top_builddir)libpthread/nptl_db
+
+libthread_db_SRC := $(wildcard $(libthread_db_DIR)/td_*.c)     \
+                   $(libthread_db_DIR)/fetch-value.c
+
+libthread_db_OBJ := $(patsubst $(libthread_db_DIR)/%.c,$(libthread_db_OUT)/%.o,$(libthread_db_SRC))
+
+libthread_db-so-y := $(libthread_db_OBJ:.o=.oS)
+ifeq ($(DOPIC),y)
+libthread_db-a-y := $(libthread_db-so-y)
+else
+libthread_db-a-y := $(libthread_db_OBJ)
+endif
+
+libthread_db-multi-y := $(libthread_db_SRC)
+
+lib-a-$(PTHREADS_DEBUG_SUPPORT) += $(top_builddir)lib/libthread_db.a
+lib-so-$(PTHREADS_DEBUG_SUPPORT) += $(top_builddir)lib/libthread_db.so
+objclean-y += libthread_db_clean
+headers-$(PTHREADS_DEBUG_SUPPORT) += $(nptl_db_headers)
+headers_clean-y += nptl_db_headers_clean
+
+ifeq ($(DOPIC),y)
+$(top_builddir)lib/libthread_db.so: $(top_builddir)lib/libthread_db.a $(libc)
+else
+$(top_builddir)lib/libthread_db.so: $(libthread_db_OUT)/libthread_db_so.a $(libc)
+endif
+       $(call link.so,$(libthread_db_FULL_NAME),1)
+
+$(libthread_db_OUT)/libthread_db_so.a: $(libthread_db-so-y)
+       $(Q)$(RM) $@
+       $(do_strip)
+       $(do_ar)
+
+$(top_builddir)lib/libthread_db.a: $(libthread_db-a-y)
+       $(Q)$(INSTALL) -d $(dir $@)
+       $(Q)$(RM) $@
+       $(do_strip)
+       $(do_ar)
+
+$(top_builddir)include/thread_db.h:
+       $(do_ln) $(call rel_srcdir)$(PTDIR)_db/$(@F) $@
+
+nptl_db_headers:= $(top_builddir)include/thread_db.h
+
+nptl_db_headers_clean:
+       $(do_rm) $(nptl_db_headers)
+
+libthread_db_clean:
+       $(do_rm) $(addprefix $(libthread_db_OUT)/*., o oS a)
diff --git a/libpthread/nptl_db/db_info.c b/libpthread/nptl_db/db_info.c
new file mode 100644 (file)
index 0000000..5aec152
--- /dev/null
@@ -0,0 +1,103 @@
+/* This file is included by pthread_create.c to define in libpthread
+   all the magic symbols required by libthread_db.
+
+   Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+#include <tls.h>
+
+typedef struct pthread pthread;
+typedef struct pthread_key_struct pthread_key_struct;
+typedef struct pthread_key_data pthread_key_data;
+typedef struct
+{
+  struct pthread_key_data data[PTHREAD_KEY_2NDLEVEL_SIZE];
+}
+pthread_key_data_level2;
+
+typedef struct
+{
+  union dtv dtv[UINT32_MAX / 2 / sizeof (union dtv)]; /* No constant bound.  */
+} dtv;
+
+typedef struct link_map link_map;
+
+
+#define schedparam_sched_priority schedparam.sched_priority
+
+#define eventbuf_eventmask eventbuf.eventmask
+#define eventbuf_eventmask_event_bits eventbuf.eventmask.event_bits
+
+#define DESC(name, offset, obj) \
+  DB_DEFINE_DESC (name, 8 * sizeof (obj), 1, offset);
+#define ARRAY_DESC(name, offset, obj) \
+  DB_DEFINE_DESC (name, \
+                 8 * sizeof (obj)[0], sizeof (obj) / sizeof (obj)[0], \
+                 offset);
+
+#if defined(TLS_TCB_AT_TP)
+# define dtvp header.dtv
+#elif defined(TLS_DTV_AT_TP)
+/* Special case hack.  If TLS_TCB_SIZE == 0 (on PowerPC), there is no TCB
+   containing the DTV at the TP, but actually the TCB lies behind the TP,
+   i.e. at the very end of the area covered by TLS_PRE_TCB_SIZE.  */
+DESC (_thread_db_pthread_dtvp,
+      TLS_PRE_TCB_SIZE + offsetof (tcbhead_t, dtv)
+      - (TLS_TCB_SIZE == 0 ? sizeof (tcbhead_t) : 0), union dtv)
+#endif
+
+
+#define DB_STRUCT(type) \
+  const uint32_t _thread_db_sizeof_##type = sizeof (type);
+#define DB_STRUCT_FIELD(type, field) \
+  DESC (_thread_db_##type##_##field, \
+       offsetof (type, field), ((type *) 0)->field)
+#define DB_STRUCT_ARRAY_FIELD(type, field) \
+  ARRAY_DESC (_thread_db_##type##_##field, \
+             offsetof (type, field), ((type *) 0)->field)
+#define DB_VARIABLE(name) DESC (_thread_db_##name, 0, name)
+#define DB_ARRAY_VARIABLE(name) ARRAY_DESC (_thread_db_##name, 0, name)
+#define DB_SYMBOL(name)        /* Nothing.  */
+#define DB_FUNCTION(name) /* Nothing.  */
+#include "structs.def"
+#undef DB_STRUCT
+#undef DB_STRUCT_FIELD
+#undef DB_SYMBOL
+#undef DB_FUNCTION
+#undef DB_VARIABLE
+#undef DESC
+
+
+
+#ifdef DB_THREAD_SELF
+# ifdef DB_THREAD_SELF_INCLUDE
+#  include DB_THREAD_SELF_INCLUDE
+# endif
+
+/* This macro is defined in the machine's tls.h using the three below.  */
+# define CONST_THREAD_AREA(bits, value) \
+  const uint32_t _thread_db_const_thread_area = (value);
+# define REGISTER_THREAD_AREA(bits, regofs, scale) \
+  DB_DEFINE_DESC (_thread_db_register##bits##_thread_area, \
+                 bits, (scale), (regofs));
+# define REGISTER(bits, size, regofs, bias) \
+  DB_DEFINE_DESC (_thread_db_register##bits, size, (uint32_t)(bias), (regofs));
+
+DB_THREAD_SELF
+#endif
diff --git a/libpthread/nptl_db/fetch-value.c b/libpthread/nptl_db/fetch-value.c
new file mode 100644 (file)
index 0000000..0d9bb0e
--- /dev/null
@@ -0,0 +1,284 @@
+/* Helper routines for libthread_db.
+   Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+#include <byteswap.h>
+#include <assert.h>
+
+td_err_e
+_td_check_sizeof (td_thragent_t *ta, uint32_t *sizep, int sizep_name)
+{
+  if (*sizep == 0)
+    {
+      psaddr_t descptr;
+      ps_err_e err = td_lookup (ta->ph, sizep_name, &descptr);
+      if (err == PS_NOSYM)
+       return TD_NOCAPAB;
+      if (err == PS_OK)
+       err = ps_pdread (ta->ph, descptr, sizep, sizeof *sizep);
+      if (err != PS_OK)
+       return TD_ERR;
+      if (*sizep & 0xff000000U)
+       *sizep = bswap_32 (*sizep);
+    }
+  return TD_OK;
+}
+
+td_err_e
+_td_locate_field (td_thragent_t *ta,
+                 db_desc_t desc, int descriptor_name,
+                 psaddr_t idx, psaddr_t *address)
+{
+  uint32_t elemsize;
+
+  if (DB_DESC_SIZE (desc) == 0)
+    {
+      /* Read the information about this field from the inferior.  */
+      psaddr_t descptr;
+      ps_err_e err = td_lookup (ta->ph, descriptor_name, &descptr);
+      if (err == PS_NOSYM)
+       return TD_NOCAPAB;
+      if (err == PS_OK)
+       err = ps_pdread (ta->ph, descptr, desc, DB_SIZEOF_DESC);
+      if (err != PS_OK)
+       return TD_ERR;
+      if (DB_DESC_SIZE (desc) == 0)
+       return TD_DBERR;
+      if (DB_DESC_SIZE (desc) & 0xff000000U)
+       {
+         /* Byte-swap these words, though we leave the size word
+            in native order as the handy way to distinguish.  */
+         DB_DESC_OFFSET (desc) = bswap_32 (DB_DESC_OFFSET (desc));
+         DB_DESC_NELEM (desc) = bswap_32 (DB_DESC_NELEM (desc));
+       }
+    }
+
+  if (idx != 0 && idx - (psaddr_t) 0 > DB_DESC_NELEM (desc))
+    /* This is an internal indicator to callers with nonzero IDX
+       that the IDX value is too big.  */
+    return TD_NOAPLIC;
+
+  elemsize = DB_DESC_SIZE (desc);
+  if (elemsize & 0xff000000U)
+    elemsize = bswap_32 (elemsize);
+
+  *address += (int32_t) DB_DESC_OFFSET (desc);
+  *address += (elemsize / 8 * (idx - (psaddr_t) 0));
+  return TD_OK;
+}
+
+td_err_e
+_td_fetch_value (td_thragent_t *ta,
+                db_desc_t desc, int descriptor_name,
+                psaddr_t idx, psaddr_t address,
+                psaddr_t *result)
+{
+  ps_err_e err;
+  td_err_e terr = _td_locate_field (ta, desc, descriptor_name, idx, &address);
+  if (terr != TD_OK)
+    return terr;
+
+  if (DB_DESC_SIZE (desc) == 8 || DB_DESC_SIZE (desc) == bswap_32 (8))
+    {
+      uint8_t value;
+      err = ps_pdread (ta->ph, address, &value, sizeof value);
+      *result = (psaddr_t) 0 + value;
+    }
+  else if (DB_DESC_SIZE (desc) == 32)
+    {
+      uint32_t value;
+      err = ps_pdread (ta->ph, address, &value, sizeof value);
+      *result = (psaddr_t) 0 + value;
+    }
+  else if (DB_DESC_SIZE (desc) == 64)
+    {
+      uint64_t value;
+      if (sizeof (psaddr_t) < 8)
+       return TD_NOCAPAB;
+      err = ps_pdread (ta->ph, address, &value, sizeof value);
+      *result = (psaddr_t) 0 + value;
+    }
+  else if (DB_DESC_SIZE (desc) == bswap_32 (32))
+    {
+      uint32_t value;
+      err = ps_pdread (ta->ph, address, &value, sizeof value);
+      value = bswap_32 (value);
+      *result = (psaddr_t) 0 + value;
+    }
+  else if (DB_DESC_SIZE (desc) == bswap_32 (64))
+    {
+      uint64_t value;
+      if (sizeof (psaddr_t) < 8)
+       return TD_NOCAPAB;
+      err = ps_pdread (ta->ph, address, &value, sizeof value);
+      value = bswap_64 (value);
+      *result = (psaddr_t) 0 + value;
+    }
+  else
+    return TD_DBERR;
+
+  return err == PS_OK ? TD_OK : TD_ERR;
+}
+
+
+td_err_e
+_td_store_value (td_thragent_t *ta,
+                uint32_t desc[2], int descriptor_name, psaddr_t idx,
+                psaddr_t address, psaddr_t widened_value)
+{
+  ps_err_e err;
+  td_err_e terr = _td_locate_field (ta, desc, descriptor_name, idx, &address);
+  if (terr != TD_OK)
+    return terr;
+
+  if (DB_DESC_SIZE (desc) == 8 || DB_DESC_SIZE (desc) == bswap_32 (8))
+    {
+      uint8_t value = widened_value - (psaddr_t) 0;
+      err = ps_pdwrite (ta->ph, address, &value, sizeof value);
+    }
+  else if (DB_DESC_SIZE (desc) == 32)
+    {
+      uint32_t value = widened_value - (psaddr_t) 0;
+      err = ps_pdwrite (ta->ph, address, &value, sizeof value);
+    }
+  else if (DB_DESC_SIZE (desc) == 64)
+    {
+      uint64_t value = widened_value - (psaddr_t) 0;
+      if (sizeof (psaddr_t) < 8)
+       return TD_NOCAPAB;
+      err = ps_pdwrite (ta->ph, address, &value, sizeof value);
+    }
+  else if (DB_DESC_SIZE (desc) == bswap_32 (32))
+    {
+      uint32_t value = widened_value - (psaddr_t) 0;
+      value = bswap_32 (value);
+      err = ps_pdwrite (ta->ph, address, &value, sizeof value);
+    }
+  else if (DB_DESC_SIZE (desc) == bswap_32 (64))
+    {
+      uint64_t value = widened_value - (psaddr_t) 0;
+      if (sizeof (psaddr_t) < 8)
+       return TD_NOCAPAB;
+      value = bswap_64 (value);
+      err = ps_pdwrite (ta->ph, address, &value, sizeof value);
+    }
+  else
+    return TD_DBERR;
+
+  return err == PS_OK ? TD_OK : TD_ERR;
+}
+
+td_err_e
+_td_fetch_value_local (td_thragent_t *ta,
+                      db_desc_t desc, int descriptor_name, psaddr_t idx,
+                      void *address,
+                      psaddr_t *result)
+{
+  td_err_e terr = _td_locate_field (ta, desc, descriptor_name, idx, &address);
+  if (terr != TD_OK)
+    return terr;
+
+  if (DB_DESC_SIZE (desc) == 8 || DB_DESC_SIZE (desc) == bswap_32 (8))
+    {
+      uint8_t value;
+      memcpy (&value, address, sizeof value);
+      *result = (psaddr_t) 0 + value;
+    }
+  else if (DB_DESC_SIZE (desc) == 32)
+    {
+      uint32_t value;
+      memcpy (&value, address, sizeof value);
+      *result = (psaddr_t) 0 + value;
+    }
+  else if (DB_DESC_SIZE (desc) == 64)
+    {
+      uint64_t value;
+      if (sizeof (psaddr_t) < 8)
+       return TD_NOCAPAB;
+      memcpy (&value, address, sizeof value);
+      *result = (psaddr_t) 0 + value;
+    }
+  else if (DB_DESC_SIZE (desc) == bswap_32 (32))
+    {
+      uint32_t value;
+      memcpy (&value, address, sizeof value);
+      value = bswap_32 (value);
+      *result = (psaddr_t) 0 + value;
+    }
+  else if (DB_DESC_SIZE (desc) == bswap_32 (64))
+    {
+      uint64_t value;
+      if (sizeof (psaddr_t) < 8)
+       return TD_NOCAPAB;
+      memcpy (&value, address, sizeof value);
+      value = bswap_64 (value);
+      *result = (psaddr_t) 0 + value;
+    }
+  else
+    return TD_DBERR;
+
+  return TD_OK;
+}
+
+
+td_err_e
+_td_store_value_local (td_thragent_t *ta,
+                      uint32_t desc[2], int descriptor_name, psaddr_t idx,
+                      void *address, psaddr_t widened_value)
+{
+  td_err_e terr = _td_locate_field (ta, desc, descriptor_name, idx, &address);
+  if (terr != TD_OK)
+    return terr;
+
+  if (DB_DESC_SIZE (desc) == 8 || DB_DESC_SIZE (desc) == bswap_32 (8))
+    {
+      uint8_t value = widened_value - (psaddr_t) 0;
+      memcpy (address, &value, sizeof value);
+    }
+  else if (DB_DESC_SIZE (desc) == 32)
+    {
+      uint32_t value = widened_value - (psaddr_t) 0;
+      memcpy (address, &value, sizeof value);
+    }
+  else if (DB_DESC_SIZE (desc) == 64)
+    {
+      uint64_t value = widened_value - (psaddr_t) 0;
+      if (sizeof (psaddr_t) < 8)
+       return TD_NOCAPAB;
+      memcpy (address, &value, sizeof value);
+    }
+  else if (DB_DESC_SIZE (desc) == bswap_32 (32))
+    {
+      uint32_t value = widened_value - (psaddr_t) 0;
+      value = bswap_32 (value);
+      memcpy (address, &value, sizeof value);
+    }
+  else if (DB_DESC_SIZE (desc) == bswap_32 (64))
+    {
+      uint64_t value = widened_value - (psaddr_t) 0;
+      if (sizeof (psaddr_t) < 8)
+       return TD_NOCAPAB;
+      value = bswap_64 (value);
+      memcpy (address, &value, sizeof value);
+    }
+  else
+    return TD_DBERR;
+
+  return TD_OK;
+}
diff --git a/libpthread/nptl_db/proc_service.h b/libpthread/nptl_db/proc_service.h
new file mode 100644 (file)
index 0000000..d49e87a
--- /dev/null
@@ -0,0 +1,87 @@
+/* Callback interface for libthread_db, functions users must define.
+   Copyright (C) 1999,2002,2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* The definitions in this file must correspond to those in the debugger.  */
+#include <sys/procfs.h>
+
+/* Functions in this interface return one of these status codes.  */
+typedef enum
+{
+  PS_OK,               /* Generic "call succeeded".  */
+  PS_ERR,              /* Generic error. */
+  PS_BADPID,           /* Bad process handle.  */
+  PS_BADLID,           /* Bad LWP identifier.  */
+  PS_BADADDR,          /* Bad address.  */
+  PS_NOSYM,            /* Could not find given symbol.  */
+  PS_NOFREGS           /* FPU register set not available for given LWP.  */
+} ps_err_e;
+
+
+/* This type is opaque in this interface.
+   It's defined by the user of libthread_db.  */
+struct ps_prochandle;
+
+
+/* Read or write process memory at the given address.  */
+extern ps_err_e ps_pdread (struct ps_prochandle *,
+                          psaddr_t, void *, size_t);
+extern ps_err_e ps_pdwrite (struct ps_prochandle *,
+                           psaddr_t, const void *, size_t);
+extern ps_err_e ps_ptread (struct ps_prochandle *,
+                          psaddr_t, void *, size_t);
+extern ps_err_e ps_ptwrite (struct ps_prochandle *,
+                           psaddr_t, const void *, size_t);
+
+
+/* Get and set the given LWP's general or FPU register set.  */
+extern ps_err_e ps_lgetregs (struct ps_prochandle *,
+                            lwpid_t, prgregset_t);
+extern ps_err_e ps_lsetregs (struct ps_prochandle *,
+                            lwpid_t, const prgregset_t);
+extern ps_err_e ps_lgetfpregs (struct ps_prochandle *,
+                              lwpid_t, prfpregset_t *);
+extern ps_err_e ps_lsetfpregs (struct ps_prochandle *,
+                              lwpid_t, const prfpregset_t *);
+
+/* Return the PID of the process.  */
+extern pid_t ps_getpid (struct ps_prochandle *);
+
+/* Fetch the special per-thread address associated with the given LWP.
+   This call is only used on a few platforms (most use a normal register).
+   The meaning of the `int' parameter is machine-dependent.  */
+extern ps_err_e ps_get_thread_area (const struct ps_prochandle *,
+                                   lwpid_t, int, psaddr_t *);
+
+
+/* Look up the named symbol in the named DSO in the symbol tables
+   associated with the process being debugged, filling in *SYM_ADDR
+   with the corresponding run-time address.  */
+extern ps_err_e ps_pglobal_lookup (struct ps_prochandle *,
+                                  const char *object_name,
+                                  const char *sym_name,
+                                  psaddr_t *sym_addr);
+
+
+/* Stop or continue the entire process.  */
+extern ps_err_e ps_pstop (const struct ps_prochandle *);
+extern ps_err_e ps_pcontinue (const struct ps_prochandle *);
+
+/* Stop or continue the given LWP alone.  */
+extern ps_err_e ps_lstop (const struct ps_prochandle *, lwpid_t);
+extern ps_err_e ps_lcontinue (const struct ps_prochandle *, lwpid_t);
diff --git a/libpthread/nptl_db/structs.def b/libpthread/nptl_db/structs.def
new file mode 100644 (file)
index 0000000..1572ad6
--- /dev/null
@@ -0,0 +1,88 @@
+/* List of types and symbols in libpthread examined by libthread_db.
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef DB_STRUCT_ARRAY_FIELD
+# define DB_STRUCT_ARRAY_FIELD(type, field) DB_STRUCT_FIELD (type, field)
+# define DB_ARRAY_VARIABLE(name) DB_VARIABLE (name)
+# define STRUCTS_DEF_DEFAULTS 1
+#endif
+
+DB_STRUCT (pthread)
+DB_STRUCT_FIELD (pthread, list)
+DB_STRUCT_FIELD (pthread, report_events)
+DB_STRUCT_FIELD (pthread, tid)
+DB_STRUCT_FIELD (pthread, start_routine)
+DB_STRUCT_FIELD (pthread, cancelhandling)
+DB_STRUCT_FIELD (pthread, schedpolicy)
+DB_STRUCT_FIELD (pthread, schedparam_sched_priority)
+DB_STRUCT_FIELD (pthread, specific)
+DB_STRUCT_FIELD (pthread, eventbuf)
+DB_STRUCT_FIELD (pthread, eventbuf_eventmask)
+DB_STRUCT_ARRAY_FIELD (pthread, eventbuf_eventmask_event_bits)
+DB_STRUCT_FIELD (pthread, nextevent)
+
+DB_STRUCT (list_t)
+DB_STRUCT_FIELD (list_t, next)
+DB_STRUCT_FIELD (list_t, prev)
+
+DB_STRUCT (td_thr_events_t)
+DB_STRUCT_ARRAY_FIELD (td_thr_events_t, event_bits)
+
+DB_STRUCT (td_eventbuf_t)
+DB_STRUCT_FIELD (td_eventbuf_t, eventnum)
+DB_STRUCT_FIELD (td_eventbuf_t, eventdata)
+
+DB_SYMBOL (stack_used)
+DB_SYMBOL (__stack_user)
+DB_SYMBOL (nptl_version)
+DB_FUNCTION (__nptl_create_event)
+DB_FUNCTION (__nptl_death_event)
+DB_SYMBOL (__nptl_threads_events)
+DB_VARIABLE (__nptl_nthreads)
+DB_VARIABLE (__nptl_last_event)
+
+DB_ARRAY_VARIABLE (__pthread_keys)
+DB_STRUCT (pthread_key_struct)
+DB_STRUCT_FIELD (pthread_key_struct, seq)
+DB_STRUCT_FIELD (pthread_key_struct, destr)
+
+DB_STRUCT (pthread_key_data)
+DB_STRUCT_FIELD (pthread_key_data, seq)
+DB_STRUCT_FIELD (pthread_key_data, data)
+DB_STRUCT (pthread_key_data_level2)
+DB_STRUCT_ARRAY_FIELD (pthread_key_data_level2, data)
+
+#if USE_TLS
+DB_STRUCT_FIELD (link_map, l_tls_modid)
+#endif
+
+#if !defined IS_IN_libpthread || USE_TLS
+DB_STRUCT_ARRAY_FIELD (dtv, dtv)
+# define pointer_val pointer.val /* Field of anonymous struct in dtv_t.  */
+DB_STRUCT_FIELD (dtv_t, pointer_val)
+#endif
+#if !defined IS_IN_libpthread || (defined TLS_TCB_AT_TP && TLS_TCB_AT_TP)
+DB_STRUCT_FIELD (pthread, dtvp)
+#endif
+
+#ifdef STRUCTS_DEF_DEFAULTS
+# undef DB_STRUCT_ARRAY_FIELD
+# undef DB_ARRAY_VARIABLE
+# undef STRUCTS_DEF_DEFAULTS
+#endif
diff --git a/libpthread/nptl_db/td_init.c b/libpthread/nptl_db/td_init.c
new file mode 100644 (file)
index 0000000..946ff72
--- /dev/null
@@ -0,0 +1,32 @@
+/* Initialization function of thread debugger support library.
+   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+
+int __td_debug;
+
+
+td_err_e
+td_init (void)
+{
+  /* XXX We have to figure out what has to be done.  */
+  LOG ("td_init");
+  return TD_OK;
+}
diff --git a/libpthread/nptl_db/td_log.c b/libpthread/nptl_db/td_log.c
new file mode 100644 (file)
index 0000000..52212a0
--- /dev/null
@@ -0,0 +1,32 @@
+/* Noop, left for historical reasons.
+   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_log (void)
+{
+  /* This interface is deprecated in the Sun interface.  We provide it
+     for compatibility but don't do anything ourself.  We might in
+     future do some logging if this seems reasonable.  */
+  LOG ("td_log");
+  return TD_OK;
+}
diff --git a/libpthread/nptl_db/td_symbol_list.c b/libpthread/nptl_db/td_symbol_list.c
new file mode 100644 (file)
index 0000000..04aed67
--- /dev/null
@@ -0,0 +1,87 @@
+/* Return list of symbols the library can request.
+   Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2001.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with 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>
+#ifndef __UCLIBC__
+#include <gnu/lib-names.h>
+#endif
+#include "thread_dbP.h"
+
+
+#ifdef HAVE_ASM_GLOBAL_DOT_NAME
+# define DOT "."               /* PPC64 requires . prefix on code symbols.  */
+#else
+# define DOT                   /* No prefix.  */
+#endif
+
+static const char *symbol_list_arr[] =
+{
+# define DB_STRUCT(type) \
+  [SYM_SIZEOF_##type] = "_thread_db_sizeof_" #type,
+# define DB_STRUCT_FIELD(type, field) \
+  [SYM_##type##_FIELD_##field] = "_thread_db_" #type "_" #field,
+# define DB_SYMBOL(name) \
+  [SYM_##name] = #name,
+# define DB_FUNCTION(name) \
+  [SYM_##name] = DOT #name,
+# define DB_VARIABLE(name) \
+  [SYM_##name] = #name, \
+  [SYM_DESC_##name] = "_thread_db_" #name,
+# include "structs.def"
+# undef DB_STRUCT
+# undef DB_FUNCTION
+# undef DB_SYMBOL
+# undef DB_VARIABLE
+
+  [SYM_TH_UNIQUE_CONST_THREAD_AREA] = "_thread_db_const_thread_area",
+  [SYM_TH_UNIQUE_REGISTER64] = "_thread_db_register64",
+  [SYM_TH_UNIQUE_REGISTER32] = "_thread_db_register32",
+  [SYM_TH_UNIQUE_REGISTER32_THREAD_AREA] = "_thread_db_register32_thread_area",
+  [SYM_TH_UNIQUE_REGISTER64_THREAD_AREA] = "_thread_db_register64_thread_area",
+
+  [SYM_NUM_MESSAGES] = NULL
+};
+
+
+const char **
+td_symbol_list (void)
+{
+  return symbol_list_arr;
+}
+
+
+ps_err_e
+td_lookup (struct ps_prochandle *ps, int idx, psaddr_t *sym_addr)
+{
+  ps_err_e result;
+  assert (idx >= 0 && idx < SYM_NUM_MESSAGES);
+  result = ps_pglobal_lookup (ps, LIBPTHREAD_SO, symbol_list_arr[idx],
+                             sym_addr);
+
+#ifdef HAVE_ASM_GLOBAL_DOT_NAME
+  /* For PowerPC, 64-bit uses dot symbols but 32-bit does not.
+     We could be a 64-bit libthread_db debugging a 32-bit libpthread.  */
+  if (result == PS_NOSYM && symbol_list_arr[idx][0] == '.')
+    result = ps_pglobal_lookup (ps, LIBPTHREAD_SO, &symbol_list_arr[idx][1],
+                               sym_addr);
+#endif
+
+  return result;
+}
diff --git a/libpthread/nptl_db/td_ta_clear_event.c b/libpthread/nptl_db/td_ta_clear_event.c
new file mode 100644 (file)
index 0000000..7a2850c
--- /dev/null
@@ -0,0 +1,79 @@
+/* Globally disable events.
+   Copyright (C) 1999, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_ta_clear_event (ta_arg, event)
+     const td_thragent_t *ta_arg;
+     td_thr_events_t *event;
+{
+  td_thragent_t *const ta = (td_thragent_t *) ta_arg;
+  td_err_e err;
+  psaddr_t eventmask = 0;
+  void *copy = NULL;
+
+  LOG ("td_ta_clear_event");
+
+  /* Test whether the TA parameter is ok.  */
+  if (! ta_ok (ta))
+    return TD_BADTA;
+
+  /* Fetch the old event mask from the inferior and modify it in place.  */
+  err = DB_GET_SYMBOL (eventmask, ta, __nptl_threads_events);
+  if (err == TD_OK)
+    err = DB_GET_STRUCT (copy, ta, eventmask, td_thr_events_t);
+  if (err == TD_OK)
+    {
+      uint32_t idx;
+      for (idx = 0; idx < TD_EVENTSIZE; ++idx)
+       {
+         psaddr_t word;
+         uint32_t mask;
+         err = DB_GET_FIELD_LOCAL (word, ta, copy,
+                                   td_thr_events_t, event_bits, idx);
+         if (err != TD_OK)
+           break;
+         mask = (uintptr_t) word;
+         mask &= ~event->event_bits[idx];
+         word = (psaddr_t) (uintptr_t) mask;
+         err = DB_PUT_FIELD_LOCAL (ta, copy,
+                                   td_thr_events_t, event_bits, idx, word);
+         if (err != TD_OK)
+           break;
+       }
+      if (err == TD_NOAPLIC)
+       {
+         err = TD_OK;
+         while (idx < TD_EVENTSIZE)
+           if (event->event_bits[idx++] != 0)
+             {
+               err = TD_NOEVENT;
+               break;
+             }
+       }
+      if (err == TD_OK)
+       /* Now write it back to the inferior.  */
+       err = DB_PUT_STRUCT (ta, eventmask, td_thr_events_t, copy);
+    }
+
+  return err;
+}
diff --git a/libpthread/nptl_db/td_ta_delete.c b/libpthread/nptl_db/td_ta_delete.c
new file mode 100644 (file)
index 0000000..57b90e5
--- /dev/null
@@ -0,0 +1,42 @@
+/* Detach to target process.
+   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with 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 "thread_dbP.h"
+
+
+td_err_e
+td_ta_delete (td_thragent_t *ta)
+{
+  LOG ("td_ta_delete");
+
+  /* Safety check.  Note that the test will also fail for TA == NULL.  */
+  if (!ta_ok (ta))
+    return TD_BADTA;
+
+  /* Remove the handle from the list.  */
+  list_del (&ta->list);
+
+  /* The handle was allocated in `td_ta_new'.  */
+  free (ta);
+
+  return TD_OK;
+}
diff --git a/libpthread/nptl_db/td_ta_enable_stats.c b/libpthread/nptl_db/td_ta_enable_stats.c
new file mode 100644 (file)
index 0000000..ec7014a
--- /dev/null
@@ -0,0 +1,35 @@
+/* Enable collection of statistics for process.
+   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_ta_enable_stats (const td_thragent_t *ta, int enable)
+{
+  /* XXX We have to figure out what has to be done.  */
+  LOG ("td_ta_enable_stats");
+
+  /* Test whether the TA parameter is ok.  */
+  if (! ta_ok (ta))
+    return TD_BADTA;
+
+  return TD_OK;
+}
diff --git a/libpthread/nptl_db/td_ta_event_addr.c b/libpthread/nptl_db/td_ta_event_addr.c
new file mode 100644 (file)
index 0000000..45c6b11
--- /dev/null
@@ -0,0 +1,61 @@
+/* Get event address.
+   Copyright (C) 1999,2001,2002,2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_ta_event_addr (const td_thragent_t *ta_arg,
+                 td_event_e event, td_notify_t *addr)
+{
+  td_thragent_t *const ta = (td_thragent_t *) ta_arg;
+  td_err_e err;
+  psaddr_t taddr = NULL;
+
+  LOG ("td_ta_event_addr");
+
+  /* Test whether the TA parameter is ok.  */
+  if (! ta_ok (ta))
+    return TD_BADTA;
+
+  switch (event)
+    {
+    case TD_CREATE:
+      err = DB_GET_SYMBOL (taddr, ta, __nptl_create_event);
+      break;
+
+    case TD_DEATH:
+      err = DB_GET_SYMBOL (taddr, ta, __nptl_death_event);
+      break;
+
+    default:
+      /* Event cannot be handled.  */
+      return TD_NOEVENT;
+    }
+
+  if (err == TD_OK)
+    {
+      /* Success, we got the address.  */
+      addr->type = NOTIFY_BPT;
+      addr->u.bptaddr = taddr;
+    }
+
+  return err;
+}
diff --git a/libpthread/nptl_db/td_ta_event_getmsg.c b/libpthread/nptl_db/td_ta_event_getmsg.c
new file mode 100644 (file)
index 0000000..d3b46bd
--- /dev/null
@@ -0,0 +1,105 @@
+/* Retrieve event.
+   Copyright (C) 1999, 2001, 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stddef.h>
+#include <string.h>
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_ta_event_getmsg (const td_thragent_t *ta_arg, td_event_msg_t *msg)
+{
+  td_thragent_t *const ta = (td_thragent_t *) ta_arg;
+  td_err_e err;
+  psaddr_t eventbuf, eventnum, eventdata;
+  psaddr_t thp, next;
+  void *copy = NULL;
+
+  /* XXX I cannot think of another way but using a static variable.  */
+  /* XXX Use at least __thread once it is possible.  */
+  static td_thrhandle_t th;
+
+  LOG ("td_thr_event_getmsg");
+
+  /* Test whether the TA parameter is ok.  */
+  if (! ta_ok (ta))
+    return TD_BADTA;
+
+  /* Get the pointer to the thread descriptor with the last event.  */
+  err = DB_GET_VALUE (thp, ta, __nptl_last_event, 0);
+  if (err != TD_OK)
+    return err;
+
+  if (thp == 0)
+    /* Nothing waiting.  */
+    return TD_NOMSG;
+
+  /* Copy the event message buffer in from the inferior.  */
+  err = DB_GET_FIELD_ADDRESS (eventbuf, ta, thp, pthread, eventbuf, 0);
+  if (err == TD_OK)
+    err = DB_GET_STRUCT (copy, ta, eventbuf, td_eventbuf_t);
+  if (err != TD_OK)
+    return err;
+
+  /* Read the event details from the target thread.  */
+  err = DB_GET_FIELD_LOCAL (eventnum, ta, copy, td_eventbuf_t, eventnum, 0);
+  if (err != TD_OK)
+    return err;
+  /* If the structure is on the list there better be an event recorded.  */
+  if ((int) (uintptr_t) eventnum == TD_EVENT_NONE)
+    return TD_DBERR;
+
+  /* Fill the user's data structure.  */
+  err = DB_GET_FIELD_LOCAL (eventdata, ta, copy, td_eventbuf_t, eventdata, 0);
+  if (err != TD_OK)
+    return err;
+
+  /* Generate the thread descriptor.  */
+  th.th_ta_p = (td_thragent_t *) ta;
+  th.th_unique = thp;
+
+  /* Fill the user's data structure.  */
+  msg->msg.data = (uintptr_t) eventdata;
+  msg->event = (uintptr_t) eventnum;
+  msg->th_p = &th;
+
+  /* And clear the event message in the target.  */
+  memset (copy, 0, ta->ta_sizeof_td_eventbuf_t);
+  err = DB_PUT_STRUCT (ta, eventbuf, td_eventbuf_t, copy);
+  if (err != TD_OK)
+    return err;
+
+  /* Get the pointer to the next descriptor with an event.  */
+  err = DB_GET_FIELD (next, ta, thp, pthread, nextevent, 0);
+  if (err != TD_OK)
+    return err;
+
+  /* Store the pointer in the list head variable.  */
+  err = DB_PUT_VALUE (ta, __nptl_last_event, 0, next);
+  if (err != TD_OK)
+    return err;
+
+  if (next != 0)
+    /* Clear the next pointer in the current descriptor.  */
+    err = DB_PUT_FIELD (ta, thp, pthread, nextevent, 0, 0);
+
+  return err;
+}
diff --git a/libpthread/nptl_db/td_ta_get_nthreads.c b/libpthread/nptl_db/td_ta_get_nthreads.c
new file mode 100644 (file)
index 0000000..ffe78bd
--- /dev/null
@@ -0,0 +1,42 @@
+/* Get the number of threads in the process.
+   Copyright (C) 1999,2001,2002,2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+
+td_err_e
+td_ta_get_nthreads (const td_thragent_t *ta_arg, int *np)
+{
+  td_thragent_t *const ta = (td_thragent_t *) ta_arg;
+  td_err_e err;
+  psaddr_t n;
+
+  LOG ("td_ta_get_nthreads");
+
+  /* Test whether the TA parameter is ok.  */
+  if (! ta_ok (ta))
+    return TD_BADTA;
+
+  /* Access the variable in the inferior that tells us.  */
+  err = DB_GET_VALUE (n, ta, __nptl_nthreads, 0);
+  if (err == TD_OK)
+    *np = (uintptr_t) n;
+
+  return err;
+}
diff --git a/libpthread/nptl_db/td_ta_get_ph.c b/libpthread/nptl_db/td_ta_get_ph.c
new file mode 100644 (file)
index 0000000..04e01fb
--- /dev/null
@@ -0,0 +1,36 @@
+/* Get external process handle.
+   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_ta_get_ph (const td_thragent_t *ta, struct ps_prochandle **ph)
+{
+  LOG ("td_ta_get_ph");
+
+  /* Test whether the TA parameter is ok.  */
+  if (! ta_ok (ta))
+    return TD_BADTA;
+
+  *ph = ta->ph;
+
+  return TD_OK;
+}
diff --git a/libpthread/nptl_db/td_ta_get_stats.c b/libpthread/nptl_db/td_ta_get_stats.c
new file mode 100644 (file)
index 0000000..d5d879c
--- /dev/null
@@ -0,0 +1,35 @@
+/* Retrieve statistics for process.
+   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_ta_get_stats (const td_thragent_t *ta, td_ta_stats_t *statsp)
+{
+  /* XXX We have to figure out what has to be done.  */
+  LOG ("td_ta_get_stats");
+
+  /* Test whether the TA parameter is ok.  */
+  if (! ta_ok (ta))
+    return TD_BADTA;
+
+  return TD_OK;
+}
diff --git a/libpthread/nptl_db/td_ta_map_id2thr.c b/libpthread/nptl_db/td_ta_map_id2thr.c
new file mode 100644 (file)
index 0000000..189a671
--- /dev/null
@@ -0,0 +1,38 @@
+/* Map thread ID to thread handle.
+   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_ta_map_id2thr (const td_thragent_t *ta, pthread_t pt, td_thrhandle_t *th)
+{
+  LOG ("td_ta_map_id2thr");
+
+  /* Test whether the TA parameter is ok.  */
+  if (! ta_ok (ta))
+    return TD_BADTA;
+
+  /* Create the `td_thrhandle_t' object.  */
+  th->th_ta_p = (td_thragent_t *) ta;
+  th->th_unique = (psaddr_t) pt;
+
+  return TD_OK;
+}
diff --git a/libpthread/nptl_db/td_ta_map_lwp2thr.c b/libpthread/nptl_db/td_ta_map_lwp2thr.c
new file mode 100644 (file)
index 0000000..acfa0fd
--- /dev/null
@@ -0,0 +1,178 @@
+/* Which thread is running on an LWP?
+   Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+#include <stdlib.h>
+#include <byteswap.h>
+#include <sys/procfs.h>
+
+
+td_err_e
+td_ta_map_lwp2thr (const td_thragent_t *ta_arg,
+                  lwpid_t lwpid, td_thrhandle_t *th)
+{
+  td_thragent_t *const ta = (td_thragent_t *) ta_arg;
+  ps_err_e err;
+  td_err_e terr;
+  prgregset_t regs;
+  psaddr_t addr;
+
+  LOG ("td_ta_map_lwp2thr");
+
+  /* Test whether the TA parameter is ok.  */
+  if (! ta_ok (ta))
+    return TD_BADTA;
+
+  if (ta->ta_howto == ta_howto_unknown)
+    {
+      /* We need to read in from the inferior the instructions what to do.  */
+      psaddr_t howto;
+
+      err = td_lookup (ta->ph, SYM_TH_UNIQUE_CONST_THREAD_AREA, &howto);
+      if (err == PS_OK)
+       {
+         err = ps_pdread (ta->ph, howto,
+                          &ta->ta_howto_data.const_thread_area,
+                          sizeof ta->ta_howto_data.const_thread_area);
+         if (err != PS_OK)
+           return TD_ERR;
+         ta->ta_howto = ta_howto_const_thread_area;
+         if (ta->ta_howto_data.const_thread_area & 0xff000000U)
+           ta->ta_howto_data.const_thread_area
+             = bswap_32 (ta->ta_howto_data.const_thread_area);
+       }
+      else
+       {
+         switch (sizeof (regs[0]))
+           {
+           case 8:
+             err = td_lookup (ta->ph, SYM_TH_UNIQUE_REGISTER64, &howto);
+             if (err == PS_OK)
+               ta->ta_howto = ta_howto_reg;
+             else if (err == PS_NOSYM)
+               {
+                 err = td_lookup (ta->ph,
+                                  SYM_TH_UNIQUE_REGISTER64_THREAD_AREA,
+                                  &howto);
+                 if (err == PS_OK)
+                   ta->ta_howto = ta_howto_reg_thread_area;
+               }
+             break;
+
+           case 4:
+             err = td_lookup (ta->ph, SYM_TH_UNIQUE_REGISTER32, &howto);
+             if (err == PS_OK)
+               ta->ta_howto = ta_howto_reg;
+             else if (err == PS_NOSYM)
+               {
+                 err = td_lookup (ta->ph,
+                                  SYM_TH_UNIQUE_REGISTER32_THREAD_AREA,
+                                  &howto);
+                 if (err == PS_OK)
+                   ta->ta_howto = ta_howto_reg_thread_area;
+               }
+             break;
+
+           default:
+             abort ();
+             return TD_DBERR;
+           }
+
+         if (err != PS_OK)
+           return TD_DBERR;
+
+         /* For either of these methods we read in the same descriptor.  */
+         err = ps_pdread (ta->ph, howto,
+                          ta->ta_howto_data.reg, DB_SIZEOF_DESC);
+         if (err != PS_OK)
+           return TD_ERR;
+         if (DB_DESC_SIZE (ta->ta_howto_data.reg) == 0)
+           return TD_DBERR;
+         if (DB_DESC_SIZE (ta->ta_howto_data.reg) & 0xff000000U)
+           {
+             /* Byte-swap these words, though we leave the size word
+                in native order as the handy way to distinguish.  */
+             DB_DESC_OFFSET (ta->ta_howto_data.reg)
+               = bswap_32 (DB_DESC_OFFSET (ta->ta_howto_data.reg));
+             DB_DESC_NELEM (ta->ta_howto_data.reg)
+               = bswap_32 (DB_DESC_NELEM (ta->ta_howto_data.reg));
+           }
+       }
+    }
+
+  switch (ta->ta_howto)
+    {
+    case ta_howto_unknown:
+      return TD_DBERR;
+
+    default:
+      return TD_DBERR;
+
+    case ta_howto_reg:
+      /* On most machines, we are just looking at a register.  */
+      if (ps_lgetregs (ta->ph, lwpid, regs) != PS_OK)
+       return TD_ERR;
+      terr = _td_fetch_value_local (ta, ta->ta_howto_data.reg, -1,
+                                   0, regs, &addr);
+      if (terr != TD_OK)
+       return terr;
+      /* In this descriptor the nelem word is overloaded as the bias.  */
+      addr += (int32_t) DB_DESC_NELEM (ta->ta_howto_data.reg);
+      th->th_unique = addr;
+      break;
+
+    case ta_howto_const_thread_area:
+      /* Some hosts don't have this call and this case won't be used.  */
+# pragma weak ps_get_thread_area
+      if (&ps_get_thread_area == NULL)
+       return TD_NOCAPAB;
+
+       /* A la x86-64, there is a constant magic index for get_thread_area.  */
+       if (ps_get_thread_area (ta->ph, lwpid,
+                              ta->ta_howto_data.const_thread_area,
+                              &th->th_unique) != PS_OK)
+        return TD_ERR; /* XXX Other error value?  */
+       break;
+
+     case ta_howto_reg_thread_area:
+      if (&ps_get_thread_area == NULL)
+       return TD_NOCAPAB;
+
+       /* A la i386, there is a register with an index for get_thread_area.  */
+       if (ps_lgetregs (ta->ph, lwpid, regs) != PS_OK)
+        return TD_ERR;
+       terr = _td_fetch_value_local (ta, ta->ta_howto_data.reg_thread_area, -1,
+                                    0, regs, &addr);
+      if (terr != TD_OK)
+       return terr;
+      /* In this descriptor the nelem word is overloaded as scale factor.  */
+      if (ps_get_thread_area
+         (ta->ph, lwpid,
+          ((addr - (psaddr_t) 0)
+           >> DB_DESC_NELEM (ta->ta_howto_data.reg_thread_area)),
+          &th->th_unique) != PS_OK)
+       return TD_ERR;  /* XXX Other error value?  */
+      break;
+    }
+
+  /* Found it.  Now complete the `td_thrhandle_t' object.  */
+  th->th_ta_p = (td_thragent_t *) ta;
+
+  return TD_OK;
+}
diff --git a/libpthread/nptl_db/td_ta_new.c b/libpthread/nptl_db/td_ta_new.c
new file mode 100644 (file)
index 0000000..f84049a
--- /dev/null
@@ -0,0 +1,65 @@
+/* Attach to target process.
+   Copyright (C) 1999,2001,2002,2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <version.h>
+
+#include "thread_dbP.h"
+
+
+/* Datatype for the list of known thread agents.  Normally there will
+   be exactly one so we don't spend much though on making it fast.  */
+LIST_HEAD (__td_agent_list);
+
+
+td_err_e
+td_ta_new (struct ps_prochandle *ps, td_thragent_t **ta)
+{
+  psaddr_t versaddr;
+  char versbuf[sizeof (VERSION)];
+
+  LOG ("td_ta_new");
+
+  /* Check whether the versions match.  */
+  if (td_lookup (ps, SYM_nptl_version, &versaddr) != PS_OK)
+    return TD_NOLIBTHREAD;
+  if (ps_pdread (ps, versaddr, versbuf, sizeof (versbuf)) != PS_OK)
+    return TD_ERR;
+
+  if (memcmp (versbuf, VERSION, sizeof VERSION) != 0)
+    /* Not the right version.  */
+    return TD_VERSION;
+
+  /* Fill in the appropriate information.  */
+  *ta = (td_thragent_t *) calloc (1, sizeof (td_thragent_t));
+  if (*ta == NULL)
+    return TD_MALLOC;
+
+  /* Store the proc handle which we will pass to the callback functions
+     back into the debugger.  */
+  (*ta)->ph = ps;
+
+  /* Now add the new agent descriptor to the list.  */
+  list_add (&(*ta)->list, &__td_agent_list);
+
+  return TD_OK;
+}
diff --git a/libpthread/nptl_db/td_ta_reset_stats.c b/libpthread/nptl_db/td_ta_reset_stats.c
new file mode 100644 (file)
index 0000000..ea59d2c
--- /dev/null
@@ -0,0 +1,35 @@
+/* Reset statistics.
+   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_ta_reset_stats (const td_thragent_t *ta)
+{
+  /* XXX We have to figure out what has to be done.  */
+  LOG ("td_ta_reset_stats");
+
+  /* Test whether the TA parameter is ok.  */
+  if (! ta_ok (ta))
+    return TD_BADTA;
+
+  return TD_OK;
+}
diff --git a/libpthread/nptl_db/td_ta_set_event.c b/libpthread/nptl_db/td_ta_set_event.c
new file mode 100644 (file)
index 0000000..29fc14b
--- /dev/null
@@ -0,0 +1,79 @@
+/* Globally enable events.
+   Copyright (C) 1999,2001,2002,2003,2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_ta_set_event (ta_arg, event)
+     const td_thragent_t *ta_arg;
+     td_thr_events_t *event;
+{
+  td_thragent_t *const ta = (td_thragent_t *) ta_arg;
+  td_err_e err;
+  psaddr_t eventmask = 0;
+  void *copy = NULL;
+
+  LOG ("td_ta_set_event");
+
+  /* Test whether the TA parameter is ok.  */
+  if (! ta_ok (ta))
+    return TD_BADTA;
+
+  /* Fetch the old event mask from the inferior and modify it in place.  */
+  err = DB_GET_SYMBOL (eventmask, ta, __nptl_threads_events);
+  if (err == TD_OK)
+    err = DB_GET_STRUCT (copy, ta, eventmask, td_thr_events_t);
+  if (err == TD_OK)
+    {
+      uint32_t idx;
+      for (idx = 0; idx < TD_EVENTSIZE; ++idx)
+       {
+         psaddr_t word;
+         uint32_t mask;
+         err = DB_GET_FIELD_LOCAL (word, ta, copy,
+                                   td_thr_events_t, event_bits, idx);
+         if (err != TD_OK)
+           break;
+         mask = (uintptr_t) word;
+         mask |= event->event_bits[idx];
+         word = (psaddr_t) (uintptr_t) mask;
+         err = DB_PUT_FIELD_LOCAL (ta, copy,
+                                   td_thr_events_t, event_bits, idx, word);
+         if (err != TD_OK)
+           break;
+       }
+      if (err == TD_NOAPLIC)
+       {
+         err = TD_OK;
+         while (idx < TD_EVENTSIZE)
+           if (event->event_bits[idx++] != 0)
+             {
+               err = TD_NOEVENT;
+               break;
+             }
+       }
+      if (err == TD_OK)
+       /* Now write it back to the inferior.  */
+       err = DB_PUT_STRUCT (ta, eventmask, td_thr_events_t, copy);
+    }
+
+  return err;
+}
diff --git a/libpthread/nptl_db/td_ta_setconcurrency.c b/libpthread/nptl_db/td_ta_setconcurrency.c
new file mode 100644 (file)
index 0000000..8552ffb
--- /dev/null
@@ -0,0 +1,35 @@
+/* Set suggested concurrency level for process.
+   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_ta_setconcurrency (const td_thragent_t *ta, int level)
+{
+  /* This is something LinuxThreads does not need to support.  */
+  LOG ("td_ta_setconcurrency");
+
+  /* Test whether the TA parameter is ok.  */
+  if (! ta_ok (ta))
+    return TD_BADTA;
+
+  return TD_NOCAPAB;
+}
diff --git a/libpthread/nptl_db/td_ta_thr_iter.c b/libpthread/nptl_db/td_ta_thr_iter.c
new file mode 100644 (file)
index 0000000..66e4376
--- /dev/null
@@ -0,0 +1,148 @@
+/* Iterate over a process's threads.
+   Copyright (C) 1999,2000,2001,2002,2003,2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+
+
+static td_err_e
+iterate_thread_list (td_thragent_t *ta, td_thr_iter_f *callback,
+                    void *cbdata_p, td_thr_state_e state, int ti_pri,
+                    psaddr_t head, int fake_empty)
+{
+  td_err_e err;
+  psaddr_t next, ofs;
+  void *copy;
+
+  /* Test the state.
+     XXX This is incomplete.  Normally this test should be in the loop.  */
+  if (state != TD_THR_ANY_STATE)
+    return TD_OK;
+
+  err = DB_GET_FIELD (next, ta, head, list_t, next, 0);
+  if (err != TD_OK)
+    return err;
+
+  if (next == 0 && fake_empty)
+    {
+      /* __pthread_initialize_minimal has not run.
+        There is just the main thread to return.  */
+      td_thrhandle_t th;
+      err = td_ta_map_lwp2thr (ta, ps_getpid (ta->ph), &th);
+      if (err == TD_OK)
+       err = callback (&th, cbdata_p) != 0 ? TD_DBERR : TD_OK;
+      return err;
+    }
+
+  /* Cache the offset from struct pthread to its list_t member.  */
+  err = DB_GET_FIELD_ADDRESS (ofs, ta, 0, pthread, list, 0);
+  if (err != TD_OK)
+    return err;
+
+  if (ta->ta_sizeof_pthread == 0)
+    {
+      err = _td_check_sizeof (ta, &ta->ta_sizeof_pthread, SYM_SIZEOF_pthread);
+      if (err != TD_OK)
+       return err;
+    }
+  copy = __alloca (ta->ta_sizeof_pthread);
+
+  while (next != head)
+    {
+      psaddr_t addr, schedpolicy, schedprio;
+
+      addr = next - (ofs - (psaddr_t) 0);
+      if (next == 0 || addr == 0) /* Sanity check.  */
+       return TD_DBERR;
+
+      /* Copy the whole descriptor in once so we can access the several
+        fields locally.  Excess copying in one go is much better than
+        multiple ps_pdread calls.  */
+      if (ps_pdread (ta->ph, addr, copy, ta->ta_sizeof_pthread) != PS_OK)
+       return TD_ERR;
+
+      err = DB_GET_FIELD_LOCAL (schedpolicy, ta, copy, pthread,
+                               schedpolicy, 0);
+      if (err != TD_OK)
+       break;
+      err = DB_GET_FIELD_LOCAL (schedprio, ta, copy, pthread,
+                               schedparam_sched_priority, 0);
+      if (err != TD_OK)
+       break;
+
+      /* Now test whether this thread matches the specified conditions.  */
+
+      /* Only if the priority level is as high or higher.  */
+      int descr_pri = ((uintptr_t) schedpolicy == SCHED_OTHER
+                      ? 0 : (uintptr_t) schedprio);
+      if (descr_pri >= ti_pri)
+       {
+         /* Yep, it matches.  Call the callback function.  */
+         td_thrhandle_t th;
+         th.th_ta_p = (td_thragent_t *) ta;
+         th.th_unique = addr;
+         if (callback (&th, cbdata_p) != 0)
+           return TD_DBERR;
+       }
+
+      /* Get the pointer to the next element.  */
+      err = DB_GET_FIELD_LOCAL (next, ta, copy + (ofs - (psaddr_t) 0), list_t,
+                               next, 0);
+      if (err != TD_OK)
+       break;
+    }
+
+  return err;
+}
+
+
+td_err_e
+td_ta_thr_iter (const td_thragent_t *ta_arg, td_thr_iter_f *callback,
+               void *cbdata_p, td_thr_state_e state, int ti_pri,
+               sigset_t *ti_sigmask_p, unsigned int ti_user_flags)
+{
+  td_thragent_t *const ta = (td_thragent_t *) ta_arg;
+  td_err_e err;
+  psaddr_t list = 0;
+
+  LOG ("td_ta_thr_iter");
+
+  /* Test whether the TA parameter is ok.  */
+  if (! ta_ok (ta))
+    return TD_BADTA;
+
+  /* The thread library keeps two lists for the running threads.  One
+     list contains the thread which are using user-provided stacks
+     (this includes the main thread) and the other includes the
+     threads for which the thread library allocated the stacks.  We
+     have to iterate over both lists separately.  We start with the
+     list of threads with user-defined stacks.  */
+
+  err = DB_GET_SYMBOL (list, ta, __stack_user);
+  if (err == TD_OK)
+    err = iterate_thread_list (ta, callback, cbdata_p, state, ti_pri, list, 1);
+
+  /* And the threads with stacks allocated by the implementation.  */
+  if (err == TD_OK)
+    err = DB_GET_SYMBOL (list, ta, stack_used);
+  if (err == TD_OK)
+    err = iterate_thread_list (ta, callback, cbdata_p, state, ti_pri, list, 0);
+
+  return err;
+}
diff --git a/libpthread/nptl_db/td_ta_tsd_iter.c b/libpthread/nptl_db/td_ta_tsd_iter.c
new file mode 100644 (file)
index 0000000..9cfb1e8
--- /dev/null
@@ -0,0 +1,81 @@
+/* Iterate over a process's thread-specific data.
+   Copyright (C) 1999,2000,2001,2002,2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+#include <alloca.h>
+
+td_err_e
+td_ta_tsd_iter (const td_thragent_t *ta_arg, td_key_iter_f *callback,
+               void *cbdata_p)
+{
+  td_thragent_t *const ta = (td_thragent_t *) ta_arg;
+  td_err_e err;
+  void *keys;
+  size_t keys_nb, keys_elemsize;
+  psaddr_t addr;
+  uint32_t idx;
+
+  LOG ("td_ta_tsd_iter");
+
+  /* Test whether the TA parameter is ok.  */
+  if (! ta_ok (ta))
+    return TD_BADTA;
+
+  /* This makes sure we have the size information on hand.  */
+  addr = 0;
+  err = _td_locate_field (ta,
+                         ta->ta_var___pthread_keys, SYM_DESC___pthread_keys,
+                         (psaddr_t) 0 + 1, &addr);
+  if (err != TD_OK)
+    return err;
+
+  /* Now copy in the entire array of key descriptors.  */
+  keys_elemsize = (addr - (psaddr_t) 0) / 8;
+  keys_nb = keys_elemsize * DB_DESC_NELEM (ta->ta_var___pthread_keys);
+  keys = __alloca (keys_nb);
+  err = DB_GET_SYMBOL (addr, ta, __pthread_keys);
+  if (err != TD_OK)
+    return err;
+  if (ps_pdread (ta->ph, addr, keys, keys_nb) != PS_OK)
+    return TD_ERR;
+
+  /* Now get all descriptors, one after the other.  */
+  for (idx = 0; idx < DB_DESC_NELEM (ta->ta_var___pthread_keys); ++idx)
+    {
+      psaddr_t seq, destr;
+      err = DB_GET_FIELD_LOCAL (seq, ta, keys, pthread_key_struct, seq, 0);
+      if (err != TD_OK)
+       return err;
+      if (((uintptr_t) seq) & 1)
+       {
+         err = DB_GET_FIELD_LOCAL (destr, ta, keys, pthread_key_struct,
+                                   destr, 0);
+         if (err != TD_OK)
+           return err;
+         /* Return with an error if the callback returns a nonzero value.  */
+         if (callback ((thread_key_t) idx, destr, cbdata_p) != 0)
+           return TD_DBERR;
+       }
+      /* Advance to the next element in the copied array.  */
+      keys += keys_elemsize;
+    }
+
+  return TD_OK;
+}
diff --git a/libpthread/nptl_db/td_thr_clear_event.c b/libpthread/nptl_db/td_thr_clear_event.c
new file mode 100644 (file)
index 0000000..c43c625
--- /dev/null
@@ -0,0 +1,77 @@
+/* Disable specific event for thread.
+   Copyright (C) 1999,2001,2002,2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stddef.h>
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_thr_clear_event (th, event)
+     const td_thrhandle_t *th;
+     td_thr_events_t *event;
+{
+  td_err_e err;
+  psaddr_t eventmask;
+  void *copy = NULL;
+
+  LOG ("td_thr_clear_event");
+
+  /* Fetch the old event mask from the inferior and modify it in place.  */
+  err = DB_GET_FIELD_ADDRESS (eventmask, th->th_ta_p,
+                             th->th_unique, pthread, eventbuf_eventmask, 0);
+  if (err == TD_OK)
+    err = DB_GET_STRUCT (copy, th->th_ta_p, eventmask, td_thr_events_t);
+  if (err == TD_OK)
+    {
+      uint32_t idx;
+      for (idx = 0; idx < TD_EVENTSIZE; ++idx)
+       {
+         psaddr_t word;
+         uint32_t mask;
+         err = DB_GET_FIELD_LOCAL (word, th->th_ta_p, copy,
+                                   td_thr_events_t, event_bits, idx);
+         if (err != TD_OK)
+           break;
+         mask = (uintptr_t) word;
+         mask &= ~event->event_bits[idx];
+         word = (psaddr_t) (uintptr_t) mask;
+         err = DB_PUT_FIELD_LOCAL (th->th_ta_p, copy,
+                                   td_thr_events_t, event_bits, idx, word);
+         if (err != TD_OK)
+           break;
+       }
+      if (err == TD_NOAPLIC)
+       {
+         err = TD_OK;
+         while (idx < TD_EVENTSIZE)
+           if (event->event_bits[idx++] != 0)
+             {
+               err = TD_NOEVENT;
+               break;
+             }
+       }
+      if (err == TD_OK)
+       /* Now write it back to the inferior.  */
+       err = DB_PUT_STRUCT (th->th_ta_p, eventmask, td_thr_events_t, copy);
+    }
+
+  return err;
+}
diff --git a/libpthread/nptl_db/td_thr_dbresume.c b/libpthread/nptl_db/td_thr_dbresume.c
new file mode 100644 (file)
index 0000000..3fd7943
--- /dev/null
@@ -0,0 +1,30 @@
+/* Resume execution of given thread.
+   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_thr_dbresume (const td_thrhandle_t *th)
+{
+  /* XXX We have to figure out what has to be done.  */
+  LOG ("td_thr_dbresume");
+  return TD_NOCAPAB;
+}
diff --git a/libpthread/nptl_db/td_thr_dbsuspend.c b/libpthread/nptl_db/td_thr_dbsuspend.c
new file mode 100644 (file)
index 0000000..6ef82ad
--- /dev/null
@@ -0,0 +1,30 @@
+/* Suspend execution of given thread.
+   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_thr_dbsuspend (const td_thrhandle_t *th)
+{
+  /* XXX We have to figure out what has to be done.  */
+  LOG ("td_thr_dbsuspend");
+  return TD_NOCAPAB;
+}
diff --git a/libpthread/nptl_db/td_thr_event_enable.c b/libpthread/nptl_db/td_thr_event_enable.c
new file mode 100644 (file)
index 0000000..a02be5d
--- /dev/null
@@ -0,0 +1,34 @@
+/* Enable event process-wide.
+   Copyright (C) 1999, 2001, 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_thr_event_enable (th, onoff)
+     const td_thrhandle_t *th;
+     int onoff;
+{
+  LOG ("td_thr_event_enable");
+
+  /* Write the new value into the thread data structure.  */
+  return DB_PUT_FIELD (th->th_ta_p, th->th_unique, pthread, report_events, 0,
+                      (psaddr_t) 0 + (onoff != 0));
+}
diff --git a/libpthread/nptl_db/td_thr_event_getmsg.c b/libpthread/nptl_db/td_thr_event_getmsg.c
new file mode 100644 (file)
index 0000000..b24fc25
--- /dev/null
@@ -0,0 +1,119 @@
+/* Retrieve event.
+   Copyright (C) 1999, 2001, 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+#include <assert.h>
+
+
+td_err_e
+td_thr_event_getmsg (const td_thrhandle_t *th, td_event_msg_t *msg)
+{
+  td_err_e err;
+  psaddr_t eventbuf, eventnum, eventdata;
+  psaddr_t thp, prevp;
+  void *copy = NULL;
+
+  LOG ("td_thr_event_getmsg");
+
+  /* Copy the event message buffer in from the inferior.  */
+  err = DB_GET_FIELD_ADDRESS (eventbuf, th->th_ta_p, th->th_unique, pthread,
+                             eventbuf, 0);
+  if (err == TD_OK)
+    err = DB_GET_STRUCT (copy, th->th_ta_p, eventbuf, td_eventbuf_t);
+  if (err != TD_OK)
+    return err;
+
+  /* Check whether an event occurred.  */
+  err = DB_GET_FIELD_LOCAL (eventnum, th->th_ta_p, copy,
+                           td_eventbuf_t, eventnum, 0);
+  if (err != TD_OK)
+    return err;
+  if ((int) (uintptr_t) eventnum == TD_EVENT_NONE)
+    /* Nothing.  */
+    return TD_NOMSG;
+
+  /* Fill the user's data structure.  */
+  err = DB_GET_FIELD_LOCAL (eventdata, th->th_ta_p, copy,
+                           td_eventbuf_t, eventdata, 0);
+  if (err != TD_OK)
+    return err;
+
+  msg->msg.data = (uintptr_t) eventdata;
+  msg->event = (uintptr_t) eventnum;
+  msg->th_p = th;
+
+  /* And clear the event message in the target.  */
+  memset (copy, 0, th->th_ta_p->ta_sizeof_td_eventbuf_t);
+  err = DB_PUT_STRUCT (th->th_ta_p, eventbuf, td_eventbuf_t, copy);
+  if (err != TD_OK)
+    return err;
+
+  /* Get the pointer to the thread descriptor with the last event.
+     If it doesn't match TH, then walk down the list until we find it.
+     We must splice it out of the list so that there is no dangling
+     pointer to it later when it dies.  */
+  err = DB_GET_SYMBOL (prevp, th->th_ta_p, __nptl_last_event);
+  if (err != TD_OK)
+    return err;
+  err = DB_GET_VALUE (thp, th->th_ta_p, __nptl_last_event, 0);
+  if (err != TD_OK)
+    return err;
+
+  while (thp != 0)
+    {
+      psaddr_t next;
+      err = DB_GET_FIELD (next, th->th_ta_p, th->th_unique, pthread,
+                         nextevent, 0);
+      if (err != TD_OK)
+       return err;
+
+      if (next == thp)
+       return TD_DBERR;
+
+      if (thp == th->th_unique)
+       {
+         /* PREVP points at this thread, splice it out.  */
+         psaddr_t next_nextp;
+         err = DB_GET_FIELD_ADDRESS (next_nextp, th->th_ta_p, next, pthread,
+                                     nextevent, 0);
+         assert (err == TD_OK); /* We used this field before.  */
+         if (prevp == next_nextp)
+           return TD_DBERR;
+
+         err = _td_store_value (th->th_ta_p,
+                                th->th_ta_p->ta_var___nptl_last_event, -1,
+                                0, prevp, next);
+         if (err != TD_OK)
+           return err;
+
+         /* Now clear this thread's own next pointer so it's not dangling
+            when the thread resumes and then chains on for its next event.  */
+         return DB_PUT_FIELD (th->th_ta_p, thp, pthread, nextevent, 0, 0);
+       }
+
+      err = DB_GET_FIELD_ADDRESS (prevp, th->th_ta_p, thp, pthread,
+                                 nextevent, 0);
+      assert (err == TD_OK); /* We used this field before.  */
+      thp = next;
+    }
+
+  /* Ack!  This should not happen.  */
+  return TD_DBERR;
+}
diff --git a/libpthread/nptl_db/td_thr_get_info.c b/libpthread/nptl_db/td_thr_get_info.c
new file mode 100644 (file)
index 0000000..bb13888
--- /dev/null
@@ -0,0 +1,110 @@
+/* Get thread information.
+   Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stddef.h>
+#include <string.h>
+#include "thread_dbP.h"
+
+
+td_err_e
+td_thr_get_info (const td_thrhandle_t *th, td_thrinfo_t *infop)
+{
+  td_err_e err;
+  void *copy;
+  psaddr_t tls, schedpolicy, schedprio, cancelhandling, tid, report_events;
+
+  LOG ("td_thr_get_info");
+
+  /* Copy the whole descriptor in once so we can access the several
+     fields locally.  Excess copying in one go is much better than
+     multiple ps_pdread calls.  */
+  err = DB_GET_STRUCT (copy, th->th_ta_p, th->th_unique, pthread);
+  if (err != TD_OK)
+    return err;
+
+  err = DB_GET_FIELD_ADDRESS (tls, th->th_ta_p, th->th_unique,
+                             pthread, specific, 0);
+  if (err != TD_OK)
+    return err;
+
+  err = DB_GET_FIELD_LOCAL (schedpolicy, th->th_ta_p, copy, pthread,
+                           schedpolicy, 0);
+  if (err != TD_OK)
+    return err;
+  err = DB_GET_FIELD_LOCAL (schedprio, th->th_ta_p, copy, pthread,
+                           schedparam_sched_priority, 0);
+  if (err != TD_OK)
+    return err;
+  err = DB_GET_FIELD_LOCAL (tid, th->th_ta_p, copy, pthread, tid, 0);
+  if (err != TD_OK)
+    return err;
+  err = DB_GET_FIELD_LOCAL (cancelhandling, th->th_ta_p, copy, pthread,
+                           cancelhandling, 0);
+  if (err != TD_OK)
+    return err;
+  err = DB_GET_FIELD_LOCAL (report_events, th->th_ta_p, copy, pthread,
+                           report_events, 0);
+  if (err != TD_OK)
+    return err;
+
+  /* Fill in information.  Clear first to provide reproducable
+     results for the fields we do not fill in.  */
+  memset (infop, '\0', sizeof (td_thrinfo_t));
+
+  infop->ti_tid = (thread_t) th->th_unique;
+  infop->ti_tls = (char *) tls;
+  infop->ti_pri = ((uintptr_t) schedpolicy == SCHED_OTHER
+                  ? 0 : (uintptr_t) schedprio);
+  infop->ti_type = TD_THR_USER;
+
+  if ((((int) (uintptr_t) cancelhandling) & EXITING_BITMASK) == 0)
+    /* XXX For now there is no way to get more information.  */
+    infop->ti_state = TD_THR_ACTIVE;
+  else if ((((int) (uintptr_t) cancelhandling) & TERMINATED_BITMASK) == 0)
+    infop->ti_state = TD_THR_ZOMBIE;
+  else
+    infop->ti_state = TD_THR_UNKNOWN;
+
+  /* Initialization which are the same in both cases.  */
+  infop->ti_ta_p = th->th_ta_p;
+  infop->ti_lid = tid == 0 ? ps_getpid (th->th_ta_p->ph) : (uintptr_t) tid;
+  infop->ti_traceme = report_events != 0;
+
+  err = DB_GET_FIELD_LOCAL (infop->ti_startfunc, th->th_ta_p, copy, pthread,
+                           start_routine, 0);
+  if (err == TD_OK)
+    {
+      uint32_t idx;
+      for (idx = 0; idx < TD_EVENTSIZE; ++idx)
+       {
+         psaddr_t word;
+         err = DB_GET_FIELD_LOCAL (word, th->th_ta_p, copy, pthread,
+                                   eventbuf_eventmask_event_bits, idx);
+         if (err != TD_OK)
+           break;
+         infop->ti_events.event_bits[idx] = (uintptr_t) word;
+       }
+      if (err == TD_NOAPLIC)
+       memset (&infop->ti_events.event_bits[idx], 0,
+               (TD_EVENTSIZE - idx) * sizeof infop->ti_events.event_bits[0]);
+    }
+
+  return err;
+}
diff --git a/libpthread/nptl_db/td_thr_getfpregs.c b/libpthread/nptl_db/td_thr_getfpregs.c
new file mode 100644 (file)
index 0000000..7760512
--- /dev/null
@@ -0,0 +1,53 @@
+/* Get a thread's floating-point register set.
+   Copyright (C) 1999, 2001, 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_thr_getfpregs (const td_thrhandle_t *th, prfpregset_t *regset)
+{
+  psaddr_t cancelhandling, tid;
+  td_err_e err;
+
+  LOG ("td_thr_getfpregs");
+
+  /* We have to get the state and the PID for this thread.  */
+  err = DB_GET_FIELD (cancelhandling, th->th_ta_p, th->th_unique, pthread,
+                     cancelhandling, 0);
+  if (err != TD_OK)
+    return err;
+
+  /* If the thread already terminated we return all zeroes.  */
+  if (((int) (uintptr_t) cancelhandling) & TERMINATED_BITMASK)
+    memset (regset, '\0', sizeof (*regset));
+  /* Otherwise get the register content through the callback.  */
+  else
+    {
+      err = DB_GET_FIELD (tid, th->th_ta_p, th->th_unique, pthread, tid, 0);
+      if (err != TD_OK)
+       return err;
+
+      if (ps_lgetfpregs (th->th_ta_p->ph, (uintptr_t) tid, regset) != PS_OK)
+       return TD_ERR;
+    }
+
+  return TD_OK;
+}
diff --git a/libpthread/nptl_db/td_thr_getgregs.c b/libpthread/nptl_db/td_thr_getgregs.c
new file mode 100644 (file)
index 0000000..4c2373e
--- /dev/null
@@ -0,0 +1,53 @@
+/* Get a thread's general register set.
+   Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_thr_getgregs (const td_thrhandle_t *th, prgregset_t regset)
+{
+  psaddr_t cancelhandling, tid;
+  td_err_e err;
+
+  LOG ("td_thr_getgregs");
+
+  /* We have to get the state and the PID for this thread.  */
+  err = DB_GET_FIELD (cancelhandling, th->th_ta_p, th->th_unique, pthread,
+                     cancelhandling, 0);
+  if (err != TD_OK)
+    return err;
+
+  /* If the thread already terminated we return all zeroes.  */
+  if (((int) (uintptr_t) cancelhandling) & TERMINATED_BITMASK)
+    memset (regset, '\0', sizeof (*regset));
+  /* Otherwise get the register content through the callback.  */
+  else
+    {
+      err = DB_GET_FIELD (tid, th->th_ta_p, th->th_unique, pthread, tid, 0);
+      if (err != TD_OK)
+       return err;
+
+      if (ps_lgetregs (th->th_ta_p->ph, (uintptr_t) tid, regset) != PS_OK)
+       return TD_ERR;
+    }
+
+  return TD_OK;
+}
diff --git a/libpthread/nptl_db/td_thr_getxregs.c b/libpthread/nptl_db/td_thr_getxregs.c
new file mode 100644 (file)
index 0000000..3c77ab6
--- /dev/null
@@ -0,0 +1,30 @@
+/* Get a thread's extra state register set.
+   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_thr_getxregs (const td_thrhandle_t *th, void *xregs)
+{
+  /* XXX This might be platform specific.  */
+  LOG ("td_thr_getxregs");
+  return TD_NOXREGS;
+}
diff --git a/libpthread/nptl_db/td_thr_getxregsize.c b/libpthread/nptl_db/td_thr_getxregsize.c
new file mode 100644 (file)
index 0000000..1704e4b
--- /dev/null
@@ -0,0 +1,30 @@
+/* Get the size of the extra state register set for this architecture.
+   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_thr_getxregsize (const td_thrhandle_t *th, int *sizep)
+{
+  /* XXX This might be platform specific.  */
+  LOG ("td_thr_getxregsize");
+  return TD_NOXREGS;
+}
diff --git a/libpthread/nptl_db/td_thr_set_event.c b/libpthread/nptl_db/td_thr_set_event.c
new file mode 100644 (file)
index 0000000..6617147
--- /dev/null
@@ -0,0 +1,77 @@
+/* Enable specific event for thread.
+   Copyright (C) 1999,2001,2002,2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stddef.h>
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_thr_set_event (th, event)
+     const td_thrhandle_t *th;
+     td_thr_events_t *event;
+{
+  td_err_e err;
+  psaddr_t eventmask;
+  void *copy = NULL;
+
+  LOG ("td_thr_set_event");
+
+  /* Fetch the old event mask from the inferior and modify it in place.  */
+  err = DB_GET_FIELD_ADDRESS (eventmask, th->th_ta_p,
+                             th->th_unique, pthread, eventbuf_eventmask, 0);
+  if (err == TD_OK)
+    err = DB_GET_STRUCT (copy, th->th_ta_p, eventmask, td_thr_events_t);
+  if (err == TD_OK)
+    {
+      uint32_t idx;
+      for (idx = 0; idx < TD_EVENTSIZE; ++idx)
+       {
+         psaddr_t word;
+         uint32_t mask;
+         err = DB_GET_FIELD_LOCAL (word, th->th_ta_p, copy,
+                                   td_thr_events_t, event_bits, idx);
+         if (err != TD_OK)
+           break;
+         mask = (uintptr_t) word;
+         mask |= event->event_bits[idx];
+         word = (psaddr_t) (uintptr_t) mask;
+         err = DB_PUT_FIELD_LOCAL (th->th_ta_p, copy,
+                                   td_thr_events_t, event_bits, idx, word);
+         if (err != TD_OK)
+           break;
+       }
+      if (err == TD_NOAPLIC)
+       {
+         err = TD_OK;
+         while (idx < TD_EVENTSIZE)
+           if (event->event_bits[idx++] != 0)
+             {
+               err = TD_NOEVENT;
+               break;
+             }
+       }
+      if (err == TD_OK)
+       /* Now write it back to the inferior.  */
+       err = DB_PUT_STRUCT (th->th_ta_p, eventmask, td_thr_events_t, copy);
+    }
+
+  return err;
+}
diff --git a/libpthread/nptl_db/td_thr_setfpregs.c b/libpthread/nptl_db/td_thr_setfpregs.c
new file mode 100644 (file)
index 0000000..01bdb53
--- /dev/null
@@ -0,0 +1,50 @@
+/* Set a thread's floating-point register set.
+   Copyright (C) 1999, 2001, 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_thr_setfpregs (const td_thrhandle_t *th, const prfpregset_t *fpregs)
+{
+  psaddr_t cancelhandling, tid;
+  td_err_e err;
+
+  LOG ("td_thr_setfpregs");
+
+  /* We have to get the state and the PID for this thread.  */
+  err = DB_GET_FIELD (cancelhandling, th->th_ta_p, th->th_unique, pthread,
+                     cancelhandling, 0);
+  if (err != TD_OK)
+    return err;
+
+  /* Only set the registers if the thread hasn't yet terminated.  */
+  if ((((int) (uintptr_t) cancelhandling) & TERMINATED_BITMASK) == 0)
+    {
+      err = DB_GET_FIELD (tid, th->th_ta_p, th->th_unique, pthread, tid, 0);
+      if (err != TD_OK)
+       return err;
+
+      if (ps_lsetfpregs (th->th_ta_p->ph, (uintptr_t) tid, fpregs) != PS_OK)
+       return TD_ERR;
+    }
+
+  return TD_OK;
+}
diff --git a/libpthread/nptl_db/td_thr_setgregs.c b/libpthread/nptl_db/td_thr_setgregs.c
new file mode 100644 (file)
index 0000000..2a9ce7e
--- /dev/null
@@ -0,0 +1,50 @@
+/* Set a thread's general register set.
+   Copyright (C) 1999, 2001, 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_thr_setgregs (const td_thrhandle_t *th, prgregset_t gregs)
+{
+  psaddr_t cancelhandling, tid;
+  td_err_e err;
+
+  LOG ("td_thr_setgregs");
+
+  /* We have to get the state and the PID for this thread.  */
+  err = DB_GET_FIELD (cancelhandling, th->th_ta_p, th->th_unique, pthread,
+                     cancelhandling, 0);
+  if (err != TD_OK)
+    return err;
+
+  /* Only set the registers if the thread hasn't yet terminated.  */
+  if ((((int) (uintptr_t) cancelhandling) & TERMINATED_BITMASK) == 0)
+    {
+      err = DB_GET_FIELD (tid, th->th_ta_p, th->th_unique, pthread, tid, 0);
+      if (err != TD_OK)
+       return err;
+
+      if (ps_lsetregs (th->th_ta_p->ph, tid - (psaddr_t) 0, gregs) != PS_OK)
+       return TD_ERR;
+    }
+
+  return TD_OK;
+}
diff --git a/libpthread/nptl_db/td_thr_setprio.c b/libpthread/nptl_db/td_thr_setprio.c
new file mode 100644 (file)
index 0000000..6032b0e
--- /dev/null
@@ -0,0 +1,30 @@
+/* Set a thread's priority.
+   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_thr_setprio (const td_thrhandle_t *th, int prio)
+{
+  /* XXX We have to figure out what has to be done.  */
+  LOG ("td_thr_setprio");
+  return TD_OK;
+}
diff --git a/libpthread/nptl_db/td_thr_setsigpending.c b/libpthread/nptl_db/td_thr_setsigpending.c
new file mode 100644 (file)
index 0000000..e2c9d7a
--- /dev/null
@@ -0,0 +1,31 @@
+/* Raise a signal for a thread.
+   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_thr_setsigpending (const td_thrhandle_t *th, unsigned char n,
+                     const sigset_t *ss)
+{
+  /* XXX We have to figure out what has to be done.  */
+  LOG ("td_thr_setsigpending");
+  return TD_OK;
+}
diff --git a/libpthread/nptl_db/td_thr_setxregs.c b/libpthread/nptl_db/td_thr_setxregs.c
new file mode 100644 (file)
index 0000000..f48877c
--- /dev/null
@@ -0,0 +1,30 @@
+/* Set a thread's extra state register set.
+   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_thr_setxregs (const td_thrhandle_t *ta, const void *addr)
+{
+  /* XXX This might have to be platform specific.  */
+  LOG ("td_thr_setxregs");
+  return TD_NOXREGS;
+}
diff --git a/libpthread/nptl_db/td_thr_sigsetmask.c b/libpthread/nptl_db/td_thr_sigsetmask.c
new file mode 100644 (file)
index 0000000..3a68aec
--- /dev/null
@@ -0,0 +1,30 @@
+/* Set a thread's signal mask.
+   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_thr_sigsetmask (const td_thrhandle_t *th, const sigset_t *ss)
+{
+  /* XXX We have to figure out what has to be done.  */
+  LOG ("td_thr_sigsetmask");
+  return TD_OK;
+}
diff --git a/libpthread/nptl_db/td_thr_tls_get_addr.c b/libpthread/nptl_db/td_thr_tls_get_addr.c
new file mode 100644 (file)
index 0000000..e7d2322
--- /dev/null
@@ -0,0 +1,43 @@
+/* Get address of thread local variable.
+   Copyright (C) 2002,2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.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 <link.h>
+#include "thread_dbP.h"
+
+td_err_e
+td_thr_tls_get_addr (const td_thrhandle_t *th,
+                    psaddr_t map_address, size_t offset, psaddr_t *address)
+{
+  td_err_e err;
+  psaddr_t modid;
+
+  /* Get the TLS module ID from the `struct link_map' in the inferior.  */
+  err = DB_GET_FIELD (modid, th->th_ta_p, map_address, link_map,
+                     l_tls_modid, 0);
+  if (err == TD_NOCAPAB)
+    return TD_NOAPLIC;
+  if (err == TD_OK)
+    {
+      err = td_thr_tlsbase (th, (uintptr_t) modid, address);
+      if (err == TD_OK)
+       *address += offset;
+    }
+  return err;
+}
diff --git a/libpthread/nptl_db/td_thr_tlsbase.c b/libpthread/nptl_db/td_thr_tlsbase.c
new file mode 100644 (file)
index 0000000..aaeda6f
--- /dev/null
@@ -0,0 +1,55 @@
+/* Locate TLS data for a thread.
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+
+td_err_e
+td_thr_tlsbase (const td_thrhandle_t *th,
+               unsigned long int modid,
+               psaddr_t *base)
+{
+  td_err_e err;
+  psaddr_t dtv, dtvslot, dtvptr;
+
+  if (modid < 1)
+    return TD_NOTLS;
+
+  /* Get the DTV pointer from the thread descriptor.  */
+  err = DB_GET_FIELD (dtv, th->th_ta_p, th->th_unique, pthread, dtvp, 0);
+  if (err != TD_OK)
+    return err;
+
+  /* Find the corresponding entry in the DTV.  */
+  err = DB_GET_FIELD_ADDRESS (dtvslot, th->th_ta_p, dtv, dtv, dtv, modid);
+  if (err != TD_OK)
+    return err;
+
+  /* Extract the TLS block address from that DTV slot.  */
+  err = DB_GET_FIELD (dtvptr, th->th_ta_p, dtvslot, dtv_t, pointer_val, 0);
+  if (err != TD_OK)
+    return err;
+
+  /* It could be that the memory for this module is not allocated for
+     the given thread.  */
+  if ((uintptr_t) dtvptr & 1)
+    return TD_TLSDEFER;
+
+  *base = dtvptr;
+  return TD_OK;
+}
diff --git a/libpthread/nptl_db/td_thr_tsd.c b/libpthread/nptl_db/td_thr_tsd.c
new file mode 100644 (file)
index 0000000..08f617b
--- /dev/null
@@ -0,0 +1,96 @@
+/* Get a thread-specific data pointer for a thread.
+   Copyright (C) 1999,2001,2002,2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_thr_tsd (const td_thrhandle_t *th, const thread_key_t tk, void **data)
+{
+  td_err_e err;
+  psaddr_t tk_seq, level1, level2, seq, value;
+  void *copy;
+  uint32_t pthread_key_2ndlevel_size, idx1st, idx2nd;
+
+  LOG ("td_thr_tsd");
+
+  /* Get the key entry.  */
+  err = DB_GET_VALUE (tk_seq, th->th_ta_p, __pthread_keys, tk);
+  if (err == TD_NOAPLIC)
+    return TD_BADKEY;
+  if (err != TD_OK)
+    return err;
+
+  /* Fail if this key is not at all used.  */
+  if (((uintptr_t) tk_seq & 1) == 0)
+    return TD_BADKEY;
+
+  /* This makes sure we have the size information on hand.  */
+  err = DB_GET_FIELD_ADDRESS (level2, th->th_ta_p, 0, pthread_key_data_level2,
+                             data, 1);
+  if (err != TD_OK)
+    return err;
+
+  /* Compute the indeces.  */
+  pthread_key_2ndlevel_size
+    = DB_DESC_NELEM (th->th_ta_p->ta_field_pthread_key_data_level2_data);
+  idx1st = tk / pthread_key_2ndlevel_size;
+  idx2nd = tk % pthread_key_2ndlevel_size;
+
+  /* Now fetch the first level pointer.  */
+  err = DB_GET_FIELD (level1, th->th_ta_p, th->th_unique, pthread,
+                     specific, idx1st);
+  if (err == TD_NOAPLIC)
+    return TD_DBERR;
+  if (err != TD_OK)
+    return err;
+
+  /* Check the pointer to the second level array.  */
+  if (level1 == 0)
+    return TD_NOTSD;
+
+  /* Locate the element within the second level array.  */
+  err = DB_GET_FIELD_ADDRESS (level2, th->th_ta_p,
+                             level1, pthread_key_data_level2, data, idx2nd);
+  if (err == TD_NOAPLIC)
+    return TD_DBERR;
+  if (err != TD_OK)
+    return err;
+
+  /* Now copy in that whole structure.  */
+  err = DB_GET_STRUCT (copy, th->th_ta_p, level2, pthread_key_data);
+  if (err != TD_OK)
+    return err;
+
+  /* Check whether the data is valid.  */
+  err = DB_GET_FIELD_LOCAL (seq, th->th_ta_p, copy, pthread_key_data, seq, 0);
+  if (err != TD_OK)
+    return err;
+  if (seq != tk_seq)
+    return TD_NOTSD;
+
+  /* Finally, fetch the value.  */
+  err = DB_GET_FIELD_LOCAL (value, th->th_ta_p, copy, pthread_key_data,
+                           data, 0);
+  if (err == TD_OK)
+    *data = value;
+
+  return err;
+}
diff --git a/libpthread/nptl_db/td_thr_validate.c b/libpthread/nptl_db/td_thr_validate.c
new file mode 100644 (file)
index 0000000..19ee940
--- /dev/null
@@ -0,0 +1,91 @@
+/* Validate a thread handle.
+   Copyright (C) 1999, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+#include <stdbool.h>
+
+static td_err_e
+check_thread_list (const td_thrhandle_t *th, psaddr_t head, bool *uninit)
+{
+  td_err_e err;
+  psaddr_t next, ofs;
+
+  err = DB_GET_FIELD (next, th->th_ta_p, head, list_t, next, 0);
+  if (err == TD_OK)
+    {
+      if (next == 0)
+       {
+         *uninit = true;
+         return TD_NOTHR;
+       }
+      err = DB_GET_FIELD_ADDRESS (ofs, th->th_ta_p, 0, pthread, list, 0);
+    }
+
+  while (err == TD_OK)
+    {
+      if (next == head)
+       return TD_NOTHR;
+
+      if (next - (ofs - (psaddr_t) 0) == th->th_unique)
+       return TD_OK;
+
+      err = DB_GET_FIELD (next, th->th_ta_p, next, list_t, next, 0);
+    }
+
+  return err;
+}
+
+
+td_err_e
+td_thr_validate (const td_thrhandle_t *th)
+{
+  td_err_e err;
+  psaddr_t list = NULL;
+
+  LOG ("td_thr_validate");
+
+  /* First check the list with threads using user allocated stacks.  */
+  bool uninit = false;
+  err = DB_GET_SYMBOL (list, th->th_ta_p, __stack_user);
+  if (err == TD_OK)
+    err = check_thread_list (th, list, &uninit);
+
+  /* If our thread is not on this list search the list with stack
+     using implementation allocated stacks.  */
+  if (err == TD_NOTHR)
+    {
+      err = DB_GET_SYMBOL (list, th->th_ta_p, stack_used);
+      if (err == TD_OK)
+       err = check_thread_list (th, list, &uninit);
+
+      if (err == TD_NOTHR && uninit)
+       {
+         /* __pthread_initialize_minimal has not run yet.
+            But the main thread still has a valid ID.  */
+         td_thrhandle_t main_th;
+         err = td_ta_map_lwp2thr (th->th_ta_p,
+                                  ps_getpid (th->th_ta_p->ph), &main_th);
+         if (err == TD_OK && th->th_unique != main_th.th_unique)
+           err = TD_NOTHR;
+       }
+    }
+
+  return err;
+}
diff --git a/libpthread/nptl_db/thread_db.h b/libpthread/nptl_db/thread_db.h
new file mode 100644 (file)
index 0000000..433b54f
--- /dev/null
@@ -0,0 +1,459 @@
+/* thread_db.h -- interface to libthread_db.so library for debugging -lpthread
+   Copyright (C) 1999,2001,2002,2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _THREAD_DB_H
+#define _THREAD_DB_H   1
+
+/* This is the debugger interface for the NPTL library.  It is
+   modelled closely after the interface with same names in Solaris
+   with the goal to share the same code in the debugger.  */
+#include <pthread.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/procfs.h>
+
+
+/* Error codes of the library.  */
+typedef enum
+{
+  TD_OK,         /* No error.  */
+  TD_ERR,        /* No further specified error.  */
+  TD_NOTHR,      /* No matching thread found.  */
+  TD_NOSV,       /* No matching synchronization handle found.  */
+  TD_NOLWP,      /* No matching light-weighted process found.  */
+  TD_BADPH,      /* Invalid process handle.  */
+  TD_BADTH,      /* Invalid thread handle.  */
+  TD_BADSH,      /* Invalid synchronization handle.  */
+  TD_BADTA,      /* Invalid thread agent.  */
+  TD_BADKEY,     /* Invalid key.  */
+  TD_NOMSG,      /* No event available.  */
+  TD_NOFPREGS,   /* No floating-point register content available.  */
+  TD_NOLIBTHREAD, /* Application not linked with thread library.  */
+  TD_NOEVENT,    /* Requested event is not supported.  */
+  TD_NOCAPAB,    /* Capability not available.  */
+  TD_DBERR,      /* Internal debug library error.  */
+  TD_NOAPLIC,    /* Operation is not applicable.  */
+  TD_NOTSD,      /* No thread-specific data available.  */
+  TD_MALLOC,     /* Out of memory.  */
+  TD_PARTIALREG,  /* Not entire register set was read or written.  */
+  TD_NOXREGS,    /* X register set not available for given thread.  */
+  TD_TLSDEFER,   /* Thread has not yet allocated TLS for given module.  */
+  TD_NOTALLOC = TD_TLSDEFER,
+  TD_VERSION,    /* Version if libpthread and libthread_db do not match.  */
+  TD_NOTLS       /* There is no TLS segment in the given module.  */
+} td_err_e;
+
+
+/* Possible thread states.  TD_THR_ANY_STATE is a pseudo-state used to
+   select threads regardless of state in td_ta_thr_iter().  */
+typedef enum
+{
+  TD_THR_ANY_STATE,
+  TD_THR_UNKNOWN,
+  TD_THR_STOPPED,
+  TD_THR_RUN,
+  TD_THR_ACTIVE,
+  TD_THR_ZOMBIE,
+  TD_THR_SLEEP,
+  TD_THR_STOPPED_ASLEEP
+} td_thr_state_e;
+
+/* Thread type: user or system.  TD_THR_ANY_TYPE is a pseudo-type used
+   to select threads regardless of type in td_ta_thr_iter().  */
+typedef enum
+{
+  TD_THR_ANY_TYPE,
+  TD_THR_USER,
+  TD_THR_SYSTEM
+} td_thr_type_e;
+
+
+/* Types of the debugging library.  */
+
+/* Handle for a process.  This type is opaque.  */
+typedef struct td_thragent td_thragent_t;
+
+/* The actual thread handle type.  This is also opaque.  */
+typedef struct td_thrhandle
+{
+  td_thragent_t *th_ta_p;
+  psaddr_t th_unique;
+} td_thrhandle_t;
+
+
+/* Forward declaration of a type defined by and for the dynamic linker.  */
+struct link_map;
+
+
+/* Flags for `td_ta_thr_iter'.  */
+#define TD_THR_ANY_USER_FLAGS  0xffffffff
+#define TD_THR_LOWEST_PRIORITY -20
+#define TD_SIGNO_MASK          NULL
+
+
+#define TD_EVENTSIZE   2
+#define BT_UISHIFT     5 /* log base 2 of BT_NBIPUI, to extract word index */
+#define BT_NBIPUI      (1 << BT_UISHIFT)       /* n bits per uint */
+#define BT_UIMASK      (BT_NBIPUI - 1)         /* to extract bit index */
+
+/* Bitmask of enabled events. */
+typedef struct td_thr_events
+{
+  uint32_t event_bits[TD_EVENTSIZE];
+} td_thr_events_t;
+
+/* Event set manipulation macros. */
+#define __td_eventmask(n) \
+  (UINT32_C (1) << (((n) - 1) & BT_UIMASK))
+#define __td_eventword(n) \
+  ((UINT32_C ((n) - 1)) >> BT_UISHIFT)
+
+#define td_event_emptyset(setp) \
+  do {                                                                       \
+    int __i;                                                                 \
+    for (__i = TD_EVENTSIZE; __i > 0; --__i)                                 \
+      (setp)->event_bits[__i - 1] = 0;                                       \
+  } while (0)
+
+#define td_event_fillset(setp) \
+  do {                                                                       \
+    int __i;                                                                 \
+    for (__i = TD_EVENTSIZE; __i > 0; --__i)                                 \
+      (setp)->event_bits[__i - 1] = UINT32_C (0xffffffff);                   \
+  } while (0)
+
+#define td_event_addset(setp, n) \
+  (((setp)->event_bits[__td_eventword (n)]) |= __td_eventmask (n))
+#define td_event_delset(setp, n) \
+  (((setp)->event_bits[__td_eventword (n)]) &= ~__td_eventmask (n))
+#define td_eventismember(setp, n) \
+  (__td_eventmask (n) & ((setp)->event_bits[__td_eventword (n)]))
+#if TD_EVENTSIZE == 2
+# define td_eventisempty(setp) \
+  (!((setp)->event_bits[0]) && !((setp)->event_bits[1]))
+#else
+# error "td_eventisempty must be changed to match TD_EVENTSIZE"
+#endif
+
+/* Events reportable by the thread implementation.  */
+typedef enum
+{
+  TD_ALL_EVENTS,                /* Pseudo-event number.  */
+  TD_EVENT_NONE = TD_ALL_EVENTS, /* Depends on context.  */
+  TD_READY,                     /* Is executable now. */
+  TD_SLEEP,                     /* Blocked in a synchronization obj.  */
+  TD_SWITCHTO,                  /* Now assigned to a process.  */
+  TD_SWITCHFROM,                /* Not anymore assigned to a process.  */
+  TD_LOCK_TRY,                  /* Trying to get an unavailable lock.  */
+  TD_CATCHSIG,                  /* Signal posted to the thread.  */
+  TD_IDLE,                      /* Process getting idle.  */
+  TD_CREATE,                    /* New thread created.  */
+  TD_DEATH,                     /* Thread terminated.  */
+  TD_PREEMPT,                   /* Preempted.  */
+  TD_PRI_INHERIT,               /* Inherited elevated priority.  */
+  TD_REAP,                      /* Reaped.  */
+  TD_CONCURRENCY,               /* Number of processes changing.  */
+  TD_TIMEOUT,                   /* Conditional variable wait timed out.  */
+  TD_MIN_EVENT_NUM = TD_READY,
+  TD_MAX_EVENT_NUM = TD_TIMEOUT,
+  TD_EVENTS_ENABLE = 31                /* Event reporting enabled.  */
+} td_event_e;
+
+/* Values representing the different ways events are reported.  */
+typedef enum
+{
+  NOTIFY_BPT,                  /* User must insert breakpoint at u.bptaddr. */
+  NOTIFY_AUTOBPT,              /* Breakpoint at u.bptaddr is automatically
+                                  inserted.  */
+  NOTIFY_SYSCALL               /* System call u.syscallno will be invoked.  */
+} td_notify_e;
+
+/* Description how event type is reported.  */
+typedef struct td_notify
+{
+  td_notify_e type;            /* Way the event is reported.  */
+  union
+  {
+    psaddr_t bptaddr;          /* Address of breakpoint.  */
+    int syscallno;             /* Number of system call used.  */
+  } u;
+} td_notify_t;
+
+/* Structure used to report event.  */
+typedef struct td_event_msg
+{
+  td_event_e event;            /* Event type being reported.  */
+  const td_thrhandle_t *th_p;  /* Thread reporting the event.  */
+  union
+  {
+# if 0
+    td_synchandle_t *sh;       /* Handle of synchronization object.  */
+#endif
+    uintptr_t data;            /* Event specific data.  */
+  } msg;
+} td_event_msg_t;
+
+/* Structure containing event data available in each thread structure.  */
+typedef struct
+{
+  td_thr_events_t eventmask;   /* Mask of enabled events.  */
+  td_event_e eventnum;         /* Number of last event.  */
+  void *eventdata;             /* Data associated with event.  */
+} td_eventbuf_t;
+
+
+/* Gathered statistics about the process.  */
+typedef struct td_ta_stats
+{
+  int nthreads;                /* Total number of threads in use.  */
+  int r_concurrency;           /* Concurrency level requested by user.  */
+  int nrunnable_num;           /* Average runnable threads, numerator.  */
+  int nrunnable_den;           /* Average runnable threads, denominator.  */
+  int a_concurrency_num;       /* Achieved concurrency level, numerator.  */
+  int a_concurrency_den;       /* Achieved concurrency level, denominator.  */
+  int nlwps_num;               /* Average number of processes in use,
+                                  numerator.  */
+  int nlwps_den;               /* Average number of processes in use,
+                                  denominator.  */
+  int nidle_num;               /* Average number of idling processes,
+                                  numerator.  */
+  int nidle_den;               /* Average number of idling processes,
+                                  denominator.  */
+} td_ta_stats_t;
+
+
+/* Since Sun's library is based on Solaris threads we have to define a few
+   types to map them to POSIX threads.  */
+typedef pthread_t thread_t;
+typedef pthread_key_t thread_key_t;
+
+
+/* Callback for iteration over threads.  */
+typedef int td_thr_iter_f (const td_thrhandle_t *, void *);
+
+/* Callback for iteration over thread local data.  */
+typedef int td_key_iter_f (thread_key_t, void (*) (void *), void *);
+
+
+
+/* Forward declaration.  This has to be defined by the user.  */
+struct ps_prochandle;
+
+
+/* Information about the thread.  */
+typedef struct td_thrinfo
+{
+  td_thragent_t *ti_ta_p;              /* Process handle.  */
+  unsigned int ti_user_flags;          /* Unused.  */
+  thread_t ti_tid;                     /* Thread ID returned by
+                                          pthread_create().  */
+  char *ti_tls;                                /* Pointer to thread-local data.  */
+  psaddr_t ti_startfunc;               /* Start function passed to
+                                          pthread_create().  */
+  psaddr_t ti_stkbase;                 /* Base of thread's stack.  */
+  long int ti_stksize;                 /* Size of thread's stack.  */
+  psaddr_t ti_ro_area;                 /* Unused.  */
+  int ti_ro_size;                      /* Unused.  */
+  td_thr_state_e ti_state;             /* Thread state.  */
+  unsigned char ti_db_suspended;       /* Nonzero if suspended by debugger. */
+  td_thr_type_e ti_type;               /* Type of the thread (system vs
+                                          user thread).  */
+  intptr_t ti_pc;                      /* Unused.  */
+  intptr_t ti_sp;                      /* Unused.  */
+  short int ti_flags;                  /* Unused.  */
+  int ti_pri;                          /* Thread priority.  */
+  lwpid_t ti_lid;                      /* Kernel PID for this thread.  */
+  sigset_t ti_sigmask;                 /* Signal mask.  */
+  unsigned char ti_traceme;            /* Nonzero if event reporting
+                                          enabled.  */
+  unsigned char ti_preemptflag;                /* Unused.  */
+  unsigned char ti_pirecflag;          /* Unused.  */
+  sigset_t ti_pending;                 /* Set of pending signals.  */
+  td_thr_events_t ti_events;           /* Set of enabled events.  */
+} td_thrinfo_t;
+
+
+
+/* Prototypes for exported library functions.  */
+
+/* Initialize the thread debug support library.  */
+extern td_err_e td_init (void);
+
+/* Historical relict.  Should not be used anymore.  */
+extern td_err_e td_log (void);
+
+/* Return list of symbols the library can request.  */
+extern const char **td_symbol_list (void);
+
+/* Generate new thread debug library handle for process PS.  */
+extern td_err_e td_ta_new (struct ps_prochandle *__ps, td_thragent_t **__ta);
+
+/* Free resources allocated for TA.  */
+extern td_err_e td_ta_delete (td_thragent_t *__ta);
+
+/* Get number of currently running threads in process associated with TA.  */
+extern td_err_e td_ta_get_nthreads (const td_thragent_t *__ta, int *__np);
+
+/* Return process handle passed in `td_ta_new' for process associated with
+   TA.  */
+extern td_err_e td_ta_get_ph (const td_thragent_t *__ta,
+                             struct ps_prochandle **__ph);
+
+/* Map thread library handle PT to thread debug library handle for process
+   associated with TA and store result in *TH.  */
+extern td_err_e td_ta_map_id2thr (const td_thragent_t *__ta, pthread_t __pt,
+                                 td_thrhandle_t *__th);
+
+/* Map process ID LWPID to thread debug library handle for process
+   associated with TA and store result in *TH.  */
+extern td_err_e td_ta_map_lwp2thr (const td_thragent_t *__ta, lwpid_t __lwpid,
+                                  td_thrhandle_t *__th);
+
+
+/* Call for each thread in a process associated with TA the callback function
+   CALLBACK.  */
+extern td_err_e td_ta_thr_iter (const td_thragent_t *__ta,
+                               td_thr_iter_f *__callback, void *__cbdata_p,
+                               td_thr_state_e __state, int __ti_pri,
+                               sigset_t *__ti_sigmask_p,
+                               unsigned int __ti_user_flags);
+
+/* Call for each defined thread local data entry the callback function KI.  */
+extern td_err_e td_ta_tsd_iter (const td_thragent_t *__ta, td_key_iter_f *__ki,
+                               void *__p);
+
+
+/* Get event address for EVENT.  */
+extern td_err_e td_ta_event_addr (const td_thragent_t *__ta,
+                                 td_event_e __event, td_notify_t *__ptr);
+
+/* Enable EVENT in global mask.  */
+extern td_err_e td_ta_set_event (const td_thragent_t *__ta,
+                                td_thr_events_t *__event);
+
+/* Disable EVENT in global mask.  */
+extern td_err_e td_ta_clear_event (const td_thragent_t *__ta,
+                                  td_thr_events_t *__event);
+
+/* Return information about last event.  */
+extern td_err_e td_ta_event_getmsg (const td_thragent_t *__ta,
+                                   td_event_msg_t *__msg);
+
+
+/* Set suggested concurrency level for process associated with TA.  */
+extern td_err_e td_ta_setconcurrency (const td_thragent_t *__ta, int __level);
+
+
+/* Enable collecting statistics for process associated with TA.  */
+extern td_err_e td_ta_enable_stats (const td_thragent_t *__ta, int __enable);
+
+/* Reset statistics.  */
+extern td_err_e td_ta_reset_stats (const td_thragent_t *__ta);
+
+/* Retrieve statistics from process associated with TA.  */
+extern td_err_e td_ta_get_stats (const td_thragent_t *__ta,
+                                td_ta_stats_t *__statsp);
+
+
+/* Validate that TH is a thread handle.  */
+extern td_err_e td_thr_validate (const td_thrhandle_t *__th);
+
+/* Return information about thread TH.  */
+extern td_err_e td_thr_get_info (const td_thrhandle_t *__th,
+                                td_thrinfo_t *__infop);
+
+/* Retrieve floating-point register contents of process running thread TH.  */
+extern td_err_e td_thr_getfpregs (const td_thrhandle_t *__th,
+                                 prfpregset_t *__regset);
+
+/* Retrieve general register contents of process running thread TH.  */
+extern td_err_e td_thr_getgregs (const td_thrhandle_t *__th,
+                                prgregset_t __gregs);
+
+/* Retrieve extended register contents of process running thread TH.  */
+extern td_err_e td_thr_getxregs (const td_thrhandle_t *__th, void *__xregs);
+
+/* Get size of extended register set of process running thread TH.  */
+extern td_err_e td_thr_getxregsize (const td_thrhandle_t *__th, int *__sizep);
+
+/* Set floating-point register contents of process running thread TH.  */
+extern td_err_e td_thr_setfpregs (const td_thrhandle_t *__th,
+                                 const prfpregset_t *__fpregs);
+
+/* Set general register contents of process running thread TH.  */
+extern td_err_e td_thr_setgregs (const td_thrhandle_t *__th,
+                                prgregset_t __gregs);
+
+/* Set extended register contents of process running thread TH.  */
+extern td_err_e td_thr_setxregs (const td_thrhandle_t *__th,
+                                const void *__addr);
+
+
+/* Get address of the given module's TLS storage area for the given thread.  */
+extern td_err_e td_thr_tlsbase (const td_thrhandle_t *__th,
+                               unsigned long int __modid,
+                               psaddr_t *__base);
+
+/* Get address of thread local variable.  */
+extern td_err_e td_thr_tls_get_addr (const td_thrhandle_t *__th,
+                                    psaddr_t __map_address, size_t __offset,
+                                    psaddr_t *__address);
+
+
+/* Enable reporting for EVENT for thread TH.  */
+extern td_err_e td_thr_event_enable (const td_thrhandle_t *__th, int __event);
+
+/* Enable EVENT for thread TH.  */
+extern td_err_e td_thr_set_event (const td_thrhandle_t *__th,
+                                 td_thr_events_t *__event);
+
+/* Disable EVENT for thread TH.  */
+extern td_err_e td_thr_clear_event (const td_thrhandle_t *__th,
+                                   td_thr_events_t *__event);
+
+/* Get event message for thread TH.  */
+extern td_err_e td_thr_event_getmsg (const td_thrhandle_t *__th,
+                                    td_event_msg_t *__msg);
+
+
+/* Set priority of thread TH.  */
+extern td_err_e td_thr_setprio (const td_thrhandle_t *__th, int __prio);
+
+
+/* Set pending signals for thread TH.  */
+extern td_err_e td_thr_setsigpending (const td_thrhandle_t *__th,
+                                     unsigned char __n, const sigset_t *__ss);
+
+/* Set signal mask for thread TH.  */
+extern td_err_e td_thr_sigsetmask (const td_thrhandle_t *__th,
+                                  const sigset_t *__ss);
+
+
+/* Return thread local data associated with key TK in thread TH.  */
+extern td_err_e td_thr_tsd (const td_thrhandle_t *__th,
+                           const thread_key_t __tk, void **__data);
+
+
+/* Suspend execution of thread TH.  */
+extern td_err_e td_thr_dbsuspend (const td_thrhandle_t *__th);
+
+/* Resume execution of thread TH.  */
+extern td_err_e td_thr_dbresume (const td_thrhandle_t *__th);
+
+#endif /* thread_db.h */
diff --git a/libpthread/nptl_db/thread_dbP.h b/libpthread/nptl_db/thread_dbP.h
new file mode 100644 (file)
index 0000000..c3d263b
--- /dev/null
@@ -0,0 +1,258 @@
+/* Private header for thread debug library
+   Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _THREAD_DBP_H
+#define _THREAD_DBP_H  1
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <assert.h>
+#include "proc_service.h"
+#include "thread_db.h"
+#include "../nptl/pthreadP.h"          /* This is for *_BITMASK only.  */
+
+#ifdef __UCLIBC__
+#define __alloca       alloca
+#endif
+
+/* Indeces for the symbol names.  */
+enum
+  {
+# define DB_STRUCT(type)               SYM_SIZEOF_##type,
+# define DB_STRUCT_FIELD(type, field)  SYM_##type##_FIELD_##field,
+# define DB_SYMBOL(name)               SYM_##name,
+# define DB_FUNCTION(name)             SYM_##name,
+# define DB_VARIABLE(name)             SYM_##name, SYM_DESC_##name,
+# include "structs.def"
+# undef DB_STRUCT
+# undef DB_STRUCT_FIELD
+# undef DB_SYMBOL
+# undef DB_FUNCTION
+# undef DB_VARIABLE
+
+    SYM_TH_UNIQUE_CONST_THREAD_AREA,
+    SYM_TH_UNIQUE_REGISTER64,
+    SYM_TH_UNIQUE_REGISTER32,
+    SYM_TH_UNIQUE_REGISTER64_THREAD_AREA,
+    SYM_TH_UNIQUE_REGISTER32_THREAD_AREA,
+
+    SYM_NUM_MESSAGES
+  };
+
+
+/* Comment out the following for less verbose output.  */
+#ifndef NDEBUG
+# define LOG(c) if (__td_debug) write (2, c "\n", strlen (c "\n"))
+extern int __td_debug attribute_hidden;
+#else
+# define LOG(c)
+#endif
+
+
+#define DB_DESC_SIZE(desc)     ((desc)[0])
+#define DB_DESC_NELEM(desc)    ((desc)[1])
+#define DB_DESC_OFFSET(desc)   ((desc)[2])
+#define DB_SIZEOF_DESC         (3 * sizeof (uint32_t))
+#define DB_DEFINE_DESC(name, size, nelem, offset) \
+  const uint32_t name[3] = { (size), (nelem), (offset) }
+typedef uint32_t db_desc_t[3];
+
+
+/* Handle for a process.  This type is opaque.  */
+struct td_thragent
+{
+  /* Chain on the list of all agent structures.  */
+  list_t list;
+
+  /* Delivered by the debugger and we have to pass it back in the
+     proc callbacks.  */
+  struct ps_prochandle *ph;
+
+  /* Cached values read from the inferior.  */
+# define DB_STRUCT(type) \
+  uint32_t ta_sizeof_##type;
+# define DB_STRUCT_FIELD(type, field) \
+  db_desc_t ta_field_##type##_##field;
+# define DB_SYMBOL(name) \
+  psaddr_t ta_addr_##name;
+# define DB_FUNCTION(name) \
+  psaddr_t ta_addr_##name;
+# define DB_VARIABLE(name) \
+  psaddr_t ta_addr_##name; \
+  db_desc_t ta_var_##name;
+# include "structs.def"
+# undef DB_STRUCT
+# undef DB_STRUCT_FIELD
+# undef DB_FUNCTION
+# undef DB_SYMBOL
+# undef DB_VARIABLE
+
+  /* The method of locating a thread's th_unique value.  */
+  enum
+    {
+      ta_howto_unknown,
+      ta_howto_reg,
+      ta_howto_reg_thread_area,
+      ta_howto_const_thread_area
+    } ta_howto;
+  union
+  {
+    uint32_t const_thread_area;        /* Constant argument to ps_get_thread_area.  */
+    /* These are as if the descriptor of the field in prregset_t,
+       but DB_DESC_NELEM is overloaded as follows: */
+    db_desc_t reg;             /* Signed bias applied to register value.  */
+    db_desc_t reg_thread_area; /* Bits to scale down register value.  */
+  } ta_howto_data;
+};
+
+
+/* List of all known descriptors.  */
+extern list_t __td_agent_list attribute_hidden;
+
+
+/* Function used to test for correct thread agent pointer.  */
+static inline bool
+ta_ok (const td_thragent_t *ta)
+{
+  list_t *runp;
+
+  list_for_each (runp, &__td_agent_list)
+    if (list_entry (runp, td_thragent_t, list) == ta)
+      return true;
+
+  return false;
+}
+
+
+/* Internal wrapper around ps_pglobal_lookup.  */
+extern ps_err_e td_lookup (struct ps_prochandle *ps,
+                          int idx, psaddr_t *sym_addr) attribute_hidden;
+
+
+
+
+/* Store in psaddr_t VAR the address of inferior's symbol NAME.  */
+#define DB_GET_SYMBOL(var, ta, name)                                         \
+  (((ta)->ta_addr_##name == 0                                                \
+    && td_lookup ((ta)->ph, SYM_##name, &(ta)->ta_addr_##name) != PS_OK)      \
+   ? TD_ERR : ((var) = (ta)->ta_addr_##name, TD_OK))
+
+/* Store in psaddr_t VAR the value of ((TYPE) PTR)->FIELD[IDX] in the inferior.
+   A target field smaller than psaddr_t is zero-extended.  */
+#define DB_GET_FIELD(var, ta, ptr, type, field, idx) \
+  _td_fetch_value ((ta), (ta)->ta_field_##type##_##field, \
+                  SYM_##type##_FIELD_##field, \
+                  (psaddr_t) 0 + (idx), (ptr), &(var))
+
+#define DB_GET_FIELD_ADDRESS(var, ta, ptr, type, field, idx) \
+  ((var) = (ptr), _td_locate_field ((ta), (ta)->ta_field_##type##_##field, \
+                                   SYM_##type##_FIELD_##field, \
+                                   (psaddr_t) 0 + (idx), &(var)))
+
+extern td_err_e _td_locate_field (td_thragent_t *ta,
+                                 db_desc_t desc, int descriptor_name,
+                                 psaddr_t idx,
+                                 psaddr_t *address) attribute_hidden;
+
+
+/* Like DB_GET_FIELD, but PTR is a local pointer to a structure that
+   has already been copied in from the inferior.  */
+#define DB_GET_FIELD_LOCAL(var, ta, ptr, type, field, idx) \
+  _td_fetch_value_local ((ta), (ta)->ta_field_##type##_##field, \
+                        SYM_##type##_FIELD_##field, \
+                        (psaddr_t) 0 + (idx), (ptr), &(var))
+
+/* Store in psaddr_t VAR the value of variable NAME[IDX] in the inferior.
+   A target value smaller than psaddr_t is zero-extended.  */
+#define DB_GET_VALUE(var, ta, name, idx)                                     \
+  (((ta)->ta_addr_##name == 0                                                \
+    && td_lookup ((ta)->ph, SYM_##name, &(ta)->ta_addr_##name) != PS_OK)      \
+   ? TD_ERR                                                                  \
+   : _td_fetch_value ((ta), (ta)->ta_var_##name, SYM_DESC_##name,            \
+                     (psaddr_t) 0 + (idx), (ta)->ta_addr_##name, &(var)))
+
+/* Helper functions for those.  */
+extern td_err_e _td_fetch_value (td_thragent_t *ta,
+                                db_desc_t field, int descriptor_name,
+                                psaddr_t idx, psaddr_t address,
+                                psaddr_t *result) attribute_hidden;
+extern td_err_e _td_fetch_value_local (td_thragent_t *ta,
+                                      db_desc_t field,
+                                      int descriptor_name,
+                                      psaddr_t idx, void *address,
+                                      psaddr_t *result) attribute_hidden;
+
+/* Store psaddr_t VALUE in ((TYPE) PTR)->FIELD[IDX] in the inferior.
+   A target field smaller than psaddr_t is zero-extended.  */
+#define DB_PUT_FIELD(ta, ptr, type, field, idx, value) \
+  _td_store_value ((ta), (ta)->ta_field_##type##_##field, \
+                  SYM_##type##_FIELD_##field, \
+                  (psaddr_t) 0 + (idx), (ptr), (value))
+
+#define DB_PUT_FIELD_LOCAL(ta, ptr, type, field, idx, value) \
+  _td_store_value_local ((ta), (ta)->ta_field_##type##_##field, \
+                        SYM_##type##_FIELD_##field, \
+                        (psaddr_t) 0 + (idx), (ptr), (value))
+
+/* Store psaddr_t VALUE in variable NAME[IDX] in the inferior.
+   A target field smaller than psaddr_t is zero-extended.  */
+#define DB_PUT_VALUE(ta, name, idx, value)                                   \
+  (((ta)->ta_addr_##name == 0                                                \
+    && td_lookup ((ta)->ph, SYM_##name, &(ta)->ta_addr_##name) != PS_OK)      \
+   ? TD_ERR                                                                  \
+   : _td_store_value ((ta), (ta)->ta_var_##name, SYM_DESC_##name,            \
+                     (psaddr_t) 0 + (idx), (ta)->ta_addr_##name, (value)))
+
+/* Helper functions for those.  */
+extern td_err_e _td_store_value (td_thragent_t *ta,
+                                db_desc_t field, int descriptor_name,
+                                psaddr_t idx, psaddr_t address,
+                                psaddr_t value) attribute_hidden;
+extern td_err_e _td_store_value_local (td_thragent_t *ta,
+                                      db_desc_t field, int descriptor_name,
+                                      psaddr_t idx, void *address,
+                                      psaddr_t value) attribute_hidden;
+
+#define DB_GET_STRUCT(var, ta, ptr, type)                                    \
+  ({ td_err_e _err = TD_OK;                                                  \
+     if ((ta)->ta_sizeof_##type == 0)                                        \
+       _err = _td_check_sizeof ((ta), &(ta)->ta_sizeof_##type,               \
+                                     SYM_SIZEOF_##type);                     \
+     if (_err == TD_OK)                                                              \
+       _err = ps_pdread ((ta)->ph, (ptr),                                    \
+                        (var) = __alloca ((ta)->ta_sizeof_##type),           \
+                        (ta)->ta_sizeof_##type)                              \
+        == PS_OK ? TD_OK : TD_ERR;                                           \
+     else                                                                    \
+       (var) = NULL;                                                         \
+     _err;                                                                   \
+  })
+#define DB_PUT_STRUCT(ta, ptr, type, copy)                                   \
+  ({ assert ((ta)->ta_sizeof_##type != 0);                                   \
+     ps_pdwrite ((ta)->ph, (ptr), (copy), (ta)->ta_sizeof_##type)            \
+       == PS_OK ? TD_OK : TD_ERR;                                            \
+  })
+
+extern td_err_e _td_check_sizeof (td_thragent_t *ta, uint32_t *sizep,
+                                 int sizep_name) attribute_hidden;
+
+#endif /* thread_dbP.h */
index 5a8668f..873684c 100644 (file)
@@ -9,7 +9,12 @@ subdirs += librt
 
 CFLAGS-librt := -DNOT_IN_libc -DIS_IN_librt $(SSP_ALL_CFLAGS)
 
-LDFLAGS-librt.so := $(LDFLAGS) $(call link.asneeded,-lc)
+ifeq ($(UCLIBC_HAS_THREADS_NATIVE),y)
+LDFLAGS-librt.so := $(LDFLAGS) $(top_builddir)lib/libdl.so     \
+                   $(top_builddir)lib/libpthread.so
+else
+LDFLAGS-librt.so := $(LDFLAGS)
+endif
 
 LIBS-librt.so := $(LIBS)
 
@@ -19,24 +24,38 @@ librt_DIR := $(top_srcdir)librt
 librt_OUT := $(top_builddir)librt
 
 ifeq ($(UCLIBC_HAS_REALTIME),y)
-librt_SRC := $(wildcard $(librt_DIR)/*.c)
-librt_OBJ := $(patsubst $(librt_DIR)/%.c,$(librt_OUT)/%.o,$(librt_SRC))
+ifeq ($(UCLIBC_HAS_THREADS_NATIVE),y)
+librt_CSRC := $(filter-out mq_notify.c timer_create.c timer_delete.c   \
+             timer_getoverr.c timer_gettime.c timer_settime.c, \
+             $(notdir $(wildcard $(librt_DIR)/*.c)))
+librt_SSRC := $(wildcard $(librt_DIR)/*.S)
+librt_OBJ := $(patsubst %.c,$(librt_OUT)/%.o,$(librt_CSRC))
+librt_OBJ += $(patsubst $(librt_DIR)/%.S,$(librt_OUT)/%.o,$(librt_SSRC))
+else
+librt_SRC := $(filter-out clock_nanosleep.c clock_getcpuclockid.c clock_gettime.c,     \
+            $(notdir $(wildcard $(librt_DIR)/*.c)))
+librt_OBJ := $(patsubst %.c,$(librt_OUT)/%.o,$(librt_SRC))
+endif
+
+ASFLAGS-mq_timedreceive.S = -D_LIBC_REENTRANT
+ASFLAGS-mq_timedsend.S = -D_LIBC_REENTRANT
 
 ifeq ($(DOPIC),y)
 librt-a-y += $(librt_OBJ:.o=.os)
 else
 librt-a-y += $(librt_OBJ)
 endif
-librt-so-y += $(librt_OBJ:.o=.os)
+librt-so-y += $(librt_OBJ:.o=.oS)
 
 lib-a-y += $(top_builddir)lib/librt.a
 lib-so-y += $(top_builddir)lib/librt.so
 endif
 
-ifeq ($(DOPIC),y)
+
+ifeq ($(DOPIC)$(UCLIBC_HAS_THREADS_NATIVE),yn)
 $(top_builddir)lib/librt.so: $(top_builddir)lib/librt.a $(libc.depend)
 else
-$(top_builddir)lib/librt.so: $(librt_OUT)/librt_so.a $(libc.depend)
+$(top_builddir)lib/librt.so: $(librt_OUT)/librt_so.a $(libc.depend) $(libpthread.depend) $(libdl.depend)
 endif
        $(call link.so,$(librt_FULL_NAME),$(MAJOR_VERSION))
 
diff --git a/librt/clock_getcpuclockid.c b/librt/clock_getcpuclockid.c
new file mode 100644 (file)
index 0000000..704c574
--- /dev/null
@@ -0,0 +1,104 @@
+/* clock_getcpuclockid -- Get a clockid_t for process CPU time.  Linux version.
+   Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <time.h>
+#include <sysdep.h>
+#include <unistd.h>
+#include <bits/kernel-features.h>
+#include "kernel-posix-cpu-timers.h"
+
+#ifndef HAS_CPUCLOCK
+# define HAS_CPUCLOCK 1
+#endif
+
+int
+clock_getcpuclockid (pid_t pid, clockid_t *clock_id)
+{
+#ifdef __NR_clock_getres
+  /* The clockid_t value is a simple computation from the PID.
+     But we do a clock_getres call to validate it.  */
+
+  const clockid_t pidclock = MAKE_PROCESS_CPUCLOCK (pid, CPUCLOCK_SCHED);
+
+# if !(__ASSUME_POSIX_CPU_TIMERS > 0)
+  extern int __libc_missing_posix_cpu_timers attribute_hidden;
+#  if !(__ASSUME_POSIX_TIMERS > 0)
+  extern int __libc_missing_posix_timers attribute_hidden;
+  if (__libc_missing_posix_timers && !__libc_missing_posix_cpu_timers)
+    __libc_missing_posix_cpu_timers = 1;
+#  endif
+  if (!__libc_missing_posix_cpu_timers)
+# endif
+    {
+      INTERNAL_SYSCALL_DECL (err);
+      int r = INTERNAL_SYSCALL (clock_getres, err, 2, pidclock, NULL);
+      if (!INTERNAL_SYSCALL_ERROR_P (r, err))
+       {
+         *clock_id = pidclock;
+         return 0;
+       }
+
+# if !(__ASSUME_POSIX_TIMERS > 0)
+      if (INTERNAL_SYSCALL_ERRNO (r, err) == ENOSYS)
+       {
+         /* The kernel doesn't support these calls at all.  */
+         __libc_missing_posix_timers = 1;
+         __libc_missing_posix_cpu_timers = 1;
+       }
+      else
+# endif
+       if (INTERNAL_SYSCALL_ERRNO (r, err) == EINVAL)
+         {
+# if !(__ASSUME_POSIX_CPU_TIMERS > 0)
+           if (pidclock == MAKE_PROCESS_CPUCLOCK (0, CPUCLOCK_SCHED)
+               || INTERNAL_SYSCALL_ERROR_P (INTERNAL_SYSCALL
+                                            (clock_getres, err, 2,
+                                             MAKE_PROCESS_CPUCLOCK
+                                             (0, CPUCLOCK_SCHED), NULL),
+                                            err))
+             /* The kernel doesn't support these clocks at all.  */
+             __libc_missing_posix_cpu_timers = 1;
+           else
+# endif
+             /* The clock_getres system call checked the PID for us.  */
+             return ESRCH;
+         }
+       else
+         return INTERNAL_SYSCALL_ERRNO (r, err);
+    }
+#endif
+
+  /* We don't allow any process ID but our own.  */
+  if (pid != 0 && pid != getpid ())
+    return EPERM;
+
+#ifdef CLOCK_PROCESS_CPUTIME_ID
+  if (HAS_CPUCLOCK)
+    {
+      /* Store the number.  */
+      *clock_id = CLOCK_PROCESS_CPUTIME_ID;
+
+      return 0;
+    }
+#endif
+
+  /* We don't have a timer for that.  */
+  return ENOENT;
+}
diff --git a/librt/clock_gettime.c b/librt/clock_gettime.c
new file mode 100644 (file)
index 0000000..8308329
--- /dev/null
@@ -0,0 +1,301 @@
+/* clock_gettime -- Get current time from a POSIX clockid_t.  Linux version.
+   Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <errno.h>
+#include <time.h>
+#include "kernel-posix-cpu-timers.h"
+#include <bits/kernel-features.h>
+
+
+#define SYSCALL_GETTIME \
+  retval = INLINE_SYSCALL (clock_gettime, 2, clock_id, tp); \
+  break
+
+#ifdef __ASSUME_POSIX_TIMERS
+
+/* This means the REALTIME and MONOTONIC clock are definitely
+   supported in the kernel.  */
+# define SYSDEP_GETTIME                                                              \
+  SYSDEP_GETTIME_CPUTIME                                                     \
+  case CLOCK_REALTIME:                                                       \
+  case CLOCK_MONOTONIC:                                                              \
+    SYSCALL_GETTIME
+
+# define __libc_missing_posix_timers 0
+#elif defined __NR_clock_gettime
+/* Is the syscall known to exist?  */
+int __libc_missing_posix_timers attribute_hidden;
+
+static inline int
+maybe_syscall_gettime (clockid_t clock_id, struct timespec *tp)
+{
+  int e = EINVAL;
+
+  if (!__libc_missing_posix_timers)
+    {
+      INTERNAL_SYSCALL_DECL (err);
+      int r = INTERNAL_SYSCALL (clock_gettime, err, 2, clock_id, tp);
+      if (!INTERNAL_SYSCALL_ERROR_P (r, err))
+       return 0;
+
+      e = INTERNAL_SYSCALL_ERRNO (r, err);
+      if (e == ENOSYS)
+       {
+         __libc_missing_posix_timers = 1;
+         e = EINVAL;
+       }
+    }
+
+  return e;
+}
+
+/* The REALTIME and MONOTONIC clock might be available.  Try the
+   syscall first.  */
+# define SYSDEP_GETTIME                                                              \
+  SYSDEP_GETTIME_CPUTIME                                                     \
+  case CLOCK_REALTIME:                                                       \
+  case CLOCK_MONOTONIC:                                                              \
+    retval = maybe_syscall_gettime (clock_id, tp);                           \
+    if (retval == 0)                                                         \
+      break;                                                                 \
+    /* Fallback code.  */                                                    \
+    if (retval == EINVAL && clock_id == CLOCK_REALTIME)                              \
+      retval = realtime_gettime (tp);                                        \
+    else                                                                     \
+      {                                                                              \
+       __set_errno (retval);                                                 \
+       retval = -1;                                                          \
+      }                                                                              \
+    break;
+#endif
+
+#ifdef __NR_clock_gettime
+/* We handled the REALTIME clock here.  */
+# define HANDLED_REALTIME      1
+# define HANDLED_CPUTIME       1
+
+# if __ASSUME_POSIX_CPU_TIMERS > 0
+
+#  define SYSDEP_GETTIME_CPU SYSCALL_GETTIME
+#  define SYSDEP_GETTIME_CPUTIME       /* Default catches them too.  */
+
+# else
+
+int __libc_missing_posix_cpu_timers attribute_hidden;
+
+static int
+maybe_syscall_gettime_cpu (clockid_t clock_id, struct timespec *tp)
+{
+  int e = EINVAL;
+
+  if (!__libc_missing_posix_cpu_timers)
+    {
+      INTERNAL_SYSCALL_DECL (err);
+      int r = INTERNAL_SYSCALL (clock_gettime, err, 2, clock_id, tp);
+      if (!INTERNAL_SYSCALL_ERROR_P (r, err))
+       return 0;
+
+      e = INTERNAL_SYSCALL_ERRNO (r, err);
+# ifndef __ASSUME_POSIX_TIMERS
+      if (e == ENOSYS)
+       {
+         __libc_missing_posix_timers = 1;
+         __libc_missing_posix_cpu_timers = 1;
+         e = EINVAL;
+       }
+      else
+# endif
+       {
+         if (e == EINVAL)
+           {
+             /* Check whether the kernel supports CPU clocks at all.
+                If not, record it for the future.  */
+             r = INTERNAL_SYSCALL (clock_getres, err, 2,
+                                   MAKE_PROCESS_CPUCLOCK (0, CPUCLOCK_SCHED),
+                                   NULL);
+             if (INTERNAL_SYSCALL_ERROR_P (r, err))
+               __libc_missing_posix_cpu_timers = 1;
+           }
+       }
+    }
+
+  return e;
+}
+
+#  define SYSDEP_GETTIME_CPU                                                 \
+  retval = maybe_syscall_gettime_cpu (clock_id, tp);                         \
+  if (retval == 0)                                                           \
+    break;                                                                   \
+  if (retval != EINVAL || !__libc_missing_posix_cpu_timers)                  \
+    {                                                                        \
+      __set_errno (retval);                                                  \
+      retval = -1;                                                           \
+      break;                                                                 \
+    }                                                                        \
+  retval = -1 /* Otherwise continue on to the HP_TIMING version.  */;
+
+static inline int
+maybe_syscall_gettime_cputime (clockid_t clock_id, struct timespec *tp)
+{
+  return maybe_syscall_gettime_cpu
+    (clock_id == CLOCK_THREAD_CPUTIME_ID
+     ? MAKE_THREAD_CPUCLOCK (0, CPUCLOCK_SCHED)
+     : MAKE_PROCESS_CPUCLOCK (0, CPUCLOCK_SCHED),
+     tp);
+}
+
+#  define SYSDEP_GETTIME_CPUTIME                                             \
+    case CLOCK_PROCESS_CPUTIME_ID:                                           \
+    case CLOCK_THREAD_CPUTIME_ID:                                            \
+      retval = maybe_syscall_gettime_cputime (clock_id, tp);                 \
+      if (retval == 0)                                                       \
+       break;                                                                \
+      if (retval != EINVAL || !__libc_missing_posix_cpu_timers)                      \
+       {                                                                     \
+         __set_errno (retval);                                               \
+         retval = -1;                                                        \
+         break;                                                              \
+       }                                                                     \
+      retval = hp_timing_gettime (clock_id, tp);                             \
+      break;
+#  if !HP_TIMING_AVAIL
+#   define hp_timing_gettime(clock_id, tp) (__set_errno (EINVAL), -1)
+#  endif
+
+# endif
+#endif
+
+#include <errno.h>
+#include <stdint.h>
+#include <time.h>
+#include <sys/time.h>
+#include <libc-internal.h>
+#include <ldsodefs.h>
+
+
+#if HP_TIMING_AVAIL
+/* Clock frequency of the processor.  We make it a 64-bit variable
+   because some jokers are already playing with processors with more
+   than 4GHz.  */
+static hp_timing_t freq;
+
+
+/* This function is defined in the thread library.  */
+extern int __pthread_clock_gettime (clockid_t clock_id, hp_timing_t freq,
+                                   struct timespec *tp)
+     __attribute__ ((__weak__));
+
+static int
+hp_timing_gettime (clockid_t clock_id, struct timespec *tp)
+{
+  hp_timing_t tsc;
+
+  if (__builtin_expect (freq == 0, 0))
+    {
+      /* This can only happen if we haven't initialized the `freq'
+        variable yet.  Do this now. We don't have to protect this
+        code against multiple execution since all of them should
+        lead to the same result.  */
+      freq = __get_clockfreq ();
+      if (__builtin_expect (freq == 0, 0))
+       /* Something went wrong.  */
+       return -1;
+    }
+
+  if (clock_id != CLOCK_PROCESS_CPUTIME_ID
+      && __pthread_clock_gettime != NULL)
+    return __pthread_clock_gettime (clock_id, freq, tp);
+
+  /* Get the current counter.  */
+  HP_TIMING_NOW (tsc);
+
+  /* Compute the offset since the start time of the process.  */
+  tsc -= GL(dl_cpuclock_offset);
+
+  /* Compute the seconds.  */
+  tp->tv_sec = tsc / freq;
+
+  /* And the nanoseconds.  This computation should be stable until
+     we get machines with about 16GHz frequency.  */
+  tp->tv_nsec = ((tsc % freq) * UINT64_C (1000000000)) / freq;
+
+  return 0;
+}
+#endif
+
+
+static inline int
+realtime_gettime (struct timespec *tp)
+{
+  struct timeval tv;
+  int retval = gettimeofday (&tv, NULL);
+  if (retval == 0)
+    /* Convert into `timespec'.  */
+    TIMEVAL_TO_TIMESPEC (&tv, tp);
+  return retval;
+}
+
+librt_hidden_proto (clock_gettime)
+/* Get current value of CLOCK and store it in TP.  */
+int
+clock_gettime (clockid_t clock_id, struct timespec *tp)
+{
+  int retval = -1;
+#ifndef HANDLED_REALTIME
+  struct timeval tv;
+#endif
+
+  switch (clock_id)
+    {
+#ifdef SYSDEP_GETTIME
+      SYSDEP_GETTIME;
+#endif
+
+#ifndef HANDLED_REALTIME
+    case CLOCK_REALTIME:
+      retval = gettimeofday (&tv, NULL);
+      if (retval == 0)
+       TIMEVAL_TO_TIMESPEC (&tv, tp);
+      break;
+#endif
+
+    default:
+#ifdef SYSDEP_GETTIME_CPU
+      SYSDEP_GETTIME_CPU;
+#endif
+#if HP_TIMING_AVAIL
+      if ((clock_id & ((1 << CLOCK_IDFIELD_SIZE) - 1))
+         == CLOCK_THREAD_CPUTIME_ID)
+       retval = hp_timing_gettime (clock_id, tp);
+      else
+#endif
+       __set_errno (EINVAL);
+      break;
+
+#if HP_TIMING_AVAIL && !defined HANDLED_CPUTIME
+    case CLOCK_PROCESS_CPUTIME_ID:
+      retval = hp_timing_gettime (clock_id, tp);
+      break;
+#endif
+    }
+
+  return retval;
+}
+librt_hidden_def (clock_gettime)
diff --git a/librt/clock_nanosleep.c b/librt/clock_nanosleep.c
new file mode 100644 (file)
index 0000000..69e6008
--- /dev/null
@@ -0,0 +1,96 @@
+/* Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <time.h>
+#include <errno.h>
+
+#include <sysdep-cancel.h>
+#include <bits/kernel-features.h>
+#include "kernel-posix-cpu-timers.h"
+
+
+#ifdef __ASSUME_POSIX_TIMERS
+/* We can simply use the syscall.  The CPU clocks are not supported
+   with this function.  */
+int
+clock_nanosleep (clockid_t clock_id, int flags, const struct timespec *req,
+                struct timespec *rem)
+{
+  INTERNAL_SYSCALL_DECL (err);
+  int r;
+
+  if (clock_id == CLOCK_THREAD_CPUTIME_ID)
+    return EINVAL;
+  if (clock_id == CLOCK_PROCESS_CPUTIME_ID)
+    clock_id = MAKE_PROCESS_CPUCLOCK (0, CPUCLOCK_SCHED);
+
+  if (SINGLE_THREAD_P)
+    r = INTERNAL_SYSCALL (clock_nanosleep, err, 4, clock_id, flags, req, rem);
+  else
+    {
+      int oldstate = LIBC_CANCEL_ASYNC ();
+
+      r = INTERNAL_SYSCALL (clock_nanosleep, err, 4, clock_id, flags, req,
+                           rem);
+
+      LIBC_CANCEL_RESET (oldstate);
+    }
+
+  return (INTERNAL_SYSCALL_ERROR_P (r, err)
+         ? INTERNAL_SYSCALL_ERRNO (r, err) : 0);
+}
+
+#else
+# ifdef __NR_clock_nanosleep
+/* Is the syscall known to exist?  */
+extern int __libc_missing_posix_timers attribute_hidden;
+
+/* The REALTIME and MONOTONIC clock might be available.  Try the
+   syscall first.  */
+#  define SYSDEP_NANOSLEEP \
+  if (!__libc_missing_posix_timers)                                          \
+    {                                                                        \
+      clockid_t syscall_clockid;                                             \
+      INTERNAL_SYSCALL_DECL (err);                                           \
+                                                                             \
+      if (clock_id == CLOCK_THREAD_CPUTIME_ID)                               \
+       return EINVAL;                                                        \
+      if (clock_id == CLOCK_PROCESS_CPUTIME_ID)                                      \
+       syscall_clockid = MAKE_PROCESS_CPUCLOCK (0, CPUCLOCK_SCHED);          \
+      else                                                                   \
+       syscall_clockid = clock_id;                                           \
+                                                                             \
+      int oldstate = LIBC_CANCEL_ASYNC ();                                   \
+                                                                             \
+      int r = INTERNAL_SYSCALL (clock_nanosleep, err, 4,                     \
+                               syscall_clockid, flags, req, rem);            \
+                                                                             \
+      LIBC_CANCEL_RESET (oldstate);                                          \
+                                                                             \
+      if (!INTERNAL_SYSCALL_ERROR_P (r, err))                                \
+       return 0;                                                             \
+                                                                             \
+      if (INTERNAL_SYSCALL_ERRNO (r, err) != ENOSYS)                         \
+       return INTERNAL_SYSCALL_ERRNO (r, err);                               \
+                                                                             \
+      __libc_missing_posix_timers = 1;                                       \
+    }
+# endif
+
+# include <sysdeps/unix/clock_nanosleep.c>
+#endif
diff --git a/librt/kernel-posix-cpu-timers.h b/librt/kernel-posix-cpu-timers.h
new file mode 100644 (file)
index 0000000..164a90d
--- /dev/null
@@ -0,0 +1,18 @@
+/* Parameters for the Linux kernel ABI for CPU clocks.  */
+
+#define CPUCLOCK_PID(clock)            ((pid_t) ~((clock) >> 3))
+#define CPUCLOCK_PERTHREAD(clock) \
+       (((clock) & (clockid_t) CPUCLOCK_PERTHREAD_MASK) != 0)
+#define CPUCLOCK_PID_MASK      7
+#define CPUCLOCK_PERTHREAD_MASK        4
+#define CPUCLOCK_WHICH(clock)  ((clock) & (clockid_t) CPUCLOCK_CLOCK_MASK)
+#define CPUCLOCK_CLOCK_MASK    3
+#define CPUCLOCK_PROF          0
+#define CPUCLOCK_VIRT          1
+#define CPUCLOCK_SCHED         2
+#define CPUCLOCK_MAX           3
+
+#define MAKE_PROCESS_CPUCLOCK(pid, clock) \
+       ((~(clockid_t) (pid) << 3) | (clockid_t) (clock))
+#define MAKE_THREAD_CPUCLOCK(tid, clock) \
+       MAKE_PROCESS_CPUCLOCK((tid), (clock) | CPUCLOCK_PERTHREAD_MASK)
index bf246c9..f8bfdc2 100644 (file)
 #include <pthread.h>
 #endif
 
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+/* Nonzero if the system calls are not available.  */
+extern int __no_posix_timers attribute_hidden;
+
+/* Callback to start helper thread.  */
+extern void __start_helper_thread (void) attribute_hidden;
+
+/* Control variable for helper thread creation.  */
+extern pthread_once_t __helper_once attribute_hidden;
+
+/* TID of the helper thread.  */
+extern pid_t __helper_tid attribute_hidden;
+
+/* List of active SIGEV_THREAD timers.  */
+extern struct timer *__active_timer_sigev_thread attribute_hidden;
+/* Lock for the __active_timer_sigev_thread.  */
+extern pthread_mutex_t __active_timer_sigev_thread_lock attribute_hidden;
+#endif
+
 /* Type of timers in the kernel */
 typedef int kernel_timer_t;
 
@@ -33,4 +52,7 @@ struct timer {
 #ifdef __UCLIBC_HAS_THREADS__
     pthread_attr_t attr;
 #endif
+
+    /* Next element in list of active SIGEV_THREAD timers. */
+    struct timer *next;
 };
index c0392b0..40447df 100644 (file)
@@ -6,13 +6,18 @@
 #include <stddef.h>
 #include <sys/syscall.h>
 #include <mqueue.h>
+#warning FIXME: hard dependency on ADVANCED REALTIME feature
 
+librt_hidden_proto(mq_timedreceive)
+
+#ifndef __UCLIBC_HAS_THREADS_NATIVE__
 #ifdef __NR_mq_timedreceive
 #define __NR___syscall_mq_timedreceive __NR_mq_timedreceive
-static _syscall5(int, __syscall_mq_timedreceive, int, mqdes,
-                char *, msg_ptr, size_t, msg_len, unsigned int *,
-                msg_prio, const void *, abs_timeout)
-# if defined __USE_XOPEN2K && defined __UCLIBC_HAS_ADVANCED_REALTIME__
+static __inline__ _syscall5(int, __syscall_mq_timedreceive, int, mqdes,
+                       char *, msg_ptr, size_t, msg_len, unsigned int *,
+                       msg_prio, const void *, abs_timeout);
+#endif
+
 /*
  * Receive the oldest from highest priority messages.
  * Stop waiting if abs_timeout expires.
@@ -21,31 +26,21 @@ ssize_t mq_timedreceive(mqd_t mqdes, char *msg_ptr, size_t msg_len,
                        unsigned int *msg_prio,
                        const struct timespec *abs_timeout)
 {
+#ifdef __NR_mq_timedreceive
        return __syscall_mq_timedreceive(mqdes, msg_ptr, msg_len, msg_prio,
                                         abs_timeout);
+#else
+       errno = ENOSYS;
+       return -1;
+#endif
 }
-# endif
+
+librt_hidden_def(mq_timedreceive)
+#endif
 
 /* Receive the oldest from highest priority messages */
 ssize_t mq_receive(mqd_t mqdes, char *msg_ptr, size_t msg_len,
                   unsigned int *msg_prio)
 {
-       return __syscall_mq_timedreceive(mqdes, msg_ptr, msg_len, msg_prio, NULL);
+       return mq_timedreceive(mqdes, msg_ptr, msg_len, msg_prio, NULL);
 }
-#elif defined __UCLIBC_HAS_STUBS__
-# if defined __USE_XOPEN2K && defined __UCLIBC_HAS_ADVANCED_REALTIME__
-ssize_t mq_timedreceive(mqd_t mqdes attribute_unused, char *msg_ptr attribute_unused,
-                       size_t msg_len attribute_unused, unsigned int *msg_prio attribute_unused,
-                       const struct timespec *abs_timeout attribute_unused)
-{
-       __set_errno(ENOSYS);
-       return -1;
-}
-# endif
-ssize_t mq_receive(mqd_t mqdes attribute_unused, char *msg_ptr attribute_unused,
-                  size_t msg_len attribute_unused, unsigned int *msg_prio attribute_unused)
-{
-       __set_errno(ENOSYS);
-       return -1;
-}
-#endif
index 4c1a492..f0fcfa3 100644 (file)
@@ -6,14 +6,18 @@
 #include <stddef.h>
 #include <sys/syscall.h>
 #include <mqueue.h>
+#warning FIXME: hard dependency on ADVANCED REALTIME feature
 
+librt_hidden_proto(mq_timedsend)
+
+#ifndef __UCLIBC_HAS_THREADS_NATIVE__
 #ifdef __NR_mq_timedsend
 #define __NR___syscall_mq_timedsend __NR_mq_timedsend
-static _syscall5(int, __syscall_mq_timedsend, int, mqdes,
-                const char *, msg_ptr, size_t, msg_len, unsigned int,
-                msg_prio, const void *, abs_timeout);
+static __inline__ _syscall5(int, __syscall_mq_timedsend, int, mqdes,
+                       const char *, msg_ptr, size_t, msg_len, unsigned int,
+                       msg_prio, const void *, abs_timeout);
+#endif
 
-# if defined __USE_XOPEN2K && defined __UCLIBC_HAS_ADVANCED_REALTIME__
 /*
  * Add a message to queue. If O_NONBLOCK is set and queue is full, wait
  * for sufficient room in the queue until abs_timeout expires.
@@ -21,31 +25,21 @@ static _syscall5(int, __syscall_mq_timedsend, int, mqdes,
 int mq_timedsend(mqd_t mqdes, const char *msg_ptr, size_t msg_len,
                 unsigned int msg_prio, const struct timespec *abs_timeout)
 {
+#ifdef __NR_mq_timedsend
        return __syscall_mq_timedsend(mqdes, msg_ptr, msg_len, msg_prio,
                                      abs_timeout);
+#else
+       errno = ENOSYS;
+       return -1;
+#endif
 }
-# endif
+
+librt_hidden_def(mq_timedsend)
+#endif
 
 /* Add a message to queue */
 int mq_send(mqd_t mqdes, const char *msg_ptr, size_t msg_len,
            unsigned int msg_prio)
 {
-       return __syscall_mq_timedsend(mqdes, msg_ptr, msg_len, msg_prio, NULL);
+       return mq_timedsend(mqdes, msg_ptr, msg_len, msg_prio, NULL);
 }
-#elif defined __UCLIBC_HAS_STUBS__
-# if defined __USE_XOPEN2K && defined __UCLIBC_HAS_ADVANCED_REALTIME__
-int mq_timedsend(mqd_t mqdes attribute_unused, const char *msg_ptr attribute_unused,
-                size_t msg_len attribute_unused, unsigned int msg_prio attribute_unused,
-                const struct timespec *abs_timeout attribute_unused)
-{
-       __set_errno(ENOSYS);
-       return -1;
-}
-# endif
-int mq_send(mqd_t mqdes attribute_unused, const char *msg_ptr attribute_unused,
-           size_t msg_len attribute_unused, unsigned int msg_prio attribute_unused)
-{
-       __set_errno(ENOSYS);
-       return -1;
-}
-#endif
diff --git a/librt/mq_timedreceive.S b/librt/mq_timedreceive.S
new file mode 100644 (file)
index 0000000..015eb88
--- /dev/null
@@ -0,0 +1,10 @@
+#include <sysdep-cancel.h>
+#ifndef __NR_mq_timedreceive
+#error Missing definition of NR_timedreceive needed for cancellation.
+#endif
+PSEUDO (__mq_timedreceive, mq_timedreceive, 5)
+ret
+PSEUDO_END(__mq_timedreceive)
+librt_hidden_def (__mq_timedreceive)
+weak_alias (__mq_timedreceive, mq_timedreceive)
+librt_hidden_weak (mq_timedreceive)
diff --git a/librt/mq_timedsend.S b/librt/mq_timedsend.S
new file mode 100644 (file)
index 0000000..67758a3
--- /dev/null
@@ -0,0 +1,10 @@
+#include <sysdep-cancel.h>
+#ifndef __NR_mq_timedsend
+#error Missing definition of NR_timedsend needed for cancellation.
+#endif
+PSEUDO (__mq_timedsend, mq_timedsend, 5)
+ret
+PSEUDO_END(__mq_timedsend)
+librt_hidden_def (__mq_timedsend)
+weak_alias (__mq_timedsend, mq_timedsend)
+librt_hidden_weak (mq_timedsend)
index f4fc7c7..464130d 100644 (file)
@@ -163,7 +163,7 @@ nptl/tst-detach1
 nptl/tst-eintr[1-5]
 nptl/tst-exec[2-4]
 nptl/tst-exit[1-3]
-nptl/tst-flock1
+nptl/tst-flock[1-2]
 nptl/tst-fork[1-4]
 nptl/tst-initializers1
 nptl/tst-join[1-5]
index bd68884..857ac8a 100644 (file)
@@ -26,6 +26,9 @@ endif
 ifneq ($(UCLIBC_HAS_REGEX),y)
        DIRS := $(filter-out regex,$(DIRS))
 endif
+ifneq ($(UCLIBC_HAS_THREADS_NATIVE),y)
+       DIRS := $(filter-out tls nptl,$(DIRS))
+endif
 ifneq ($(UCLIBC_HAS_WCHAR),y)
        DIRS := $(filter-out locale-mbwc,$(DIRS))
 endif
@@ -41,7 +44,7 @@ endif
 
 test check all: run
 
-run: subdirs_run
+run: compile subdirs_run
 
 compile: $(top_builddir)/$(LOCAL_INSTALL_PATH) subdirs_compile
 
index a84a7db..2131a7b 100644 (file)
@@ -64,9 +64,9 @@ CFLAGS         += $(OPTIMIZATION) $(CPU_CFLAGS) $(XWARNINGS)
 
 # Can't add $(OPTIMIZATION) here, it may be target-specific.
 # Just adding -Os for now.
-HOST_CFLAGS    += $(XCOMMON_CFLAGS) -Os $(XWARNINGS)
+HOST_CFLAGS    += $(XCOMMON_CFLAGS) -Os $(XWARNINGS) -std=gnu99
 
-LDFLAGS        := $(CPU_LDFLAGS-y) -Wl,-z,defs -Wl,-z,now
+LDFLAGS        := $(CPU_LDFLAGS-y) -Wl,-z,now
 ifeq ($(DODEBUG),y)
        CFLAGS        += -g
        HOST_CFLAGS   += -g
@@ -78,8 +78,7 @@ else
 endif
 
 ifneq ($(HAVE_SHARED),y)
-       LDFLAGS       += -Wl,-static
-       HOST_LDFLAGS  += -Wl,-static
+       LDFLAGS       += -Wl,-static -static-libgcc
 endif
 
 LDFLAGS += -B$(top_builddir)lib -Wl,-rpath,$(top_builddir)lib -Wl,-rpath-link,$(top_builddir)lib
index ce89062..43562f2 100644 (file)
@@ -21,6 +21,10 @@ endif
 U_TARGETS := $(TESTS)
 G_TARGETS := $(addsuffix _glibc,$(U_TARGETS))
 
+ifneq ($(GLIBC_TESTS_DISABLED),)
+G_TARGETS := $(filter-out $(GLIBC_TESTS_DISABLED),$(G_TARGETS))
+endif
+
 ifeq ($(GLIBC_ONLY),)
 TARGETS   += $(U_TARGETS)
 endif
@@ -29,12 +33,12 @@ TARGETS   += $(G_TARGETS)
 endif
 
 CLEAN_TARGETS := $(U_TARGETS) $(G_TARGETS)
-CLEAN_TARGETS += $(TESTS_DISABLED) $(addsuffix _glibc,$(TESTS_DISABLED))
+CLEAN_TARGETS += $(TESTS_DISABLED) $(addsuffix _glibc,$(TESTS_DISABLED)) $(GLIBC_TESTS_DISABLED)
 COMPILE_TARGETS :=  $(TARGETS)
 RUN_TARGETS := $(addsuffix .exe,$(TARGETS))
 # provide build rules even for disabled tests:
 U_TARGETS += $(TESTS_DISABLED)
-G_TARGETS += $(addsuffix _glibc,$(TESTS_DISABLED))
+G_TARGETS += $(addsuffix _glibc,$(TESTS_DISABLED)) $(GLIBC_TESTS_DISABLED)
 TARGETS += $(SHELL_TESTS)
 CFLAGS += $(CFLAGS_$(notdir $(CURDIR)))
 
@@ -76,9 +80,8 @@ define exec_test
 endef
 
 test check all: run
-run: $(RUN_TARGETS) compile
-
-$(RUN_TARGETS): $(TARGETS)
+run: $(RUN_TARGETS)
+$(RUN_TARGETS):
        $(exec_test)
        $(diff_test)
 ifeq ($(UCLIBC_ONLY),)
index ef15d86..92d14b9 100644 (file)
@@ -4,4 +4,9 @@
 top_builddir=../../
 include ../Rules.mak
 -include Makefile.in
+ifneq ($(HAVE_SHARED),y)
+TESTS_DISABLED := test3
+LDFLAGS_libtest.so := -lpthread
+endif
+
 include ../Test.mak
diff --git a/test/nptl/Makefile b/test/nptl/Makefile
new file mode 100644 (file)
index 0000000..c22b635
--- /dev/null
@@ -0,0 +1,8 @@
+# uClibc NPTL tests
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+
+top_builddir=../../
+top_srcdir=../../
+include ../Rules.mak
+-include Makefile.in
+include ../Test.mak
diff --git a/test/nptl/Makefile.in b/test/nptl/Makefile.in
new file mode 100644 (file)
index 0000000..b8e140b
--- /dev/null
@@ -0,0 +1,161 @@
+# uClibc NPTL tests
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+
+TESTS := tst-align tst-align2 tst-atfork1 tst-attr1 tst-attr2 tst-attr3        \
+       tst-barrier1 tst-barrier2 tst-barrier3 tst-barrier4 tst-basic1  \
+       tst-basic2 tst-basic3 tst-basic4 tst-basic5 tst-basic6          \
+       tst-cancel1 tst-cancel2 tst-cancel3 tst-cancel6 tst-cancel7     \
+       tst-cancel8 tst-cancel9 tst-cancel10 tst-cancel11 tst-cancel12  \
+       tst-cancel13 tst-cancel14 tst-cancel15 tst-cancel16             \
+       tst-cancel19 tst-cancel20 tst-cancel21 tst-cancel22             \
+       tst-cleanup0 tst-cleanup1 tst-cleanup2 tst-cleanup3             \
+       tst-cleanup4 tst-clock1 tst-clock2 tst-cond1 tst-cond2          \
+       tst-cond3 tst-cond4 tst-cond5 tst-cond6 tst-cond7 tst-cond8     \
+       tst-cond9 tst-cond10 tst-cond11 tst-cond12 tst-cond13           \
+       tst-cond14 tst-cond15 tst-cond16 tst-cond17 tst-cond18          \
+       tst-cond19 tst-cond20 tst-cond21 tst-detach1 tst-eintr1         \
+       tst-eintr2 tst-eintr3 tst-eintr4 tst-eintr5 tst-exec2 tst-exec3 \
+       tst-exec4 tst-exit1 tst-exit2 tst-exit3 tst-flock1 tst-flock2   \
+       tst-fork1 tst-fork2 tst-fork3 tst-fork4 tst-initializers1       \
+       tst-join1 tst-join2 tst-join3 tst-join4 tst-join5 tst-key1      \
+       tst-key2 tst-key3 tst-key4 tst-kill1 tst-kill2 tst-kill3        \
+       tst-kill4 tst-kill5 tst-kill6 tst-mutex1 tst-mutex2 tst-mutex3  \
+       tst-mutex4 tst-mutex5 tst-mutex6 tst-mutex7 tst-mutex8          \
+       tst-mutex9 tst-mutex5a tst-mutex7a tst-once1 tst-once2          \
+       tst-once3 tst-once4 tst-popen1 tst-raise1 tst-rwlock1           \
+       tst-rwlock2 tst-rwlock3 tst-rwlock4 tst-rwlock5 tst-rwlock6     \
+       tst-rwlock7 tst-rwlock8 tst-rwlock9 tst-rwlock10 tst-rwlock11   \
+       tst-rwlock12 tst-rwlock13 tst-rwlock14 tst-sched1 tst-sem1      \
+       tst-sem2 tst-sem3 tst-sem4 tst-sem5 tst-sem6 tst-sem7 tst-sem8  \
+       tst-sem9 tst-signal1 tst-signal2 tst-signal3 tst-signal4        \
+       tst-signal5 tst-signal6 tst-spin1 tst-spin2 tst-spin3           \
+       tst-stack1 tst-stack2 tst-stdio1 tst-stdio2 tst-sysconf         \
+       tst-tls1 tst-tls2 tst-tls3 tst-tls4 tst-tls5 tst-tsd1 tst-tsd2  \
+       tst-tsd3 tst-tsd4 tst-tsd5 tst-umask1
+
+#
+# These are for the RT library and POSIX timers.
+#
+TESTS += tst-clock tst-clock_nanosleep tst-cpuclock1 tst-cpuclock2     \
+       tst-cputimer1 tst-cputimer2 tst-cputimer3 tst-mqueue1           \
+       tst-mqueue2 tst-mqueue3 tst-mqueue4 tst-mqueue5 tst-mqueue6     \
+       tst-mqueue7 tst-mqueue8 tst-mqueue9 tst-timer2 tst-timer3       \
+       tst-timer4 tst-timer5
+
+ifeq ($(UCLIBC_HAS_OBSOLETE_BSD_SIGNAL),)
+TESTS_DISABLED += tst-exec2 tst-exec3 tst-exec4
+endif
+
+GLIBC_TESTS_DISABLED := tst-eintr1_glibc tst-eintr2_glibc \
+       tst-eintr3_glibc tst-eintr4_glibc tst-eintr5_glibc \
+       tst-tls1_glibc tst-tls2_glibc
+
+
+ifeq ($(HAVE_SHARED),)
+TESTS_DISABLED += tst-tls3 tst-tls4 tst-tls5
+else
+GLIBC_TESTS_DISABLED += tst-tls3_glibc tst-tls4_glibc tst-tls5_glibc
+endif
+
+PTDIR := $(top_builddir)libpthread/nptl
+SYSDEPS_DIR := $(top_srcdir)libc/sysdeps
+
+EXTRA_CFLAGS := -DNOT_IN_libc=1 -D_LIBC -D__USE_GNU -std=gnu99 \
+       -I$(SYSDEPS_DIR)/linux \
+       -I$(SYSDEPS_DIR)/linux/$(TARGET_ARCH) \
+       -I$(PTDIR) -I$(PTDIR)/sysdeps/unix/sysv/linux/$(TARGET_ARCH)    \
+       -I$(PTDIR)/sysdeps/$(TARGET_ARCH)                               \
+       -I$(PTDIR)/sysdeps/unix/sysv/linux                              \
+       -I$(PTDIR)/sysdeps/pthread                                      \
+       -I$(PTDIR)/sysdeps/pthread/bits                                 \
+       -I$(PTDIR)/sysdeps/generic                                      \
+       -I$(top_builddir)ldso/include                                   \
+       -I$(top_builddir)ldso/ldso/$(TARGET_ARCH)                       \
+       -I$(top_builddir)include                                        \
+       -include $(top_builddir)include/libc-symbols.h
+
+ifeq ($(TARGET_ARCH),i386)
+CFLAGS_tst-align.o := -malign-double -mpreferred-stack-boundary=4
+endif
+ifeq ($(TARGET_ARCH),i686)
+CFLAGS_tst-align.o := -malign-double -mpreferred-stack-boundary=4 -msse
+endif
+CFLAGS_tst-cleanup4aux.o := -W -Wall -sjh
+CFLAGS_tst-initializers1.o := -W -Wall -Werror
+CFLAGS_tst-tls3.o := tst-tls3mod.so
+CFLAGS_tst-tls4.o := tst-tls4moda.so tst-tls4modb.so
+CFLAGS_tst-tls5.o := tst-tls5mod.so
+CFLAGS_tst-tls3mod.so := -fPIC -DPIC -DSHARED -shared -DNOT_IN_libc
+CFLAGS_tst-tls4moda.so := -fPIC -DPIC -DSHARED -shared -DNOT_IN_libc
+CFLAGS_tst-tls4modb.so := -fPIC -DPIC -DSHARED -shared -DNOT_IN_libc
+CFLAGS_tst-tls5mod.so := -fPIC -DPIC -DSHARED -shared -DNOT_IN_libc
+CFLAGS_tst-tls5moda.so := -fPIC -DPIC -DSHARED -shared -DNOT_IN_libc
+CFLAGS_tst-tls5modb.so := -fPIC -DPIC -DSHARED -shared -DNOT_IN_libc
+CFLAGS_tst-tls5modc.so := -fPIC -DPIC -DSHARED -shared -DNOT_IN_libc
+CFLAGS_tst-tls5modd.so := -fPIC -DPIC -DSHARED -shared -DNOT_IN_libc
+CFLAGS_tst-tls5mode.so := -fPIC -DPIC -DSHARED -shared -DNOT_IN_libc
+CFLAGS_tst-tls5modf.so := -fPIC -DPIC -DSHARED -shared -DNOT_IN_libc
+
+EXTRA_LDFLAGS := -lpthread
+
+LDFLAGS_tst-cleanup4 := tst-cleanup4aux.o
+LDFLAGS_tst-clock2 := -lrt
+LDFLAGS_tst-cond11 := -lrt
+LDFLAGS_tst-cond19 := -lrt
+LDFLAGS_tst-rwlock14 := -lrt
+LDFLAGS_tst-tls3 := -ldl -rdynamic tst-tls3mod.so
+LDFLAGS_tst-tls4 := -ldl
+LDFLAGS_tst-tls5 :=  tst-tls5mod.so
+LDFLAGS_tst-clock := -lrt
+LDFLAGS_tst-clock_nanosleep := -lrt
+LDFLAGS_tst-cpuclock1 := -lrt
+LDFLAGS_tst-cpuclock2 := -lrt -lpthread
+LDFLAGS_tst-cputimer1 := -lrt -lpthread
+LDFLAGS_tst-cputimer2 := -lrt -lpthread
+LDFLAGS_tst-cputimer3 := -lrt -lpthread
+LDFLAGS_tst-mqueue1 := -lrt
+LDFLAGS_tst-mqueue2 := -lrt
+LDFLAGS_tst-mqueue3 := -lrt -lpthread
+LDFLAGS_tst-mqueue4 := -lrt
+LDFLAGS_tst-mqueue5 := -lrt -lpthread
+LDFLAGS_tst-mqueue6 := -lrt -lpthread
+LDFLAGS_tst-mqueue7 := -lrt
+LDFLAGS_tst-mqueue8 := -lrt
+LDFLAGS_tst-mqueue9 := -lrt
+LDFLAGS_tst-timer2 := -lrt -lpthread
+LDFLAGS_tst-timer3 := -lrt -lpthread
+LDFLAGS_tst-timer4 := -lrt -lpthread
+LDFLAGS_tst-timer5 := -lrt -lpthread
+LDFLAGS_tst-tls3mod.so := -shared -static-libgcc -lpthread
+LDFLAGS_tst-tls4moda.so := -shared -static-libgcc
+LDFLAGS_tst-tls4modb.so := -shared -static-libgcc
+LDFLAGS_tst-tls5mod.so := -shared -static-libgcc -Wl,-soname,tst-tls5mod.so
+LDFLAGS_tst-tls5moda.so := -shared -static-libgcc
+LDFLAGS_tst-tls5modb.so := -shared -static-libgcc
+LDFLAGS_tst-tls5modc.so := -shared -static-libgcc
+LDFLAGS_tst-tls5modd.so := -shared -static-libgcc
+LDFLAGS_tst-tls5mode.so := -shared -static-libgcc
+LDFLAGS_tst-tls5modf.so := -shared -static-libgcc
+
+#
+# Special case
+#
+tst-cleanup4aux.o:
+       $(Q)$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c tst-cleanup4aux.c -o $@
+
+tst-cleanup4: tst-cleanup4aux.o
+tst-tls3: tst-tls3mod.so
+tst-tls4: tst-tls4moda.so tst-tls4modb.so
+tst-tls5: tst-tls5mod.so tst-tls5moda.so tst-tls5modb.so       \
+         tst-tls5modc.so tst-tls5modd.so tst-tls5mode.so tst-tls5modf.so
+
+OPTS_tst-cancel7 = --command ./tst-cancel7
+OPTS_tst-mqueue7 = -- ./tst-mqueue7
+OPTS_tst-exec4 = ./tst-exec4
+
+RET_tst-clock2 := 1
+RET_tst-cputimer1 := 1
+RET_tst-cputimer2 := 1
+RET_tst-cputimer3 := 1
+
+WRAPPER := env LD_LIBRARY_PATH="$$PWD:.:$(LD_LIBRARY_PATH)" TIMEOUTFACTOR=100
diff --git a/test/nptl/tst-align.c b/test/nptl/tst-align.c
new file mode 100644 (file)
index 0000000..381db8f
--- /dev/null
@@ -0,0 +1,71 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include "tst-stack-align.h"
+
+static void *
+tf (void *arg)
+{
+  bool ok = true;
+
+  puts ("in thread");
+
+  if (TEST_STACK_ALIGN ())
+    ok = false;
+
+  return ok ? NULL : (void *) -1l;
+}
+
+static int
+do_test (void)
+{
+  bool ok = true;
+
+  puts ("in main");
+
+  if (TEST_STACK_ALIGN ())
+    ok = false;
+
+  pthread_t th;
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("create failed");
+      return 1;
+    }
+
+  void *res;
+  if (pthread_join (th, &res) != 0)
+    {
+      puts ("join failed");
+      return 1;
+    }
+
+  if (res != NULL)
+    ok = false;
+
+  return ok ? 0 : 1;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-align2.c b/test/nptl/tst-align2.c
new file mode 100644 (file)
index 0000000..7d8be53
--- /dev/null
@@ -0,0 +1,87 @@
+/* Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sched.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include "tst-stack-align.h"
+
+static int
+f (void *arg)
+{
+  bool ok = true;
+
+  if (TEST_STACK_ALIGN ())
+    ok = false;
+
+  return ok ? 0 : 1;
+}
+
+static int
+do_test (void)
+{
+  bool ok = true;
+
+  puts ("in main");
+
+  if (TEST_STACK_ALIGN ())
+    ok = false;
+
+#ifdef __ia64__
+  extern int __clone2 (int (*__fn) (void *__arg), void *__child_stack_base,
+                      size_t __child_stack_size, int __flags,
+                      void *__arg, ...);
+  char st[256 * 1024];
+  pid_t p = __clone2 (f, st, sizeof (st), 0, 0);
+#else
+  char st[128 * 1024];
+  pid_t p = clone (f, st + sizeof (st), 0, 0);
+#endif
+  if (p == -1)
+    {
+      printf("clone failed: %m\n");
+      return 1;
+    }
+
+  int e;
+  if (waitpid (p, &e, __WCLONE) != p)
+    {
+      puts ("waitpid failed");
+      kill (p, SIGKILL);
+      return 1;
+    }
+  if (!WIFEXITED (e))
+    {
+      if (WIFSIGNALED (e))
+       printf ("died from signal %s\n", strsignal (WTERMSIG (e)));
+      else
+       puts ("did not terminate correctly");
+      return 1;
+    }
+  if (WEXITSTATUS (e) != 0)
+    ok = false;
+
+  return ok ? 0 : 1;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-atfork1.c b/test/nptl/tst-atfork1.c
new file mode 100644 (file)
index 0000000..b42ab42
--- /dev/null
@@ -0,0 +1,121 @@
+/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+
+static int val;
+
+
+static void
+prepare1 (void)
+{
+  val *= 2;
+}
+
+static void
+prepare2 (void)
+{
+  ++val;
+}
+
+static void
+parent1 (void)
+{
+  val += 4;
+}
+
+static void
+parent2 (void)
+{
+  val *= 4;
+}
+
+static void
+child1 (void)
+{
+  val += 8;
+}
+
+static void
+child2 (void)
+{
+  val *= 8;
+}
+
+
+static int
+do_test (void)
+{
+  pid_t pid;
+  int status = 0;
+
+  if (pthread_atfork (prepare1, parent1, child1) != 0)
+    {
+      puts ("1st atfork failed");
+      exit (1);
+    }
+  if (pthread_atfork (prepare2, parent2, child2) != 0)
+    {
+      puts ("2nd atfork failed");
+      exit (1);
+    }
+
+  pid = fork ();
+  if (pid == -1)
+    {
+      puts ("fork failed");
+      exit (1);
+    }
+
+  if (pid != 0)
+    {
+      /* Parent.  */
+      if (val != 24)
+       {
+         printf ("expected val=%d, got %d\n", 24, val);
+         exit (1);
+       }
+
+      if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid)
+       {
+         puts ("waitpid failed");
+         exit (1);
+       }
+    }
+  else
+    {
+      /* Child.  */
+      if (val != 80)
+       {
+         printf ("expected val=%d, got %d\n", 80, val);
+         exit (2);
+       }
+    }
+
+  return status;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-attr1.c b/test/nptl/tst-attr1.c
new file mode 100644 (file)
index 0000000..13b62a6
--- /dev/null
@@ -0,0 +1,306 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+
+int
+do_test (void)
+{
+  int i;
+  pthread_attr_t a;
+
+  if (pthread_attr_init (&a) != 0)
+    {
+      puts ("attr_init failed");
+      exit (1);
+    }
+
+  pthread_mutexattr_t ma;
+
+  if (pthread_mutexattr_init (&ma) != 0)
+    {
+      puts ("mutexattr_init failed");
+      exit (1);
+    }
+
+  pthread_rwlockattr_t rwa;
+
+  if (pthread_rwlockattr_init (&rwa) != 0)
+    {
+      puts ("rwlockattr_init failed");
+      exit (1);
+    }
+
+  /* XXX Remove if default value is clear.  */
+  pthread_attr_setinheritsched (&a, PTHREAD_INHERIT_SCHED);
+  pthread_attr_setschedpolicy (&a, SCHED_OTHER);
+  pthread_attr_setscope (&a, PTHREAD_SCOPE_SYSTEM);
+
+  for (i = 0; i < 10000; ++i)
+    {
+      long int r = random ();
+
+      if (r != PTHREAD_CREATE_DETACHED && r != PTHREAD_CREATE_JOINABLE)
+       {
+         int e = pthread_attr_setdetachstate (&a, r);
+
+         if (e == 0)
+           {
+             printf ("attr_setdetachstate with value %ld succeeded\n", r);
+             exit (1);
+           }
+         if (e != EINVAL)
+           {
+             puts ("attr_setdetachstate didn't return EINVAL");
+             exit (1);
+           }
+
+         int s;
+         if (pthread_attr_getdetachstate (&a, &s) != 0)
+           {
+             puts ("attr_getdetachstate failed");
+             exit (1);
+           }
+
+         if (s != PTHREAD_CREATE_JOINABLE)
+           {
+             printf ("\
+detach state changed to %d by invalid setdetachstate call\n", s);
+             exit (1);
+           }
+       }
+
+      if (r != PTHREAD_INHERIT_SCHED && r != PTHREAD_EXPLICIT_SCHED)
+       {
+         int e = pthread_attr_setinheritsched (&a, r);
+
+         if (e == 0)
+           {
+             printf ("attr_setinheritsched with value %ld succeeded\n", r);
+             exit (1);
+           }
+         if (e != EINVAL)
+           {
+             puts ("attr_setinheritsched didn't return EINVAL");
+             exit (1);
+           }
+
+         int s;
+         if (pthread_attr_getinheritsched (&a, &s) != 0)
+           {
+             puts ("attr_getinheritsched failed");
+             exit (1);
+           }
+
+         if (s != PTHREAD_INHERIT_SCHED)
+           {
+             printf ("\
+inheritsched changed to %d by invalid setinheritsched call\n", s);
+             exit (1);
+           }
+       }
+
+      if (r != SCHED_OTHER && r != SCHED_RR && r != SCHED_FIFO)
+       {
+         int e = pthread_attr_setschedpolicy (&a, r);
+
+         if (e == 0)
+           {
+             printf ("attr_setschedpolicy with value %ld succeeded\n", r);
+             exit (1);
+           }
+         if (e != EINVAL)
+           {
+             puts ("attr_setschedpolicy didn't return EINVAL");
+             exit (1);
+           }
+
+         int s;
+         if (pthread_attr_getschedpolicy (&a, &s) != 0)
+           {
+             puts ("attr_getschedpolicy failed");
+             exit (1);
+           }
+
+         if (s != SCHED_OTHER)
+           {
+             printf ("\
+schedpolicy changed to %d by invalid setschedpolicy call\n", s);
+             exit (1);
+           }
+       }
+
+      if (r != PTHREAD_SCOPE_SYSTEM && r != PTHREAD_SCOPE_PROCESS)
+       {
+         int e = pthread_attr_setscope (&a, r);
+
+         if (e == 0)
+           {
+             printf ("attr_setscope with value %ld succeeded\n", r);
+             exit (1);
+           }
+         if (e != EINVAL)
+           {
+             puts ("attr_setscope didn't return EINVAL");
+             exit (1);
+           }
+
+         int s;
+         if (pthread_attr_getscope (&a, &s) != 0)
+           {
+             puts ("attr_getscope failed");
+             exit (1);
+           }
+
+         if (s != PTHREAD_SCOPE_SYSTEM)
+           {
+             printf ("\
+contentionscope changed to %d by invalid setscope call\n", s);
+             exit (1);
+           }
+       }
+
+      if (r != PTHREAD_PROCESS_PRIVATE && r != PTHREAD_PROCESS_SHARED)
+       {
+         int e = pthread_mutexattr_setpshared (&ma, r);
+
+         if (e == 0)
+           {
+             printf ("mutexattr_setpshared with value %ld succeeded\n", r);
+             exit (1);
+           }
+         if (e != EINVAL)
+           {
+             puts ("mutexattr_setpshared didn't return EINVAL");
+             exit (1);
+           }
+
+         int s;
+         if (pthread_mutexattr_getpshared (&ma, &s) != 0)
+           {
+             puts ("mutexattr_getpshared failed");
+             exit (1);
+           }
+
+         if (s != PTHREAD_PROCESS_PRIVATE)
+           {
+             printf ("\
+pshared changed to %d by invalid mutexattr_setpshared call\n", s);
+             exit (1);
+           }
+
+         e = pthread_rwlockattr_setpshared (&rwa, r);
+
+         if (e == 0)
+           {
+             printf ("rwlockattr_setpshared with value %ld succeeded\n", r);
+             exit (1);
+           }
+         if (e != EINVAL)
+           {
+             puts ("rwlockattr_setpshared didn't return EINVAL");
+             exit (1);
+           }
+
+         if (pthread_rwlockattr_getpshared (&rwa, &s) != 0)
+           {
+             puts ("rwlockattr_getpshared failed");
+             exit (1);
+           }
+
+         if (s != PTHREAD_PROCESS_PRIVATE)
+           {
+             printf ("\
+pshared changed to %d by invalid rwlockattr_setpshared call\n", s);
+             exit (1);
+           }
+       }
+
+      if (r != PTHREAD_CANCEL_ENABLE && r != PTHREAD_CANCEL_DISABLE)
+       {
+         int e = pthread_setcancelstate (r, NULL);
+
+         if (e == 0)
+           {
+             printf ("setcancelstate with value %ld succeeded\n", r);
+             exit (1);
+           }
+
+         if (e != EINVAL)
+           {
+             puts ("setcancelstate didn't return EINVAL");
+             exit (1);
+           }
+
+         int s;
+         if (pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, &s) != 0)
+           {
+             puts ("setcancelstate failed for PTHREAD_CANCEL_ENABLE");
+             exit (1);
+           }
+
+         if (s != PTHREAD_CANCEL_ENABLE)
+           {
+             puts ("invalid setcancelstate changed state");
+             exit (1);
+           }
+       }
+
+      if (r != PTHREAD_CANCEL_DEFERRED && r != PTHREAD_CANCEL_ASYNCHRONOUS)
+       {
+         int e = pthread_setcanceltype (r, NULL);
+
+         if (e == 0)
+           {
+             printf ("setcanceltype with value %ld succeeded\n", r);
+             exit (1);
+           }
+
+         if (e != EINVAL)
+           {
+             puts ("setcanceltype didn't return EINVAL");
+             exit (1);
+           }
+
+         int s;
+         if (pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, &s) != 0)
+           {
+             puts ("setcanceltype failed for PTHREAD_CANCEL_DEFERRED");
+             exit (1);
+           }
+
+         if (s != PTHREAD_CANCEL_DEFERRED)
+           {
+             puts ("invalid setcanceltype changed state");
+             exit (1);
+           }
+       }
+    }
+
+  return 0;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-attr2.c b/test/nptl/tst-attr2.c
new file mode 100644 (file)
index 0000000..a60598d
--- /dev/null
@@ -0,0 +1,317 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+
+int
+do_test (void)
+{
+  pthread_attr_t a;
+
+  if (pthread_attr_init (&a) != 0)
+    {
+      puts ("attr_init failed");
+      exit (1);
+    }
+
+  /* Check default value of detach state.  */
+  int s;
+  if (pthread_attr_getdetachstate (&a, &s) != 0)
+    {
+      puts ("1st attr_getdestachstate failed");
+      exit (1);
+    }
+  if (s != PTHREAD_CREATE_JOINABLE)
+    {
+      printf ("\
+default detach state wrong: %d, expected %d (PTHREAD_CREATE_JOINABLE)\n",
+             s, PTHREAD_CREATE_JOINABLE);
+      exit (1);
+    }
+
+  int e = pthread_attr_setdetachstate (&a, PTHREAD_CREATE_DETACHED);
+  if (e != 0)
+    {
+      puts ("1st attr_setdetachstate failed");
+      exit (1);
+    }
+  if (pthread_attr_getdetachstate (&a, &s) != 0)
+    {
+      puts ("2nd attr_getdestachstate failed");
+      exit (1);
+    }
+  if (s != PTHREAD_CREATE_DETACHED)
+    {
+      puts ("PTHREAD_CREATE_DETACHED set, but not given back");
+      exit (1);
+    }
+
+  e = pthread_attr_setdetachstate (&a, PTHREAD_CREATE_JOINABLE);
+  if (e != 0)
+    {
+      puts ("2nd attr_setdetachstate failed");
+      exit (1);
+    }
+  if (pthread_attr_getdetachstate (&a, &s) != 0)
+    {
+      puts ("3rd attr_getdestachstate failed");
+      exit (1);
+    }
+  if (s != PTHREAD_CREATE_JOINABLE)
+    {
+      puts ("PTHREAD_CREATE_JOINABLE set, but not given back");
+      exit (1);
+    }
+
+
+  size_t g;
+  if (pthread_attr_getguardsize (&a, &g) != 0)
+    {
+      puts ("1st attr_getguardsize failed");
+      exit (1);
+    }
+  if (g != (size_t) sysconf (_SC_PAGESIZE))
+    {
+      printf ("default guardsize %zu, expected %ld (PAGESIZE)\n",
+             g, sysconf (_SC_PAGESIZE));
+      exit (1);
+    }
+
+  e = pthread_attr_setguardsize (&a, 0);
+  if (e != 0)
+    {
+      puts ("1st attr_setguardsize failed");
+      exit (1);
+    }
+  if (pthread_attr_getguardsize (&a, &g) != 0)
+    {
+      puts ("2nd attr_getguardsize failed");
+      exit (1);
+    }
+  if (g != 0)
+    {
+      printf ("guardsize set to zero but %zu returned\n", g);
+      exit (1);
+    }
+
+  e = pthread_attr_setguardsize (&a, 1);
+  if (e != 0)
+    {
+      puts ("2nd attr_setguardsize failed");
+      exit (1);
+    }
+  if (pthread_attr_getguardsize (&a, &g) != 0)
+    {
+      puts ("3rd attr_getguardsize failed");
+      exit (1);
+    }
+  if (g != 1)
+    {
+      printf ("guardsize set to 1 but %zu returned\n", g);
+      exit (1);
+    }
+
+
+  if (pthread_attr_getinheritsched (&a, &s) != 0)
+    {
+      puts ("1st attr_getinheritsched failed");
+      exit (1);
+    }
+  /* XXX What is the correct default value.  */
+  if (s != PTHREAD_INHERIT_SCHED && s != PTHREAD_EXPLICIT_SCHED)
+    {
+      puts ("incorrect default value for inheritsched");
+      exit (1);
+    }
+
+  e = pthread_attr_setinheritsched (&a, PTHREAD_EXPLICIT_SCHED);
+  if (e != 0)
+    {
+      puts ("1st attr_setinheritsched failed");
+      exit (1);
+    }
+  if (pthread_attr_getinheritsched (&a, &s) != 0)
+    {
+      puts ("2nd attr_getinheritsched failed");
+      exit (1);
+    }
+  if (s != PTHREAD_EXPLICIT_SCHED)
+    {
+      printf ("inheritsched set to PTHREAD_EXPLICIT_SCHED, but got %d\n", s);
+      exit (1);
+    }
+
+  e = pthread_attr_setinheritsched (&a, PTHREAD_INHERIT_SCHED);
+  if (e != 0)
+    {
+      puts ("2nd attr_setinheritsched failed");
+      exit (1);
+    }
+  if (pthread_attr_getinheritsched (&a, &s) != 0)
+    {
+      puts ("3rd attr_getinheritsched failed");
+      exit (1);
+    }
+  if (s != PTHREAD_INHERIT_SCHED)
+    {
+      printf ("inheritsched set to PTHREAD_INHERIT_SCHED, but got %d\n", s);
+      exit (1);
+    }
+
+
+  if (pthread_attr_getschedpolicy (&a, &s) != 0)
+    {
+      puts ("1st attr_getschedpolicy failed");
+      exit (1);
+    }
+  /* XXX What is the correct default value.  */
+  if (s != SCHED_OTHER && s != SCHED_FIFO && s != SCHED_RR)
+    {
+      puts ("incorrect default value for schedpolicy");
+      exit (1);
+    }
+
+  e = pthread_attr_setschedpolicy (&a, SCHED_RR);
+  if (e != 0)
+    {
+      puts ("1st attr_setschedpolicy failed");
+      exit (1);
+    }
+  if (pthread_attr_getschedpolicy (&a, &s) != 0)
+    {
+      puts ("2nd attr_getschedpolicy failed");
+      exit (1);
+    }
+  if (s != SCHED_RR)
+    {
+      printf ("schedpolicy set to SCHED_RR, but got %d\n", s);
+      exit (1);
+    }
+
+  e = pthread_attr_setschedpolicy (&a, SCHED_FIFO);
+  if (e != 0)
+    {
+      puts ("2nd attr_setschedpolicy failed");
+      exit (1);
+    }
+  if (pthread_attr_getschedpolicy (&a, &s) != 0)
+    {
+      puts ("3rd attr_getschedpolicy failed");
+      exit (1);
+    }
+  if (s != SCHED_FIFO)
+    {
+      printf ("schedpolicy set to SCHED_FIFO, but got %d\n", s);
+      exit (1);
+    }
+
+  e = pthread_attr_setschedpolicy (&a, SCHED_OTHER);
+  if (e != 0)
+    {
+      puts ("3rd attr_setschedpolicy failed");
+      exit (1);
+    }
+  if (pthread_attr_getschedpolicy (&a, &s) != 0)
+    {
+      puts ("4th attr_getschedpolicy failed");
+      exit (1);
+    }
+  if (s != SCHED_OTHER)
+    {
+      printf ("schedpolicy set to SCHED_OTHER, but got %d\n", s);
+      exit (1);
+    }
+
+
+  if (pthread_attr_getscope (&a, &s) != 0)
+    {
+      puts ("1st attr_getscope failed");
+      exit (1);
+    }
+  /* XXX What is the correct default value.  */
+  if (s != PTHREAD_SCOPE_SYSTEM && s != PTHREAD_SCOPE_PROCESS)
+    {
+      puts ("incorrect default value for contentionscope");
+      exit (1);
+    }
+
+  e = pthread_attr_setscope (&a, PTHREAD_SCOPE_PROCESS);
+  if (e != ENOTSUP)
+    {
+      if (e != 0)
+       {
+         puts ("1st attr_setscope failed");
+         exit (1);
+       }
+      if (pthread_attr_getscope (&a, &s) != 0)
+       {
+         puts ("2nd attr_getscope failed");
+         exit (1);
+       }
+      if (s != PTHREAD_SCOPE_PROCESS)
+       {
+         printf ("\
+contentionscope set to PTHREAD_SCOPE_PROCESS, but got %d\n", s);
+         exit (1);
+       }
+    }
+
+  e = pthread_attr_setscope (&a, PTHREAD_SCOPE_SYSTEM);
+  if (e != 0)
+    {
+      puts ("2nd attr_setscope failed");
+      exit (1);
+    }
+  if (pthread_attr_getscope (&a, &s) != 0)
+    {
+      puts ("3rd attr_getscope failed");
+      exit (1);
+    }
+  if (s != PTHREAD_SCOPE_SYSTEM)
+    {
+      printf ("contentionscope set to PTHREAD_SCOPE_SYSTEM, but got %d\n", s);
+      exit (1);
+    }
+
+  char buf[1];
+  e = pthread_attr_setstack (&a, buf, 1);
+  if (e != EINVAL)
+    {
+      puts ("setstack with size 1 did not produce EINVAL");
+      exit (1);
+    }
+
+  e = pthread_attr_setstacksize (&a, 1);
+  if (e != EINVAL)
+    {
+      puts ("setstacksize with size 1 did not produce EINVAL");
+      exit (1);
+    }
+
+  return 0;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-attr3.c b/test/nptl/tst-attr3.c
new file mode 100644 (file)
index 0000000..29b4bbe
--- /dev/null
@@ -0,0 +1,420 @@
+/* pthread_getattr_np test.
+   Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <error.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static void *
+tf (void *arg)
+{
+  pthread_attr_t a, *ap, a2;
+  int err;
+  void *result = NULL;
+
+  if (arg == NULL)
+    {
+      ap = &a2;
+      err = pthread_attr_init (ap);
+      if (err)
+        {
+          error (0, err, "pthread_attr_init failed");
+          return tf;
+        }
+    }
+  else
+    ap = (pthread_attr_t *) arg;
+
+  err = pthread_getattr_np (pthread_self (), &a);
+  if (err)
+    {
+      error (0, err, "pthread_getattr_np failed");
+      result = tf;
+    }
+
+  int detachstate1, detachstate2;
+  err = pthread_attr_getdetachstate (&a, &detachstate1);
+  if (err)
+    {
+      error (0, err, "pthread_attr_getdetachstate failed");
+      result = tf;
+    }
+  else
+    {
+      err = pthread_attr_getdetachstate (ap, &detachstate2);
+      if (err)
+       {
+         error (0, err, "pthread_attr_getdetachstate failed");
+         result = tf;
+       }
+      else if (detachstate1 != detachstate2)
+       {
+         error (0, 0, "detachstate differs %d != %d",
+                detachstate1, detachstate2);
+         result = tf;
+       }
+    }
+
+  void *stackaddr;
+  size_t stacksize;
+  err = pthread_attr_getstack (&a, &stackaddr, &stacksize);
+  if (err)
+    {
+      error (0, err, "pthread_attr_getstack failed");
+      result = tf;
+    }
+  else if ((void *) &a < stackaddr
+          || (void *) &a >= stackaddr + stacksize)
+    {
+      error (0, 0, "pthread_attr_getstack returned range does not cover thread's stack");
+      result = tf;
+    }
+  else
+    printf ("thread stack %p-%p (0x%zx)\n", stackaddr, stackaddr + stacksize,
+           stacksize);
+
+  size_t guardsize1, guardsize2;
+  err = pthread_attr_getguardsize (&a, &guardsize1);
+  if (err)
+    {
+      error (0, err, "pthread_attr_getguardsize failed");
+      result = tf;
+    }
+  else
+    {
+      err = pthread_attr_getguardsize (ap, &guardsize2);
+      if (err)
+       {
+         error (0, err, "pthread_attr_getguardsize failed");
+         result = tf;
+       }
+      else if (guardsize1 != guardsize2)
+       {
+         error (0, 0, "guardsize differs %zd != %zd",
+                guardsize1, guardsize2);
+         result = tf;
+       }
+      else
+       printf ("thread guardsize %zd\n", guardsize1);
+    }
+
+  int scope1, scope2;
+  err = pthread_attr_getscope (&a, &scope1);
+  if (err)
+    {
+      error (0, err, "pthread_attr_getscope failed");
+      result = tf;
+    }
+  else
+    {
+      err = pthread_attr_getscope (ap, &scope2);
+      if (err)
+       {
+         error (0, err, "pthread_attr_getscope failed");
+         result = tf;
+       }
+      else if (scope1 != scope2)
+       {
+         error (0, 0, "scope differs %d != %d",
+                scope1, scope2);
+         result = tf;
+       }
+    }
+
+  int inheritsched1, inheritsched2;
+  err = pthread_attr_getinheritsched (&a, &inheritsched1);
+  if (err)
+    {
+      error (0, err, "pthread_attr_getinheritsched failed");
+      result = tf;
+    }
+  else
+    {
+      err = pthread_attr_getinheritsched (ap, &inheritsched2);
+      if (err)
+       {
+         error (0, err, "pthread_attr_getinheritsched failed");
+         result = tf;
+       }
+      else if (inheritsched1 != inheritsched2)
+       {
+         error (0, 0, "inheritsched differs %d != %d",
+                inheritsched1, inheritsched2);
+         result = tf;
+       }
+    }
+
+  cpu_set_t c1, c2;
+  err = pthread_getaffinity_np (pthread_self (), sizeof (c1), &c1);
+  if (err == 0)
+    {
+      err = pthread_attr_getaffinity_np (&a, sizeof (c2), &c2);
+      if (err)
+       {
+         error (0, err, "pthread_attr_getaffinity_np failed");
+         result = tf;
+       }
+      else if (memcmp (&c1, &c2, sizeof (c1)))
+       {
+         error (0, 0, "pthread_attr_getaffinity_np returned different CPU mask than pthread_getattr_np");
+         result = tf;
+       }
+    }
+
+  err = pthread_attr_destroy (&a);
+  if (err)
+    {
+      error (0, err, "pthread_attr_destroy failed");
+      result = tf;
+    }
+
+  if (ap == &a2)
+    {
+      err = pthread_attr_destroy (ap);
+      if (err)
+       {
+         error (0, err, "pthread_attr_destroy failed");
+         result = tf;
+       }
+    }
+
+  return result;
+}
+
+
+static int
+do_test (void)
+{
+  int result = 0;
+  pthread_attr_t a;
+  cpu_set_t c1, c2;
+
+  int err = pthread_attr_init (&a);
+  if (err)
+    {
+      error (0, err, "pthread_attr_init failed");
+      result = 1;
+    }
+
+  err = pthread_attr_getaffinity_np (&a, sizeof (c1), &c1);
+  if (err && err != ENOSYS)
+    {
+      error (0, err, "pthread_attr_getaffinity_np failed");
+      result = 1;
+    }
+
+  err = pthread_attr_destroy (&a);
+  if (err)
+    {
+      error (0, err, "pthread_attr_destroy failed");
+      result = 1;
+    }
+
+  err = pthread_getattr_np (pthread_self (), &a);
+  if (err)
+    {
+      error (0, err, "pthread_getattr_np failed");
+      result = 1;
+    }
+
+  int detachstate;
+  err = pthread_attr_getdetachstate (&a, &detachstate);
+  if (err)
+    {
+      error (0, err, "pthread_attr_getdetachstate failed");
+      result = 1;
+    }
+  else if (detachstate != PTHREAD_CREATE_JOINABLE)
+    {
+      error (0, 0, "initial thread not joinable");
+      result = 1;
+    }
+
+  void *stackaddr;
+  size_t stacksize;
+  err = pthread_attr_getstack (&a, &stackaddr, &stacksize);
+  if (err)
+    {
+      error (0, err, "pthread_attr_getstack failed");
+      result = 1;
+    }
+  else if ((void *) &a < stackaddr
+          || (void *) &a >= stackaddr + stacksize)
+    {
+      error (0, 0, "pthread_attr_getstack returned range does not cover main's stack");
+      result = 1;
+    }
+  else
+    printf ("initial thread stack %p-%p (0x%zx)\n", stackaddr,
+           stackaddr + stacksize, stacksize);
+
+  size_t guardsize;
+  err = pthread_attr_getguardsize (&a, &guardsize);
+  if (err)
+    {
+      error (0, err, "pthread_attr_getguardsize failed");
+      result = 1;
+    }
+  else if (guardsize != 0)
+    {
+      error (0, 0, "pthread_attr_getguardsize returned %zd != 0",
+            guardsize);
+      result = 1;
+    }
+
+  int scope;
+  err = pthread_attr_getscope (&a, &scope);
+  if (err)
+    {
+      error (0, err, "pthread_attr_getscope failed");
+      result = 1;
+    }
+  else if (scope != PTHREAD_SCOPE_SYSTEM)
+    {
+      error (0, 0, "pthread_attr_getscope returned %d != PTHREAD_SCOPE_SYSTEM",
+            scope);
+      result = 1;
+    }
+
+  int inheritsched;
+  err = pthread_attr_getinheritsched (&a, &inheritsched);
+  if (err)
+    {
+      error (0, err, "pthread_attr_getinheritsched failed");
+      result = 1;
+    }
+  else if (inheritsched != PTHREAD_INHERIT_SCHED)
+    {
+      error (0, 0, "pthread_attr_getinheritsched returned %d != PTHREAD_INHERIT_SCHED",
+            inheritsched);
+      result = 1;
+    }
+
+  err = pthread_getaffinity_np (pthread_self (), sizeof (c1), &c1);
+  if (err == 0)
+    {
+      err = pthread_attr_getaffinity_np (&a, sizeof (c2), &c2);
+      if (err)
+       {
+         error (0, err, "pthread_attr_getaffinity_np failed");
+         result = 1;
+       }
+      else if (memcmp (&c1, &c2, sizeof (c1)))
+       {
+         error (0, 0, "pthread_attr_getaffinity_np returned different CPU mask than pthread_getattr_np");
+         result = 1;
+       }
+    }
+
+  err = pthread_attr_destroy (&a);
+  if (err)
+    {
+      error (0, err, "pthread_attr_destroy failed");
+      result = 1;
+    }
+
+  pthread_t th;
+  err = pthread_create (&th, NULL, tf, NULL);
+  if (err)
+    {
+      error (0, err, "pthread_create #1 failed");
+      result = 1;
+    }
+  else
+    {
+      void *ret;
+      err = pthread_join (th, &ret);
+      if (err)
+       {
+         error (0, err, "pthread_join #1 failed");
+         result = 1;
+       }
+      else if (ret != NULL)
+        result = 1;
+    }
+
+  err = pthread_attr_init (&a);
+  if (err)
+    {
+      error (0, err, "pthread_attr_init failed");
+      result = 1;
+    }
+
+  err = pthread_create (&th, &a, tf, &a);
+  if (err)
+    {
+      error (0, err, "pthread_create #2 failed");
+      result = 1;
+    }
+  else
+    {
+      void *ret;
+      err = pthread_join (th, &ret);
+      if (err)
+       {
+         error (0, err, "pthread_join #2 failed");
+         result = 1;
+       }
+      else if (ret != NULL)
+        result = 1;
+    }
+
+  err = pthread_attr_setguardsize (&a, 16 * sysconf (_SC_PAGESIZE));
+  if (err)
+    {
+      error (0, err, "pthread_attr_setguardsize failed");
+      result = 1;
+    }
+
+  err = pthread_create (&th, &a, tf, &a);
+  if (err)
+    {
+      error (0, err, "pthread_create #3 failed");
+      result = 1;
+    }
+  else
+    {
+      void *ret;
+      err = pthread_join (th, &ret);
+      if (err)
+       {
+         error (0, err, "pthread_join #3 failed");
+         result = 1;
+       }
+      else if (ret != NULL)
+        result = 1;
+    }
+
+  err = pthread_attr_destroy (&a);
+  if (err)
+    {
+      error (0, err, "pthread_attr_destroy failed");
+      result = 1;
+    }
+
+  return result;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-barrier1.c b/test/nptl/tst-barrier1.c
new file mode 100644 (file)
index 0000000..2859fb4
--- /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 <pthread.h>
+#include <stdio.h>
+
+
+static int
+do_test (void)
+{
+  pthread_barrier_t b;
+  int e;
+  int cnt;
+
+  e = pthread_barrier_init (&b, NULL, 0);
+  if (e == 0)
+    {
+      puts ("barrier_init with count 0 succeeded");
+      return 1;
+    }
+  if (e != EINVAL)
+    {
+      puts ("barrier_init with count 0 didn't return EINVAL");
+      return 1;
+    }
+
+  if (pthread_barrier_init (&b, NULL, 1) != 0)
+    {
+      puts ("real barrier_init failed");
+      return 1;
+    }
+
+  for (cnt = 0; cnt < 10; ++cnt)
+    {
+      e = pthread_barrier_wait (&b);
+
+      if (e != PTHREAD_BARRIER_SERIAL_THREAD)
+       {
+         puts ("barrier_wait didn't return PTHREAD_BARRIER_SERIAL_THREAD");
+         return 1;
+       }
+    }
+
+  if (pthread_barrier_destroy (&b) != 0)
+    {
+      puts ("barrier_destroy failed");
+      return 1;
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-barrier2.c b/test/nptl/tst-barrier2.c
new file mode 100644 (file)
index 0000000..7f58869
--- /dev/null
@@ -0,0 +1,185 @@
+/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+
+
+static int
+do_test (void)
+{
+  size_t ps = sysconf (_SC_PAGESIZE);
+  char tmpfname[] = "/tmp/tst-barrier2.XXXXXX";
+  char data[ps];
+  void *mem;
+  int fd;
+  pthread_barrier_t *b;
+  pthread_barrierattr_t a;
+  pid_t pid;
+  int serials = 0;
+  int cnt;
+  int status;
+  int p;
+
+  fd = mkstemp (tmpfname);
+  if (fd == -1)
+    {
+      printf ("cannot open temporary file: %m\n");
+      return 1;
+    }
+
+  /* Make sure it is always removed.  */
+  unlink (tmpfname);
+
+  /* Create one page of data.  */
+  memset (data, '\0', ps);
+
+  /* Write the data to the file.  */
+  if (write (fd, data, ps) != (ssize_t) ps)
+    {
+      puts ("short write");
+      return 1;
+    }
+
+  mem = mmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+  if (mem == MAP_FAILED)
+    {
+      printf ("mmap failed: %m\n");
+      return 1;
+    }
+
+  b = (pthread_barrier_t *) (((uintptr_t) mem + __alignof (pthread_barrier_t))
+                            & ~(__alignof (pthread_barrier_t) - 1));
+
+  if (pthread_barrierattr_init (&a) != 0)
+    {
+      puts ("barrierattr_init failed");
+      return 1;
+    }
+
+  if (pthread_barrierattr_getpshared (&a, &p) != 0)
+    {
+      puts ("1st barrierattr_getpshared failed");
+      return 1;
+    }
+
+  if (p != PTHREAD_PROCESS_PRIVATE)
+    {
+      puts ("default pshared value wrong");
+      return 1;
+    }
+
+  if (pthread_barrierattr_setpshared (&a, PTHREAD_PROCESS_SHARED) != 0)
+    {
+      puts ("barrierattr_setpshared failed");
+      return 1;
+    }
+
+  if (pthread_barrierattr_getpshared (&a, &p) != 0)
+    {
+      puts ("2nd barrierattr_getpshared failed");
+      return 1;
+    }
+
+  if (p != PTHREAD_PROCESS_SHARED)
+    {
+      puts ("pshared value after setpshared call wrong");
+      return 1;
+    }
+
+  if (pthread_barrier_init (b, &a, 2) != 0)
+    {
+      puts ("barrier_init failed");
+      return 1;
+    }
+
+  if (pthread_barrierattr_destroy (&a) != 0)
+    {
+      puts ("barrierattr_destroy failed");
+      return 1;
+    }
+
+  puts ("going to fork now");
+  pid = fork ();
+  if (pid == -1)
+    {
+      puts ("fork failed");
+      return 1;
+    }
+
+  /* Just to be sure we don't hang forever.  */
+  alarm (4);
+
+#define N 30
+  for (cnt = 0; cnt < N; ++cnt)
+    {
+      int e;
+
+      e = pthread_barrier_wait (b);
+      if (e == PTHREAD_BARRIER_SERIAL_THREAD)
+       ++serials;
+      else if (e != 0)
+       {
+         printf ("%s: barrier_wait returned value %d != 0 and PTHREAD_BARRIER_SERIAL_THREAD\n",
+                 pid == 0 ? "child" : "parent", e);
+         return 1;
+       }
+    }
+
+  alarm (0);
+
+  printf ("%s: was %d times the serial thread\n",
+         pid == 0 ? "child" : "parent", serials);
+
+  if (pid == 0)
+    /* The child.  Pass the number of times we had the serializing
+       thread back to the parent.  */
+    exit (serials);
+
+  if (waitpid (pid, &status, 0) != pid)
+    {
+      puts ("waitpid failed");
+      return 1;
+    }
+
+  if (!WIFEXITED (status))
+    {
+      puts ("child exited abnormally");
+      return 1;
+    }
+
+  if (WEXITSTATUS (status) + serials != N)
+    {
+      printf ("total number of serials is %d, expected %d\n",
+             WEXITSTATUS (status) + serials, N);
+      return 1;
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-barrier3.c b/test/nptl/tst-barrier3.c
new file mode 100644 (file)
index 0000000..b5478f8
--- /dev/null
@@ -0,0 +1,154 @@
+/* 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.  */
+
+/* Test of POSIX barriers.  */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define NTHREADS 20
+
+#define ROUNDS 20
+
+static pthread_barrier_t barriers[NTHREADS];
+
+static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+static int counters[NTHREADS];
+static int serial[NTHREADS];
+
+static void *
+worker (void *arg)
+{
+  void *result = NULL;
+  int nr = (long int) arg;
+  int i;
+
+  for (i = 0; i < ROUNDS; ++i)
+    {
+      int j;
+      int retval;
+
+      if (nr == 0)
+       {
+         memset (counters, '\0', sizeof (counters));
+         memset (serial, '\0', sizeof (serial));
+       }
+
+      retval = pthread_barrier_wait (&barriers[NTHREADS - 1]);
+      if (retval != 0 && retval != PTHREAD_BARRIER_SERIAL_THREAD)
+       {
+         printf ("thread %d failed to wait for all the others\n", nr);
+         result = (void *) 1;
+       }
+
+      for (j = nr; j < NTHREADS; ++j)
+       {
+         /* Increment the counter for this round.  */
+         pthread_mutex_lock (&lock);
+         ++counters[j];
+         pthread_mutex_unlock (&lock);
+
+         /* Wait for the rest.  */
+         retval = pthread_barrier_wait (&barriers[j]);
+
+         /* Test the result.  */
+         if (nr == 0 && counters[j] != j + 1)
+           {
+             printf ("barrier in round %d released but count is %d\n",
+                     j, counters[j]);
+             result = (void *) 1;
+           }
+
+         if (retval != 0)
+           {
+             if (retval != PTHREAD_BARRIER_SERIAL_THREAD)
+               {
+                 printf ("thread %d in round %d has nonzero return value != PTHREAD_BARRIER_SERIAL_THREAD\n",
+                         nr, j);
+                 result = (void *) 1;
+               }
+             else
+               {
+                 pthread_mutex_lock (&lock);
+                 ++serial[j];
+                 pthread_mutex_unlock (&lock);
+               }
+           }
+
+         /* Wait for the rest again.  */
+         retval = pthread_barrier_wait (&barriers[j]);
+
+         /* Now we can check whether exactly one thread was serializing.  */
+         if (nr == 0 && serial[j] != 1)
+           {
+             printf ("not exactly one serial thread in round %d\n", j);
+             result = (void *) 1;
+           }
+       }
+    }
+
+  return result;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#define TIMEOUT 60
+static int
+do_test (void)
+{
+  pthread_t threads[NTHREADS];
+  int i;
+  void *res;
+  int result = 0;
+
+  /* Initialized the barrier variables.  */
+  for (i = 0; i < NTHREADS; ++i)
+    if (pthread_barrier_init (&barriers[i], NULL, i + 1) != 0)
+      {
+       printf ("Failed to initialize barrier %d\n", i);
+       exit (1);
+      }
+
+  /* Start the threads.  */
+  for (i = 0; i < NTHREADS; ++i)
+    if (pthread_create (&threads[i], NULL, worker, (void *) (long int) i) != 0)
+      {
+       printf ("Failed to start thread %d\n", i);
+       exit (1);
+      }
+
+  /* And wait for them.  */
+  for (i = 0; i < NTHREADS; ++i)
+    if (pthread_join (threads[i], &res) != 0 || res != NULL)
+      {
+       printf ("thread %d returned a failure\n", i);
+       result = 1;
+      }
+    else
+      printf ("joined threads %d\n", i);
+
+  if (result == 0)
+    puts ("all OK");
+
+  return result;
+}
+
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-barrier4.c b/test/nptl/tst-barrier4.c
new file mode 100644 (file)
index 0000000..efc2755
--- /dev/null
@@ -0,0 +1,122 @@
+/* Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2004.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* This is a test for behavior not guaranteed by POSIX.  */
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+static pthread_barrier_t b1;
+static pthread_barrier_t b2;
+
+
+#define N 20
+
+static void *
+tf (void *arg)
+{
+  int round = 0;
+
+  while (round++ < 30)
+    {
+      if (pthread_barrier_wait (&b1) == PTHREAD_BARRIER_SERIAL_THREAD)
+       {
+         pthread_barrier_destroy (&b1);
+         if (pthread_barrier_init (&b1, NULL, N) != 0)
+           {
+             puts ("tf: 1st barrier_init failed");
+             exit (1);
+           }
+       }
+
+      if (pthread_barrier_wait (&b2) == PTHREAD_BARRIER_SERIAL_THREAD)
+       {
+         pthread_barrier_destroy (&b2);
+         if (pthread_barrier_init (&b2, NULL, N) != 0)
+           {
+             puts ("tf: 2nd barrier_init failed");
+             exit (1);
+           }
+       }
+    }
+
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  pthread_attr_t at;
+  int cnt;
+
+  if (pthread_attr_init (&at) != 0)
+    {
+      puts ("attr_init failed");
+      return 1;
+    }
+
+  if (pthread_attr_setstacksize (&at, 1 * 1024 * 1024) != 0)
+    {
+      puts ("attr_setstacksize failed");
+      return 1;
+    }
+
+  if (pthread_barrier_init (&b1, NULL, N) != 0)
+    {
+      puts ("1st barrier_init failed");
+      return 1;
+    }
+
+  if (pthread_barrier_init (&b2, NULL, N) != 0)
+    {
+      puts ("2nd barrier_init failed");
+      return 1;
+    }
+
+  pthread_t th[N - 1];
+  for (cnt = 0; cnt < N - 1; ++cnt)
+    if (pthread_create (&th[cnt], &at, tf, NULL) != 0)
+      {
+       puts ("pthread_create failed");
+       return 1;
+      }
+
+  if (pthread_attr_destroy (&at) != 0)
+    {
+      puts ("attr_destroy failed");
+      return 1;
+    }
+
+  tf (NULL);
+
+  for (cnt = 0; cnt < N - 1; ++cnt)
+    if (pthread_join (th[cnt], NULL) != 0)
+      {
+       puts ("pthread_join failed");
+       return 1;
+      }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-basic1.c b/test/nptl/tst-basic1.c
new file mode 100644 (file)
index 0000000..7637c8e
--- /dev/null
@@ -0,0 +1,82 @@
+/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+
+static pid_t pid;
+
+static void *
+tf (void *a)
+{
+  if (getpid () != pid)
+    {
+      write (2, "pid mismatch\n", 13);
+      _exit (1);
+    }
+
+  return a;
+}
+
+
+int
+do_test (void)
+{
+  pid = getpid ();
+
+#define N 2
+  pthread_t t[N];
+  int i;
+
+  for (i = 0; i < N; ++i)
+    if (pthread_create (&t[i], NULL, tf, (void *) (long int) (i + 1)) != 0)
+      {
+       write (2, "create failed\n", 14);
+       _exit (1);
+      }
+    else
+      printf ("created thread %d\n", i);
+
+  for (i = 0; i < N; ++i)
+    {
+      void *r;
+      int e;
+      if ((e = pthread_join (t[i], &r)) != 0)
+       {
+         printf ("join failed: %d\n", e);
+         _exit (1);
+       }
+      else if (r != (void *) (long int) (i + 1))
+       {
+         write (2, "result wrong\n", 13);
+         _exit (1);
+       }
+      else
+       printf ("joined thread %d\n", i);
+    }
+
+  return 0;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-basic2.c b/test/nptl/tst-basic2.c
new file mode 100644 (file)
index 0000000..1c4632c
--- /dev/null
@@ -0,0 +1,121 @@
+/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+
+#define N 20
+
+static pthread_t th[N];
+static pthread_mutex_t lock[N];
+
+
+static void *tf (void *a)
+{
+  uintptr_t idx = (uintptr_t) a;
+
+  pthread_mutex_lock (&lock[idx]);
+
+  return pthread_equal (pthread_self (), th[idx]) ? NULL : (void *) 1l;
+}
+
+
+int
+do_test (void)
+{
+  if (pthread_equal (pthread_self (), pthread_self ()) == 0)
+    {
+      puts ("pthread_equal (pthread_self (), pthread_self ()) failed");
+      exit (1);
+    }
+
+  pthread_attr_t at;
+
+  if (pthread_attr_init (&at) != 0)
+    {
+      puts ("attr_init failed");
+      return 1;
+    }
+
+  if (pthread_attr_setstacksize (&at, 1 * 1024 * 1024) != 0)
+    {
+      puts ("attr_setstacksize failed");
+      return 1;
+    }
+
+  int i;
+  for (i = 0; i < N; ++i)
+    {
+      if (pthread_mutex_init (&lock[i], NULL) != 0)
+       {
+         puts ("mutex_init failed");
+         exit (1);
+       }
+
+      if (pthread_mutex_lock (&lock[i]) != 0)
+       {
+         puts ("mutex_lock failed");
+         exit (1);
+       }
+
+      if (pthread_create (&th[i], &at, tf, (void *) (long int) i) != 0)
+       {
+         puts ("create failed");
+         exit (1);
+       }
+
+      if (pthread_mutex_unlock (&lock[i]) != 0)
+       {
+         puts ("mutex_unlock failed");
+         exit (1);
+       }
+
+      printf ("created thread %d\n", i);
+    }
+
+  if (pthread_attr_destroy (&at) != 0)
+    {
+      puts ("attr_destroy failed");
+      return 1;
+    }
+
+  int result = 0;
+  for (i = 0; i < N; ++i)
+    {
+      void *r;
+      int e;
+      if ((e = pthread_join (th[i], &r)) != 0)
+       {
+         printf ("join failed: %d\n", e);
+         _exit (1);
+       }
+      else if (r != NULL)
+       result = 1;
+    }
+
+  return 0;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-basic3.c b/test/nptl/tst-basic3.c
new file mode 100644 (file)
index 0000000..cb4816d
--- /dev/null
@@ -0,0 +1,87 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+
+static int nrunning = 1;
+
+
+static void
+final_test (void)
+{
+  puts ("final_test has been called");
+
+#define THE_SIGNAL SIGUSR1
+  kill (getpid (), SIGUSR1);
+}
+
+
+static void *
+tf (void *a)
+{
+  if (pthread_join ((pthread_t) a, NULL) != 0)
+    {
+      printf ("join failed while %d are running\n", nrunning);
+      _exit (1);
+    }
+
+  printf ("%2d left\n", --nrunning);
+
+  return NULL;
+}
+
+
+int
+do_test (void)
+{
+#define N 20
+  pthread_t t[N];
+  pthread_t last = pthread_self ();
+  int i;
+
+  atexit (final_test);
+
+  printf ("starting %d + 1 threads\n", N);
+  for (i = 0; i < N; ++i)
+    {
+      if (pthread_create (&t[i], NULL, tf, (void *) last) != 0)
+       {
+         puts ("create failed");
+         _exit (1);
+       }
+
+      ++nrunning;
+
+      last = t[i];
+    }
+
+  printf ("%2d left\n", --nrunning);
+
+  pthread_exit (NULL);
+}
+
+
+#define EXPECTED_SIGNAL THE_SIGNAL
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-basic4.c b/test/nptl/tst-basic4.c
new file mode 100644 (file)
index 0000000..6eb6ea9
--- /dev/null
@@ -0,0 +1,101 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+
+static void
+final_test (void)
+{
+  puts ("final_test has been called");
+
+#define THE_SIGNAL SIGUSR1
+  kill (getpid (), SIGUSR1);
+}
+
+
+static void *
+tf (void *a)
+{
+  pid_t pid = fork ();
+  if (pid == -1)
+    {
+      puts ("fork failed");
+      exit (1);
+    }
+
+  if (pid == 0)
+    {
+      atexit (final_test);
+
+      pthread_exit (NULL);
+    }
+
+  int r;
+  int e = TEMP_FAILURE_RETRY (waitpid (pid, &r, 0));
+  if (e != pid)
+    {
+      puts ("waitpid failed");
+      exit (1);
+    }
+
+  if (! WIFSIGNALED (r))
+    {
+      puts ("child not signled");
+      exit (1);
+    }
+
+  if (WTERMSIG (r) != THE_SIGNAL)
+    {
+      puts ("child's termination signal wrong");
+      exit (1);
+    }
+
+  return NULL;
+}
+
+
+int
+do_test (void)
+{
+  pthread_t th;
+
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("create failed");
+      _exit (1);
+    }
+
+  if (pthread_join (th, NULL) != 0)
+    {
+      puts ("join failed");
+      exit (1);
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-basic5.c b/test/nptl/tst-basic5.c
new file mode 100644 (file)
index 0000000..83a8810
--- /dev/null
@@ -0,0 +1,74 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+
+int
+do_test (void)
+{
+  int c = pthread_getconcurrency ();
+  if (c != 0)
+    {
+      puts ("initial concurrencylevel wrong");
+      exit (1);
+    }
+
+  if (pthread_setconcurrency (1) != 0)
+    {
+      puts ("setconcurrency failed");
+      exit (1);
+    }
+
+  c = pthread_getconcurrency ();
+  if (c != 1)
+    {
+      puts ("getconcurrency didn't return the value previous set");
+      exit (1);
+    }
+
+  int e = pthread_setconcurrency (-1);
+  if (e == 0)
+    {
+      puts ("setconcurrency of negative value didn't failed");
+      exit (1);
+    }
+  if (e != EINVAL)
+    {
+      puts ("setconcurrency didn't return EINVAL for negative value");
+      exit (1);
+    }
+
+  c = pthread_getconcurrency ();
+  if (c != 1)
+    {
+      puts ("invalid getconcurrency changed level");
+      exit (1);
+    }
+
+  return 0;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-basic6.c b/test/nptl/tst-basic6.c
new file mode 100644 (file)
index 0000000..413ae03
--- /dev/null
@@ -0,0 +1,132 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+
+static char *p;
+
+static pthread_barrier_t b;
+#define BT \
+  e = pthread_barrier_wait (&b);                                             \
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)                          \
+    {                                                                        \
+      puts ("barrier_wait failed");                                          \
+      exit (1);                                                                      \
+    }
+
+
+static void *
+tf (void *a)
+{
+  int e;
+
+  BT;
+
+  char *p2 = getcwd (NULL, 0);
+  if (p2 == NULL)
+    {
+      puts ("2nd getcwd failed");
+      exit (1);
+    }
+
+  if (strcmp (p, p2) != 0)
+    {
+      printf ("initial cwd mismatch: \"%s\" vs \"%s\"\n", p, p2);
+      exit (1);
+    }
+
+  free (p);
+  free (p2);
+
+  if (chdir ("..") != 0)
+    {
+      puts ("chdir failed");
+      exit (1);
+    }
+
+  p = getcwd (NULL, 0);
+  if (p == NULL)
+    {
+      puts ("getcwd failed");
+      exit (1);
+    }
+
+  return a;
+}
+
+
+int
+do_test (void)
+{
+  if (pthread_barrier_init (&b, NULL, 2) != 0)
+    {
+      puts ("barrier_init failed");
+      exit (1);
+    }
+
+  pthread_t th;
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("create failed");
+      exit (1);
+    }
+
+  p = getcwd (NULL, 0);
+  if (p == NULL)
+    {
+      puts ("getcwd failed");
+      exit (1);
+    }
+
+  int e;
+  BT;
+
+  if (pthread_join (th, NULL) != 0)
+    {
+      puts ("join failed");
+      exit (1);
+    }
+
+  char *p2 = getcwd (NULL, 0);
+  if (p2 == NULL)
+    {
+      puts ("2nd getcwd failed");
+      exit (1);
+    }
+
+  if (strcmp (p, p2) != 0)
+    {
+      printf ("cwd after chdir mismatch: \"%s\" vs \"%s\"\n", p, p2);
+      exit (1);
+    }
+
+  free (p);
+  free (p2);
+
+  return 0;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-cancel1.c b/test/nptl/tst-cancel1.c
new file mode 100644 (file)
index 0000000..690319d
--- /dev/null
@@ -0,0 +1,163 @@
+/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+static pthread_mutex_t m1 = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t m2 = PTHREAD_MUTEX_INITIALIZER;
+
+static int cntr;
+
+
+static void
+cleanup (void *arg)
+{
+  if (arg != (void *) 42l)
+    cntr = 42;
+  else
+    cntr = 1;
+}
+
+
+static void *
+tf (void *arg)
+{
+  /* Ignore all signals.  This must not have any effect on delivering
+     the cancellation signal.  */
+  sigset_t ss;
+
+  sigfillset (&ss);
+
+  if (pthread_sigmask (SIG_BLOCK, &ss, NULL) != 0)
+    {
+      puts ("pthread_sigmask failed");
+      exit (1);
+    }
+
+  pthread_cleanup_push (cleanup, (void *) 42l);
+
+  int err = pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
+  if (err != 0)
+    {
+      printf ("setcanceltype failed: %s\n", strerror (err));
+      exit (1);
+    }
+  /* The following code is not standard compliant: the mutex functions
+     must not be called with asynchronous cancellation enabled.  */
+
+  err = pthread_mutex_unlock (&m2);
+  if (err != 0)
+    {
+      printf ("child: mutex_unlock failed: %s\n", strerror (err));
+      exit (1);
+    }
+
+  err = pthread_mutex_lock (&m1);
+  if (err != 0)
+    {
+      printf ("child: 1st mutex_lock failed: %s\n", strerror (err));
+      exit (1);
+    }
+
+  /* We should never come here.  */
+
+  pthread_cleanup_pop (0);
+
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  int err;
+  pthread_t th;
+  int result = 0;
+  void *retval;
+
+  /* Get the mutexes.  */
+  err = pthread_mutex_lock (&m1);
+  if (err != 0)
+    {
+      printf ("parent: 1st mutex_lock failed: %s\n", strerror (err));
+      return 1;
+    }
+  err = pthread_mutex_lock (&m2);
+  if (err != 0)
+    {
+      printf ("parent: 2nd mutex_lock failed: %s\n", strerror (err));
+      return 1;
+    }
+
+  err = pthread_create (&th, NULL, tf, NULL);
+  if (err != 0)
+    {
+      printf ("create failed: %s\n", strerror (err));
+      return 1;
+    }
+
+  err = pthread_mutex_lock (&m2);
+  if (err != 0)
+    {
+      printf ("parent: 3rd mutex_lock failed: %s\n", strerror (err));
+      return 1;
+    }
+
+  err = pthread_cancel (th);
+  if (err != 0)
+    {
+      printf ("cancel failed: %s\n", strerror (err));
+      return 1;
+    }
+
+  err = pthread_join (th, &retval);
+  if (err != 0)
+    {
+      printf ("join failed: %s\n", strerror (err));
+      return 1;
+    }
+
+  if (retval != PTHREAD_CANCELED)
+    {
+      printf ("wrong return value: %p\n", retval);
+      result = 1;
+    }
+
+  if (cntr == 42)
+    {
+      puts ("cleanup handler called with wrong argument");
+      result = 1;
+    }
+  else if (cntr != 1)
+    {
+      puts ("cleanup handling not called");
+      result = 1;
+    }
+
+  return result;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-cancel10.c b/test/nptl/tst-cancel10.c
new file mode 100644 (file)
index 0000000..7af0f2f
--- /dev/null
@@ -0,0 +1,126 @@
+/* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+static void
+cleanup (void *arg)
+{
+  /* Just for fun.  */
+  if (pthread_cancel (pthread_self ()) != 0)
+    {
+      puts ("cleanup: cancel failed");
+      exit (1);
+    }
+
+  printf ("cleanup for %ld\n", (long int) arg);
+}
+
+
+static void *
+tf (void *arg)
+{
+  long int n = (long int) arg;
+
+  pthread_cleanup_push (cleanup, arg);
+
+  if (pthread_setcanceltype ((n & 1) == 0
+                            ? PTHREAD_CANCEL_DEFERRED
+                            : PTHREAD_CANCEL_ASYNCHRONOUS, NULL) != 0)
+    {
+      puts ("setcanceltype failed");
+      exit (1);
+    }
+
+  if (pthread_cancel (pthread_self ()) != 0)
+    {
+      puts ("cancel failed");
+      exit (1);
+    }
+
+  pthread_testcancel ();
+
+  /* We should never come here.  */
+
+  pthread_cleanup_pop (0);
+
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  pthread_attr_t at;
+
+  if (pthread_attr_init (&at) != 0)
+    {
+      puts ("attr_init failed");
+      return 1;
+    }
+
+  if (pthread_attr_setstacksize (&at, 1 * 1024 * 1024) != 0)
+    {
+      puts ("attr_setstacksize failed");
+      return 1;
+    }
+
+#define N 20
+  int i;
+  pthread_t th[N];
+
+  for (i = 0; i < N; ++i)
+    if (pthread_create (&th[i], &at, tf, (void *) (long int) i) != 0)
+      {
+       puts ("create failed");
+       exit (1);
+      }
+
+  if (pthread_attr_destroy (&at) != 0)
+    {
+      puts ("attr_destroy failed");
+      return 1;
+    }
+
+  for (i = 0; i < N; ++i)
+    {
+      void *r;
+      if (pthread_join (th[i], &r) != 0)
+       {
+         puts ("join failed");
+         exit (1);
+       }
+
+      if (r != PTHREAD_CANCELED)
+       {
+         puts ("thread not canceled");
+         exit (1);
+       }
+    }
+
+  return 0;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-cancel11.c b/test/nptl/tst-cancel11.c
new file mode 100644 (file)
index 0000000..235aef5
--- /dev/null
@@ -0,0 +1,123 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+
+static pthread_barrier_t bar;
+static int fd[2];
+
+
+static void
+cleanup (void *arg)
+{
+  static int ncall;
+
+  if (++ncall != 1)
+    {
+      puts ("second call to cleanup");
+      exit (1);
+    }
+
+  printf ("cleanup call #%d\n", ncall);
+}
+
+
+static void *
+tf (void *arg)
+{
+  pthread_cleanup_push (cleanup, NULL);
+
+  int e = pthread_barrier_wait (&bar);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("tf: 1st barrier_wait failed");
+      exit (1);
+    }
+
+  /* This call should block and be cancelable.  */
+  char buf[20];
+  read (fd[0], buf, sizeof (buf));
+
+  pthread_cleanup_pop (0);
+
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  pthread_t th;
+
+  if (pthread_barrier_init (&bar, NULL, 2) != 0)
+    {
+      puts ("barrier_init failed");
+      exit (1);
+    }
+
+  if (pipe (fd) != 0)
+    {
+      puts ("pipe failed");
+      exit (1);
+    }
+
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("create failed");
+      exit (1);
+    }
+
+  int e = pthread_barrier_wait (&bar);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("1st barrier_wait failed");
+      exit (1);
+    }
+
+  if (pthread_cancel (th) != 0)
+    {
+      puts ("1st cancel failed");
+      exit (1);
+    }
+
+  void *r;
+  if (pthread_join (th, &r) != 0)
+    {
+      puts ("join failed");
+      exit (1);
+    }
+
+  if (r != PTHREAD_CANCELED)
+    {
+      puts ("thread not canceled");
+      exit (1);
+    }
+
+  return 0;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-cancel12.c b/test/nptl/tst-cancel12.c
new file mode 100644 (file)
index 0000000..6fdf5cf
--- /dev/null
@@ -0,0 +1,127 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+
+static pthread_barrier_t bar;
+static sem_t sem;
+
+
+static void
+cleanup (void *arg)
+{
+  static int ncall;
+
+  if (++ncall != 1)
+    {
+      puts ("second call to cleanup");
+      exit (1);
+    }
+
+  printf ("cleanup call #%d\n", ncall);
+}
+
+
+static void *
+tf (void *arg)
+{
+  pthread_cleanup_push (cleanup, NULL);
+
+  int e = pthread_barrier_wait (&bar);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("tf: 1st barrier_wait failed");
+      exit (1);
+    }
+
+  /* This call should block and be cancelable.  */
+  sem_wait (&sem);
+
+  pthread_cleanup_pop (0);
+
+  puts ("sem_wait returned");
+
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  pthread_t th;
+
+  if (pthread_barrier_init (&bar, NULL, 2) != 0)
+    {
+      puts ("barrier_init failed");
+      exit (1);
+    }
+
+  if (sem_init (&sem, 0, 1) != 0)
+    {
+      puts ("sem_init failed");
+      exit (1);
+    }
+
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("create failed");
+      exit (1);
+    }
+
+  /* Check whether cancellation is honored even before sem_wait does
+     anything.  */
+  if (pthread_cancel (th) != 0)
+    {
+      puts ("1st cancel failed");
+      exit (1);
+    }
+
+  int e = pthread_barrier_wait (&bar);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("1st barrier_wait failed");
+      exit (1);
+    }
+
+  void *r;
+  if (pthread_join (th, &r) != 0)
+    {
+      puts ("join failed");
+      exit (1);
+    }
+
+  if (r != PTHREAD_CANCELED)
+    {
+      puts ("thread not canceled");
+      exit (1);
+    }
+
+  return 0;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-cancel13.c b/test/nptl/tst-cancel13.c
new file mode 100644 (file)
index 0000000..66ab455
--- /dev/null
@@ -0,0 +1,129 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+
+static pthread_barrier_t bar;
+static sem_t sem;
+
+
+static void
+cleanup (void *arg)
+{
+  static int ncall;
+
+  if (++ncall != 1)
+    {
+      puts ("second call to cleanup");
+      exit (1);
+    }
+
+  printf ("cleanup call #%d\n", ncall);
+}
+
+
+static void *
+tf (void *arg)
+{
+  pthread_cleanup_push (cleanup, NULL);
+
+  int e = pthread_barrier_wait (&bar);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("tf: 1st barrier_wait failed");
+      exit (1);
+    }
+
+  /* This call should block and be cancelable.  */
+  sem_wait (&sem);
+
+  pthread_cleanup_pop (0);
+
+  puts ("sem_wait returned");
+
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  pthread_t th;
+
+  if (pthread_barrier_init (&bar, NULL, 2) != 0)
+    {
+      puts ("barrier_init failed");
+      exit (1);
+    }
+
+  if (sem_init (&sem, 0, 0) != 0)
+    {
+      puts ("sem_init failed");
+      exit (1);
+    }
+
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("create failed");
+      exit (1);
+    }
+
+  int e = pthread_barrier_wait (&bar);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("1st barrier_wait failed");
+      exit (1);
+    }
+
+  /* Give the child a chance to go to sleep in sem_wait.  */
+  sleep (1);
+
+  /* Check whether cancellation is honored when waiting in sem_wait.  */
+  if (pthread_cancel (th) != 0)
+    {
+      puts ("1st cancel failed");
+      exit (1);
+    }
+
+  void *r;
+  if (pthread_join (th, &r) != 0)
+    {
+      puts ("join failed");
+      exit (1);
+    }
+
+  if (r != PTHREAD_CANCELED)
+    {
+      puts ("thread not canceled");
+      exit (1);
+    }
+
+  return 0;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-cancel14.c b/test/nptl/tst-cancel14.c
new file mode 100644 (file)
index 0000000..592c086
--- /dev/null
@@ -0,0 +1,137 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/time.h>
+
+
+static pthread_barrier_t bar;
+static sem_t sem;
+
+
+static void
+cleanup (void *arg)
+{
+  static int ncall;
+
+  if (++ncall != 1)
+    {
+      puts ("second call to cleanup");
+      exit (1);
+    }
+
+  printf ("cleanup call #%d\n", ncall);
+}
+
+
+static void *
+tf (void *arg)
+{
+  pthread_cleanup_push (cleanup, NULL);
+
+  int e = pthread_barrier_wait (&bar);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("tf: 1st barrier_wait failed");
+      exit (1);
+    }
+
+  struct timeval tv;
+  (void) gettimeofday (&tv, NULL);
+
+  struct timespec ts;
+  TIMEVAL_TO_TIMESPEC (&tv, &ts);
+
+  /* Timeout in 5 seconds.  */
+  ts.tv_sec += 5;
+
+  /* This call should block and be cancelable.  */
+  sem_timedwait (&sem, &ts);
+
+  pthread_cleanup_pop (0);
+
+  puts ("sem_timedwait returned");
+
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  pthread_t th;
+
+  if (pthread_barrier_init (&bar, NULL, 2) != 0)
+    {
+      puts ("barrier_init failed");
+      exit (1);
+    }
+
+  if (sem_init (&sem, 0, 1) != 0)
+    {
+      puts ("sem_init failed");
+      exit (1);
+    }
+
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("create failed");
+      exit (1);
+    }
+
+  /* Check whether cancellation is honored even before sem_timedwait does
+     anything.  */
+  if (pthread_cancel (th) != 0)
+    {
+      puts ("1st cancel failed");
+      exit (1);
+    }
+
+  int e = pthread_barrier_wait (&bar);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("1st barrier_wait failed");
+      exit (1);
+    }
+
+  void *r;
+  if (pthread_join (th, &r) != 0)
+    {
+      puts ("join failed");
+      exit (1);
+    }
+
+  if (r != PTHREAD_CANCELED)
+    {
+      puts ("thread not canceled");
+      exit (1);
+    }
+
+  return 0;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-cancel15.c b/test/nptl/tst-cancel15.c
new file mode 100644 (file)
index 0000000..5fd9502
--- /dev/null
@@ -0,0 +1,142 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/time.h>
+
+
+static pthread_barrier_t bar;
+static sem_t sem;
+
+
+static void
+cleanup (void *arg)
+{
+  static int ncall;
+
+  if (++ncall != 1)
+    {
+      puts ("second call to cleanup");
+      exit (1);
+    }
+
+  printf ("cleanup call #%d\n", ncall);
+}
+
+
+static void *
+tf (void *arg)
+{
+  int e;
+
+  pthread_cleanup_push (cleanup, NULL);
+
+  e = pthread_barrier_wait (&bar);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("tf: 1st barrier_wait failed");
+      exit (1);
+    }
+
+  struct timeval tv;
+  (void) gettimeofday (&tv, NULL);
+
+  struct timespec ts;
+  TIMEVAL_TO_TIMESPEC (&tv, &ts);
+
+  /* Timeout in 5 seconds.  */
+  ts.tv_sec += 5;
+
+  /* This call should block and be cancelable.  */
+  errno = 0;
+  e = sem_timedwait (&sem, &ts);
+
+  pthread_cleanup_pop (0);
+
+  printf ("sem_timedwait returned, e = %d, errno = %d\n", e, errno);
+
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  pthread_t th;
+
+  if (pthread_barrier_init (&bar, NULL, 2) != 0)
+    {
+      puts ("barrier_init failed");
+      exit (1);
+    }
+
+  if (sem_init (&sem, 0, 0) != 0)
+    {
+      puts ("sem_init failed");
+      exit (1);
+    }
+
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("create failed");
+      exit (1);
+    }
+
+  int e = pthread_barrier_wait (&bar);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("1st barrier_wait failed");
+      exit (1);
+    }
+
+  /* Give the child a chance to go to sleep in sem_wait.  */
+  sleep (1);
+
+  /* Check whether cancellation is honored when waiting in sem_timedwait.  */
+  if (pthread_cancel (th) != 0)
+    {
+      puts ("1st cancel failed");
+      exit (1);
+    }
+
+  void *r;
+  if (pthread_join (th, &r) != 0)
+    {
+      puts ("join failed");
+      exit (1);
+    }
+
+  if (r != PTHREAD_CANCELED)
+    {
+      puts ("thread not canceled");
+      exit (1);
+    }
+
+  return 0;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-cancel16.c b/test/nptl/tst-cancel16.c
new file mode 100644 (file)
index 0000000..709902e
--- /dev/null
@@ -0,0 +1,231 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+
+
+static pthread_barrier_t b2;
+static int fd;
+static int called;
+
+
+static void
+cl (void *arg)
+{
+  called = 1;
+}
+
+
+static void *
+tf (void *arg)
+{
+  int r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("child thread: barrier_wait failed");
+      exit (1);
+    }
+
+  pthread_cleanup_push (cl, NULL);
+
+  /* This call should never return.  */
+  (void) lockf (fd, F_LOCK, 0);
+
+  pthread_cleanup_pop (0);
+
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  char fname[] = "/tmp/cancel16XXXXXX";
+  fd = mkstemp (fname);
+  if (fd == -1)
+    {
+      puts ("mkstemp failed");
+      return 1;
+    }
+  unlink (fname);
+
+  char mem[sizeof (pthread_barrier_t)];
+  memset (mem, '\0', sizeof (mem));
+  if (TEMP_FAILURE_RETRY (pwrite (fd, mem, sizeof (mem), 0)) != sizeof (mem))
+    {
+      puts ("pwrite failed");
+      return 1;
+    }
+
+  void *p = mmap (NULL, sizeof (mem), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+  if (p == MAP_FAILED)
+    {
+      puts ("mmap failed");
+      return 1;
+    }
+  pthread_barrier_t *b = (pthread_barrier_t *) p;
+
+  pthread_barrierattr_t ba;
+  if (pthread_barrierattr_init (&ba) != 0)
+    {
+      puts ("barrierattr_init failed");
+      return 1;
+    }
+  if (pthread_barrierattr_setpshared (&ba, 1) != 0)
+    {
+      puts ("barrierattr_setshared failed");
+      return 1;
+    }
+
+  if (pthread_barrier_init (b, &ba, 2) != 0)
+    {
+      puts ("1st barrier_init failed");
+      return 1;
+    }
+  if (pthread_barrierattr_destroy (&ba) != 0)
+    {
+      puts ("barrier_destroy failed");
+      return 1;
+    }
+
+  pid_t pid = fork ();
+  if (pid == 0)
+    {
+      /* Child.  Lock the file and wait.  */
+      if (lockf (fd, F_LOCK, 0) != 0)
+       {
+         puts ("child process: lockf failed");
+         _exit (1);
+       }
+
+      int r = pthread_barrier_wait (b);
+      if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+       {
+         puts ("child process: 1st barrier_wait failed");
+         _exit (1);
+       }
+
+      /* Make sure the process dies.  */
+      alarm (5);
+
+      r = pthread_barrier_wait (b);
+      if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+       {
+         puts ("child process: 2nd barrier_wait failed");
+         _exit (1);
+       }
+
+      _exit (0);
+    }
+  if (pid == -1)
+    {
+      puts ("fork failed");
+      return 1;
+    }
+
+  int r = pthread_barrier_wait (b);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("main: 1st barrier_wait failed");
+      _exit (1);
+    }
+
+  if (pthread_barrier_init (&b2, NULL, 2) != 0)
+    {
+      puts ("2nd barrier_init failed");
+      return 1;
+    }
+
+  pthread_t th;
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("create failed");
+      return 1;
+    }
+
+  r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("main: 2nd barrier_wait failed");
+      return 1;
+    }
+
+  /* Delay.  */
+  sleep (1);
+
+  if (pthread_cancel (th) != 0)
+    {
+      puts ("cancel failed");
+      return 1;
+    }
+
+  void *result;
+  if (pthread_join (th, &result) != 0)
+    {
+      puts ("join failed");
+      return 1;
+    }
+  if (result != PTHREAD_CANCELED)
+    {
+      puts ("thread not canceled");
+      return 1;
+    }
+  if (called == 0)
+    {
+      puts ("cleanup handler not called");
+      return 1;
+    }
+
+  r = pthread_barrier_wait (b);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("main: 3rd barrier_wait failed");
+      return 1;
+    }
+
+  int status;
+  if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid)
+    {
+      puts ("waitpid failed");
+      return 1;
+    }
+  if (WEXITSTATUS (status) != 0)
+    {
+      printf ("child process exits with %d\n", WEXITSTATUS (status));
+      return 1;
+    }
+
+  if (lockf (fd, F_LOCK, 0) != 0)
+    {
+      puts ("main: lockf failed");
+      return 1;
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-cancel19.c b/test/nptl/tst-cancel19.c
new file mode 100644 (file)
index 0000000..7c248ae
--- /dev/null
@@ -0,0 +1,287 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <error.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/select.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+static void *
+tf (void *arg)
+{
+  return NULL;
+}
+
+static void
+handler (int sig)
+{
+}
+
+static void __attribute__ ((noinline))
+clobber_lots_of_regs (void)
+{
+#define X1(n) long r##n = 10##n; __asm __volatile ("" : "+r" (r##n));
+#define X2(n) X1(n##0) X1(n##1) X1(n##2) X1(n##3) X1(n##4)
+#define X3(n) X2(n##0) X2(n##1) X2(n##2) X2(n##3) X2(n##4)
+  X3(0) X3(1) X3(2) X3(3) X3(4)
+#undef X1
+#define X1(n) __asm __volatile ("" : : "r" (r##n));
+  X3(0) X3(1) X3(2) X3(3) X3(4)
+#undef X1
+#undef X2
+#undef X3
+}
+
+static int
+do_test (void)
+{
+  pthread_t th;
+  int old, rc;
+  int ret = 0;
+  int fd[2];
+
+  rc = pipe (fd);
+  if (rc < 0)
+    error (EXIT_FAILURE, errno, "couldn't create pipe");
+
+  rc = pthread_create (&th, NULL, tf, NULL);
+  if (rc)
+    error (EXIT_FAILURE, rc, "couldn't create thread");
+
+  rc = pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, &old);
+  if (rc)
+    {
+      error (0, rc, "1st pthread_setcanceltype failed");
+      ret = 1;
+    }
+  if (old != PTHREAD_CANCEL_DEFERRED && old != PTHREAD_CANCEL_ASYNCHRONOUS)
+    {
+      error (0, 0, "1st pthread_setcanceltype returned invalid value %d",
+            old);
+      ret = 1;
+    }
+
+  clobber_lots_of_regs ();
+  close (fd[0]);
+
+  rc = pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, &old);
+  if (rc)
+    {
+      error (0, rc, "pthread_setcanceltype after close failed");
+      ret = 1;
+    }
+  if (old != PTHREAD_CANCEL_DEFERRED)
+    {
+      error (0, 0, "pthread_setcanceltype after close returned invalid value %d",
+            old);
+      ret = 1;
+    }
+
+  clobber_lots_of_regs ();
+  close (fd[1]);
+
+  rc = pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, &old);
+  if (rc)
+    {
+      error (0, rc, "pthread_setcanceltype after 2nd close failed");
+      ret = 1;
+    }
+  if (old != PTHREAD_CANCEL_ASYNCHRONOUS)
+    {
+      error (0, 0, "pthread_setcanceltype after 2nd close returned invalid value %d",
+            old);
+      ret = 1;
+    }
+
+  struct sigaction sa = { .sa_handler = handler, .sa_flags = 0 };
+  sigemptyset (&sa.sa_mask);
+  sigaction (SIGALRM, &sa, NULL);
+
+  struct itimerval it;
+  it.it_value.tv_sec = 1;
+  it.it_value.tv_usec = 0;
+  it.it_interval = it.it_value;
+  setitimer (ITIMER_REAL, &it, NULL);
+
+  clobber_lots_of_regs ();
+  pause ();
+
+  memset (&it, 0, sizeof (it));
+  setitimer (ITIMER_REAL, &it, NULL);
+
+  rc = pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, &old);
+  if (rc)
+    {
+      error (0, rc, "pthread_setcanceltype after pause failed");
+      ret = 1;
+    }
+  if (old != PTHREAD_CANCEL_DEFERRED)
+    {
+      error (0, 0, "pthread_setcanceltype after pause returned invalid value %d",
+            old);
+      ret = 1;
+    }
+
+  it.it_value.tv_sec = 1;
+  it.it_value.tv_usec = 0;
+  it.it_interval = it.it_value;
+  setitimer (ITIMER_REAL, &it, NULL);
+
+  clobber_lots_of_regs ();
+  pause ();
+
+  memset (&it, 0, sizeof (it));
+  setitimer (ITIMER_REAL, &it, NULL);
+
+  rc = pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, &old);
+  if (rc)
+    {
+      error (0, rc, "pthread_setcanceltype after 2nd pause failed");
+      ret = 1;
+    }
+  if (old != PTHREAD_CANCEL_ASYNCHRONOUS)
+    {
+      error (0, 0, "pthread_setcanceltype after 2nd pause returned invalid value %d",
+            old);
+      ret = 1;
+    }
+
+  char fname[] = "/tmp/tst-cancel19-dir-XXXXXX\0foo/bar";
+  char *enddir = strchr (fname, '\0');
+  if (mkdtemp (fname) == NULL)
+    {
+      error (0, errno, "mkdtemp failed");
+      ret = 1;
+    }
+  *enddir = '/';
+
+  clobber_lots_of_regs ();
+  creat (fname, 0400);
+
+  rc = pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, &old);
+  if (rc)
+    {
+      error (0, rc, "pthread_setcanceltype after creat failed");
+      ret = 1;
+    }
+  if (old != PTHREAD_CANCEL_DEFERRED)
+    {
+      error (0, 0, "pthread_setcanceltype after creat returned invalid value %d",
+            old);
+      ret = 1;
+    }
+
+  clobber_lots_of_regs ();
+  creat (fname, 0400);
+
+  rc = pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, &old);
+  if (rc)
+    {
+      error (0, rc, "pthread_setcanceltype after 2nd creat failed");
+      ret = 1;
+    }
+  if (old != PTHREAD_CANCEL_ASYNCHRONOUS)
+    {
+      error (0, 0, "pthread_setcanceltype after 2nd creat returned invalid value %d",
+            old);
+      ret = 1;
+    }
+
+  clobber_lots_of_regs ();
+  open (fname, O_CREAT, 0400);
+
+  rc = pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, &old);
+  if (rc)
+    {
+      error (0, rc, "pthread_setcanceltype after open failed");
+      ret = 1;
+    }
+  if (old != PTHREAD_CANCEL_DEFERRED)
+    {
+      error (0, 0, "pthread_setcanceltype after open returned invalid value %d",
+            old);
+      ret = 1;
+    }
+
+  clobber_lots_of_regs ();
+  open (fname, O_CREAT, 0400);
+
+  rc = pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, &old);
+  if (rc)
+    {
+      error (0, rc, "pthread_setcanceltype after 2nd open failed");
+      ret = 1;
+    }
+  if (old != PTHREAD_CANCEL_ASYNCHRONOUS)
+    {
+      error (0, 0, "pthread_setcanceltype after 2nd open returned invalid value %d",
+            old);
+      ret = 1;
+    }
+
+  *enddir = '\0';
+  rmdir (fname);
+
+  clobber_lots_of_regs ();
+  select (-1, NULL, NULL, NULL, NULL);
+
+  rc = pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, &old);
+  if (rc)
+    {
+      error (0, rc, "pthread_setcanceltype after select failed");
+      ret = 1;
+    }
+  if (old != PTHREAD_CANCEL_DEFERRED)
+    {
+      error (0, 0, "pthread_setcanceltype after select returned invalid value %d",
+            old);
+      ret = 1;
+    }
+
+  clobber_lots_of_regs ();
+  select (-1, NULL, NULL, NULL, NULL);
+
+  rc = pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, &old);
+  if (rc)
+    {
+      error (0, rc, "pthread_setcanceltype after 2nd select failed");
+      ret = 1;
+    }
+  if (old != PTHREAD_CANCEL_ASYNCHRONOUS)
+    {
+      error (0, 0, "pthread_setcanceltype after 2nd select returned invalid value %d",
+            old);
+      ret = 1;
+    }
+
+  pthread_join (th, NULL);
+
+  return ret;
+}
+
+#define TIMEOUT 20
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-cancel2.c b/test/nptl/tst-cancel2.c
new file mode 100644 (file)
index 0000000..6d80f8a
--- /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 <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <unistd.h>
+
+
+static int fd[2];
+
+
+static void *
+tf (void *arg)
+{
+  /* The buffer size must be larger than the pipe size so that the
+     write blocks.  */
+  char buf[100000];
+
+  if (write (fd[1], buf, sizeof (buf)) == sizeof (buf))
+    {
+      puts ("write succeeded");
+      return (void *) 1l;
+    }
+
+  return (void *) 42l;
+}
+
+
+static int
+do_test (void)
+{
+  pthread_t th;
+  void *r;
+  struct sigaction sa;
+
+  sa.sa_handler = SIG_IGN;
+  sigemptyset (&sa.sa_mask);
+  sa.sa_flags = 0;
+
+  if (sigaction (SIGPIPE, &sa, NULL) != 0)
+    {
+      puts ("sigaction failed");
+      return 1;
+    }
+
+  if (pipe (fd) != 0)
+    {
+      puts ("pipe failed");
+      return 1;
+    }
+
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("create failed");
+      return 1;
+    }
+
+  if (pthread_cancel (th) != 0)
+    {
+      puts ("cancel failed");
+      return 1;
+    }
+
+  /* This will cause the write in the child to return.  */
+  close (fd[0]);
+
+  if (pthread_join (th, &r) != 0)
+    {
+      puts ("join failed");
+      return 1;
+    }
+
+  if (r != PTHREAD_CANCELED)
+    {
+      printf ("result is wrong: expected %p, got %p\n", PTHREAD_CANCELED, r);
+      return 1;
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-cancel20.c b/test/nptl/tst-cancel20.c
new file mode 100644 (file)
index 0000000..d88cb9c
--- /dev/null
@@ -0,0 +1,264 @@
+/* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+
+static int fd[4];
+static pthread_barrier_t b;
+volatile int in_sh_body;
+unsigned long cleanups;
+
+static void
+cl (void *arg)
+{
+  cleanups = (cleanups << 4) | (long) arg;
+}
+
+
+static void __attribute__((noinline))
+sh_body (void)
+{
+  char c;
+
+  pthread_cleanup_push (cl, (void *) 1L);
+
+  in_sh_body = 1;
+  if (read (fd[2], &c, 1) == 1)
+    {
+      puts ("read succeeded");
+      exit (1);
+    }
+
+  pthread_cleanup_pop (0);
+}
+
+
+static void
+sh (int sig)
+{
+  pthread_cleanup_push (cl, (void *) 2L);
+  sh_body ();
+  in_sh_body = 0;
+
+  pthread_cleanup_pop (0);
+}
+
+
+static void __attribute__((noinline))
+tf_body (void)
+{
+  char c;
+
+  pthread_cleanup_push (cl, (void *) 3L);
+
+  int r = pthread_barrier_wait (&b);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("child thread: barrier_wait failed");
+      exit (1);
+    }
+
+  if (read (fd[0], &c, 1) == 1)
+    {
+      puts ("read succeeded");
+      exit (1);
+    }
+
+  read (fd[0], &c, 1);
+
+  pthread_cleanup_pop (0);
+}
+
+
+static void *
+tf (void *arg)
+{
+  pthread_cleanup_push (cl, (void *) 4L);
+  tf_body ();
+  pthread_cleanup_pop (0);
+  return NULL;
+}
+
+
+static int
+do_one_test (void)
+{
+  in_sh_body = 0;
+  cleanups = 0;
+  if (pipe (fd) != 0 || pipe (fd + 2) != 0)
+    {
+      puts ("pipe failed");
+      return 1;
+    }
+
+  pthread_t th;
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("create failed");
+      return 1;
+    }
+
+  int r = pthread_barrier_wait (&b);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("parent thread: barrier_wait failed");
+      return 1;
+    }
+
+  sleep (1);
+
+  r = pthread_kill (th, SIGHUP);
+  if (r)
+    {
+      errno = r;
+      printf ("pthread_kill failed %m\n");
+      return 1;
+    }
+
+  while (in_sh_body == 0)
+    sleep (1);
+
+  if (pthread_cancel (th) != 0)
+    {
+      puts ("cancel failed");
+      return 1;
+    }
+
+  /* This will cause the read in the child to return.  */
+  close (fd[0]);
+  close (fd[1]);
+  close (fd[2]);
+  close (fd[3]);
+
+  void *ret;
+  if (pthread_join (th, &ret) != 0)
+    {
+      puts ("join failed");
+      return 1;
+    }
+
+  if (ret != PTHREAD_CANCELED)
+    {
+      puts ("result is wrong");
+      return 1;
+    }
+
+  if (cleanups != 0x1234L)
+    {
+      printf ("called cleanups %lx\n", cleanups);
+      return 1;
+    }
+
+  return 0;
+}
+
+
+static int
+do_test (void)
+{
+  stack_t ss;
+  ss.ss_sp = malloc (2 * SIGSTKSZ);
+  if (ss.ss_sp == NULL)
+    {
+      puts ("failed to allocate alternate stack");
+      return 1;
+    }
+  ss.ss_flags = 0;
+  ss.ss_size = 2 * SIGSTKSZ;
+  if (sigaltstack (&ss, NULL) < 0)
+    {
+      printf ("sigaltstack failed %m\n");
+      return 1;
+    }
+
+  if (pthread_barrier_init (&b, NULL, 2) != 0)
+    {
+      puts ("barrier_init failed");
+      return 1;
+    }
+
+  struct sigaction sa;
+  sa.sa_handler = sh;
+  sigemptyset (&sa.sa_mask);
+  sa.sa_flags = 0;
+
+  if (sigaction (SIGHUP, &sa, NULL) != 0)
+    {
+      puts ("sigaction failed");
+      return 1;
+    }
+
+  puts ("sa_flags = 0 test");
+  if (do_one_test ())
+    return 1;
+
+  sa.sa_handler = sh;
+  sigemptyset (&sa.sa_mask);
+  sa.sa_flags = SA_ONSTACK;
+
+  if (sigaction (SIGHUP, &sa, NULL) != 0)
+    {
+      puts ("sigaction failed");
+      return 1;
+    }
+
+  puts ("sa_flags = SA_ONSTACK test");
+  if (do_one_test ())
+    return 1;
+
+  sa.sa_sigaction = (void (*)(int, siginfo_t *, void *)) sh;
+  sigemptyset (&sa.sa_mask);
+  sa.sa_flags = SA_SIGINFO;
+
+  if (sigaction (SIGHUP, &sa, NULL) != 0)
+    {
+      puts ("sigaction failed");
+      return 1;
+    }
+
+  puts ("sa_flags = SA_SIGINFO test");
+  if (do_one_test ())
+    return 1;
+
+  sa.sa_sigaction = (void (*)(int, siginfo_t *, void *)) sh;
+  sigemptyset (&sa.sa_mask);
+  sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
+
+  if (sigaction (SIGHUP, &sa, NULL) != 0)
+    {
+      puts ("sigaction failed");
+      return 1;
+    }
+
+  puts ("sa_flags = SA_SIGINFO|SA_ONSTACK test");
+  if (do_one_test ())
+    return 1;
+
+  return 0;
+}
+
+#define TIMEOUT 40
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-cancel21.c b/test/nptl/tst-cancel21.c
new file mode 100644 (file)
index 0000000..cc00cc1
--- /dev/null
@@ -0,0 +1,294 @@
+/* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+
+static int fd[4];
+static pthread_barrier_t b;
+volatile int in_sh_body;
+unsigned long cleanups;
+
+static void
+cl (void *arg)
+{
+  cleanups = (cleanups << 4) | (long) arg;
+}
+
+
+static void __attribute__((noinline))
+sh_body (void)
+{
+  char c;
+
+  pthread_cleanup_push (cl, (void *) 1L);
+
+  in_sh_body = 1;
+  if (read (fd[2], &c, 1) == 1)
+    {
+      puts ("read succeeded");
+      exit (1);
+    }
+
+  pthread_cleanup_pop (0);
+}
+
+
+static void
+sh (int sig)
+{
+  pthread_cleanup_push (cl, (void *) 2L);
+  sh_body ();
+  in_sh_body = 0;
+
+  pthread_cleanup_pop (0);
+}
+
+
+static void __attribute__((noinline))
+tf_body (void)
+{
+  char c;
+
+  pthread_cleanup_push (cl, (void *) 3L);
+
+  int r = pthread_barrier_wait (&b);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("child thread: barrier_wait failed");
+      exit (1);
+    }
+
+  if (read (fd[0], &c, 1) == 1)
+    {
+      puts ("read succeeded");
+      exit (1);
+    }
+
+  read (fd[0], &c, 1);
+
+  pthread_cleanup_pop (0);
+}
+
+
+static void *
+tf (void *arg)
+{
+  pthread_t th = (pthread_t) arg;
+
+  int r = pthread_barrier_wait (&b);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("parent thread: barrier_wait failed");
+      exit (1);
+    }
+
+  sleep (1);
+
+  r = pthread_kill (th, SIGHUP);
+  if (r)
+    {
+      errno = r;
+      printf ("pthread_kill failed %m\n");
+      exit (1);
+    }
+
+  while (in_sh_body == 0)
+    sleep (1);
+
+  if (pthread_cancel (th) != 0)
+    {
+      puts ("cancel failed");
+      exit (1);
+    }
+
+  /* This will cause the read in the initial thread to return.  */
+  close (fd[0]);
+  close (fd[1]);
+  close (fd[2]);
+  close (fd[3]);
+
+  void *ret;
+  if (pthread_join (th, &ret) != 0)
+    {
+      puts ("join failed");
+      exit (1);
+    }
+
+  if (ret != PTHREAD_CANCELED)
+    {
+      puts ("result is wrong");
+      exit (1);
+    }
+
+  if (cleanups != 0x1234L)
+    {
+      printf ("called cleanups %lx\n", cleanups);
+      exit (1);
+    }
+
+  if (pthread_barrier_destroy (&b))
+    {
+      puts ("barrier destroy failed");
+      exit (1);
+    }
+
+  exit (0);
+}
+
+
+static int
+do_one_test (void)
+{
+  in_sh_body = 0;
+
+  pid_t pid = fork ();
+
+  if (pid == -1)
+    {
+      printf ("fork failed: %m\n");
+      return 1;
+    }
+
+  if (pid)
+    {
+      int status;
+      if (waitpid (pid, &status, 0) < 0)
+       {
+         printf ("waitpid failed %m\n");
+         return 1;
+       }
+
+      return !WIFEXITED (status) || WEXITSTATUS (status);
+    }
+
+  if (pthread_barrier_init (&b, NULL, 2) != 0)
+    {
+      puts ("barrier_init failed");
+      exit (1);
+    }
+
+  cleanups = 0;
+  if (pipe (fd) != 0 || pipe (fd + 2) != 0)
+    {
+      puts ("pipe failed");
+      exit (1);
+    }
+
+  pthread_t th;
+  if (pthread_create (&th, NULL, tf, (void *) pthread_self ()) != 0)
+    {
+      puts ("create failed");
+      exit (1);
+    }
+
+  pthread_cleanup_push (cl, (void *) 4L);
+  tf_body ();
+  pthread_cleanup_pop (0);
+  exit (1);
+}
+
+
+static int
+do_test (void)
+{
+  stack_t ss;
+  ss.ss_sp = malloc (2 * SIGSTKSZ);
+  if (ss.ss_sp == NULL)
+    {
+      puts ("failed to allocate alternate stack");
+      return 1;
+    }
+  ss.ss_flags = 0;
+  ss.ss_size = 2 * SIGSTKSZ;
+  if (sigaltstack (&ss, NULL) < 0)
+    {
+      printf ("sigaltstack failed %m\n");
+      return 1;
+    }
+
+  struct sigaction sa;
+  sa.sa_handler = sh;
+  sigemptyset (&sa.sa_mask);
+  sa.sa_flags = 0;
+
+  if (sigaction (SIGHUP, &sa, NULL) != 0)
+    {
+      puts ("sigaction failed");
+      return 1;
+    }
+
+  puts ("sa_flags = 0 test");
+  if (do_one_test ())
+    return 1;
+
+  sa.sa_handler = sh;
+  sigemptyset (&sa.sa_mask);
+  sa.sa_flags = SA_ONSTACK;
+
+  if (sigaction (SIGHUP, &sa, NULL) != 0)
+    {
+      puts ("sigaction failed");
+      return 1;
+    }
+
+  puts ("sa_flags = SA_ONSTACK test");
+  if (do_one_test ())
+    return 1;
+
+  sa.sa_sigaction = (void (*)(int, siginfo_t *, void *)) sh;
+  sigemptyset (&sa.sa_mask);
+  sa.sa_flags = SA_SIGINFO;
+
+  if (sigaction (SIGHUP, &sa, NULL) != 0)
+    {
+      puts ("sigaction failed");
+      return 1;
+    }
+
+  puts ("sa_flags = SA_SIGINFO test");
+  if (do_one_test ())
+    return 1;
+
+  sa.sa_sigaction = (void (*)(int, siginfo_t *, void *)) sh;
+  sigemptyset (&sa.sa_mask);
+  sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
+
+  if (sigaction (SIGHUP, &sa, NULL) != 0)
+    {
+      puts ("sigaction failed");
+      return 1;
+    }
+
+  puts ("sa_flags = SA_SIGINFO|SA_ONSTACK test");
+  if (do_one_test ())
+    return 1;
+
+  return 0;
+}
+
+#define TIMEOUT 40
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-cancel22.c b/test/nptl/tst-cancel22.c
new file mode 100644 (file)
index 0000000..c47167b
--- /dev/null
@@ -0,0 +1,122 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+pthread_barrier_t b;
+int seen;
+
+static void *
+tf (void *arg)
+{
+  int i;
+  int old;
+  int r = pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &old);
+  if (r != 0)
+    {
+      puts ("setcancelstate failed");
+      exit (1);
+    }
+
+  r = pthread_barrier_wait (&b);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("barrier_wait failed");
+      exit (1);
+    }
+
+  for (i = 0; i < 10; ++i)
+    {
+      struct timespec ts = { .tv_sec = 0, .tv_nsec = 100000000 };
+      TEMP_FAILURE_RETRY (nanosleep (&ts, &ts));
+    }
+
+  seen = 1;
+  pthread_setcancelstate (old, NULL);
+
+  struct timespec ts = { .tv_sec = 0, .tv_nsec = 100000000 };
+  TEMP_FAILURE_RETRY (nanosleep (&ts, &ts));
+
+  exit (1);
+}
+
+
+static int
+do_test (void)
+{
+  if (pthread_barrier_init (&b, NULL, 2) != 0)
+   {
+     puts ("barrier init failed");
+     return 1;
+   }
+
+  pthread_t th;
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("thread creation failed");
+      return 1;
+    }
+
+  int r = pthread_barrier_wait (&b);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("barrier_wait failed");
+      return 1;
+    }
+
+  if (pthread_cancel (th) != 0)
+    {
+      puts ("cancel failed");
+      return 1;
+    }
+
+  void *status;
+  if (pthread_join (th, &status) != 0)
+    {
+      puts ("join failed");
+      return 1;
+    }
+  if (status != PTHREAD_CANCELED)
+    {
+      puts ("thread not canceled");
+      return 1;
+    }
+
+  if (pthread_barrier_destroy (&b) != 0)
+    {
+      puts ("barrier_destroy failed");
+      return 1;
+    }
+
+  if (seen != 1)
+    {
+      puts ("thread cancelled when PTHREAD_CANCEL_DISABLED");
+      return 1;
+    }
+
+  return 0;
+}
+
+#define TIMEOUT 5
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-cancel3.c b/test/nptl/tst-cancel3.c
new file mode 100644 (file)
index 0000000..86c482b
--- /dev/null
@@ -0,0 +1,98 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <unistd.h>
+
+
+static int fd[2];
+
+
+static void *
+tf (void *arg)
+{
+  char buf[100];
+
+  if (read (fd[0], buf, sizeof (buf)) == sizeof (buf))
+    {
+      puts ("read succeeded");
+      return (void *) 1l;
+    }
+
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  pthread_t th;
+  void *r;
+  struct sigaction sa;
+
+  sa.sa_handler = SIG_IGN;
+  sigemptyset (&sa.sa_mask);
+  sa.sa_flags = 0;
+
+  if (sigaction (SIGPIPE, &sa, NULL) != 0)
+    {
+      puts ("sigaction failed");
+      return 1;
+    }
+
+  if (pipe (fd) != 0)
+    {
+      puts ("pipe failed");
+      return 1;
+    }
+
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("create failed");
+      return 1;
+    }
+
+  if (pthread_cancel (th) != 0)
+    {
+      puts ("cancel failed");
+      return 1;
+    }
+
+  /* This will cause the read in the child to return.  */
+  close (fd[0]);
+
+  if (pthread_join (th, &r) != 0)
+    {
+      puts ("join failed");
+      return 1;
+    }
+
+  if (r != PTHREAD_CANCELED)
+    {
+      puts ("result is wrong");
+      return 1;
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-cancel6.c b/test/nptl/tst-cancel6.c
new file mode 100644 (file)
index 0000000..94de858
--- /dev/null
@@ -0,0 +1,79 @@
+/* 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 <stdlib.h>
+#include <unistd.h>
+
+
+static void *
+tf (void *arg)
+{
+  char buf[100];
+  fgets (buf, sizeof (buf), arg);
+  /* This call should never return.  */
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  int fd[2];
+  if (pipe (fd) != 0)
+    {
+      puts ("pipe failed");
+      return 1;
+    }
+
+  FILE *fp = fdopen (fd[0], "r");
+  if (fp == NULL)
+    {
+      puts ("fdopen failed");
+      return 1;
+    }
+
+  pthread_t th;
+  if (pthread_create (&th, NULL, tf, fp) != 0)
+    {
+      puts ("pthread_create failed");
+      return 1;
+    }
+
+  sleep (1);
+
+  if (pthread_cancel (th) != 0)
+    {
+      puts ("pthread_cancel failed");
+      return 1;
+    }
+
+  void *r;
+  if (pthread_join (th, &r) != 0)
+    {
+      puts ("pthread_join failed");
+      return 1;
+    }
+
+  return r != PTHREAD_CANCELED;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-cancel7.c b/test/nptl/tst-cancel7.c
new file mode 100644 (file)
index 0000000..16cc47c
--- /dev/null
@@ -0,0 +1,213 @@
+/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+const char *command;
+const char *pidfile;
+char pidfilename[] = "/tmp/tst-cancel7-XXXXXX";
+
+static void *
+tf (void *arg)
+{
+  const char *args = " --direct --pidfile ";
+  char *cmd = alloca (strlen (command) + strlen (args)
+                     + strlen (pidfilename) + 1);
+
+  strcpy (stpcpy (stpcpy (cmd, command), args), pidfilename);
+  system (cmd);
+  /* This call should never return.  */
+  return NULL;
+}
+
+
+static void
+sl (void)
+{
+  FILE *f = fopen (pidfile, "w");
+  if (f == NULL)
+    exit (1);
+
+  fprintf (f, "%lld\n", (long long) getpid ());
+  fflush (f);
+
+  struct flock fl =
+    {
+      .l_type = F_WRLCK,
+      .l_start = 0,
+      .l_whence = SEEK_SET,
+      .l_len = 1
+    };
+  if (fcntl (fileno (f), F_SETLK, &fl) != 0)
+    exit (1);
+
+  sigset_t ss;
+  sigfillset (&ss);
+  sigsuspend (&ss);
+  exit (0);
+}
+
+
+static void
+do_prepare (int argc, char *argv[])
+{
+  if (command == NULL)
+    command = argv[0];
+
+  if (pidfile)
+    sl ();
+
+  int fd = mkstemp (pidfilename);
+  if (fd == -1)
+    {
+      puts ("mkstemp failed");
+      exit (1);
+    }
+
+  write (fd, " ", 1);
+  close (fd);
+}
+
+
+static int
+do_test (void)
+{
+  pthread_t th;
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("pthread_create failed");
+      return 1;
+    }
+
+  do
+    sleep (1);
+  while (access (pidfilename, R_OK) != 0);
+
+  if (pthread_cancel (th) != 0)
+    {
+      puts ("pthread_cancel failed");
+      return 1;
+    }
+
+  void *r;
+  if (pthread_join (th, &r) != 0)
+    {
+      puts ("pthread_join failed");
+      return 1;
+    }
+
+  sleep (1);
+
+  FILE *f = fopen (pidfilename, "r+");
+  if (f == NULL)
+    {
+      puts ("no pidfile");
+      return 1;
+    }
+
+  long long ll;
+  if (fscanf (f, "%lld\n", &ll) != 1)
+    {
+      puts ("could not read pid");
+      unlink (pidfilename);
+      return 1;
+    }
+
+  struct flock fl =
+    {
+      .l_type = F_WRLCK,
+      .l_start = 0,
+      .l_whence = SEEK_SET,
+      .l_len = 1
+    };
+  if (fcntl (fileno (f), F_GETLK, &fl) != 0)
+    {
+      puts ("F_GETLK failed");
+      unlink (pidfilename);
+      return 1;
+    }
+
+  if (fl.l_type != F_UNLCK)
+    {
+      printf ("child %lld still running\n", (long long) fl.l_pid);
+      if (fl.l_pid == ll)
+       kill (fl.l_pid, SIGKILL);
+
+      unlink (pidfilename);
+      return 1;
+    }
+
+  fclose (f);
+
+  unlink (pidfilename);
+
+  return r != PTHREAD_CANCELED;
+}
+
+#if 0 /* unused */
+static void
+do_cleanup (void)
+{
+  FILE *f = fopen (pidfilename, "r+");
+  long long ll;
+
+  if (f != NULL && fscanf (f, "%lld\n", &ll) == 1)
+    {
+      struct flock fl =
+       {
+         .l_type = F_WRLCK,
+         .l_start = 0,
+         .l_whence = SEEK_SET,
+         .l_len = 1
+       };
+      if (fcntl (fileno (f), F_GETLK, &fl) == 0 && fl.l_type != F_UNLCK
+         && fl.l_pid == ll)
+       kill (fl.l_pid, SIGKILL);
+
+      fclose (f);
+    }
+
+  unlink (pidfilename);
+}
+#endif
+
+#define OPT_COMMAND    10000
+#define OPT_PIDFILE    10001
+#define CMDLINE_OPTIONS \
+  { "command", required_argument, NULL, OPT_COMMAND }, \
+  { "pidfile", required_argument, NULL, OPT_PIDFILE },
+#define CMDLINE_PROCESS \
+  case OPT_COMMAND:    \
+    command = optarg;  \
+    break;             \
+  case OPT_PIDFILE:    \
+    pidfile = optarg;  \
+    break;
+// #define CLEANUP_HANDLER do_cleanup ()
+#define PREPARE(argc, argv) do_prepare (argc, argv)
+#define TEST_FUNCTION do_test ()
+#define TIMEOUT 5
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-cancel8.c b/test/nptl/tst-cancel8.c
new file mode 100644 (file)
index 0000000..fc83662
--- /dev/null
@@ -0,0 +1,143 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+
+static pthread_barrier_t bar;
+
+static int global;
+
+
+static void
+cleanup (void *arg)
+{
+  global = 1;
+}
+
+
+static void *
+tf (void *arg)
+{
+  /* Enable cancellation, but defer it.  */
+  if (pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL) != 0)
+    {
+      puts ("setcancelstate failed");
+      exit (1);
+    }
+  if (pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, NULL) != 0)
+    {
+      puts ("setcanceltype failed");
+      exit (1);
+    }
+
+  /* Add cleanup handler.  */
+  pthread_cleanup_push (cleanup, NULL);
+
+  /* Synchronize with the main thread.  */
+  int r = pthread_barrier_wait (&bar);
+  if (r != 0 && r!= PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("tf: first barrier_wait failed");
+      exit (1);
+    }
+
+  /* And again.  Once this is done the main thread should have canceled
+     this thread.  */
+  r = pthread_barrier_wait (&bar);
+  if (r != 0 && r!= PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("tf: second barrier_wait failed");
+      exit (1);
+    }
+
+  /* Remove the cleanup handler without executing it.  */
+  pthread_cleanup_pop (0);
+
+  /* Now react on the cancellation.  */
+  pthread_testcancel ();
+
+  /* This call should never return.  */
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  if (pthread_barrier_init (&bar, NULL, 2) != 0)
+    {
+      puts ("barrier_init failed");
+      exit (1);
+    }
+
+  pthread_t th;
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("pthread_create failed");
+      return 1;
+    }
+
+  int r = pthread_barrier_wait (&bar);
+  if (r != 0 && r!= PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("first barrier_wait failed");
+      exit (1);
+    }
+
+  if (pthread_cancel (th) != 0)
+    {
+      puts ("pthread_cancel failed");
+      return 1;
+    }
+
+  r = pthread_barrier_wait (&bar);
+  if (r != 0 && r!= PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("second barrier_wait failed");
+      exit (1);
+    }
+
+  void *result;
+  if (pthread_join (th, &result) != 0)
+    {
+      puts ("pthread_join failed");
+      return 1;
+    }
+
+  if (result != PTHREAD_CANCELED)
+    {
+      puts ("thread was not canceled");
+      exit (1);
+    }
+
+  if (global != 0)
+    {
+      puts ("cancellation handler has been called");
+      exit (1);
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-cancel9.c b/test/nptl/tst-cancel9.c
new file mode 100644 (file)
index 0000000..037ef30
--- /dev/null
@@ -0,0 +1,126 @@
+/* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <fcntl.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+
+static pthread_barrier_t b;
+
+
+static void
+cleanup (void *arg)
+{
+  fputs ("in cleanup\n", stdout);
+}
+
+
+static void *
+tf (void *arg)
+{
+  int fd = open ("/dev/null", O_RDWR);
+  if (fd == -1)
+    {
+      puts ("cannot open /dev/null");
+      exit (1);
+    }
+  FILE *fp = fdopen (fd, "w");
+  if (fp == NULL)
+    {
+      puts ("fdopen failed");
+      exit (1);
+    }
+
+  pthread_cleanup_push (cleanup, NULL);
+
+  int e = pthread_barrier_wait (&b);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("barrier_wait failed");
+      exit (1);
+    }
+
+  while (1)
+    /* fprintf() uses write() which is a cancallation point.  */
+    fprintf (fp, "foo");
+
+  pthread_cleanup_pop (0);
+
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  if (pthread_barrier_init (&b, NULL, 2) != 0)
+    {
+      puts ("barrier_init failed");
+      exit (1);
+    }
+
+  pthread_t th;
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("create failed");
+      return 1;
+    }
+
+  int e = pthread_barrier_wait (&b);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("barrier_wait failed");
+      exit (1);
+    }
+
+  sleep (1);
+
+  puts ("cancel now");
+
+  if (pthread_cancel (th) != 0)
+    {
+      puts ("cancel failed");
+      exit (1);
+    }
+
+  puts ("waiting for the child");
+
+  void *r;
+  if (pthread_join (th, &r) != 0)
+    {
+      puts ("join failed");
+      exit (1);
+    }
+
+  if (r != PTHREAD_CANCELED)
+    {
+      puts ("thread wasn't canceled");
+      exit (1);
+    }
+
+  return 0;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-cleanup0.c b/test/nptl/tst-cleanup0.c
new file mode 100644 (file)
index 0000000..6fc2209
--- /dev/null
@@ -0,0 +1,76 @@
+/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+
+static int global;
+
+
+static void
+ch (void *arg)
+{
+  int val = (long int) arg;
+
+  printf ("ch (%d)\n", val);
+
+  global *= val;
+  global += val;
+}
+
+
+static void
+endfct (void)
+{
+  /* We force exit right here.  */
+  _exit (global);
+}
+
+
+static int
+do_test (void)
+{
+  atexit (endfct);
+
+  pthread_cancel (pthread_self ());
+
+  pthread_cleanup_push (ch, (void *) 1l);
+
+  pthread_cleanup_push (ch, (void *) 2l);
+
+  pthread_cleanup_push (ch, (void *) 3l);
+
+//  pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
+
+  pthread_cleanup_pop (1);
+
+  pthread_cleanup_pop (1);
+
+  pthread_cleanup_pop (1);
+
+  return 100;
+}
+
+
+#define EXPECTED_STATUS 9
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-cleanup1.c b/test/nptl/tst-cleanup1.c
new file mode 100644 (file)
index 0000000..2230e0f
--- /dev/null
@@ -0,0 +1,100 @@
+/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+
+static int global;
+
+
+static void
+ch (void *arg)
+{
+  int val = (long int) arg;
+
+  printf ("ch (%d)\n", val);
+
+  global *= val;
+  global += val;
+}
+
+
+static void *
+tf (void *a)
+{
+  pthread_cancel (pthread_self ());
+
+  pthread_cleanup_push (ch, (void *) 1l);
+
+  pthread_cleanup_push (ch, (void *) 2l);
+
+  pthread_cleanup_push (ch, (void *) 3l);
+
+  pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
+
+  pthread_cleanup_pop (1);
+
+  pthread_cleanup_pop (1);
+
+  pthread_cleanup_pop (1);
+
+  return NULL;
+}
+
+
+int
+do_test (void)
+{
+  pthread_t th;
+
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      write (2, "create failed\n", 14);
+      _exit (1);
+    }
+
+  void *r;
+  int e;
+  if ((e = pthread_join (th, &r)) != 0)
+    {
+      printf ("join failed: %d\n", e);
+      _exit (1);
+    }
+
+  if (r != PTHREAD_CANCELED)
+    {
+      puts ("thread not canceled");
+      exit (1);
+    }
+
+  if (global != 9)
+    {
+      printf ("global = %d, expected 9\n", global);
+      exit (1);
+    }
+
+  return 0;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-cleanup2.c b/test/nptl/tst-cleanup2.c
new file mode 100644 (file)
index 0000000..30e10b1
--- /dev/null
@@ -0,0 +1,63 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Bao Duong <bduong@progress.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <setjmp.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+static sigjmp_buf jmpbuf;
+
+static void
+sig_handler (int signo)
+{
+  siglongjmp (jmpbuf, 1);
+}
+
+static int
+do_test (void)
+{
+  char *p = NULL;
+  struct sigaction sa;
+
+  sa.sa_handler = sig_handler;
+  sigemptyset (&sa.sa_mask);
+  sa.sa_flags = SA_SIGINFO;
+
+  if (sigaction (SIGSEGV, &sa, 0))
+    {
+      perror ("installing SIGSEGV handler\n");
+      exit (1);
+    }
+
+  puts ("Attempting to sprintf to null ptr");
+  if (setjmp (jmpbuf))
+    {
+      puts ("Exiting main...");
+      return 0;
+    }
+
+  sprintf (p, "This should segv\n");
+
+  return 1;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-cleanup3.c b/test/nptl/tst-cleanup3.c
new file mode 100644 (file)
index 0000000..c442773
--- /dev/null
@@ -0,0 +1,98 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+
+static int global;
+
+
+static void
+ch (void *arg)
+{
+  int val = (long int) arg;
+
+  printf ("ch (%d)\n", val);
+
+  global *= val;
+  global += val;
+}
+
+
+static void *
+tf (void *a)
+{
+  pthread_cleanup_push (ch, (void *) 1l);
+
+  pthread_cleanup_push (ch, (void *) 2l);
+
+  pthread_cleanup_push (ch, (void *) 3l);
+
+  pthread_exit ((void *) 1l);
+
+  pthread_cleanup_pop (1);
+
+  pthread_cleanup_pop (1);
+
+  pthread_cleanup_pop (1);
+
+  return NULL;
+}
+
+
+int
+do_test (void)
+{
+  pthread_t th;
+
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      write (2, "create failed\n", 14);
+      _exit (1);
+    }
+
+  void *r;
+  int e;
+  if ((e = pthread_join (th, &r)) != 0)
+    {
+      printf ("join failed: %d\n", e);
+      _exit (1);
+    }
+
+  if (r != (void *) 1l)
+    {
+      puts ("thread not canceled");
+      exit (1);
+    }
+
+  if (global != 9)
+    {
+      printf ("global = %d, expected 9\n", global);
+      exit (1);
+    }
+
+  return 0;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-cleanup4.c b/test/nptl/tst-cleanup4.c
new file mode 100644 (file)
index 0000000..1489fd3
--- /dev/null
@@ -0,0 +1,198 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+/* LinuxThreads pthread_cleanup_{push,pop} helpers.  */
+extern void _pthread_cleanup_push (struct _pthread_cleanup_buffer *__buffer,
+                                   void (*__routine) (void *),
+                                   void *__arg);
+extern void _pthread_cleanup_pop (struct _pthread_cleanup_buffer *__buffer,
+                                  int __execute);
+
+static int fds[2];
+static pthread_barrier_t b2;
+static int global;
+
+/* Defined in tst-cleanup4aux.c, never compiled with -fexceptions.  */
+extern void fn5 (void);
+extern void fn7 (void);
+extern void fn9 (void);
+
+void
+clh (void *arg)
+{
+  int val = (long int) arg;
+
+  printf ("clh (%d)\n", val);
+
+  global *= val;
+  global += val;
+}
+
+
+static __attribute__((noinline)) void
+fn_read (void)
+{
+  int r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  char c;
+  read (fds[0], &c, 1);
+}
+
+
+__attribute__((noinline)) void
+fn0 (void)
+{
+  pthread_cleanup_push (clh, (void *) 1l);
+
+  fn_read ();
+
+  pthread_cleanup_pop (1);
+}
+
+
+__attribute__((noinline)) void
+fn1 (void)
+{
+  /* This is the old LinuxThreads pthread_cleanup_{push,pop}.  */
+  struct _pthread_cleanup_buffer b;
+  _pthread_cleanup_push (&b, clh, (void *) 2l);
+
+  fn0 ();
+
+  _pthread_cleanup_pop (&b, 1);
+}
+
+
+static __attribute__((noinline)) void
+fn2 (void)
+{
+  pthread_cleanup_push (clh, (void *) 3l);
+
+  fn1 ();
+
+  pthread_cleanup_pop (1);
+}
+
+
+static void *
+tf (void *a)
+{
+  switch ((long) a)
+    {
+    case 0:
+      fn2 ();
+      break;
+    case 1:
+      fn5 ();
+      break;
+    case 2:
+      fn7 ();
+      break;
+    case 3:
+      fn9 ();
+      break;
+    }
+
+  return NULL;
+}
+
+
+int
+do_test (void)
+{
+  int result = 0;
+
+  if (pipe (fds) != 0)
+    {
+      puts ("pipe failed");
+      exit (1);
+    }
+
+  if (pthread_barrier_init (&b2, NULL, 2) != 0)
+    {
+      puts ("b2 init failed");
+      exit (1);
+    }
+
+  const int expect[] =
+    {
+      15,      /* 1 2 3 */
+      276,     /* 1 4 5 6 */
+      120,     /* 1 7 8 */
+      460      /* 1 2 9 10 */
+    };
+
+  long i;
+  for (i = 0; i < 4; ++i)
+    {
+      global = 0;
+
+      printf ("test %ld\n", i);
+
+      pthread_t th;
+      if (pthread_create (&th, NULL, tf, (void *) i) != 0)
+       {
+         puts ("create failed");
+         exit (1);
+       }
+
+      int e = pthread_barrier_wait (&b2);
+      if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+       {
+         printf ("%s: barrier_wait failed\n", __FUNCTION__);
+         exit (1);
+       }
+
+      pthread_cancel (th);
+
+      void *r;
+      if ((e = pthread_join (th, &r)) != 0)
+       {
+         printf ("join failed: %d\n", e);
+         _exit (1);
+       }
+
+      if (r != PTHREAD_CANCELED)
+       {
+         puts ("thread not canceled");
+         exit (1);
+       }
+
+      if (global != expect[i])
+       {
+         printf ("global = %d, expected %d\n", global, expect[i]);
+         result = 1;
+       }
+    }
+
+  return result;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-cleanup4aux.c b/test/nptl/tst-cleanup4aux.c
new file mode 100644 (file)
index 0000000..cd1a89a
--- /dev/null
@@ -0,0 +1,121 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+extern void _pthread_cleanup_push (struct _pthread_cleanup_buffer *__buffer,
+                                   void (*__routine) (void *),
+                                   void *__arg);
+extern void _pthread_cleanup_pop (struct _pthread_cleanup_buffer *__buffer,
+                                  int __execute);
+
+extern void clh (void *arg);
+extern void fn0 (void);
+extern void fn1 (void);
+extern void fn5 (void);
+extern void fn7 (void);
+extern void fn9 (void);
+
+
+static __attribute__((noinline)) void
+fn3 (void)
+{
+  /* This is the old LinuxThreads pthread_cleanup_{push,pop}.  */
+     struct _pthread_cleanup_buffer b;
+  _pthread_cleanup_push (&b, clh, (void *) 4l);
+
+  fn0 ();
+
+  _pthread_cleanup_pop (&b, 1);
+}
+
+
+static __attribute__((noinline)) void
+fn4 (void)
+{
+  pthread_cleanup_push (clh, (void *) 5l);
+
+  fn3 ();
+
+  pthread_cleanup_pop (1);
+}
+
+
+void
+fn5 (void)
+{
+  /* This is the old LinuxThreads pthread_cleanup_{push,pop}.  */
+     struct _pthread_cleanup_buffer b;
+  _pthread_cleanup_push (&b, clh, (void *) 6l);
+
+  fn4 ();
+
+  _pthread_cleanup_pop (&b, 1);
+}
+
+
+static __attribute__((noinline)) void
+fn6 (void)
+{
+  pthread_cleanup_push (clh, (void *) 7l);
+
+  fn0 ();
+
+  pthread_cleanup_pop (1);
+}
+
+
+void
+fn7 (void)
+{
+  /* This is the old LinuxThreads pthread_cleanup_{push,pop}.  */
+     struct _pthread_cleanup_buffer b;
+  _pthread_cleanup_push (&b, clh, (void *) 8l);
+
+  fn6 ();
+
+  _pthread_cleanup_pop (&b, 1);
+}
+
+
+static __attribute__((noinline)) void
+fn8 (void)
+{
+  pthread_cleanup_push (clh, (void *) 9l);
+
+  fn1 ();
+
+  pthread_cleanup_pop (1);
+}
+
+
+void
+fn9 (void)
+{
+  /* This is the old LinuxThreads pthread_cleanup_{push,pop}.  */
+     struct _pthread_cleanup_buffer b;
+  _pthread_cleanup_push (&b, clh, (void *) 10l);
+
+  fn8 ();
+
+  _pthread_cleanup_pop (&b, 1);
+}
diff --git a/test/nptl/tst-clock.c b/test/nptl/tst-clock.c
new file mode 100644 (file)
index 0000000..f2f1887
--- /dev/null
@@ -0,0 +1,124 @@
+/* Test program for POSIX clock_* functions.
+   Copyright (C) 2000 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 2000.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+
+/* We want to see output immediately.  */
+#define STDOUT_UNBUFFERED
+
+/* We expect to run at least 10 seconds.  */
+#define TIMEOUT 15
+
+static int
+clock_test (clockid_t cl)
+{
+  struct timespec old_ts;
+  struct timespec ts;
+  struct timespec waitit;
+  int result = 0;
+  int i;
+
+  memset (&ts, '\0', sizeof ts);
+
+  waitit.tv_sec = 0;
+  waitit.tv_nsec = 500000000;
+
+  /* Get and print resolution of the clock.  */
+  if (clock_getres (cl, &ts) == 0)
+    {
+      if (ts.tv_nsec < 0 || ts.tv_nsec >= 1000000000)
+       {
+         printf ("clock %d: nanosecond value of resolution wrong\n", cl);
+         result = 1;
+       }
+      else
+       printf ("clock %d: resolution = %ld.%09ld secs\n",
+               cl, ts.tv_sec, ts.tv_nsec);
+    }
+  else
+    {
+      printf ("clock %d: cannot get resolution\n", cl);
+      result = 1;
+    }
+
+  memset (&ts, '\0', sizeof ts);
+  memset (&old_ts, '\0', sizeof old_ts);
+
+  /* Next get the current time value a few times.  */
+  for (i = 0; i < 10; ++i)
+    {
+      if (clock_gettime (cl, &ts) == 0)
+       {
+         if (ts.tv_nsec < 0 || ts.tv_nsec >= 1000000000)
+           {
+             printf ("clock %d: nanosecond value of time wrong (try %d)\n",
+                     cl, i);
+             result = 1;
+           }
+         else
+           {
+             printf ("clock %d: time = %ld.%09ld secs\n",
+                     cl, ts.tv_sec, ts.tv_nsec);
+
+             if (memcmp (&ts, &old_ts, sizeof ts) == 0)
+               {
+                 printf ("clock %d: time hasn't changed (try %d)\n", cl, i);
+                 result = 1;
+
+                 old_ts = ts;
+               }
+           }
+       }
+      else
+       {
+         printf ("clock %d: cannot get time (try %d)\n", cl, i);
+         result = 1;
+       }
+
+      /* Wait a bit before the next iteration.  */
+      nanosleep (&waitit, NULL);
+    }
+
+  return result;
+}
+
+static int
+do_test (void)
+{
+  clockid_t cl;
+  int result;
+
+  result = clock_test (CLOCK_REALTIME);
+
+  if (clock_getcpuclockid (0, &cl) == 0)
+    /* XXX It's not yet a bug when this fails.  */
+    clock_test (cl);
+  else
+         printf("CPU clock unavailble, skipping test\n");
+
+  return result;
+}
+#define TEST_FUNCTION do_test ()
+
+
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-clock1.c b/test/nptl/tst-clock1.c
new file mode 100644 (file)
index 0000000..0848d77
--- /dev/null
@@ -0,0 +1,51 @@
+/* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+
+
+int
+do_test (void)
+{
+#if defined _POSIX_THREAD_CPUTIME && _POSIX_THREAD_CPUTIME >= 0
+  clockid_t cl;
+  /* This is really only a linking-test here.  */
+  int e = pthread_getcpuclockid (pthread_self (), &cl);
+  if (e != 0)
+    {
+# if _POSIX_THREAD_CPUTIME == 0
+      if (sysconf (_SC_THREAD_CPUTIME) >= 0)
+# endif
+       {
+         puts ("cpuclock advertized, but cannot get ID");
+         exit (1);
+       }
+    }
+#endif
+
+  return 0;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-clock2.c b/test/nptl/tst-clock2.c
new file mode 100644 (file)
index 0000000..49a769b
--- /dev/null
@@ -0,0 +1,202 @@
+/* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+
+
+#if defined _POSIX_THREAD_CPUTIME && _POSIX_THREAD_CPUTIME >= 0
+static pthread_barrier_t b2;
+static pthread_barrier_t bN;
+
+
+static void *
+tf (void *arg)
+{
+  int e = pthread_barrier_wait (&b2);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("barrier_wait failed");
+      exit (1);
+    }
+
+  e = pthread_barrier_wait (&bN);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("barrier_wait failed");
+      exit (1);
+    }
+
+  return NULL;
+}
+#endif
+
+
+int
+do_test (void)
+{
+#if defined _POSIX_THREAD_CPUTIME && _POSIX_THREAD_CPUTIME >= 0
+# define N 10
+
+# if _POSIX_THREAD_CPUTIME == 0
+  if (sysconf (_SC_THREAD_CPUTIME) < 0)
+    {
+      puts ("_POSIX_THREAD_CPUTIME option not available");
+      return 1;
+    }
+# endif
+
+  if (pthread_barrier_init (&b2, NULL, 2) != 0
+      || pthread_barrier_init (&bN, NULL, N + 1) != 0)
+    {
+      puts ("barrier_init failed");
+      return 1;
+    }
+
+  struct timespec ts = { .tv_sec = 0, .tv_nsec = 100000000 };
+  TEMP_FAILURE_RETRY (nanosleep (&ts, &ts));
+
+  pthread_t th[N + 1];
+  clockid_t cl[N + 1];
+# ifndef CLOCK_THREAD_CPUTIME_ID
+  if (pthread_getcpuclockid (pthread_self (), &cl[0]) != 0)
+    {
+      puts ("own pthread_getcpuclockid failed");
+      return 1;
+    }
+# else
+  cl[0] = CLOCK_THREAD_CPUTIME_ID;
+# endif
+
+  pthread_attr_t at;
+
+  if (pthread_attr_init (&at) != 0)
+    {
+      puts ("attr_init failed");
+      return 1;
+    }
+
+  if (pthread_attr_setstacksize (&at, 1 * 1024 * 1024) != 0)
+    {
+      puts ("attr_setstacksize failed");
+      return 1;
+    }
+
+  int i;
+  int e;
+  for (i = 0; i < N; ++i)
+    {
+      if (pthread_create (&th[i], &at, tf, NULL) != 0)
+       {
+         puts ("create failed");
+         return 1;
+       }
+
+      e = pthread_barrier_wait (&b2);
+      if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+       {
+         puts ("barrier_wait failed");
+         return 1;
+       }
+
+      ts.tv_sec = 0;
+      ts.tv_nsec = 100000000;
+      TEMP_FAILURE_RETRY (nanosleep (&ts, &ts));
+
+      if (pthread_getcpuclockid (th[i], &cl[i + 1]) != 0)
+       {
+         puts ("pthread_getcpuclockid failed");
+         return 1;
+       }
+    }
+
+  if (pthread_attr_destroy (&at) != 0)
+    {
+      puts ("attr_destroy failed");
+      return 1;
+    }
+
+  struct timespec t[N + 1];
+  for (i = 0; i < N + 1; ++i)
+    if (clock_gettime (cl[i], &t[i]) != 0)
+      {
+       printf ("clock_gettime round %d failed\n", i);
+       return 1;
+      }
+
+  for (i = 0; i < N; ++i)
+    {
+      struct timespec diff;
+
+      diff.tv_sec = t[i].tv_sec - t[i + 1].tv_sec;
+      diff.tv_nsec = t[i].tv_nsec - t[i + 1].tv_nsec;
+      if (diff.tv_nsec < 0)
+       {
+         diff.tv_nsec += 1000000000;
+         --diff.tv_sec;
+       }
+
+      if (diff.tv_sec < 0 || (diff.tv_sec == 0 && diff.tv_nsec < 100000000))
+       {
+         printf ("\
+difference between thread %d and %d too small (%ld.%09ld)\n",
+                 i, i + 1, (long int) diff.tv_sec, (long int) diff.tv_nsec);
+         return 1;
+       }
+
+      printf ("diff %d->%d: %ld.%09ld\n",
+             i, i + 1, (long int) diff.tv_sec, (long int) diff.tv_nsec);
+    }
+
+  ts.tv_sec = 0;
+  ts.tv_nsec = 0;
+  for (i = 0; i < N + 1; ++i)
+    if (clock_settime (cl[i], &ts) != 0)
+      {
+       printf ("clock_settime(%d) round %d failed\n", cl[i], i);
+       return 1;
+      }
+
+  for (i = 0; i < N + 1; ++i)
+    {
+      if (clock_gettime (cl[i], &ts) != 0)
+       {
+         puts ("clock_gettime failed");
+         return 1;
+       }
+
+      if (ts.tv_sec > t[i].tv_sec
+         || (ts.tv_sec == t[i].tv_sec && ts.tv_nsec > t[i].tv_nsec))
+       {
+         puts ("clock_settime didn't reset clock");
+         return 1;
+       }
+    }
+#endif
+
+  return 0;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-clock_nanosleep.c b/test/nptl/tst-clock_nanosleep.c
new file mode 100644 (file)
index 0000000..98a8b5f
--- /dev/null
@@ -0,0 +1,58 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <time.h>
+
+
+/* Test that clock_nanosleep() does sleep.  */
+static int
+do_test (void)
+{
+  /* Current time.  */
+  struct timeval tv1;
+  (void) gettimeofday (&tv1, NULL);
+
+  struct timespec ts;
+  ts.tv_sec = 1;
+  ts.tv_nsec = 0;
+  TEMP_FAILURE_RETRY (clock_nanosleep (CLOCK_REALTIME, 0, &ts, &ts));
+
+  /* At least one second must have passed.  */
+  struct timeval tv2;
+  (void) gettimeofday (&tv2, NULL);
+
+  tv2.tv_sec -= tv1.tv_sec;
+  tv2.tv_usec -= tv1.tv_usec;
+  if (tv2.tv_usec < 0)
+    --tv2.tv_sec;
+
+  if (tv2.tv_sec < 1)
+    {
+      puts ("clock_nanosleep didn't sleep long enough");
+      return 1;
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-cond1.c b/test/nptl/tst-cond1.c
new file mode 100644 (file)
index 0000000..46085c2
--- /dev/null
@@ -0,0 +1,94 @@
+/* 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 <error.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
+static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
+
+
+static void *
+tf (void *p)
+{
+  int err;
+
+  err = pthread_mutex_lock (&mut);
+  if (err != 0)
+    error (EXIT_FAILURE, err, "child: cannot get mutex");
+
+  puts ("child: got mutex; signalling");
+
+  pthread_cond_signal (&cond);
+
+  puts ("child: unlock");
+
+  err = pthread_mutex_unlock (&mut);
+  if (err != 0)
+    error (EXIT_FAILURE, err, "child: cannot unlock");
+
+  puts ("child: done");
+
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  pthread_t th;
+  int err;
+
+  printf ("&cond = %p\n&mut = %p\n", &cond, &mut);
+
+  puts ("parent: get mutex");
+
+  err = pthread_mutex_lock (&mut);
+  if (err != 0)
+    error (EXIT_FAILURE, err, "parent: cannot get mutex");
+
+  puts ("parent: create child");
+
+  err = pthread_create (&th, NULL, tf, NULL);
+  if (err != 0)
+    error (EXIT_FAILURE, err, "parent: cannot create thread");
+
+  puts ("parent: wait for condition");
+
+  err = pthread_cond_wait (&cond, &mut);
+  if (err != 0)
+    error (EXIT_FAILURE, err, "parent: cannot wait fir signal");
+
+  puts ("parent: got signal");
+
+  err = pthread_join (th, NULL);
+  if (err != 0)
+    error (EXIT_FAILURE, err, "parent: failed to join");
+
+  puts ("done");
+
+  return 0;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-cond10.c b/test/nptl/tst-cond10.c
new file mode 100644 (file)
index 0000000..34956d4
--- /dev/null
@@ -0,0 +1,173 @@
+/* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <error.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+#define N 10
+#define ROUNDS 100
+
+static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
+static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
+static pthread_barrier_t bN1;
+static pthread_barrier_t b2;
+
+
+static void *
+tf (void *p)
+{
+  if (pthread_mutex_lock (&mut) != 0)
+    {
+      puts ("child: 1st mutex_lock failed");
+      exit (1);
+    }
+
+  int e = pthread_barrier_wait (&b2);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("child: 1st barrier_wait failed");
+      exit (1);
+    }
+
+  if (pthread_cond_wait (&cond, &mut) != 0)
+    {
+      puts ("child: cond_wait failed");
+      exit (1);
+    }
+
+  if (pthread_mutex_unlock (&mut) != 0)
+    {
+      puts ("child: mutex_unlock failed");
+      exit (1);
+    }
+
+  e = pthread_barrier_wait (&bN1);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("child: 2nd barrier_wait failed");
+      exit (1);
+    }
+
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  if (pthread_barrier_init (&bN1, NULL, N + 1) != 0)
+    {
+      puts ("barrier_init failed");
+      exit (1);
+    }
+
+  if (pthread_barrier_init (&b2, NULL, 2) != 0)
+    {
+      puts ("barrier_init failed");
+      exit (1);
+    }
+
+  pthread_attr_t at;
+
+  if (pthread_attr_init (&at) != 0)
+    {
+      puts ("attr_init failed");
+      return 1;
+    }
+
+  if (pthread_attr_setstacksize (&at, 1 * 1024 * 1024) != 0)
+    {
+      puts ("attr_setstacksize failed");
+      return 1;
+    }
+
+  int r;
+  for (r = 0; r < ROUNDS; ++r)
+    {
+      printf ("round %d\n", r + 1);
+
+      int i;
+      pthread_t th[N];
+      for (i = 0; i < N; ++i)
+       {
+         if (pthread_create (&th[i], &at, tf, NULL) != 0)
+           {
+             puts ("create failed");
+             exit (1);
+           }
+
+         int e = pthread_barrier_wait (&b2);
+         if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+           {
+             puts ("parent: 1st barrier_wait failed");
+             exit (1);
+           }
+       }
+
+      if (pthread_mutex_lock (&mut) != 0)
+       {
+         puts ("parent: mutex_lock failed");
+         exit (1);
+       }
+      if (pthread_mutex_unlock (&mut) != 0)
+       {
+         puts ("parent: mutex_unlock failed");
+         exit (1);
+       }
+
+      /* N single signal calls.  Without locking.  This tests that no
+        signal gets lost.  */
+      for (i = 0; i < N; ++i)
+       if (pthread_cond_signal (&cond) != 0)
+         {
+           puts ("cond_signal failed");
+           exit (1);
+         }
+
+      int e = pthread_barrier_wait (&bN1);
+      if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+       {
+         puts ("parent: 2nd barrier_wait failed");
+         exit (1);
+       }
+
+      for (i = 0; i < N; ++i)
+       if (pthread_join (th[i], NULL) != 0)
+         {
+           puts ("join failed");
+           exit (1);
+         }
+    }
+
+  if (pthread_attr_destroy (&at) != 0)
+    {
+      puts ("attr_destroy failed");
+      return 1;
+    }
+
+  return 0;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-cond11.c b/test/nptl/tst-cond11.c
new file mode 100644 (file)
index 0000000..0de4d56
--- /dev/null
@@ -0,0 +1,191 @@
+/* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <time.h>
+#include <unistd.h>
+
+
+#if defined _POSIX_CLOCK_SELECTION && _POSIX_CLOCK_SELECTION >= 0
+static int
+run_test (clockid_t cl)
+{
+  pthread_condattr_t condattr;
+  pthread_cond_t cond;
+  pthread_mutexattr_t mutattr;
+  pthread_mutex_t mut;
+
+  printf ("clock = %d\n", (int) cl);
+
+  if (pthread_condattr_init (&condattr) != 0)
+    {
+      puts ("condattr_init failed");
+      return 1;
+    }
+
+  if (pthread_condattr_setclock (&condattr, cl) != 0)
+    {
+      puts ("condattr_setclock failed");
+      return 1;
+    }
+
+  clockid_t cl2;
+  if (pthread_condattr_getclock (&condattr, &cl2) != 0)
+    {
+      puts ("condattr_getclock failed");
+      return 1;
+    }
+  if (cl != cl2)
+    {
+      printf ("condattr_getclock returned wrong value: %d, expected %d\n",
+             (int) cl2, (int) cl);
+      return 1;
+    }
+
+  if (pthread_cond_init (&cond, &condattr) != 0)
+    {
+      puts ("cond_init failed");
+      return 1;
+    }
+
+  if (pthread_condattr_destroy (&condattr) != 0)
+    {
+      puts ("condattr_destroy failed");
+      return 1;
+    }
+
+  if (pthread_mutexattr_init (&mutattr) != 0)
+    {
+      puts ("mutexattr_init failed");
+      return 1;
+    }
+
+  if (pthread_mutexattr_settype (&mutattr, PTHREAD_MUTEX_ERRORCHECK) != 0)
+    {
+      puts ("mutexattr_settype failed");
+      return 1;
+    }
+
+  if (pthread_mutex_init (&mut, &mutattr) != 0)
+    {
+      puts ("mutex_init failed");
+      return 1;
+    }
+
+  if (pthread_mutexattr_destroy (&mutattr) != 0)
+    {
+      puts ("mutexattr_destroy failed");
+      return 1;
+    }
+
+  if (pthread_mutex_lock (&mut) != 0)
+    {
+      puts ("mutex_lock failed");
+      return 1;
+    }
+
+  if (pthread_mutex_lock (&mut) != EDEADLK)
+    {
+      puts ("2nd mutex_lock did not return EDEADLK");
+      return 1;
+    }
+
+  struct timespec ts;
+  if (clock_gettime (cl, &ts) != 0)
+    {
+      puts ("clock_gettime failed");
+      return 1;
+    }
+
+  /* Wait one second.  */
+  ++ts.tv_sec;
+
+  int e = pthread_cond_timedwait (&cond, &mut, &ts);
+  if (e == 0)
+    {
+      puts ("cond_timedwait succeeded");
+      return 1;
+    }
+  else if (e != ETIMEDOUT)
+    {
+      puts ("cond_timedwait did not return ETIMEDOUT");
+      return 1;
+    }
+
+  if (pthread_mutex_unlock (&mut) != 0)
+    {
+      puts ("mutex_unlock failed");
+      return 1;
+    }
+
+  if (pthread_mutex_destroy (&mut) != 0)
+    {
+      puts ("mutex_destroy failed");
+      return 1;
+    }
+
+  if (pthread_cond_destroy (&cond) != 0)
+    {
+      puts ("cond_destroy failed");
+      return 1;
+    }
+
+  return 0;
+}
+#endif
+
+
+static int
+do_test (void)
+{
+#if !defined _POSIX_CLOCK_SELECTION || _POSIX_CLOCK_SELECTION == -1
+
+  puts ("_POSIX_CLOCK_SELECTION not supported, test skipped");
+  return 0;
+
+#else
+
+  int res = run_test (CLOCK_REALTIME);
+
+# if defined _POSIX_MONOTONIC_CLOCK && _POSIX_MONOTONIC_CLOCK >= 0
+#  if _POSIX_MONOTONIC_CLOCK == 0
+  int e = sysconf (_SC_MONOTONIC_CLOCK);
+  if (e < 0)
+    puts ("CLOCK_MONOTONIC not supported");
+  else if (e == 0)
+    {
+      puts ("sysconf (_SC_MONOTONIC_CLOCK) must not return 0");
+      res = 1;
+    }
+  else
+#  endif
+    res |= run_test (CLOCK_MONOTONIC);
+# else
+  puts ("_POSIX_MONOTONIC_CLOCK not defined");
+# endif
+
+  return res;
+#endif
+}
+
+#define TIMEOUT 3
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-cond12.c b/test/nptl/tst-cond12.c
new file mode 100644 (file)
index 0000000..03e4881
--- /dev/null
@@ -0,0 +1,196 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+
+
+static char fname[] = "/tmp/tst-cond12-XXXXXX";
+static int fd;
+
+
+static void prepare (void);
+#define PREPARE(argc, argv) prepare ()
+
+static int do_test (void);
+#define TEST_FUNCTION do_test ()
+
+#include "../test-skeleton.c"
+
+
+static void
+prepare (void)
+{
+  fd = mkstemp (fname);
+  if (fd == -1)
+    {
+      printf ("mkstemp failed: %m\n");
+      exit (1);
+    }
+  add_temp_file (fname);
+  if (ftruncate (fd, 1000) < 0)
+    {
+      printf ("ftruncate failed: %m\n");
+      exit (1);
+    }
+}
+
+
+static int
+do_test (void)
+{
+  struct
+  {
+    pthread_mutex_t m;
+    pthread_cond_t c;
+    int var;
+  } *p = mmap (NULL, sizeof (*p), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+  if (p == MAP_FAILED)
+    {
+      printf ("initial mmap failed: %m\n");
+      return 1;
+    }
+
+  pthread_mutexattr_t ma;
+  if (pthread_mutexattr_init (&ma) != 0)
+    {
+      puts ("mutexattr_init failed");
+      return 1;
+    }
+  if (pthread_mutexattr_setpshared (&ma, 1) != 0)
+    {
+      puts ("mutexattr_setpshared failed");
+      return 1;
+    }
+  if (pthread_mutex_init (&p->m, &ma) != 0)
+    {
+      puts ("mutex_init failed");
+      return 1;
+    }
+  if (pthread_mutexattr_destroy (&ma) != 0)
+    {
+      puts ("mutexattr_destroy failed");
+      return 1;
+    }
+
+  pthread_condattr_t ca;
+  if (pthread_condattr_init (&ca) != 0)
+    {
+      puts ("condattr_init failed");
+      return 1;
+    }
+  if (pthread_condattr_setpshared (&ca, 1) != 0)
+    {
+      puts ("condattr_setpshared failed");
+      return 1;
+    }
+  if (pthread_cond_init (&p->c, &ca) != 0)
+    {
+      puts ("mutex_init failed");
+      return 1;
+    }
+  if (pthread_condattr_destroy (&ca) != 0)
+    {
+      puts ("condattr_destroy failed");
+      return 1;
+    }
+
+  if (pthread_mutex_lock (&p->m) != 0)
+    {
+      puts ("initial mutex_lock failed");
+      return 1;
+    }
+
+  p->var = 42;
+
+  pid_t pid = fork ();
+  if (pid == -1)
+    {
+      printf ("fork failed: %m\n");
+      return 1;
+    }
+
+  if (pid == 0)
+    {
+      void *oldp = p;
+      p = mmap (NULL, sizeof (*p), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+
+      if (p == oldp)
+       {
+         puts ("child: mapped to same address");
+         kill (getppid (), SIGKILL);
+         exit (1);
+       }
+
+      munmap (oldp, sizeof (*p));
+
+      if (pthread_mutex_lock (&p->m) != 0)
+       {
+         puts ("child: mutex_lock failed");
+         kill (getppid (), SIGKILL);
+         exit (1);
+       }
+
+      p->var = 0;
+
+#ifndef USE_COND_SIGNAL
+      if (pthread_cond_broadcast (&p->c) != 0)
+       {
+         puts ("child: cond_broadcast failed");
+         kill (getppid (), SIGKILL);
+         exit (1);
+       }
+#else
+      if (pthread_cond_signal (&p->c) != 0)
+       {
+         puts ("child: cond_signal failed");
+         kill (getppid (), SIGKILL);
+         exit (1);
+       }
+#endif
+
+      if (pthread_mutex_unlock (&p->m) != 0)
+       {
+         puts ("child: mutex_unlock failed");
+         kill (getppid (), SIGKILL);
+         exit (1);
+       }
+
+      exit (0);
+    }
+
+  do
+    pthread_cond_wait (&p->c, &p->m);
+  while (p->var != 0);
+
+  if (TEMP_FAILURE_RETRY (waitpid (pid, NULL, 0)) != pid)
+    {
+      printf ("waitpid failed: %m\n");
+      kill (pid, SIGKILL);
+      return 1;
+    }
+
+  return 0;
+}
diff --git a/test/nptl/tst-cond13.c b/test/nptl/tst-cond13.c
new file mode 100644 (file)
index 0000000..29d79b5
--- /dev/null
@@ -0,0 +1,2 @@
+#define USE_COND_SIGNAL 1
+#include "tst-cond12.c"
diff --git a/test/nptl/tst-cond14.c b/test/nptl/tst-cond14.c
new file mode 100644 (file)
index 0000000..106fa8c
--- /dev/null
@@ -0,0 +1,118 @@
+/* Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2004.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with 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 <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+
+static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
+static pthread_mutex_t mut = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
+static pthread_mutex_t mut2 = PTHREAD_MUTEX_INITIALIZER;
+
+static void *
+tf (void *p)
+{
+  if (pthread_mutex_lock (&mut) != 0)
+    {
+      printf ("%s: 1st mutex_lock failed\n", __func__);
+      exit (1);
+    }
+  if (pthread_mutex_lock (&mut) != 0)
+    {
+      printf ("%s: 2nd mutex_lock failed\n", __func__);
+      exit (1);
+    }
+  if (pthread_mutex_lock (&mut) != 0)
+    {
+      printf ("%s: 3rd mutex_lock failed\n", __func__);
+      exit (1);
+    }
+
+  if (pthread_mutex_unlock (&mut2) != 0)
+    {
+      printf ("%s: mutex_unlock failed\n", __func__);
+      exit (1);
+    }
+
+  if (pthread_cond_wait (&cond, &mut) != 0)
+    {
+      printf ("%s: cond_wait failed\n", __func__);
+      exit (1);
+    }
+
+  puts ("child: done");
+
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  if (pthread_mutex_lock (&mut2) != 0)
+    {
+      puts ("1st mutex_lock failed");
+      return 1;
+    }
+
+  puts ("parent: create child");
+
+  pthread_t th;
+  int err = pthread_create (&th, NULL, tf, NULL);
+  if (err != 0)
+    {
+      printf ("parent: cannot create thread: %s\n", strerror (err));
+      return 1;
+    }
+
+  /* We have to synchronize with the child.  */
+  if (pthread_mutex_lock (&mut2) != 0)
+    {
+      puts ("2nd mutex_lock failed");
+      return 1;
+    }
+
+  /* Give the child to reach to pthread_cond_wait.  */
+  sleep (1);
+
+  if (pthread_cond_signal (&cond) != 0)
+    {
+      puts ("cond_signal failed");
+      return 1;
+    }
+
+  err = pthread_join (th, NULL);
+  if (err != 0)
+    {
+      printf ("parent: failed to join: %s\n", strerror (err));
+      return 1;
+    }
+
+  puts ("done");
+
+  return 0;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#define TIMEOUT 3
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-cond15.c b/test/nptl/tst-cond15.c
new file mode 100644 (file)
index 0000000..e815e25
--- /dev/null
@@ -0,0 +1,160 @@
+/* Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2004.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with 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 <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/time.h>
+
+
+static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
+static pthread_mutex_t mut = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
+static pthread_mutex_t mut2 = PTHREAD_MUTEX_INITIALIZER;
+
+static void *
+tf (void *p)
+{
+  if (pthread_mutex_lock (&mut) != 0)
+    {
+      printf ("%s: 1st mutex_lock failed\n", __func__);
+      exit (1);
+    }
+  if (pthread_mutex_lock (&mut) != 0)
+    {
+      printf ("%s: 2nd mutex_lock failed\n", __func__);
+      exit (1);
+    }
+  if (pthread_mutex_lock (&mut) != 0)
+    {
+      printf ("%s: 3rd mutex_lock failed\n", __func__);
+      exit (1);
+    }
+
+  if (pthread_mutex_unlock (&mut2) != 0)
+    {
+      printf ("%s: mutex_unlock failed\n", __func__);
+      exit (1);
+    }
+
+  struct timeval tv;
+  gettimeofday (&tv, NULL);
+  struct timespec ts;
+  TIMEVAL_TO_TIMESPEC (&tv, &ts);
+  ts.tv_sec += p == NULL ? 100 : 1;
+
+  int err = pthread_cond_timedwait (&cond, &mut, &ts);
+  if ((err != 0 && p == NULL) || (err != ETIMEDOUT && p != NULL))
+    {
+      printf ("%s: cond_wait failed\n", __func__);
+      exit (1);
+    }
+
+  if (pthread_mutex_unlock (&mut) != 0)
+    {
+      printf ("%s: 1st mutex_unlock failed\n", __func__);
+      exit (1);
+    }
+  if (pthread_mutex_unlock (&mut) != 0)
+    {
+      printf ("%s: 2nd mutex_unlock failed\n", __func__);
+      exit (1);
+    }
+  if (pthread_mutex_unlock (&mut) != 0)
+    {
+      printf ("%s: 3rd mutex_unlock failed\n", __func__);
+      exit (1);
+    }
+
+  puts ("child: done");
+
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  if (pthread_mutex_lock (&mut2) != 0)
+    {
+      puts ("1st mutex_lock failed");
+      return 1;
+    }
+
+  puts ("parent: create 1st child");
+
+  pthread_t th;
+  int err = pthread_create (&th, NULL, tf, NULL);
+  if (err != 0)
+    {
+      printf ("parent: cannot 1st create thread: %s\n", strerror (err));
+      return 1;
+    }
+
+  /* We have to synchronize with the child.  */
+  if (pthread_mutex_lock (&mut2) != 0)
+    {
+      puts ("2nd mutex_lock failed");
+      return 1;
+    }
+
+  /* Give the child to reach to pthread_cond_wait.  */
+  sleep (1);
+
+  if (pthread_cond_signal (&cond) != 0)
+    {
+      puts ("cond_signal failed");
+      return 1;
+    }
+
+  err = pthread_join (th, NULL);
+  if (err != 0)
+    {
+      printf ("parent: failed to join: %s\n", strerror (err));
+      return 1;
+    }
+
+
+  puts ("parent: create 2nd child");
+
+  err = pthread_create (&th, NULL, tf, (void *) 1l);
+  if (err != 0)
+    {
+      printf ("parent: cannot 2nd create thread: %s\n", strerror (err));
+      return 1;
+    }
+
+  err = pthread_join (th, NULL);
+  if (err != 0)
+    {
+      printf ("parent: failed to join: %s\n", strerror (err));
+      return 1;
+    }
+
+  puts ("done");
+
+  return 0;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#define TIMEOUT 6
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-cond16.c b/test/nptl/tst-cond16.c
new file mode 100644 (file)
index 0000000..00c27ec
--- /dev/null
@@ -0,0 +1,105 @@
+/* Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2004.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with 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 <pthread.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+pthread_cond_t cv = PTHREAD_COND_INITIALIZER;
+pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+bool n, exiting;
+FILE *f;
+int count;
+
+void *
+tf (void *dummy)
+{
+  bool loop = true;
+
+  while (loop)
+    {
+      pthread_mutex_lock (&lock);
+      while (n && !exiting)
+       pthread_cond_wait (&cv, &lock);
+      n = true;
+      pthread_mutex_unlock (&lock);
+
+      fputs (".", f);
+
+      pthread_mutex_lock (&lock);
+      n = false;
+      if (exiting)
+       loop = false;
+#ifdef UNLOCK_AFTER_BROADCAST
+      pthread_cond_broadcast (&cv);
+      pthread_mutex_unlock (&lock);
+#else
+      pthread_mutex_unlock (&lock);
+      pthread_cond_broadcast (&cv);
+#endif
+    }
+
+  return NULL;
+}
+
+int
+do_test (void)
+{
+  f = fopen ("/dev/null", "w");
+  if (f == NULL)
+    {
+      printf ("couldn't open /dev/null, %m\n");
+      return 1;
+    }
+
+  count = sysconf (_SC_NPROCESSORS_ONLN);
+  if (count <= 0)
+    count = 1;
+  count *= 4;
+
+  pthread_t th[count];
+  int i, ret;
+  for (i = 0; i < count; ++i)
+    if ((ret = pthread_create (&th[i], NULL, tf, NULL)) != 0)
+      {
+       errno = ret;
+       printf ("pthread_create %d failed: %m\n", i);
+       return 1;
+      }
+
+  struct timespec ts = { .tv_sec = 20, .tv_nsec = 0 };
+  while (nanosleep (&ts, &ts) != 0);
+
+  pthread_mutex_lock (&lock);
+  exiting = true;
+  pthread_mutex_unlock (&lock);
+
+  for (i = 0; i < count; ++i)
+    pthread_join (th[i], NULL);
+
+  fclose (f);
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#define TIMEOUT 40
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-cond17.c b/test/nptl/tst-cond17.c
new file mode 100644 (file)
index 0000000..0586fa5
--- /dev/null
@@ -0,0 +1,2 @@
+#define UNLOCK_AFTER_BROADCAST 1
+#include "tst-cond16.c"
diff --git a/test/nptl/tst-cond18.c b/test/nptl/tst-cond18.c
new file mode 100644 (file)
index 0000000..9fd81d2
--- /dev/null
@@ -0,0 +1,117 @@
+/* Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2004.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with 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 <pthread.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+pthread_cond_t cv = PTHREAD_COND_INITIALIZER;
+pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+bool exiting;
+int fd, count, spins, nn;
+
+void *
+tf (void *id)
+{
+  pthread_mutex_lock (&lock);
+
+  if ((long) id == 0)
+    {
+      while (!exiting)
+       {
+         if ((spins++ % 1000) == 0)
+           write (fd, ".", 1);
+         pthread_mutex_unlock (&lock);
+
+         pthread_mutex_lock (&lock);
+         int njobs = rand () % (count + 1);
+         nn = njobs;
+         if ((rand () % 30) == 0)
+           pthread_cond_broadcast (&cv);
+         else
+           while (njobs--)
+             pthread_cond_signal (&cv);
+       }
+
+      pthread_cond_broadcast (&cv);
+    }
+  else
+    {
+      while (!exiting)
+       {
+         while (!nn && !exiting)
+           pthread_cond_wait (&cv, &lock);
+         --nn;
+         pthread_mutex_unlock (&lock);
+
+         pthread_mutex_lock (&lock);
+       }
+    }
+
+  pthread_mutex_unlock (&lock);
+  return NULL;
+}
+
+int
+do_test (void)
+{
+  fd = open ("/dev/null", O_WRONLY);
+  if (fd < 0)
+    {
+      printf ("couldn't open /dev/null, %m\n");
+      return 1;
+    }
+
+  count = sysconf (_SC_NPROCESSORS_ONLN);
+  if (count <= 0)
+    count = 1;
+  count *= 8;
+
+  pthread_t th[count + 1];
+  int i, ret;
+
+  for (i = 0; i <= count; ++i)
+    if ((ret = pthread_create (&th[i], NULL, tf, (void *) (long) i)) != 0)
+      {
+       errno = ret;
+       printf ("pthread_create %d failed: %m\n", i);
+       return 1;
+      }
+
+  struct timespec ts = { .tv_sec = 20, .tv_nsec = 0 };
+  while (nanosleep (&ts, &ts) != 0);
+
+  pthread_mutex_lock (&lock);
+  exiting = true;
+  pthread_mutex_unlock (&lock);
+
+  for (i = 0; i < count; ++i)
+    pthread_join (th[i], NULL);
+
+  close (fd);
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#define TIMEOUT 40
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-cond19.c b/test/nptl/tst-cond19.c
new file mode 100644 (file)
index 0000000..1c9bb7d
--- /dev/null
@@ -0,0 +1,76 @@
+/* Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2004.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with 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 <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+
+static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
+static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
+
+
+static int
+do_test (void)
+{
+  int result = 0;
+  struct timespec ts;
+
+  if (clock_gettime (CLOCK_REALTIME, &ts) != 0)
+    {
+      puts ("clock_gettime failed");
+      return 1;
+    }
+
+  ts.tv_nsec = -1;
+
+  int e = pthread_cond_timedwait (&cond, &mut, &ts);
+  if (e == 0)
+    {
+      puts ("first cond_timedwait did not fail");
+      result = 1;
+    }
+  else if (e != EINVAL)
+    {
+      puts ("first cond_timedwait did not return EINVAL");
+      result = 1;
+    }
+
+  ts.tv_nsec = 2000000000;
+
+  e = pthread_cond_timedwait (&cond, &mut, &ts);
+  if (e == 0)
+    {
+      puts ("second cond_timedwait did not fail");
+      result = 1;
+    }
+  else if (e != EINVAL)
+    {
+      puts ("second cond_timedwait did not return EINVAL");
+      result = 1;
+    }
+
+  return result;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-cond2.c b/test/nptl/tst-cond2.c
new file mode 100644 (file)
index 0000000..36f0f29
--- /dev/null
@@ -0,0 +1,163 @@
+/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <error.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
+
+static pthread_barrier_t bar;
+
+
+static void *
+tf (void *a)
+{
+  int i = (long int) a;
+  int err;
+
+  printf ("child %d: lock\n", i);
+
+  err = pthread_mutex_lock (&mut);
+  if (err != 0)
+    error (EXIT_FAILURE, err, "locking in child failed");
+
+  printf ("child %d: sync\n", i);
+
+  int e = pthread_barrier_wait (&bar);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("child: barrier_wait failed");
+      exit (1);
+    }
+
+  printf ("child %d: wait\n", i);
+
+  err = pthread_cond_wait (&cond, &mut);
+  if (err != 0)
+    error (EXIT_FAILURE, err, "child %d: failed to wait", i);
+
+  printf ("child %d: woken up\n", i);
+
+  err = pthread_mutex_unlock (&mut);
+  if (err != 0)
+    error (EXIT_FAILURE, err, "child %d: unlock[2] failed", i);
+
+  printf ("child %d: done\n", i);
+
+  return NULL;
+}
+
+
+#define N 10
+
+
+static int
+do_test (void)
+{
+  pthread_t th[N];
+  int i;
+  int err;
+
+  printf ("&cond = %p\n&mut = %p\n", &cond, &mut);
+
+  if (pthread_barrier_init (&bar, NULL, 2) != 0)
+    {
+      puts ("barrier_init failed");
+      exit (1);
+    }
+
+  pthread_attr_t at;
+
+  if (pthread_attr_init (&at) != 0)
+    {
+      puts ("attr_init failed");
+      return 1;
+    }
+
+  if (pthread_attr_setstacksize (&at, 1 * 1024 * 1024) != 0)
+    {
+      puts ("attr_setstacksize failed");
+      return 1;
+    }
+
+  for (i = 0; i < N; ++i)
+    {
+      printf ("create thread %d\n", i);
+
+      err = pthread_create (&th[i], &at, tf, (void *) (long int) i);
+      if (err != 0)
+       error (EXIT_FAILURE, err, "cannot create thread %d", i);
+
+      printf ("wait for child %d\n", i);
+
+      /* Wait for the child to start up and get the mutex for the
+        conditional variable.  */
+      int e = pthread_barrier_wait (&bar);
+      if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+       {
+         puts ("barrier_wait failed");
+         exit (1);
+       }
+    }
+
+  if (pthread_attr_destroy (&at) != 0)
+    {
+      puts ("attr_destroy failed");
+      return 1;
+    }
+
+  puts ("get lock outselves");
+
+  err = pthread_mutex_lock (&mut);
+  if (err != 0)
+    error (EXIT_FAILURE, err, "mut locking failed");
+
+  puts ("broadcast");
+
+  /* Wake up all threads.  */
+  err = pthread_cond_broadcast (&cond);
+  if (err != 0)
+    error (EXIT_FAILURE, err, "parent: broadcast failed");
+
+  err = pthread_mutex_unlock (&mut);
+  if (err != 0)
+    error (EXIT_FAILURE, err, "mut unlocking failed");
+
+  /* Join all threads.  */
+  for (i = 0; i < N; ++i)
+    {
+      printf ("join thread %d\n", i);
+
+      err = pthread_join (th[i], NULL);
+      if (err != 0)
+       error (EXIT_FAILURE, err, "join of child %d failed", i);
+    }
+
+  puts ("done");
+
+  return 0;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-cond20.c b/test/nptl/tst-cond20.c
new file mode 100644 (file)
index 0000000..18918f3
--- /dev/null
@@ -0,0 +1,170 @@
+/* Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2004.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with 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 <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define N 10
+#define ROUNDS 1000
+static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
+static pthread_cond_t cond2 = PTHREAD_COND_INITIALIZER;
+static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
+static pthread_barrier_t b;
+static int count;
+
+static void *
+tf (void *p)
+{
+  int i;
+  for (i = 0; i < ROUNDS; ++i)
+    {
+      pthread_mutex_lock (&mut);
+
+      if (++count == N)
+       pthread_cond_signal (&cond2);
+
+#ifdef TIMED
+      struct timeval tv;
+      gettimeofday (&tv, NULL);
+      struct timespec ts;
+      /* Wait three seconds.  */
+      ts.tv_sec = tv.tv_sec + 3;
+      ts.tv_nsec = tv.tv_usec * 1000;
+      pthread_cond_timedwait (&cond, &mut, &ts);
+#else
+      pthread_cond_wait (&cond, &mut);
+#endif
+
+      pthread_mutex_unlock (&mut);
+
+      int err = pthread_barrier_wait (&b);
+      if (err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD)
+       {
+         puts ("child: barrier_wait failed");
+         exit (1);
+       }
+
+      err = pthread_barrier_wait (&b);
+      if (err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD)
+       {
+         puts ("child: barrier_wait failed");
+         exit (1);
+       }
+    }
+
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  if (pthread_barrier_init (&b, NULL, N + 1) != 0)
+    {
+      puts ("barrier_init failed");
+      return 1;
+    }
+
+  pthread_mutex_lock (&mut);
+
+  int i, j, err;
+  pthread_t th[N];
+  for (i = 0; i < N; ++i)
+    if ((err = pthread_create (&th[i], NULL, tf, NULL)) != 0)
+      {
+       printf ("cannot create thread %d: %s\n", i, strerror (err));
+       return 1;
+      }
+
+  for (i = 0; i < ROUNDS; ++i)
+    {
+      pthread_cond_wait (&cond2, &mut);
+
+      if (i & 1)
+        pthread_mutex_unlock (&mut);
+
+      if (i & 2)
+       pthread_cond_broadcast (&cond);
+      else if (i & 4)
+       for (j = 0; j < N; ++j)
+         pthread_cond_signal (&cond);
+      else
+       {
+         for (j = 0; j < (i / 8) % N; ++j)
+           pthread_cond_signal (&cond);
+         pthread_cond_broadcast (&cond);
+       }
+
+      if ((i & 1) == 0)
+        pthread_mutex_unlock (&mut);
+
+      err = pthread_cond_destroy (&cond);
+      if (err)
+       {
+         printf ("pthread_cond_destroy failed: %s\n", strerror (err));
+         return 1;
+       }
+
+      /* Now clobber the cond variable which has been successfully
+         destroyed above.  */
+      memset (&cond, (char) i, sizeof (cond));
+
+      err = pthread_barrier_wait (&b);
+      if (err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD)
+       {
+         puts ("parent: barrier_wait failed");
+         return 1;
+       }
+
+      pthread_mutex_lock (&mut);
+
+      err = pthread_barrier_wait (&b);
+      if (err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD)
+       {
+         puts ("parent: barrier_wait failed");
+         return 1;
+       }
+
+      count = 0;
+      err = pthread_cond_init (&cond, NULL);
+      if (err)
+       {
+         printf ("pthread_cond_init failed: %s\n", strerror (err));
+         return 1;
+       }
+    }
+
+  for (i = 0; i < N; ++i)
+    if ((err = pthread_join (th[i], NULL)) != 0)
+      {
+       printf ("failed to join thread %d: %s\n", i, strerror (err));
+       return 1;
+      }
+
+  puts ("done");
+
+  return 0;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-cond21.c b/test/nptl/tst-cond21.c
new file mode 100644 (file)
index 0000000..89cb771
--- /dev/null
@@ -0,0 +1,3 @@
+#include <sys/time.h>
+#define TIMED 1
+#include "tst-cond20.c"
diff --git a/test/nptl/tst-cond3.c b/test/nptl/tst-cond3.c
new file mode 100644 (file)
index 0000000..cb9eb85
--- /dev/null
@@ -0,0 +1,113 @@
+/* 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 <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+
+/* Note that this test requires more than the standard.  It is
+   required that there are no spurious wakeups if only more readers
+   are added.  This is a reasonable demand.  */
+
+
+static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
+static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
+
+
+#define N 10
+
+
+static void *
+tf (void *arg)
+{
+  int i = (long int) arg;
+  int err;
+
+  /* Get the mutex.  */
+  err = pthread_mutex_lock (&mut);
+  if (err != 0)
+    {
+      printf ("child %d mutex_lock failed: %s\n", i, strerror (err));
+      exit (1);
+    }
+
+  /* This call should never return.  */
+  pthread_cond_wait (&cond, &mut);
+
+  /* We should never get here.  */
+  exit (1);
+
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  int err;
+  int i;
+
+  for (i = 0; i < N; ++i)
+    {
+      pthread_t th;
+
+      if (i != 0)
+       {
+         /* Release the mutex.  */
+         err = pthread_mutex_unlock (&mut);
+         if (err != 0)
+           {
+             printf ("mutex_unlock %d failed: %s\n", i, strerror (err));
+             return 1;
+           }
+       }
+
+      err = pthread_create (&th, NULL, tf, (void *) (long int) i);
+      if (err != 0)
+       {
+         printf ("create %d failed: %s\n", i, strerror (err));
+         return 1;
+       }
+
+      /* Get the mutex.  */
+      err = pthread_mutex_lock (&mut);
+      if (err != 0)
+       {
+         printf ("mutex_lock %d failed: %s\n", i, strerror (err));
+         return 1;
+       }
+    }
+
+  /* Set an alarm for 1 second.  The wrapper will expect this.  */
+  alarm (1);
+
+  /* This call should never return.  */
+  pthread_cond_wait (&cond, &mut);
+
+  puts ("cond_wait returned");
+  return 1;
+}
+
+
+#define EXPECTED_SIGNAL SIGALRM
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-cond4.c b/test/nptl/tst-cond4.c
new file mode 100644 (file)
index 0000000..4d88596
--- /dev/null
@@ -0,0 +1,264 @@
+/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+#include <stdint.h>
+
+
+int *condition;
+
+static int
+do_test (void)
+{
+  size_t ps = sysconf (_SC_PAGESIZE);
+  char tmpfname[] = "/tmp/tst-cond4.XXXXXX";
+  char data[ps];
+  void *mem;
+  int fd;
+  pthread_mutexattr_t ma;
+  pthread_mutex_t *mut1;
+  pthread_mutex_t *mut2;
+  pthread_condattr_t ca;
+  pthread_cond_t *cond;
+  pid_t pid;
+  int result = 0;
+  int p;
+
+  fd = mkstemp (tmpfname);
+  if (fd == -1)
+    {
+      printf ("cannot open temporary file: %m\n");
+      return 1;
+    }
+
+  /* Make sure it is always removed.  */
+  unlink (tmpfname);
+
+  /* Create one page of data.  */
+  memset (data, '\0', ps);
+
+  /* Write the data to the file.  */
+  if (write (fd, data, ps) != (ssize_t) ps)
+    {
+      puts ("short write");
+      return 1;
+    }
+
+  mem = mmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+  if (mem == MAP_FAILED)
+    {
+      printf ("mmap failed: %m\n");
+      return 1;
+    }
+
+  mut1 = (pthread_mutex_t *) (((uintptr_t) mem
+                              + __alignof (pthread_mutex_t))
+                             & ~(__alignof (pthread_mutex_t) - 1));
+  mut2 = mut1 + 1;
+
+  cond = (pthread_cond_t *) (((uintptr_t) (mut2 + 1)
+                             + __alignof (pthread_cond_t))
+                            & ~(__alignof (pthread_cond_t) - 1));
+
+  condition = (int *) (((uintptr_t) (cond + 1) + __alignof (int))
+                      & ~(__alignof (int) - 1));
+
+  if (pthread_mutexattr_init (&ma) != 0)
+    {
+      puts ("mutexattr_init failed");
+      return 1;
+    }
+
+  if (pthread_mutexattr_getpshared (&ma, &p) != 0)
+    {
+      puts ("1st mutexattr_getpshared failed");
+      return 1;
+    }
+
+  if (p != PTHREAD_PROCESS_PRIVATE)
+    {
+      puts ("default pshared value wrong");
+      return 1;
+    }
+
+  if (pthread_mutexattr_setpshared (&ma, PTHREAD_PROCESS_SHARED) != 0)
+    {
+      puts ("mutexattr_setpshared failed");
+      return 1;
+    }
+
+  if (pthread_mutexattr_getpshared (&ma, &p) != 0)
+    {
+      puts ("2nd mutexattr_getpshared failed");
+      return 1;
+    }
+
+  if (p != PTHREAD_PROCESS_SHARED)
+    {
+      puts ("pshared value after setpshared call wrong");
+      return 1;
+    }
+
+  if (pthread_mutex_init (mut1, &ma) != 0)
+    {
+      puts ("1st mutex_init failed");
+      return 1;
+    }
+
+  if (pthread_mutex_init (mut2, &ma) != 0)
+    {
+      puts ("2nd mutex_init failed");
+      return 1;
+    }
+
+  if (pthread_condattr_init (&ca) != 0)
+    {
+      puts ("condattr_init failed");
+      return 1;
+    }
+
+  if (pthread_condattr_getpshared (&ca, &p) != 0)
+    {
+      puts ("1st condattr_getpshared failed");
+      return 1;
+    }
+
+  if (p != PTHREAD_PROCESS_PRIVATE)
+    {
+      puts ("default value for pshared in condattr wrong");
+      return 1;
+    }
+
+  if (pthread_condattr_setpshared (&ca, PTHREAD_PROCESS_SHARED) != 0)
+    {
+      puts ("condattr_setpshared failed");
+      return 1;
+    }
+
+  if (pthread_condattr_getpshared (&ca, &p) != 0)
+    {
+      puts ("2nd condattr_getpshared failed");
+      return 1;
+    }
+
+  if (p != PTHREAD_PROCESS_SHARED)
+    {
+      puts ("pshared condattr still not set");
+      return 1;
+    }
+
+  if (pthread_cond_init (cond, &ca) != 0)
+    {
+      puts ("cond_init failed");
+      return 1;
+    }
+
+  if (pthread_mutex_lock (mut1) != 0)
+    {
+      puts ("parent: 1st mutex_lock failed");
+      return 1;
+    }
+
+  puts ("going to fork now");
+  pid = fork ();
+  if (pid == -1)
+    {
+      puts ("fork failed");
+      return 1;
+    }
+  else if (pid == 0)
+    {
+      if (pthread_mutex_lock (mut2) != 0)
+       {
+         puts ("child: mutex_lock failed");
+         return 1;
+       }
+
+      if (pthread_mutex_unlock (mut1) != 0)
+       {
+         puts ("child: 1st mutex_unlock failed");
+         return 1;
+       }
+
+      do
+       if (pthread_cond_wait (cond, mut2) != 0)
+         {
+           puts ("child: cond_wait failed");
+           return 1;
+         }
+      while (*condition == 0);
+
+      if (pthread_mutex_unlock (mut2) != 0)
+       {
+         puts ("child: 2nd mutex_unlock failed");
+         return 1;
+       }
+
+      puts ("child done");
+    }
+  else
+    {
+      int status;
+
+      if (pthread_mutex_lock (mut1) != 0)
+       {
+         puts ("parent: 2nd mutex_lock failed");
+         return 1;
+       }
+
+      if (pthread_mutex_lock (mut2) != 0)
+       {
+         puts ("parent: 3rd mutex_lock failed");
+         return 1;
+       }
+
+      if (pthread_cond_signal (cond) != 0)
+       {
+         puts ("parent: cond_signal failed");
+         return 1;
+       }
+
+      *condition = 1;
+
+      if (pthread_mutex_unlock (mut2) != 0)
+       {
+         puts ("parent: mutex_unlock failed");
+         return 1;
+       }
+
+      puts ("waiting for child");
+
+      waitpid (pid, &status, 0);
+      result |= status;
+
+      puts ("parent done");
+    }
+
+ return result;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-cond5.c b/test/nptl/tst-cond5.c
new file mode 100644 (file)
index 0000000..efa207b
--- /dev/null
@@ -0,0 +1,106 @@
+/* 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 <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <sys/time.h>
+
+
+static pthread_mutex_t mut;
+static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
+
+
+static int
+do_test (void)
+{
+  pthread_mutexattr_t ma;
+  int err;
+  struct timespec ts;
+  struct timeval tv;
+
+  if (pthread_mutexattr_init (&ma) != 0)
+    {
+      puts ("mutexattr_init failed");
+      exit (1);
+    }
+
+  if (pthread_mutexattr_settype (&ma, PTHREAD_MUTEX_ERRORCHECK) != 0)
+    {
+      puts ("mutexattr_settype failed");
+      exit (1);
+    }
+
+  if (pthread_mutex_init (&mut, &ma) != 0)
+    {
+      puts ("mutex_init failed");
+      exit (1);
+    }
+
+  /* Get the mutex.  */
+  if (pthread_mutex_lock (&mut) != 0)
+    {
+      puts ("mutex_lock failed");
+      exit (1);
+    }
+
+  /* Waiting for the condition will fail.  But we want the timeout here.  */
+  if (gettimeofday (&tv, NULL) != 0)
+    {
+      puts ("gettimeofday failed");
+      exit (1);
+    }
+
+  TIMEVAL_TO_TIMESPEC (&tv, &ts);
+  ts.tv_nsec += 500000000;
+  if (ts.tv_nsec >= 1000000000)
+    {
+      ts.tv_nsec -= 1000000000;
+      ++ts.tv_sec;
+    }
+  err = pthread_cond_timedwait (&cond, &mut, &ts);
+  if (err == 0)
+    {
+      /* This could in theory happen but here without any signal and
+        additional waiter it should not.  */
+      puts ("cond_timedwait succeeded");
+      exit (1);
+    }
+  else if (err != ETIMEDOUT)
+    {
+      printf ("cond_timedwait returned with %s\n", strerror (err));
+      exit (1);
+    }
+
+  err = pthread_mutex_unlock (&mut);
+  if (err != 0)
+    {
+      printf ("mutex_unlock failed: %s\n", strerror (err));
+      exit (1);
+    }
+
+  return 0;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-cond6.c b/test/nptl/tst-cond6.c
new file mode 100644 (file)
index 0000000..8c5fe20
--- /dev/null
@@ -0,0 +1,234 @@
+/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <stdint.h>
+
+
+int *condition;
+
+static int
+do_test (void)
+{
+  size_t ps = sysconf (_SC_PAGESIZE);
+  char tmpfname[] = "/tmp/tst-cond6.XXXXXX";
+  char data[ps];
+  void *mem;
+  int fd;
+  pthread_mutexattr_t ma;
+  pthread_mutex_t *mut1;
+  pthread_mutex_t *mut2;
+  pthread_condattr_t ca;
+  pthread_cond_t *cond;
+  pid_t pid;
+  int result = 0;
+
+  fd = mkstemp (tmpfname);
+  if (fd == -1)
+    {
+      printf ("cannot open temporary file: %m\n");
+      exit (1);
+    }
+
+  /* Make sure it is always removed.  */
+  unlink (tmpfname);
+
+  /* Create one page of data.  */
+  memset (data, '\0', ps);
+
+  /* Write the data to the file.  */
+  if (write (fd, data, ps) != (ssize_t) ps)
+    {
+      puts ("short write");
+      exit (1);
+    }
+
+  mem = mmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+  if (mem == MAP_FAILED)
+    {
+      printf ("mmap failed: %m\n");
+      exit (1);
+    }
+
+  mut1 = (pthread_mutex_t *) (((uintptr_t) mem
+                              + __alignof (pthread_mutex_t))
+                             & ~(__alignof (pthread_mutex_t) - 1));
+  mut2 = mut1 + 1;
+
+  cond = (pthread_cond_t *) (((uintptr_t) (mut2 + 1)
+                             + __alignof (pthread_cond_t))
+                            & ~(__alignof (pthread_cond_t) - 1));
+
+  condition = (int *) (((uintptr_t) (cond + 1) + __alignof (int))
+                      & ~(__alignof (int) - 1));
+
+  if (pthread_mutexattr_init (&ma) != 0)
+    {
+      puts ("mutexattr_init failed");
+      exit (1);
+    }
+
+  if (pthread_mutexattr_setpshared (&ma, PTHREAD_PROCESS_SHARED) != 0)
+    {
+      puts ("mutexattr_setpshared failed");
+      exit (1);
+    }
+
+  if (pthread_mutex_init (mut1, &ma) != 0)
+    {
+      puts ("1st mutex_init failed");
+      exit (1);
+    }
+
+  if (pthread_mutex_init (mut2, &ma) != 0)
+    {
+      puts ("2nd mutex_init failed");
+      exit (1);
+    }
+
+  if (pthread_condattr_init (&ca) != 0)
+    {
+      puts ("condattr_init failed");
+      exit (1);
+    }
+
+  if (pthread_condattr_setpshared (&ca, PTHREAD_PROCESS_SHARED) != 0)
+    {
+      puts ("condattr_setpshared failed");
+      exit (1);
+    }
+
+  if (pthread_cond_init (cond, &ca) != 0)
+    {
+      puts ("cond_init failed");
+      exit (1);
+    }
+
+  if (pthread_mutex_lock (mut1) != 0)
+    {
+      puts ("parent: 1st mutex_lock failed");
+      exit (1);
+    }
+
+  puts ("going to fork now");
+  pid = fork ();
+  if (pid == -1)
+    {
+      puts ("fork failed");
+      exit (1);
+    }
+  else if (pid == 0)
+    {
+      struct timespec ts;
+      struct timeval tv;
+
+      if (pthread_mutex_lock (mut2) != 0)
+       {
+         puts ("child: mutex_lock failed");
+         exit (1);
+       }
+
+      if (pthread_mutex_unlock (mut1) != 0)
+       {
+         puts ("child: 1st mutex_unlock failed");
+         exit (1);
+       }
+
+      if (gettimeofday (&tv, NULL) != 0)
+       {
+         puts ("gettimeofday failed");
+         exit (1);
+       }
+
+      TIMEVAL_TO_TIMESPEC (&tv, &ts);
+      ts.tv_nsec += 500000000;
+      if (ts.tv_nsec >= 1000000000)
+       {
+         ts.tv_nsec -= 1000000000;
+         ++ts.tv_sec;
+       }
+
+      do
+       if (pthread_cond_timedwait (cond, mut2, &ts) != 0)
+         {
+           puts ("child: cond_wait failed");
+           exit (1);
+         }
+      while (*condition == 0);
+
+      if (pthread_mutex_unlock (mut2) != 0)
+       {
+         puts ("child: 2nd mutex_unlock failed");
+         exit (1);
+       }
+
+      puts ("child done");
+    }
+  else
+    {
+      int status;
+
+      if (pthread_mutex_lock (mut1) != 0)
+       {
+         puts ("parent: 2nd mutex_lock failed");
+         exit (1);
+       }
+
+      if (pthread_mutex_lock (mut2) != 0)
+       {
+         puts ("parent: 3rd mutex_lock failed");
+         exit (1);
+       }
+
+      if (pthread_cond_signal (cond) != 0)
+       {
+         puts ("parent: cond_signal failed");
+         exit (1);
+       }
+
+      *condition = 1;
+
+      if (pthread_mutex_unlock (mut2) != 0)
+       {
+         puts ("parent: mutex_unlock failed");
+         exit (1);
+       }
+
+      puts ("waiting for child");
+
+      waitpid (pid, &status, 0);
+      result |= status;
+
+      puts ("parent done");
+    }
+
+ return result;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-cond7.c b/test/nptl/tst-cond7.c
new file mode 100644 (file)
index 0000000..5ab7b8f
--- /dev/null
@@ -0,0 +1,168 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <sys/time.h>
+
+
+typedef struct
+  {
+    pthread_cond_t cond;
+    pthread_mutex_t lock;
+    pthread_t h;
+  } T;
+
+
+static volatile bool done;
+
+
+static void *
+tf (void *arg)
+{
+  puts ("child created");
+
+  if (pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL) != 0
+      || pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, NULL) != 0)
+    {
+      puts ("cannot set cancellation options");
+      exit (1);
+    }
+
+  T *t = (T *) arg;
+
+  if (pthread_mutex_lock (&t->lock) != 0)
+    {
+      puts ("child: lock failed");
+      exit (1);
+    }
+
+  done = true;
+
+  if (pthread_cond_signal (&t->cond) != 0)
+    {
+      puts ("child: cond_signal failed");
+      exit (1);
+    }
+
+  if (pthread_cond_wait (&t->cond, &t->lock) != 0)
+    {
+      puts ("child: cond_wait failed");
+      exit (1);
+    }
+
+  if (pthread_mutex_unlock (&t->lock) != 0)
+    {
+      puts ("child: unlock failed");
+      exit (1);
+    }
+
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  int i;
+#define N 100
+  T *t[N];
+  for (i = 0; i < N; ++i)
+    {
+      printf ("round %d\n", i);
+
+      t[i] = (T *) malloc (sizeof (T));
+      if (t[i] == NULL)
+       {
+         puts ("out of memory");
+         exit (1);
+       }
+
+      if (pthread_mutex_init (&t[i]->lock, NULL) != 0
+         || pthread_cond_init (&t[i]->cond, NULL) != 0)
+       {
+         puts ("an _init function failed");
+         exit (1);
+       }
+
+      if (pthread_mutex_lock (&t[i]->lock) != 0)
+       {
+         puts ("initial mutex_lock failed");
+         exit (1);
+       }
+
+      done = false;
+
+      if (pthread_create (&t[i]->h, NULL, tf, t[i]) != 0)
+       {
+         puts ("pthread_create failed");
+         exit (1);
+       }
+
+      do
+       if (pthread_cond_wait (&t[i]->cond, &t[i]->lock) != 0)
+         {
+           puts ("cond_wait failed");
+           exit (1);
+         }
+      while (! done);
+
+      /* Release the lock since the cancel handler will get it.  */
+      if (pthread_mutex_unlock (&t[i]->lock) != 0)
+       {
+         puts ("mutex_unlock failed");
+         exit (1);
+       }
+
+      if (pthread_cancel (t[i]->h) != 0)
+       {
+         puts ("cancel failed");
+         exit (1);
+       }
+
+      puts ("parent: joining now");
+
+      void *result;
+      if (pthread_join (t[i]->h, &result) != 0)
+       {
+         puts ("join failed");
+         exit (1);
+       }
+
+      if (result != PTHREAD_CANCELED)
+       {
+         puts ("result != PTHREAD_CANCELED");
+         exit (1);
+       }
+    }
+
+  for (i = 0; i < N; ++i)
+    free (t[i]);
+
+  return 0;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-cond8.c b/test/nptl/tst-cond8.c
new file mode 100644 (file)
index 0000000..9c97a96
--- /dev/null
@@ -0,0 +1,277 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sys/time.h>
+
+
+static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
+static pthread_mutex_t mut = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
+
+static pthread_barrier_t bar;
+
+
+static void
+ch (void *arg)
+{
+  int e = pthread_mutex_lock (&mut);
+  if (e == 0)
+    {
+      puts ("mutex not locked at all by cond_wait");
+      exit (1);
+    }
+
+  if (e != EDEADLK)
+    {
+      puts ("no deadlock error signaled");
+      exit (1);
+    }
+
+  if (pthread_mutex_unlock (&mut) != 0)
+    {
+      puts ("ch: cannot unlock mutex");
+      exit (1);
+    }
+
+  puts ("ch done");
+}
+
+
+static void *
+tf1 (void *p)
+{
+  int err;
+
+  if (pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL) != 0
+      || pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, NULL) != 0)
+    {
+      puts ("cannot set cancellation options");
+      exit (1);
+    }
+
+  err = pthread_mutex_lock (&mut);
+  if (err != 0)
+    {
+      puts ("child: cannot get mutex");
+      exit (1);
+    }
+
+  err = pthread_barrier_wait (&bar);
+  if (err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("barrier_wait returned %d\n", err);
+      exit (1);
+    }
+
+  puts ("child: got mutex; waiting");
+
+  pthread_cleanup_push (ch, NULL);
+
+  pthread_cond_wait (&cond, &mut);
+
+  pthread_cleanup_pop (0);
+
+  puts ("child: cond_wait should not have returned");
+
+  return NULL;
+}
+
+
+static void *
+tf2 (void *p)
+{
+  int err;
+
+  if (pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL) != 0
+      || pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, NULL) != 0)
+    {
+      puts ("cannot set cancellation options");
+      exit (1);
+    }
+
+  err = pthread_mutex_lock (&mut);
+  if (err != 0)
+    {
+      puts ("child: cannot get mutex");
+      exit (1);
+    }
+
+  err = pthread_barrier_wait (&bar);
+  if (err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("barrier_wait returned %d\n", err);
+      exit (1);
+    }
+
+  puts ("child: got mutex; waiting");
+
+  pthread_cleanup_push (ch, NULL);
+
+  /* Current time.  */
+  struct timeval tv;
+  (void) gettimeofday (&tv, NULL);
+  /* +1000 seconds in correct format.  */
+  struct timespec ts;
+  TIMEVAL_TO_TIMESPEC (&tv, &ts);
+  ts.tv_sec += 1000;
+
+  pthread_cond_timedwait (&cond, &mut, &ts);
+
+  pthread_cleanup_pop (0);
+
+  puts ("child: cond_wait should not have returned");
+
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  pthread_t th;
+  int err;
+
+  printf ("&cond = %p\n&mut = %p\n", &cond, &mut);
+
+  puts ("parent: get mutex");
+
+  err = pthread_barrier_init (&bar, NULL, 2);
+  if (err != 0)
+    {
+      puts ("parent: cannot init barrier");
+      exit (1);
+    }
+
+  puts ("parent: create child");
+
+  err = pthread_create (&th, NULL, tf1, NULL);
+  if (err != 0)
+    {
+      puts ("parent: cannot create thread");
+      exit (1);
+    }
+
+  puts ("parent: wait for child to lock mutex");
+
+  err = pthread_barrier_wait (&bar);
+  if (err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("parent: cannot wait for barrier");
+      exit (1);
+    }
+
+  err = pthread_mutex_lock (&mut);
+  if (err != 0)
+    {
+      puts ("parent: mutex_lock failed");
+      exit (1);
+    }
+
+  err = pthread_mutex_unlock (&mut);
+  if (err != 0)
+    {
+      puts ("parent: mutex_unlock failed");
+      exit (1);
+    }
+
+  if (pthread_cancel (th) != 0)
+    {
+      puts ("cannot cancel thread");
+      exit (1);
+    }
+
+  void *r;
+  err = pthread_join (th, &r);
+  if (err != 0)
+    {
+      puts ("parent: failed to join");
+      exit (1);
+    }
+
+  if (r != PTHREAD_CANCELED)
+    {
+      puts ("child hasn't been canceled");
+      exit (1);
+    }
+
+
+
+  puts ("parent: create 2nd child");
+
+  err = pthread_create (&th, NULL, tf2, NULL);
+  if (err != 0)
+    {
+      puts ("parent: cannot create thread");
+      exit (1);
+    }
+
+  puts ("parent: wait for child to lock mutex");
+
+  err = pthread_barrier_wait (&bar);
+  if (err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("parent: cannot wait for barrier");
+      exit (1);
+    }
+
+  err = pthread_mutex_lock (&mut);
+  if (err != 0)
+    {
+      puts ("parent: mutex_lock failed");
+      exit (1);
+    }
+
+  err = pthread_mutex_unlock (&mut);
+  if (err != 0)
+    {
+      puts ("parent: mutex_unlock failed");
+      exit (1);
+    }
+
+  if (pthread_cancel (th) != 0)
+    {
+      puts ("cannot cancel thread");
+      exit (1);
+    }
+
+  err = pthread_join (th, &r);
+  if (err != 0)
+    {
+      puts ("parent: failed to join");
+      exit (1);
+    }
+
+  if (r != PTHREAD_CANCELED)
+    {
+      puts ("child hasn't been canceled");
+      exit (1);
+    }
+
+  puts ("done");
+
+  return 0;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-cond9.c b/test/nptl/tst-cond9.c
new file mode 100644 (file)
index 0000000..2a8477d
--- /dev/null
@@ -0,0 +1,150 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sys/time.h>
+
+
+static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
+static pthread_mutex_t mut = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
+
+
+static void *
+tf (void *arg)
+{
+  int err = pthread_cond_wait (&cond, &mut);
+  if (err == 0)
+    {
+      puts ("cond_wait did not fail");
+      exit (1);
+    }
+
+  if (err != EPERM)
+    {
+      printf ("cond_wait didn't return EPERM but %d\n", err);
+      exit (1);
+    }
+
+
+  /* Current time.  */
+  struct timeval tv;
+  (void) gettimeofday (&tv, NULL);
+  /* +1000 seconds in correct format.  */
+  struct timespec ts;
+  TIMEVAL_TO_TIMESPEC (&tv, &ts);
+  ts.tv_sec += 1000;
+
+  err = pthread_cond_timedwait (&cond, &mut, &ts);
+  if (err == 0)
+    {
+      puts ("cond_timedwait did not fail");
+      exit (1);
+    }
+
+  if (err != EPERM)
+    {
+      printf ("cond_timedwait didn't return EPERM but %d\n", err);
+      exit (1);
+    }
+
+  return (void *) 1l;
+}
+
+
+static int
+do_test (void)
+{
+  pthread_t th;
+  int err;
+
+  printf ("&cond = %p\n&mut = %p\n", &cond, &mut);
+
+  err = pthread_cond_wait (&cond, &mut);
+  if (err == 0)
+    {
+      puts ("cond_wait did not fail");
+      exit (1);
+    }
+
+  if (err != EPERM)
+    {
+      printf ("cond_wait didn't return EPERM but %d\n", err);
+      exit (1);
+    }
+
+
+  /* Current time.  */
+  struct timeval tv;
+  (void) gettimeofday (&tv, NULL);
+  /* +1000 seconds in correct format.  */
+  struct timespec ts;
+  TIMEVAL_TO_TIMESPEC (&tv, &ts);
+  ts.tv_sec += 1000;
+
+  err = pthread_cond_timedwait (&cond, &mut, &ts);
+  if (err == 0)
+    {
+      puts ("cond_timedwait did not fail");
+      exit (1);
+    }
+
+  if (err != EPERM)
+    {
+      printf ("cond_timedwait didn't return EPERM but %d\n", err);
+      exit (1);
+    }
+
+  if (pthread_mutex_lock (&mut) != 0)
+    {
+      puts ("parent: mutex_lock failed");
+      exit (1);
+    }
+
+  puts ("creating thread");
+
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("create failed");
+      exit (1);
+    }
+
+  void *r;
+  if (pthread_join (th, &r) != 0)
+    {
+      puts ("join failed");
+      exit (1);
+    }
+  if (r != (void *) 1l)
+    {
+      puts ("thread has wrong return value");
+      exit (1);
+    }
+
+  puts ("done");
+
+  return 0;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-cpuclock1.c b/test/nptl/tst-cpuclock1.c
new file mode 100644 (file)
index 0000000..024df63
--- /dev/null
@@ -0,0 +1,307 @@
+/* Test program for process CPU clocks.
+   Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <signal.h>
+#include <sys/wait.h>
+
+/* This function is intended to rack up both user and system time.  */
+static void
+chew_cpu (void)
+{
+  while (1)
+    {
+      static volatile char buf[4096];
+      for (int i = 0; i < 100; ++i)
+       for (size_t j = 0; j < sizeof buf; ++j)
+         buf[j] = 0xaa;
+      int nullfd = open ("/dev/null", O_WRONLY);
+      for (int i = 0; i < 100; ++i)
+       for (size_t j = 0; j < sizeof buf; ++j)
+         buf[j] = 0xbb;
+      write (nullfd, (char *) buf, sizeof buf);
+      close (nullfd);
+      if (getppid () == 1)
+       _exit (2);
+    }
+}
+
+static int
+do_test (void)
+{
+  int result = 0;
+  clockid_t cl;
+  int e;
+  pid_t dead_child, child;
+
+  /* Fork a child and let it die, to give us a PID known not be valid
+     (assuming PIDs don't wrap around during the test).  */
+  {
+    dead_child = fork ();
+    if (dead_child == 0)
+      _exit (0);
+    if (dead_child < 0)
+      {
+       perror ("fork");
+       return 1;
+      }
+    int x;
+    if (wait (&x) != dead_child)
+      {
+       perror ("wait");
+       return 2;
+      }
+  }
+
+  /* POSIX says we should get ESRCH for this.  */
+  e = clock_getcpuclockid (dead_child, &cl);
+  if (e != ENOSYS && e != ESRCH && e != EPERM)
+    {
+      printf ("clock_getcpuclockid on dead PID %d => %s\n",
+             dead_child, strerror (e));
+      result = 1;
+    }
+
+  /* Now give us a live child eating up CPU time.  */
+  child = fork ();
+  if (child == 0)
+    {
+      chew_cpu ();
+      _exit (1);
+    }
+  if (child < 0)
+    {
+      perror ("fork");
+      return 1;
+    }
+
+  e = clock_getcpuclockid (child, &cl);
+  if (e == EPERM)
+    {
+      puts ("clock_getcpuclockid does not support other processes");
+      goto done;
+    }
+  if (e != 0)
+    {
+      printf ("clock_getcpuclockid on live PID %d => %s\n",
+             child, strerror (e));
+      result = 1;
+      goto done;
+    }
+
+  const clockid_t child_clock = cl;
+  struct timespec res;
+  if (clock_getres (child_clock, &res) < 0)
+    {
+      printf ("clock_getres on live PID %d clock %lx => %s\n",
+             child, (unsigned long int) child_clock, strerror (errno));
+      result = 1;
+      goto done;
+    }
+  printf ("live PID %d clock %lx resolution %lu.%.9lu\n",
+         child, (unsigned long int) child_clock, res.tv_sec, res.tv_nsec);
+
+  struct timespec before, after;
+  if (clock_gettime (child_clock, &before) < 0)
+    {
+      printf ("clock_gettime on live PID %d clock %lx => %s\n",
+             child, (unsigned long int) child_clock, strerror (errno));
+      result = 1;
+      goto done;
+    }
+  printf ("live PID %d before sleep => %lu.%.9lu\n",
+         child, before.tv_sec, before.tv_nsec);
+
+  struct timespec sleeptime = { .tv_nsec = 500000000 };
+  nanosleep (&sleeptime, NULL);
+
+  if (clock_gettime (child_clock, &after) < 0)
+    {
+      printf ("clock_gettime on live PID %d clock %lx => %s\n",
+             child, (unsigned long int) child_clock, strerror (errno));
+      result = 1;
+      goto done;
+    }
+  printf ("live PID %d after sleep => %lu.%.9lu\n",
+         child, after.tv_sec, after.tv_nsec);
+
+  struct timespec diff = { .tv_sec = after.tv_sec - before.tv_sec,
+                          .tv_nsec = after.tv_nsec - before.tv_nsec };
+  if (diff.tv_nsec < 0)
+    {
+      --diff.tv_sec;
+      diff.tv_nsec += 1000000000;
+    }
+  if (diff.tv_sec != 0
+      || diff.tv_nsec > 600000000
+      || diff.tv_nsec < 100000000)
+    {
+      printf ("before - after %lu.%.9lu outside reasonable range\n",
+             diff.tv_sec, diff.tv_nsec);
+      result = 1;
+    }
+
+  sleeptime.tv_nsec = 100000000;
+  e = clock_nanosleep (child_clock, 0, &sleeptime, NULL);
+  if (e == EINVAL || e == ENOTSUP || e == ENOSYS)
+    {
+      printf ("clock_nanosleep not supported for other process clock: %s\n",
+             strerror (e));
+    }
+  else if (e != 0)
+    {
+      printf ("clock_nanosleep on other process clock: %s\n", strerror (e));
+      result = 1;
+    }
+  else
+    {
+      struct timespec afterns;
+      if (clock_gettime (child_clock, &afterns) < 0)
+       {
+         printf ("clock_gettime on live PID %d clock %lx => %s\n",
+                 child, (unsigned long int) child_clock, strerror (errno));
+         result = 1;
+       }
+      else
+       {
+         struct timespec d = { .tv_sec = afterns.tv_sec - after.tv_sec,
+                               .tv_nsec = afterns.tv_nsec - after.tv_nsec };
+         if (d.tv_nsec < 0)
+           {
+             --d.tv_sec;
+             d.tv_nsec += 1000000000;
+           }
+         if (d.tv_sec > 0
+             || d.tv_nsec < sleeptime.tv_nsec
+             || d.tv_nsec > sleeptime.tv_nsec * 2)
+           {
+             printf ("nanosleep time %lu.%.9lu outside reasonable range\n",
+                     d.tv_sec, d.tv_nsec);
+             result = 1;
+           }
+       }
+    }
+
+  if (kill (child, SIGKILL) != 0)
+    {
+      perror ("kill");
+      result = 2;
+      goto done;
+    }
+
+  /* Wait long enough to let the child finish dying.  */
+
+  sleeptime.tv_nsec = 200000000;
+  nanosleep (&sleeptime, NULL);
+
+  struct timespec dead;
+  if (clock_gettime (child_clock, &dead) < 0)
+    {
+      printf ("clock_gettime on dead PID %d clock %lx => %s\n",
+             child, (unsigned long int) child_clock, strerror (errno));
+      result = 1;
+      goto done;
+    }
+  printf ("dead PID %d => %lu.%.9lu\n",
+         child, dead.tv_sec, dead.tv_nsec);
+
+  diff.tv_sec = dead.tv_sec - after.tv_sec;
+  diff.tv_nsec = dead.tv_nsec - after.tv_nsec;
+  if (diff.tv_nsec < 0)
+    {
+      --diff.tv_sec;
+      diff.tv_nsec += 1000000000;
+    }
+  if (diff.tv_sec != 0 || diff.tv_nsec > 200000000)
+    {
+      printf ("dead - after %lu.%.9lu outside reasonable range\n",
+             diff.tv_sec, diff.tv_nsec);
+      result = 1;
+    }
+
+  /* Now reap the child and verify that its clock is no longer valid.  */
+  {
+    int x;
+    if (waitpid (child, &x, 0) != child)
+      {
+       perror ("waitpid");
+       result = 1;
+      }
+  }
+
+  if (clock_gettime (child_clock, &dead) == 0)
+    {
+      printf ("clock_gettime on reaped PID %d clock %lx => %lu%.9lu\n",
+             child, (unsigned long int) child_clock,
+             dead.tv_sec, dead.tv_nsec);
+      result = 1;
+    }
+  else
+    {
+      if (errno != EINVAL)
+       result = 1;
+      printf ("clock_gettime on reaped PID %d clock %lx => %s\n",
+             child, (unsigned long int) child_clock, strerror (errno));
+    }
+
+  if (clock_getres (child_clock, &dead) == 0)
+    {
+      printf ("clock_getres on reaped PID %d clock %lx => %lu%.9lu\n",
+             child, (unsigned long int) child_clock,
+             dead.tv_sec, dead.tv_nsec);
+      result = 1;
+    }
+  else
+    {
+      if (errno != EINVAL)
+       result = 1;
+      printf ("clock_getres on reaped PID %d clock %lx => %s\n",
+             child, (unsigned long int) child_clock, strerror (errno));
+    }
+
+  return result;
+
+ done:
+  {
+    if (kill (child, SIGKILL) != 0 && errno != ESRCH)
+      {
+       perror ("kill");
+       return 2;
+      }
+    int x;
+    if (waitpid (child, &x, 0) != child && errno != ECHILD)
+      {
+       perror ("waitpid");
+       return 2;
+      }
+  }
+
+  return result;
+}
+
+
+#define TIMEOUT 5
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-cpuclock2.c b/test/nptl/tst-cpuclock2.c
new file mode 100644 (file)
index 0000000..d1621f3
--- /dev/null
@@ -0,0 +1,332 @@
+/* Test program for process and thread CPU clocks.
+   Copyright (C) 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <unistd.h>
+
+#if (_POSIX_THREADS - 0) <= 0
+
+# define TEST_FUNCTION 0
+
+#else
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <pthread.h>
+
+static pthread_barrier_t barrier;
+
+/* This function is intended to rack up both user and system time.  */
+static void *
+chew_cpu (void *arg)
+{
+  pthread_barrier_wait (&barrier);
+
+  while (1)
+    {
+      static volatile char buf[4096];
+      for (int i = 0; i < 100; ++i)
+       for (size_t j = 0; j < sizeof buf; ++j)
+         buf[j] = 0xaa;
+      int nullfd = open ("/dev/null", O_WRONLY);
+      for (int i = 0; i < 100; ++i)
+       for (size_t j = 0; j < sizeof buf; ++j)
+         buf[j] = 0xbb;
+      write (nullfd, (char *) buf, sizeof buf);
+      close (nullfd);
+    }
+
+  return NULL;
+}
+
+static unsigned long long int
+tsdiff (const struct timespec *before, const struct timespec *after)
+{
+  struct timespec diff = { .tv_sec = after->tv_sec - before->tv_sec,
+                          .tv_nsec = after->tv_nsec - before->tv_nsec };
+  while (diff.tv_nsec < 0)
+    {
+      --diff.tv_sec;
+      diff.tv_nsec += 1000000000;
+    }
+  return diff.tv_sec * 1000000000ULL + diff.tv_nsec;
+}
+
+static unsigned long long int
+test_nanosleep (clockid_t clock, const char *which,
+               const struct timespec *before, int *bad)
+{
+  const struct timespec sleeptime = { .tv_nsec = 100000000 };
+  int e = clock_nanosleep (clock, 0, &sleeptime, NULL);
+  if (e == EINVAL || e == ENOTSUP || e == ENOSYS)
+    {
+      printf ("clock_nanosleep not supported for %s CPU clock: %s\n",
+             which, strerror (e));
+      return 0;
+    }
+  if (e != 0)
+    {
+      printf ("clock_nanosleep on %s CPU clock: %s\n", which, strerror (e));
+      *bad = 1;
+      return 0;
+    }
+
+  struct timespec after;
+  if (clock_gettime (clock, &after) < 0)
+    {
+      printf ("clock_gettime on %s CPU clock %lx => %s\n",
+             which, (unsigned long int) clock, strerror (errno));
+      *bad = 1;
+      return 0;
+    }
+
+  unsigned long long int diff = tsdiff (before, &after);
+  if (diff < sleeptime.tv_nsec || diff > sleeptime.tv_nsec * 2)
+    {
+      printf ("clock_nanosleep on %s slept %llu (outside reasonable range)\n",
+             which, diff);
+      *bad = 1;
+      return diff;
+    }
+
+  struct timespec sleeptimeabs = sleeptime;
+  sleeptimeabs.tv_sec += after.tv_sec;
+  sleeptimeabs.tv_nsec += after.tv_nsec;
+  while (sleeptimeabs.tv_nsec > 1000000000)
+    {
+      ++sleeptimeabs.tv_sec;
+      sleeptimeabs.tv_nsec -= 1000000000;
+    }
+  e = clock_nanosleep (clock, TIMER_ABSTIME, &sleeptimeabs, NULL);
+  if (e != 0)
+    {
+      printf ("absolute clock_nanosleep on %s CPU clock: %s\n",
+             which, strerror (e));
+      *bad = 1;
+      return diff;
+    }
+
+  struct timespec afterabs;
+  if (clock_gettime (clock, &afterabs) < 0)
+    {
+      printf ("clock_gettime on %s CPU clock %lx => %s\n",
+             which, (unsigned long int) clock, strerror (errno));
+      *bad = 1;
+      return diff;
+    }
+
+  unsigned long long int sleepdiff = tsdiff (&sleeptimeabs, &afterabs);
+  if (sleepdiff > sleeptime.tv_nsec)
+    {
+      printf ("\
+absolute clock_nanosleep on %s %llu past target (outside reasonable range)\n",
+             which, sleepdiff);
+      *bad = 1;
+    }
+
+  unsigned long long int diffabs = tsdiff (&after, &afterabs);
+  if (diffabs < sleeptime.tv_nsec || diffabs > sleeptime.tv_nsec * 2)
+    {
+      printf ("\
+absolute clock_nanosleep on %s slept %llu (outside reasonable range)\n",
+             which, diffabs);
+      *bad = 1;
+    }
+
+  return diff + diffabs;
+}
+
+
+
+static int
+do_test (void)
+{
+  int result = 0;
+  clockid_t process_clock, th_clock, my_thread_clock;
+  int e;
+  pthread_t th;
+
+  e = clock_getcpuclockid (0, &process_clock);
+  if (e != 0)
+    {
+      printf ("clock_getcpuclockid on self => %s\n", strerror (e));
+      return 1;
+    }
+
+  e = pthread_getcpuclockid (pthread_self (), &my_thread_clock);
+  if (e != 0)
+    {
+      printf ("pthread_getcpuclockid on self => %s\n", strerror (e));
+      return 1;
+    }
+
+  /* This is a kludge.  This test fails if the semantics of thread and
+     process clocks are wrong.  The old code using hp-timing without kernel
+     support has bogus semantics if there are context switches.  We don't
+     fail to report failure when the proper functionality is not available
+     in the kernel.  It so happens that Linux kernels without correct CPU
+     clock support also lack CPU timer support, so we use use that to guess
+     that we are using the bogus code and not test it.  */
+  timer_t t;
+  if (timer_create (my_thread_clock, NULL, &t) != 0)
+    {
+      printf ("timer_create: %m\n");
+      puts ("No support for CPU clocks with good semantics, skipping test");
+      return 0;
+    }
+  timer_delete (t);
+
+
+  pthread_barrier_init (&barrier, NULL, 2);
+
+  e = pthread_create (&th, NULL, chew_cpu, NULL);
+  if (e != 0)
+    {
+      printf ("pthread_create: %s\n", strerror (e));
+      return 1;
+    }
+
+  e = pthread_getcpuclockid (th, &th_clock);
+  if (e == ENOENT || e == ENOSYS || e == ENOTSUP)
+    {
+      puts ("pthread_getcpuclockid does not support other threads");
+      return 1;
+    }
+
+  pthread_barrier_wait (&barrier);
+
+  struct timespec res;
+  if (clock_getres (th_clock, &res) < 0)
+    {
+      printf ("clock_getres on thread clock %lx => %s\n",
+             (unsigned long int) th_clock, strerror (errno));
+      result = 1;
+      return 1;
+    }
+  printf ("live thread clock %lx resolution %lu.%.9lu\n",
+         (unsigned long int) th_clock, res.tv_sec, res.tv_nsec);
+
+  struct timespec process_before, process_after;
+  if (clock_gettime (process_clock, &process_before) < 0)
+    {
+      printf ("clock_gettime on process clock %lx => %s\n",
+             (unsigned long int) th_clock, strerror (errno));
+      return 1;
+    }
+
+  struct timespec before, after;
+  if (clock_gettime (th_clock, &before) < 0)
+    {
+      printf ("clock_gettime on live thread clock %lx => %s\n",
+             (unsigned long int) th_clock, strerror (errno));
+      return 1;
+    }
+  printf ("live thread before sleep => %lu.%.9lu\n",
+         before.tv_sec, before.tv_nsec);
+
+  struct timespec me_before, me_after;
+  if (clock_gettime (my_thread_clock, &me_before) < 0)
+    {
+      printf ("clock_gettime on live thread clock %lx => %s\n",
+             (unsigned long int) th_clock, strerror (errno));
+      return 1;
+    }
+  printf ("self thread before sleep => %lu.%.9lu\n",
+         me_before.tv_sec, me_before.tv_nsec);
+
+  struct timespec sleeptime = { .tv_nsec = 500000000 };
+  nanosleep (&sleeptime, NULL);
+
+  if (clock_gettime (th_clock, &after) < 0)
+    {
+      printf ("clock_gettime on live thread clock %lx => %s\n",
+             (unsigned long int) th_clock, strerror (errno));
+      return 1;
+    }
+  printf ("live thread after sleep => %lu.%.9lu\n",
+         after.tv_sec, after.tv_nsec);
+
+  if (clock_gettime (process_clock, &process_after) < 0)
+    {
+      printf ("clock_gettime on process clock %lx => %s\n",
+             (unsigned long int) th_clock, strerror (errno));
+      return 1;
+    }
+
+  if (clock_gettime (my_thread_clock, &me_after) < 0)
+    {
+      printf ("clock_gettime on live thread clock %lx => %s\n",
+             (unsigned long int) th_clock, strerror (errno));
+      return 1;
+    }
+  printf ("self thread after sleep => %lu.%.9lu\n",
+         me_after.tv_sec, me_after.tv_nsec);
+
+  unsigned long long int th_diff = tsdiff (&before, &after);
+  unsigned long long int pdiff = tsdiff (&process_before, &process_after);
+  unsigned long long int my_diff = tsdiff (&me_before, &me_after);
+
+  if (th_diff < 100000000 || th_diff > 600000000)
+    {
+      printf ("thread before - after %llu outside reasonable range\n",
+             th_diff);
+      result = 1;
+    }
+
+  if (my_diff > 100000000)
+    {
+      printf ("self thread before - after %llu outside reasonable range\n",
+             my_diff);
+      result = 1;
+    }
+
+  if (pdiff < th_diff)
+    {
+      printf ("process before - after %llu outside reasonable range (%llu)\n",
+             pdiff, th_diff);
+      result = 1;
+    }
+
+  process_after.tv_nsec += test_nanosleep (th_clock, "thread",
+                                          &after, &result);
+  process_after.tv_nsec += test_nanosleep (process_clock, "process",
+                                          &process_after, &result);
+  test_nanosleep (CLOCK_PROCESS_CPUTIME_ID,
+                 "PROCESS_CPUTIME_ID", &process_after, &result);
+
+  pthread_cancel (th);
+
+  e = clock_nanosleep (CLOCK_THREAD_CPUTIME_ID, 0, &sleeptime, NULL);
+  if (e != EINVAL)
+    {
+      printf ("clock_nanosleep CLOCK_THREAD_CPUTIME_ID: %s\n",
+             strerror (e));
+      result = 1;
+    }
+
+  return result;
+}
+# define TIMEOUT 8
+# define TEST_FUNCTION do_test ()
+#endif
+
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-cputimer1.c b/test/nptl/tst-cputimer1.c
new file mode 100644 (file)
index 0000000..8f5dd76
--- /dev/null
@@ -0,0 +1,68 @@
+/* Tests for POSIX timer implementation using process CPU clock.  */
+
+#include <unistd.h>
+
+#if _POSIX_THREADS && defined _POSIX_CPUTIME
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <time.h>
+#include <pthread.h>
+
+#define TEST_CLOCK CLOCK_PROCESS_CPUTIME_ID
+#define TEST_CLOCK_MISSING(clock) \
+  (setup_test () ? "process CPU clock timer support" : NULL)
+
+/* This function is intended to rack up both user and system time.  */
+static void *
+chew_cpu (void *arg)
+{
+  while (1)
+    {
+      static volatile char buf[4096];
+      for (int i = 0; i < 100; ++i)
+       for (size_t j = 0; j < sizeof buf; ++j)
+         buf[j] = 0xaa;
+      int nullfd = open ("/dev/null", O_WRONLY);
+      for (int i = 0; i < 100; ++i)
+       for (size_t j = 0; j < sizeof buf; ++j)
+         buf[j] = 0xbb;
+      write (nullfd, (char *) buf, sizeof buf);
+      close (nullfd);
+    }
+
+  return NULL;
+}
+
+static int
+setup_test (void)
+{
+  /* Test timers on our own process CPU clock by having a worker thread
+     eating CPU.  First make sure we can make such timers at all.  */
+
+  timer_t t;
+  if (timer_create (TEST_CLOCK, NULL, &t) != 0)
+    {
+      printf ("timer_create: %m\n");
+      return 1;
+    }
+  timer_delete (t);
+
+  pthread_t th;
+  int e = pthread_create (&th, NULL, chew_cpu, NULL);
+  if (e != 0)
+    {
+      printf ("pthread_create: %s\n", strerror (e));
+      exit (1);
+    }
+
+  return 0;
+}
+
+#else
+# define TEST_CLOCK_MISSING(clock) "process clocks"
+#endif
+
+#include "tst-timer4.c"
diff --git a/test/nptl/tst-cputimer2.c b/test/nptl/tst-cputimer2.c
new file mode 100644 (file)
index 0000000..397d799
--- /dev/null
@@ -0,0 +1,83 @@
+/* Tests for POSIX timer implementation using thread CPU clock.  */
+
+#include <unistd.h>
+
+#if _POSIX_THREADS && defined _POSIX_CPUTIME
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <time.h>
+#include <pthread.h>
+
+static clockid_t worker_thread_clock;
+
+#define TEST_CLOCK worker_thread_clock
+#define TEST_CLOCK_MISSING(clock) \
+  (setup_test () ? "thread CPU clock timer support" : NULL)
+
+/* This function is intended to rack up both user and system time.  */
+static void *
+chew_cpu (void *arg)
+{
+  while (1)
+    {
+      static volatile char buf[4096];
+      for (int i = 0; i < 100; ++i)
+       for (size_t j = 0; j < sizeof buf; ++j)
+         buf[j] = 0xaa;
+      int nullfd = open ("/dev/null", O_WRONLY);
+      for (int i = 0; i < 100; ++i)
+       for (size_t j = 0; j < sizeof buf; ++j)
+         buf[j] = 0xbb;
+      write (nullfd, (char *) buf, sizeof buf);
+      close (nullfd);
+    }
+
+  return NULL;
+}
+
+static int
+setup_test (void)
+{
+  /* Test timers on a thread CPU clock by having a worker thread eating
+     CPU.  First make sure we can make such timers at all.  */
+
+  pthread_t th;
+  int e = pthread_create (&th, NULL, chew_cpu, NULL);
+  if (e != 0)
+    {
+      printf ("pthread_create: %s\n", strerror (e));
+      exit (1);
+    }
+
+  e = pthread_getcpuclockid (th, &worker_thread_clock);
+  if (e == EPERM || e == ENOENT || e == ENOTSUP)
+    {
+      puts ("pthread_getcpuclockid does not support other threads");
+      return 1;
+    }
+  if (e != 0)
+    {
+      printf ("pthread_getcpuclockid: %s\n", strerror (e));
+      exit (1);
+    }
+
+  timer_t t;
+  if (timer_create (TEST_CLOCK, NULL, &t) != 0)
+    {
+      printf ("timer_create: %m\n");
+      return 1;
+    }
+  timer_delete (t);
+
+  return 0;
+}
+
+#else
+# define TEST_CLOCK_MISSING(clock) "process clocks"
+#endif
+
+#include "tst-timer4.c"
diff --git a/test/nptl/tst-cputimer3.c b/test/nptl/tst-cputimer3.c
new file mode 100644 (file)
index 0000000..056766a
--- /dev/null
@@ -0,0 +1,130 @@
+/* Tests for POSIX timer implementation using another process's CPU clock.  */
+
+#include <unistd.h>
+
+#if _POSIX_THREADS && defined _POSIX_CPUTIME
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <time.h>
+#include <signal.h>
+#include <sys/wait.h>
+
+static clockid_t child_clock;
+
+#define TEST_CLOCK child_clock
+#define TEST_CLOCK_MISSING(clock) \
+  (setup_test () ? "other-process CPU clock timer support" : NULL)
+
+/* This function is intended to rack up both user and system time.  */
+static void
+chew_cpu (void)
+{
+  while (1)
+    {
+      static volatile char buf[4096];
+      for (int i = 0; i < 100; ++i)
+       for (size_t j = 0; j < sizeof buf; ++j)
+         buf[j] = 0xaa;
+      int nullfd = open ("/dev/null", O_WRONLY);
+      for (int i = 0; i < 100; ++i)
+       for (size_t j = 0; j < sizeof buf; ++j)
+         buf[j] = 0xbb;
+      write (nullfd, (char *) buf, sizeof buf);
+      close (nullfd);
+      if (getppid () == 1)
+       _exit (2);
+    }
+}
+
+static pid_t child;
+static void
+cleanup_child (void)
+{
+  if (child <= 0)
+    return;
+  if (kill (child, SIGKILL) < 0 && errno != ESRCH)
+    printf ("cannot kill child %d: %m\n", child);
+  else
+    {
+      int status;
+      errno = 0;
+      if (waitpid (child, &status, 0) != child)
+       printf ("waitpid %d: %m\n", child);
+    }
+}
+#define CLEANUP_HANDLER cleanup_child ()
+
+static int
+setup_test (void)
+{
+  /* Test timers on a process CPU clock by having a child process eating
+     CPU.  First make sure we can make such timers at all.  */
+
+  int pipefd[2];
+  if (pipe (pipefd) < 0)
+    {
+      printf ("pipe: %m\n");
+      exit (1);
+    }
+
+  child = fork ();
+
+  if (child == 0)
+    {
+      char c;
+      close (pipefd[1]);
+      if (read (pipefd[0], &c, 1) == 1)
+       chew_cpu ();
+      _exit (1);
+    }
+
+  if (child < 0)
+    {
+      printf ("fork: %m\n");
+      exit (1);
+    }
+
+  atexit (&cleanup_child);
+
+  close (pipefd[0]);
+
+  int e = clock_getcpuclockid (child, &child_clock);
+  if (e == EPERM)
+    {
+      puts ("clock_getcpuclockid does not support other processes");
+      return 1;
+    }
+  if (e != 0)
+    {
+      printf ("clock_getcpuclockid: %s\n", strerror (e));
+      exit (1);
+    }
+
+  timer_t t;
+  if (timer_create (TEST_CLOCK, NULL, &t) != 0)
+    {
+      printf ("timer_create: %m\n");
+      return 1;
+    }
+  timer_delete (t);
+
+  /* Get the child started chewing.  */
+  if (write (pipefd[1], "x", 1) != 1)
+    {
+      printf ("write to pipe: %m\n");
+      return 1;
+    }
+  close (pipefd[1]);
+
+  return 0;
+}
+
+#else
+# define TEST_CLOCK_MISSING(clock) "process clocks"
+#endif
+
+#include "tst-timer4.c"
diff --git a/test/nptl/tst-detach1.c b/test/nptl/tst-detach1.c
new file mode 100644 (file)
index 0000000..7b27f6e
--- /dev/null
@@ -0,0 +1,56 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+
+static void *
+tf (void *arg)
+{
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  pthread_t th;
+  if (pthread_create (&th, NULL, tf, (void *) pthread_self ()) != 0)
+    {
+      puts ("create failed");
+      exit (1);
+    }
+
+  /* Give the child a chance to finish.  */
+  sleep (1);
+
+  if (pthread_detach (th) != 0)
+    {
+      puts ("detach failed");
+      exit (1);
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-eintr1.c b/test/nptl/tst-eintr1.c
new file mode 100644 (file)
index 0000000..43a5df5
--- /dev/null
@@ -0,0 +1,105 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "eintr.c"
+
+
+static void *
+tf2 (void *arg)
+{
+  return arg;
+}
+
+
+static void *
+tf1 (void *arg)
+{
+  while (1)
+    {
+      pthread_t th;
+
+      int e = pthread_create (&th, NULL, tf2, NULL);
+      if (e != 0)
+       {
+         if (e == EINTR)
+           {
+             puts ("pthread_create returned EINTR");
+             exit (1);
+           }
+
+         char buf[100];
+         printf ("tf1: pthread_create failed: %s\n",
+                 strerror_r (e, buf, sizeof (buf)));
+         exit (1);
+       }
+
+      e = pthread_join (th, NULL);
+      if (e != 0)
+       {
+         if (e == EINTR)
+           {
+             puts ("pthread_join returned EINTR");
+             exit (1);
+           }
+
+         char buf[100];
+         printf ("tf1: pthread_join failed: %s\n",
+                 strerror_r (e, buf, sizeof (buf)));
+         exit (1);
+       }
+    }
+}
+
+
+static int
+do_test (void)
+{
+  setup_eintr (SIGUSR1, NULL);
+
+  int i;
+  for (i = 0; i < 10; ++i)
+    {
+      pthread_t th;
+      int e = pthread_create (&th, NULL, tf1, NULL);
+      if (e != 0)
+       {
+         char buf[100];
+         printf ("main: pthread_create failed: %s\n",
+                 strerror_r (e, buf, sizeof (buf)));
+         exit (1);
+       }
+    }
+
+  (void) tf1 (NULL);
+  /* NOTREACHED */
+
+  return 0;
+}
+
+#define EXPECTED_SIGNAL SIGALRM
+#define TIMEOUT 3
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-eintr2.c b/test/nptl/tst-eintr2.c
new file mode 100644 (file)
index 0000000..8cbbc5a
--- /dev/null
@@ -0,0 +1,118 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+
+#include "eintr.c"
+
+
+static pthread_mutex_t m1 = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t m2 = PTHREAD_MUTEX_INITIALIZER;
+
+
+static void *
+tf1 (void *arg)
+{
+  struct timespec ts;
+  struct timeval tv;
+
+  gettimeofday (&tv, NULL);
+  TIMEVAL_TO_TIMESPEC (&tv, &ts);
+  ts.tv_sec += 10000;
+
+  /* This call must never return.  */
+  int e = pthread_mutex_timedlock (&m1, &ts);
+  char buf[100];
+  printf ("tf1: mutex_timedlock returned: %s\n",
+         strerror_r (e, buf, sizeof (buf)));
+
+  exit (1);
+}
+
+
+static void *
+tf2 (void *arg)
+{
+  while (1)
+    {
+      int e = pthread_mutex_lock (&m2);
+      if (e != 0)
+       {
+         puts ("tf2: mutex_lock failed");
+         exit (1);
+       }
+      e = pthread_mutex_unlock (&m2);
+      if (e != 0)
+       {
+         puts ("tf2: mutex_unlock failed");
+         exit (1);
+       }
+      struct timespec ts = { .tv_sec = 0, .tv_nsec = 10000000 };
+      nanosleep (&ts, NULL);
+    }
+}
+
+
+static int
+do_test (void)
+{
+  if (pthread_mutex_lock (&m1) != 0)
+    {
+      puts ("mutex_lock failed");
+      exit (1);
+    }
+
+  setup_eintr (SIGUSR1, NULL);
+
+  pthread_t th;
+  char buf[100];
+  int e = pthread_create (&th, NULL, tf1, NULL);
+  if (e != 0)
+    {
+      printf ("main: 1st pthread_create failed: %s\n",
+             strerror_r (e, buf, sizeof (buf)));
+      exit (1);
+    }
+
+  e = pthread_create (&th, NULL, tf2, NULL);
+  if (e != 0)
+    {
+      printf ("main: 2nd pthread_create failed: %s\n",
+             strerror_r (e, buf, sizeof (buf)));
+      exit (1);
+    }
+
+  /* This call must never return.  */
+  e = pthread_mutex_lock (&m1);
+  printf ("main: mutex_lock returned: %s\n",
+         strerror_r (e, buf, sizeof (buf)));
+
+  return 0;
+}
+
+#define EXPECTED_SIGNAL SIGALRM
+#define TIMEOUT 3
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-eintr3.c b/test/nptl/tst-eintr3.c
new file mode 100644 (file)
index 0000000..eecab48
--- /dev/null
@@ -0,0 +1,72 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "eintr.c"
+
+
+static void *
+tf (void *arg)
+{
+  pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
+  pthread_mutex_lock (&m);
+  /* This call must not return.  */
+  pthread_mutex_lock (&m);
+
+  puts ("tf: mutex_lock returned");
+  exit (1);
+}
+
+
+static int
+do_test (void)
+{
+  pthread_t self = pthread_self ();
+
+  setup_eintr (SIGUSR1, &self);
+
+  pthread_t th;
+  char buf[100];
+  int e = pthread_create (&th, NULL, tf, NULL);
+  if (e != 0)
+    {
+      printf ("main: pthread_create failed: %s\n",
+             strerror_r (e, buf, sizeof (buf)));
+      exit (1);
+    }
+
+  /* This call must never return.  */
+  e = pthread_join (th, NULL);
+
+  if (e == EINTR)
+    puts ("pthread_join returned with EINTR");
+
+  return 0;
+}
+
+#define EXPECTED_SIGNAL SIGALRM
+#define TIMEOUT 1
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-eintr4.c b/test/nptl/tst-eintr4.c
new file mode 100644 (file)
index 0000000..dffbdd6
--- /dev/null
@@ -0,0 +1,56 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "eintr.c"
+
+
+static int
+do_test (void)
+{
+  pthread_t self = pthread_self ();
+
+  setup_eintr (SIGUSR1, &self);
+
+  pthread_barrier_t b;
+  if (pthread_barrier_init (&b, NULL, 2) != 0)
+    {
+      puts ("barrier_init failed");
+      exit (1);
+    }
+
+  /* This call must never return.  */
+  int e = pthread_barrier_wait (&b);
+
+  if (e == EINTR)
+    puts ("pthread_join returned with EINTR");
+
+  return 0;
+}
+
+#define EXPECTED_SIGNAL SIGALRM
+#define TIMEOUT 1
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-eintr5.c b/test/nptl/tst-eintr5.c
new file mode 100644 (file)
index 0000000..91473ec
--- /dev/null
@@ -0,0 +1,81 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+
+#include "eintr.c"
+
+
+static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t c = PTHREAD_COND_INITIALIZER;
+
+
+static void *
+tf (void *arg)
+{
+  struct timespec ts;
+  struct timeval tv;
+
+  gettimeofday (&tv, NULL);
+  TIMEVAL_TO_TIMESPEC (&tv, &ts);
+  ts.tv_sec += 10000;
+
+  /* This call must never return.  */
+  int e = pthread_cond_timedwait (&c, &m, &ts);
+  char buf[100];
+  printf ("tf: cond_timedwait returned: %s\n",
+         strerror_r (e, buf, sizeof (buf)));
+
+  exit (1);
+}
+
+
+static int
+do_test (void)
+{
+  setup_eintr (SIGUSR1, NULL);
+
+  pthread_t th;
+  char buf[100];
+  int e = pthread_create (&th, NULL, tf, NULL);
+  if (e != 0)
+    {
+      printf ("main: pthread_create failed: %s\n",
+             strerror_r (e, buf, sizeof (buf)));
+      exit (1);
+    }
+
+  /* This call must never return.  */
+  e = pthread_cond_wait (&c, &m);
+  printf ("main: cond_wait returned: %s\n",
+         strerror_r (e, buf, sizeof (buf)));
+
+  return 0;
+}
+
+#define EXPECTED_SIGNAL SIGALRM
+#define TIMEOUT 3
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-exec2.c b/test/nptl/tst-exec2.c
new file mode 100644 (file)
index 0000000..432da32
--- /dev/null
@@ -0,0 +1,154 @@
+/* Thread with running thread calls exec.
+   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 <paths.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+
+static void *
+tf (void *arg)
+{
+  pthread_t th = (pthread_t) arg;
+
+  if (pthread_join (th, NULL) == 0)
+    {
+      puts ("thread in parent joined!?");
+      exit (1);
+    }
+
+  puts ("join in thread in parent returned!?");
+  exit (1);
+}
+
+
+static int
+do_test (void)
+{
+  int fd[2];
+  if (pipe (fd) != 0)
+    {
+      puts ("pipe failed");
+      exit (1);
+    }
+
+  /* Not interested in knowing when the pipe is closed.  */
+  if (sigignore (SIGPIPE) != 0)
+    {
+      puts ("sigignore failed");
+      exit (1);
+    }
+
+  pid_t pid = fork ();
+  if (pid == -1)
+    {
+      puts ("fork failed");
+      exit (1);
+    }
+
+  if (pid == 0)
+    {
+      /* Use the fd for stdout.  This is kind of ugly because it
+        substitutes the fd of stdout but we know what we are doing
+        here...  */
+      if (dup2 (fd[1], STDOUT_FILENO) != STDOUT_FILENO)
+       {
+         puts ("dup2 failed");
+         exit (1);
+       }
+
+      close (fd[0]);
+
+      pthread_t th;
+      if (pthread_create (&th, NULL, tf, (void *) pthread_self ()) != 0)
+       {
+         puts ("create failed");
+         exit (1);
+       }
+
+      execl (_PATH_BSHELL, _PATH_BSHELL, "-c", "echo $$", NULL);
+
+      puts ("execl failed");
+      exit (1);
+    }
+
+  close (fd[1]);
+
+  char buf[200];
+  ssize_t n;
+  bool seen_pid = false;
+  while (TEMP_FAILURE_RETRY ((n = read (fd[0], buf, sizeof (buf)))) > 0)
+    {
+      /* We only expect to read the PID.  */
+      char *endp;
+      long int rpid = strtol (buf, &endp, 10);
+
+      if (*endp != '\n')
+       {
+         printf ("didn't parse whole line: \"%s\"\n", buf);
+         exit (1);
+       }
+      if (endp == buf)
+       {
+         puts ("read empty line");
+         exit (1);
+       }
+
+      if (rpid != pid)
+       {
+         printf ("found \"%s\", expected PID %ld\n", buf, (long int) pid);
+         exit (1);
+       }
+
+      if (seen_pid)
+       {
+         puts ("found more than one PID line");
+         exit (1);
+       }
+      seen_pid = true;
+    }
+
+  close (fd[0]);
+
+  int status;
+  int err = waitpid (pid, &status, 0);
+  if (err != pid)
+    {
+      puts ("waitpid failed");
+      exit (1);
+    }
+
+  if (!seen_pid)
+    {
+      puts ("didn't get PID");
+      exit (1);
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-exec3.c b/test/nptl/tst-exec3.c
new file mode 100644 (file)
index 0000000..be49b04
--- /dev/null
@@ -0,0 +1,152 @@
+/* Thread calls exec.
+   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 <paths.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+
+static void *
+tf (void *arg)
+{
+  execl (_PATH_BSHELL, _PATH_BSHELL, "-c", "echo $$", NULL);
+
+  puts ("execl failed");
+  exit (1);
+}
+
+
+static int
+do_test (void)
+{
+  int fd[2];
+  if (pipe (fd) != 0)
+    {
+      puts ("pipe failed");
+      exit (1);
+    }
+
+  /* Not interested in knowing when the pipe is closed.  */
+  if (sigignore (SIGPIPE) != 0)
+    {
+      puts ("sigignore failed");
+      exit (1);
+    }
+
+  pid_t pid = fork ();
+  if (pid == -1)
+    {
+      puts ("fork failed");
+      exit (1);
+    }
+
+  if (pid == 0)
+    {
+      /* Use the fd for stdout.  This is kind of ugly because it
+        substitutes the fd of stdout but we know what we are doing
+        here...  */
+      if (dup2 (fd[1], STDOUT_FILENO) != STDOUT_FILENO)
+       {
+         puts ("dup2 failed");
+         exit (1);
+       }
+
+      close (fd[0]);
+
+      pthread_t th;
+      if (pthread_create (&th, NULL, tf, NULL) != 0)
+       {
+         puts ("create failed");
+         exit (1);
+       }
+
+      if (pthread_join (th, NULL) == 0)
+       {
+         puts ("join succeeded!?");
+         exit (1);
+       }
+
+      puts ("join returned!?");
+      exit (1);
+    }
+
+  close (fd[1]);
+
+  char buf[200];
+  ssize_t n;
+  bool seen_pid = false;
+  while (TEMP_FAILURE_RETRY ((n = read (fd[0], buf, sizeof (buf)))) > 0)
+    {
+      /* We only expect to read the PID.  */
+      char *endp;
+      long int rpid = strtol (buf, &endp, 10);
+
+      if (*endp != '\n')
+       {
+         printf ("didn't parse whole line: \"%s\"\n", buf);
+         exit (1);
+       }
+      if (endp == buf)
+       {
+         puts ("read empty line");
+         exit (1);
+       }
+
+      if (rpid != pid)
+       {
+         printf ("found \"%s\", expected PID %ld\n", buf, (long int) pid);
+         exit (1);
+       }
+
+      if (seen_pid)
+       {
+         puts ("found more than one PID line");
+         exit (1);
+       }
+      seen_pid = true;
+    }
+
+  close (fd[0]);
+
+  int status;
+  int err = waitpid (pid, &status, 0);
+  if (err != pid)
+    {
+      puts ("waitpid failed");
+      exit (1);
+    }
+
+  if (!seen_pid)
+    {
+      puts ("didn't get PID");
+      exit (1);
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-exec4.c b/test/nptl/tst-exec4.c
new file mode 100644 (file)
index 0000000..b3920a0
--- /dev/null
@@ -0,0 +1,116 @@
+/* Signal handler and mask set in thread which calls exec.
+   Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+
+static void *
+tf (void *arg)
+{
+  /* Ignore SIGUSR1 and block SIGUSR2.  */
+  if (sigignore (SIGUSR1) != 0)
+    {
+      puts ("sigignore failed");
+      exit (1);
+    }
+
+  sigset_t ss;
+  sigemptyset (&ss);
+  sigaddset (&ss, SIGUSR2);
+  if (pthread_sigmask (SIG_BLOCK, &ss, NULL) != 0)
+    {
+      puts ("1st run: sigmask failed");
+      exit (1);
+    }
+
+  char **oldargv = (char **) arg;
+  size_t n = 1;
+  while (oldargv[n] != NULL)
+    ++n;
+
+  char **argv = (char **) alloca ((n + 1) * sizeof (char *));
+  for (n = 0; oldargv[n + 1] != NULL; ++n)
+    argv[n] = oldargv[n + 1];
+  argv[n++] = (char *) "--direct";
+  argv[n] = NULL;
+
+  execv (argv[0], argv);
+
+  puts ("execv failed");
+
+  exit (1);
+}
+
+
+static int
+do_test (int argc, char *argv[])
+{
+  if (argc == 1)
+    {
+      /* This is the second call.  Perform the test.  */
+      struct sigaction sa;
+
+      if (sigaction (SIGUSR1, NULL, &sa) != 0)
+       {
+         puts ("2nd run: sigaction failed");
+         return 1;
+       }
+      if (sa.sa_handler != SIG_IGN)
+       {
+         puts ("SIGUSR1 not ignored");
+         return 1;
+       }
+
+      sigset_t ss;
+      if (pthread_sigmask (SIG_SETMASK, NULL, &ss) != 0)
+       {
+         puts ("2nd run: sigmask failed");
+         return 1;
+       }
+      if (! sigismember (&ss, SIGUSR2))
+       {
+         puts ("SIGUSR2 not blocked");
+         return 1;
+       }
+
+      return 0;
+    }
+
+  pthread_t th;
+  if (pthread_create (&th, NULL, tf, argv) != 0)
+    {
+      puts ("create failed");
+      exit (1);
+    }
+
+  /* This call should never return.  */
+  pthread_join (th, NULL);
+
+  puts ("join returned");
+
+  return 1;
+}
+
+#define TEST_FUNCTION do_test (argc, argv)
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-exit1.c b/test/nptl/tst-exit1.c
new file mode 100644 (file)
index 0000000..44175f7
--- /dev/null
@@ -0,0 +1,79 @@
+/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* NOTE: this tests functionality beyond POSIX.  POSIX does not allow
+   exit to be called more than once.  */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static pthread_barrier_t b;
+
+
+static void *
+tf (void *arg)
+{
+  int r = pthread_barrier_wait (&b);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("barrier_wait failed");
+      exit (1);
+    }
+
+  exit (0);
+}
+
+
+static int
+do_test (void)
+{
+  if (pthread_barrier_init (&b, NULL, 2) != 0)
+    {
+      puts ("barrier_init failed");
+      exit (1);
+    }
+
+  pthread_t th;
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("create failed");
+      exit (1);
+    }
+
+  int r = pthread_barrier_wait (&b);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("barrier_wait failed");
+      exit (1);
+    }
+
+  /* Do nothing.  */
+  if (pthread_join (th, NULL) == 0)
+    {
+      puts ("join succeeded!?");
+      exit (1);
+    }
+
+  puts ("join returned!?");
+  exit (1);
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-exit2.c b/test/nptl/tst-exit2.c
new file mode 100644 (file)
index 0000000..3f5ff27
--- /dev/null
@@ -0,0 +1,40 @@
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+
+static void *
+tf (void *arg)
+{
+  while (1)
+    sleep (100);
+
+  /* NOTREACHED */
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  pthread_t th;
+
+  int e = pthread_create (&th, NULL, tf, NULL);
+  if (e != 0)
+    {
+      printf ("create failed: %s\n", strerror (e));
+      return 1;
+    }
+
+  /* Terminate only this thread.  */
+  pthread_exit (NULL);
+
+  /* NOTREACHED */
+  return 1;
+}
+
+#define EXPECTED_SIGNAL SIGALRM
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-exit3.c b/test/nptl/tst-exit3.c
new file mode 100644 (file)
index 0000000..da92c82
--- /dev/null
@@ -0,0 +1,81 @@
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+
+static pthread_barrier_t b;
+
+
+static void *
+tf2 (void *arg)
+{
+  while (1)
+    sleep (100);
+
+  /* NOTREACHED */
+  return NULL;
+}
+
+
+static void *
+tf (void *arg)
+{
+  pthread_t th;
+
+  int e = pthread_barrier_wait (&b);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("barrier_wait failed");
+      exit (1);
+    }
+
+  e = pthread_create (&th, NULL, tf2, NULL);
+  if (e != 0)
+    {
+      printf ("create failed: %s\n", strerror (e));
+      exit (1);
+    }
+
+  /* Terminate only this thread.  */
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  pthread_t th;
+
+  if (pthread_barrier_init (&b, NULL, 2) != 0)
+    {
+      puts ("barrier_init failed");
+      exit (1);
+    }
+
+  int e = pthread_create (&th, NULL, tf, NULL);
+  if (e != 0)
+    {
+      printf ("create failed: %s\n", strerror (e));
+      exit (1);
+    }
+
+  e = pthread_barrier_wait (&b);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("barrier_wait failed");
+      exit (1);
+    }
+
+  /* Terminate only this thread.  */
+  pthread_exit (NULL);
+
+  /* NOTREACHED */
+  return 1;
+}
+
+#define EXPECTED_SIGNAL SIGALRM
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-flock1.c b/test/nptl/tst-flock1.c
new file mode 100644 (file)
index 0000000..ed2472d
--- /dev/null
@@ -0,0 +1,93 @@
+/* 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 <stdlib.h>
+#include <unistd.h>
+#include <sys/file.h>
+
+
+static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+
+static int fd;
+
+
+static void *
+tf (void *arg)
+{
+  if (flock (fd, LOCK_SH | LOCK_NB) != 0)
+    {
+      puts ("second flock failed");
+      exit (1);
+    }
+
+  pthread_mutex_unlock (&lock);
+
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  char tmp[] = "/tmp/tst-flock1-XXXXXX";
+
+  fd = mkstemp (tmp);
+  if (fd == -1)
+    {
+      puts ("mkstemp failed");
+      exit (1);
+    }
+
+  unlink (tmp);
+
+  write (fd, "foobar xyzzy", 12);
+
+  if (flock (fd, LOCK_EX | LOCK_NB) != 0)
+    {
+      puts ("first flock failed");
+      exit (1);
+    }
+
+  pthread_mutex_lock (&lock);
+
+  pthread_t th;
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("pthread_create failed");
+      exit (1);
+    }
+
+  pthread_mutex_lock (&lock);
+
+  void *result;
+  if (pthread_join (th, &result) != 0)
+    {
+      puts ("pthread_join failed");
+      exit (1);
+    }
+
+  close (fd);
+
+  return result != NULL;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-flock2.c b/test/nptl/tst-flock2.c
new file mode 100644 (file)
index 0000000..8ef3206
--- /dev/null
@@ -0,0 +1,260 @@
+/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/file.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+
+
+static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t lock2 = PTHREAD_MUTEX_INITIALIZER;
+static int fd;
+
+
+static void *
+tf (void *arg)
+{
+  struct flock fl =
+    {
+      .l_type = F_WRLCK,
+      .l_start = 0,
+      .l_whence = SEEK_SET,
+      .l_len = 10
+    };
+  if (TEMP_FAILURE_RETRY (fcntl (fd, F_SETLKW, &fl)) != 0)
+    {
+      puts ("fourth fcntl failed");
+      exit (1);
+    }
+
+  pthread_mutex_unlock (&lock);
+
+  pthread_mutex_lock (&lock2);
+
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  char tmp[] = "/tmp/tst-flock2-XXXXXX";
+
+  fd = mkstemp (tmp);
+  if (fd == -1)
+    {
+      puts ("mkstemp failed");
+      return 1;
+    }
+
+  unlink (tmp);
+
+  int i;
+  for (i = 0; i < 20; ++i)
+    write (fd, "foobar xyzzy", 12);
+
+  pthread_barrier_t *b;
+  b = mmap (NULL, sizeof (pthread_barrier_t), PROT_READ | PROT_WRITE,
+           MAP_SHARED, fd, 0);
+  if (b == MAP_FAILED)
+    {
+      puts ("mmap failed");
+      return 1;
+    }
+
+  pthread_barrierattr_t ba;
+  if (pthread_barrierattr_init (&ba) != 0)
+    {
+      puts ("barrierattr_init failed");
+      return 1;
+    }
+
+  if (pthread_barrierattr_setpshared (&ba, PTHREAD_PROCESS_SHARED) != 0)
+    {
+      puts ("barrierattr_setpshared failed");
+      return 1;
+    }
+
+  if (pthread_barrier_init (b, &ba, 2) != 0)
+    {
+      puts ("barrier_init failed");
+      return 1;
+    }
+
+  if (pthread_barrierattr_destroy (&ba) != 0)
+    {
+      puts ("barrierattr_destroy failed");
+      return 1;
+    }
+
+  struct flock fl =
+    {
+      .l_type = F_WRLCK,
+      .l_start = 0,
+      .l_whence = SEEK_SET,
+      .l_len = 10
+    };
+  if (TEMP_FAILURE_RETRY (fcntl (fd, F_SETLKW, &fl)) != 0)
+    {
+      puts ("first fcntl failed");
+      return 1;
+    }
+
+  pid_t pid = fork ();
+  if (pid == -1)
+    {
+      puts ("fork failed");
+      return 1;
+    }
+
+  if (pid == 0)
+    {
+      /* Make sure the child does not stay around indefinitely.  */
+      alarm (10);
+
+      /* Try to get the lock.  */
+      if (TEMP_FAILURE_RETRY (fcntl (fd, F_SETLK, &fl)) == 0)
+       {
+         puts ("child:  second flock succeeded");
+         return 1;
+       }
+    }
+
+  pthread_barrier_wait (b);
+
+  if (pid != 0)
+    {
+      fl.l_type = F_UNLCK;
+      if (TEMP_FAILURE_RETRY (fcntl (fd, F_SETLKW, &fl)) != 0)
+       {
+         puts ("third fcntl failed");
+         return 1;
+       }
+    }
+
+  pthread_barrier_wait (b);
+
+  pthread_t th;
+  if (pid == 0)
+    {
+      if (pthread_mutex_lock (&lock) != 0)
+       {
+         puts ("1st locking of lock failed");
+         return 1;
+       }
+
+      if (pthread_mutex_lock (&lock2) != 0)
+       {
+         puts ("1st locking of lock2 failed");
+         return 1;
+       }
+
+      if (pthread_create (&th, NULL, tf, NULL) != 0)
+       {
+         puts ("pthread_create failed");
+         return 1;
+       }
+
+      if (pthread_mutex_lock (&lock) != 0)
+       {
+         puts ("2nd locking of lock failed");
+         return 1;
+       }
+
+      puts ("child locked file");
+    }
+
+  pthread_barrier_wait (b);
+
+  if (pid != 0)
+    {
+      fl.l_type = F_WRLCK;
+      if (TEMP_FAILURE_RETRY (fcntl (fd, F_SETLK, &fl)) == 0)
+       {
+         puts ("fifth fcntl succeeded");
+         return 1;
+       }
+
+      puts ("file locked by child");
+    }
+
+  pthread_barrier_wait (b);
+
+  if (pid == 0)
+    {
+      if (pthread_mutex_unlock (&lock2) != 0)
+       {
+         puts ("unlock of lock2 failed");
+         return 1;
+       }
+
+      if (pthread_join (th, NULL) != 0)
+       {
+         puts ("join failed");
+         return 1;
+       }
+
+      puts ("child's thread terminated");
+    }
+
+  pthread_barrier_wait (b);
+
+  if (pid != 0)
+    {
+      fl.l_type = F_WRLCK;
+      if (TEMP_FAILURE_RETRY (fcntl (fd, F_SETLK, &fl)) == 0)
+       {
+         puts ("fifth fcntl succeeded");
+         return 1;
+       }
+
+      puts ("file still locked");
+    }
+
+  pthread_barrier_wait (b);
+
+  if (pid == 0)
+    {
+      _exit (0);
+    }
+
+  int status;
+  if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid)
+    {
+      puts ("waitpid failed");
+      return 1;
+    }
+  puts ("child terminated");
+
+  if (TEMP_FAILURE_RETRY (fcntl (fd, F_SETLKW, &fl)) != 0)
+    {
+      puts ("sixth fcntl failed");
+      return 1;
+    }
+
+  return status;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-fork1.c b/test/nptl/tst-fork1.c
new file mode 100644 (file)
index 0000000..33c4ed8
--- /dev/null
@@ -0,0 +1,120 @@
+/* Copyright (C) 2002, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Roland McGrath <roland@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 <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+static void *
+thread_function (void * arg)
+{
+  int i = (intptr_t) arg;
+  int status;
+  pid_t pid;
+  pid_t pid2;
+
+  pid = fork ();
+  switch (pid)
+    {
+    case 0:
+      printf ("%ld for %d\n", (long int) getpid (), i);
+      struct timespec ts = { .tv_sec = 0, .tv_nsec = 100000000 * i };
+      nanosleep (&ts, NULL);
+      _exit (i);
+      break;
+    case -1:
+      printf ("fork: %m\n");
+      return (void *) 1l;
+      break;
+    }
+
+  pid2 = TEMP_FAILURE_RETRY (waitpid (pid, &status, 0));
+  if (pid2 != pid)
+    {
+      printf ("waitpid returned %ld, expected %ld\n",
+             (long int) pid2, (long int) pid);
+      return (void *) 1l;
+    }
+
+  printf ("%ld with %d, expected %d\n",
+         (long int) pid, WEXITSTATUS (status), i);
+
+  return WEXITSTATUS (status) == i ? NULL : (void *) 1l;
+}
+
+#define N 5
+static const int t[N] = { 7, 6, 5, 4, 3 };
+
+int
+main (void)
+{
+  pthread_t th[N];
+  int i;
+  int result = 0;
+  pthread_attr_t at;
+
+  if (pthread_attr_init (&at) != 0)
+    {
+      puts ("attr_init failed");
+      return 1;
+    }
+
+  if (pthread_attr_setstacksize (&at, 1 * 1024 * 1024) != 0)
+    {
+      puts ("attr_setstacksize failed");
+      return 1;
+    }
+
+  for (i = 0; i < N; ++i)
+    if (pthread_create (&th[i], NULL, thread_function,
+                       (void *) (intptr_t) t[i]) != 0)
+      {
+       printf ("creation of thread %d failed\n", i);
+       exit (1);
+      }
+
+  if (pthread_attr_destroy (&at) != 0)
+    {
+      puts ("attr_destroy failed");
+      return 1;
+    }
+
+  for (i = 0; i < N; ++i)
+    {
+      void *v;
+      if (pthread_join (th[i], &v) != 0)
+       {
+         printf ("join of thread %d failed\n", i);
+         result = 1;
+       }
+      else if (v != NULL)
+       {
+         printf ("join %d successful, but child failed\n", i);
+         result = 1;
+       }
+      else
+       printf ("join %d successful\n", i);
+    }
+
+  return result;
+}
diff --git a/test/nptl/tst-fork2.c b/test/nptl/tst-fork2.c
new file mode 100644 (file)
index 0000000..07d6c22
--- /dev/null
@@ -0,0 +1,90 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Roland McGrath <roland@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 <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+
+static pid_t initial_pid;
+
+
+static void *
+tf (void *arg)
+{
+  if (getppid () != initial_pid)
+    {
+      printf ("getppid in thread returned %ld, expected %ld\n",
+             (long int) getppid (), (long int) initial_pid);
+      return (void *) -1;
+    }
+
+  return NULL;
+}
+
+
+int
+main (void)
+{
+  initial_pid = getpid ();
+
+  pid_t child = fork ();
+  if (child == 0)
+    {
+      if (getppid () != initial_pid)
+       {
+         printf ("first getppid returned %ld, expected %ld\n",
+                 (long int) getppid (), (long int) initial_pid);
+         exit (1);
+       }
+
+      pthread_t th;
+      if (pthread_create (&th, NULL, tf, NULL) != 0)
+       {
+         puts ("pthread_create failed");
+         exit (1);
+       }
+
+      void *result;
+      if (pthread_join (th, &result) != 0)
+       {
+         puts ("pthread_join failed");
+         exit  (1);
+       }
+
+      exit (result == NULL ? 0 : 1);
+    }
+  else if (child == -1)
+    {
+      puts ("initial fork failed");
+      return 1;
+    }
+
+  int status;
+  if (TEMP_FAILURE_RETRY (waitpid (child, &status, 0)) != child)
+    {
+      printf ("waitpid failed: %m\n");
+      return 1;
+    }
+
+  return status;
+}
diff --git a/test/nptl/tst-fork3.c b/test/nptl/tst-fork3.c
new file mode 100644 (file)
index 0000000..bc73853
--- /dev/null
@@ -0,0 +1,107 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Roland McGrath <roland@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 <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+
+static pid_t initial_pid;
+
+
+static void *
+tf2 (void *arg)
+{
+  if (getppid () != initial_pid)
+    {
+      printf ("getppid in thread returned %ld, expected %ld\n",
+             (long int) getppid (), (long int) initial_pid);
+      return (void *) -1;
+    }
+
+  return NULL;
+}
+
+
+static void *
+tf1 (void *arg)
+{
+  pid_t child = fork ();
+  if (child == 0)
+    {
+      if (getppid () != initial_pid)
+       {
+         printf ("first getppid returned %ld, expected %ld\n",
+                 (long int) getppid (), (long int) initial_pid);
+         exit (1);
+       }
+
+      pthread_t th2;
+      if (pthread_create (&th2, NULL, tf2, NULL) != 0)
+       {
+         puts ("child: pthread_create failed");
+         exit (1);
+       }
+
+      void *result;
+      if (pthread_join (th2, &result) != 0)
+       {
+         puts ("pthread_join failed");
+         exit  (1);
+       }
+
+      exit (result == NULL ? 0 : 1);
+    }
+  else if (child == -1)
+    {
+      puts ("initial fork failed");
+      exit (1);
+    }
+
+  int status;
+  if (TEMP_FAILURE_RETRY (waitpid (child, &status, 0)) != child)
+    {
+      printf ("waitpid failed: %m\n");
+      exit (1);
+    }
+
+  exit (status);
+}
+
+
+int
+main (void)
+{
+  initial_pid = getpid ();
+
+  pthread_t th1;
+  if (pthread_create (&th1, NULL, tf1, NULL) != 0)
+    {
+      puts ("parent: pthread_create failed");
+      exit (1);
+    }
+
+  /* This call should never return.  */
+  pthread_join (th1, NULL);
+
+  return 1;
+}
diff --git a/test/nptl/tst-fork4.c b/test/nptl/tst-fork4.c
new file mode 100644 (file)
index 0000000..cca19f4
--- /dev/null
@@ -0,0 +1,65 @@
+/* Test of fork updating child universe's pthread structures.
+   Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <string.h>
+
+
+static int
+do_test (void)
+{
+  pthread_t me = pthread_self ();
+
+  pid_t pid = fork ();
+
+  if (pid < 0)
+    {
+      printf ("fork: %m\n");
+      return 1;
+    }
+
+  if (pid == 0)
+    {
+      int err = pthread_kill (me, SIGTERM);
+      printf ("pthread_kill returned: %s\n", strerror (err));
+      return 3;
+    }
+
+  int status;
+  errno = 0;
+  if (wait (&status) != pid)
+    printf ("wait failed: %m\n");
+  else if (WIFSIGNALED (status) && WTERMSIG (status) == SIGTERM)
+    {
+      printf ("child correctly died with SIGTERM\n");
+      return 0;
+    }
+  else
+    printf ("child died with bad status %#x\n", status);
+
+  return 1;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-initializers1.c b/test/nptl/tst-initializers1.c
new file mode 100644 (file)
index 0000000..ccd2728
--- /dev/null
@@ -0,0 +1,48 @@
+/* Copyright (C) 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2005.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with 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>
+
+pthread_mutex_t mtx_normal = PTHREAD_MUTEX_INITIALIZER;
+pthread_mutex_t mtx_recursive = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
+pthread_mutex_t mtx_errorchk = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
+pthread_mutex_t mtx_adaptive = PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP;
+pthread_rwlock_t rwl_normal = PTHREAD_RWLOCK_INITIALIZER;
+pthread_rwlock_t rwl_writer
+  = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP;
+pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
+
+int
+main (void)
+{
+  if (mtx_normal.__data.__kind != PTHREAD_MUTEX_TIMED_NP)
+    return 1;
+  if (mtx_recursive.__data.__kind != PTHREAD_MUTEX_RECURSIVE_NP)
+    return 1;
+  if (mtx_errorchk.__data.__kind != PTHREAD_MUTEX_ERRORCHECK_NP)
+    return 1;
+  if (mtx_adaptive.__data.__kind != PTHREAD_MUTEX_ADAPTIVE_NP)
+    return 1;
+  if (rwl_normal.__data.__flags != PTHREAD_RWLOCK_PREFER_READER_NP)
+    return 1;
+  if (rwl_writer.__data.__flags
+      != PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP)
+    return 1;
+  return 0;
+}
diff --git a/test/nptl/tst-join1.c b/test/nptl/tst-join1.c
new file mode 100644 (file)
index 0000000..95a78ba
--- /dev/null
@@ -0,0 +1,83 @@
+/* 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 <stdlib.h>
+
+
+static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+
+
+static void *
+tf (void *arg)
+{
+  pthread_t mh = (pthread_t) arg;
+  void *result;
+
+  if (pthread_mutex_unlock (&lock) != 0)
+    {
+      puts ("unlock failed");
+      exit (1);
+    }
+
+  if (pthread_join (mh, &result) != 0)
+    {
+      puts ("join failed");
+      exit (1);
+    }
+
+  if (result != (void *) 42l)
+    {
+      printf ("result wrong: expected %p, got %p\n", (void *) 42, result);
+      exit (1);
+    }
+
+  exit (0);
+}
+
+
+static int
+do_test (void)
+{
+  pthread_t th;
+
+  if (pthread_mutex_lock (&lock) != 0)
+    {
+      puts ("1st lock failed");
+      exit (1);
+    }
+
+  if (pthread_create (&th, NULL, tf, (void *) pthread_self ()) != 0)
+    {
+      puts ("create failed");
+      exit (1);
+    }
+
+  if (pthread_mutex_lock (&lock) != 0)
+    {
+      puts ("2nd lock failed");
+      exit (1);
+    }
+
+  pthread_exit ((void *) 42);
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-join2.c b/test/nptl/tst-join2.c
new file mode 100644 (file)
index 0000000..2cfab8b
--- /dev/null
@@ -0,0 +1,104 @@
+/* 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 <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+
+static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+
+
+static void *
+tf (void *arg)
+{
+  if (pthread_mutex_lock (&lock) != 0)
+    {
+      puts ("child: mutex_lock failed");
+      return NULL;
+    }
+
+  return (void *) 42l;
+}
+
+
+static int
+do_test (void)
+{
+  pthread_t th;
+
+  if (pthread_mutex_lock (&lock) != 0)
+    {
+      puts ("mutex_lock failed");
+      exit (1);
+    }
+
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("mutex_create failed");
+      exit (1);
+    }
+
+  void *status;
+  int val = pthread_tryjoin_np (th, &status);
+  if (val == 0)
+    {
+      puts ("1st tryjoin succeeded");
+      exit (1);
+    }
+  else if (val != EBUSY)
+    {
+      puts ("1st tryjoin didn't return EBUSY");
+      exit (1);
+    }
+
+  if (pthread_mutex_unlock (&lock) != 0)
+    {
+      puts ("mutex_unlock failed");
+      exit (1);
+    }
+
+  while ((val = pthread_tryjoin_np (th, &status)) != 0)
+    {
+      if (val != EBUSY)
+       {
+         printf ("tryjoin returned %s (%d), expected only 0 or EBUSY\n",
+                 strerror (val), val);
+         exit (1);
+       }
+
+      /* Delay minimally.  */
+      struct timespec ts = { .tv_sec = 0, .tv_nsec = 10000000 };
+      nanosleep (&ts, NULL);
+    }
+
+  if (status != (void *) 42l)
+    {
+      printf ("return value %p, expected %p\n", status, (void *) 42l);
+      exit (1);
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-join3.c b/test/nptl/tst-join3.c
new file mode 100644 (file)
index 0000000..df1135f
--- /dev/null
@@ -0,0 +1,123 @@
+/* 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 <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+
+
+static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+
+
+static void *
+tf (void *arg)
+{
+  if (pthread_mutex_lock (&lock) != 0)
+    {
+      puts ("child: mutex_lock failed");
+      return NULL;
+    }
+
+  return (void *) 42l;
+}
+
+
+static int
+do_test (void)
+{
+  pthread_t th;
+
+  if (pthread_mutex_lock (&lock) != 0)
+    {
+      puts ("mutex_lock failed");
+      exit (1);
+    }
+
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("mutex_create failed");
+      exit (1);
+    }
+
+  void *status;
+  struct timespec ts;
+  struct timeval tv;
+  (void) gettimeofday (&tv, NULL);
+  TIMEVAL_TO_TIMESPEC (&tv, &ts);
+  ts.tv_nsec += 200000000;
+  if (ts.tv_nsec >= 1000000000)
+    {
+      ts.tv_nsec -= 1000000000;
+      ++ts.tv_sec;
+    }
+  int val = pthread_timedjoin_np (th, &status, &ts);
+  if (val == 0)
+    {
+      puts ("1st timedjoin succeeded");
+      exit (1);
+    }
+  else if (val != ETIMEDOUT)
+    {
+      puts ("1st timedjoin didn't return ETIMEDOUT");
+      exit (1);
+    }
+
+  if (pthread_mutex_unlock (&lock) != 0)
+    {
+      puts ("mutex_unlock failed");
+      exit (1);
+    }
+
+  while (1)
+    {
+      (void) gettimeofday (&tv, NULL);
+      TIMEVAL_TO_TIMESPEC (&tv, &ts);
+      ts.tv_nsec += 200000000;
+      if (ts.tv_nsec >= 1000000000)
+       {
+         ts.tv_nsec -= 1000000000;
+         ++ts.tv_sec;
+       }
+
+      val = pthread_timedjoin_np (th, &status, &ts);
+      if (val == 0)
+       break;
+
+      if (val != ETIMEDOUT)
+       {
+         printf ("timedjoin returned %s (%d), expected only 0 or ETIMEDOUT\n",
+                 strerror (val), val);
+         exit (1);
+       }
+    }
+
+  if (status != (void *) 42l)
+    {
+      printf ("return value %p, expected %p\n", status, (void *) 42l);
+      exit (1);
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-join4.c b/test/nptl/tst-join4.c
new file mode 100644 (file)
index 0000000..b13a510
--- /dev/null
@@ -0,0 +1,125 @@
+/* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+static pthread_barrier_t bar;
+
+
+static void *
+tf (void *arg)
+{
+  if (pthread_barrier_wait (&bar) != 0)
+    {
+      puts ("tf: barrier_wait failed");
+      exit (1);
+    }
+
+  return (void *) 1l;
+}
+
+
+static int
+do_test (void)
+{
+  if (pthread_barrier_init (&bar, NULL, 3) != 0)
+    {
+      puts ("barrier_init failed");
+      exit (1);
+    }
+
+  pthread_attr_t a;
+
+  if (pthread_attr_init (&a) != 0)
+    {
+      puts ("attr_init failed");
+      exit (1);
+    }
+
+  if (pthread_attr_setstacksize (&a, 1 * 1024 * 1024) != 0)
+    {
+      puts ("attr_setstacksize failed");
+      return 1;
+    }
+
+  pthread_t th[2];
+
+  if (pthread_create (&th[0], &a, tf, NULL) != 0)
+    {
+      puts ("1st create failed");
+      exit (1);
+    }
+
+  if (pthread_attr_setdetachstate (&a, PTHREAD_CREATE_DETACHED) != 0)
+    {
+      puts ("attr_setdetachstate failed");
+      exit (1);
+    }
+
+  if (pthread_create (&th[1], &a, tf, NULL) != 0)
+    {
+      puts ("1st create failed");
+      exit (1);
+    }
+
+  if (pthread_attr_destroy (&a) != 0)
+    {
+      puts ("attr_destroy failed");
+      exit (1);
+    }
+
+  if (pthread_detach (th[0]) != 0)
+    {
+      puts ("could not detach 1st thread");
+      exit (1);
+    }
+
+  int err = pthread_detach (th[0]);
+  if (err == 0)
+    {
+      puts ("second detach of 1st thread succeeded");
+      exit (1);
+    }
+  if (err != EINVAL)
+    {
+      printf ("second detach of 1st thread returned %d, not EINVAL\n", err);
+      exit (1);
+    }
+
+  err = pthread_detach (th[1]);
+  if (err == 0)
+    {
+      puts ("detach of 2nd thread succeeded");
+      exit (1);
+    }
+  if (err != EINVAL)
+    {
+      printf ("detach of 2nd thread returned %d, not EINVAL\n", err);
+      exit (1);
+    }
+
+  exit (0);
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-join5.c b/test/nptl/tst-join5.c
new file mode 100644 (file)
index 0000000..b08af6e
--- /dev/null
@@ -0,0 +1,143 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+static void *
+tf1 (void *arg)
+{
+  pthread_join ((pthread_t) arg, NULL);
+
+  puts ("1st join returned");
+
+  return (void *) 1l;
+}
+
+
+static void *
+tf2 (void *arg)
+{
+  int a;
+  a = pthread_join ((pthread_t) arg, NULL);
+
+  puts ("2nd join returned");
+  printf("a = %i\n", a);
+
+  return (void *) 1l;
+}
+
+
+static int
+do_test (void)
+{
+  pthread_t th;
+
+  int err = pthread_join (pthread_self (), NULL);
+  if (err == 0)
+    {
+      puts ("1st circular join succeeded");
+      exit (1);
+    }
+  if (err != EDEADLK)
+    {
+      printf ("1st circular join %d, not EDEADLK\n", err);
+      exit (1);
+    }
+
+  if (pthread_create (&th, NULL, tf1, (void *) pthread_self ()) != 0)
+    {
+      puts ("1st create failed");
+      exit (1);
+    }
+
+  if (pthread_cancel (th) != 0)
+    {
+      puts ("cannot cancel 1st thread");
+      exit (1);
+    }
+
+  void *r;
+  err = pthread_join (th, &r);
+  if (err != 0)
+    {
+      printf ("cannot join 1st thread: %d\n", err);
+      exit (1);
+    }
+  if (r != PTHREAD_CANCELED)
+    {
+      puts ("1st thread not canceled");
+      exit (1);
+    }
+
+  err = pthread_join (pthread_self (), NULL);
+  if (err == 0)
+    {
+      puts ("2nd circular join succeeded");
+      exit (1);
+    }
+  if (err != EDEADLK)
+    {
+      printf ("2nd circular join %d, not EDEADLK\n", err);
+      exit (1);
+    }
+
+  if (pthread_create (&th, NULL, tf2, (void *) pthread_self ()) != 0)
+    {
+      puts ("2nd create failed");
+      exit (1);
+    }
+
+  if (pthread_cancel (th) != 0)
+    {
+      puts ("cannot cancel 2nd thread");
+      exit (1);
+    }
+
+  if (pthread_join (th, &r) != 0)
+    {
+      puts ("cannot join 2nd thread");
+      exit (1);
+    }
+  if (r != PTHREAD_CANCELED)
+    {
+      puts ("2nd thread not canceled");
+      exit (1);
+    }
+
+  err = pthread_join (pthread_self (), NULL);
+  if (err == 0)
+    {
+      puts ("2nd circular join succeeded");
+      exit (1);
+    }
+  if (err != EDEADLK)
+    {
+      printf ("2nd circular join %d, not EDEADLK\n", err);
+      exit (1);
+    }
+
+  exit (0);
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-key1.c b/test/nptl/tst-key1.c
new file mode 100644 (file)
index 0000000..dfbe584
--- /dev/null
@@ -0,0 +1,89 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <limits.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+
+int
+do_test (void)
+{
+  int max;
+#ifdef PTHREAD_KEYS_MAX
+  max = PTHREAD_KEYS_MAX;
+#else
+  max = _POSIX_THREAD_KEYS_MAX;
+#endif
+  pthread_key_t *keys = alloca (max * sizeof (pthread_key_t));
+
+  int i;
+  for (i = 0; i < max; ++i)
+    if (pthread_key_create (&keys[i], NULL) != 0)
+      {
+       write (2, "key_create failed\n", 18);
+       _exit (1);
+      }
+    else
+      {
+       printf ("created key %d\n", i);
+
+       if (pthread_setspecific (keys[i], (const void *) (i + 100l)) != 0)
+         {
+           write (2, "setspecific failed\n", 19);
+           _exit (1);
+         }
+      }
+
+  for (i = 0; i < max; ++i)
+    {
+      if (pthread_getspecific (keys[i]) != (void *) (i + 100l))
+       {
+         write (2, "getspecific failed\n", 19);
+         _exit (1);
+       }
+
+      if (pthread_key_delete (keys[i]) != 0)
+       {
+         write (2, "key_delete failed\n", 18);
+         _exit (1);
+       }
+    }
+
+  /* Now it must be once again possible to allocate keys.  */
+  if (pthread_key_create (&keys[0], NULL) != 0)
+    {
+      write (2, "2nd key_create failed\n", 22);
+      _exit (1);
+    }
+
+  if (pthread_key_delete (keys[0]) != 0)
+    {
+      write (2, "2nd key_delete failed\n", 22);
+      _exit (1);
+    }
+
+  return 0;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-key2.c b/test/nptl/tst-key2.c
new file mode 100644 (file)
index 0000000..c549332
--- /dev/null
@@ -0,0 +1,115 @@
+/* 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 <unistd.h>
+
+#define N 2
+
+
+static int cnt0;
+static void
+f0 (void *p)
+{
+  ++cnt0;
+}
+
+
+static int cnt1;
+static void
+f1 (void *p)
+{
+  ++cnt1;
+}
+
+
+static void (*fcts[N]) (void *) =
+{
+  f0,
+  f1
+};
+
+
+static void *
+tf (void *arg)
+{
+  pthread_key_t *key = (pthread_key_t *) arg;
+
+  if (pthread_setspecific (*key, (void *) -1l) != 0)
+    {
+      write (2, "setspecific failed\n", 19);
+      _exit (1);
+    }
+
+  return NULL;
+}
+
+
+int
+do_test (void)
+{
+  pthread_key_t keys[N];
+
+  int i;
+  for (i = 0; i < N; ++i)
+    if (pthread_key_create (&keys[i], fcts[i]) != 0)
+      {
+       write (2, "key_create failed\n", 18);
+       _exit (1);
+      }
+
+  pthread_t th;
+  if (pthread_create (&th, NULL, tf, &keys[1]) != 0)
+    {
+      write (2, "create failed\n", 14);
+      _exit (1);
+    }
+
+  if (pthread_join (th, NULL) != 0)
+    {
+      write (2, "join failed\n", 12);
+      _exit (1);
+    }
+
+  if (cnt0 != 0)
+    {
+      write (2, "cnt0 != 0\n", 10);
+      _exit (1);
+    }
+
+  if (cnt1 != 1)
+    {
+      write (2, "cnt1 != 1\n", 10);
+      _exit (1);
+    }
+
+  for (i = 0; i < N; ++i)
+    if (pthread_key_delete (keys[i]) != 0)
+      {
+       write (2, "key_delete failed\n", 18);
+       _exit (1);
+      }
+
+  return 0;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-key3.c b/test/nptl/tst-key3.c
new file mode 100644 (file)
index 0000000..73cb741
--- /dev/null
@@ -0,0 +1,156 @@
+/* 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 <unistd.h>
+
+#define N 2
+
+
+static int cnt0;
+static void
+f0 (void *p)
+{
+  ++cnt0;
+}
+
+
+static int cnt1;
+static void
+f1 (void *p)
+{
+  ++cnt1;
+}
+
+
+static void (*fcts[N]) (void *) =
+{
+  f0,
+  f1
+};
+
+
+static pthread_barrier_t b;
+
+
+static void *
+tf (void *arg)
+{
+  pthread_key_t *key = (pthread_key_t *) arg;
+
+  if (pthread_setspecific (*key, (void *) -1l) != 0)
+    {
+      write (2, "setspecific failed\n", 19);
+      _exit (1);
+    }
+
+  pthread_barrier_wait (&b);
+
+  const struct timespec t = { .tv_sec = 1000, .tv_nsec = 0 };
+  while (1)
+    nanosleep (&t, NULL);
+
+  /* NOTREACHED */
+  return NULL;
+}
+
+
+int
+do_test (void)
+{
+  pthread_key_t keys[N];
+
+  int i;
+  for (i = 0; i < N; ++i)
+    if (pthread_key_create (&keys[i], fcts[i]) != 0)
+      {
+       write (2, "key_create failed\n", 18);
+       _exit (1);
+      }
+
+  if (pthread_barrier_init (&b, NULL, 2) != 0)
+    {
+      write (2, "barrier_init failed\n", 20);
+      _exit (1);
+    }
+
+  pthread_t th;
+  if (pthread_create (&th, NULL, tf, &keys[1]) != 0)
+    {
+      write (2, "create failed\n", 14);
+      _exit (1);
+    }
+
+  pthread_barrier_wait (&b);
+
+  if (pthread_cancel (th) != 0)
+    {
+      write (2, "cancel failed\n", 14);
+      _exit (1);
+    }
+
+  void *status;
+  if (pthread_join (th, &status) != 0)
+    {
+      write (2, "join failed\n", 12);
+      _exit (1);
+    }
+
+  if (status != PTHREAD_CANCELED)
+    {
+      write (2, "thread not canceled\n", 20);
+      _exit (1);
+    }
+
+  /* Note that the TSD destructors not necessarily have to have
+     finished by the time pthread_join returns.  At least according to
+     POSIX.  We implement the stronger requirement that they indeed
+     have run and therefore these tests succeed.  */
+  if (cnt0 != 0)
+    {
+      write (2, "cnt0 != 0\n", 10);
+      _exit (1);
+    }
+
+  if (cnt1 != 1)
+    {
+      write (2, "cnt1 != 1\n", 10);
+      _exit (1);
+    }
+
+  for (i = 0; i < N; ++i)
+    if (pthread_key_delete (keys[i]) != 0)
+      {
+       write (2, "key_delete failed\n", 18);
+       _exit (1);
+      }
+
+  if (pthread_barrier_destroy (&b) != 0)
+    {
+      write (2, "barrier_destroy failed\n", 23);
+      _exit (1);
+    }
+
+  return 0;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-key4.c b/test/nptl/tst-key4.c
new file mode 100644 (file)
index 0000000..0a5b448
--- /dev/null
@@ -0,0 +1,137 @@
+/* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <limits.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+
+#ifdef PTHREAD_KEYS_MAX
+const int max = PTHREAD_KEYS_MAX;
+#else
+const int max = _POSIX_THREAD_KEYS_MAX;
+#endif
+static pthread_key_t *keys;
+
+
+static void *
+tf1 (void *arg)
+{
+  int i;
+  for (i = 0; i < max; ++i)
+    if (pthread_setspecific (keys[i], (void *) (long int) (i + 1)) != 0)
+      {
+       puts ("setspecific failed");
+       exit (1);
+      }
+
+  return NULL;
+}
+
+
+static void *
+tf2 (void *arg)
+{
+  int i;
+  for (i = 0; i < max; ++i)
+    if (pthread_getspecific (keys[i]) != NULL)
+      {
+       printf ("getspecific for key %d not NULL\n", i);
+       exit (1);
+      }
+
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  keys = alloca (max * sizeof (pthread_key_t));
+
+  int i;
+  for (i = 0; i < max; ++i)
+    if (pthread_key_create (&keys[i], NULL) != 0)
+      {
+       puts ("key_create failed");
+       exit (1);
+      }
+
+  pthread_attr_t a;
+
+  if (pthread_attr_init (&a) != 0)
+    {
+      puts ("attr_init failed");
+      exit (1);
+    }
+
+  if (pthread_attr_setstacksize (&a, 1 * 1024 * 1024) != 0)
+    {
+      puts ("attr_setstacksize failed");
+      return 1;
+    }
+
+  for (i = 0; i < 10; ++i)
+    {
+      int j;
+#define N 2
+      pthread_t th[N];
+      for (j = 0; j < N; ++j)
+       if (pthread_create (&th[j], NULL, tf1, NULL) != 0)
+         {
+           puts ("1st create failed");
+           exit (1);
+         }
+
+      for (j = 0; j < N; ++j)
+       if (pthread_join (th[j], NULL) != 0)
+         {
+           puts ("1st join failed");
+           exit (1);
+         }
+
+      for (j = 0; j < N; ++j)
+       if (pthread_create (&th[j], NULL, tf2, NULL) != 0)
+         {
+           puts ("2nd create failed");
+           exit (1);
+         }
+
+      for (j = 0; j < N; ++j)
+       if (pthread_join (th[j], NULL) != 0)
+         {
+           puts ("2nd join failed");
+           exit (1);
+         }
+    }
+
+  if (pthread_attr_destroy (&a) != 0)
+    {
+      puts ("attr_destroy failed");
+      exit (1);
+    }
+
+  return 0;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-kill1.c b/test/nptl/tst-kill1.c
new file mode 100644 (file)
index 0000000..9eaf29b
--- /dev/null
@@ -0,0 +1,100 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+static pthread_cond_t c = PTHREAD_COND_INITIALIZER;
+static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
+static pthread_barrier_t b;
+
+static void *
+tf (void *a)
+{
+  if (pthread_mutex_lock (&m) != 0)
+    {
+      puts ("child: mutex_lock failed");
+      exit (1);
+    }
+
+  int e = pthread_barrier_wait (&b);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("child: barrier_wait failed");
+      exit (1);
+    }
+
+  /* This call should never return.  */
+  pthread_cond_wait (&c, &m);
+
+  return NULL;
+}
+
+
+int
+do_test (void)
+{
+  pthread_t th;
+
+  if (pthread_barrier_init (&b, NULL, 2) != 0)
+    {
+      puts ("barrier_init failed");
+      exit (1);
+    }
+
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("create failed");
+      exit (1);
+    }
+
+  int e = pthread_barrier_wait (&b);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("barrier_wait failed");
+      exit (1);
+    }
+
+  if (pthread_mutex_lock (&m) != 0)
+    {
+      puts ("mutex_lock failed");
+      exit (1);
+    }
+
+  /* Send the thread a signal which it doesn't catch and which will
+     cause the process to terminate.  */
+  if (pthread_kill (th, SIGUSR1) != 0)
+    {
+      puts ("kill failed");
+      exit (1);
+    }
+
+  /* This call should never return.  */
+  pthread_join (th, NULL);
+
+  return 0;
+}
+
+
+#define EXPECTED_SIGNAL SIGUSR1
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-kill2.c b/test/nptl/tst-kill2.c
new file mode 100644 (file)
index 0000000..1e3dc41
--- /dev/null
@@ -0,0 +1,139 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/time.h>
+
+
+static pthread_cond_t c = PTHREAD_COND_INITIALIZER;
+static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
+static pthread_barrier_t b;
+
+static void *
+tf (void *a)
+{
+  /* Block SIGUSR1.  */
+  sigset_t ss;
+
+  sigemptyset (&ss);
+  sigaddset (&ss, SIGUSR1);
+  if (pthread_sigmask (SIG_BLOCK, &ss, NULL) != 0)
+    {
+      puts ("child: sigmask failed");
+      exit (1);
+    }
+
+  if (pthread_mutex_lock (&m) != 0)
+    {
+      puts ("child: mutex_lock failed");
+      exit (1);
+    }
+
+  int e = pthread_barrier_wait (&b);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("child: barrier_wait failed");
+      exit (1);
+    }
+
+  /* Compute timeout.  */
+  struct timeval tv;
+  (void) gettimeofday (&tv, NULL);
+  struct timespec ts;
+  TIMEVAL_TO_TIMESPEC (&tv, &ts);
+  /* Timeout: 1sec.  */
+  ts.tv_sec += 1;
+
+  /* This call should never return.  */
+  if (pthread_cond_timedwait (&c, &m, &ts) != ETIMEDOUT)
+    {
+      puts ("cond_timedwait didn't time out");
+      exit (1);
+    }
+
+  return NULL;
+}
+
+
+int
+do_test (void)
+{
+  pthread_t th;
+
+  if (pthread_barrier_init (&b, NULL, 2) != 0)
+    {
+      puts ("barrier_init failed");
+      exit (1);
+    }
+
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("create failed");
+      exit (1);
+    }
+
+  int e = pthread_barrier_wait (&b);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("barrier_wait failed");
+      exit (1);
+    }
+
+  if (pthread_mutex_lock (&m) != 0)
+    {
+      puts ("mutex_lock failed");
+      exit (1);
+    }
+
+  /* Send the thread a signal which it has blocked.  */
+  if (pthread_kill (th, SIGUSR1) != 0)
+    {
+      puts ("kill failed");
+      exit (1);
+    }
+
+  if (pthread_mutex_unlock (&m) != 0)
+    {
+      puts ("mutex_unlock failed");
+      exit (1);
+    }
+
+  void *r;
+  if (pthread_join (th, &r) != 0)
+    {
+      puts ("join failed");
+      exit (1);
+    }
+  if (r != NULL)
+    {
+      puts ("return value wrong");
+      exit (1);
+    }
+
+  return 0;
+}
+
+
+#define TIMEOUT 5
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-kill3.c b/test/nptl/tst-kill3.c
new file mode 100644 (file)
index 0000000..9ea8d55
--- /dev/null
@@ -0,0 +1,159 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/time.h>
+
+
+static pthread_cond_t c = PTHREAD_COND_INITIALIZER;
+static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
+static pthread_barrier_t b;
+
+
+static void
+handler (int sig)
+{
+  write (1, "handler called\n", 15);
+  _exit (1);
+}
+
+
+static void *
+tf (void *a)
+{
+  /* Block SIGUSR1.  */
+  sigset_t ss;
+
+  sigemptyset (&ss);
+  sigaddset (&ss, SIGUSR1);
+  if (pthread_sigmask (SIG_BLOCK, &ss, NULL) != 0)
+    {
+      puts ("child: sigmask failed");
+      exit (1);
+    }
+
+  if (pthread_mutex_lock (&m) != 0)
+    {
+      puts ("child: mutex_lock failed");
+      exit (1);
+    }
+
+  int e = pthread_barrier_wait (&b);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("child: barrier_wait failed");
+      exit (1);
+    }
+
+  /* Compute timeout.  */
+  struct timeval tv;
+  (void) gettimeofday (&tv, NULL);
+  struct timespec ts;
+  TIMEVAL_TO_TIMESPEC (&tv, &ts);
+  /* Timeout: 1sec.  */
+  ts.tv_sec += 1;
+
+  /* This call should never return.  */
+  if (pthread_cond_timedwait (&c, &m, &ts) != ETIMEDOUT)
+    {
+      puts ("cond_timedwait didn't time out");
+      exit (1);
+    }
+
+  return NULL;
+}
+
+
+int
+do_test (void)
+{
+  pthread_t th;
+
+  struct sigaction sa;
+  sigemptyset (&sa.sa_mask);
+  sa.sa_flags = 0;
+  sa.sa_handler = handler;
+  if (sigaction (SIGUSR1, &sa, NULL) != 0)
+    {
+      puts ("sigaction failed");
+      exit (1);
+    }
+
+  if (pthread_barrier_init (&b, NULL, 2) != 0)
+    {
+      puts ("barrier_init failed");
+      exit (1);
+    }
+
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("create failed");
+      exit (1);
+    }
+
+  int e = pthread_barrier_wait (&b);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("barrier_wait failed");
+      exit (1);
+    }
+
+  if (pthread_mutex_lock (&m) != 0)
+    {
+      puts ("mutex_lock failed");
+      exit (1);
+    }
+
+  /* Send the thread a signal which it has blocked.  */
+  if (pthread_kill (th, SIGUSR1) != 0)
+    {
+      puts ("kill failed");
+      exit (1);
+    }
+
+  if (pthread_mutex_unlock (&m) != 0)
+    {
+      puts ("mutex_unlock failed");
+      exit (1);
+    }
+
+  void *r;
+  if (pthread_join (th, &r) != 0)
+    {
+      puts ("join failed");
+      exit (1);
+    }
+  if (r != NULL)
+    {
+      puts ("return value wrong");
+      exit (1);
+    }
+
+  return 0;
+}
+
+
+#define TIMEOUT 5
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-kill4.c b/test/nptl/tst-kill4.c
new file mode 100644 (file)
index 0000000..4e7ff5e
--- /dev/null
@@ -0,0 +1,74 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+
+static void *
+tf (void *a)
+{
+  return NULL;
+}
+
+
+int
+do_test (void)
+{
+  pthread_t th;
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("create failed");
+      exit (1);
+    }
+
+  if (pthread_join (th, NULL) != 0)
+    {
+      puts ("join failed");
+      exit (1);
+    }
+
+  /* The following only works because we assume here something about
+     the implementation.  Namely, that the memory allocated for the
+     thread descriptor is not going away, that the the TID field is
+     cleared and therefore the signal is sent to process 0, and that
+     we can savely assume there is no other process with this ID at
+     that time.  */
+  int e = pthread_kill (th, 0);
+  if (e == 0)
+    {
+      puts ("pthread_kill succeeded");
+      exit (1);
+    }
+  if (e != ESRCH)
+    {
+      puts ("pthread_kill didn't return ESRCH");
+      exit (1);
+    }
+
+  return 0;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-kill5.c b/test/nptl/tst-kill5.c
new file mode 100644 (file)
index 0000000..1256094
--- /dev/null
@@ -0,0 +1,49 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+int
+do_test (void)
+{
+  /* XXX This test might require architecture and system specific changes.
+     There is no guarantee that this signal number is invalid.  */
+  int e = pthread_kill (pthread_self (), SIGRTMAX + 10);
+  if (e == 0)
+    {
+      puts ("kill didn't failed");
+      exit (1);
+    }
+  if (e != EINVAL)
+    {
+      puts ("error not EINVAL");
+      exit (1);
+    }
+
+  return 0;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-kill6.c b/test/nptl/tst-kill6.c
new file mode 100644 (file)
index 0000000..26e82d9
--- /dev/null
@@ -0,0 +1,162 @@
+/* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+
+static pthread_t receiver;
+static sem_t sem;
+static pthread_barrier_t b;
+
+static void
+handler (int sig)
+{
+  if (sig != SIGUSR1)
+    {
+      write (STDOUT_FILENO, "wrong signal\n", 13);
+      _exit (1);
+    }
+
+  if (pthread_self () != receiver)
+    {
+      write (STDOUT_FILENO, "not the intended receiver\n", 26);
+      _exit (1);
+    }
+
+  if (sem_post (&sem) != 0)
+    {
+      write (STDOUT_FILENO, "sem_post failed\n", 16);
+      _exit (1);
+    }
+}
+
+
+static void *
+tf (void *a)
+{
+  int e = pthread_barrier_wait (&b);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("child: barrier_wait failed");
+      exit (1);
+    }
+
+  return NULL;
+}
+
+
+int
+do_test (void)
+{
+  struct sigaction sa;
+  sigemptyset (&sa.sa_mask);
+  sa.sa_flags = 0;
+  sa.sa_handler = handler;
+  if (sigaction (SIGUSR1, &sa, NULL) != 0)
+    {
+      puts ("sigaction failed");
+      exit (1);
+    }
+
+#define N 20
+
+  if (pthread_barrier_init (&b, NULL, N + 1) != 0)
+    {
+      puts ("barrier_init failed");
+      exit (1);
+    }
+
+  pthread_attr_t a;
+
+  if (pthread_attr_init (&a) != 0)
+    {
+      puts ("attr_init failed");
+      exit (1);
+    }
+
+  if (pthread_attr_setstacksize (&a, 1 * 1024 * 1024) != 0)
+    {
+      puts ("attr_setstacksize failed");
+      return 1;
+    }
+
+  pthread_t th[N];
+  int i;
+  for (i = 0; i < N; ++i)
+    if (pthread_create (&th[i], &a, tf, NULL) != 0)
+      {
+       puts ("create failed");
+       exit (1);
+      }
+
+  if (pthread_attr_destroy (&a) != 0)
+    {
+      puts ("attr_destroy failed");
+      exit (1);
+    }
+
+  if (sem_init (&sem, 0, 0) != 0)
+    {
+      puts ("sem_init failed");
+      exit (1);
+    }
+
+  for (i = 0; i < N * 10; ++i)
+    {
+      receiver = th[i % N];
+
+      if (pthread_kill (receiver, SIGUSR1) != 0)
+       {
+         puts ("kill failed");
+         exit (1);
+       }
+
+      if (TEMP_FAILURE_RETRY (sem_wait (&sem)) != 0)
+       {
+         puts ("sem_wait failed");
+         exit (1);
+       }
+    }
+
+  int e = pthread_barrier_wait (&b);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("barrier_wait failed");
+      exit (1);
+    }
+
+  for (i = 0; i < N; ++i)
+    if (pthread_join (th[i], NULL) != 0)
+      {
+       puts ("join failed");
+       exit (1);
+      }
+
+  return 0;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-mqueue.h b/test/nptl/tst-mqueue.h
new file mode 100644 (file)
index 0000000..8e73be5
--- /dev/null
@@ -0,0 +1,84 @@
+/* Common code for message queue passing tests.
+   Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2004.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <mqueue.h>
+#include <search.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/uio.h>
+#include <unistd.h>
+
+static int temp_mq_fd;
+
+/* Add temporary files in list.  */
+static void
+__attribute__ ((unused))
+add_temp_mq (const char *name)
+{
+  struct iovec iov[2];
+  iov[0].iov_base = (char *) name;
+  iov[0].iov_len = strlen (name);
+  iov[1].iov_base = (char *) "\n";
+  iov[1].iov_len = 1;
+  if (writev (temp_mq_fd, iov, 2) != iov[0].iov_len + 1)
+    printf ("Could not record temp mq filename %s\n", name);
+}
+
+/* Delete all temporary message queues.  */
+static void
+do_cleanup (void)
+{
+  if (lseek (temp_mq_fd, 0, SEEK_SET) != 0)
+    return;
+
+  FILE *f = fdopen (temp_mq_fd, "r");
+  if (f == NULL)
+    return;
+
+  char *line = NULL;
+  size_t n = 0;
+  ssize_t rets;
+  while ((rets = getline (&line, &n, f)) > 0)
+    {
+      if (line[rets - 1] != '\n')
+        continue;
+
+      line[rets - 1] = '\0';
+      mq_unlink (line);
+    }
+  fclose (f);
+}
+
+static void
+do_prepare (void)
+{
+  char name [] = "/tmp/tst-mqueueN.XXXXXX";
+  temp_mq_fd = mkstemp (name);
+  if (temp_mq_fd == -1)
+    {
+      printf ("Could not create temporary file %s: %m\n", name);
+      exit (1);
+    }
+  unlink (name);
+}
+
+#define PREPARE(argc, argv) do_prepare ()
+#define CLEANUP_HANDLER        do_cleanup ()
diff --git a/test/nptl/tst-mqueue1.c b/test/nptl/tst-mqueue1.c
new file mode 100644 (file)
index 0000000..70e4237
--- /dev/null
@@ -0,0 +1,417 @@
+/* Test message queue passing.
+   Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2004.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with 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 <mqueue.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+#include "tst-mqueue.h"
+
+static int
+intcmp (const void *a, const void *b)
+{
+  if (*(unsigned char *)a < *(unsigned char *)b)
+    return 1;
+  if (*(unsigned char *)a > *(unsigned char *)b)
+    return -1;
+  return 0;
+}
+
+static int
+check_attrs (struct mq_attr *attr, int nonblock, long cnt)
+{
+  int result = 0;
+
+  if (attr->mq_maxmsg != 10 || attr->mq_msgsize != 1)
+    {
+      printf ("attributes don't match those passed to mq_open\n"
+             "mq_maxmsg %ld, mq_msgsize %ld\n",
+             attr->mq_maxmsg, attr->mq_msgsize);
+      result = 1;
+    }
+
+  if ((attr->mq_flags & O_NONBLOCK) != nonblock)
+    {
+      printf ("mq_flags %lx != %x\n", (attr->mq_flags & O_NONBLOCK), nonblock);
+      result = 1;
+    }
+
+  if (attr->mq_curmsgs != cnt)
+    {
+      printf ("mq_curmsgs %ld != %ld\n", attr->mq_curmsgs, cnt);
+      result = 1;
+    }
+
+  return result;
+}
+
+static int
+do_one_test (mqd_t q, const char *name, int nonblock)
+{
+  int result = 0;
+
+  char v []
+    = { 0x32, 0x62, 0x22, 0x31, 0x11, 0x73, 0x61, 0x21, 0x72, 0x71, 0x81 };
+
+  struct mq_attr attr;
+  memset (&attr, 0xaa, sizeof (attr));
+  if (mq_getattr (q, &attr) != 0)
+    {
+      printf ("mq_getattr failed: %m\n");
+      result = 1;
+    }
+  else
+    result |= check_attrs (&attr, nonblock, 0);
+
+  if (mq_receive (q, &v[0], 1, NULL) != -1)
+    {
+      puts ("mq_receive on O_WRONLY mqd_t unexpectedly succeeded");
+      result = 1;
+    }
+  else if (errno != EBADF)
+    {
+      printf ("mq_receive on O_WRONLY mqd_t did not fail with EBADF: %m\n");
+      result = 1;
+    }
+
+  struct timespec ts;
+  if (clock_gettime (CLOCK_REALTIME, &ts) == 0)
+    --ts.tv_sec;
+  else
+    {
+      ts.tv_sec = time (NULL) - 1;
+      ts.tv_nsec = 0;
+    }
+
+  int ret;
+  for (int i = 0; i < 10; ++i)
+    {
+      if (i & 1)
+       ret = mq_send (q, &v[i], 1, v[i] >> 4);
+      else
+       ret = mq_timedsend (q, &v[i], 1, v[i] >> 4, &ts);
+
+      if (ret)
+       {
+         printf ("mq_%ssend failed: %m\n", (i & 1) ? "" : "timed");
+         result = 1;
+       }
+    }
+
+  ret = mq_timedsend (q, &v[10], 1, 8, &ts);
+  if (ret != -1)
+    {
+      puts ("mq_timedsend on full queue did not fail");
+      result = 1;
+    }
+  else if (errno != (nonblock ? EAGAIN : ETIMEDOUT))
+    {
+      printf ("mq_timedsend on full queue did not fail with %s: %m\n",
+             nonblock ? "EAGAIN" : "ETIMEDOUT");
+      result = 1;
+    }
+
+  if (nonblock)
+    {
+      ret = mq_send (q, &v[10], 1, 8);
+      if (ret != -1)
+       {
+         puts ("mq_send on full non-blocking queue did not fail");
+         result = 1;
+       }
+      else if (errno != EAGAIN)
+       {
+         printf ("mq_send on full non-blocking queue did not fail"
+                 "with EAGAIN: %m\n");
+         result = 1;
+       }
+    }
+
+  memset (&attr, 0xaa, sizeof (attr));
+  if (mq_getattr (q, &attr) != 0)
+    {
+      printf ("mq_getattr failed: %m\n");
+      result = 1;
+    }
+  else
+    result |= check_attrs (&attr, nonblock, 10);
+
+  pid_t pid = fork ();
+  if (pid == -1)
+    {
+      printf ("fork failed: %m\n");
+      result = 1;
+    }
+  else if (pid == 0)
+    {
+      result = 0;
+
+      if (mq_close (q) != 0)
+       {
+         printf ("mq_close in child failed: %m\n");
+         result = 1;
+       }
+
+      q = mq_open (name, O_RDONLY | nonblock);
+      if (q == (mqd_t) -1)
+        {
+         printf ("mq_open in child failed: %m\n");
+         exit (1);
+        }
+
+      memset (&attr, 0xaa, sizeof (attr));
+      if (mq_getattr (q, &attr) != 0)
+       {
+         printf ("mq_getattr failed: %m\n");
+         result = 1;
+       }
+      else
+       result |= check_attrs (&attr, nonblock, 10);
+
+      char vr[11] = { };
+      unsigned int prio;
+      ssize_t rets;
+
+      if (mq_send (q, &v[0], 1, 1) != -1)
+       {
+         puts ("mq_send on O_RDONLY mqd_t unexpectedly succeeded");
+         result = 1;
+       }
+      else if (errno != EBADF)
+       {
+         printf ("mq_send on O_WRONLY mqd_t did not fail with EBADF: %m\n");
+         result = 1;
+       }
+
+      for (int i = 0; i < 10; ++i)
+       {
+         if (i & 1)
+           rets = mq_receive (q, &vr[i], 1, &prio);
+         else
+           rets = mq_timedreceive (q, &vr[i], 1, &prio, &ts);
+
+         if (rets != 1)
+           {
+             if (rets == -1)
+               printf ("mq_%sreceive failed: %m\n", (i & 1) ? "" : "timed");
+             else
+               printf ("mq_%sreceive returned %zd != 1\n",
+                       (i & 1) ? "" : "timed", rets);
+             result = 1;
+           }
+         else if (prio != (unsigned int) vr[i] >> 4)
+           {
+             printf ("unexpected priority %x for value %02x\n", prio,
+                     vr[i]);
+             result = 1;
+           }
+       }
+
+      qsort (v, 10, 1, intcmp);
+      if (memcmp (v, vr, 10) != 0)
+       {
+         puts ("messages not received in expected order");
+         result = 1;
+       }
+
+      rets = mq_timedreceive (q, &vr[10], 1, &prio, &ts);
+      if (rets != -1)
+       {
+         puts ("mq_timedreceive on empty queue did not fail");
+         result = 1;
+       }
+      else if (errno != (nonblock ? EAGAIN : ETIMEDOUT))
+       {
+         printf ("mq_timedreceive on empty queue did not fail with %s: %m\n",
+                 nonblock ? "EAGAIN" : "ETIMEDOUT");
+         result = 1;
+       }
+
+      if (nonblock)
+       {
+         ret = mq_receive (q, &vr[10], 1, &prio);
+         if (ret != -1)
+           {
+             puts ("mq_receive on empty non-blocking queue did not fail");
+             result = 1;
+           }
+         else if (errno != EAGAIN)
+           {
+             printf ("mq_receive on empty non-blocking queue did not fail"
+                     "with EAGAIN: %m\n");
+             result = 1;
+           }
+       }
+
+      memset (&attr, 0xaa, sizeof (attr));
+      if (mq_getattr (q, &attr) != 0)
+       {
+         printf ("mq_getattr failed: %m\n");
+         result = 1;
+       }
+      else
+       result |= check_attrs (&attr, nonblock, 0);
+
+      if (mq_close (q) != 0)
+       {
+         printf ("mq_close in child failed: %m\n");
+         result = 1;
+       }
+
+      exit (result);
+    }
+
+  int status;
+  if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid)
+    {
+      printf ("waitpid failed: %m\n");
+      kill (pid, SIGKILL);
+      result = 1;
+    }
+  else if (!WIFEXITED (status) || WEXITSTATUS (status))
+    {
+      printf ("child failed: %d\n", status);
+      result = 1;
+    }
+
+  memset (&attr, 0xaa, sizeof (attr));
+  if (mq_getattr (q, &attr) != 0)
+    {
+      printf ("mq_getattr failed: %m\n");
+      result = 1;
+    }
+  else
+    result |= check_attrs (&attr, nonblock, 0);
+
+  return result;
+}
+
+#define TEST_FUNCTION do_test ()
+static int
+do_test (void)
+{
+  int result = 0;
+
+  char name[sizeof "/tst-mqueue1-" + sizeof (pid_t) * 3];
+  snprintf (name, sizeof (name), "/tst-mqueue1-%u", getpid ());
+
+  struct mq_attr attr = { .mq_maxmsg = 10, .mq_msgsize = 1 };
+  mqd_t q = mq_open (name, O_CREAT | O_EXCL | O_WRONLY, 0600, &attr);
+
+  if (q == (mqd_t) -1)
+    {
+      printf ("mq_open failed with: %m\n");
+      return result;
+    }
+  else
+    add_temp_mq (name);
+
+  result |= do_one_test (q, name, 0);
+
+  mqd_t q2 = mq_open (name, O_WRONLY | O_NONBLOCK);
+  if (q2 == (mqd_t) -1)
+    {
+      printf ("mq_open failed with: %m\n");
+      q2 = q;
+      result = 1;
+    }
+  else
+    {
+      if (mq_close (q) != 0)
+       {
+         printf ("mq_close in parent failed: %m\n");
+         result = 1;
+       }
+
+      q = q2;
+      result |= do_one_test (q, name, O_NONBLOCK);
+
+      if (mq_getattr (q, &attr) != 0)
+       {
+         printf ("mq_getattr failed: %m\n");
+         result = 1;
+       }
+      else
+       {
+         attr.mq_flags ^= O_NONBLOCK;
+
+         struct mq_attr attr2;
+         memset (&attr2, 0x55, sizeof (attr2));
+         if (mq_setattr (q, &attr, &attr2) != 0)
+           {
+             printf ("mq_setattr failed: %m\n");
+             result = 1;
+           }
+         else if (attr.mq_flags != (attr2.mq_flags ^ O_NONBLOCK)
+                  || attr.mq_maxmsg != attr2.mq_maxmsg
+                  || attr.mq_msgsize != attr2.mq_msgsize
+                  || attr.mq_curmsgs != 0
+                  || attr2.mq_curmsgs != 0)
+           {
+             puts ("mq_setattr returned unexpected values in *omqstat");
+             result = 1;
+           }
+         else
+           {
+             result |= do_one_test (q, name, 0);
+
+             if (mq_setattr (q, &attr2, NULL) != 0)
+               {
+                 printf ("mq_setattr failed: %m\n");
+                 result = 1;
+               }
+             else
+               result |= do_one_test (q, name, O_NONBLOCK);
+           }
+       }
+    }
+
+  if (mq_unlink (name) != 0)
+    {
+      printf ("mq_unlink failed: %m\n");
+      result = 1;
+    }
+
+  if (mq_close (q) != 0)
+    {
+      printf ("mq_close in parent failed: %m\n");
+      result = 1;
+    }
+
+  if (mq_close (q) != -1)
+    {
+      puts ("second mq_close did not fail");
+      result = 1;
+    }
+  else if (errno != EBADF)
+    {
+      printf ("second mq_close did not fail with EBADF: %m\n");
+      result = 1;
+    }
+
+  return result;
+}
+
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-mqueue2.c b/test/nptl/tst-mqueue2.c
new file mode 100644 (file)
index 0000000..1948965
--- /dev/null
@@ -0,0 +1,477 @@
+/* Test message queue passing.
+   Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2004.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with 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 <mqueue.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+#include "tst-mqueue.h"
+
+static void
+alrm_handler (int sig)
+{
+}
+
+#define TIMEOUT 10
+#define TEST_FUNCTION do_test ()
+static int
+do_test (void)
+{
+  int result = 0;
+
+  char name[sizeof "/tst-mqueue2-" + sizeof (pid_t) * 3];
+  snprintf (name, sizeof (name), "/tst-mqueue2-%u", getpid ());
+
+  struct mq_attr attr = { .mq_maxmsg = 2, .mq_msgsize = 2 };
+  mqd_t q = mq_open (name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr);
+
+  if (q == (mqd_t) -1)
+    {
+      printf ("mq_open failed with: %m\n");
+      return result;
+    }
+  else
+    add_temp_mq (name);
+
+  mqd_t q2 = mq_open (name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr);
+  if (q2 != (mqd_t) -1)
+    {
+      puts ("mq_open with O_EXCL unexpectedly succeeded");
+      result = 1;
+    }
+  else if (errno != EEXIST)
+    {
+      printf ("mq_open did not fail with EEXIST: %m\n");
+      result = 1;
+    }
+
+  char name2[sizeof "/tst-mqueue2-2-" + sizeof (pid_t) * 3];
+  snprintf (name2, sizeof (name2), "/tst-mqueue2-2-%u", getpid ());
+
+  attr.mq_maxmsg = -2;
+  q2 = mq_open (name2, O_CREAT | O_EXCL | O_RDWR, 0600, &attr);
+  if (q2 != (mqd_t) -1)
+    {
+      puts ("mq_open with invalid mq_maxmsg unexpectedly succeeded");
+      add_temp_mq (name2);
+      result = 1;
+    }
+  else if (errno != EINVAL)
+    {
+      printf ("mq_open with invalid mq_maxmsg did not fail with "
+             "EINVAL: %m\n");
+      result = 1;
+    }
+
+  attr.mq_maxmsg = 2;
+  attr.mq_msgsize = -56;
+  q2 = mq_open (name2, O_CREAT | O_EXCL | O_RDWR, 0600, &attr);
+  if (q2 != (mqd_t) -1)
+    {
+      puts ("mq_open with invalid mq_msgsize unexpectedly succeeded");
+      add_temp_mq (name2);
+      result = 1;
+    }
+  else if (errno != EINVAL)
+    {
+      printf ("mq_open with invalid mq_msgsize did not fail with "
+             "EINVAL: %m\n");
+      result = 1;
+    }
+
+  char buf[3];
+  struct timespec ts;
+  if (clock_gettime (CLOCK_REALTIME, &ts) == 0)
+    ts.tv_sec += 10;
+  else
+    {
+      ts.tv_sec = time (NULL) + 10;
+      ts.tv_nsec = 0;
+    }
+
+  if (mq_timedreceive (q, buf, 1, NULL, &ts) == 0)
+    {
+      puts ("mq_timedreceive with too small msg_len did not fail");
+      result = 1;
+    }
+  else if (errno != EMSGSIZE)
+    {
+      printf ("mq_timedreceive with too small msg_len did not fail with "
+             "EMSGSIZE: %m\n");
+      result = 1;
+    }
+
+  ts.tv_nsec = -1;
+  if (mq_timedreceive (q, buf, 2, NULL, &ts) == 0)
+    {
+      puts ("mq_timedreceive with negative tv_nsec did not fail");
+      result = 1;
+    }
+  else if (errno != EINVAL)
+    {
+      printf ("mq_timedreceive with negative tv_nsec did not fail with "
+             "EINVAL: %m\n");
+      result = 1;
+    }
+
+  ts.tv_nsec = 1000000000;
+  if (mq_timedreceive (q, buf, 2, NULL, &ts) == 0)
+    {
+      puts ("mq_timedreceive with tv_nsec >= 1000000000 did not fail");
+      result = 1;
+    }
+  else if (errno != EINVAL)
+    {
+      printf ("mq_timedreceive with tv_nsec >= 1000000000 did not fail with "
+             "EINVAL: %m\n");
+      result = 1;
+    }
+
+  struct sigaction sa = { .sa_handler = alrm_handler, .sa_flags = 0 };
+  sigemptyset (&sa.sa_mask);
+  sigaction (SIGALRM, &sa, NULL);
+
+  struct itimerval it = { .it_value = { .tv_sec = 1 } };
+  setitimer (ITIMER_REAL, &it, NULL);
+
+  if (mq_receive (q, buf, 2, NULL) == 0)
+    {
+      puts ("mq_receive on empty queue did not block");
+      result = 1;
+    }
+  else if (errno != EINTR)
+    {
+      printf ("mq_receive on empty queue did not fail with EINTR: %m\n");
+      result = 1;
+    }
+
+  setitimer (ITIMER_REAL, &it, NULL);
+
+  ts.tv_nsec = 0;
+  if (mq_timedreceive (q, buf, 2, NULL, &ts) == 0)
+    {
+      puts ("mq_timedreceive on empty queue did not block");
+      result = 1;
+    }
+  else if (errno != EINTR)
+    {
+      printf ("mq_timedreceive on empty queue did not fail with EINTR: %m\n");
+      result = 1;
+    }
+
+  buf[0] = '6';
+  buf[1] = '7';
+  if (mq_send (q, buf, 2, 3) != 0
+      || (buf[0] = '8', mq_send (q, buf, 1, 4) != 0))
+    {
+      printf ("mq_send failed: %m\n");
+      result = 1;
+    }
+
+  memset (buf, ' ', sizeof (buf));
+
+  unsigned int prio;
+  ssize_t rets = mq_receive (q, buf, 3, &prio);
+  if (rets != 1)
+    {
+      if (rets == -1)
+       printf ("mq_receive failed: %m\n");
+      else
+       printf ("mq_receive returned %zd != 1\n", rets);
+      result = 1;
+    }
+  else if (prio != 4 || memcmp (buf, "8  ", 3) != 0)
+    {
+      printf ("mq_receive prio %u (4) buf \"%c%c%c\" (\"8  \")\n",
+             prio, buf[0], buf[1], buf[2]);
+      result = 1;
+    }
+
+  rets = mq_receive (q, buf, 2, NULL);
+  if (rets != 2)
+    {
+      if (rets == -1)
+       printf ("mq_receive failed: %m\n");
+      else
+       printf ("mq_receive returned %zd != 2\n", rets);
+      result = 1;
+    }
+  else if (memcmp (buf, "67 ", 3) != 0)
+    {
+      printf ("mq_receive buf \"%c%c%c\" != \"67 \"\n",
+             buf[0], buf[1], buf[2]);
+      result = 1;
+    }
+
+  buf[0] = '2';
+  buf[1] = '1';
+  if (clock_gettime (CLOCK_REALTIME, &ts) != 0)
+    ts.tv_sec = time (NULL);
+  ts.tv_nsec = -1000000001;
+  if ((mq_timedsend (q, buf, 2, 5, &ts) != 0
+       && (errno != EINVAL || mq_send (q, buf, 2, 5) != 0))
+      || (buf[0] = '3', ts.tv_nsec = -ts.tv_nsec,
+         (mq_timedsend (q, buf, 1, 4, &ts) != 0
+          && (errno != EINVAL || mq_send (q, buf, 1, 4) != 0))))
+    {
+      printf ("mq_timedsend failed: %m\n");
+      result = 1;
+    }
+
+  buf[0] = '-';
+  ts.tv_nsec = 1000000001;
+  if (mq_timedsend (q, buf, 1, 6, &ts) == 0)
+    {
+      puts ("mq_timedsend with tv_nsec >= 1000000000 did not fail");
+      result = 1;
+    }
+  else if (errno != EINVAL)
+    {
+      printf ("mq_timedsend with tv_nsec >= 1000000000 did not fail with "
+             "EINVAL: %m\n");
+      result = 1;
+    }
+
+  ts.tv_nsec = -2;
+  if (mq_timedsend (q, buf, 1, 6, &ts) == 0)
+    {
+      puts ("mq_timedsend with negative tv_nsec did not fail");
+      result = 1;
+    }
+  else if (errno != EINVAL)
+    {
+      printf ("mq_timedsend with megatove tv_nsec did not fail with "
+             "EINVAL: %m\n");
+      result = 1;
+    }
+
+  setitimer (ITIMER_REAL, &it, NULL);
+
+  if (mq_send (q, buf, 2, 8) == 0)
+    {
+      puts ("mq_send on full queue did not block");
+      result = 1;
+    }
+  else if (errno != EINTR)
+    {
+      printf ("mq_send on full queue did not fail with EINTR: %m\n");
+      result = 1;
+    }
+
+  setitimer (ITIMER_REAL, &it, NULL);
+
+  ts.tv_sec += 10;
+  ts.tv_nsec = 0;
+  if (mq_timedsend (q, buf, 2, 7, &ts) == 0)
+    {
+      puts ("mq_timedsend on full queue did not block");
+      result = 1;
+    }
+  else if (errno != EINTR)
+    {
+      printf ("mq_timedsend on full queue did not fail with EINTR: %m\n");
+      result = 1;
+    }
+
+  memset (buf, ' ', sizeof (buf));
+
+  if (clock_gettime (CLOCK_REALTIME, &ts) != 0)
+    ts.tv_sec = time (NULL);
+  ts.tv_nsec = -1000000001;
+  rets = mq_timedreceive (q, buf, 2, &prio, &ts);
+  if (rets == -1 && errno == EINVAL)
+    rets = mq_receive (q, buf, 2, &prio);
+  if (rets != 2)
+    {
+      if (rets == -1)
+       printf ("mq_timedreceive failed: %m\n");
+      else
+       printf ("mq_timedreceive returned %zd != 2\n", rets);
+      result = 1;
+    }
+  else if (prio != 5 || memcmp (buf, "21 ", 3) != 0)
+    {
+      printf ("mq_timedreceive prio %u (5) buf \"%c%c%c\" (\"21 \")\n",
+             prio, buf[0], buf[1], buf[2]);
+      result = 1;
+    }
+
+  if (mq_receive (q, buf, 1, NULL) == 0)
+    {
+      puts ("mq_receive with too small msg_len did not fail");
+      result = 1;
+    }
+  else if (errno != EMSGSIZE)
+    {
+      printf ("mq_receive with too small msg_len did not fail with "
+             "EMSGSIZE: %m\n");
+      result = 1;
+    }
+
+  ts.tv_nsec = -ts.tv_nsec;
+  rets = mq_timedreceive (q, buf, 2, NULL, &ts);
+  if (rets == -1 && errno == EINVAL)
+    rets = mq_receive (q, buf, 2, NULL);
+  if (rets != 1)
+    {
+      if (rets == -1)
+       printf ("mq_timedreceive failed: %m\n");
+      else
+       printf ("mq_timedreceive returned %zd != 1\n", rets);
+      result = 1;
+    }
+  else if (memcmp (buf, "31 ", 3) != 0)
+    {
+      printf ("mq_timedreceive buf \"%c%c%c\" != \"31 \"\n",
+             buf[0], buf[1], buf[2]);
+      result = 1;
+    }
+
+  if (mq_send (q, "", 0, 2) != 0)
+    {
+      printf ("mq_send with msg_len 0 failed: %m\n");
+      result = 1;
+    }
+
+  rets = mq_receive (q, buf, 2, &prio);
+  if (rets)
+    {
+      if (rets == -1)
+       printf ("mq_receive failed: %m\n");
+      else
+       printf ("mq_receive returned %zd != 0\n", rets);
+      result = 1;
+    }
+
+  long mq_prio_max = sysconf (_SC_MQ_PRIO_MAX);
+  if (mq_prio_max > 0 && (unsigned int) mq_prio_max == mq_prio_max)
+    {
+      if (mq_send (q, buf, 1, mq_prio_max) == 0)
+       {
+         puts ("mq_send with MQ_PRIO_MAX priority unpexpectedly succeeded");
+         result = 1;
+       }
+      else if (errno != EINVAL)
+       {
+         printf ("mq_send with MQ_PRIO_MAX priority did not fail with "
+                 "EINVAL: %m\n");
+         result = 1;
+       }
+
+      if (mq_send (q, buf, 1, mq_prio_max - 1) != 0)
+       {
+         printf ("mq_send with MQ_PRIO_MAX-1 priority failed: %m\n");
+         result = 1;
+       }
+    }
+
+  if (mq_unlink (name) != 0)
+    {
+      printf ("mq_unlink failed: %m\n");
+      result = 1;
+    }
+
+  q2 = mq_open (name, O_RDWR);
+  if (q2 != (mqd_t) -1)
+    {
+      printf ("mq_open of unlinked %s without O_CREAT unexpectedly"
+             "succeeded\n", name);
+      result = 1;
+    }
+  else if (errno != ENOENT)
+    {
+      printf ("mq_open of unlinked %s without O_CREAT did not fail with "
+             "ENOENT: %m\n", name);
+      result = 1;
+    }
+
+  if (mq_close (q) != 0)
+    {
+      printf ("mq_close in parent failed: %m\n");
+      result = 1;
+    }
+
+  if (mq_receive (q, buf, 2, NULL) == 0)
+    {
+      puts ("mq_receive on invalid mqd_t did not fail");
+      result = 1;
+    }
+  else if (errno != EBADF)
+    {
+      printf ("mq_receive on invalid mqd_t did not fail with EBADF: %m\n");
+      result = 1;
+    }
+
+  if (mq_send (q, buf, 1, 2) == 0)
+    {
+      puts ("mq_send on invalid mqd_t did not fail");
+      result = 1;
+    }
+  else if (errno != EBADF)
+    {
+      printf ("mq_send on invalid mqd_t did not fail with EBADF: %m\n");
+      result = 1;
+    }
+
+  if (mq_getattr (q, &attr) == 0)
+    {
+      puts ("mq_getattr on invalid mqd_t did not fail");
+      result = 1;
+    }
+  else if (errno != EBADF)
+    {
+      printf ("mq_getattr on invalid mqd_t did not fail with EBADF: %m\n");
+      result = 1;
+    }
+
+  memset (&attr, 0, sizeof (attr));
+  if (mq_setattr (q, &attr, NULL) == 0)
+    {
+      puts ("mq_setattr on invalid mqd_t did not fail");
+      result = 1;
+    }
+  else if (errno != EBADF)
+    {
+      printf ("mq_setattr on invalid mqd_t did not fail with EBADF: %m\n");
+      result = 1;
+    }
+
+  if (mq_unlink ("/tst-mqueue2-which-should-never-exist") != -1)
+    {
+      puts ("mq_unlink of non-existant message queue unexpectedly succeeded");
+      result = 1;
+    }
+  else if (errno != ENOENT)
+    {
+      printf ("mq_unlink of non-existant message queue did not fail with "
+             "ENOENT: %m\n");
+      result = 1;
+    }
+  return result;
+}
+
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-mqueue3.c b/test/nptl/tst-mqueue3.c
new file mode 100644 (file)
index 0000000..990e057
--- /dev/null
@@ -0,0 +1,244 @@
+/* Test SIGEV_THREAD handling for POSIX message queues.
+   Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2004.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with 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 <mqueue.h>
+#include <signal.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#if _POSIX_THREADS
+# include <pthread.h>
+
+static pid_t pid;
+static mqd_t m;
+static const char message[] = "hello";
+
+# define MAXMSG 10
+# define MSGSIZE 10
+# define UNIQUE 42
+
+
+static void
+fct (union sigval s)
+{
+  /* Put the mq in non-blocking mode.  */
+  struct mq_attr attr;
+  if (mq_getattr (m, &attr) != 0)
+    {
+      printf ("%s: mq_getattr failed: %m\n", __FUNCTION__);
+      exit (1);
+    }
+  attr.mq_flags |= O_NONBLOCK;
+  if (mq_setattr (m, &attr, NULL) != 0)
+    {
+      printf ("%s: mq_setattr failed: %m\n", __FUNCTION__);
+      exit (1);
+    }
+
+  /* Check the values.  */
+  if (attr.mq_maxmsg != MAXMSG)
+    {
+      printf ("%s: mq_maxmsg wrong: is %ld, expecte %d\n",
+             __FUNCTION__, attr.mq_maxmsg, MAXMSG);
+      exit (1);
+    }
+  if (attr.mq_msgsize != MAXMSG)
+    {
+      printf ("%s: mq_msgsize wrong: is %ld, expecte %d\n",
+             __FUNCTION__, attr.mq_msgsize, MSGSIZE);
+      exit (1);
+    }
+
+  /* Read the message.  */
+  char buf[attr.mq_msgsize];
+  ssize_t n = TEMP_FAILURE_RETRY (mq_receive (m, buf, attr.mq_msgsize, NULL));
+  if (n != sizeof (message))
+    {
+      printf ("%s: length of message wrong: is %zd, expected %zu\n",
+             __FUNCTION__, n, sizeof (message));
+      exit (1);
+    }
+  if (memcmp (buf, message, sizeof (message)) != 0)
+    {
+      printf ("%s: message wrong: is \"%s\", expected \"%s\"\n",
+             __FUNCTION__, buf, message);
+      exit (1);
+    }
+
+  exit (UNIQUE);
+}
+
+
+int
+do_test (void)
+{
+  char tmpfname[] = "/tmp/tst-mqueue3-barrier.XXXXXX";
+  int fd = mkstemp (tmpfname);
+  if (fd == -1)
+    {
+      printf ("cannot open temporary file: %m\n");
+      return 1;
+    }
+
+  /* Make sure it is always removed.  */
+  unlink (tmpfname);
+
+  /* Create one page of data.  */
+  size_t ps = sysconf (_SC_PAGESIZE);
+  char data[ps];
+  memset (data, '\0', ps);
+
+  /* Write the data to the file.  */
+  if (write (fd, data, ps) != (ssize_t) ps)
+    {
+      puts ("short write");
+      return 1;
+    }
+
+  void *mem = mmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+  if (mem == MAP_FAILED)
+    {
+      printf ("mmap failed: %m\n");
+      return 1;
+    }
+
+  pthread_barrier_t *b;
+  b = (pthread_barrier_t *) (((uintptr_t) mem + __alignof (pthread_barrier_t))
+                             & ~(__alignof (pthread_barrier_t) - 1));
+
+  pthread_barrierattr_t a;
+  if (pthread_barrierattr_init (&a) != 0)
+    {
+      puts ("barrierattr_init failed");
+      return 1;
+    }
+
+  if (pthread_barrierattr_setpshared (&a, PTHREAD_PROCESS_SHARED) != 0)
+    {
+      puts ("barrierattr_setpshared failed, could not test");
+      return 0;
+    }
+
+  if (pthread_barrier_init (b, &a, 2) != 0)
+    {
+      puts ("barrier_init failed");
+      return 1;
+    }
+
+  if (pthread_barrierattr_destroy (&a) != 0)
+    {
+      puts ("barrierattr_destroy failed");
+      return 1;
+    }
+
+  /* Name for the message queue.  */
+  char mqname[sizeof ("/tst-mqueue3-") + 3 * sizeof (pid_t)];
+  snprintf (mqname, sizeof (mqname) - 1, "/tst-mqueue3-%ld",
+           (long int) getpid ());
+
+  /* Create the message queue.  */
+  struct mq_attr attr = { .mq_maxmsg = MAXMSG, .mq_msgsize = MSGSIZE };
+  m = mq_open (mqname, O_CREAT | O_EXCL | O_RDWR, 0600, &attr);
+  if (m == -1)
+    {
+      if (errno == ENOSYS)
+       {
+         puts ("not implemented");
+         return 0;
+       }
+
+      puts ("mq_open failed");
+      return 1;
+    }
+
+  /* Unlink the message queue right away.  */
+  if (mq_unlink (mqname) != 0)
+    {
+      puts ("mq_unlink failed");
+      return 1;
+    }
+
+  pid = fork ();
+  if (pid == -1)
+    {
+      puts ("fork failed");
+      return 1;
+    }
+  if (pid == 0)
+    {
+      /* Request notification via thread.  */
+      struct sigevent ev;
+      ev.sigev_notify = SIGEV_THREAD;
+      ev.sigev_notify_function = fct;
+      ev.sigev_value.sival_ptr = NULL;
+      ev.sigev_notify_attributes = NULL;
+
+      /* Tell the kernel.  */
+      if (mq_notify (m,&ev) != 0)
+       {
+         puts ("mq_notify failed");
+         exit (1);
+       }
+
+      /* Tell the parent we are ready.  */
+      (void) pthread_barrier_wait (b);
+
+      /* Make sure the process goes away eventually.  */
+      alarm (10);
+
+      /* Do nothing forever.  */
+      while (1)
+       pause ();
+    }
+
+  /* Wait for the child process to register to notification method.  */
+  (void) pthread_barrier_wait (b);
+
+  /* Send the message.  */
+  if (mq_send (m, message, sizeof (message), 1) != 0)
+    {
+      kill (pid, SIGKILL);
+      puts ("mq_send failed");
+      return 1;
+    }
+
+  int r;
+  if (TEMP_FAILURE_RETRY (waitpid (pid, &r, 0)) != pid)
+    {
+      kill (pid, SIGKILL);
+      puts ("waitpid failed");
+      return 1;
+    }
+
+  return WIFEXITED (r) && WEXITSTATUS (r) == UNIQUE ? 0 : 1;
+}
+# define TEST_FUNCTION do_test ()
+#else
+# define TEST_FUNCTION 0
+#endif
+
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-mqueue4.c b/test/nptl/tst-mqueue4.c
new file mode 100644 (file)
index 0000000..aa31706
--- /dev/null
@@ -0,0 +1,288 @@
+/* Test message queue passing.
+   Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2004.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with 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 <mqueue.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+#include "tst-mqueue.h"
+
+#define TIMEOUT 4
+#define TEST_FUNCTION do_test ()
+static int
+do_test (void)
+{
+  int result = 0;
+
+  char name[sizeof "/tst-mqueue4-" + sizeof (pid_t) * 3 + NAME_MAX];
+  char *p;
+  p = name + snprintf (name, sizeof (name), "/tst-mqueue4-%u", getpid ());
+  struct mq_attr attr = { .mq_maxmsg = 2, .mq_msgsize = 2 };
+  mqd_t q = mq_open (name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr);
+
+  if (q == (mqd_t) -1)
+    {
+      printf ("mq_open failed with: %m\n");
+      return result;
+    }
+  else
+    add_temp_mq (name);
+
+  *p = '.';
+  memset (p + 1, 'x', NAME_MAX + 1 - (p - name));
+  name[NAME_MAX + 1] = '\0';
+
+  mqd_t q2 = mq_open (name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr);
+  if (q2 == (mqd_t) -1)
+    {
+      printf ("mq_open with NAME_MAX long name compoment failed with: %m\n");
+      result = 1;
+    }
+
+  if (mq_unlink (name) != 0)
+    {
+      printf ("mq_unlink failed: %m\n");
+      result = 1;
+    }
+
+  if (mq_close (q2) != 0)
+    {
+      printf ("mq_close failed: %m\n");
+      result = 1;
+    }
+
+  name[NAME_MAX + 1] = 'x';
+  name[NAME_MAX + 2] = '\0';
+  q2 = mq_open (name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr);
+  if (q2 != (mqd_t) -1)
+    {
+      puts ("mq_open with too long name component unexpectedly succeeded");
+      mq_unlink (name);
+      mq_close (q2);
+      result = 1;
+    }
+  else if (errno != ENAMETOOLONG)
+    {
+      printf ("mq_open with too long name component did not fail with "
+             "ENAMETOOLONG: %m\n");
+      result = 1;
+    }
+
+  if (mq_unlink (name) == 0)
+    {
+      puts ("mq_unlink with too long name component unexpectedly succeeded");
+      result = 1;
+    }
+  else if (errno != ENAMETOOLONG)
+    {
+      printf ("mq_unlink with too long name component did not fail with "
+             "ENAMETOOLONG: %m\n");
+      result = 1;
+    }
+
+  *p = '\0';
+  attr.mq_maxmsg = 1;
+  attr.mq_msgsize = 3;
+  q2 = mq_open (name, O_CREAT | O_RDWR, 0600, &attr);
+  if (q2 == (mqd_t) -1)
+    {
+      printf ("mq_open without O_EXCL failed with %m\n");
+      result = 1;
+    }
+
+  char buf[3];
+  strcpy (buf, "jk");
+  if (mq_send (q, buf, 2, 4) != 0)
+    {
+      printf ("mq_send failed: %m\n");
+      result = 1;
+    }
+
+  if (mq_send (q, buf + 1, 1, 5) != 0)
+    {
+      printf ("mq_send failed: %m\n");
+      result = 1;
+    }
+
+  if (mq_getattr (q2, &attr) != 0)
+    {
+      printf ("mq_getattr failed: %m\n");
+      result = 1;
+    }
+
+  if ((attr.mq_flags & O_NONBLOCK)
+      || attr.mq_maxmsg != 2
+      || attr.mq_msgsize != 2
+      || attr.mq_curmsgs != 2)
+    {
+      printf ("mq_getattr returned unexpected { .mq_flags = %ld,\n"
+             ".mq_maxmsg = %ld, .mq_msgsize = %ld, .mq_curmsgs = %ld }\n",
+             attr.mq_flags, attr.mq_maxmsg, attr.mq_msgsize, attr.mq_curmsgs);
+      result = 1;
+    }
+
+  struct timespec ts;
+  if (clock_gettime (CLOCK_REALTIME, &ts) == 0)
+    ++ts.tv_sec;
+  else
+    {
+      ts.tv_sec = time (NULL) + 1;
+      ts.tv_nsec = 0;
+    }
+
+  if (mq_timedsend (q2, buf, 1, 1, &ts) == 0)
+    {
+      puts ("mq_timedsend unexpectedly succeeded");
+      result = 1;
+    }
+  else if (errno != ETIMEDOUT)
+    {
+      printf ("mq_timedsend did not fail with ETIMEDOUT: %m\n");
+      result = 1;
+    }
+
+  if (mq_close (q2) != 0)
+    {
+      printf ("mq_close failed: %m\n");
+      result = 1;
+    }
+
+  q2 = mq_open (name, O_RDONLY, 0600);
+  if (q2 == (mqd_t) -1)
+    {
+      printf ("mq_open without O_CREAT failed with %m\n");
+      result = 1;
+    }
+
+  mqd_t q3 = mq_open (name, O_RDONLY, 0600);
+  if (q3 == (mqd_t) -1)
+    {
+      printf ("mq_open without O_CREAT failed with %m\n");
+      result = 1;
+    }
+
+  memset (buf, ' ', sizeof (buf));
+
+  unsigned int prio;
+  ssize_t rets = mq_receive (q2, buf, 2, &prio);
+  if (rets != 1)
+    {
+      if (rets == -1)
+       printf ("mq_receive failed with: %m\n");
+      else
+       printf ("mq_receive returned %zd != 1\n", rets);
+      result = 1;
+    }
+  else if (prio != 5 || memcmp (buf, "k  ", 3) != 0)
+    {
+      printf ("mq_receive returned prio %u (2) buf \"%c%c%c\" (\"k  \")\n",
+             prio, buf[0], buf[1], buf[2]);
+      result = 1;
+    }
+
+  if (mq_getattr (q3, &attr) != 0)
+    {
+      printf ("mq_getattr failed: %m\n");
+      result = 1;
+    }
+
+  if ((attr.mq_flags & O_NONBLOCK)
+      || attr.mq_maxmsg != 2
+      || attr.mq_msgsize != 2
+      || attr.mq_curmsgs != 1)
+    {
+      printf ("mq_getattr returned unexpected { .mq_flags = %ld,\n"
+             ".mq_maxmsg = %ld, .mq_msgsize = %ld, .mq_curmsgs = %ld }\n",
+             attr.mq_flags, attr.mq_maxmsg, attr.mq_msgsize, attr.mq_curmsgs);
+      result = 1;
+    }
+
+  rets = mq_receive (q3, buf, 2, NULL);
+  if (rets != 2)
+    {
+      if (rets == -1)
+       printf ("mq_receive failed with: %m\n");
+      else
+       printf ("mq_receive returned %zd != 2\n", rets);
+      result = 1;
+    }
+  else if (memcmp (buf, "jk ", 3) != 0)
+    {
+      printf ("mq_receive returned buf \"%c%c%c\" != \"jk \"\n",
+             buf[0], buf[1], buf[2]);
+      result = 1;
+    }
+
+  if (clock_gettime (CLOCK_REALTIME, &ts) == 0)
+    ++ts.tv_sec;
+  else
+    {
+      ts.tv_sec = time (NULL) + 1;
+      ts.tv_nsec = 0;
+    }
+
+  if (mq_timedreceive (q2, buf, 2, NULL, &ts) != -1)
+    {
+      puts ("mq_timedreceive on empty queue unexpectedly succeeded");
+      result = 1;
+    }
+  else if (errno != ETIMEDOUT)
+    {
+      printf ("mq_timedreceive on empty queue did not fail with "
+             "ETIMEDOUT: %m\n");
+      result = 1;
+    }
+
+  if (mq_unlink (name) != 0)
+    {
+      printf ("mq_unlink failed: %m\n");
+      result = 1;
+    }
+
+  if (mq_close (q) != 0)
+    {
+      printf ("mq_close failed: %m\n");
+      result = 1;
+    }
+
+  if (mq_close (q2) != 0)
+    {
+      printf ("mq_close failed: %m\n");
+      result = 1;
+    }
+
+  if (mq_close (q3) != 0)
+    {
+      printf ("mq_close failed: %m\n");
+      result = 1;
+    }
+
+  return result;
+}
+
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-mqueue5.c b/test/nptl/tst-mqueue5.c
new file mode 100644 (file)
index 0000000..97571da
--- /dev/null
@@ -0,0 +1,1014 @@
+/* Test mq_notify.
+   Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2004.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with 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 <mqueue.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+#include "tst-mqueue.h"
+
+#define TIMEOUT 3
+
+#if _POSIX_THREADS
+# include <pthread.h>
+
+volatile int rtmin_cnt;
+volatile pid_t rtmin_pid;
+volatile uid_t rtmin_uid;
+volatile int rtmin_code;
+volatile union sigval rtmin_sigval;
+
+static void
+rtmin_handler (int sig, siginfo_t *info, void *ctx)
+{
+  if (sig != SIGRTMIN)
+    abort ();
+  ++rtmin_cnt;
+  rtmin_pid = info->si_pid;
+  rtmin_uid = info->si_uid;
+  rtmin_code = info->si_code;
+  rtmin_sigval = info->si_value;
+}
+
+#define mqsend(q) (mqsend) (q, __LINE__)
+static int
+(mqsend) (mqd_t q, int line)
+{
+  char c;
+  if (mq_send (q, &c, 1, 1) != 0)
+    {
+      printf ("mq_send on line %d failed with: %m\n", line);
+      return 1;
+    }
+  return 0;
+}
+
+#define mqrecv(q) (mqrecv) (q, __LINE__)
+static int
+(mqrecv) (mqd_t q, int line)
+{
+  char c;
+  ssize_t rets = TEMP_FAILURE_RETRY (mq_receive (q, &c, 1, NULL));
+  if (rets != 1)
+    {
+      if (rets == -1)
+       printf ("mq_receive on line %d failed with: %m\n", line);
+      else
+       printf ("mq_receive on line %d returned %zd != 1\n",
+               line, rets);
+      return 1;
+    }
+  return 0;
+}
+
+struct thr_data
+{
+  const char *name;
+  pthread_barrier_t *b3;
+  mqd_t q;
+};
+
+static void *
+thr (void *arg)
+{
+  pthread_barrier_t *b3 = ((struct thr_data *)arg)->b3;
+  mqd_t q = ((struct thr_data *)arg)->q;
+  const char *name = ((struct thr_data *)arg)->name;
+  int result = 0;
+
+  result |= mqrecv (q);
+
+  (void) pthread_barrier_wait (b3);
+
+  /* Child verifies SIGRTMIN has not been sent.  */
+
+  (void) pthread_barrier_wait (b3);
+
+  /* Parent calls mqsend (q), which should trigger notification.  */
+
+  (void) pthread_barrier_wait (b3);
+
+  if (rtmin_cnt != 2)
+    {
+      puts ("SIGRTMIN signal in child did not arrive");
+      result = 1;
+    }
+  else if (rtmin_pid != getppid ()
+          || rtmin_uid != getuid ()
+          || rtmin_code != SI_MESGQ
+          || rtmin_sigval.sival_int != 0xdeadbeef)
+    {
+      printf ("unexpected siginfo_t fields: pid %u (%u), uid %u (%u), code %d (%d), si_int %d (%d)\n",
+             rtmin_pid, getppid (), rtmin_uid, getuid (),
+             rtmin_code, SI_MESGQ, rtmin_sigval.sival_int, 0xdeadbeef);
+      result = 1;
+    }
+
+  struct sigevent ev;
+  memset (&ev, 0x82, sizeof (ev));
+  ev.sigev_notify = SIGEV_NONE;
+  if (mq_notify (q, &ev) != 0)
+    {
+      printf ("mq_notify in thread (q, { SIGEV_NONE }) failed with: %m\n");
+      result = 1;
+    }
+
+  if (mq_notify (q, NULL) != 0)
+    {
+      printf ("mq_notify in thread (q, NULL) failed with: %m\n");
+      result = 1;
+    }
+
+  result |= mqrecv (q);
+
+  (void) pthread_barrier_wait (b3);
+
+  /* Child calls mq_notify (q, { SIGEV_SIGNAL }).  */
+
+  (void) pthread_barrier_wait (b3);
+
+  if (mq_notify (q, NULL) != 0)
+    {
+      printf ("second mq_notify in thread (q, NULL) failed with: %m\n");
+      result = 1;
+    }
+
+  (void) pthread_barrier_wait (b3);
+
+  /* Parent calls mqsend (q), which should not trigger notification.  */
+
+  (void) pthread_barrier_wait (b3);
+
+  /* Child verifies SIGRTMIN has not been received.  */
+  /* Child calls mq_notify (q, { SIGEV_SIGNAL }).  */
+
+  (void) pthread_barrier_wait (b3);
+
+  mqd_t q4 = mq_open (name, O_RDONLY);
+  if (q4 == (mqd_t) -1)
+    {
+      printf ("mq_open in thread failed with: %m\n");
+      result = 1;
+    }
+
+  if (mq_notify (q4, NULL) != 0)
+    {
+      printf ("mq_notify in thread (q4, NULL) failed with: %m\n");
+      result = 1;
+    }
+
+  if (mq_close (q4) != 0)
+    {
+      printf ("mq_close in thread failed with: %m\n");
+      result = 1;
+    }
+
+  (void) pthread_barrier_wait (b3);
+
+  /* Parent calls mqsend (q), which should not trigger notification.  */
+
+  (void) pthread_barrier_wait (b3);
+
+  /* Child verifies SIGRTMIN has not been received.  */
+  /* Child calls mq_notify (q, { SIGEV_SIGNAL }).  */
+
+  (void) pthread_barrier_wait (b3);
+
+  mqd_t q5 = mq_open (name, O_WRONLY);
+  if (q5 == (mqd_t) -1)
+    {
+      printf ("mq_open O_WRONLY in thread failed with: %m\n");
+      result = 1;
+    }
+
+  if (mq_notify (q5, NULL) != 0)
+    {
+      printf ("mq_notify in thread (q5, NULL) failed with: %m\n");
+      result = 1;
+    }
+
+  if (mq_close (q5) != 0)
+    {
+      printf ("mq_close in thread failed with: %m\n");
+      result = 1;
+    }
+
+  (void) pthread_barrier_wait (b3);
+
+  /* Parent calls mqsend (q), which should not trigger notification.  */
+
+  (void) pthread_barrier_wait (b3);
+
+  /* Child verifies SIGRTMIN has not been received.  */
+
+  return (void *) (long) result;
+}
+
+static void
+do_child (const char *name, pthread_barrier_t *b2, pthread_barrier_t *b3,
+         mqd_t q)
+{
+  int result = 0;
+
+  struct sigevent ev;
+  memset (&ev, 0x55, sizeof (ev));
+  ev.sigev_notify = SIGEV_SIGNAL;
+  ev.sigev_signo = SIGRTMIN;
+  ev.sigev_value.sival_ptr = &ev;
+  if (mq_notify (q, &ev) == 0)
+    {
+      puts ("first mq_notify in child (q, { SIGEV_SIGNAL }) unexpectedly succeeded");
+      result = 1;
+    }
+  else if (errno != EBUSY)
+    {
+      printf ("first mq_notify in child (q, { SIGEV_SIGNAL }) failed with: %m\n");
+      result = 1;
+    }
+
+  (void) pthread_barrier_wait (b2);
+
+  /* Parent calls mqsend (q), which makes notification available.  */
+
+  (void) pthread_barrier_wait (b2);
+
+  rtmin_cnt = 0;
+
+  if (mq_notify (q, &ev) != 0)
+    {
+      printf ("second mq_notify in child (q, { SIGEV_SIGNAL }) failed with: %m\n");
+      result = 1;
+    }
+
+  if (rtmin_cnt != 0)
+    {
+      puts ("SIGRTMIN signal in child caught too early");
+      result = 1;
+    }
+
+  (void) pthread_barrier_wait (b2);
+
+  /* Parent unsuccessfully attempts to mq_notify.  */
+  /* Parent calls mqsend (q), which makes notification available
+     and triggers a signal in the child.  */
+  /* Parent successfully calls mq_notify SIGEV_SIGNAL.  */
+
+  (void) pthread_barrier_wait (b2);
+
+  if (rtmin_cnt != 1)
+    {
+      puts ("SIGRTMIN signal in child did not arrive");
+      result = 1;
+    }
+  else if (rtmin_pid != getppid ()
+          || rtmin_uid != getuid ()
+          || rtmin_code != SI_MESGQ
+          || rtmin_sigval.sival_ptr != &ev)
+    {
+      printf ("unexpected siginfo_t fields: pid %u (%u), uid %u (%u), code %d (%d), si_ptr %p (%p)\n",
+             rtmin_pid, getppid (), rtmin_uid, getuid (),
+             rtmin_code, SI_MESGQ, rtmin_sigval.sival_ptr, &ev);
+      result = 1;
+    }
+
+  result |= mqsend (q);
+
+  (void) pthread_barrier_wait (b2);
+
+  /* Parent verifies caught SIGRTMIN.  */
+
+  mqd_t q2 = mq_open (name, O_RDWR);
+  if (q2 == (mqd_t) -1)
+    {
+      printf ("mq_open in child failed with: %m\n");
+      result = 1;
+    }
+
+  (void) pthread_barrier_wait (b2);
+
+  /* Parent mq_open's another mqd_t for the same queue (q3).  */
+
+  memset (&ev, 0x11, sizeof (ev));
+  ev.sigev_notify = SIGEV_SIGNAL;
+  ev.sigev_signo = SIGRTMIN;
+  ev.sigev_value.sival_ptr = &ev;
+  if (mq_notify (q2, &ev) != 0)
+    {
+      printf ("mq_notify in child (q2, { SIGEV_SIGNAL }) failed with: %m\n");
+      result = 1;
+    }
+
+  (void) pthread_barrier_wait (b2);
+
+  /* Parent unsuccessfully attempts to mq_notify { SIGEV_NONE } on q.  */
+
+  (void) pthread_barrier_wait (b2);
+
+  if (mq_close (q2) != 0)
+    {
+      printf ("mq_close failed: %m\n");
+      result = 1;
+    }
+
+  (void) pthread_barrier_wait (b2);
+
+  /* Parent successfully calls mq_notify { SIGEV_NONE } on q3.  */
+
+  (void) pthread_barrier_wait (b2);
+
+  memset (&ev, 0xbb, sizeof (ev));
+  ev.sigev_notify = SIGEV_SIGNAL;
+  ev.sigev_signo = SIGRTMIN;
+  ev.sigev_value.sival_ptr = &b2;
+  if (mq_notify (q, &ev) == 0)
+    {
+      puts ("third mq_notify in child (q, { SIGEV_SIGNAL }) unexpectedly succeeded");
+      result = 1;
+    }
+  else if (errno != EBUSY)
+    {
+      printf ("third mq_notify in child (q, { SIGEV_SIGNAL }) failed with: %m\n");
+      result = 1;
+    }
+
+  (void) pthread_barrier_wait (b2);
+
+  /* Parent calls mq_close on q3, which makes the queue available again for
+     notification.  */
+
+  (void) pthread_barrier_wait (b2);
+
+  memset (&ev, 0x13, sizeof (ev));
+  ev.sigev_notify = SIGEV_NONE;
+  if (mq_notify (q, &ev) != 0)
+    {
+      printf ("mq_notify in child (q, { SIGEV_NONE }) failed with: %m\n");
+      result = 1;
+    }
+
+  if (mq_notify (q, NULL) != 0)
+    {
+      printf ("mq_notify in child (q, NULL) failed with: %m\n");
+      result = 1;
+    }
+
+  (void) pthread_barrier_wait (b2);
+
+  struct thr_data thr_data = { .name = name, .b3 = b3, .q = q };
+  pthread_t th;
+  int ret = pthread_create (&th, NULL, thr, &thr_data);
+  if (ret)
+    {
+      errno = ret;
+      printf ("pthread_created failed with: %m\n");
+      result = 1;
+    }
+
+  /* Wait till thr calls mq_receive on the empty queue q and blocks on it.  */
+  sleep (1);
+
+  memset (&ev, 0x5f, sizeof (ev));
+  ev.sigev_notify = SIGEV_SIGNAL;
+  ev.sigev_signo = SIGRTMIN;
+  ev.sigev_value.sival_int = 0xdeadbeef;
+  if (mq_notify (q, &ev) != 0)
+    {
+      printf ("fourth mq_notify in child (q, { SIGEV_SIGNAL }) failed with: %m\n");
+      result = 1;
+    }
+
+  (void) pthread_barrier_wait (b2);
+
+  /* Parent calls mqsend (q), which should wake up mqrecv (q)
+     in the thread but no notification should be sent.  */
+
+  (void) pthread_barrier_wait (b3);
+
+  if (rtmin_cnt != 1)
+    {
+      puts ("SIGRTMIN signal caught while thr was blocked on mq_receive");
+      result = 1;
+    }
+
+  (void) pthread_barrier_wait (b3);
+
+  /* Parent calls mqsend (q), which should trigger notification.  */
+
+  (void) pthread_barrier_wait (b3);
+
+  /* Thread verifies SIGRTMIN has been received.  */
+  /* Thread calls mq_notify (q, { SIGEV_NONE }) to verify notification is now
+     available for registration.  */
+  /* Thread calls mq_notify (q, NULL).  */
+
+  (void) pthread_barrier_wait (b3);
+
+  memset (&ev, 0x6a, sizeof (ev));
+  ev.sigev_notify = SIGEV_SIGNAL;
+  ev.sigev_signo = SIGRTMIN;
+  ev.sigev_value.sival_ptr = do_child;
+  if (mq_notify (q, &ev) != 0)
+    {
+      printf ("fifth mq_notify in child (q, { SIGEV_SIGNAL }) failed with: %m\n");
+      result = 1;
+    }
+
+  (void) pthread_barrier_wait (b3);
+
+  /* Thread calls mq_notify (q, NULL), which should unregister the above
+     notification.  */
+
+  (void) pthread_barrier_wait (b3);
+
+  /* Parent calls mqsend (q), which should not trigger notification.  */
+
+  (void) pthread_barrier_wait (b3);
+
+  if (rtmin_cnt != 2)
+    {
+      puts ("SIGRTMIN signal caught while notification has been disabled");
+      result = 1;
+    }
+
+  memset (&ev, 0x7b, sizeof (ev));
+  ev.sigev_notify = SIGEV_SIGNAL;
+  ev.sigev_signo = SIGRTMIN;
+  ev.sigev_value.sival_ptr = thr;
+  if (mq_notify (q, &ev) != 0)
+    {
+      printf ("sixth mq_notify in child (q, { SIGEV_SIGNAL }) failed with: %m\n");
+      result = 1;
+    }
+
+  (void) pthread_barrier_wait (b3);
+
+  /* Thread opens a new O_RDONLY mqd_t (q4).  */
+  /* Thread calls mq_notify (q4, NULL), which should unregister the above
+     notification.  */
+  /* Thread calls mq_close (q4).  */
+
+  (void) pthread_barrier_wait (b3);
+
+  /* Parent calls mqsend (q), which should not trigger notification.  */
+
+  (void) pthread_barrier_wait (b3);
+
+  if (rtmin_cnt != 2)
+    {
+      puts ("SIGRTMIN signal caught while notification has been disabled");
+      result = 1;
+    }
+
+  memset (&ev, 0xe1, sizeof (ev));
+  ev.sigev_notify = SIGEV_SIGNAL;
+  ev.sigev_signo = SIGRTMIN;
+  ev.sigev_value.sival_int = 127;
+  if (mq_notify (q, &ev) != 0)
+    {
+      printf ("seventh mq_notify in child (q, { SIGEV_SIGNAL }) failed with: %m\n");
+      result = 1;
+    }
+
+  (void) pthread_barrier_wait (b3);
+
+  /* Thread opens a new O_WRONLY mqd_t (q5).  */
+  /* Thread calls mq_notify (q5, NULL), which should unregister the above
+     notification.  */
+  /* Thread calls mq_close (q5).  */
+
+  (void) pthread_barrier_wait (b3);
+
+  /* Parent calls mqsend (q), which should not trigger notification.  */
+
+  (void) pthread_barrier_wait (b3);
+
+  if (rtmin_cnt != 2)
+    {
+      puts ("SIGRTMIN signal caught while notification has been disabled");
+      result = 1;
+    }
+
+ void *thr_ret;
+  ret = pthread_join (th, &thr_ret);
+  if (ret)
+    {
+      errno = ret;
+      printf ("pthread_join failed: %m\n");
+      result = 1;
+    }
+  else if (thr_ret)
+    result = 1;
+
+  if (mq_close (q) != 0)
+    {
+      printf ("mq_close failed: %m\n");
+      result = 1;
+    }
+
+  exit (result);
+}
+
+#define TEST_FUNCTION do_test ()
+static int
+do_test (void)
+{
+  int result = 0;
+
+  char tmpfname[] = "/tmp/tst-mqueue5-barrier.XXXXXX";
+  int fd = mkstemp (tmpfname);
+  if (fd == -1)
+    {
+      printf ("cannot open temporary file: %m\n");
+      return 1;
+    }
+
+  /* Make sure it is always removed.  */
+  unlink (tmpfname);
+
+  /* Create one page of data.  */
+  size_t ps = sysconf (_SC_PAGESIZE);
+  char data[ps];
+  memset (data, '\0', ps);
+
+  /* Write the data to the file.  */
+  if (write (fd, data, ps) != (ssize_t) ps)
+    {
+      puts ("short write");
+      return 1;
+    }
+
+  void *mem = mmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+  if (mem == MAP_FAILED)
+    {
+      printf ("mmap failed: %m\n");
+      return 1;
+    }
+
+  pthread_barrier_t *b2;
+  b2 = (pthread_barrier_t *) (((uintptr_t) mem + __alignof (pthread_barrier_t))
+                             & ~(__alignof (pthread_barrier_t) - 1));
+
+  pthread_barrier_t *b3;
+  b3 = b2 + 1;
+
+  pthread_barrierattr_t a;
+  if (pthread_barrierattr_init (&a) != 0)
+    {
+      puts ("barrierattr_init failed");
+      return 1;
+    }
+
+  if (pthread_barrierattr_setpshared (&a, PTHREAD_PROCESS_SHARED) != 0)
+    {
+      puts ("barrierattr_setpshared failed, could not test");
+      return 0;
+    }
+
+  if (pthread_barrier_init (b2, &a, 2) != 0)
+    {
+      puts ("barrier_init failed");
+      return 1;
+    }
+
+  if (pthread_barrier_init (b3, &a, 3) != 0)
+    {
+      puts ("barrier_init failed");
+      return 1;
+    }
+
+  if (pthread_barrierattr_destroy (&a) != 0)
+    {
+      puts ("barrierattr_destroy failed");
+      return 1;
+    }
+
+  char name[sizeof "/tst-mqueue5-" + sizeof (pid_t) * 3];
+  snprintf (name, sizeof (name), "/tst-mqueue5-%u", getpid ());
+
+  struct mq_attr attr = { .mq_maxmsg = 1, .mq_msgsize = 1 };
+  mqd_t q = mq_open (name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr);
+
+  if (q == (mqd_t) -1)
+    {
+      printf ("mq_open failed with: %m\n");
+      return result;
+    }
+  else
+    add_temp_mq (name);
+
+  struct sigevent ev;
+  memset (&ev, 0xaa, sizeof (ev));
+  ev.sigev_notify = SIGEV_NONE;
+  if (mq_notify (q, &ev) != 0)
+    {
+      printf ("mq_notify (q, { SIGEV_NONE }) failed with: %m\n");
+      result = 1;
+    }
+
+  if (mq_notify (q, &ev) == 0)
+    {
+      puts ("second mq_notify (q, { SIGEV_NONE }) unexpectedly succeeded");
+      result = 1;
+    }
+  else if (errno != EBUSY)
+    {
+      printf ("second mq_notify (q, { SIGEV_NONE }) failed with: %m\n");
+      result = 1;
+    }
+
+  result |= mqsend (q);
+
+  if (mq_notify (q, &ev) != 0)
+    {
+      printf ("third mq_notify (q, { SIGEV_NONE }) failed with: %m\n");
+      result = 1;
+    }
+
+  result |= mqrecv (q);
+
+  if (mq_notify (q, NULL) != 0)
+    {
+      printf ("mq_notify (q, NULL) failed with: %m\n");
+      result = 1;
+    }
+
+  if (mq_notify (q, NULL) != 0)
+    {
+      /* Implementation-defined behaviour, so don't fail,
+        just inform.  */
+      printf ("second mq_notify (q, NULL) failed with: %m\n");
+    }
+
+  struct sigaction sa = { .sa_sigaction = rtmin_handler,
+                         .sa_flags = SA_SIGINFO };
+  sigemptyset (&sa.sa_mask);
+  sigaction (SIGRTMIN, &sa, NULL);
+
+  memset (&ev, 0x55, sizeof (ev));
+  ev.sigev_notify = SIGEV_SIGNAL;
+  ev.sigev_signo = SIGRTMIN;
+  ev.sigev_value.sival_int = 26;
+  if (mq_notify (q, &ev) != 0)
+    {
+      printf ("mq_notify (q, { SIGEV_SIGNAL }) failed with: %m\n");
+      result = 1;
+    }
+
+  ev.sigev_value.sival_ptr = &ev;
+  if (mq_notify (q, &ev) == 0)
+    {
+      puts ("second mq_notify (q, { SIGEV_SIGNAL }) unexpectedly succeeded");
+      result = 1;
+    }
+  else if (errno != EBUSY)
+    {
+      printf ("second mq_notify (q, { SIGEV_SIGNAL }) failed with: %m\n");
+      result = 1;
+    }
+
+  if (rtmin_cnt != 0)
+    {
+      puts ("SIGRTMIN signal caught too early");
+      result = 1;
+    }
+
+  result |= mqsend (q);
+
+  if (rtmin_cnt != 1)
+    {
+      puts ("SIGRTMIN signal did not arrive");
+      result = 1;
+    }
+  else if (rtmin_pid != getpid ()
+          || rtmin_uid != getuid ()
+          || rtmin_code != SI_MESGQ
+          || rtmin_sigval.sival_int != 26)
+    {
+      printf ("unexpected siginfo_t fields: pid %u (%u), uid %u (%u), code %d (%d), si_int %d (26)\n",
+             rtmin_pid, getpid (), rtmin_uid, getuid (),
+             rtmin_code, SI_MESGQ, rtmin_sigval.sival_int);
+      result = 1;
+    }
+
+  ev.sigev_value.sival_int = 75;
+  if (mq_notify (q, &ev) != 0)
+    {
+      printf ("third mq_notify (q, { SIGEV_SIGNAL }) failed with: %m\n");
+      result = 1;
+    }
+
+  result |= mqrecv (q);
+
+  if (mq_notify (q, NULL) != 0)
+    {
+      printf ("mq_notify (q, NULL) failed with: %m\n");
+      result = 1;
+    }
+
+  memset (&ev, 0x33, sizeof (ev));
+  ev.sigev_notify = SIGEV_NONE;
+  if (mq_notify (q, &ev) != 0)
+    {
+      printf ("fourth mq_notify (q, { SIGEV_NONE }) failed with: %m\n");
+      result = 1;
+    }
+
+  pid_t pid = fork ();
+  if (pid == -1)
+    {
+      printf ("fork () failed: %m\n");
+      mq_unlink (name);
+      return 1;
+    }
+
+  if (pid == 0)
+    do_child (name, b2, b3, q);
+
+  /* Child unsuccessfully attempts to mq_notify.  */
+
+  (void) pthread_barrier_wait (b2);
+
+  result |= mqsend (q);
+
+  (void) pthread_barrier_wait (b2);
+
+  /* Child successfully calls mq_notify SIGEV_SIGNAL now.  */
+
+  result |= mqrecv (q);
+
+  (void) pthread_barrier_wait (b2);
+
+  memset (&ev, 0xbb, sizeof (ev));
+  ev.sigev_notify = SIGEV_SIGNAL;
+  ev.sigev_signo = SIGRTMIN;
+  ev.sigev_value.sival_int = 15;
+  if (mq_notify (q, &ev) == 0)
+    {
+      puts ("fourth mq_notify (q, { SIGEV_SIGNAL }) unexpectedly succeeded");
+      result = 1;
+    }
+  else if (errno != EBUSY)
+    {
+      printf ("fourth mq_notify (q, { SIGEV_SIGNAL }) failed with: %m\n");
+      result = 1;
+    }
+
+  result |= mqsend (q);
+
+  if (mq_notify (q, &ev) != 0)
+    {
+      printf ("fifth mq_notify (q, { SIGEV_SIGNAL }) failed with: %m\n");
+      result = 1;
+    }
+
+  if (rtmin_cnt != 1)
+    {
+      puts ("SIGRTMIN signal caught too early");
+      result = 1;
+    }
+
+  result |= mqrecv (q);
+
+  (void) pthread_barrier_wait (b2);
+
+  /* Child verifies caught SIGRTMIN signal.  */
+  /* Child calls mq_send (q) which triggers SIGRTMIN signal here.  */
+
+  (void) pthread_barrier_wait (b2);
+
+  /* Child mq_open's another mqd_t for the same queue (q2).  */
+
+  if (rtmin_cnt != 2)
+    {
+      puts ("SIGRTMIN signal did not arrive");
+      result = 1;
+    }
+  else if (rtmin_pid != pid
+          || rtmin_uid != getuid ()
+          || rtmin_code != SI_MESGQ
+          || rtmin_sigval.sival_int != 15)
+    {
+      printf ("unexpected siginfo_t fields: pid %u (%u), uid %u (%u), code %d (%d), si_int %d (15)\n",
+             rtmin_pid, pid, rtmin_uid, getuid (),
+             rtmin_code, SI_MESGQ, rtmin_sigval.sival_int);
+      result = 1;
+    }
+
+  result |= mqrecv (q);
+
+  (void) pthread_barrier_wait (b2);
+
+  /* Child successfully calls mq_notify { SIGEV_SIGNAL } on q2.  */
+
+  (void) pthread_barrier_wait (b2);
+
+  memset (&ev, 0xbb, sizeof (ev));
+  ev.sigev_notify = SIGEV_NONE;
+  if (mq_notify (q, &ev) == 0)
+    {
+      puts ("fifth mq_notify (q, { SIGEV_NONE }) unexpectedly succeeded");
+      result = 1;
+    }
+  else if (errno != EBUSY)
+    {
+      printf ("fifth mq_notify (q, { SIGEV_NONE }) failed with: %m\n");
+      result = 1;
+    }
+
+  (void) pthread_barrier_wait (b2);
+
+  /* Child calls mq_close on q2, which makes the queue available again for
+     notification.  */
+
+  mqd_t q3 = mq_open (name, O_RDWR);
+  if (q3 == (mqd_t) -1)
+    {
+      printf ("mq_open q3 in parent failed with: %m\n");
+      result = 1;
+    }
+
+  (void) pthread_barrier_wait (b2);
+
+  memset (&ev, 0x12, sizeof (ev));
+  ev.sigev_notify = SIGEV_NONE;
+  if (mq_notify (q3, &ev) != 0)
+    {
+      printf ("mq_notify (q3, { SIGEV_NONE }) failed with: %m\n");
+      result = 1;
+    }
+
+  (void) pthread_barrier_wait (b2);
+
+  /* Child unsuccessfully attempts to mq_notify { SIGEV_SIGNAL } on q.  */
+
+  (void) pthread_barrier_wait (b2);
+
+  if (mq_close (q3) != 0)
+    {
+      printf ("mq_close failed: %m\n");
+      result = 1;
+    }
+
+  (void) pthread_barrier_wait (b2);
+
+  /* Child successfully calls mq_notify { SIGEV_NONE } on q.  */
+  /* Child successfully calls mq_notify NULL on q.  */
+
+  (void) pthread_barrier_wait (b2);
+
+  /* Child creates new thread.  */
+  /* Thread blocks on mqrecv (q).  */
+  /* Child sleeps for 1sec so that thread has time to reach that point.  */
+  /* Child successfully calls mq_notify { SIGEV_SIGNAL } on q.  */
+
+  (void) pthread_barrier_wait (b2);
+
+  result |= mqsend (q);
+
+  (void) pthread_barrier_wait (b3);
+
+  /* Child verifies SIGRTMIN has not been sent.  */
+
+  (void) pthread_barrier_wait (b3);
+
+  result |= mqsend (q);
+
+  (void) pthread_barrier_wait (b3);
+
+  /* Thread verifies SIGRTMIN has been caught.  */
+  /* Thread calls mq_notify (q, { SIGEV_NONE }) to verify notification is now
+     available for registration.  */
+  /* Thread calls mq_notify (q, NULL).  */
+
+  (void) pthread_barrier_wait (b3);
+
+  /* Child calls mq_notify (q, { SIGEV_SIGNAL }).  */
+
+  (void) pthread_barrier_wait (b3);
+
+  /* Thread calls mq_notify (q, NULL). */
+
+  (void) pthread_barrier_wait (b3);
+
+  result |= mqsend (q);
+  result |= mqrecv (q);
+
+  (void) pthread_barrier_wait (b3);
+
+  /* Child verifies SIGRTMIN has not been sent.  */
+  /* Child calls mq_notify (q, { SIGEV_SIGNAL }).  */
+
+  (void) pthread_barrier_wait (b3);
+
+  /* Thread opens a new O_RDONLY mqd_t (q4).  */
+  /* Thread calls mq_notify (q4, NULL). */
+  /* Thread calls mq_close (q4).  */
+
+  (void) pthread_barrier_wait (b3);
+
+  result |= mqsend (q);
+  result |= mqrecv (q);
+
+  (void) pthread_barrier_wait (b3);
+
+  /* Child verifies SIGRTMIN has not been sent.  */
+  /* Child calls mq_notify (q, { SIGEV_SIGNAL }).  */
+
+  (void) pthread_barrier_wait (b3);
+
+  /* Thread opens a new O_WRONLY mqd_t (q5).  */
+  /* Thread calls mq_notify (q5, NULL). */
+  /* Thread calls mq_close (q5).  */
+
+  (void) pthread_barrier_wait (b3);
+
+  result |= mqsend (q);
+  result |= mqrecv (q);
+
+  (void) pthread_barrier_wait (b3);
+
+  /* Child verifies SIGRTMIN has not been sent.  */
+
+  int status;
+  if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid)
+    {
+      puts ("waitpid failed");
+      kill (pid, SIGKILL);
+      result = 1;
+    }
+  else if (!WIFEXITED (status) || WEXITSTATUS (status))
+    {
+      printf ("child failed with status %d\n", status);
+      result = 1;
+    }
+
+  if (mq_unlink (name) != 0)
+    {
+      printf ("mq_unlink failed: %m\n");
+      result = 1;
+    }
+
+  if (mq_close (q) != 0)
+    {
+      printf ("mq_close failed: %m\n");
+      result = 1;
+    }
+
+  if (mq_notify (q, NULL) == 0)
+    {
+      puts ("mq_notify on closed mqd_t unexpectedly succeeded");
+      result = 1;
+    }
+  else if (errno != EBADF)
+    {
+      printf ("mq_notify on closed mqd_t did not fail with EBADF: %m\n");
+      result = 1;
+    }
+
+  memset (&ev, 0x55, sizeof (ev));
+  ev.sigev_notify = SIGEV_NONE;
+  if (mq_notify (q, &ev) == 0)
+    {
+      puts ("mq_notify on closed mqd_t unexpectedly succeeded");
+      result = 1;
+    }
+  else if (errno != EBADF)
+    {
+      printf ("mq_notify on closed mqd_t did not fail with EBADF: %m\n");
+      result = 1;
+    }
+
+  return result;
+}
+#else
+# define TEST_FUNCTION 0
+#endif
+
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-mqueue6.c b/test/nptl/tst-mqueue6.c
new file mode 100644 (file)
index 0000000..5c9ee69
--- /dev/null
@@ -0,0 +1,305 @@
+/* Test mq_notify.
+   Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2004.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with 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 <mqueue.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+#include "tst-mqueue.h"
+
+#if _POSIX_THREADS
+# include <pthread.h>
+
+# define mqsend(q) (mqsend) (q, __LINE__)
+static int
+(mqsend) (mqd_t q, int line)
+{
+  char c;
+  if (mq_send (q, &c, 1, 1) != 0)
+    {
+      printf ("mq_send on line %d failed with: %m\n", line);
+      return 1;
+    }
+  return 0;
+}
+
+# define mqrecv(q) (mqrecv) (q, __LINE__)
+static int
+(mqrecv) (mqd_t q, int line)
+{
+  char c;
+  ssize_t rets = TEMP_FAILURE_RETRY (mq_receive (q, &c, 1, NULL));
+  if (rets != 1)
+    {
+      if (rets == -1)
+       printf ("mq_receive on line %d failed with: %m\n", line);
+      else
+       printf ("mq_receive on line %d returned %zd != 1\n",
+               line, rets);
+      return 1;
+    }
+  return 0;
+}
+
+volatile int fct_cnt, fct_err;
+size_t fct_guardsize;
+
+static void
+fct (union sigval s)
+{
+  mqd_t q = *(mqd_t *) s.sival_ptr;
+
+  pthread_attr_t nattr;
+  int ret = pthread_getattr_np (pthread_self (), &nattr);
+  if (ret)
+    {
+      errno = ret;
+      printf ("pthread_getattr_np failed: %m\n");
+      fct_err = 1;
+    }
+  else
+    {
+      ret = pthread_attr_getguardsize (&nattr, &fct_guardsize);
+      if (ret)
+       {
+         errno = ret;
+         printf ("pthread_attr_getguardsize failed: %m\n");
+         fct_err = 1;
+       }
+      if (pthread_attr_destroy (&nattr) != 0)
+       {
+         puts ("pthread_attr_destroy failed");
+         fct_err = 1;
+       }
+    }
+
+  ++fct_cnt;
+  fct_err |= mqsend (q);
+}
+
+# define TEST_FUNCTION do_test ()
+static int
+do_test (void)
+{
+  int result = 0;
+
+  char name[sizeof "/tst-mqueue6-" + sizeof (pid_t) * 3];
+  snprintf (name, sizeof (name), "/tst-mqueue6-%u", getpid ());
+
+  struct mq_attr attr = { .mq_maxmsg = 1, .mq_msgsize = 1 };
+  mqd_t q = mq_open (name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr);
+
+  if (q == (mqd_t) -1)
+    {
+      printf ("mq_open failed with: %m\n");
+      return result;
+    }
+  else
+    add_temp_mq (name);
+
+  pthread_attr_t nattr;
+  if (pthread_attr_init (&nattr)
+      || pthread_attr_setguardsize (&nattr, 0))
+    {
+      puts ("pthread_attr_t setup failed");
+      result = 1;
+    }
+
+  fct_guardsize = 1;
+
+  struct sigevent ev;
+  memset (&ev, 0xaa, sizeof (ev));
+  ev.sigev_notify = SIGEV_THREAD;
+  ev.sigev_notify_function = fct;
+  ev.sigev_notify_attributes = &nattr;
+  ev.sigev_value.sival_ptr = &q;
+  if (mq_notify (q, &ev) != 0)
+    {
+      printf ("mq_notify (q, { SIGEV_THREAD }) failed with: %m\n");
+      result = 1;
+    }
+
+  size_t ps = sysconf (_SC_PAGESIZE);
+  if (pthread_attr_setguardsize (&nattr, 32 * ps))
+    {
+      puts ("pthread_attr_t setup failed");
+      result = 1;
+    }
+
+  if (mq_notify (q, &ev) == 0)
+    {
+      puts ("second mq_notify (q, { SIGEV_NONE }) unexpectedly succeeded");
+      result = 1;
+    }
+  else if (errno != EBUSY)
+    {
+      printf ("second mq_notify (q, { SIGEV_NONE }) failed with: %m\n");
+      result = 1;
+    }
+
+  if (fct_cnt != 0)
+    {
+      printf ("fct called too early (%d on %d)\n", fct_cnt, __LINE__);
+      result = 1;
+    }
+
+  result |= mqsend (q);
+
+  result |= mqrecv (q);
+  result |= mqrecv (q);
+
+  if (fct_cnt != 1)
+    {
+      printf ("fct not called (%d on %d)\n", fct_cnt, __LINE__);
+      result = 1;
+    }
+  else if (fct_guardsize != 0)
+    {
+      printf ("fct_guardsize %zd != 0\n", fct_guardsize);
+      result = 1;
+    }
+
+  if (mq_notify (q, &ev) != 0)
+    {
+      printf ("third mq_notify (q, { SIGEV_NONE }) failed with: %m\n");
+      result = 1;
+    }
+
+  if (mq_notify (q, NULL) != 0)
+    {
+      printf ("mq_notify (q, NULL) failed with: %m\n");
+      result = 1;
+    }
+
+  memset (&ev, 0x11, sizeof (ev));
+  ev.sigev_notify = SIGEV_THREAD;
+  ev.sigev_notify_function = fct;
+  ev.sigev_notify_attributes = &nattr;
+  ev.sigev_value.sival_ptr = &q;
+  if (mq_notify (q, &ev) != 0)
+    {
+      printf ("mq_notify (q, { SIGEV_THREAD }) failed with: %m\n");
+      result = 1;
+    }
+
+  if (pthread_attr_setguardsize (&nattr, 0))
+    {
+      puts ("pthread_attr_t setup failed");
+      result = 1;
+    }
+
+  if (mq_notify (q, &ev) == 0)
+    {
+      puts ("second mq_notify (q, { SIGEV_NONE }) unexpectedly succeeded");
+      result = 1;
+    }
+  else if (errno != EBUSY)
+    {
+      printf ("second mq_notify (q, { SIGEV_NONE }) failed with: %m\n");
+      result = 1;
+    }
+
+  if (fct_cnt != 1)
+    {
+      printf ("fct called too early (%d on %d)\n", fct_cnt, __LINE__);
+      result = 1;
+    }
+
+  result |= mqsend (q);
+
+  result |= mqrecv (q);
+  result |= mqrecv (q);
+
+  if (fct_cnt != 2)
+    {
+      printf ("fct not called (%d on %d)\n", fct_cnt, __LINE__);
+      result = 1;
+    }
+  else if (fct_guardsize != 32 * ps)
+    {
+      printf ("fct_guardsize %zd != %zd\n", fct_guardsize, 32 * ps);
+      result = 1;
+    }
+
+  if (mq_notify (q, &ev) != 0)
+    {
+      printf ("third mq_notify (q, { SIGEV_NONE }) failed with: %m\n");
+      result = 1;
+    }
+
+  if (mq_notify (q, NULL) != 0)
+    {
+      printf ("mq_notify (q, NULL) failed with: %m\n");
+      result = 1;
+    }
+
+  if (pthread_attr_destroy (&nattr) != 0)
+    {
+      puts ("pthread_attr_destroy failed");
+      result = 1;
+    }
+
+  if (mq_unlink (name) != 0)
+    {
+      printf ("mq_unlink failed: %m\n");
+      result = 1;
+    }
+
+  if (mq_close (q) != 0)
+    {
+      printf ("mq_close failed: %m\n");
+      result = 1;
+    }
+
+  memset (&ev, 0x55, sizeof (ev));
+  ev.sigev_notify = SIGEV_THREAD;
+  ev.sigev_notify_function = fct;
+  ev.sigev_notify_attributes = NULL;
+  ev.sigev_value.sival_int = 0;
+  if (mq_notify (q, &ev) == 0)
+    {
+      puts ("mq_notify on closed mqd_t unexpectedly succeeded");
+      result = 1;
+    }
+  else if (errno != EBADF)
+    {
+      printf ("mq_notify on closed mqd_t did not fail with EBADF: %m\n");
+      result = 1;
+    }
+
+  if (fct_err)
+    result = 1;
+  return result;
+}
+#else
+# define TEST_FUNCTION 0
+#endif
+
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-mqueue7.c b/test/nptl/tst-mqueue7.c
new file mode 100644 (file)
index 0000000..34222f8
--- /dev/null
@@ -0,0 +1,109 @@
+/* Test all open message queues descriptors are closed during exec*.
+   Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2004.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with 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 <mqueue.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#define OPT_AFTEREXEC 20000
+
+static mqd_t after_exec = (mqd_t) -1;
+
+#define CMDLINE_OPTIONS \
+  { "after-exec", required_argument, NULL, OPT_AFTEREXEC },
+
+#define CMDLINE_PROCESS \
+  case OPT_AFTEREXEC:                                  \
+    after_exec = (mqd_t) strtoul (optarg, NULL, 0);    \
+    break;
+
+static int
+do_after_exec (void)
+{
+  int result = 0;
+
+  struct mq_attr attr;
+  if (mq_getattr (after_exec, &attr) == 0)
+    {
+      puts ("mq_getattr after exec unexpectedly succeeded");
+      result = 1;
+    }
+  else if (errno != EBADF)
+    {
+      printf ("mq_getattr after exec did not fail with EBADF: %m\n");
+      result = 1;
+    }
+
+  return result;
+}
+
+static int
+do_test (int argc, char **argv)
+{
+  if (after_exec != (mqd_t) -1)
+    return do_after_exec ();
+
+  char name[sizeof "/tst-mqueue7-" + sizeof (pid_t) * 3];
+  snprintf (name, sizeof (name), "/tst-mqueue7-%u", getpid ());
+
+  struct mq_attr attr = { .mq_maxmsg = 10, .mq_msgsize = 1 };
+  mqd_t q = mq_open (name, O_CREAT | O_EXCL | O_WRONLY, 0600, &attr);
+
+  if (q == (mqd_t) -1)
+    {
+      printf ("mq_open failed with: %m\n");
+      return 0;
+    }
+  else if (mq_unlink (name) != 0)
+    {
+      printf ("mq_unlink failed with: %m\n");
+      return 1;
+    }
+
+  if (mq_getattr (q, &attr) != 0)
+    {
+      printf ("mq_getattr failed: %m\n");
+      return 1;
+    }
+
+  char after_exec_arg[sizeof "--after-exec=0x" + sizeof (long) * 3];
+  snprintf (after_exec_arg, sizeof (after_exec_arg),
+           "--after-exec=0x%lx", (long) q);
+
+  const char *newargv[argc + 2];
+  for (int i = 1; i < argc; ++i)
+    newargv[i - 1] = argv[i];
+  newargv[argc - 1] = "--direct";
+  newargv[argc] = after_exec_arg;
+  newargv[argc + 1] = NULL;
+
+  /* Verify that exec* has the effect of mq_close (q).  */
+  execv (newargv[0], (char * const *) newargv);
+  printf ("execv failed: %m\n");
+  return 1;
+}
+
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-mqueue8.c b/test/nptl/tst-mqueue8.c
new file mode 100644 (file)
index 0000000..7e902aa
--- /dev/null
@@ -0,0 +1,266 @@
+/* Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2004.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with 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 <mqueue.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#if _POSIX_THREADS
+# include <pthread.h>
+
+static pthread_barrier_t b;
+
+/* Cleanup handling test.  */
+static int cl_called;
+
+static void
+cl (void *arg)
+{
+  ++cl_called;
+}
+
+#define TF_MQ_RECEIVE          0L
+#define TF_MQ_TIMEDRECEIVE     1L
+#define TF_MQ_SEND             2L
+#define TF_MQ_TIMEDSEND                3L
+
+static const char *names[]
+  = { "mq_receive", "mq_timedreceive", "mq_send", "mq_timedsend" };
+
+static mqd_t q;
+static struct timespec never;
+
+static void *
+tf (void *arg)
+{
+  int r = pthread_barrier_wait (&b);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("tf: barrier_wait failed");
+      exit (1);
+    }
+
+  pthread_cleanup_push (cl, NULL);
+
+  char c = ' ';
+
+  switch ((long) arg)
+    {
+    case TF_MQ_SEND:
+      TEMP_FAILURE_RETRY (mq_send (q, &c, 1, 1));
+      break;
+    case TF_MQ_TIMEDSEND:
+      TEMP_FAILURE_RETRY (mq_timedsend (q, &c, 1, 1, &never));
+      break;
+    case TF_MQ_RECEIVE:
+      TEMP_FAILURE_RETRY (mq_receive (q, &c, 1, NULL));
+      break;
+    case TF_MQ_TIMEDRECEIVE:
+      TEMP_FAILURE_RETRY (mq_timedreceive (q, &c, 1, NULL, &never));
+      break;
+    }
+
+  pthread_cleanup_pop (0);
+
+  printf ("tf: %s returned\n", names[(long) arg]);
+
+  exit (1);
+}
+
+#define TEST_FUNCTION do_test ()
+static int
+do_test (void)
+{
+  char name[sizeof "/tst-mqueue8-" + sizeof (pid_t) * 3];
+  snprintf (name, sizeof (name), "/tst-mqueue8-%u", getpid ());
+
+  struct mq_attr attr = { .mq_maxmsg = 1, .mq_msgsize = 1 };
+  q = mq_open (name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr);
+
+  if (q == (mqd_t) -1)
+    {
+      printf ("mq_open failed with: %m\n");
+      return 0;
+    }
+
+  if (mq_unlink (name) != 0)
+    {
+      printf ("mq_unlink failed with: %m\n");
+      return 1;
+    }
+
+  if (pthread_barrier_init (&b, NULL, 2) != 0)
+    {
+      puts ("barrier_init failed");
+      return 1;
+    }
+
+  if (clock_gettime (CLOCK_REALTIME, &never) == 0)
+    never.tv_sec += 100;
+  else
+    {
+      never.tv_sec = time (NULL) + 100;
+      never.tv_nsec = 0;
+    }
+
+  int result = 0;
+  for (long l = TF_MQ_RECEIVE; l <= TF_MQ_TIMEDSEND; ++l)
+    {
+      cl_called = 0;
+
+      pthread_t th;
+      if (pthread_create (&th, NULL, tf, (void *) l) != 0)
+       {
+         printf ("1st %s create failed\n", names[l]);
+         result = 1;
+         continue;
+       }
+
+      int r = pthread_barrier_wait (&b);
+      if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+       {
+         puts ("barrier_wait failed");
+         result = 1;
+         continue;
+       }
+
+      struct timespec ts = { .tv_sec = 0, .tv_nsec = 100000000 };
+      while (nanosleep (&ts, &ts) != 0)
+       continue;
+
+      printf ("going to cancel %s in-time\n", names[l]);
+      if (pthread_cancel (th) != 0)
+       {
+         printf ("1st cancel of %s failed\n", names[l]);
+         result = 1;
+         continue;
+       }
+
+      void *status;
+      if (pthread_join (th, &status) != 0)
+       {
+         printf ("1st join of %s failed\n", names[l]);
+         result = 1;
+         continue;
+       }
+      if (status != PTHREAD_CANCELED)
+       {
+         printf ("1st %s thread not canceled\n", names[l]);
+         result = 1;
+         continue;
+       }
+
+      if (cl_called == 0)
+       {
+         printf ("%s cleanup handler not called\n", names[l]);
+         result = 1;
+         continue;
+       }
+      if (cl_called > 1)
+       {
+         printf ("%s cleanup handler called more than once\n", names[l]);
+         result = 1;
+         continue;
+       }
+
+      printf ("in-time %s cancellation succeeded\n", names[l]);
+
+      cl_called = 0;
+
+      if (pthread_create (&th, NULL, tf, (void *) l) != 0)
+       {
+         printf ("2nd %s create failed\n", names[l]);
+         result = 1;
+         continue;
+       }
+
+      printf ("going to cancel %s early\n", names[l]);
+      if (pthread_cancel (th) != 0)
+       {
+         printf ("2nd cancel of %s failed\n", names[l]);
+         result = 1;
+         continue;
+       }
+
+      r = pthread_barrier_wait (&b);
+      if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+       {
+         puts ("barrier_wait failed");
+         result = 1;
+         continue;
+       }
+
+      if (pthread_join (th, &status) != 0)
+       {
+         printf ("2nd join of %s failed\n", names[l]);
+         result = 1;
+         continue;
+       }
+      if (status != PTHREAD_CANCELED)
+       {
+         printf ("2nd %s thread not canceled\n", names[l]);
+         result = 1;
+         continue;
+       }
+
+      if (cl_called == 0)
+       {
+         printf ("%s cleanup handler not called\n", names[l]);
+         result = 1;
+         continue;
+       }
+      if (cl_called > 1)
+       {
+         printf ("%s cleanup handler called more than once\n", names[l]);
+         result = 1;
+         continue;
+       }
+
+      printf ("early %s cancellation succeeded\n", names[l]);
+
+      if (l == TF_MQ_TIMEDRECEIVE)
+       {
+         /* mq_receive and mq_timedreceive are tested on empty mq.
+            For mq_send and mq_timedsend we need to make it full.
+            If this fails, there is no point in doing further testing.  */
+         char c = ' ';
+         if (mq_send (q, &c, 1, 1) != 0)
+           {
+             printf ("mq_send failed: %m\n");
+             result = 1;
+             break;
+           }
+       }
+    }
+
+  if (mq_close (q) != 0)
+    {
+      printf ("mq_close failed: %m\n");
+      result = 1;
+    }
+
+  return result;
+}
+#else
+# define TEST_FUNCTION 0
+#endif
+
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-mqueue9.c b/test/nptl/tst-mqueue9.c
new file mode 100644 (file)
index 0000000..fb057d4
--- /dev/null
@@ -0,0 +1,92 @@
+/* Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2004.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with 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 <mqueue.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "tst-mqueue.h"
+
+#define TEST_FUNCTION do_test ()
+static int
+do_test (void)
+{
+  if (geteuid () != 0)
+    {
+      puts ("this test requires root");
+      return 0;
+    }
+
+  char name[sizeof "/tst-mqueue9-" + sizeof (pid_t) * 3];
+  snprintf (name, sizeof (name), "/tst-mqueue9-%u", getpid ());
+
+  struct mq_attr attr = { .mq_maxmsg = 1, .mq_msgsize = 1 };
+  mqd_t q = mq_open (name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr);
+
+  if (q == (mqd_t) -1)
+    {
+      printf ("mq_open failed with: %m\n");
+      return 0;
+    }
+  else
+    add_temp_mq (name);
+
+  if (seteuid (1) != 0)
+    {
+      printf ("failed to seteuid (1): %m\n");
+      mq_unlink (name);
+      return 0;
+    }
+
+  int result = 0;
+  if (mq_unlink (name) == 0)
+    {
+      puts ("mq_unlink unexpectedly succeeded");
+      result = 1;
+    }
+  else if (errno != EACCES)
+    {
+      printf ("mq_unlink did not fail with EACCES: %m\n");
+      result = 1;;
+    }
+
+  if (seteuid (0) != 0)
+    {
+      printf ("failed to seteuid (0): %m\n");
+      result = 1;
+    }
+
+  if (mq_unlink (name) != 0)
+    {
+      printf ("mq_unlink failed with: %m\n");
+      result = 1;
+    }
+
+  if (mq_close (q) != 0)
+    {
+      printf ("mq_close failed with: %m\n");
+      result = 1;
+    }
+
+  return result;
+}
+
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-mutex1.c b/test/nptl/tst-mutex1.c
new file mode 100644 (file)
index 0000000..50b5cca
--- /dev/null
@@ -0,0 +1,57 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with 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>
+
+
+static int
+do_test (void)
+{
+  pthread_mutex_t m;
+
+  if (pthread_mutex_init (&m, NULL) != 0)
+    {
+      puts ("mutex_init failed");
+      return 1;
+    }
+
+  if (pthread_mutex_lock (&m) != 0)
+    {
+      puts ("mutex_lock failed");
+      return 1;
+    }
+
+  if (pthread_mutex_unlock (&m) != 0)
+    {
+      puts ("mutex_unlock failed");
+      return 1;
+    }
+
+  if (pthread_mutex_destroy (&m) != 0)
+    {
+      puts ("mutex_destroy failed");
+      return 1;
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-mutex2.c b/test/nptl/tst-mutex2.c
new file mode 100644 (file)
index 0000000..f589a1e
--- /dev/null
@@ -0,0 +1,223 @@
+/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+static pthread_mutex_t m;
+static pthread_barrier_t b;
+
+
+static void *
+tf (void *arg)
+{
+  int e = pthread_mutex_unlock (&m);
+  if (e == 0)
+    {
+      puts ("child: 1st mutex_unlock succeeded");
+      exit (1);
+    }
+  else if (e != EPERM)
+    {
+      puts ("child: 1st mutex_unlock error != EPERM");
+      exit (1);
+    }
+
+  e = pthread_mutex_trylock (&m);
+  if (e == 0)
+    {
+      puts ("child: 1st trylock suceeded");
+      exit (1);
+    }
+  if (e != EBUSY)
+    {
+      puts ("child: 1st trylock didn't return EBUSY");
+      exit (1);
+    }
+
+  e = pthread_barrier_wait (&b);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("child: 1st barrier_wait failed");
+      exit (1);
+    }
+
+  e = pthread_barrier_wait (&b);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("child: 2nd barrier_wait failed");
+      exit (1);
+    }
+
+  e = pthread_mutex_unlock (&m);
+  if (e == 0)
+    {
+      puts ("child: 2nd mutex_unlock succeeded");
+      exit (1);
+    }
+  else if (e != EPERM)
+    {
+      puts ("child: 2nd mutex_unlock error != EPERM");
+      exit (1);
+    }
+
+  if (pthread_mutex_trylock (&m) != 0)
+    {
+      puts ("child: 2nd trylock failed");
+      exit (1);
+    }
+
+  if (pthread_mutex_unlock (&m) != 0)
+    {
+      puts ("child: 3rd mutex_unlock failed");
+      exit (1);
+    }
+
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  pthread_mutexattr_t a;
+  int e;
+
+  if (pthread_mutexattr_init (&a) != 0)
+    {
+      puts ("mutexattr_init failed");
+      exit (1);
+    }
+
+  if (pthread_mutexattr_settype (&a, PTHREAD_MUTEX_ERRORCHECK) != 0)
+    {
+      puts ("mutexattr_settype failed");
+      exit (1);
+    }
+
+  if (pthread_mutex_init (&m, &a) != 0)
+    {
+      puts ("mutex_init failed");
+      exit (1);
+    }
+
+  if (pthread_barrier_init (&b, NULL, 2) != 0)
+    {
+      puts ("barrier_init failed");
+      exit (1);
+    }
+
+  if ((e = pthread_mutex_unlock (&m)) == 0)
+    {
+      puts ("1st mutex_unlock succeeded");
+      exit (1);
+    }
+  else if (e != EPERM)
+    {
+      puts ("1st mutex_unlock error != EPERM");
+      exit (1);
+    }
+
+  if (pthread_mutex_lock (&m) != 0)
+    {
+      puts ("mutex_lock failed");
+      exit (1);
+    }
+
+  if ((e = pthread_mutex_lock (&m)) == 0)
+    {
+      puts ("2nd mutex_lock succeeded");
+      exit (1);
+    }
+  else if (e != EDEADLK)
+    {
+      puts ("2nd mutex_lock error != EDEADLK");
+      exit (1);
+    }
+
+  pthread_t th;
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("create failed");
+      exit (1);
+    }
+
+  e = pthread_barrier_wait (&b);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("1st barrier_wait failed");
+      exit (1);
+    }
+
+  if (pthread_mutex_unlock (&m) != 0)
+    {
+      puts ("2nd mutex_unlock failed");
+      exit (1);
+    }
+
+  if ((e = pthread_mutex_unlock (&m)) == 0)
+    {
+      puts ("3rd mutex_unlock succeeded");
+      exit (1);
+    }
+  else if (e != EPERM)
+    {
+      puts ("3rd mutex_unlock error != EPERM");
+      exit (1);
+    }
+
+  e = pthread_barrier_wait (&b);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("2nd barrier_wait failed");
+      exit (1);
+    }
+
+  if (pthread_join (th, NULL) != 0)
+    {
+      puts ("join failed");
+      exit (1);
+    }
+
+  if (pthread_mutex_destroy (&m) != 0)
+    {
+      puts ("mutex_destroy failed");
+      exit (1);
+    }
+
+  if (pthread_barrier_destroy (&b) != 0)
+    {
+      puts ("barrier_destroy failed");
+      exit (1);
+    }
+
+  if (pthread_mutexattr_destroy (&a) != 0)
+    {
+      puts ("mutexattr_destroy failed");
+      exit (1);
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-mutex3.c b/test/nptl/tst-mutex3.c
new file mode 100644 (file)
index 0000000..8e57924
--- /dev/null
@@ -0,0 +1,225 @@
+/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+static pthread_mutex_t m;
+static pthread_barrier_t b;
+
+
+static void *
+tf (void *arg)
+{
+  int e = pthread_mutex_unlock (&m);
+  if (e == 0)
+    {
+      puts ("1st mutex_unlock in child succeeded");
+      exit (1);
+    }
+  if (e != EPERM)
+    {
+      puts ("1st mutex_unlock in child didn't return EPERM");
+      exit (1);
+    }
+
+  e = pthread_mutex_trylock (&m);
+  if (e == 0)
+    {
+      puts ("mutex_trylock in second thread succeeded");
+      exit (1);
+    }
+  if (e != EBUSY)
+    {
+      puts ("mutex_trylock returned wrong value");
+      exit (1);
+    }
+
+  e = pthread_barrier_wait (&b);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("barrier_wait failed");
+      exit (1);
+    }
+
+  e = pthread_barrier_wait (&b);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("barrier_wait failed");
+      exit (1);
+    }
+
+  e = pthread_mutex_unlock (&m);
+  if (e == 0)
+    {
+      puts ("2nd mutex_unlock in child succeeded");
+      exit (1);
+    }
+  if (e != EPERM)
+    {
+      puts ("2nd mutex_unlock in child didn't return EPERM");
+      exit (1);
+    }
+
+  if (pthread_mutex_trylock (&m) != 0)
+    {
+      puts ("2nd mutex_trylock in second thread failed");
+      exit (1);
+    }
+
+  if (pthread_mutex_unlock (&m) != 0)
+    {
+      puts ("3rd mutex_unlock in second thread failed");
+      exit (1);
+    }
+
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  pthread_mutexattr_t a;
+
+  if (pthread_mutexattr_init (&a) != 0)
+    {
+      puts ("mutexattr_init failed");
+      return 1;
+    }
+
+  if (pthread_mutexattr_settype (&a, PTHREAD_MUTEX_RECURSIVE) != 0)
+    {
+      puts ("mutexattr_settype failed");
+      return 1;
+    }
+
+  if (pthread_mutex_init (&m, &a) != 0)
+    {
+      puts ("mutex_init failed");
+      return 1;
+    }
+
+  if (pthread_barrier_init (&b, NULL, 2) != 0)
+    {
+      puts ("barrier_init failed");
+      return 1;
+    }
+
+  if (pthread_mutex_lock (&m) != 0)
+    {
+      puts ("mutex_lock failed");
+      return 1;
+    }
+
+  if (pthread_mutex_lock (&m) != 0)
+    {
+      puts ("2nd mutex_lock failed");
+      return 1;
+    }
+
+  if (pthread_mutex_trylock (&m) != 0)
+    {
+      puts ("1st trylock failed");
+      return 1;
+    }
+
+  if (pthread_mutex_unlock (&m) != 0)
+    {
+      puts ("mutex_unlock failed");
+      return 1;
+    }
+
+  if (pthread_mutex_unlock (&m) != 0)
+    {
+      puts ("2nd mutex_unlock failed");
+      return 1;
+    }
+
+  pthread_t th;
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("create failed");
+      return 1;
+    }
+
+  int e = pthread_barrier_wait (&b);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("barrier_wait failed");
+      return 1;
+    }
+
+  if (pthread_mutex_unlock (&m) != 0)
+    {
+      puts ("3rd mutex_unlock failed");
+      return 1;
+    }
+
+  e = pthread_mutex_unlock (&m);
+  if (e == 0)
+    {
+      puts ("4th mutex_unlock succeeded");
+      return 1;
+    }
+  if (e != EPERM)
+    {
+      puts ("4th mutex_unlock didn't return EPERM");
+      return 1;
+    }
+
+  e = pthread_barrier_wait (&b);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("barrier_wait failed");
+      return 1;
+    }
+
+  if (pthread_join (th, NULL) != 0)
+    {
+      puts ("join failed");
+      return 1;
+    }
+
+  if (pthread_barrier_destroy (&b) != 0)
+    {
+      puts ("barrier_destroy failed");
+      return 1;
+    }
+
+  if (pthread_mutex_destroy (&m) != 0)
+    {
+      puts ("mutex_destroy failed");
+      return 1;
+    }
+
+  if (pthread_mutexattr_destroy (&a) != 0)
+    {
+      puts ("mutexattr_destroy failed");
+      return 1;
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-mutex4.c b/test/nptl/tst-mutex4.c
new file mode 100644 (file)
index 0000000..0ce7313
--- /dev/null
@@ -0,0 +1,191 @@
+/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+
+
+static int
+do_test (void)
+{
+  size_t ps = sysconf (_SC_PAGESIZE);
+  char tmpfname[] = "/tmp/tst-mutex4.XXXXXX";
+  char data[ps];
+  void *mem;
+  int fd;
+  pthread_mutex_t *m;
+  pthread_mutexattr_t a;
+  pid_t pid;
+  char *p;
+  int err;
+  int s;
+
+  fd = mkstemp (tmpfname);
+  if (fd == -1)
+    {
+      printf ("cannot open temporary file: %m\n");
+      return 1;
+    }
+
+  /* Make sure it is always removed.  */
+  unlink (tmpfname);
+
+  /* Create one page of data.  */
+  memset (data, '\0', ps);
+
+  /* Write the data to the file.  */
+  if (write (fd, data, ps) != (ssize_t) ps)
+    {
+      puts ("short write");
+      return 1;
+    }
+
+  mem = mmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+  if (mem == MAP_FAILED)
+    {
+      printf ("mmap failed: %m\n");
+      return 1;
+    }
+
+  m = (pthread_mutex_t *) (((uintptr_t) mem + __alignof (pthread_mutex_t))
+                          & ~(__alignof (pthread_mutex_t) - 1));
+  p = (char *) (m + 1);
+
+  if (pthread_mutexattr_init (&a) != 0)
+    {
+      puts ("mutexattr_init failed");
+      return 1;
+    }
+
+  if (pthread_mutexattr_getpshared (&a, &s) != 0)
+    {
+      puts ("1st mutexattr_getpshared failed");
+      return 1;
+    }
+
+  if (s != PTHREAD_PROCESS_PRIVATE)
+    {
+      puts ("default pshared value wrong");
+      return 1;
+    }
+
+  if (pthread_mutexattr_setpshared (&a, PTHREAD_PROCESS_SHARED) != 0)
+    {
+      puts ("mutexattr_setpshared failed");
+      return 1;
+    }
+
+  if (pthread_mutexattr_getpshared (&a, &s) != 0)
+    {
+      puts ("2nd mutexattr_getpshared failed");
+      return 1;
+    }
+
+  if (s != PTHREAD_PROCESS_SHARED)
+    {
+      puts ("pshared value after setpshared call wrong");
+      return 1;
+    }
+
+  if (pthread_mutex_init (m, &a) != 0)
+    {
+      puts ("mutex_init failed");
+      return 1;
+    }
+
+  if (pthread_mutex_lock (m) != 0)
+    {
+      puts ("mutex_lock failed");
+      return 1;
+    }
+
+  if (pthread_mutexattr_destroy (&a) != 0)
+    {
+      puts ("mutexattr_destroy failed");
+      return 1;
+    }
+
+  err = pthread_mutex_trylock (m);
+  if (err == 0)
+    {
+      puts ("mutex_trylock succeeded");
+      return 1;
+    }
+  else if (err != EBUSY)
+    {
+      puts ("mutex_trylock didn't return EBUSY");
+      return 1;
+    }
+
+  *p = 0;
+
+  puts ("going to fork now");
+  pid = fork ();
+  if (pid == -1)
+    {
+      puts ("fork failed");
+      return 1;
+    }
+  else if (pid == 0)
+    {
+      /* Play some lock ping-pong.  It's our turn to unlock first.  */
+      if ((*p)++ != 0)
+       {
+         puts ("child: *p != 0");
+         return 1;
+       }
+
+      if (pthread_mutex_unlock (m) != 0)
+       {
+         puts ("child: 1st mutex_unlock failed");
+         return 1;
+       }
+
+      puts ("child done");
+    }
+  else
+    {
+      if (pthread_mutex_lock (m) != 0)
+       {
+         puts ("parent: 2nd mutex_lock failed");
+         return 1;
+       }
+
+      if (*p != 1)
+       {
+         puts ("*p != 1");
+         return 1;
+       }
+
+      puts ("parent done");
+    }
+
+  return 0;
+}
+
+#define TIMEOUT 4
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-mutex5.c b/test/nptl/tst-mutex5.c
new file mode 100644 (file)
index 0000000..eb35b78
--- /dev/null
@@ -0,0 +1,186 @@
+/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/time.h>
+
+
+#ifndef TYPE
+# define TYPE PTHREAD_MUTEX_NORMAL
+#endif
+
+
+static int
+do_test (void)
+{
+  pthread_mutex_t m;
+  struct timespec ts;
+  struct timeval tv;
+  struct timeval tv2;
+  int err;
+  pthread_mutexattr_t a;
+
+  if (pthread_mutexattr_init (&a) != 0)
+    {
+      puts ("mutexattr_init failed");
+      return 1;
+    }
+
+  if (pthread_mutexattr_settype (&a, TYPE) != 0)
+    {
+      puts ("mutexattr_settype failed");
+      return 1;
+    }
+
+  if (pthread_mutex_init (&m, &a) != 0)
+    {
+      puts ("mutex_init failed");
+      return 1;
+    }
+
+  if (pthread_mutexattr_destroy (&a) != 0)
+    {
+      puts ("mutexattr_destroy failed");
+      return 1;
+    }
+
+  if (pthread_mutex_lock (&m) != 0)
+    {
+      puts ("mutex_lock failed");
+      return 1;
+    }
+
+  if (pthread_mutex_trylock (&m) == 0)
+    {
+      puts ("mutex_trylock succeeded");
+      return 1;
+    }
+
+  gettimeofday (&tv, NULL);
+  TIMEVAL_TO_TIMESPEC (&tv, &ts);
+
+  ts.tv_sec += 2;      /* Wait 2 seconds.  */
+
+  err = pthread_mutex_timedlock (&m, &ts);
+  if (err == 0)
+    {
+      puts ("timedlock succeeded");
+      return 1;
+    }
+  else if (err != ETIMEDOUT)
+    {
+      printf ("timedlock error != ETIMEDOUT: %d\n", err);
+      return 1;
+    }
+  else
+    {
+      int clk_tck = sysconf (_SC_CLK_TCK);
+
+      gettimeofday (&tv2, NULL);
+
+      tv2.tv_sec -= tv.tv_sec;
+      tv2.tv_usec -= tv.tv_usec;
+      if (tv2.tv_usec < 0)
+       {
+         tv2.tv_usec += 1000000;
+         tv2.tv_sec -= 1;
+       }
+
+      /* Be a bit tolerant, add one CLK_TCK.  */
+      tv2.tv_usec += 1000000 / clk_tck;
+      if (tv2.tv_usec >= 1000000)
+       {
+         tv2.tv_usec -= 1000000;
+         ++tv2.tv_sec;
+       }
+
+      if (tv2.tv_sec < 2)
+       {
+         printf ("premature timeout: %ld.%06ld difference\n",
+                 tv2.tv_sec, tv2.tv_usec);
+         return 1;
+       }
+    }
+
+  (void) gettimeofday (&tv, NULL);
+  TIMEVAL_TO_TIMESPEC (&tv, &ts);
+
+  ts.tv_sec += 2;      /* Wait 2 seconds.  */
+  /* The following makes the ts value invalid.  */
+  ts.tv_nsec += 1000000000;
+
+  err = pthread_mutex_timedlock (&m, &ts);
+  if (err == 0)
+    {
+      puts ("2nd timedlock succeeded");
+      return 1;
+    }
+  else if (err != EINVAL)
+    {
+      printf ("2nd timedlock error != EINVAL: %d\n", err);
+      return 1;
+    }
+
+  if (pthread_mutex_unlock (&m) != 0)
+    {
+      puts ("mutex_unlock failed");
+      return 1;
+    }
+
+  (void) gettimeofday (&tv, NULL);
+  TIMEVAL_TO_TIMESPEC (&tv, &ts);
+
+  ts.tv_sec += 2;      /* Wait 2 seconds.  */
+  if (pthread_mutex_timedlock (&m, &ts) != 0)
+    {
+      puts ("3rd timedlock failed");
+    }
+
+  (void) gettimeofday (&tv2, NULL);
+
+  /* Check that timedlock didn't delay.  We use a limit of 0.1 secs.  */
+  timersub (&tv2, &tv, &tv2);
+  if (tv2.tv_sec > 0 || tv2.tv_usec > 100000)
+    {
+      puts ("3rd timedlock didn't return right away");
+      return 1;
+    }
+
+  if (pthread_mutex_unlock (&m) != 0)
+    {
+      puts ("final mutex_unlock failed");
+      return 1;
+    }
+
+  if (pthread_mutex_destroy (&m) != 0)
+    {
+      puts ("mutex_destroy failed");
+      return 1;
+    }
+
+  return 0;
+}
+
+#define TIMEOUT 4
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-mutex5a.c b/test/nptl/tst-mutex5a.c
new file mode 100644 (file)
index 0000000..f91eec0
--- /dev/null
@@ -0,0 +1,2 @@
+#define TYPE PTHREAD_MUTEX_ADAPTIVE_NP
+#include "tst-mutex5.c"
diff --git a/test/nptl/tst-mutex6.c b/test/nptl/tst-mutex6.c
new file mode 100644 (file)
index 0000000..f066c62
--- /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 <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <unistd.h>
+
+
+static int
+do_test (void)
+{
+  pthread_mutex_t m;
+
+  if (pthread_mutex_init (&m, NULL) != 0)
+    {
+      puts ("mutex_init failed");
+      return 1;
+    }
+
+  if (pthread_mutex_lock (&m) != 0)
+    {
+      puts ("1st mutex_lock failed");
+      return 1;
+    }
+
+  /* Set an alarm for 1 second.  The wrapper will expect this.  */
+  alarm (1);
+
+  /* This call should never return.  */
+  pthread_mutex_lock (&m);
+
+  puts ("2nd mutex_lock returned");
+  return 1;
+}
+
+#define EXPECTED_SIGNAL SIGALRM
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-mutex7.c b/test/nptl/tst-mutex7.c
new file mode 100644 (file)
index 0000000..a9b9f31
--- /dev/null
@@ -0,0 +1,121 @@
+/* Copyright (C) 2002, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <time.h>
+
+
+#ifndef INIT
+# define INIT PTHREAD_MUTEX_INITIALIZER
+#endif
+
+
+static pthread_mutex_t lock = INIT;
+
+
+#define ROUNDS 1000
+#define N 100
+
+
+static void *
+tf (void *arg)
+{
+  int nr = (long int) arg;
+  int cnt;
+  struct timespec ts = { .tv_sec = 0, .tv_nsec = 11000 };
+
+  for (cnt = 0; cnt < ROUNDS; ++cnt)
+    {
+      if (pthread_mutex_lock (&lock) != 0)
+       {
+         printf ("thread %d: failed to get the lock\n", nr);
+         return (void *) 1l;
+       }
+
+      if (pthread_mutex_unlock (&lock) != 0)
+       {
+         printf ("thread %d: failed to release the lock\n", nr);
+         return (void *) 1l;
+       }
+
+      nanosleep (&ts, NULL);
+    }
+
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  pthread_attr_t at;
+  pthread_t th[N];
+  int cnt;
+
+  if (pthread_attr_init (&at) != 0)
+    {
+      puts ("attr_init failed");
+      return 1;
+    }
+
+  if (pthread_attr_setstacksize (&at, 1 * 1024 * 1024) != 0)
+    {
+      puts ("attr_setstacksize failed");
+      return 1;
+    }
+
+  if (pthread_mutex_lock (&lock) != 0)
+    {
+      puts ("locking in parent failed");
+      return 1;
+    }
+
+  for (cnt = 0; cnt < N; ++cnt)
+    if (pthread_create (&th[cnt], &at, tf, (void *) (long int) cnt) != 0)
+      {
+       printf ("creating thread %d failed\n", cnt);
+       return 1;
+      }
+
+  if (pthread_attr_destroy (&at) != 0)
+    {
+      puts ("attr_destroy failed");
+      return 1;
+    }
+
+  if (pthread_mutex_unlock (&lock) != 0)
+    {
+      puts ("unlocking in parent failed");
+      return 1;
+    }
+
+  for (cnt = 0; cnt < N; ++cnt)
+    if (pthread_join (th[cnt], NULL) != 0)
+      {
+       printf ("joining thread %d failed\n", cnt);
+       return 1;
+      }
+
+  return 0;
+}
+
+#define TIMEOUT 60
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-mutex7a.c b/test/nptl/tst-mutex7a.c
new file mode 100644 (file)
index 0000000..f08799a
--- /dev/null
@@ -0,0 +1,2 @@
+#define INIT PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
+#include "tst-mutex7.c"
diff --git a/test/nptl/tst-mutex8.c b/test/nptl/tst-mutex8.c
new file mode 100644 (file)
index 0000000..80ebe71
--- /dev/null
@@ -0,0 +1,367 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* This test checks behavior not required by POSIX.  */
+#include <errno.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+static pthread_mutex_t *m;
+static pthread_barrier_t b;
+static pthread_cond_t c;
+static bool done;
+
+
+static void
+cl (void *arg)
+{
+  if (pthread_mutex_unlock (m) != 0)
+    {
+      puts ("cl: mutex_unlocked failed");
+      exit (1);
+    }
+}
+
+
+static void *
+tf (void *arg)
+{
+  if (pthread_mutex_lock (m) != 0)
+    {
+      puts ("tf: mutex_lock failed");
+      return (void *) 1l;
+    }
+
+  int e = pthread_barrier_wait (&b);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("barrier_wait failed");
+      return (void *) 1l;
+    }
+
+  if (arg == NULL)
+    do
+      if (pthread_cond_wait (&c, m) != 0)
+       {
+         puts ("tf: cond_wait failed");
+         return (void *) 1l;
+       }
+    while (! done);
+  else
+    do
+      {
+       pthread_cleanup_push (cl, NULL);
+
+       if (pthread_cond_wait (&c, m) != 0)
+         {
+           puts ("tf: cond_wait failed");
+           return (void *) 1l;
+         }
+
+       pthread_cleanup_pop (0);
+      }
+    while (! done);
+
+  if (pthread_mutex_unlock (m) != 0)
+    {
+      puts ("tf: mutex_unlock failed");
+      return (void *) 1l;
+    }
+
+  return NULL;
+}
+
+
+static int
+check_type (const char *mas, pthread_mutexattr_t *ma)
+{
+  if (pthread_mutex_init (m, ma) != 0)
+    {
+      printf ("1st mutex_init failed for %s\n", mas);
+      return 1;
+    }
+
+  if (pthread_mutex_destroy (m) != 0)
+    {
+      printf ("immediate mutex_destroy failed for %s\n", mas);
+      return 1;
+    }
+
+  if (pthread_mutex_init (m, ma) != 0)
+    {
+      printf ("2nd mutex_init failed for %s\n", mas);
+      return 1;
+    }
+
+  if (pthread_mutex_lock (m) != 0)
+    {
+      printf ("1st mutex_lock failed for %s\n", mas);
+      return 1;
+    }
+
+  int e = pthread_mutex_destroy (m);
+  if (e == 0)
+    {
+      printf ("mutex_destroy of self-locked mutex succeeded for %s\n", mas);
+      return 1;
+    }
+  if (e != EBUSY)
+    {
+      printf ("mutex_destroy of self-locked mutex did not return EBUSY %s\n",
+             mas);
+      return 1;
+    }
+
+  if (pthread_mutex_unlock (m) != 0)
+    {
+      printf ("1st mutex_unlock failed for %s\n", mas);
+      return 1;
+    }
+
+  if (pthread_mutex_trylock (m) != 0)
+    {
+      printf ("mutex_trylock failed for %s\n", mas);
+      return 1;
+    }
+
+  e = pthread_mutex_destroy (m);
+  if (e == 0)
+    {
+      printf ("mutex_destroy of self-trylocked mutex succeeded for %s\n", mas);
+      return 1;
+    }
+  if (e != EBUSY)
+    {
+      printf ("\
+mutex_destroy of self-trylocked mutex did not return EBUSY %s\n",
+             mas);
+      return 1;
+    }
+
+  if (pthread_mutex_unlock (m) != 0)
+    {
+      printf ("2nd mutex_unlock failed for %s\n", mas);
+      return 1;
+    }
+
+  pthread_t th;
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("1st create failed");
+      return 1;
+    }
+  done = false;
+
+  e = pthread_barrier_wait (&b);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("1st barrier_wait failed");
+      return 1;
+    }
+
+  if (pthread_mutex_lock (m) != 0)
+    {
+      printf ("2nd mutex_lock failed for %s\n", mas);
+      return 1;
+    }
+
+  if (pthread_mutex_unlock (m) != 0)
+    {
+      printf ("3rd mutex_unlock failed for %s\n", mas);
+      return 1;
+    }
+
+  e = pthread_mutex_destroy (m);
+  if (e == 0)
+    {
+      printf ("mutex_destroy of condvar-used mutex succeeded for %s\n", mas);
+      return 1;
+    }
+  if (e != EBUSY)
+    {
+      printf ("\
+mutex_destroy of condvar-used mutex did not return EBUSY for %s\n", mas);
+      return 1;
+    }
+
+  done = true;
+  if (pthread_cond_signal (&c) != 0)
+    {
+      puts ("cond_signal failed");
+      return 1;
+    }
+
+  void *r;
+  if (pthread_join (th, &r) != 0)
+    {
+      puts ("join failed");
+      return 1;
+    }
+  if (r != NULL)
+    {
+      puts ("thread didn't return NULL");
+      return 1;
+    }
+
+  if (pthread_mutex_destroy (m) != 0)
+    {
+      printf ("mutex_destroy after condvar-use failed for %s\n", mas);
+      return 1;
+    }
+
+  if (pthread_mutex_init (m, ma) != 0)
+    {
+      printf ("3rd mutex_init failed for %s\n", mas);
+      return 1;
+    }
+
+  if (pthread_create (&th, NULL, tf, (void *) 1) != 0)
+    {
+      puts ("2nd create failed");
+      return 1;
+    }
+  done = false;
+
+  e = pthread_barrier_wait (&b);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("2nd barrier_wait failed");
+      return 1;
+    }
+
+  if (pthread_mutex_lock (m) != 0)
+    {
+      printf ("3rd mutex_lock failed for %s\n", mas);
+      return 1;
+    }
+
+  if (pthread_mutex_unlock (m) != 0)
+    {
+      printf ("4th mutex_unlock failed for %s\n", mas);
+      return 1;
+    }
+
+  e = pthread_mutex_destroy (m);
+  if (e == 0)
+    {
+      printf ("2nd mutex_destroy of condvar-used mutex succeeded for %s\n",
+             mas);
+      return 1;
+    }
+  if (e != EBUSY)
+    {
+      printf ("\
+2nd mutex_destroy of condvar-used mutex did not return EBUSY for %s\n",
+             mas);
+      return 1;
+    }
+
+  if (pthread_cancel (th) != 0)
+    {
+      puts ("cond_cancel failed");
+      return 1;
+    }
+
+  if (pthread_join (th, &r) != 0)
+    {
+      puts ("join failed");
+      return 1;
+    }
+  if (r != PTHREAD_CANCELED)
+    {
+      puts ("thread not canceled");
+      return 1;
+    }
+
+  if (pthread_mutex_destroy (m) != 0)
+    {
+      printf ("mutex_destroy after condvar-canceled failed for %s\n", mas);
+      return 1;
+    }
+
+  return 0;
+}
+
+
+static int
+do_test (void)
+{
+  pthread_mutex_t mm;
+  m = &mm;
+
+  if (pthread_barrier_init (&b, NULL, 2) != 0)
+    {
+      puts ("barrier_init failed");
+      return 1;
+    }
+
+  if (pthread_cond_init (&c, NULL) != 0)
+    {
+      puts ("cond_init failed");
+      return 1;
+    }
+
+  puts ("check normal mutex");
+  int res = check_type ("normal", NULL);
+
+  pthread_mutexattr_t ma;
+  if (pthread_mutexattr_init (&ma) != 0)
+    {
+      puts ("1st mutexattr_init failed");
+      return 1;
+    }
+  if (pthread_mutexattr_settype (&ma, PTHREAD_MUTEX_RECURSIVE) != 0)
+    {
+      puts ("1st mutexattr_settype failed");
+      return 1;
+    }
+  puts ("check recursive mutex");
+  res |= check_type ("recursive", &ma);
+  if (pthread_mutexattr_destroy (&ma) != 0)
+    {
+      puts ("1st mutexattr_destroy failed");
+      return 1;
+    }
+
+  if (pthread_mutexattr_init (&ma) != 0)
+    {
+      puts ("2nd mutexattr_init failed");
+      return 1;
+    }
+  if (pthread_mutexattr_settype (&ma, PTHREAD_MUTEX_ERRORCHECK) != 0)
+    {
+      puts ("2nd mutexattr_settype failed");
+      return 1;
+    }
+  puts ("check error-checking mutex");
+  res |= check_type ("error-checking", &ma);
+  if (pthread_mutexattr_destroy (&ma) != 0)
+    {
+      puts ("2nd mutexattr_destroy failed");
+      return 1;
+    }
+
+  return res;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-mutex9.c b/test/nptl/tst-mutex9.c
new file mode 100644 (file)
index 0000000..3748584
--- /dev/null
@@ -0,0 +1,191 @@
+/* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/time.h>
+
+int gettimeofday(struct timeval *tv, struct timezone *tz);
+
+
+static int
+do_test (void)
+{
+  size_t ps = sysconf (_SC_PAGESIZE);
+  char tmpfname[] = "/tmp/tst-mutex9.XXXXXX";
+  char data[ps];
+  void *mem;
+  int fd;
+  pthread_mutex_t *m;
+  pthread_mutexattr_t a;
+  pid_t pid;
+  char *p;
+
+  fd = mkstemp (tmpfname);
+  if (fd == -1)
+    {
+      printf ("cannot open temporary file: %m\n");
+      return 1;
+    }
+
+  /* Make sure it is always removed.  */
+  unlink (tmpfname);
+
+  /* Create one page of data.  */
+  memset (data, '\0', ps);
+
+  /* Write the data to the file.  */
+  if (write (fd, data, ps) != (ssize_t) ps)
+    {
+      puts ("short write");
+      return 1;
+    }
+
+  mem = mmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+  if (mem == MAP_FAILED)
+    {
+      printf ("mmap failed: %m\n");
+      return 1;
+    }
+
+  m = (pthread_mutex_t *) (((uintptr_t) mem + __alignof (pthread_mutex_t))
+                          & ~(__alignof (pthread_mutex_t) - 1));
+  p = (char *) (m + 1);
+
+  if (pthread_mutexattr_init (&a) != 0)
+    {
+      puts ("mutexattr_init failed");
+      return 1;
+    }
+
+  if (pthread_mutexattr_setpshared (&a, PTHREAD_PROCESS_SHARED) != 0)
+    {
+      puts ("mutexattr_setpshared failed");
+      return 1;
+    }
+
+  if (pthread_mutexattr_settype (&a, PTHREAD_MUTEX_RECURSIVE) != 0)
+    {
+      puts ("mutexattr_settype failed");
+      return 1;
+    }
+
+  if (pthread_mutex_init (m, &a) != 0)
+    {
+      puts ("mutex_init failed");
+      return 1;
+    }
+
+  if (pthread_mutex_lock (m) != 0)
+    {
+      puts ("mutex_lock failed");
+      return 1;
+    }
+
+  if (pthread_mutexattr_destroy (&a) != 0)
+    {
+      puts ("mutexattr_destroy failed");
+      return 1;
+    }
+
+  puts ("going to fork now");
+  pid = fork ();
+  if (pid == -1)
+    {
+      puts ("fork failed");
+      return 1;
+    }
+  else if (pid == 0)
+    {
+      if (pthread_mutex_trylock (m) == 0)
+       {
+         puts ("child: mutex_trylock succeeded");
+         exit (1);
+       }
+
+      if (pthread_mutex_unlock (m) == 0)
+       {
+         puts ("child: mutex_unlock succeeded");
+         exit (1);
+       }
+
+      struct timeval tv;
+      gettimeofday (&tv, NULL);
+      struct timespec ts;
+      TIMEVAL_TO_TIMESPEC (&tv, &ts);
+      ts.tv_nsec += 500000000;
+      if (ts.tv_nsec >= 1000000000)
+       {
+         ++ts.tv_sec;
+         ts.tv_nsec -= 1000000000;
+       }
+
+      int e = pthread_mutex_timedlock (m, &ts);
+      if (e == 0)
+       {
+         puts ("child: mutex_timedlock succeeded");
+         exit (1);
+       }
+      if (e != ETIMEDOUT)
+       {
+         puts ("child: mutex_timedlock didn't time out");
+         exit (1);
+       }
+
+      alarm (1);
+
+      pthread_mutex_lock (m);
+
+      puts ("child: mutex_lock returned");
+
+      exit (0);
+    }
+
+  sleep (2);
+
+  int status;
+  if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid)
+    {
+      puts ("waitpid failed");
+      return 1;
+    }
+  if (! WIFSIGNALED (status))
+    {
+      puts ("child not killed by signal");
+      return 1;
+    }
+  if (WTERMSIG (status) != SIGALRM)
+    {
+      puts ("child not killed by SIGALRM");
+      return 1;
+    }
+
+  return 0;
+}
+
+#define TIMEOUT 3
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-once1.c b/test/nptl/tst-once1.c
new file mode 100644 (file)
index 0000000..87ed51c
--- /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 <pthread.h>
+#include <stdio.h>
+
+
+static pthread_once_t once = PTHREAD_ONCE_INIT;
+
+static int global;
+
+static void
+once_handler (void)
+{
+  ++global;
+}
+
+
+static int
+do_test (void)
+{
+  pthread_once (&once, once_handler);
+  pthread_once (&once, once_handler);
+
+  if (global != 1)
+    {
+      printf ("global = %d, expected 1\n", global);
+      return 1;
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-once2.c b/test/nptl/tst-once2.c
new file mode 100644 (file)
index 0000000..c606345
--- /dev/null
@@ -0,0 +1,104 @@
+/* Copyright (C) 2002, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+
+#define N 100
+
+static pthread_once_t once = PTHREAD_ONCE_INIT;
+
+static int global;
+
+static void
+once_handler (void)
+{
+  struct timespec ts;
+
+  ++global;
+
+  ts.tv_sec = 2;
+  ts.tv_nsec = 0;
+  nanosleep (&ts, NULL);
+}
+
+
+static void *
+tf (void *arg)
+{
+  pthread_once (&once, once_handler);
+
+  if (global != 1)
+    {
+      printf ("thread %ld: global == %d\n", (long int) arg, global);
+      exit (1);
+    }
+
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  pthread_attr_t at;
+  pthread_t th[N];
+  int cnt;
+
+  if (pthread_attr_init (&at) != 0)
+    {
+      puts ("attr_init failed");
+      return 1;
+    }
+
+  if (pthread_attr_setstacksize (&at, 1 * 1024 * 1024) != 0)
+    {
+      puts ("attr_setstacksize failed");
+      return 1;
+    }
+
+  for (cnt = 0; cnt < N; ++cnt)
+    if (pthread_create (&th[cnt], &at, tf, (void *) (long int) cnt) != 0)
+      {
+       printf ("creation of thread %d failed\n", cnt);
+       return 1;
+      }
+
+  if (pthread_attr_destroy (&at) != 0)
+    {
+      puts ("attr_destroy failed");
+      return 1;
+    }
+
+  for (cnt = 0; cnt < N; ++cnt)
+    if (pthread_join (th[cnt], NULL) != 0)
+      {
+       printf ("join of thread %d failed\n", cnt);
+       return 1;
+      }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#define TIMEOUT 4
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-once3.c b/test/nptl/tst-once3.c
new file mode 100644 (file)
index 0000000..43b354a
--- /dev/null
@@ -0,0 +1,162 @@
+/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+
+#define N 100
+
+static pthread_once_t once = PTHREAD_ONCE_INIT;
+
+static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
+static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
+
+static pthread_barrier_t bar;
+
+static int global;
+static int cl_called;
+
+static void
+once_handler1 (void)
+{
+  if (pthread_mutex_lock (&mut) != 0)
+    {
+      puts ("once_handler1: mutex_lock failed");
+      exit (1);
+    }
+  puts ("once_handler1: locked");
+
+  int r = pthread_barrier_wait (&bar);
+  if (r != 0 && r!= PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("once_handler1: barrier_wait failed");
+      exit (1);
+    }
+
+  pthread_cond_wait (&cond, &mut);
+
+  /* We should never get here.  */
+  exit (42);
+}
+
+static void
+once_handler2 (void)
+{
+  global = 1;
+}
+
+
+static void
+cl (void *arg)
+{
+  cl_called = 1;
+}
+
+
+static void *
+tf (void *arg)
+{
+  pthread_cleanup_push (cl, NULL)
+
+  pthread_once (&once, once_handler1);
+
+  pthread_cleanup_pop (0);
+
+  /* We should never get here.  */
+  puts ("pthread_once in tf returned");
+  exit (1);
+}
+
+
+static int
+do_test (void)
+{
+  pthread_t th;
+
+  if (pthread_barrier_init (&bar, NULL, 2) != 0)
+    {
+      puts ("barrier_init failed");
+      return 1;
+    }
+
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("first create failed");
+      return 1;
+    }
+
+  int r = pthread_barrier_wait (&bar);
+  if (r != 0 && r!= PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("barrier_wait failed");
+      return 1;
+    }
+
+  if (pthread_mutex_lock (&mut) != 0)
+    {
+      puts ("mutex_lock failed");
+      return 1;
+    }
+  /* We unlock the mutex so that we catch the case where the pthread_cond_wait
+     call incorrectly resumes and tries to get the mutex.  */
+  if (pthread_mutex_unlock (&mut) != 0)
+    {
+      puts ("mutex_unlock failed");
+      return 1;
+    }
+
+  /* Cancel the thread.  */
+  puts ("going to cancel");
+  if (pthread_cancel (th) != 0)
+    {
+      puts ("cancel failed");
+      return 1;
+    }
+
+  void *result;
+  pthread_join (th, &result);
+  if (result != PTHREAD_CANCELED)
+    {
+      puts ("join didn't return PTHREAD_CANCELED");
+      return 1;
+    }
+
+  if (cl_called != 1)
+    {
+      puts ("cleanup handler not called");
+      return 1;
+    }
+
+  pthread_once (&once, once_handler2);
+
+  if (global != 1)
+    {
+      puts ("global still 0");
+      return 1;
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#define TIMEOUT 4
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-once4.c b/test/nptl/tst-once4.c
new file mode 100644 (file)
index 0000000..35bae3c
--- /dev/null
@@ -0,0 +1,202 @@
+/* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+
+
+static pthread_once_t once = PTHREAD_ONCE_INIT;
+
+static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
+static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
+
+static pthread_barrier_t bar;
+
+static int global;
+static int cl_called;
+
+static void
+once_handler1 (void)
+{
+  if (pthread_mutex_lock (&mut) != 0)
+    {
+      puts ("once_handler1: mutex_lock failed");
+      exit (1);
+    }
+
+  int r = pthread_barrier_wait (&bar);
+  if (r != 0 && r!= PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("once_handler1: barrier_wait failed");
+      exit (1);
+    }
+
+  pthread_cond_wait (&cond, &mut);
+
+  /* We should never get here.  */
+}
+
+
+static void
+once_handler2 (void)
+{
+  global = 1;
+}
+
+
+static void
+cl (void *arg)
+{
+  ++cl_called;
+}
+
+
+static void *
+tf1 (void *arg)
+{
+  pthread_cleanup_push (cl, NULL);
+
+  pthread_once (&once, once_handler1);
+
+  pthread_cleanup_pop (0);
+
+  /* We should never get here.  */
+  puts ("pthread_once in tf returned");
+  exit (1);
+}
+
+
+static void *
+tf2 (void *arg)
+{
+  pthread_cleanup_push (cl, NULL);
+
+  int r = pthread_barrier_wait (&bar);
+  if (r != 0 && r!= PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("once_handler2: barrier_wait failed");
+      exit (1);
+    }
+
+  pthread_cleanup_pop (0);
+
+  pthread_once (&once, once_handler2);
+
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  pthread_t th[2];
+
+  if (pthread_barrier_init (&bar, NULL, 2) != 0)
+    {
+      puts ("barrier_init failed");
+      return 1;
+    }
+
+  if (pthread_create (&th[0], NULL, tf1, NULL) != 0)
+    {
+      puts ("first create failed");
+      return 1;
+    }
+
+  int r = pthread_barrier_wait (&bar);
+  if (r != 0 && r!= PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("first barrier_wait failed");
+      return 1;
+    }
+
+  if (pthread_mutex_lock (&mut) != 0)
+    {
+      puts ("mutex_lock failed");
+      return 1;
+    }
+  /* We unlock the mutex so that we catch the case where the pthread_cond_wait
+     call incorrectly resumes and tries to get the mutex.  */
+  if (pthread_mutex_unlock (&mut) != 0)
+    {
+      puts ("mutex_unlock failed");
+      return 1;
+    }
+
+  if (pthread_create (&th[1], NULL, tf2, NULL) != 0)
+    {
+      puts ("second create failed");
+      return 1;
+    }
+
+  r = pthread_barrier_wait (&bar);
+  if (r != 0 && r!= PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("second barrier_wait failed");
+      return 1;
+    }
+
+  /* Give the second thread a chance to reach the pthread_once call.  */
+  sleep (2);
+
+  /* Cancel the thread.  */
+  if (pthread_cancel (th[0]) != 0)
+    {
+      puts ("cancel failed");
+      return 1;
+    }
+
+  void *result;
+  pthread_join (th[0], &result);
+  if (result != PTHREAD_CANCELED)
+    {
+      puts ("first join didn't return PTHREAD_CANCELED");
+      return 1;
+    }
+
+  puts ("joined first thread");
+
+  pthread_join (th[1], &result);
+  if (result != NULL)
+    {
+      puts ("second join didn't return PTHREAD_CANCELED");
+      return 1;
+    }
+
+  if (global != 1)
+    {
+      puts ("global still 0");
+      return 1;
+    }
+
+  if (cl_called != 1)
+    {
+      printf ("cl_called = %d\n", cl_called);
+      return 1;
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#define TIMEOUT 4
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-popen1.c b/test/nptl/tst-popen1.c
new file mode 100644 (file)
index 0000000..a9d0773
--- /dev/null
@@ -0,0 +1,60 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <error.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static void *
+dummy (void *x)
+{
+  return NULL;
+}
+
+static char buf[sizeof "something\n"];
+
+static int
+do_test (void)
+{
+  FILE *f;
+  pthread_t p;
+  int err;
+
+  f = popen ("echo something", "r");
+  if (f == NULL)
+    error (EXIT_FAILURE, errno, "popen failed");
+  if (fgets (buf, sizeof (buf), f) == NULL)
+    error (EXIT_FAILURE, 0, "fgets failed");
+  if (strcmp (buf, "something\n"))
+    error (EXIT_FAILURE, 0, "read wrong data");
+  if (pclose (f))
+    error (EXIT_FAILURE, errno, "pclose returned non-zero");
+  if ((err = pthread_create (&p, NULL, dummy, NULL)))
+    error (EXIT_FAILURE, err, "pthread_create failed");
+  if ((err = pthread_join (p, NULL)))
+    error (EXIT_FAILURE, err, "pthread_join failed");
+  exit (0);
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-raise1.c b/test/nptl/tst-raise1.c
new file mode 100644 (file)
index 0000000..5ea9886
--- /dev/null
@@ -0,0 +1,62 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <error.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+volatile int count;
+
+void
+sh (int sig)
+{
+  ++count;
+}
+
+int
+main (void)
+{
+  struct sigaction sa;
+  sa.sa_handler = sh;
+  sigemptyset (&sa.sa_mask);
+  sa.sa_flags = 0;
+  if (sigaction (SIGUSR1, &sa, NULL) < 0)
+    {
+      printf ("sigaction failed: %m\n");
+      exit (1);
+    }
+  if (raise (SIGUSR1) < 0)
+    {
+      printf ("first raise failed: %m\n");
+      exit (1);
+    }
+  if (raise (SIGUSR1) < 0)
+    {
+      printf ("second raise failed: %m\n");
+      exit (1);
+    }
+  if (count != 2)
+    {
+      printf ("signal handler not called 2 times\n");
+      exit (1);
+    }
+  exit (0);
+}
diff --git a/test/nptl/tst-rwlock1.c b/test/nptl/tst-rwlock1.c
new file mode 100644 (file)
index 0000000..c97e0e6
--- /dev/null
@@ -0,0 +1,117 @@
+/* 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>
+
+
+static int
+do_test (void)
+{
+  pthread_rwlock_t r;
+
+  if (pthread_rwlock_init (&r, NULL) != 0)
+    {
+      puts ("rwlock_init failed");
+      return 1;
+    }
+  puts ("rwlock_init succeeded");
+
+  if (pthread_rwlock_rdlock (&r) != 0)
+    {
+      puts ("1st rwlock_rdlock failed");
+      return 1;
+    }
+  puts ("1st rwlock_rdlock succeeded");
+
+  if (pthread_rwlock_rdlock (&r) != 0)
+    {
+      puts ("2nd rwlock_rdlock failed");
+      return 1;
+    }
+  puts ("2nd rwlock_rdlock succeeded");
+
+  if (pthread_rwlock_unlock (&r) != 0)
+    {
+      puts ("1st rwlock_unlock failed");
+      return 1;
+    }
+  puts ("1st rwlock_unlock succeeded");
+
+  if (pthread_rwlock_unlock (&r) != 0)
+    {
+      puts ("2nd rwlock_unlock failed");
+      return 1;
+    }
+  puts ("2nd rwlock_unlock succeeded");
+
+  if (pthread_rwlock_wrlock (&r) != 0)
+    {
+      puts ("1st rwlock_wrlock failed");
+      return 1;
+    }
+  puts ("1st rwlock_wrlock succeeded");
+
+  if (pthread_rwlock_unlock (&r) != 0)
+    {
+      puts ("3rd rwlock_unlock failed");
+      return 1;
+    }
+  puts ("3rd rwlock_unlock succeeded");
+
+  if (pthread_rwlock_wrlock (&r) != 0)
+    {
+      puts ("2nd rwlock_wrlock failed");
+      return 1;
+    }
+  puts ("2nd rwlock_wrlock succeeded");
+
+  if (pthread_rwlock_unlock (&r) != 0)
+    {
+      puts ("4th rwlock_unlock failed");
+      return 1;
+    }
+  puts ("4th rwlock_unlock succeeded");
+
+  if (pthread_rwlock_rdlock (&r) != 0)
+    {
+      puts ("3rd rwlock_rdlock failed");
+      return 1;
+    }
+  puts ("3rd rwlock_rdlock succeeded");
+
+  if (pthread_rwlock_unlock (&r) != 0)
+    {
+      puts ("5th rwlock_unlock failed");
+      return 1;
+    }
+  puts ("5th rwlock_unlock succeeded");
+
+  if (pthread_rwlock_destroy (&r) != 0)
+    {
+      puts ("rwlock_destroy failed");
+      return 1;
+    }
+  puts ("rwlock_destroy succeeded");
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-rwlock10.c b/test/nptl/tst-rwlock10.c
new file mode 100644 (file)
index 0000000..43156ea
--- /dev/null
@@ -0,0 +1,21 @@
+/* Test program for timedout read/write lock functions.
+   Copyright (C) 2003 Free Software Foundation, Inc.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#define INIT PTHREAD_RWLOCK_INITIALIZER
+#include "tst-rwlock8.c"
diff --git a/test/nptl/tst-rwlock11.c b/test/nptl/tst-rwlock11.c
new file mode 100644 (file)
index 0000000..ed9af7e
--- /dev/null
@@ -0,0 +1,21 @@
+/* Test program for timedout read/write lock functions.
+   Copyright (C) 2003 Free Software Foundation, Inc.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#define INIT PTHREAD_RWLOCK_INITIALIZER
+#include "tst-rwlock9.c"
diff --git a/test/nptl/tst-rwlock12.c b/test/nptl/tst-rwlock12.c
new file mode 100644 (file)
index 0000000..91f25d3
--- /dev/null
@@ -0,0 +1,208 @@
+/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+
+
+static int
+do_test (void)
+{
+  size_t ps = sysconf (_SC_PAGESIZE);
+  char tmpfname[] = "/tmp/tst-rwlock12.XXXXXX";
+  char data[ps];
+  void *mem;
+  int fd;
+  pthread_mutex_t *m;
+  pthread_mutexattr_t ma;
+  pthread_rwlock_t *r;
+  pthread_rwlockattr_t ra;
+  pid_t pid;
+  int status = 0;
+
+  fd = mkstemp (tmpfname);
+  if (fd == -1)
+    {
+      printf ("cannot open temporary file: %m\n");
+      return 1;
+    }
+
+  /* Make sure it is always removed.  */
+  unlink (tmpfname);
+
+  /* Create one page of data.  */
+  memset (data, '\0', ps);
+
+  /* Write the data to the file.  */
+  if (write (fd, data, ps) != (ssize_t) ps)
+    {
+      puts ("short write");
+      return 1;
+    }
+
+  mem = mmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+  if (mem == MAP_FAILED)
+    {
+      printf ("mmap failed: %m\n");
+      return 1;
+    }
+
+  r = (pthread_rwlock_t *) (((uintptr_t) mem + __alignof (pthread_rwlock_t))
+                           & ~(__alignof (pthread_rwlock_t) - 1));
+  /* The following assumes alignment for a mutex is at least as high
+     as that for a rwlock.  Which is true in our case.  */
+  m = (pthread_mutex_t *) (r + 1);
+
+  if (pthread_rwlockattr_init (&ra) != 0)
+    {
+      puts ("rwlockattr_init failed");
+      return 1;
+    }
+
+  if (pthread_rwlockattr_setpshared (&ra, PTHREAD_PROCESS_SHARED) != 0)
+    {
+      puts ("rwlockattr_setpshared failed");
+      return 1;
+    }
+
+  if (pthread_rwlock_init (r, &ra) != 0)
+    {
+      puts ("rwlock_init failed");
+      return 1;
+    }
+
+  if (pthread_mutexattr_init (&ma) != 0)
+    {
+      puts ("rwlockattr_init failed");
+      return 1;
+    }
+
+  if (pthread_mutexattr_setpshared (&ma, PTHREAD_PROCESS_SHARED) != 0)
+    {
+      puts ("mutexattr_setpshared failed");
+      return 1;
+    }
+
+  if (pthread_mutex_init (m, &ma) != 0)
+    {
+      puts ("mutex_init failed");
+      return 1;
+    }
+
+  /* Lock the mutex.  */
+  if (pthread_mutex_lock (m) != 0)
+    {
+      puts ("mutex_lock failed");
+      return 1;
+    }
+
+  puts ("going to fork now");
+  pid = fork ();
+  if (pid == -1)
+    {
+      puts ("fork failed");
+      return 1;
+    }
+  else if (pid == 0)
+    {
+      /* Lock the mutex.  */
+      if (pthread_mutex_lock (m) != 0)
+       {
+         puts ("child: mutex_lock failed");
+         return 1;
+       }
+
+      /* Try to get the rwlock.  */
+      if (pthread_rwlock_trywrlock (r) == 0)
+       {
+         puts ("rwlock_trywrlock succeeded");
+         return 1;
+       }
+
+      /* Try again.  */
+      struct timespec ts = { .tv_sec = 0, .tv_nsec = 500000000 };
+      int e = pthread_rwlock_timedwrlock (r, &ts);
+      if (e == 0)
+       {
+         puts ("rwlock_timedwrlock succeeded");
+         return 1;
+       }
+      if (e != ETIMEDOUT)
+       {
+         puts ("rwlock_timedwrlock didn't return ETIMEDOUT");
+         status = 1;
+       }
+
+      if (pthread_rwlock_tryrdlock (r) == 0)
+       {
+         puts ("rwlock_tryrdlock succeeded");
+         return 1;
+       }
+
+      e = pthread_rwlock_timedrdlock (r, &ts);
+      if (e == 0)
+       {
+         puts ("rwlock_timedrdlock succeeded");
+         return 1;
+       }
+      if (e != ETIMEDOUT)
+       {
+         puts ("rwlock_timedrdlock didn't return ETIMEDOUT");
+         status = 1;
+       }
+    }
+  else
+    {
+      /* Lock the rwlock for writing.  */
+      if (pthread_rwlock_wrlock (r) != 0)
+       {
+         puts ("rwlock_wrlock failed");
+         kill (pid, SIGTERM);
+         return 1;
+       }
+
+      /* Allow the child to run.  */
+      if (pthread_mutex_unlock (m) != 0)
+       {
+         puts ("mutex_unlock failed");
+         kill (pid, SIGTERM);
+         return 1;
+       }
+
+      /* Just wait for the child.  */
+      if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid)
+       {
+         puts ("waitpid failed");
+         kill (pid, SIGTERM);
+         return 1;
+       }
+    }
+
+  return status;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-rwlock13.c b/test/nptl/tst-rwlock13.c
new file mode 100644 (file)
index 0000000..61d5b83
--- /dev/null
@@ -0,0 +1,71 @@
+/* Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <string.h>
+
+
+static int
+do_test (void)
+{
+  pthread_rwlock_t r;
+  int ret;
+
+  memset (&r, 0xaa, sizeof (r));
+  if ((ret = pthread_rwlock_init (&r, NULL)) != 0)
+    {
+      printf ("rwlock_init failed: %d\n", ret);
+      return 1;
+    }
+
+  if ((ret = pthread_rwlock_rdlock (&r)) != 0)
+    {
+      printf ("rwlock_rdlock failed: %d\n", ret);
+      return 1;
+    }
+
+  if ((ret = pthread_rwlock_unlock (&r)) != 0)
+    {
+      printf ("rwlock_unlock failed: %d\n", ret);
+      return 1;
+    }
+
+  if ((ret = pthread_rwlock_wrlock (&r)) != 0)
+    {
+      printf ("rwlock_wrlock failed: %d\n", ret);
+      return 1;
+    }
+
+  if ((ret = pthread_rwlock_unlock (&r)) != 0)
+    {
+      printf ("second rwlock_unlock failed: %d\n", ret);
+      return 1;
+    }
+
+  if ((ret = pthread_rwlock_destroy (&r)) != 0)
+    {
+      printf ("second rwlock_destroy failed: %d\n", ret);
+      return 1;
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-rwlock14.c b/test/nptl/tst-rwlock14.c
new file mode 100644 (file)
index 0000000..fc0d3d2
--- /dev/null
@@ -0,0 +1,169 @@
+/* Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2004.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with 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 <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+
+static pthread_barrier_t b;
+static pthread_rwlock_t r = PTHREAD_RWLOCK_INITIALIZER;
+
+
+static void *
+tf (void *arg)
+{
+  /* Lock the read-write lock.  */
+  if (pthread_rwlock_wrlock (&r) != 0)
+    {
+      puts ("tf: cannot lock rwlock");
+      exit (EXIT_FAILURE);
+    }
+
+  pthread_t mt = *(pthread_t *) arg;
+
+  pthread_barrier_wait (&b);
+
+  /* This call will never return.  */
+  pthread_join (mt, NULL);
+
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  int result = 0;
+  struct timespec ts;
+
+  if (clock_gettime (CLOCK_REALTIME, &ts) != 0)
+    {
+      puts ("clock_gettime failed");
+      return 1;
+    }
+
+  if (pthread_barrier_init (&b, NULL, 2) != 0)
+    {
+      puts ("barrier_init failed");
+      return 1;
+    }
+
+  pthread_t me = pthread_self ();
+  pthread_t th;
+  if (pthread_create (&th, NULL, tf, &me) != 0)
+    {
+      puts ("create failed");
+      return 1;
+    }
+
+  /* Wait until the rwlock is locked.  */
+  pthread_barrier_wait (&b);
+
+  ts.tv_nsec = -1;
+
+  int e = pthread_rwlock_timedrdlock (&r, &ts);
+  if (e == 0)
+    {
+      puts ("first rwlock_timedrdlock did not fail");
+      result = 1;
+    }
+  else if (e != EINVAL)
+    {
+      puts ("first rwlock_timedrdlock did not return EINVAL");
+      result = 1;
+    }
+
+  e = pthread_rwlock_timedwrlock (&r, &ts);
+  if (e == 0)
+    {
+      puts ("first rwlock_timedwrlock did not fail");
+      result = 1;
+    }
+  else if (e != EINVAL)
+    {
+      puts ("first rwlock_timedwrlock did not return EINVAL");
+      result = 1;
+    }
+
+  ts.tv_nsec = 1000000000;
+
+  e = pthread_rwlock_timedrdlock (&r, &ts);
+  if (e == 0)
+    {
+      puts ("second rwlock_timedrdlock did not fail");
+      result = 1;
+    }
+  else if (e != EINVAL)
+    {
+      puts ("second rwlock_timedrdlock did not return EINVAL");
+      result = 1;
+    }
+
+  e = pthread_rwlock_timedrdlock (&r, &ts);
+  if (e == 0)
+    {
+      puts ("second rwlock_timedrdlock did not fail");
+      result = 1;
+    }
+  else if (e != EINVAL)
+    {
+      puts ("second rwlock_timedrdlock did not return EINVAL");
+      result = 1;
+    }
+
+  ts.tv_nsec = 0x100001000LL;
+  if (ts.tv_nsec != 0x100001000LL)
+    ts.tv_nsec = 2000000000;
+
+  e = pthread_rwlock_timedrdlock (&r, &ts);
+  if (e == 0)
+    {
+      puts ("third rwlock_timedrdlock did not fail");
+      result = 1;
+    }
+  else if (e != EINVAL)
+    {
+      puts ("third rwlock_timedrdlock did not return EINVAL");
+      result = 1;
+    }
+
+  e = pthread_rwlock_timedrdlock (&r, &ts);
+  if (e == 0)
+    {
+      puts ("third rwlock_timedrdlock did not fail");
+      result = 1;
+    }
+  else if (e != EINVAL)
+    {
+      puts ("third rwlock_timedrdlock did not return EINVAL");
+      result = 1;
+    }
+
+  if (result == 0)
+    puts ("no bugs");
+
+  return result;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-rwlock2.c b/test/nptl/tst-rwlock2.c
new file mode 100644 (file)
index 0000000..6f38682
--- /dev/null
@@ -0,0 +1,143 @@
+/* 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 <pthread.h>
+#include <stdio.h>
+
+
+static int
+do_test (void)
+{
+  pthread_rwlock_t r;
+  int e;
+
+  if (pthread_rwlock_init (&r, NULL) != 0)
+    {
+      puts ("rwlock_init failed");
+      return 1;
+    }
+  puts ("rwlock_init succeeded");
+
+  if (pthread_rwlock_wrlock (&r) != 0)
+    {
+      puts ("1st rwlock_wrlock failed");
+      return 1;
+    }
+  puts ("1st rwlock_wrlock succeeded");
+
+  e = pthread_rwlock_tryrdlock (&r);
+  if (e == 0)
+    {
+      puts ("rwlock_tryrdlock on rwlock with writer succeeded");
+      return 1;
+    }
+  if (e != EBUSY)
+    {
+      puts ("rwlock_tryrdlock on rwlock with writer return value != EBUSY");
+      return 1;
+    }
+  puts ("rwlock_tryrdlock on rwlock with writer failed with EBUSY");
+
+  e = pthread_rwlock_trywrlock (&r);
+  if (e == 0)
+    {
+      puts ("rwlock_trywrlock on rwlock with writer succeeded");
+      return 1;
+    }
+  if (e != EBUSY)
+    {
+      puts ("rwlock_trywrlock on rwlock with writer return value != EBUSY");
+      return 1;
+    }
+  puts ("rwlock_trywrlock on rwlock with writer failed with EBUSY");
+
+  if (pthread_rwlock_unlock (&r) != 0)
+    {
+      puts ("1st rwlock_unlock failed");
+      return 1;
+    }
+  puts ("1st rwlock_unlock succeeded");
+
+  if (pthread_rwlock_tryrdlock (&r) != 0)
+    {
+      puts ("rwlock_tryrdlock on unlocked rwlock failed");
+      return 1;
+    }
+  puts ("rwlock_tryrdlock on unlocked rwlock succeeded");
+
+  e = pthread_rwlock_trywrlock (&r);
+  if (e == 0)
+    {
+      puts ("rwlock_trywrlock on rwlock with reader succeeded");
+      return 1;
+    }
+  if (e != EBUSY)
+    {
+      puts ("rwlock_trywrlock on rwlock with reader return value != EBUSY");
+      return 1;
+    }
+  puts ("rwlock_trywrlock on rwlock with reader failed with EBUSY");
+
+  if (pthread_rwlock_unlock (&r) != 0)
+    {
+      puts ("2nd rwlock_unlock failed");
+      return 1;
+    }
+  puts ("2nd rwlock_unlock succeeded");
+
+  if (pthread_rwlock_trywrlock (&r) != 0)
+    {
+      puts ("rwlock_trywrlock on unlocked rwlock failed");
+      return 1;
+    }
+  puts ("rwlock_trywrlock on unlocked rwlock succeeded");
+
+  e = pthread_rwlock_tryrdlock (&r);
+  if (e == 0)
+    {
+      puts ("rwlock_tryrdlock on rwlock with writer succeeded");
+      return 1;
+    }
+  if (e != EBUSY)
+    {
+      puts ("rwlock_tryrdlock on rwlock with writer return value != EBUSY");
+      return 1;
+    }
+  puts ("rwlock_tryrdlock on rwlock with writer failed with EBUSY");
+
+  if (pthread_rwlock_unlock (&r) != 0)
+    {
+      puts ("3rd rwlock_unlock failed");
+      return 1;
+    }
+  puts ("3rd rwlock_unlock succeeded");
+
+  if (pthread_rwlock_destroy (&r) != 0)
+    {
+      puts ("rwlock_destroy failed");
+      return 1;
+    }
+  puts ("rwlock_destroy succeeded");
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-rwlock3.c b/test/nptl/tst-rwlock3.c
new file mode 100644 (file)
index 0000000..c1cac87
--- /dev/null
@@ -0,0 +1,93 @@
+/* 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.  */
+
+/* This test case checks more than standard compliance.  An
+   implementation may provide this service but it is not required to
+   do so.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+
+
+static int
+do_test (void)
+{
+  pthread_rwlock_t r;
+  int e;
+
+  if (pthread_rwlock_init (&r, NULL) != 0)
+    {
+      puts ("rwlock_init failed");
+      return 1;
+    }
+  puts ("rwlock_init succeeded");
+
+  if (pthread_rwlock_trywrlock (&r) != 0)
+    {
+      puts ("rwlock_trywrlock on unlocked rwlock failed");
+      return 1;
+    }
+  puts ("rwlock_trywrlock on unlocked rwlock succeeded");
+
+  e = pthread_rwlock_rdlock (&r);
+  if (e == 0)
+    {
+      puts ("rwlock_rdlock on rwlock with writer succeeded");
+      return 1;
+    }
+  if (e != EDEADLK)
+    {
+      puts ("rwlock_rdlock on rwlock with writer failed != EDEADLK");
+      return 1;
+    }
+  puts ("rwlock_rdlock on rwlock with writer failed with EDEADLK");
+
+  e = pthread_rwlock_wrlock (&r);
+  if (e == 0)
+    {
+      puts ("rwlock_wrlock on rwlock with writer succeeded");
+      return 1;
+    }
+  if (e != EDEADLK)
+    {
+      puts ("rwlock_wrlock on rwlock with writer failed != EDEADLK");
+      return 1;
+    }
+  puts ("rwlock_wrlock on rwlock with writer failed with EDEADLK");
+
+  if (pthread_rwlock_unlock (&r) != 0)
+    {
+      puts ("rwlock_unlock failed");
+      return 1;
+    }
+  puts ("rwlock_unlock succeeded");
+
+  if (pthread_rwlock_destroy (&r) != 0)
+    {
+      puts ("rwlock_destroy failed");
+      return 1;
+    }
+  puts ("rwlock_destroy succeeded");
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-rwlock4.c b/test/nptl/tst-rwlock4.c
new file mode 100644 (file)
index 0000000..8de0121
--- /dev/null
@@ -0,0 +1,190 @@
+/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+
+
+static int
+do_test (void)
+{
+  size_t ps = sysconf (_SC_PAGESIZE);
+  char tmpfname[] = "/tmp/tst-rwlock4.XXXXXX";
+  char data[ps];
+  void *mem;
+  int fd;
+  pthread_rwlock_t *r;
+  pthread_rwlockattr_t a;
+  pid_t pid;
+  char *p;
+  int err;
+  int s;
+
+  fd = mkstemp (tmpfname);
+  if (fd == -1)
+    {
+      printf ("cannot open temporary file: %m\n");
+      return 1;
+    }
+
+  /* Make sure it is always removed.  */
+  unlink (tmpfname);
+
+  /* Create one page of data.  */
+  memset (data, '\0', ps);
+
+  /* Write the data to the file.  */
+  if (write (fd, data, ps) != (ssize_t) ps)
+    {
+      puts ("short write");
+      return 1;
+    }
+
+  mem = mmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+  if (mem == MAP_FAILED)
+    {
+      printf ("mmap failed: %m\n");
+      return 1;
+    }
+
+  r = (pthread_rwlock_t *) (((uintptr_t) mem + __alignof (pthread_rwlock_t))
+                           & ~(__alignof (pthread_rwlock_t) - 1));
+  p = (char *) (r + 1);
+
+  if (pthread_rwlockattr_init (&a) != 0)
+    {
+      puts ("rwlockattr_init failed");
+      return 1;
+    }
+
+  if (pthread_rwlockattr_getpshared (&a, &s) != 0)
+    {
+      puts ("1st rwlockattr_getpshared failed");
+      return 1;
+    }
+
+  if (s != PTHREAD_PROCESS_PRIVATE)
+    {
+      puts ("default pshared value wrong");
+      return 1;
+    }
+
+  if (pthread_rwlockattr_setpshared (&a, PTHREAD_PROCESS_SHARED) != 0)
+    {
+      puts ("rwlockattr_setpshared failed");
+      return 1;
+    }
+
+  if (pthread_rwlockattr_getpshared (&a, &s) != 0)
+    {
+      puts ("2nd rwlockattr_getpshared failed");
+      return 1;
+    }
+
+  if (s != PTHREAD_PROCESS_SHARED)
+    {
+      puts ("pshared value after setpshared call wrong");
+      return 1;
+    }
+
+  if (pthread_rwlock_init (r, &a) != 0)
+    {
+      puts ("rwlock_init failed");
+      return 1;
+    }
+
+  if (pthread_rwlock_rdlock (r) != 0)
+    {
+      puts ("rwlock_rdlock failed");
+      return 1;
+    }
+
+  if (pthread_rwlockattr_destroy (&a) != 0)
+    {
+      puts ("rwlockattr_destroy failed");
+      return 1;
+    }
+
+  err = pthread_rwlock_trywrlock (r);
+  if (err == 0)
+    {
+      puts ("rwlock_trywrlock succeeded");
+      return 1;
+    }
+  else if (err != EBUSY)
+    {
+      puts ("rwlock_trywrlock didn't return EBUSY");
+      return 1;
+    }
+
+  *p = 0;
+
+  puts ("going to fork now");
+  pid = fork ();
+  if (pid == -1)
+    {
+      puts ("fork failed");
+      return 1;
+    }
+  else if (pid == 0)
+    {
+      /* Play some lock ping-pong.  It's our turn to unlock first.  */
+      if ((*p)++ != 0)
+       {
+         puts ("child: *p != 0");
+         return 1;
+       }
+
+      if (pthread_rwlock_unlock (r) != 0)
+       {
+         puts ("child: 1st rwlock_unlock failed");
+         return 1;
+       }
+
+      puts ("child done");
+    }
+  else
+    {
+      if (pthread_rwlock_wrlock (r) != 0)
+       {
+         puts ("parent: rwlock_wrlock failed");
+         return 1;
+       }
+
+      if (*p != 1)
+       {
+         puts ("*p != 1");
+         return 1;
+       }
+
+      puts ("parent done");
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-rwlock5.c b/test/nptl/tst-rwlock5.c
new file mode 100644 (file)
index 0000000..a04eb26
--- /dev/null
@@ -0,0 +1,87 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+
+static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
+static pthread_rwlock_t r;
+
+
+static void *
+tf (void *arg)
+{
+  if (pthread_rwlock_wrlock (&r) == 0)
+    {
+      puts ("child: rwlock_wrlock succeeded");
+      exit (1);
+    }
+
+  puts ("child: rwlock_wrlock returned");
+
+  exit (1);
+}
+
+
+static int
+do_test (void)
+{
+  pthread_t th;
+
+  if (pthread_rwlock_init (&r, NULL) != 0)
+    {
+      puts ("rwlock_init failed");
+      return 1;
+    }
+
+  if (pthread_rwlock_wrlock (&r) != 0)
+    {
+      puts ("rwlock_wrlock failed");
+      return 1;
+    }
+
+  if (pthread_mutex_lock (&m) != 0)
+    {
+      puts ("mutex_lock failed");
+      return 1;
+    }
+
+  /* Set an alarm for 1 second.  The wrapper will expect this.  */
+  alarm (1);
+
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("create failed");
+      return 1;
+    }
+
+  /* This call should never return.  */
+  pthread_mutex_lock (&m);
+
+  puts ("2nd mutex_lock returned");
+  return 1;
+}
+
+#define EXPECTED_SIGNAL SIGALRM
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-rwlock6.c b/test/nptl/tst-rwlock6.c
new file mode 100644 (file)
index 0000000..3b525b9
--- /dev/null
@@ -0,0 +1,226 @@
+/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+
+
+static int kind[] =
+  {
+    PTHREAD_RWLOCK_PREFER_READER_NP,
+    PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP,
+    PTHREAD_RWLOCK_PREFER_WRITER_NP,
+  };
+
+
+static void *
+tf (void *arg)
+{
+  pthread_rwlock_t *r = arg;
+
+  /* Timeout: 0.3 secs.  */
+  struct timeval tv;
+  (void) gettimeofday (&tv, NULL);
+
+  struct timespec ts;
+  TIMEVAL_TO_TIMESPEC (&tv, &ts);
+  ts.tv_nsec += 300000000;
+  if (ts.tv_nsec >= 1000000000)
+    {
+      ts.tv_nsec -= 1000000000;
+      ++ts.tv_sec;
+    }
+
+  puts ("child calling timedrdlock");
+
+  int err = pthread_rwlock_timedrdlock (r, &ts);
+  if (err == 0)
+    {
+      puts ("rwlock_timedrdlock returned");
+      pthread_exit ((void *) 1l);
+    }
+
+  if (err != ETIMEDOUT)
+    {
+      printf ("err = %s (%d), expected %s (%d)\n",
+             strerror (err), err, strerror (ETIMEDOUT), ETIMEDOUT);
+      pthread_exit ((void *) 1l);
+    }
+
+  puts ("1st child timedrdlock done");
+
+  struct timeval tv2;
+  (void) gettimeofday (&tv2, NULL);
+
+  timersub (&tv2, &tv, &tv);
+
+  if (tv.tv_usec < 200000)
+    {
+      puts ("timeout too short");
+      pthread_exit ((void *) 1l);
+    }
+
+  (void) gettimeofday (&tv, NULL);
+  TIMEVAL_TO_TIMESPEC (&tv, &ts);
+  ts.tv_sec += 10;
+  /* Note that the following operation makes ts invalid.  */
+  ts.tv_nsec += 1000000000;
+
+  err = pthread_rwlock_timedrdlock (r, &ts);
+  if (err == 0)
+    {
+      puts ("2nd timedrdlock succeeded");
+      pthread_exit ((void *) 1l);
+    }
+  if (err != EINVAL)
+    {
+      puts ("2nd timedrdlock did not return EINVAL");
+      pthread_exit ((void *) 1l);
+    }
+
+  puts ("2nd child timedrdlock done");
+
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  size_t cnt;
+  for (cnt = 0; cnt < sizeof (kind) / sizeof (kind[0]); ++cnt)
+    {
+      pthread_rwlock_t r;
+      pthread_rwlockattr_t a;
+
+      if (pthread_rwlockattr_init (&a) != 0)
+       {
+         printf ("round %Zu: rwlockattr_t failed\n", cnt);
+         exit (1);
+       }
+
+      if (pthread_rwlockattr_setkind_np (&a, kind[cnt]) != 0)
+       {
+         printf ("round %Zu: rwlockattr_setkind failed\n", cnt);
+         exit (1);
+       }
+
+      if (pthread_rwlock_init (&r, &a) != 0)
+       {
+         printf ("round %Zu: rwlock_init failed\n", cnt);
+         exit (1);
+       }
+
+      if (pthread_rwlockattr_destroy (&a) != 0)
+       {
+         printf ("round %Zu: rwlockattr_destroy failed\n", cnt);
+         exit (1);
+       }
+
+      struct timeval tv;
+      (void) gettimeofday (&tv, NULL);
+
+      struct timespec ts;
+      TIMEVAL_TO_TIMESPEC (&tv, &ts);
+
+      ++ts.tv_sec;
+
+      /* Get a write lock.  */
+      int e = pthread_rwlock_timedwrlock (&r, &ts);
+      if (e != 0)
+       {
+         printf ("round %Zu: rwlock_timedwrlock failed (%d)\n", cnt, e);
+         exit (1);
+       }
+
+      puts ("1st timedwrlock done");
+
+      (void) gettimeofday (&tv, NULL);
+      TIMEVAL_TO_TIMESPEC (&tv, &ts);
+      ++ts.tv_sec;
+      e = pthread_rwlock_timedrdlock (&r, &ts);
+      if (e == 0)
+       {
+         puts ("timedrdlock succeeded");
+         exit (1);
+       }
+      if (e != EDEADLK)
+       {
+         puts ("timedrdlock did not return EDEADLK");
+         exit (1);
+       }
+
+      puts ("1st timedrdlock done");
+
+      (void) gettimeofday (&tv, NULL);
+      TIMEVAL_TO_TIMESPEC (&tv, &ts);
+      ++ts.tv_sec;
+      e = pthread_rwlock_timedwrlock (&r, &ts);
+      if (e == 0)
+       {
+         puts ("2nd timedwrlock succeeded");
+         exit (1);
+       }
+      if (e != EDEADLK)
+       {
+         puts ("2nd timedwrlock did not return EDEADLK");
+         exit (1);
+       }
+
+      puts ("2nd timedwrlock done");
+
+      pthread_t th;
+      if (pthread_create (&th, NULL, tf, &r) != 0)
+       {
+         printf ("round %Zu: create failed\n", cnt);
+         exit (1);
+       }
+
+      puts ("started thread");
+
+      void *status;
+      if (pthread_join (th, &status) != 0)
+       {
+         printf ("round %Zu: join failed\n", cnt);
+         exit (1);
+       }
+      if (status != NULL)
+       {
+         printf ("failure in round %Zu\n", cnt);
+         exit (1);
+       }
+
+      puts ("joined thread");
+
+      if (pthread_rwlock_destroy (&r) != 0)
+       {
+         printf ("round %Zu: rwlock_destroy failed\n", cnt);
+         exit (1);
+       }
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-rwlock7.c b/test/nptl/tst-rwlock7.c
new file mode 100644 (file)
index 0000000..1f34c06
--- /dev/null
@@ -0,0 +1,179 @@
+/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+
+
+static int kind[] =
+  {
+    PTHREAD_RWLOCK_PREFER_READER_NP,
+    PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP,
+    PTHREAD_RWLOCK_PREFER_WRITER_NP,
+  };
+
+
+static void *
+tf (void *arg)
+{
+  pthread_rwlock_t *r = arg;
+
+  /* Timeout: 0.3 secs.  */
+  struct timeval tv;
+  (void) gettimeofday (&tv, NULL);
+
+  struct timespec ts;
+  TIMEVAL_TO_TIMESPEC (&tv, &ts);
+  ts.tv_nsec += 300000000;
+  if (ts.tv_nsec >= 1000000000)
+    {
+      ts.tv_nsec -= 1000000000;
+      ++ts.tv_sec;
+    }
+
+  int err = pthread_rwlock_timedwrlock (r, &ts);
+  if (err == 0)
+    {
+      puts ("rwlock_timedwrlock returned");
+      pthread_exit ((void *) 1l);
+    }
+
+  if (err != ETIMEDOUT)
+    {
+      printf ("err = %s (%d), expected %s (%d)\n",
+             strerror (err), err, strerror (ETIMEDOUT), ETIMEDOUT);
+      pthread_exit ((void *) 1l);
+    }
+
+  struct timeval tv2;
+  (void) gettimeofday (&tv2, NULL);
+
+  timersub (&tv2, &tv, &tv);
+
+  if (tv.tv_usec < 200000)
+    {
+      puts ("timeout too short");
+      pthread_exit ((void *) 1l);
+    }
+
+  (void) gettimeofday (&tv, NULL);
+  TIMEVAL_TO_TIMESPEC (&tv, &ts);
+  ts.tv_sec += 10;
+  /* Note that the following operation makes ts invalid.  */
+  ts.tv_nsec += 1000000000;
+
+  err = pthread_rwlock_timedwrlock (r, &ts);
+  if (err == 0)
+    {
+      puts ("2nd timedwrlock succeeded");
+      pthread_exit ((void *) 1l);
+    }
+  if (err != EINVAL)
+    {
+      puts ("2nd timedwrlock did not return EINVAL");
+      pthread_exit ((void *) 1l);
+    }
+
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  size_t cnt;
+  for (cnt = 0; cnt < sizeof (kind) / sizeof (kind[0]); ++cnt)
+    {
+      pthread_rwlock_t r;
+      pthread_rwlockattr_t a;
+
+      if (pthread_rwlockattr_init (&a) != 0)
+       {
+         printf ("round %Zu: rwlockattr_t failed\n", cnt);
+         exit (1);
+       }
+
+      if (pthread_rwlockattr_setkind_np (&a, kind[cnt]) != 0)
+       {
+         printf ("round %Zu: rwlockattr_setkind failed\n", cnt);
+         exit (1);
+       }
+
+      if (pthread_rwlock_init (&r, &a) != 0)
+       {
+         printf ("round %Zu: rwlock_init failed\n", cnt);
+         exit (1);
+       }
+
+      if (pthread_rwlockattr_destroy (&a) != 0)
+       {
+         printf ("round %Zu: rwlockattr_destroy failed\n", cnt);
+         exit (1);
+       }
+
+      struct timeval tv;
+      (void) gettimeofday (&tv, NULL);
+
+      struct timespec ts;
+      TIMEVAL_TO_TIMESPEC (&tv, &ts);
+
+      ++ts.tv_sec;
+
+      /* Get a read lock.  */
+      if (pthread_rwlock_timedrdlock (&r, &ts) != 0)
+       {
+         printf ("round %Zu: rwlock_timedrdlock failed\n", cnt);
+         exit (1);
+       }
+
+      pthread_t th;
+      if (pthread_create (&th, NULL, tf, &r) != 0)
+       {
+         printf ("round %Zu: create failed\n", cnt);
+         exit (1);
+       }
+
+      void *status;
+      if (pthread_join (th, &status) != 0)
+       {
+         printf ("round %Zu: join failed\n", cnt);
+         exit (1);
+       }
+      if (status != NULL)
+       {
+         printf ("failure in round %Zu\n", cnt);
+         exit (1);
+       }
+
+      if (pthread_rwlock_destroy (&r) != 0)
+       {
+         printf ("round %Zu: rwlock_destroy failed\n", cnt);
+         exit (1);
+       }
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-rwlock8.c b/test/nptl/tst-rwlock8.c
new file mode 100644 (file)
index 0000000..7eeaea8
--- /dev/null
@@ -0,0 +1,164 @@
+/* Test program for timedout read/write lock functions.
+   Copyright (C) 2000, 2003 Free Software Foundation, Inc.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2000.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <errno.h>
+#include <error.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+
+
+#define NWRITERS 15
+#define WRITETRIES 10
+#define NREADERS 15
+#define READTRIES 15
+
+#define DELAY   1000000
+
+#ifndef INIT
+# define INIT PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP
+#endif
+
+static pthread_rwlock_t lock = INIT;
+
+
+static void *
+writer_thread (void *nr)
+{
+  struct timespec delay;
+  int n;
+
+  delay.tv_sec = 0;
+  delay.tv_nsec = DELAY;
+
+  for (n = 0; n < WRITETRIES; ++n)
+    {
+      printf ("writer thread %ld tries again\n", (long int) nr);
+
+      if (pthread_rwlock_wrlock (&lock) != 0)
+       {
+         puts ("wrlock failed");
+         exit (1);
+       }
+
+      printf ("writer thread %ld succeeded\n", (long int) nr);
+
+      nanosleep (&delay, NULL);
+
+      if (pthread_rwlock_unlock (&lock) != 0)
+       {
+         puts ("unlock for writer failed");
+         exit (1);
+       }
+
+      printf ("writer thread %ld released\n", (long int) nr);
+    }
+
+  return NULL;
+}
+
+
+static void *
+reader_thread (void *nr)
+{
+  struct timespec delay;
+  int n;
+
+  delay.tv_sec = 0;
+  delay.tv_nsec = DELAY;
+
+  for (n = 0; n < READTRIES; ++n)
+    {
+      printf ("reader thread %ld tries again\n", (long int) nr);
+
+      if (pthread_rwlock_rdlock (&lock) != 0)
+       {
+         puts ("rdlock failed");
+         exit (1);
+       }
+
+      printf ("reader thread %ld succeeded\n", (long int) nr);
+
+      nanosleep (&delay, NULL);
+
+      if (pthread_rwlock_unlock (&lock) != 0)
+       {
+         puts ("unlock for reader failed");
+         exit (1);
+       }
+
+      printf ("reader thread %ld released\n", (long int) nr);
+    }
+
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  pthread_t thwr[NWRITERS];
+  pthread_t thrd[NREADERS];
+  int n;
+  void *res;
+
+  /* Make standard error the same as standard output.  */
+  dup2 (1, 2);
+
+  /* Make sure we see all message, even those on stdout.  */
+  setvbuf (stdout, NULL, _IONBF, 0);
+
+  for (n = 0; n < NWRITERS; ++n)
+    if (pthread_create (&thwr[n], NULL, writer_thread,
+                       (void *) (long int) n) != 0)
+      {
+       puts ("writer create failed");
+       exit (1);
+      }
+
+  for (n = 0; n < NREADERS; ++n)
+    if (pthread_create (&thrd[n], NULL, reader_thread,
+                       (void *) (long int) n) != 0)
+      {
+       puts ("reader create failed");
+       exit (1);
+      }
+
+  /* Wait for all the threads.  */
+  for (n = 0; n < NWRITERS; ++n)
+    if (pthread_join (thwr[n], &res) != 0)
+      {
+       puts ("writer join failed");
+       exit (1);
+      }
+  for (n = 0; n < NREADERS; ++n)
+    if (pthread_join (thrd[n], &res) != 0)
+      {
+       puts ("reader join failed");
+       exit (1);
+      }
+
+  return 0;
+}
+
+#define TIMEOUT 30
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-rwlock9.c b/test/nptl/tst-rwlock9.c
new file mode 100644 (file)
index 0000000..a5522ce
--- /dev/null
@@ -0,0 +1,203 @@
+/* Test program for timedout read/write lock functions.
+   Copyright (C) 2000, 2003 Free Software Foundation, Inc.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2000.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <errno.h>
+#include <error.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/time.h>
+
+
+#define NWRITERS 15
+#define WRITETRIES 10
+#define NREADERS 15
+#define READTRIES 15
+
+#define TIMEOUT 1000000
+#define DELAY   1000000
+
+#ifndef INIT
+# define INIT PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP
+#endif
+
+static pthread_rwlock_t lock = INIT;
+
+
+static void *
+writer_thread (void *nr)
+{
+  struct timespec ts;
+  struct timespec delay;
+  int n;
+
+  delay.tv_sec = 0;
+  delay.tv_nsec = DELAY;
+
+  for (n = 0; n < WRITETRIES; ++n)
+    {
+      int e;
+      do
+       {
+         struct timeval tv;
+         (void) gettimeofday (&tv, NULL);
+         TIMEVAL_TO_TIMESPEC (&tv, &ts);
+
+         ts.tv_nsec += 2 * TIMEOUT;
+         if (ts.tv_nsec >= 1000000000)
+           {
+             ts.tv_nsec -= 1000000000;
+             ++ts.tv_sec;
+           }
+
+         printf ("writer thread %ld tries again\n", (long int) nr);
+
+         e = pthread_rwlock_timedwrlock (&lock, &ts);
+         if (e != 0 && e != ETIMEDOUT)
+           {
+             puts ("timedwrlock failed");
+             exit (1);
+           }
+       }
+      while (e == ETIMEDOUT);
+
+      printf ("writer thread %ld succeeded\n", (long int) nr);
+
+      nanosleep (&delay, NULL);
+
+      if (pthread_rwlock_unlock (&lock) != 0)
+       {
+         puts ("unlock for writer failed");
+         exit (1);
+       }
+
+      printf ("writer thread %ld released\n", (long int) nr);
+    }
+
+  return NULL;
+}
+
+
+static void *
+reader_thread (void *nr)
+{
+  struct timespec ts;
+  struct timespec delay;
+  int n;
+
+  delay.tv_sec = 0;
+  delay.tv_nsec = DELAY;
+
+  for (n = 0; n < READTRIES; ++n)
+    {
+      int e;
+      do
+       {
+         struct timeval tv;
+         (void) gettimeofday (&tv, NULL);
+         TIMEVAL_TO_TIMESPEC (&tv, &ts);
+
+         ts.tv_nsec += TIMEOUT;
+         if (ts.tv_nsec >= 1000000000)
+           {
+             ts.tv_nsec -= 1000000000;
+             ++ts.tv_sec;
+           }
+
+         printf ("reader thread %ld tries again\n", (long int) nr);
+
+         e = pthread_rwlock_timedrdlock (&lock, &ts);
+         if (e != 0 && e != ETIMEDOUT)
+           {
+             puts ("timedrdlock failed");
+             exit (1);
+           }
+       }
+      while (e == ETIMEDOUT);
+
+      printf ("reader thread %ld succeeded\n", (long int) nr);
+
+      nanosleep (&delay, NULL);
+
+      if (pthread_rwlock_unlock (&lock) != 0)
+       {
+         puts ("unlock for reader failed");
+         exit (1);
+       }
+
+      printf ("reader thread %ld released\n", (long int) nr);
+    }
+
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  pthread_t thwr[NWRITERS];
+  pthread_t thrd[NREADERS];
+  int n;
+  void *res;
+
+  /* Make standard error the same as standard output.  */
+  dup2 (1, 2);
+
+  /* Make sure we see all message, even those on stdout.  */
+  setvbuf (stdout, NULL, _IONBF, 0);
+
+  for (n = 0; n < NWRITERS; ++n)
+    if (pthread_create (&thwr[n], NULL, writer_thread,
+                       (void *) (long int) n) != 0)
+      {
+       puts ("writer create failed");
+       exit (1);
+      }
+
+  for (n = 0; n < NREADERS; ++n)
+    if (pthread_create (&thrd[n], NULL, reader_thread,
+                       (void *) (long int) n) != 0)
+      {
+       puts ("reader create failed");
+       exit (1);
+      }
+
+  /* Wait for all the threads.  */
+  for (n = 0; n < NWRITERS; ++n)
+    if (pthread_join (thwr[n], &res) != 0)
+      {
+       puts ("writer join failed");
+       exit (1);
+      }
+  for (n = 0; n < NREADERS; ++n)
+    if (pthread_join (thrd[n], &res) != 0)
+      {
+       puts ("reader join failed");
+       exit (1);
+      }
+
+  return 0;
+}
+
+#undef TIMEOUT
+#define TIMEOUT 30
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-sched1.c b/test/nptl/tst-sched1.c
new file mode 100644 (file)
index 0000000..4d0702c
--- /dev/null
@@ -0,0 +1,98 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+
+static int global;
+
+static void *
+tf (void *a)
+{
+  global = 1;
+
+  return 0;
+}
+
+
+int
+do_test (void)
+{
+  pthread_t th;
+  pthread_attr_t at;
+
+  if (pthread_attr_init (&at) != 0)
+    {
+      puts ("attr_init failed");
+      return 1;
+    }
+
+  if (pthread_attr_setschedpolicy (&at, SCHED_OTHER) != 0)
+    {
+      puts ("attr_setschedpolicy failed");
+      return 1;
+    }
+
+  struct sched_param pa;
+  if (sched_getparam (getpid (), &pa) != 0)
+    {
+      puts ("sched_getschedparam failed");
+      return 1;
+    }
+
+  if (pthread_attr_setschedparam (&at, &pa) != 0)
+    {
+      puts ("attr_setschedparam failed");
+      return 1;
+    }
+
+  if (pthread_attr_setinheritsched (&at, PTHREAD_EXPLICIT_SCHED) != 0)
+    {
+      puts ("attr_setinheritsched failed");
+      return 1;
+    }
+
+  if (pthread_create (&th, &at, tf, NULL) != 0)
+    {
+      puts ("create failed");
+      return 1;
+    }
+
+  int e = pthread_join (th, NULL);
+  if (e != 0)
+    {
+      printf ("join failed: %d\n", e);
+      return 1;
+    }
+
+  if (global == 0)
+    {
+      puts ("thread didn't run");
+      return 1;
+    }
+
+  return 0;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-sem1.c b/test/nptl/tst-sem1.c
new file mode 100644 (file)
index 0000000..32d59eb
--- /dev/null
@@ -0,0 +1,89 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <semaphore.h>
+#include <stdio.h>
+#include <unistd.h>
+
+
+static int
+do_test (void)
+{
+  sem_t s;
+
+  if (sem_init (&s, 0, 1) == -1)
+    {
+      puts ("init failed");
+      return 1;
+    }
+
+  if (TEMP_FAILURE_RETRY (sem_wait (&s)) == -1)
+    {
+      puts ("1st wait failed");
+      return 1;
+    }
+
+  if (sem_post (&s) == -1)
+    {
+      puts ("1st post failed");
+      return 1;
+    }
+
+  if (TEMP_FAILURE_RETRY (sem_trywait (&s)) == -1)
+    {
+      puts ("1st trywait failed");
+      return 1;
+    }
+
+  errno = 0;
+  if (TEMP_FAILURE_RETRY (sem_trywait (&s)) != -1)
+    {
+      puts ("2nd trywait succeeded");
+      return 1;
+    }
+  else if (errno != EAGAIN)
+    {
+      puts ("2nd trywait did not set errno to EAGAIN");
+      return 1;
+    }
+
+  if (sem_post (&s) == -1)
+    {
+      puts ("2nd post failed");
+      return 1;
+    }
+
+  if (TEMP_FAILURE_RETRY (sem_wait (&s)) == -1)
+    {
+      puts ("2nd wait failed");
+      return 1;
+    }
+
+  if (sem_destroy (&s) == -1)
+    {
+      puts ("destroy failed");
+      return 1;
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-sem2.c b/test/nptl/tst-sem2.c
new file mode 100644 (file)
index 0000000..026939e
--- /dev/null
@@ -0,0 +1,54 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <semaphore.h>
+#include <signal.h>
+#include <stdio.h>
+#include <unistd.h>
+
+
+static int
+do_test (void)
+{
+  sem_t s;
+
+  if (sem_init (&s, 0, 0) == -1)
+    {
+      puts ("init failed");
+      return 1;
+    }
+
+  /* Set an alarm for 1 second.  The wrapper will expect this.  */
+  alarm (1);
+
+  if (TEMP_FAILURE_RETRY (sem_wait (&s)) == -1)
+    {
+      puts ("wait failed");
+      return 1;
+    }
+
+  /* We should never get here.  */
+  puts ("wait succeeded");
+  return 1;
+}
+
+#define EXPECTED_SIGNAL SIGALRM
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-sem3.c b/test/nptl/tst-sem3.c
new file mode 100644 (file)
index 0000000..91b9f08
--- /dev/null
@@ -0,0 +1,142 @@
+/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <semaphore.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+
+
+int
+main (void)
+{
+  size_t ps = sysconf (_SC_PAGESIZE);
+  char tmpfname[] = "/tmp/tst-sem3.XXXXXX";
+  char data[ps];
+  void *mem;
+  int fd;
+  sem_t *s;
+  pid_t pid;
+  char *p;
+
+  fd = mkstemp (tmpfname);
+  if (fd == -1)
+    {
+      printf ("cannot open temporary file: %m\n");
+      exit (1);
+    }
+
+  /* Make sure it is always removed.  */
+  unlink (tmpfname);
+
+  /* Create one page of data.  */
+  memset (data, '\0', ps);
+
+  /* Write the data to the file.  */
+  if (write (fd, data, ps) != (ssize_t) ps)
+    {
+      puts ("short write");
+      exit (1);
+    }
+
+  mem = mmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+  if (mem == MAP_FAILED)
+    {
+      printf ("mmap failed: %m\n");
+      exit (1);
+    }
+
+  s = (sem_t *) (((uintptr_t) mem + __alignof (sem_t))
+                & ~(__alignof (sem_t) - 1));
+  p = (char *) (s + 1);
+
+  if (sem_init (s, 1, 1) == -1)
+    {
+      puts ("init failed");
+      exit (1);
+    }
+
+  if (TEMP_FAILURE_RETRY (sem_wait (s)) == -1)
+    {
+      puts ("1st wait failed");
+      exit (1);
+    }
+
+  errno = 0;
+  if (TEMP_FAILURE_RETRY (sem_trywait (s)) != -1)
+    {
+      puts ("trywait succeeded");
+      exit (1);
+    }
+  else if (errno != EAGAIN)
+    {
+      puts ("trywait didn't return EAGAIN");
+      exit (1);
+    }
+
+  *p = 0;
+
+  puts ("going to fork now");
+  pid = fork ();
+  if (pid == -1)
+    {
+      puts ("fork failed");
+      exit (1);
+    }
+  else if (pid == 0)
+    {
+      /* Play some lock ping-pong.  It's our turn to unlock first.  */
+      if ((*p)++ != 0)
+       {
+         puts ("child: *p != 0");
+         exit (1);
+       }
+
+      if (sem_post (s) == -1)
+       {
+         puts ("child: 1st post failed");
+         exit (1);
+       }
+
+      puts ("child done");
+    }
+  else
+    {
+      if (TEMP_FAILURE_RETRY (sem_wait (s)) == -1)
+       {
+         printf ("parent: 2nd wait failed: %m\n");
+         exit (1);
+       }
+
+      if (*p != 1)
+       {
+         puts ("*p != 1");
+         exit (1);
+       }
+
+      puts ("parent done");
+    }
+
+  exit (0);
+}
diff --git a/test/nptl/tst-sem4.c b/test/nptl/tst-sem4.c
new file mode 100644 (file)
index 0000000..ccffbdd
--- /dev/null
@@ -0,0 +1,147 @@
+/* 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 <semaphore.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+
+static void
+remove_sem (int status, void *arg)
+{
+  sem_unlink (arg);
+}
+
+
+int
+main (void)
+{
+  sem_t *s;
+  sem_t *s2;
+  pid_t pid;
+  int val;
+
+  s = sem_open ("/glibc-tst-sem4", O_CREAT, 0600, 1);
+  if (s == SEM_FAILED)
+    {
+      if (errno == ENOSYS)
+       {
+         puts ("sem_open not supported.  Oh well.");
+         return 0;
+       }
+
+      /* Maybe the shm filesystem has strict permissions.  */
+      if (errno == EACCES)
+       {
+         puts ("sem_open not allowed.  Oh well.");
+         return 0;
+       }
+
+      printf ("sem_open: %m\n");
+      return 1;
+    }
+
+  on_exit (remove_sem, (void *) "/glibc-tst-sem4");
+
+  /* We have the semaphore object.  Now try again with O_EXCL, this
+     should fail.  */
+  s2 = sem_open ("/glibc-tst-sem4", O_CREAT | O_EXCL, 0600, 1);
+  if (s2 != SEM_FAILED)
+    {
+      puts ("2nd sem_open didn't fail");
+      return 1;
+    }
+  if (errno != EEXIST)
+    {
+      puts ("2nd sem_open returned wrong error");
+      return 1;
+    }
+
+  /* Check the value.  */
+  if (sem_getvalue (s, &val) == -1)
+    {
+      puts ("getvalue failed");
+      return 1;
+    }
+  if (val != 1)
+    {
+      printf ("initial value wrong: got %d, expected 1\n", val);
+      return 1;
+    }
+
+  if (TEMP_FAILURE_RETRY (sem_wait (s)) == -1)
+    {
+      puts ("1st sem_wait failed");
+      return 1;
+    }
+
+  pid = fork ();
+  if (pid == -1)
+    {
+      printf ("fork failed: %m\n");
+      return 1;
+    }
+
+  if (pid == 0)
+    {
+      /* Child.  */
+
+      /* Check the value.  */
+      if (sem_getvalue (s, &val) == -1)
+       {
+         puts ("child: getvalue failed");
+         return 1;
+       }
+      if (val != 0)
+       {
+         printf ("child: value wrong: got %d, expect 0\n", val);
+         return 1;
+       }
+
+      if (sem_post (s) == -1)
+       {
+         puts ("child: post failed");
+         return 1;
+       }
+    }
+  else
+    {
+      if (TEMP_FAILURE_RETRY (sem_wait (s)) == -1)
+       {
+         puts ("2nd sem_wait failed");
+         return 1;
+       }
+
+      if (sem_getvalue (s, &val) == -1)
+       {
+         puts ("parent: 2nd getvalue failed");
+         return 1;
+       }
+      if (val != 0)
+       {
+         printf ("parent: value wrong: got %d, expected 0\n", val);
+         return 1;
+       }
+    }
+
+  return 0;
+}
diff --git a/test/nptl/tst-sem5.c b/test/nptl/tst-sem5.c
new file mode 100644 (file)
index 0000000..cb85b8e
--- /dev/null
@@ -0,0 +1,80 @@
+/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <semaphore.h>
+#include <stdio.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/time.h>
+
+
+static int
+do_test (void)
+{
+  sem_t s;
+  struct timespec ts;
+  struct timeval tv;
+
+  if (sem_init (&s, 0, 1) == -1)
+    {
+      puts ("sem_init failed");
+      return 1;
+    }
+
+  if (TEMP_FAILURE_RETRY (sem_wait (&s)) == -1)
+    {
+      puts ("sem_wait failed");
+      return 1;
+    }
+
+  if (gettimeofday (&tv, NULL) != 0)
+    {
+      puts ("gettimeofday failed");
+      return 1;
+    }
+
+  TIMEVAL_TO_TIMESPEC (&tv, &ts);
+
+  /* We wait for half a second.  */
+  ts.tv_nsec += 500000000;
+  if (ts.tv_nsec >= 1000000000)
+    {
+      ++ts.tv_sec;
+      ts.tv_nsec -= 1000000000;
+    }
+
+  errno = 0;
+  if (TEMP_FAILURE_RETRY (sem_timedwait (&s, &ts)) != -1)
+    {
+      puts ("sem_timedwait succeeded");
+      return 1;
+    }
+  if (errno != ETIMEDOUT)
+    {
+      printf ("sem_timedwait return errno = %d instead of ETIMEDOUT\n",
+             errno);
+      return 1;
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-sem6.c b/test/nptl/tst-sem6.c
new file mode 100644 (file)
index 0000000..49240d9
--- /dev/null
@@ -0,0 +1,81 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <semaphore.h>
+#include <signal.h>
+#include <stdio.h>
+#include <unistd.h>
+
+
+static void
+handler (int sig)
+{
+  struct sigaction sa;
+
+  sa.sa_handler = SIG_DFL;
+  sa.sa_flags = 0;
+  sigemptyset (&sa.sa_mask);
+
+  sigaction (SIGALRM, &sa, NULL);
+
+  /* Rearm the timer.  */
+  alarm (1);
+}
+
+
+static int
+do_test (void)
+{
+  sem_t s;
+  struct sigaction sa;
+
+  sa.sa_handler = handler;
+  sa.sa_flags = 0;
+  sigemptyset (&sa.sa_mask);
+
+  sigaction (SIGALRM, &sa, NULL);
+
+  if (sem_init (&s, 0, 0) == -1)
+    {
+      puts ("init failed");
+      return 1;
+    }
+
+  /* Set an alarm for 1 second.  The wrapper will expect this.  */
+  alarm (1);
+
+  int res = sem_wait (&s);
+  if (res == 0)
+    {
+      puts ("wait succeeded");
+      return 1;
+    }
+  if (res != -1 || errno != EINTR)
+    {
+      puts ("wait didn't fail with EINTR");
+      return 1;
+    }
+
+  return 0;
+}
+
+#define TIMEOUT 3
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-sem7.c b/test/nptl/tst-sem7.c
new file mode 100644 (file)
index 0000000..a85c73e
--- /dev/null
@@ -0,0 +1,109 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <semaphore.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+
+static void
+remove_sem (int status, void *arg)
+{
+  sem_unlink (arg);
+}
+
+
+int
+main (void)
+{
+  sem_t *s;
+  sem_t *s2;
+  sem_t *s3;
+
+  s = sem_open ("/glibc-tst-sem7", O_CREAT, 0600, 1);
+  if (s == SEM_FAILED)
+    {
+      if (errno == ENOSYS)
+       {
+         puts ("sem_open not supported.  Oh well.");
+         return 0;
+       }
+
+      /* Maybe the shm filesystem has strict permissions.  */
+      if (errno == EACCES)
+       {
+         puts ("sem_open not allowed.  Oh well.");
+         return 0;
+       }
+
+      printf ("sem_open: %m\n");
+      return 1;
+    }
+
+  on_exit (remove_sem, (void *) "/glibc-tst-sem7");
+
+  /* We have the semaphore object.  Now try again.  We should get the
+     same address.  */
+  s2 = sem_open ("/glibc-tst-sem7", O_CREAT, 0600, 1);
+  if (s2 == SEM_FAILED)
+    {
+      puts ("2nd sem_open failed");
+      return 1;
+    }
+  if (s != s2)
+    {
+      puts ("2nd sem_open didn't return the same address");
+      return 1;
+    }
+
+  /* And again, this time without O_CREAT.  */
+  s3 = sem_open ("/glibc-tst-sem7", 0);
+  if (s3 == SEM_FAILED)
+    {
+      puts ("3rd sem_open failed");
+      return 1;
+    }
+  if (s != s3)
+    {
+      puts ("3rd sem_open didn't return the same address");
+      return 1;
+    }
+
+  /* Now close the handle.  Three times.  */
+  if (sem_close (s2) != 0)
+    {
+      puts ("1st sem_close failed");
+      return 1;
+    }
+  if (sem_close (s) != 0)
+    {
+      puts ("2nd sem_close failed");
+      return 1;
+    }
+  if (sem_close (s3) != 0)
+    {
+      puts ("3rd sem_close failed");
+      return 1;
+    }
+
+  return 0;
+}
diff --git a/test/nptl/tst-sem8.c b/test/nptl/tst-sem8.c
new file mode 100644 (file)
index 0000000..5dea575
--- /dev/null
@@ -0,0 +1,74 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <semaphore.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+
+static void
+remove_sem (int status, void *arg)
+{
+  sem_unlink (arg);
+}
+
+
+int
+main (void)
+{
+  sem_t *s;
+  int i;
+
+  on_exit (remove_sem, (void *) "/glibc-tst-sem8");
+
+  for (i = 0; i < 3; ++i)
+    {
+      s = sem_open ("/glibc-tst-sem8", O_CREAT, 0600, 1);
+      if (s == SEM_FAILED)
+       {
+         if (errno == ENOSYS)
+           {
+             puts ("sem_open not supported.  Oh well.");
+             return 0;
+           }
+
+         /* Maybe the shm filesystem has strict permissions.  */
+         if (errno == EACCES)
+           {
+             puts ("sem_open not allowed.  Oh well.");
+             return 0;
+           }
+
+         printf ("sem_open: %m\n");
+         return 1;
+       }
+
+      /* Now close the handle.  */
+      if (sem_close (s) != 0)
+       {
+         puts ("sem_close failed");
+         return 1;
+       }
+    }
+
+  return 0;
+}
diff --git a/test/nptl/tst-sem9.c b/test/nptl/tst-sem9.c
new file mode 100644 (file)
index 0000000..cdd8eaa
--- /dev/null
@@ -0,0 +1,81 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <semaphore.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+
+static void
+remove_sem (int status, void *arg)
+{
+  sem_unlink (arg);
+}
+
+
+int
+main (void)
+{
+  sem_t *s;
+  int i;
+
+  on_exit (remove_sem, (void *) "/glibc-tst-sem9");
+
+  for (i = 0; i < 3; ++i)
+    {
+      s = sem_open ("/glibc-tst-sem9", O_CREAT, 0600, 1);
+      if (s == SEM_FAILED)
+       {
+         if (errno == ENOSYS)
+           {
+             puts ("sem_open not supported.  Oh well.");
+             return 0;
+           }
+
+         /* Maybe the shm filesystem has strict permissions.  */
+         if (errno == EACCES)
+           {
+             puts ("sem_open not allowed.  Oh well.");
+             return 0;
+           }
+
+         printf ("sem_open: %m\n");
+         return 1;
+       }
+
+      /* Now close the handle.  */
+      if (sem_close (s) != 0)
+       {
+         puts ("sem_close failed");
+         return 1;
+       }
+
+      /* And remove it.  */
+      if (sem_unlink ("/glibc-tst-sem9") != 0)
+       {
+         puts ("sem_unlink failed");
+         return 1;
+       }
+    }
+
+  return 0;
+}
diff --git a/test/nptl/tst-signal1.c b/test/nptl/tst-signal1.c
new file mode 100644 (file)
index 0000000..3022f18
--- /dev/null
@@ -0,0 +1,189 @@
+/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+
+
+static sigset_t ss;
+static pthread_barrier_t *b;
+
+
+static void *
+tf (void *arg)
+{
+  sigdelset (&ss, SIGINT);
+
+  if (pthread_sigmask (SIG_SETMASK, &ss, NULL) != 0)
+    {
+      puts ("2nd pthread_sigmask failed");
+      exit (1);
+    }
+
+  pthread_barrier_wait (b);
+
+  int sig;
+  int res = sigwait (&ss, &sig);
+  if (res == 0)
+    {
+      printf ("sigwait returned successfully with signal %d\n", sig);
+      exit (1);
+    }
+
+  printf ("sigwait returned with %s (%d)\n", strerror (res), res);
+
+  return NULL;
+}
+
+
+static void
+receiver (void)
+{
+  pthread_t th;
+
+  /* Make sure the process doesn't run forever.  */
+  alarm (10);
+
+  sigfillset (&ss);
+
+  if (pthread_sigmask (SIG_SETMASK, &ss, NULL) != 0)
+    {
+      puts ("1st pthread_sigmask failed");
+      exit (1);
+    }
+
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("pthread_create failed");
+      exit (1);
+    }
+
+  if (pthread_join (th, NULL) == 0)
+    {
+      puts ("thread joined?!");
+      exit (1);
+    }
+
+  _exit (0);
+}
+
+
+static int
+do_test (void)
+{
+  char tmp[] = "/tmp/tst-signal1-XXXXXX";
+
+  int fd = mkstemp (tmp);
+  if (fd == -1)
+    {
+      puts ("mkstemp failed");
+      exit (1);
+    }
+
+  unlink (tmp);
+
+  int i;
+  for (i = 0; i < 20; ++i)
+    write (fd, "foobar xyzzy", 12);
+
+  b = mmap (NULL, sizeof (pthread_barrier_t), PROT_READ | PROT_WRITE,
+           MAP_SHARED, fd, 0);
+  if (b == MAP_FAILED)
+    {
+      puts ("mmap failed");
+      exit (1);
+    }
+
+  pthread_barrierattr_t ba;
+  if (pthread_barrierattr_init (&ba) != 0)
+    {
+      puts ("barrierattr_init failed");
+      exit (1);
+    }
+
+  if (pthread_barrierattr_setpshared (&ba, PTHREAD_PROCESS_SHARED) != 0)
+    {
+      puts ("barrierattr_setpshared failed");
+      exit (1);
+    }
+
+  if (pthread_barrier_init (b, &ba, 2) != 0)
+    {
+      puts ("barrier_init failed");
+      exit (1);
+    }
+
+  if (pthread_barrierattr_destroy (&ba) != 0)
+    {
+      puts ("barrierattr_destroy failed");
+      exit (1);
+    }
+
+  pid_t pid = fork ();
+  if (pid == -1)
+    {
+      puts ("fork failed");
+      exit (1);
+    }
+
+  if (pid == 0)
+    receiver ();
+
+  pthread_barrier_wait (b);
+
+  /* Wait a bit more.  */
+  struct timespec ts = { .tv_sec = 0, .tv_nsec = 10000000 };
+  nanosleep (&ts, NULL);
+
+  /* Send the signal.  */
+  puts ("sending the signal now");
+  kill (pid, SIGINT);
+
+  /* Wait for the process to terminate.  */
+  int status;
+  if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid)
+    {
+      puts ("wrong child reported terminated");
+      exit (1);
+    }
+
+  if (!WIFSIGNALED (status))
+    {
+      puts ("child wasn't signalled");
+      exit (1);
+    }
+
+  if (WTERMSIG (status) != SIGINT)
+    {
+      puts ("child not terminated with SIGINT");
+      exit (1);
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-signal2.c b/test/nptl/tst-signal2.c
new file mode 100644 (file)
index 0000000..3f2c75d
--- /dev/null
@@ -0,0 +1,198 @@
+/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+#include <string.h>
+
+
+static sigset_t ss;
+static pthread_barrier_t *b;
+
+
+static void *
+tf (void *arg)
+{
+  pthread_barrier_wait (b);
+
+  puts ("child: calling sigwait now");
+
+  int sig;
+  int err;
+  err = sigwait (&ss, &sig);
+  if (err != 0)
+    {
+      printf ("sigwait returned unsuccessfully: %s (%d)\n",
+             strerror (err), err);
+      _exit (1);
+    }
+
+  puts ("sigwait returned");
+
+  if (sig != SIGINT)
+    {
+      printf ("caught signal %d, expected %d (SIGINT)\n", sig, SIGINT);
+      _exit (1);
+    }
+
+  puts ("child thread terminating now");
+
+  return NULL;
+}
+
+
+static void
+receiver (void)
+{
+  pthread_t th;
+
+  /* Make sure the process doesn't run forever.  */
+  alarm (10);
+
+  sigfillset (&ss);
+
+  if (pthread_sigmask (SIG_SETMASK, &ss, NULL) != 0)
+    {
+      puts ("1st pthread_sigmask failed");
+      _exit (1);
+    }
+
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("pthread_create failed");
+      _exit (1);
+    }
+
+  if (pthread_join (th, NULL) != 0)
+    {
+      puts ("thread didn't join");
+      _exit (1);
+    }
+
+  puts ("join succeeded");
+
+  _exit (0);
+}
+
+
+static int
+do_test (void)
+{
+  char tmp[] = "/tmp/tst-signal1-XXXXXX";
+
+  int fd = mkstemp (tmp);
+  if (fd == -1)
+    {
+      puts ("mkstemp failed");
+      exit (1);
+    }
+
+  unlink (tmp);
+
+  int i;
+  for (i = 0; i < 20; ++i)
+    write (fd, "foobar xyzzy", 12);
+
+  b = mmap (NULL, sizeof (pthread_barrier_t), PROT_READ | PROT_WRITE,
+           MAP_SHARED, fd, 0);
+  if (b == MAP_FAILED)
+    {
+      puts ("mmap failed");
+      exit (1);
+    }
+
+  pthread_barrierattr_t ba;
+  if (pthread_barrierattr_init (&ba) != 0)
+    {
+      puts ("barrierattr_init failed");
+      exit (1);
+    }
+
+  if (pthread_barrierattr_setpshared (&ba, PTHREAD_PROCESS_SHARED) != 0)
+    {
+      puts ("barrierattr_setpshared failed");
+      exit (1);
+    }
+
+  if (pthread_barrier_init (b, &ba, 2) != 0)
+    {
+      puts ("barrier_init failed");
+      exit (1);
+    }
+
+  if (pthread_barrierattr_destroy (&ba) != 0)
+    {
+      puts ("barrierattr_destroy failed");
+      exit (1);
+    }
+
+  pid_t pid = fork ();
+  if (pid == -1)
+    {
+      puts ("fork failed");
+      exit (1);
+    }
+
+  if (pid == 0)
+    receiver ();
+
+  pthread_barrier_wait (b);
+
+  /* Wait a bit more.  */
+  struct timespec ts = { .tv_sec = 0, .tv_nsec = 10000000 };
+  nanosleep (&ts, NULL);
+
+  /* Send the signal.  */
+  puts ("sending the signal now");
+  kill (pid, SIGINT);
+
+  /* Wait for the process to terminate.  */
+  int status;
+  if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid)
+    {
+      puts ("wrong child reported terminated");
+      exit (1);
+    }
+
+  if (!WIFEXITED (status))
+    {
+      if (WIFSIGNALED (status))
+       printf ("child exited with signal %d\n", WTERMSIG (status));
+      else
+       puts ("child didn't exit normally");
+      exit (1);
+    }
+
+  if (WEXITSTATUS (status) != 0)
+    {
+      printf ("exit status %d != 0\n", WEXITSTATUS (status));
+      exit (1);
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-signal3.c b/test/nptl/tst-signal3.c
new file mode 100644 (file)
index 0000000..e4756c5
--- /dev/null
@@ -0,0 +1,261 @@
+/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+
+/* Number of different signalss to use.  Also is the number of
+   threads.  */
+#define N 10
+/* Maximum number of threads in flight at any one time.  */
+#define INFLIGHT 5
+/* Number of signals sent in total.  */
+#define ROUNDS 10000
+
+
+static int received[N][N];
+static int nsig[N];
+static pthread_t th[N];
+static sem_t sem;
+static pthread_mutex_t lock[N];
+static pthread_t th_main;
+static int sig0;
+
+static void
+handler (int sig)
+{
+  int i;
+  for (i = 0; i < N; ++i)
+    if (pthread_equal (pthread_self (), th[i]))
+      break;
+
+  if (i == N)
+    {
+      if (pthread_equal (pthread_self (), th_main))
+       puts ("signal received by main thread");
+      else
+       printf ("signal received by unknown thread (%lx)\n",
+               (unsigned long int) pthread_self ());
+      exit (1);
+    }
+
+  ++received[i][sig - sig0];
+
+  sem_post (&sem);
+}
+
+
+static void *
+tf (void *arg)
+{
+  int idx = (long int) arg;
+
+  sigset_t ss;
+  sigemptyset (&ss);
+
+  int i;
+  for (i = 0; i <= idx; ++i)
+    sigaddset (&ss, sig0 + i);
+
+  if (pthread_sigmask (SIG_UNBLOCK, &ss, NULL) != 0)
+    {
+      printf ("thread %d: pthread_sigmask failed\n", i);
+      exit (1);
+    }
+
+  pthread_mutex_lock (&lock[idx]);
+
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  /* Block all signals.  */
+  sigset_t ss;
+  sigfillset (&ss);
+
+  th_main = pthread_self ();
+
+  sig0 = SIGRTMIN;
+
+  if (pthread_sigmask (SIG_SETMASK, &ss, NULL) != 0)
+    {
+      puts ("1st pthread_sigmask failed");
+      exit (1);
+    }
+
+  /* Install the handler.  */
+  int i;
+  for (i = 0; i < N; ++i)
+    {
+      struct sigaction sa =
+       {
+         .sa_handler = handler,
+         .sa_flags = 0
+       };
+      sigfillset (&sa.sa_mask);
+
+      if (sigaction (sig0 + i, &sa, NULL) != 0)
+       {
+         printf ("sigaction for signal %d failed\n", i);
+         exit (1);
+       }
+    }
+
+  if (sem_init (&sem, 0, INFLIGHT) != 0)
+    {
+      puts ("sem_init failed");
+      exit (1);
+    }
+
+  pthread_attr_t a;
+
+  if (pthread_attr_init (&a) != 0)
+    {
+      puts ("attr_init failed");
+      exit (1);
+    }
+
+  if (pthread_attr_setstacksize (&a, 1 * 1024 * 1024) != 0)
+    {
+      puts ("attr_setstacksize failed");
+      return 1;
+    }
+
+  for (i = 0; i < N; ++i)
+    {
+      if (pthread_mutex_init (&lock[i], NULL) != 0)
+       {
+         printf ("mutex_init[%d] failed\n", i);
+       }
+
+      if (pthread_mutex_lock (&lock[i]) != 0)
+       {
+         printf ("mutex_lock[%d] failed\n", i);
+       }
+
+      if (pthread_create (&th[i], &a, tf, (void *) (long int) i) != 0)
+       {
+         printf ("create of thread %d failed\n", i);
+         exit (1);
+       }
+    }
+
+  if (pthread_attr_destroy (&a) != 0)
+    {
+      puts ("attr_destroy failed");
+      exit (1);
+    }
+
+  int result = 0;
+  unsigned int r = 42;
+  pid_t pid = getpid ();
+
+  for (i = 0; i < ROUNDS; ++i)
+    {
+      if (TEMP_FAILURE_RETRY (sem_wait (&sem)) != 0)
+       {
+         printf ("sem_wait round %d failed: %m\n", i);
+         exit (1);
+       }
+
+      int s = rand_r (&r) % N;
+
+      kill (pid, sig0 + s);
+    }
+
+  void *status;
+  for (i = 0; i < N; ++i)
+    {
+      if (pthread_mutex_unlock (&lock[i]) != 0)
+       {
+         printf ("unlock %d failed\n", i);
+         exit (1);
+       }
+
+      if (pthread_join (th[i], &status) != 0)
+       {
+         printf ("join %d failed\n", i);
+         result = 1;
+       }
+      else if (status != NULL)
+       {
+         printf ("%d: result != NULL\n", i);
+         result = 1;
+       }
+    }
+
+  int total = 0;
+  for (i = 0; i < N; ++i)
+    {
+      int j;
+
+      for (j = 0; j <= i; ++j)
+       total += received[i][j];
+
+      for (j = i + 1; j < N; ++j)
+       if (received[i][j] != 0)
+         {
+           printf ("thread %d received signal SIGRTMIN+%d\n", i, j);
+           result = 1;
+         }
+    }
+
+  if (total != ROUNDS)
+    {
+      printf ("total number of handled signals is %d, expected %d\n",
+             total, ROUNDS);
+      result = 1;
+    }
+
+  printf ("A total of %d signals sent and received\n", total);
+  for (i = 0; i < N; ++i)
+    {
+      printf ("thread %2d:", i);
+
+      int j;
+      for (j = 0; j <= i; ++j)
+       {
+         printf (" %5d", received[i][j]);
+         nsig[j] += received[i][j];
+       }
+
+      putchar ('\n');
+
+    }
+
+  printf ("\nTotal    :");
+  for (i = 0; i < N; ++i)
+    printf (" %5d", nsig[i]);
+  putchar ('\n');
+
+  return result;
+}
+
+#define TIMEOUT 10
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-signal4.c b/test/nptl/tst-signal4.c
new file mode 100644 (file)
index 0000000..dcb2893
--- /dev/null
@@ -0,0 +1,60 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static int
+do_test (void)
+{
+  sigset_t ss;
+
+  sigemptyset (&ss);
+
+  int i;
+  for (i = 0; i < 10000; ++i)
+    {
+      long int r = random ();
+
+      if (r != SIG_BLOCK && r != SIG_SETMASK && r != SIG_UNBLOCK)
+       {
+         int e = pthread_sigmask (r, &ss, NULL);
+
+         if (e == 0)
+           {
+             printf ("pthread_sigmask succeeded for how = %ld\n", r);
+             exit (1);
+           }
+
+         if (e != EINVAL)
+           {
+             puts ("pthread_sigmask didn't return EINVAL");
+             exit (1);
+           }
+       }
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-signal5.c b/test/nptl/tst-signal5.c
new file mode 100644 (file)
index 0000000..cea6ec1
--- /dev/null
@@ -0,0 +1,111 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+
+
+static sigset_t ss;
+
+
+static void *
+tf (void *arg)
+{
+  sigset_t ss2;
+  if (pthread_sigmask (SIG_SETMASK, NULL, &ss2) != 0)
+    {
+      puts ("child: sigmask failed");
+      exit (1);
+    }
+
+  int i;
+  for (i = 1; i < 32; ++i)
+    if (sigismember (&ss, i) && ! sigismember (&ss2, i))
+      {
+       printf ("signal %d set in parent mask, but not in child\n", i);
+       exit (1);
+      }
+    else if (! sigismember (&ss, i) && sigismember (&ss2, i))
+      {
+       printf ("signal %d set in child mask, but not in parent\n", i);
+       exit (1);
+      }
+
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  sigemptyset (&ss);
+  sigaddset (&ss, SIGUSR1);
+  if (pthread_sigmask (SIG_SETMASK, &ss, NULL) != 0)
+    {
+      puts ("1st sigmask failed");
+      exit (1);
+    }
+
+  pthread_t th;
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("1st create failed");
+      exit (1);
+    }
+
+  void *r;
+  if (pthread_join (th, &r) != 0)
+    {
+      puts ("1st join failed");
+      exit (1);
+    }
+
+  sigemptyset (&ss);
+  sigaddset (&ss, SIGUSR2);
+  sigaddset (&ss, SIGFPE);
+  if (pthread_sigmask (SIG_SETMASK, &ss, NULL) != 0)
+    {
+      puts ("2nd sigmask failed");
+      exit (1);
+    }
+
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("2nd create failed");
+      exit (1);
+    }
+
+  if (pthread_join (th, &r) != 0)
+    {
+      puts ("2nd join failed");
+      exit (1);
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-signal6.c b/test/nptl/tst-signal6.c
new file mode 100644 (file)
index 0000000..85a8640
--- /dev/null
@@ -0,0 +1,192 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+
+#define N 2
+static pthread_barrier_t bar;
+static struct
+{
+  void *p;
+  pthread_t s;
+} ti[N];
+static int sig1;
+
+
+static void
+handler (int sig)
+{
+  pthread_t self = pthread_self ();
+  size_t i;
+
+  for (i = 0; i < N; ++i)
+    if (ti[i].s == self)
+      {
+       if ((uintptr_t) ti[i].p <= (uintptr_t) &self
+           && (uintptr_t) ti[i].p + 2 * MINSIGSTKSZ > (uintptr_t) &self)
+         {
+           puts ("alt stack not used");
+           exit (1);
+         }
+
+       printf ("thread %zu used alt stack for signal %d\n", i, sig);
+
+       return;
+      }
+
+  puts ("handler: thread not found");
+  exit (1);
+}
+
+
+static void *
+tf (void *arg)
+{
+  size_t nr = (uintptr_t) arg;
+  if (nr >= N)
+    {
+      puts ("wrong nr parameter");
+      exit (1);
+    }
+
+  sigset_t ss;
+  sigemptyset (&ss);
+  size_t i;
+  for (i = 0; i < N; ++i)
+    if (i != nr)
+      if (sigaddset (&ss, sig1 + i) != 0)
+       {
+         puts ("tf: sigaddset failed");
+         exit (1);
+       }
+  if (pthread_sigmask (SIG_BLOCK, &ss, NULL) != 0)
+    {
+      puts ("tf: sigmask failed");
+      exit (1);
+    }
+
+  void *p = malloc (2 * MINSIGSTKSZ);
+  if (p == NULL)
+    {
+      puts ("tf: malloc failed");
+      exit (1);
+    }
+
+  stack_t s;
+  s.ss_sp = p;
+  s.ss_size = 2 * MINSIGSTKSZ;
+  s.ss_flags = 0;
+  if (sigaltstack (&s, NULL) != 0)
+    {
+      puts ("tf: sigaltstack failed");
+      exit (1);
+    }
+
+  ti[nr].p = p;
+  ti[nr].s = pthread_self ();
+
+  pthread_barrier_wait (&bar);
+
+  pthread_barrier_wait (&bar);
+
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  sig1 = SIGRTMIN;
+  if (sig1 + N > SIGRTMAX)
+    {
+      puts ("too few RT signals");
+      return 0;
+    }
+
+  struct sigaction sa;
+  sa.sa_handler = handler;
+  sa.sa_flags = 0;
+  sigemptyset (&sa.sa_mask);
+
+  if (sigaction (sig1, &sa, NULL) != 0
+      || sigaction (sig1 + 1, &sa, NULL) != 0
+      || sigaction (sig1 + 2, &sa, NULL) != 0)
+    {
+      puts ("sigaction failed");
+      return 1;
+    }
+
+  if (pthread_barrier_init (&bar, NULL, 1 + N) != 0)
+    {
+      puts ("barrier_init failed");
+      return 1;
+    }
+
+  pthread_t th[N];
+  size_t i;
+  for (i = 0; i < N; ++i)
+    if (pthread_create (&th[i], NULL, tf, (void *) (long int) i) != 0)
+      {
+       puts ("create failed");
+       return 1;
+      }
+
+  /* Block the three signals.  */
+  sigset_t ss;
+  sigemptyset (&ss);
+  for (i = 0; i <= N; ++i)
+    sigaddset (&ss, sig1 + i);
+  if (pthread_sigmask (SIG_BLOCK, &ss, NULL) != 0)
+    {
+      puts ("main: sigmask failed");
+      return 1;
+    }
+
+  pthread_barrier_wait (&bar);
+
+  /* Send some signals.  */
+  pid_t me = getpid ();
+  kill (me, sig1 + N);
+  for (i = 0; i < N; ++i)
+    kill (me, sig1 + i);
+  kill (me, sig1 + N);
+
+  /* Give the signals a chance to be worked on.  */
+  sleep (1);
+
+  pthread_barrier_wait (&bar);
+
+  for (i = 0; i < N; ++i)
+    if (pthread_join (th[i], NULL) != 0)
+      {
+       puts ("join failed");
+       return 1;
+      }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-spin1.c b/test/nptl/tst-spin1.c
new file mode 100644 (file)
index 0000000..259b4b4
--- /dev/null
@@ -0,0 +1,57 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with 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>
+
+
+static int
+do_test (void)
+{
+  pthread_spinlock_t s;
+
+  if (pthread_spin_init (&s, PTHREAD_PROCESS_PRIVATE) != 0)
+    {
+      puts ("spin_init failed");
+      return 1;
+    }
+
+  if (pthread_spin_lock (&s) != 0)
+    {
+      puts ("spin_lock failed");
+      return 1;
+    }
+
+  if (pthread_spin_unlock (&s) != 0)
+    {
+      puts ("spin_unlock failed");
+      return 1;
+    }
+
+  if (pthread_spin_destroy (&s) != 0)
+    {
+      puts ("spin_destroy failed");
+      return 1;
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-spin2.c b/test/nptl/tst-spin2.c
new file mode 100644 (file)
index 0000000..5b1df6c
--- /dev/null
@@ -0,0 +1,159 @@
+/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+
+
+static int
+do_test (void)
+{
+  size_t ps = sysconf (_SC_PAGESIZE);
+  char tmpfname[] = "/tmp/tst-spin2.XXXXXX";
+  char data[ps];
+  void *mem;
+  int fd;
+  pthread_spinlock_t *s;
+  pid_t pid;
+  char *p;
+  int err;
+
+  fd = mkstemp (tmpfname);
+  if (fd == -1)
+    {
+      printf ("cannot open temporary file: %m\n");
+      return 1;
+    }
+
+  /* Make sure it is always removed.  */
+  unlink (tmpfname);
+
+  /* Create one page of data.  */
+  memset (data, '\0', ps);
+
+  /* Write the data to the file.  */
+  if (write (fd, data, ps) != (ssize_t) ps)
+    {
+      puts ("short write");
+      return 1;
+    }
+
+  mem = mmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+  if (mem == MAP_FAILED)
+    {
+      printf ("mmap failed: %m\n");
+      return 1;
+    }
+
+  s = (pthread_spinlock_t *) (((uintptr_t) mem
+                              + __alignof (pthread_spinlock_t))
+                             & ~(__alignof (pthread_spinlock_t) - 1));
+  p = (char *) (s + 1);
+
+  if (pthread_spin_init (s, PTHREAD_PROCESS_SHARED) != 0)
+    {
+      puts ("spin_init failed");
+      return 1;
+    }
+
+  if (pthread_spin_lock (s) != 0)
+    {
+      puts ("spin_lock failed");
+      return 1;
+    }
+
+  err = pthread_spin_trylock (s);
+  if (err == 0)
+    {
+      puts ("1st spin_trylock succeeded");
+      return 1;
+    }
+  else if (err != EBUSY)
+    {
+      puts ("1st spin_trylock didn't return EBUSY");
+      return 1;
+    }
+
+  err = pthread_spin_unlock (s);
+  if (err != 0)
+    {
+      puts ("parent: spin_unlock failed");
+      return 1;
+    }
+
+  err = pthread_spin_trylock (s);
+  if (err != 0)
+    {
+      puts ("2nd spin_trylock failed");
+      return 1;
+    }
+
+  *p = 0;
+
+  puts ("going to fork now");
+  pid = fork ();
+  if (pid == -1)
+    {
+      puts ("fork failed");
+      return 1;
+    }
+  else if (pid == 0)
+    {
+      /* Play some lock ping-pong.  It's our turn to unlock first.  */
+      if ((*p)++ != 0)
+       {
+         puts ("child: *p != 0");
+         return 1;
+       }
+
+      if (pthread_spin_unlock (s) != 0)
+       {
+         puts ("child: 1st spin_unlock failed");
+         return 1;
+       }
+
+      puts ("child done");
+    }
+  else
+    {
+      if (pthread_spin_lock (s) != 0)
+       {
+         puts ("parent: 2nd spin_lock failed");
+         return 1;
+       }
+
+      puts ("waiting for child");
+
+      waitpid (pid, NULL, 0);
+
+      puts ("parent done");
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-spin3.c b/test/nptl/tst-spin3.c
new file mode 100644 (file)
index 0000000..4437740
--- /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 <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <unistd.h>
+
+
+static int
+do_test (void)
+{
+  pthread_spinlock_t s;
+
+  if (pthread_spin_init (&s, PTHREAD_PROCESS_PRIVATE) != 0)
+    {
+      puts ("spin_init failed");
+      return 1;
+    }
+
+  if (pthread_spin_lock (&s) != 0)
+    {
+      puts ("1st spin_lock failed");
+      return 1;
+    }
+
+  /* Set an alarm for 1 second.  The wrapper will expect this.  */
+  alarm (1);
+
+  /* This call should never return.  */
+  pthread_spin_lock (&s);
+
+  puts ("2nd spin_lock returned");
+  return 1;
+}
+
+#define EXPECTED_SIGNAL SIGALRM
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-stack-align.h b/test/nptl/tst-stack-align.h
new file mode 100644 (file)
index 0000000..59b1e65
--- /dev/null
@@ -0,0 +1,35 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stdio.h>
+#include <stdint.h>
+
+#define TEST_STACK_ALIGN() \
+  ({                                                                        \
+    double _d = 12.0;                                                       \
+    long double _ld = 15.0;                                                 \
+    int _ret = 0;                                                           \
+    printf ("double:  %g %p %zu\n", _d, &_d, __alignof (double));           \
+    if ((((uintptr_t) &_d) & (__alignof (double) - 1)) != 0)                \
+      _ret = 1;                                                                     \
+                                                                            \
+    printf ("ldouble: %Lg %p %zu\n", _ld, &_ld, __alignof (long double));    \
+    if ((((uintptr_t) &_ld) & (__alignof (long double) - 1)) != 0)          \
+      _ret = 1;                                                                     \
+    _ret;                                                                   \
+    })
diff --git a/test/nptl/tst-stack1.c b/test/nptl/tst-stack1.c
new file mode 100644 (file)
index 0000000..9340598
--- /dev/null
@@ -0,0 +1,146 @@
+/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <limits.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/param.h>
+#include <unistd.h>
+
+
+static void *stack;
+static size_t size;
+
+
+static void *
+tf (void *a)
+{
+  int result = 0;
+
+  puts ("child start");
+
+  pthread_attr_t attr;
+  if (pthread_getattr_np (pthread_self (), &attr) != 0)
+    {
+      puts ("getattr_np failed");
+      exit (1);
+    }
+
+  size_t test_size;
+  void *test_stack;
+  if (pthread_attr_getstack (&attr, &test_stack, &test_size) != 0)
+    {
+      puts ("attr_getstack failed");
+      exit (1);
+    }
+
+  if (test_size != size)
+    {
+      printf ("child: reported size differs: is %zu, expected %zu\n",
+             test_size, size);
+      result = 1;
+    }
+
+  if (test_stack != stack)
+    {
+      printf ("child: reported stack address differs: is %p, expected %p\n",
+             test_stack, stack);
+      result = 1;
+    }
+
+  puts ("child OK");
+
+  return result ? (void *) 1l : NULL;
+}
+
+
+int
+do_test (void)
+{
+  int result = 0;
+
+  size = MAX (4 * getpagesize (), PTHREAD_STACK_MIN);
+  if (posix_memalign (&stack, getpagesize (), size) != 0)
+    {
+      puts ("out of memory while allocating the stack memory");
+      exit (1);
+    }
+
+  pthread_attr_t attr;
+  if (pthread_attr_init (&attr) != 0)
+    {
+      puts ("attr_init failed");
+      exit (1);
+    }
+
+  puts ("attr_setstack");
+  if (pthread_attr_setstack (&attr, stack, size) != 0)
+    {
+      puts ("attr_setstack failed");
+      exit (1);
+    }
+
+  size_t test_size;
+  void *test_stack;
+  puts ("attr_getstack");
+  if (pthread_attr_getstack (&attr, &test_stack, &test_size) != 0)
+    {
+      puts ("attr_getstack failed");
+      exit (1);
+    }
+
+  if (test_size != size)
+    {
+      printf ("reported size differs: is %zu, expected %zu\n",
+             test_size, size);
+      result = 1;
+    }
+
+  if (test_stack != stack)
+    {
+      printf ("reported stack address differs: is %p, expected %p\n",
+             test_stack, stack);
+      result = 1;
+    }
+
+  puts ("create");
+
+  pthread_t th;
+  if (pthread_create (&th, &attr, tf, NULL) != 0)
+    {
+      puts ("failed to create thread");
+      exit (1);
+    }
+
+  void *status;
+  if (pthread_join (th, &status) != 0)
+    {
+      puts ("join failed");
+      exit (1);
+    }
+
+  result |= status != NULL;
+
+  return result;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-stack2.c b/test/nptl/tst-stack2.c
new file mode 100644 (file)
index 0000000..5fcdb18
--- /dev/null
@@ -0,0 +1,80 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* Test whether it is possible to create a thread with PTHREAD_STACK_MIN
+   stack size.  */
+
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <limits.h>
+
+static int seen;
+
+static void *
+tf (void *p)
+{
+  ++seen;
+  return NULL;
+}
+
+static int
+do_test (void)
+{
+  pthread_attr_t attr;
+  pthread_attr_init (&attr);
+
+  int result = 0;
+  int res = pthread_attr_setstacksize (&attr, PTHREAD_STACK_MIN);
+  if (res)
+    {
+      printf ("pthread_attr_setstacksize failed %d\n", res);
+      result = 1;
+    }
+
+  /* Create the thread.  */
+  pthread_t th;
+  res = pthread_create (&th, &attr, tf, NULL);
+  if (res)
+    {
+      printf ("pthread_create failed %d\n", res);
+      result = 1;
+    }
+  else
+    {
+      res = pthread_join (th, NULL);
+      if (res)
+       {
+         printf ("pthread_join failed %d\n", res);
+         result = 1;
+       }
+    }
+
+  if (seen != 1)
+    {
+      printf ("seen %d != 1\n", seen);
+      result = 1;
+    }
+
+  return result;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-stdio1.c b/test/nptl/tst-stdio1.c
new file mode 100644 (file)
index 0000000..ebb3e2f
--- /dev/null
@@ -0,0 +1,57 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <unistd.h>
+
+
+static void *tf (void *a)
+{
+  flockfile (stdout);
+  /* This call should never return.  */
+  return a;
+}
+
+
+int
+do_test (void)
+{
+  pthread_t th;
+
+  flockfile (stdout);
+
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      write (2, "create failed\n", 14);
+      _exit (1);
+    }
+
+  pthread_join (th, NULL);
+
+  puts ("join returned");
+
+  return 0;
+}
+
+
+#define EXPECTED_SIGNAL SIGALRM
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-stdio2.c b/test/nptl/tst-stdio2.c
new file mode 100644 (file)
index 0000000..08d6add
--- /dev/null
@@ -0,0 +1,82 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+
+static void *tf (void *a)
+{
+  puts ("start tf");
+
+  /* Multiple locking, implicitly or explicitly, must be possible.  */
+  flockfile (stdout);
+
+  puts ("after first flockfile");
+
+  flockfile (stdout);
+
+  puts ("foo");
+
+  funlockfile (stdout);
+
+  puts ("after first funlockfile");
+
+  funlockfile (stdout);
+
+  puts ("all done");
+
+  return a;
+}
+
+
+int
+do_test (void)
+{
+  pthread_t th;
+
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      write (2, "create failed\n", 14);
+      _exit (1);
+    }
+
+  void *result;
+  if (pthread_join (th, &result) != 0)
+    {
+      puts ("join failed");
+      exit (1);
+    }
+  else if (result != NULL)
+    {
+      printf ("wrong return value: %p, expected %p\n", result, NULL);
+      exit (1);
+    }
+
+  puts ("join returned succsefully");
+
+  return 0;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-sysconf.c b/test/nptl/tst-sysconf.c
new file mode 100644 (file)
index 0000000..3ad1b6a
--- /dev/null
@@ -0,0 +1,48 @@
+/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+
+static int
+do_test (void)
+{
+  puts ("We expect no limits");
+  /* We have no fixed limit on the number of threads.  Make sure the
+     headers tell the right story.  */
+#ifdef PTHREAD_THREADS_MAX
+  printf ("Header report maximum number of threads = %lu\n",
+         (unsigned long int) PTHREAD_THREADS_MAX);
+  return 1;
+#else
+  long int r = sysconf (_SC_THREAD_THREADS_MAX);
+  if (r != -1)
+    {
+      printf ("sysconf(_SC_THREAD_THREADS_MAX) return %ld\n", r);
+      return 1;
+    }
+#endif
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-timer2.c b/test/nptl/tst-timer2.c
new file mode 100644 (file)
index 0000000..60026c1
--- /dev/null
@@ -0,0 +1,65 @@
+/* Test for crashing bugs when trying to create too many timers.  */
+
+#include <stdio.h>
+#include <time.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <unistd.h>
+
+#if _POSIX_THREADS
+# include <pthread.h>
+
+void
+thread (union sigval arg)
+{
+  puts ("Timeout");
+}
+
+int
+do_test (void)
+{
+  int i, res;
+  timer_t timerId;
+  struct itimerspec itval;
+  struct sigevent sigev;
+
+  itval.it_interval.tv_sec = 2;
+  itval.it_interval.tv_nsec = 0;
+  itval.it_value.tv_sec = 2;
+  itval.it_value.tv_nsec = 0;
+
+  sigev.sigev_notify = SIGEV_THREAD;
+  sigev.sigev_signo = SIGRTMIN;
+  sigev.sigev_notify_function = thread;
+  sigev.sigev_notify_attributes = 0;
+  sigev.sigev_value.sival_ptr = (void *) &timerId;
+
+  for (i = 0; i < 100; i++)
+    {
+      printf ("cnt = %d\n", i);
+
+      if (timer_create (CLOCK_REALTIME, &sigev, &timerId) < 0)
+       {
+         perror ("timer_create");
+         continue;
+       }
+
+      res = timer_settime (timerId, 0, &itval, NULL);
+      if (res < 0)
+       perror ("timer_settime");
+
+      res = timer_delete (timerId);
+      if (res < 0)
+       perror ("timer_delete");
+    }
+
+  return 0;
+}
+
+# define TEST_FUNCTION do_test ()
+#else
+# define TEST_FUNCTION 0
+#endif
+
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-timer3.c b/test/nptl/tst-timer3.c
new file mode 100644 (file)
index 0000000..8113f66
--- /dev/null
@@ -0,0 +1,86 @@
+/* Test for bogus per-thread deletion of timers.  */
+
+#include <stdio.h>
+#include <error.h>
+#include <time.h>
+#include <signal.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <unistd.h>
+#if _POSIX_THREADS
+# include <pthread.h>
+
+
+/* Creating timers in another thread should work too.  */
+static void *
+do_timer_create (void *arg)
+{
+  struct sigevent *const sigev = arg;
+  timer_t *const timerId = sigev->sigev_value.sival_ptr;
+  if (timer_create (CLOCK_REALTIME, sigev, timerId) < 0)
+    {
+      printf ("timer_create: %m\n");
+      return NULL;
+    }
+  return timerId;
+}
+
+
+static int
+do_test (void)
+{
+  int i, res;
+  timer_t timerId;
+  struct itimerspec itval;
+  struct sigevent sigev;
+
+  itval.it_interval.tv_sec = 2;
+  itval.it_interval.tv_nsec = 0;
+  itval.it_value.tv_sec = 2;
+  itval.it_value.tv_nsec = 0;
+
+  sigev.sigev_notify = SIGEV_SIGNAL;
+  sigev.sigev_signo = SIGALRM;
+  sigev.sigev_value.sival_ptr = (void *) &timerId;
+
+  for (i = 0; i < 100; i++)
+    {
+      printf ("cnt = %d\n", i);
+
+      pthread_t thr;
+      res = pthread_create (&thr, NULL, &do_timer_create, &sigev);
+      if (res)
+       {
+         printf ("pthread_create: %s\n", strerror (res));
+         continue;
+       }
+      void *val;
+      res = pthread_join (thr, &val);
+      if (res)
+       {
+         printf ("pthread_join: %s\n", strerror (res));
+         continue;
+       }
+      if (val == NULL)
+       continue;
+
+      res = timer_settime (timerId, 0, &itval, NULL);
+      if (res < 0)
+       printf ("timer_settime: %m\n");
+
+      res = timer_delete (timerId);
+      if (res < 0)
+       printf ("timer_delete: %m\n");
+    }
+
+  return 0;
+}
+
+# define TEST_FUNCTION do_test ()
+#else
+# define TEST_FUNCTION 0
+#endif
+
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-timer4.c b/test/nptl/tst-timer4.c
new file mode 100644 (file)
index 0000000..5bec011
--- /dev/null
@@ -0,0 +1,648 @@
+/* Tests for POSIX timer implementation.
+   Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2004
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#if _POSIX_THREADS
+# include <pthread.h>
+
+# ifndef TEST_CLOCK
+#  define TEST_CLOCK           CLOCK_REALTIME
+# endif
+
+pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
+
+timer_t timer_none, timer_sig1, timer_sig2, timer_thr1, timer_thr2;
+
+int thr1_cnt, thr1_err;
+union sigval thr1_sigval;
+struct timespec thr1_ts;
+
+static void
+thr1 (union sigval sigval)
+{
+  pthread_mutex_lock (&lock);
+  thr1_err = clock_gettime (TEST_CLOCK, &thr1_ts);
+  if (thr1_cnt >= 5)
+    {
+      struct itimerspec it = { };
+      thr1_err |= timer_settime (timer_thr1, 0, &it, NULL);
+    }
+  thr1_sigval = sigval;
+  ++thr1_cnt;
+  pthread_cond_signal (&cond);
+  pthread_mutex_unlock (&lock);
+}
+
+int thr2_cnt, thr2_err;
+union sigval thr2_sigval;
+size_t thr2_guardsize;
+struct timespec thr2_ts;
+
+static void
+thr2 (union sigval sigval)
+{
+  pthread_attr_t nattr;
+  int err = 0;
+  size_t guardsize = -1;
+  int ret = pthread_getattr_np (pthread_self (), &nattr);
+  if (ret)
+    {
+      errno = ret;
+      printf ("*** pthread_getattr_np failed: %m\n");
+      err = 1;
+    }
+  else
+    {
+      ret = pthread_attr_getguardsize (&nattr, &guardsize);
+      if (ret)
+        {
+          errno = ret;
+          printf ("*** pthread_attr_getguardsize failed: %m\n");
+          err = 1;
+        }
+      if (pthread_attr_destroy (&nattr) != 0)
+        {
+          puts ("*** pthread_attr_destroy failed");
+          err = 1;
+        }
+    }
+  pthread_mutex_lock (&lock);
+  thr2_err = clock_gettime (TEST_CLOCK, &thr2_ts) | err;
+  if (thr2_cnt >= 5)
+    {
+      struct itimerspec it = { };
+      thr2_err |= timer_settime (timer_thr2, 0, &it, NULL);
+    }
+  thr2_sigval = sigval;
+  ++thr2_cnt;
+  thr2_guardsize = guardsize;
+  pthread_cond_signal (&cond);
+  pthread_mutex_unlock (&lock);
+}
+
+volatile int sig1_cnt, sig1_err;
+volatile union sigval sig1_sigval;
+struct timespec sig1_ts;
+
+static void
+sig1_handler (int sig, siginfo_t *info, void *ctx)
+{
+  int err = 0;
+  if (sig != SIGRTMIN) err |= 1 << 0;
+  if (info->si_signo != SIGRTMIN) err |= 1 << 1;
+  if (info->si_code != SI_TIMER) err |= 1 << 2;
+  if (clock_gettime (TEST_CLOCK, &sig1_ts) != 0)
+    err |= 1 << 3;
+  if (sig1_cnt >= 5)
+    {
+      struct itimerspec it = { };
+      if (timer_settime (timer_sig1, 0, &it, NULL))
+       err |= 1 << 4;
+    }
+  sig1_err |= err;
+  sig1_sigval = info->si_value;
+  ++sig1_cnt;
+}
+
+volatile int sig2_cnt, sig2_err;
+volatile union sigval sig2_sigval;
+struct timespec sig2_ts;
+
+static void
+sig2_handler (int sig, siginfo_t *info, void *ctx)
+{
+  int err = 0;
+  if (sig != SIGRTMIN + 1) err |= 1 << 0;
+  if (info->si_signo != SIGRTMIN + 1) err |= 1 << 1;
+  if (info->si_code != SI_TIMER) err |= 1 << 2;
+  if (clock_gettime (TEST_CLOCK, &sig2_ts) != 0)
+    err |= 1 << 3;
+  if (sig2_cnt >= 5)
+    {
+      struct itimerspec it = { };
+      if (timer_settime (timer_sig2, 0, &it, NULL))
+       err |= 1 << 4;
+    }
+  sig2_err |= err;
+  sig2_sigval = info->si_value;
+  ++sig2_cnt;
+}
+
+/* Check if end is later or equal to start + nsec.  */
+static int
+check_ts (const char *name, const struct timespec *start,
+         const struct timespec *end, long msec)
+{
+  struct timespec ts = *start;
+
+  ts.tv_sec += msec / 1000000;
+  ts.tv_nsec += (msec % 1000000) * 1000;
+  if (ts.tv_nsec >= 1000000000)
+    {
+      ++ts.tv_sec;
+      ts.tv_nsec -= 1000000000;
+    }
+  if (end->tv_sec < ts.tv_sec
+      || (end->tv_sec == ts.tv_sec && end->tv_nsec < ts.tv_nsec))
+    {
+      printf ("\
+*** timer %s invoked too soon: %ld.%09ld instead of expected %ld.%09ld\n",
+             name, (long) end->tv_sec, end->tv_nsec,
+             (long) ts.tv_sec, ts.tv_nsec);
+      return 1;
+    }
+  else
+    return 0;
+}
+
+#define TIMEOUT 15
+#define TEST_FUNCTION do_test ()
+static int
+do_test (void)
+{
+  int result = 0;
+
+#ifdef TEST_CLOCK_MISSING
+  const char *missing = TEST_CLOCK_MISSING (TEST_CLOCK);
+  if (missing != NULL)
+    {
+      printf ("%s missing, skipping test\n", missing);
+      return 0;
+    }
+#endif
+
+  struct timespec ts;
+  if (clock_gettime (TEST_CLOCK, &ts) != 0)
+    {
+      printf ("*** clock_gettime failed: %m\n");
+      result = 1;
+    }
+  else
+    printf ("clock_gettime returned timespec = { %ld, %ld }\n",
+           (long) ts.tv_sec, ts.tv_nsec);
+
+  if (clock_getres (TEST_CLOCK, &ts) != 0)
+    {
+      printf ("*** clock_getres failed: %m\n");
+      result = 1;
+    }
+  else
+    printf ("clock_getres returned timespec = { %ld, %ld }\n",
+           (long) ts.tv_sec, ts.tv_nsec);
+
+  struct sigevent ev;
+  memset (&ev, 0x11, sizeof (ev));
+  ev.sigev_notify = SIGEV_NONE;
+  if (timer_create (TEST_CLOCK, &ev, &timer_none) != 0)
+    {
+      printf ("*** timer_create for timer_none failed: %m\n");
+      return 1;
+    }
+
+  struct sigaction sa = { .sa_sigaction = sig1_handler,
+                         .sa_flags = SA_SIGINFO };
+  sigemptyset (&sa.sa_mask);
+  sigaction (SIGRTMIN, &sa, NULL);
+  sa.sa_sigaction = sig2_handler;
+  sigaction (SIGRTMIN + 1, &sa, NULL);
+
+  memset (&ev, 0x22, sizeof (ev));
+  ev.sigev_notify = SIGEV_SIGNAL;
+  ev.sigev_signo = SIGRTMIN;
+  ev.sigev_value.sival_ptr = &ev;
+  if (timer_create (TEST_CLOCK, &ev, &timer_sig1) != 0)
+    {
+      printf ("*** timer_create for timer_sig1 failed: %m\n");
+      return 1;
+    }
+
+  memset (&ev, 0x33, sizeof (ev));
+  ev.sigev_notify = SIGEV_SIGNAL;
+  ev.sigev_signo = SIGRTMIN + 1;
+  ev.sigev_value.sival_int = 163;
+  if (timer_create (TEST_CLOCK, &ev, &timer_sig2) != 0)
+    {
+      printf ("*** timer_create for timer_sig2 failed: %m\n");
+      return 1;
+    }
+
+  memset (&ev, 0x44, sizeof (ev));
+  ev.sigev_notify = SIGEV_THREAD;
+  ev.sigev_notify_function = thr1;
+  ev.sigev_notify_attributes = NULL;
+  ev.sigev_value.sival_ptr = &ev;
+  if (timer_create (TEST_CLOCK, &ev, &timer_thr1) != 0)
+    {
+      printf ("*** timer_create for timer_thr1 failed: %m\n");
+      return 1;
+    }
+
+  pthread_attr_t nattr;
+  if (pthread_attr_init (&nattr)
+      || pthread_attr_setguardsize (&nattr, 0))
+    {
+      puts ("*** pthread_attr_t setup failed");
+      result = 1;
+    }
+
+  memset (&ev, 0x55, sizeof (ev));
+  ev.sigev_notify = SIGEV_THREAD;
+  ev.sigev_notify_function = thr2;
+  ev.sigev_notify_attributes = &nattr;
+  ev.sigev_value.sival_int = 111;
+  if (timer_create (TEST_CLOCK, &ev, &timer_thr2) != 0)
+    {
+      printf ("*** timer_create for timer_thr2 failed: %m\n");
+      return 1;
+    }
+
+  int ret = timer_getoverrun (timer_thr1);
+  if (ret != 0)
+    {
+      if (ret == -1)
+       printf ("*** timer_getoverrun failed: %m\n");
+      else
+       printf ("*** timer_getoverrun returned %d != 0\n", ret);
+      result = 1;
+    }
+
+  struct itimerspec it;
+  it.it_value.tv_sec = 0;
+  it.it_value.tv_nsec = -26;
+  it.it_interval.tv_sec = 0;
+  it.it_interval.tv_nsec = 0;
+  if (timer_settime (timer_sig1, 0, &it, NULL) == 0)
+    {
+      puts ("*** timer_settime with negative tv_nsec unexpectedly succeeded");
+      result = 1;
+    }
+  else if (errno != EINVAL)
+    {
+      printf ("*** timer_settime with negative tv_nsec did not fail with "
+             "EINVAL: %m\n");
+      result = 1;
+    }
+
+  it.it_value.tv_nsec = 100000;
+  it.it_interval.tv_nsec = 1000000000;
+  if (timer_settime (timer_sig2, 0, &it, NULL) == 0)
+    {
+      puts ("\
+*** timer_settime with tv_nsec 1000000000 unexpectedly succeeded");
+      result = 1;
+    }
+  else if (errno != EINVAL)
+    {
+      printf ("*** timer_settime with tv_nsec 1000000000 did not fail with "
+             "EINVAL: %m\n");
+      result = 1;
+    }
+
+#if 0
+  it.it_value.tv_nsec = 0;
+  it.it_interval.tv_nsec = -26;
+  if (timer_settime (timer_thr1, 0, &it, NULL) != 0)
+    {
+      printf ("\
+!!! timer_settime with it_value 0 it_interval invalid failed: %m\n");
+      /* FIXME: is this mandated by POSIX?
+      result = 1; */
+    }
+
+  it.it_interval.tv_nsec = 3000000000;
+  if (timer_settime (timer_thr2, 0, &it, NULL) != 0)
+    {
+      printf ("\
+!!! timer_settime with it_value 0 it_interval invalid failed: %m\n");
+      /* FIXME: is this mandated by POSIX?
+      result = 1; */
+    }
+#endif
+
+  struct timespec startts;
+  if (clock_gettime (TEST_CLOCK, &startts) != 0)
+    {
+      printf ("*** clock_gettime failed: %m\n");
+      result = 1;
+    }
+
+  it.it_value.tv_nsec = 100000000;
+  it.it_interval.tv_nsec = 0;
+  if (timer_settime (timer_none, 0, &it, NULL) != 0)
+    {
+      printf ("*** timer_settime timer_none failed: %m\n");
+      result = 1;
+    }
+
+  it.it_value.tv_nsec = 200000000;
+  if (timer_settime (timer_thr1, 0, &it, NULL) != 0)
+    {
+      printf ("*** timer_settime timer_thr1 failed: %m\n");
+      result = 1;
+    }
+
+  it.it_value.tv_nsec = 300000000;
+  if (timer_settime (timer_thr2, 0, &it, NULL) != 0)
+    {
+      printf ("*** timer_settime timer_thr2 failed: %m\n");
+      result = 1;
+    }
+
+  it.it_value.tv_nsec = 400000000;
+  if (timer_settime (timer_sig1, 0, &it, NULL) != 0)
+    {
+      printf ("*** timer_settime timer_sig1 failed: %m\n");
+      result = 1;
+    }
+
+  it.it_value.tv_nsec = 500000000;
+  if (TEMP_FAILURE_RETRY (timer_settime (timer_sig2, 0, &it, NULL)) != 0)
+    {
+      printf ("*** timer_settime timer_sig2 failed: %m\n");
+      result = 1;
+    }
+
+  pthread_mutex_lock (&lock);
+  while (thr1_cnt == 0 || thr2_cnt == 0)
+    pthread_cond_wait (&cond, &lock);
+  pthread_mutex_unlock (&lock);
+
+  while (sig1_cnt == 0 || sig2_cnt == 0)
+    {
+      ts.tv_sec = 0;
+      ts.tv_nsec = 100000000;
+      nanosleep (&ts, NULL);
+    }
+
+  pthread_mutex_lock (&lock);
+
+  if (thr1_cnt != 1)
+    {
+      printf ("*** thr1 not called exactly once, but %d times\n", thr1_cnt);
+      result = 1;
+    }
+  else if (thr1_err)
+    {
+      puts ("*** an error occurred in thr1");
+      result = 1;
+    }
+  else if (thr1_sigval.sival_ptr != &ev)
+    {
+      printf ("*** thr1_sigval.sival_ptr %p != %p\n",
+             thr1_sigval.sival_ptr, &ev);
+      result = 1;
+    }
+  else if (check_ts ("thr1", &startts, &thr1_ts, 200000))
+    result = 1;
+
+  if (thr2_cnt != 1)
+    {
+      printf ("*** thr2 not called exactly once, but %d times\n", thr2_cnt);
+      result = 1;
+    }
+  else if (thr2_err)
+    {
+      puts ("*** an error occurred in thr2");
+      result = 1;
+    }
+  else if (thr2_sigval.sival_int != 111)
+    {
+      printf ("*** thr2_sigval.sival_ptr %d != 111\n", thr2_sigval.sival_int);
+      result = 1;
+    }
+  else if (check_ts ("thr2", &startts, &thr2_ts, 300000))
+    result = 1;
+  else if (thr2_guardsize != 0)
+    {
+      printf ("*** thr2 guardsize %zd != 0\n", thr2_guardsize);
+      result = 1;
+    }
+
+  pthread_mutex_unlock (&lock);
+
+  if (sig1_cnt != 1)
+    {
+      printf ("*** sig1 not called exactly once, but %d times\n", sig1_cnt);
+      result = 1;
+    }
+  else if (sig1_err)
+    {
+      printf ("*** errors occurred in sig1 handler %x\n", sig1_err);
+      result = 1;
+    }
+  else if (sig1_sigval.sival_ptr != &ev)
+    {
+      printf ("*** sig1_sigval.sival_ptr %p != %p\n",
+             sig1_sigval.sival_ptr, &ev);
+      result = 1;
+    }
+  else if (check_ts ("sig1", &startts, &sig1_ts, 400000))
+    result = 1;
+
+  if (sig2_cnt != 1)
+    {
+      printf ("*** sig2 not called exactly once, but %d times\n", sig2_cnt);
+      result = 1;
+    }
+  else if (sig2_err)
+    {
+      printf ("*** errors occurred in sig2 handler %x\n", sig2_err);
+      result = 1;
+    }
+  else if (sig2_sigval.sival_int != 163)
+    {
+      printf ("*** sig2_sigval.sival_ptr %d != 163\n", sig2_sigval.sival_int);
+      result = 1;
+    }
+  else if (check_ts ("sig2", &startts, &sig2_ts, 500000))
+    result = 1;
+
+  if (timer_gettime (timer_none, &it) != 0)
+    {
+      printf ("*** timer_gettime timer_none failed: %m\n");
+      result = 1;
+    }
+  else if (it.it_value.tv_sec || it.it_value.tv_nsec
+          || it.it_interval.tv_sec || it.it_interval.tv_nsec)
+    {
+      printf ("\
+*** timer_gettime timer_none returned { %ld.%09ld, %ld.%09ld }\n",
+             (long) it.it_value.tv_sec, it.it_value.tv_nsec,
+             (long) it.it_interval.tv_sec, it.it_interval.tv_nsec);
+      result = 1;
+    }
+
+  if (clock_gettime (TEST_CLOCK, &startts) != 0)
+    {
+      printf ("*** clock_gettime failed: %m\n");
+      result = 1;
+    }
+
+  it.it_value.tv_sec = 1;
+  it.it_value.tv_nsec = 0;
+  it.it_interval.tv_sec = 0;
+  it.it_interval.tv_nsec = 100000000;
+  if (timer_settime (timer_none, 0, &it, NULL) != 0)
+    {
+      printf ("*** timer_settime timer_none failed: %m\n");
+      result = 1;
+    }
+
+  it.it_value.tv_nsec = 100000000;
+  it.it_interval.tv_nsec = 200000000;
+  if (timer_settime (timer_thr1, 0, &it, NULL) != 0)
+    {
+      printf ("*** timer_settime timer_thr1 failed: %m\n");
+      result = 1;
+    }
+
+  it.it_value.tv_nsec = 200000000;
+  it.it_interval.tv_nsec = 300000000;
+  if (timer_settime (timer_thr2, 0, &it, NULL) != 0)
+    {
+      printf ("*** timer_settime timer_thr2 failed: %m\n");
+      result = 1;
+    }
+
+  it.it_value.tv_nsec = 300000000;
+  it.it_interval.tv_nsec = 400000000;
+  if (timer_settime (timer_sig1, 0, &it, NULL) != 0)
+    {
+      printf ("*** timer_settime timer_sig1 failed: %m\n");
+      result = 1;
+    }
+
+  it.it_value.tv_nsec = 400000000;
+  it.it_interval.tv_nsec = 500000000;
+  if (TEMP_FAILURE_RETRY (timer_settime (timer_sig2, 0, &it, NULL)) != 0)
+    {
+      printf ("*** timer_settime timer_sig2 failed: %m\n");
+      result = 1;
+    }
+
+  pthread_mutex_lock (&lock);
+  while (thr1_cnt < 6 || thr2_cnt < 6)
+    pthread_cond_wait (&cond, &lock);
+  pthread_mutex_unlock (&lock);
+
+  while (sig1_cnt < 6 || sig2_cnt < 6)
+    {
+      ts.tv_sec = 0;
+      ts.tv_nsec = 100000000;
+      nanosleep (&ts, NULL);
+    }
+
+  pthread_mutex_lock (&lock);
+
+  if (thr1_err)
+    {
+      puts ("*** an error occurred in thr1");
+      result = 1;
+    }
+  else if (check_ts ("thr1", &startts, &thr1_ts, 1100000 + 4 * 200000))
+    result = 1;
+
+  if (thr2_err)
+    {
+      puts ("*** an error occurred in thr2");
+      result = 1;
+    }
+  else if (check_ts ("thr2", &startts, &thr2_ts, 1200000 + 4 * 300000))
+    result = 1;
+  else if (thr2_guardsize != 0)
+    {
+      printf ("*** thr2 guardsize %zd != 0\n", thr2_guardsize);
+      result = 1;
+    }
+
+  pthread_mutex_unlock (&lock);
+
+  if (sig1_err)
+    {
+      printf ("*** errors occurred in sig1 handler %x\n", sig1_err);
+      result = 1;
+    }
+  else if (check_ts ("sig1", &startts, &sig1_ts, 1300000 + 4 * 400000))
+    result = 1;
+
+  if (sig2_err)
+    {
+      printf ("*** errors occurred in sig2 handler %x\n", sig2_err);
+      result = 1;
+    }
+  else if (check_ts ("sig2", &startts, &sig2_ts, 1400000 + 4 * 500000))
+    result = 1;
+
+  if (timer_gettime (timer_none, &it) != 0)
+    {
+      printf ("*** timer_gettime timer_none failed: %m\n");
+      result = 1;
+    }
+  else if (it.it_interval.tv_sec || it.it_interval.tv_nsec != 100000000)
+    {
+      printf ("\
+!!! second timer_gettime timer_none returned it_interval %ld.%09ld\n",
+             (long) it.it_interval.tv_sec, it.it_interval.tv_nsec);
+      /* FIXME: For now disabled.
+      result = 1; */
+    }
+
+  if (timer_delete (timer_none) != 0)
+    {
+      printf ("*** timer_delete for timer_none failed: %m\n");
+      result = 1;
+    }
+
+  if (timer_delete (timer_sig1) != 0)
+    {
+      printf ("*** timer_delete for timer_sig1 failed: %m\n");
+      result = 1;
+    }
+
+  if (timer_delete (timer_sig2) != 0)
+    {
+      printf ("*** timer_delete for timer_sig2 failed: %m\n");
+      result = 1;
+    }
+
+  if (timer_delete (timer_thr1) != 0)
+    {
+      printf ("*** timer_delete for timer_thr1 failed: %m\n");
+      result = 1;
+    }
+
+  if (timer_delete (timer_thr2) != 0)
+    {
+      printf ("*** timer_delete for timer_thr2 failed: %m\n");
+      result = 1;
+    }
+  return result;
+}
+#else
+# define TEST_FUNCTION 0
+#endif
+
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-timer5.c b/test/nptl/tst-timer5.c
new file mode 100644 (file)
index 0000000..6466c8e
--- /dev/null
@@ -0,0 +1,38 @@
+/* Timer test using the monotonic clock.  */
+
+#include <time.h>
+#include <unistd.h>
+
+#if defined CLOCK_MONOTONIC && defined _POSIX_MONOTONIC_CLOCK
+
+# define TEST_CLOCK    CLOCK_MONOTONIC
+# define TEST_CLOCK_MISSING(clock) \
+  (setup_test () ? "CLOCK_MONOTONIC" : NULL)
+
+# include <stdio.h>
+
+static int
+setup_test (void)
+{
+  if (sysconf (_SC_MONOTONIC_CLOCK) <= 0)
+    return 1;
+
+  /* The user-level timers implementation doesn't support CLOCK_MONOTONIC,
+     even though sysconf claims it will.  */
+  timer_t t;
+  if (timer_create (TEST_CLOCK, NULL, &t) != 0)
+    {
+      printf ("timer_create: %m\n");
+      return 1;
+    }
+  timer_delete (t);
+
+  return 0;
+}
+
+# include "tst-timer4.c"
+
+#else
+# define TEST_FUNCTION 0
+# include "../test-skeleton.c"
+#endif
diff --git a/test/nptl/tst-tls1.c b/test/nptl/tst-tls1.c
new file mode 100644 (file)
index 0000000..541035e
--- /dev/null
@@ -0,0 +1,122 @@
+/* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <tls.h>
+
+#if HAVE___THREAD
+struct test_s
+{
+  int a;
+  int b;
+};
+
+#define INIT_A 1
+#define INIT_B 42
+/* Deliberately not static.  */
+__thread struct test_s s __attribute__ ((tls_model ("initial-exec"))) =
+{
+  .a = INIT_A,
+  .b = INIT_B
+};
+
+
+static void *
+tf (void *arg)
+{
+  if (s.a != INIT_A || s.b != INIT_B)
+    {
+      puts ("initial value of s in child thread wrong");
+      exit (1);
+    }
+
+  ++s.a;
+
+  return NULL;
+}
+#endif
+
+
+int
+do_test (void)
+{
+#if !HAVE___THREAD
+
+  puts ("No __thread support in compiler, test skipped.");
+
+  return 0;
+#else
+
+  if (s.a != INIT_A || s.b != INIT_B)
+    {
+      puts ("initial value of s in main thread wrong");
+      exit (1);
+    }
+
+  pthread_attr_t a;
+
+  if (pthread_attr_init (&a) != 0)
+    {
+      puts ("attr_init failed");
+      exit (1);
+    }
+
+  if (pthread_attr_setstacksize (&a, 1 * 1024 * 1024) != 0)
+    {
+      puts ("attr_setstacksize failed");
+      return 1;
+    }
+
+#define N 10
+  int i;
+  for (i = 0; i < N; ++i)
+    {
+#define M 10
+      pthread_t th[M];
+      int j;
+      for (j = 0; j < M; ++j, ++s.a)
+       if (pthread_create (&th[j], &a, tf, NULL) != 0)
+         {
+           puts ("pthread_create failed");
+           exit (1);
+         }
+
+      for (j = 0; j < M; ++j)
+       if (pthread_join (th[j], NULL) != 0)
+         {
+           puts ("pthread_join failed");
+           exit (1);
+         }
+    }
+
+  if (pthread_attr_destroy (&a) != 0)
+    {
+      puts ("attr_destroy failed");
+      exit (1);
+    }
+
+  return 0;
+#endif
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-tls2.c b/test/nptl/tst-tls2.c
new file mode 100644 (file)
index 0000000..3615d1b
--- /dev/null
@@ -0,0 +1,216 @@
+/* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <semaphore.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <tls.h>
+
+#if HAVE___THREAD
+
+#define N 10
+static pthread_t th[N];
+
+
+#define CB(n) \
+static void                                                                  \
+cb##n (void)                                                                 \
+{                                                                            \
+  if (th[n] != pthread_self ())                                                      \
+    {                                                                        \
+      write (STDOUT_FILENO, "wrong callback\n", 15);                         \
+      _exit (1);                                                             \
+    }                                                                        \
+}
+CB (0)
+CB (1)
+CB (2)
+CB (3)
+CB (4)
+CB (5)
+CB (6)
+CB (7)
+CB (8)
+CB (9)
+static void (*cbs[]) (void) =
+{
+  cb0, cb1, cb2, cb3, cb4, cb5, cb6, cb7, cb8, cb9
+};
+
+
+static __thread void (*fp) (void) __attribute__ ((tls_model ("local-exec")));
+
+
+static sem_t s;
+
+
+#define THE_SIG SIGUSR1
+static void
+handler (int sig)
+{
+  if (sig != THE_SIG)
+    {
+      write (STDOUT_FILENO, "wrong signal\n", 13);
+      _exit (1);
+    }
+
+  fp ();
+
+  if (sem_post (&s) != 0)
+    {
+      write (STDOUT_FILENO, "sem_post failed\n", 16);
+      _exit (1);
+    }
+}
+
+
+static pthread_barrier_t b;
+
+#define TOTAL_SIGS 1000
+static int nsigs;
+
+
+static void *
+tf (void *arg)
+{
+  fp = arg;
+
+  pthread_barrier_wait (&b);
+
+  pthread_barrier_wait (&b);
+
+  if (nsigs != TOTAL_SIGS)
+    {
+      puts ("barrier_wait prematurely returns");
+      exit (1);
+    }
+
+  return NULL;
+}
+#endif
+
+int
+do_test (void)
+{
+#if !HAVE___THREAD
+
+  puts ("No __thread support in compiler, test skipped.");
+
+  return 0;
+#else
+
+  if (pthread_barrier_init (&b, NULL, N + 1) != 0)
+    {
+      puts ("barrier_init failed");
+      exit (1);
+    }
+
+  if (sem_init (&s, 0, 0) != 0)
+    {
+      puts ("sem_init failed");
+      exit (1);
+    }
+
+  struct sigaction sa;
+  sa.sa_handler = handler;
+  sigemptyset (&sa.sa_mask);
+  sa.sa_flags = 0;
+  if (sigaction (THE_SIG, &sa, NULL) != 0)
+    {
+      puts ("sigaction failed");
+      exit (1);
+    }
+
+  pthread_attr_t a;
+
+  if (pthread_attr_init (&a) != 0)
+    {
+      puts ("attr_init failed");
+      exit (1);
+    }
+
+  if (pthread_attr_setstacksize (&a, 1 * 1024 * 1024) != 0)
+    {
+      puts ("attr_setstacksize failed");
+      return 1;
+    }
+
+  int i;
+  for (i = 0; i < N; ++i)
+    if (pthread_create (&th[i], &a, tf, cbs[i]) != 0)
+      {
+       puts ("pthread_create failed");
+       exit (1);
+      }
+
+  if (pthread_attr_destroy (&a) != 0)
+    {
+      puts ("attr_destroy failed");
+      exit (1);
+    }
+
+  pthread_barrier_wait (&b);
+
+  sigset_t ss;
+  sigemptyset (&ss);
+  sigaddset (&ss, THE_SIG);
+  if (pthread_sigmask (SIG_BLOCK, &ss, NULL) != 0)
+    {
+      puts ("pthread_sigmask failed");
+      exit (1);
+    }
+
+  /* Start sending signals.  */
+  for (i = 0; i < TOTAL_SIGS; ++i)
+    {
+      if (kill (getpid (), THE_SIG) != 0)
+       {
+         puts ("kill failed");
+         exit (1);
+       }
+
+      if (TEMP_FAILURE_RETRY (sem_wait (&s)) != 0)
+       {
+         puts ("sem_wait failed");
+         exit (1);
+       }
+
+      ++nsigs;
+    }
+
+  pthread_barrier_wait (&b);
+
+  for (i = 0; i < N; ++i)
+    if (pthread_join (th[i], NULL) != 0)
+      {
+       puts ("join failed");
+       exit (1);
+      }
+
+  return 0;
+#endif
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-tls3.c b/test/nptl/tst-tls3.c
new file mode 100644 (file)
index 0000000..abc5f4c
--- /dev/null
@@ -0,0 +1,225 @@
+/* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <dlfcn.h>
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <semaphore.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pthreaddef.h>
+#include <tls.h>
+
+#define THE_SIG SIGUSR1
+
+
+#define N 10
+static pthread_t th[N];
+
+
+#define CB(n) \
+static void                                                                  \
+cb##n (void)                                                                 \
+{                                                                            \
+  if (th[n] != pthread_self ())                                                      \
+    {                                                                        \
+      write (STDOUT_FILENO, "wrong callback\n", 15);                         \
+      _exit (1);                                                             \
+    }                                                                        \
+}
+CB (0)
+CB (1)
+CB (2)
+CB (3)
+CB (4)
+CB (5)
+CB (6)
+CB (7)
+CB (8)
+CB (9)
+static void (*cbs[]) (void) =
+{
+  cb0, cb1, cb2, cb3, cb4, cb5, cb6, cb7, cb8, cb9
+};
+
+
+sem_t s;
+
+
+pthread_barrier_t b;
+
+#define TOTAL_SIGS 1000
+int nsigs;
+
+
+int
+do_test (void)
+{
+#if !HAVE___THREAD
+
+  puts ("No __thread support in compiler, test skipped.");
+
+  return 0;
+#else
+
+  if ((uintptr_t) pthread_self () & (TCB_ALIGNMENT - 1))
+    {
+      puts ("initial thread's struct pthread not aligned enough");
+      exit (1);
+    }
+
+  if (pthread_barrier_init (&b, NULL, N + 1) != 0)
+    {
+      puts ("barrier_init failed");
+      exit (1);
+    }
+
+  if (sem_init (&s, 0, 0) != 0)
+    {
+      puts ("sem_init failed");
+      exit (1);
+    }
+
+  void *h = dlopen ("tst-tls3mod.so", RTLD_LAZY);
+  if (h == NULL)
+    {
+      puts ("dlopen failed");
+      exit (1);
+    }
+
+  void *(*tf) (void *) = dlsym (h, "tf");
+  if (tf == NULL)
+    {
+      puts ("dlsym for tf failed");
+      exit (1);
+    }
+
+  void (*setup_tf) (pthread_barrier_t*, int*, sem_t*) = dlsym(h, "setup_tf");
+  if (setup_tf == NULL)
+    {
+      puts ("dlsym for setup_tf failed");
+      exit(1);
+    }
+
+  setup_tf (&b, &nsigs, &s);
+
+  struct sigaction sa;
+  sa.sa_handler = dlsym (h, "handler");
+  if (sa.sa_handler == NULL)
+    {
+      puts ("dlsym for handler failed");
+      exit (1);
+    }
+  sigemptyset (&sa.sa_mask);
+  sa.sa_flags = 0;
+  if (sigaction (THE_SIG, &sa, NULL) != 0)
+    {
+      puts ("sigaction failed");
+      exit (1);
+    }
+
+  pthread_attr_t a;
+
+  if (pthread_attr_init (&a) != 0)
+    {
+      puts ("attr_init failed");
+      exit (1);
+    }
+
+  if (pthread_attr_setstacksize (&a, 1 * 1024 * 1024) != 0)
+    {
+      puts ("attr_setstacksize failed");
+      return 1;
+    }
+
+  int r;
+  for (r = 0; r < 10; ++r)
+    {
+      int i;
+      for (i = 0; i < N; ++i)
+       if (pthread_create (&th[i], &a, tf, cbs[i]) != 0)
+         {
+           puts ("pthread_create failed");
+           exit (1);
+         }
+
+      nsigs = 0;
+
+      pthread_barrier_wait (&b);
+
+      sigset_t ss;
+      sigemptyset (&ss);
+      sigaddset (&ss, THE_SIG);
+      if (pthread_sigmask (SIG_BLOCK, &ss, NULL) != 0)
+       {
+         puts ("pthread_sigmask failed");
+         exit (1);
+       }
+
+      /* Start sending signals.  */
+      for (i = 0; i < TOTAL_SIGS; ++i)
+       {
+         if (kill (getpid (), THE_SIG) != 0)
+           {
+             puts ("kill failed");
+             exit (1);
+           }
+
+         if (TEMP_FAILURE_RETRY (sem_wait (&s)) != 0)
+           {
+             puts ("sem_wait failed");
+             exit (1);
+           }
+
+         ++nsigs;
+       }
+
+      pthread_barrier_wait (&b);
+
+      if (pthread_sigmask (SIG_UNBLOCK, &ss, NULL) != 0)
+       {
+         puts ("pthread_sigmask failed");
+         exit (1);
+       }
+
+      for (i = 0; i < N; ++i)
+       if (pthread_join (th[i], NULL) != 0)
+         {
+           puts ("join failed");
+           exit (1);
+         }
+    }
+
+  if (pthread_attr_destroy (&a) != 0)
+    {
+      puts ("attr_destroy failed");
+      exit (1);
+    }
+
+  return 0;
+#endif
+}
+
+
+#define TIMEOUT 5
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-tls3mod.c b/test/nptl/tst-tls3mod.c
new file mode 100644 (file)
index 0000000..53206d3
--- /dev/null
@@ -0,0 +1,106 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <semaphore.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pthreaddef.h>
+#include <tls.h>
+
+#if HAVE___THREAD
+
+static pthread_barrier_t* b = NULL;
+
+#define TOTAL_SIGS 1000
+static int* nsigs = NULL;
+
+static sem_t* s = NULL;
+
+static __thread void (*fp) (void);
+
+
+#define THE_SIG SIGUSR1
+void
+handler (int sig)
+{
+  if (sig != THE_SIG)
+    {
+      write (STDOUT_FILENO, "wrong signal\n", 13);
+      _exit (1);
+    }
+
+  fp ();
+
+  if (sem_post (s) != 0)
+    {
+      write (STDOUT_FILENO, "sem_post failed\n", 16);
+      _exit (1);
+    }
+}
+
+void
+setup_tf (pthread_barrier_t* t_b, int* t_nsigs, sem_t* t_s)
+{
+  b = t_b;
+  nsigs = t_nsigs;
+  s = t_s;
+}
+
+void *
+tf (void *arg)
+{
+  if (!b || !s || !nsigs)
+    {
+      puts ("need to call setup_tf first");
+      exit (1);
+    }
+
+  if ((uintptr_t) pthread_self () & (TCB_ALIGNMENT - 1))
+    {
+      puts ("thread's struct pthread not aligned enough");
+      exit (1);
+    }
+
+  if (fp != NULL)
+    {
+      printf("fp=%p\n", (void *)&fp);
+      puts ("fp not initially NULL");
+      exit (1);
+    }
+
+  fp = arg;
+
+  pthread_barrier_wait (b);
+
+  pthread_barrier_wait (b);
+
+  if (*nsigs != TOTAL_SIGS)
+    {
+      puts ("barrier_wait prematurely returns");
+      exit (1);
+    }
+
+  return NULL;
+}
+
+#endif
diff --git a/test/nptl/tst-tls4.c b/test/nptl/tst-tls4.c
new file mode 100644 (file)
index 0000000..52775de
--- /dev/null
@@ -0,0 +1,191 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <dlfcn.h>
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <tls.h>
+
+#if HAVE___THREAD && defined HAVE_TLS_MODEL_ATTRIBUTE
+
+#define N 3
+
+void (*test1) (void), (*test2) (void);
+
+pthread_barrier_t b2, b3;
+
+static void *
+tf (void *arg)
+{
+  int i;
+
+  for (i = 0; i <= (uintptr_t) arg; ++i)
+    {
+      int r = pthread_barrier_wait (&b3);
+      if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+       {
+         puts ("tf: barrier_wait failed");
+         exit (1);
+       }
+    }
+
+  test1 ();
+
+  for (i = 0; i < 3; ++i)
+    {
+      int r = pthread_barrier_wait (&b3);
+      if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+       {
+         puts ("tf: barrier_wait failed");
+         exit (1);
+       }
+    }
+
+  test2 ();
+
+  for (i = 0; i < 3 - (uintptr_t) arg; ++i)
+    {
+      int r = pthread_barrier_wait (&b3);
+      if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+       {
+         puts ("tf: barrier_wait failed");
+         exit (1);
+       }
+    }
+
+  return NULL;
+}
+
+static void *
+tf2 (void *arg)
+{
+  int r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("tf2: barrier_wait failed");
+      exit (1);
+    }
+
+  int i;
+  for (i = 0; i < N; ++i)
+    tf (arg);
+  return NULL;
+}
+
+int
+do_test (void)
+{
+  pthread_t th[2];
+  const char *modules[N]
+    = { "tst-tls4moda.so", "tst-tls4moda.so", "tst-tls4modb.so" };
+
+  if (pthread_barrier_init (&b2, NULL, 2) != 0)
+    {
+      puts ("barrier_init failed");
+      return 1;
+    }
+
+  if (pthread_barrier_init (&b3, NULL, 3) != 0)
+    {
+      puts ("barrier_init failed");
+      return 1;
+    }
+
+  if (pthread_create (&th[0], NULL, tf2, (void *) (uintptr_t) 1))
+    {
+      puts ("pthread_create failed");
+      return 1;
+    }
+
+  int r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("barrier_wait failed");
+      return 1;
+    }
+
+  int i;
+  for (i = 0; i < N; ++i)
+    {
+      void *h = dlopen (modules[i], RTLD_LAZY);
+      if (h == NULL)
+       {
+         printf ("dlopen failed %s\n", dlerror ());
+         return 1;
+       }
+
+      test1 = dlsym (h, "test1");
+      if (test1 == NULL)
+       {
+         printf ("dlsym for test1 failed %s\n", dlerror ());
+         return 1;
+       }
+
+      test2 = dlsym (h, "test2");
+      if (test2 == NULL)
+       {
+         printf ("dlsym for test2 failed %s\n", dlerror ());
+         return 1;
+       }
+
+      if (pthread_create (&th[1], NULL, tf, (void *) (uintptr_t) 2))
+       {
+         puts ("pthread_create failed");
+         return 1;
+       }
+
+      tf ((void *) (uintptr_t) 0);
+
+      if (pthread_join (th[1], NULL) != 0)
+       {
+         puts ("join failed");
+         return 1;
+       }
+
+      if (dlclose (h))
+       {
+         puts ("dlclose failed");
+         return 1;
+       }
+
+      printf ("test %d with %s succeeded\n", i, modules[i]);
+    }
+
+  if (pthread_join (th[0], NULL) != 0)
+    {
+      puts ("join failed");
+      return 1;
+    }
+
+  return 0;
+}
+
+#define TIMEOUT 5
+#define TEST_FUNCTION do_test ()
+
+#else
+
+#define TEST_FUNCTION 0
+
+#endif
+
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-tls4moda.c b/test/nptl/tst-tls4moda.c
new file mode 100644 (file)
index 0000000..ff7ee56
--- /dev/null
@@ -0,0 +1,56 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <tls.h>
+
+#if HAVE___THREAD && defined HAVE_TLS_MODEL_ATTRIBUTE
+
+static __thread unsigned char foo [32]
+  __attribute__ ((tls_model ("initial-exec"), aligned (sizeof (void *))));
+
+void
+test1 (void)
+{
+  size_t s;
+
+  for (s = 0; s < sizeof (foo); ++s)
+    {
+      if (foo [s])
+        abort ();
+      foo [s] = s;
+    }
+}
+
+void
+test2 (void)
+{
+  size_t s;
+
+  for (s = 0; s < sizeof (foo); ++s)
+    {
+      if (foo [s] != s)
+        abort ();
+      foo [s] = sizeof (foo) - s;
+    }
+}
+
+#endif
diff --git a/test/nptl/tst-tls4modb.c b/test/nptl/tst-tls4modb.c
new file mode 100644 (file)
index 0000000..99f3b54
--- /dev/null
@@ -0,0 +1,65 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <tls.h>
+
+#if HAVE___THREAD && defined HAVE_TLS_MODEL_ATTRIBUTE
+
+static int i;
+int bar;
+
+static __thread void *foo [32 / sizeof (void *)]
+  __attribute__ ((tls_model ("initial-exec"), aligned (sizeof (void *))))
+  = { &i, &bar };
+
+void
+test1 (void)
+{
+  size_t s;
+
+  if (foo [0] != &i || foo [1] != &bar)
+    abort ();
+
+  foo [0] = NULL;
+  foo [1] = NULL;
+  for (s = 0; s < sizeof (foo) / sizeof (void *); ++s)
+    {
+      if (foo [s])
+        abort ();
+      foo [s] = &foo[s];
+    }
+}
+
+void
+test2 (void)
+{
+  size_t s;
+
+  for (s = 0; s < sizeof (foo) / sizeof (void *); ++s)
+    {
+      if (foo [s] != &foo [s])
+        abort ();
+      foo [s] = &foo [s ^ 1];
+    }
+}
+
+#endif
diff --git a/test/nptl/tst-tls5.c b/test/nptl/tst-tls5.c
new file mode 100644 (file)
index 0000000..476f09a
--- /dev/null
@@ -0,0 +1,119 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* Check alignment, overlapping and layout of TLS variables.  */
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <sys/param.h>
+
+#include "tst-tls5.h"
+
+#ifdef TLS_REGISTER
+
+struct tls_obj tls_registry[64];
+
+static int
+tls_addr_cmp (const void *a, const void *b)
+{
+  if (((struct tls_obj *)a)->addr < ((struct tls_obj *)b)->addr)
+    return -1;
+  if (((struct tls_obj *)a)->addr > ((struct tls_obj *)b)->addr)
+    return 1;
+  return 0;
+}
+
+static int
+do_test (void)
+{
+  size_t cnt, i;
+  int res = 0;
+  uintptr_t min_addr = ~(uintptr_t) 0, max_addr = 0;
+
+  for (cnt = 0; tls_registry[cnt].name; ++cnt);
+  tls_registry[cnt].name = NULL;
+  tls_registry[cnt].addr = (uintptr_t) pthread_self ();
+  tls_registry[cnt].size = sizeof (struct pthread);
+  tls_registry[cnt++].align = __alignof__ (struct pthread);
+
+  qsort (tls_registry, cnt, sizeof (struct tls_obj), tls_addr_cmp);
+
+  for (i = 0; i < cnt; ++i)
+    {
+      printf ("%s%s = %p, size %zd, align %zd",
+             tls_registry[i].name ? "&" : "",
+             tls_registry[i].name ?: "pthread_self ()",
+             (void *) tls_registry[i].addr,
+             tls_registry[i].size, tls_registry[i].align);
+      if (tls_registry[i].addr & (tls_registry[i].align - 1))
+       {
+         fputs (", WRONG ALIGNMENT", stdout);
+         res = 1;
+       }
+      if (i > 0
+         && (tls_registry[i - 1].addr + tls_registry[i - 1].size
+             > tls_registry[i].addr))
+       {
+         fputs (", ADDRESS OVERLAP", stdout);
+         res = 1;
+       }
+      puts ("");
+      if (tls_registry[i].name)
+       {
+         min_addr = MIN (tls_registry[i].addr, min_addr);
+         max_addr = MAX (tls_registry[i].addr + tls_registry[i].size,
+                         max_addr);
+       }
+    }
+
+  if (cnt > 1)
+    {
+#if defined(TLS_TCB_AT_TP)
+      if (tls_registry[cnt - 1].name)
+       {
+         puts ("pthread_self () not larger than all TLS addresses");
+         res = 1;
+       }
+      else
+       max_addr = MAX (tls_registry[cnt - 1].addr, max_addr);
+#elif defined(TLS_DTV_AT_TP)
+      if (tls_registry[0].name)
+       {
+         puts ("pthread_self () not smaller than all TLS addresses");
+         res = 1;
+       }
+#else
+      abort ();
+#endif
+      printf ("Initial TLS used block size %zd\n",
+             (size_t) (max_addr - min_addr));
+    }
+  return res;
+}
+
+#define TEST_FUNCTION do_test ()
+
+#else
+
+#define TEST_FUNCTION 0
+
+#endif
+
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-tls5.h b/test/nptl/tst-tls5.h
new file mode 100644 (file)
index 0000000..b7c14eb
--- /dev/null
@@ -0,0 +1,28 @@
+#include <stdint.h>
+#include <stdlib.h>
+#include <tls.h>
+
+#if USE_TLS && HAVE___THREAD
+
+struct tls_obj
+{
+  const char *name;
+  uintptr_t addr;
+  size_t size;
+  size_t align;
+};
+extern struct tls_obj tls_registry[];
+
+#define TLS_REGISTER(x)                                \
+static void __attribute__((constructor))       \
+tls_register_##x (void)                                \
+{                                              \
+  size_t i;                                    \
+  for (i = 0; tls_registry[i].name; ++i);      \
+  tls_registry[i].name = #x;                   \
+  tls_registry[i].addr = (uintptr_t) &x;       \
+  tls_registry[i].size = sizeof (x);           \
+  tls_registry[i].align = __alignof__ (x);     \
+}
+
+#endif
diff --git a/test/nptl/tst-tls5mod.c b/test/nptl/tst-tls5mod.c
new file mode 100644 (file)
index 0000000..4616a20
--- /dev/null
@@ -0,0 +1,6 @@
+#include "tst-tls5.h"
+
+#ifdef TLS_REGISTER
+/* Ensure tls_registry is exported from the binary.  */
+void *tst_tls5mod attribute_hidden = tls_registry;
+#endif
diff --git a/test/nptl/tst-tls5moda.c b/test/nptl/tst-tls5moda.c
new file mode 100644 (file)
index 0000000..4644d76
--- /dev/null
@@ -0,0 +1,6 @@
+#include "tst-tls5.h"
+
+#ifdef TLS_REGISTER
+static __thread char a [32] __attribute__ ((aligned (64)));
+TLS_REGISTER (a)
+#endif
diff --git a/test/nptl/tst-tls5modb.c b/test/nptl/tst-tls5modb.c
new file mode 100644 (file)
index 0000000..09b4396
--- /dev/null
@@ -0,0 +1,6 @@
+#include "tst-tls5.h"
+
+#ifdef TLS_REGISTER
+static __thread int b;
+TLS_REGISTER (b)
+#endif
diff --git a/test/nptl/tst-tls5modc.c b/test/nptl/tst-tls5modc.c
new file mode 100644 (file)
index 0000000..bbd8963
--- /dev/null
@@ -0,0 +1,6 @@
+#include "tst-tls5.h"
+
+#ifdef TLS_REGISTER
+static __thread int c;
+TLS_REGISTER (c)
+#endif
diff --git a/test/nptl/tst-tls5modd.c b/test/nptl/tst-tls5modd.c
new file mode 100644 (file)
index 0000000..8b54d16
--- /dev/null
@@ -0,0 +1,6 @@
+#include "tst-tls5.h"
+
+#ifdef TLS_REGISTER
+static __thread int d;
+TLS_REGISTER (d)
+#endif
diff --git a/test/nptl/tst-tls5mode.c b/test/nptl/tst-tls5mode.c
new file mode 100644 (file)
index 0000000..d30b067
--- /dev/null
@@ -0,0 +1,8 @@
+#include "tst-tls5.h"
+
+#ifdef TLS_REGISTER
+static __thread int e1 = 24;
+static __thread char e2 [32] __attribute__ ((aligned (64)));
+TLS_REGISTER (e1)
+TLS_REGISTER (e2)
+#endif
diff --git a/test/nptl/tst-tls5modf.c b/test/nptl/tst-tls5modf.c
new file mode 100644 (file)
index 0000000..52dcb94
--- /dev/null
@@ -0,0 +1,9 @@
+#include "tst-tls5.h"
+
+#ifdef TLS_REGISTER
+char tst_tls5modf[60] attribute_hidden = { 26 };
+static __thread int f1 = 24;
+static __thread char f2 [32] __attribute__ ((aligned (64)));
+TLS_REGISTER (f1)
+TLS_REGISTER (f2)
+#endif
diff --git a/test/nptl/tst-tsd1.c b/test/nptl/tst-tsd1.c
new file mode 100644 (file)
index 0000000..51b2d0c
--- /dev/null
@@ -0,0 +1,118 @@
+/* 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 <string.h>
+
+
+static int
+do_test (void)
+{
+  pthread_key_t key1;
+  pthread_key_t key2;
+  void *value;
+  int result = 0;
+  int err;
+
+  err = pthread_key_create (&key1, NULL);
+  if (err != 0)
+    {
+      printf ("1st key_create failed: %s\n", strerror (err));
+      return 1;
+    }
+
+  /* Initial value must be NULL.  */
+  value = pthread_getspecific (key1);
+  if (value != NULL)
+    {
+      puts ("1st getspecific != NULL");
+      result = 1;
+    }
+
+  err = pthread_setspecific (key1, (void *) -2l);
+  if (err != 0)
+    {
+      printf ("1st setspecific failed: %s\n", strerror (err));
+      return 1;
+    }
+
+  value = pthread_getspecific (key1);
+  if (value == NULL)
+    {
+      puts ("2nd getspecific == NULL\n");
+      result = 1;
+    }
+  else if (value != (void *) -2l)
+    {
+      puts ("2nd getspecific != -2l\n");
+      result = 1;
+    }
+
+  err = pthread_setspecific (key1, (void *) -3l);
+  if (err != 0)
+    {
+      printf ("2nd setspecific failed: %s\n", strerror (err));
+      return 1;
+    }
+
+  value = pthread_getspecific (key1);
+  if (value == NULL)
+    {
+      puts ("3rd getspecific == NULL\n");
+      result = 1;
+    }
+  else if (value != (void *) -3l)
+    {
+      puts ("3rd getspecific != -2l\n");
+      result = 1;
+    }
+
+  err = pthread_key_delete (key1);
+  if (err != 0)
+    {
+      printf ("key_delete failed: %s\n", strerror (err));
+      result = 1;
+    }
+
+
+  err = pthread_key_create (&key2, NULL);
+  if (err != 0)
+    {
+      printf ("2nd key_create failed: %s\n", strerror (err));
+      return 1;
+    }
+
+  if (key1 != key2)
+    puts ("key1 != key2; no more tests performed");
+  else
+    {
+      value = pthread_getspecific (key2);
+      if (value != NULL)
+       {
+         puts ("4th getspecific != NULL");
+         result = 1;
+       }
+    }
+
+  return result;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-tsd2.c b/test/nptl/tst-tsd2.c
new file mode 100644 (file)
index 0000000..19d8a69
--- /dev/null
@@ -0,0 +1,97 @@
+/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <string.h>
+
+
+static int result;
+
+
+static void
+destr (void *arg)
+{
+  if (arg != (void *) -2l)
+    result = 2;
+  else
+    result = 0;
+}
+
+
+static void *
+tf (void *arg)
+{
+  pthread_key_t key = (pthread_key_t) (long int) arg;
+  int err;
+
+  err = pthread_setspecific (key, (void *) -2l);
+  if (err != 0)
+    result = 3;
+
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  pthread_key_t key;
+  pthread_t th;
+  int err;
+
+  err = pthread_key_create (&key, destr);
+  if (err != 0)
+    {
+      printf ("key_create failed: %s\n", strerror (err));
+      return 1;
+    }
+
+  result = 1;
+
+  err = pthread_create (&th, NULL, tf, (void *) (long int) key);
+  if (err != 0)
+    {
+      printf ("create failed: %s\n", strerror (err));
+      return 1;
+    }
+
+  /* Wait for the thread to terminate.  */
+  err = pthread_join (th, NULL);
+  if (err != 0)
+    {
+      printf ("join failed: %s\n", strerror (err));
+      return 1;
+    }
+
+  if (result == 1)
+    puts ("destructor not called");
+  else if (result == 2)
+    puts ("destructor got passed a wrong value");
+  else if (result == 3)
+    puts ("setspecific in child failed");
+  else if (result != 0)
+    puts ("result != 0");
+
+  return result;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-tsd3.c b/test/nptl/tst-tsd3.c
new file mode 100644 (file)
index 0000000..6cdf749
--- /dev/null
@@ -0,0 +1,129 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <limits.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+
+static pthread_key_t key1;
+static pthread_key_t key2;
+
+
+static int left;
+
+
+static void
+destr1 (void *arg)
+{
+  if (--left > 0)
+    {
+      puts ("set key2");
+
+      if (pthread_setspecific (key2, (void *) 1l) != 0)
+       {
+         puts ("destr1: setspecific failed");
+         exit (1);
+       }
+    }
+}
+
+
+static void
+destr2 (void *arg)
+{
+  if (--left > 0)
+    {
+      puts ("set key1");
+
+      if (pthread_setspecific (key1, (void *) 1l) != 0)
+       {
+         puts ("destr2: setspecific failed");
+         exit (1);
+       }
+    }
+}
+
+
+static void *
+tf (void *arg)
+{
+  /* Let the destructors work.  */
+  left = 7;
+
+  if (pthread_setspecific (key1, (void *) 1l) != 0
+      || pthread_setspecific (key2, (void *) 1l) != 0)
+    {
+      puts ("tf: setspecific failed");
+      exit (1);
+    }
+
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  /* Allocate two keys, both with destructors.  */
+  if (pthread_key_create (&key1, destr1) != 0
+      || pthread_key_create (&key2, destr2) != 0)
+    {
+      puts ("key_create failed");
+      return 1;
+    }
+
+  pthread_t th;
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("create failed");
+      return 1;
+    }
+
+  if (pthread_join (th, NULL) != 0)
+    {
+      puts ("join failed");
+      return 1;
+    }
+
+  if (left != 0)
+    {
+      printf ("left == %d\n", left);
+      return 1;
+    }
+
+  if (pthread_getspecific (key1) != NULL)
+    {
+      puts ("key1 data != NULL");
+      return 1;
+    }
+  if (pthread_getspecific (key2) != NULL)
+    {
+      puts ("key2 data != NULL");
+      return 1;
+    }
+
+  return 0;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-tsd4.c b/test/nptl/tst-tsd4.c
new file mode 100644 (file)
index 0000000..44bbadb
--- /dev/null
@@ -0,0 +1,103 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <limits.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+
+static pthread_key_t key;
+
+
+static int rounds;
+
+
+static void
+destr (void *arg)
+{
+  ++rounds;
+
+  if (pthread_setspecific (key, (void *) 1l) != 0)
+    {
+      puts ("destr: setspecific failed");
+      exit (1);
+    }
+}
+
+
+static void *
+tf (void *arg)
+{
+  if (pthread_setspecific (key, (void *) 1l) != 0)
+    {
+      puts ("tf: setspecific failed");
+      exit (1);
+    }
+
+  return NULL;
+}
+
+
+/* This test check non-standard behavior.  The standard does not
+   require that the implementation has to stop calling TSD destructors
+   when they are set over and over again.  But NPTL does.  */
+static int
+do_test (void)
+{
+  /* Allocate two keys, both with destructors.  */
+  if (pthread_key_create (&key, destr) != 0)
+    {
+      puts ("key_create failed");
+      return 1;
+    }
+
+  pthread_t th;
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("create failed");
+      return 1;
+    }
+
+  if (pthread_join (th, NULL) != 0)
+    {
+      puts ("join failed");
+      return 1;
+    }
+
+  if (rounds < PTHREAD_DESTRUCTOR_ITERATIONS)
+    {
+      printf ("rounds == %d, PTHREAD_DESTRUCTOR_ITERATIONS = %d\n",
+             rounds, PTHREAD_DESTRUCTOR_ITERATIONS);
+      return 1;
+    }
+
+  if (pthread_getspecific (key) != NULL)
+    {
+      puts ("key data != NULL");
+      return 1;
+    }
+
+  return 0;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-tsd5.c b/test/nptl/tst-tsd5.c
new file mode 100644 (file)
index 0000000..8793e33
--- /dev/null
@@ -0,0 +1,81 @@
+/* Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2004.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with 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 <stdlib.h>
+
+
+static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
+
+
+static void
+cl (void *p)
+{
+  pthread_mutex_unlock (&m);
+}
+
+
+static void *
+tf (void *arg)
+{
+  if (pthread_mutex_lock (&m) != 0)
+    {
+      puts ("2nd mutex_lock failed");
+      exit (1);
+    }
+
+  exit (0);
+}
+
+
+static int
+do_test (void)
+{
+  pthread_key_t k;
+  if (pthread_key_create (&k, cl) != 0)
+    {
+      puts ("key_create failed");
+      return 1;
+    }
+  if (pthread_setspecific (k, (void *) 1) != 0)
+    {
+      puts ("setspecific failed");
+      return 1;
+    }
+
+  if (pthread_mutex_lock (&m) != 0)
+    {
+      puts ("1st mutex_lock failed");
+      return 1;
+    }
+
+  pthread_t th;
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("create failed");
+      return 1;
+    }
+
+  pthread_exit (NULL);
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/nptl/tst-umask1.c b/test/nptl/tst-umask1.c
new file mode 100644 (file)
index 0000000..d64a8be
--- /dev/null
@@ -0,0 +1,137 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <fcntl.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+
+static struct
+{
+  int (*fp) (const char *, mode_t);
+  const char *name;
+  bool is_fd;
+} fcts[] =
+{
+  { creat, "creat", true },
+  { mkdir, "mkdir", false },
+  { mkfifo, "mkfifo", false },
+};
+#define nfcts (sizeof (fcts) / sizeof (fcts[0]))
+
+
+static int
+work (const char *fname, int mask)
+{
+  int result = 0;
+  size_t i;
+  for (i = 0; i < nfcts; ++i)
+    {
+      remove (fname);
+      int fd = fcts[i].fp (fname, 0777);
+      if (fd == -1)
+       {
+         printf ("cannot %s %s: %m\n", fcts[i].name, fname);
+         exit (1);
+       }
+      if (fcts[i].is_fd)
+       close (fd);
+      struct stat64 st;
+      if (stat64 (fname, &st) == -1)
+       {
+         printf ("cannot stat %s after %s: %m\n", fname, fcts[i].name);
+         exit (1);
+       }
+
+      if ((st.st_mode & mask) != 0)
+       {
+         printf ("mask not successful after %s: %x still set\n",
+             fcts[i].name, (unsigned int) (st.st_mode & mask));
+         result = 1;
+       }
+    }
+
+  return result;
+}
+
+
+static pthread_barrier_t bar;
+
+
+static void *
+tf (void *arg)
+{
+  pthread_barrier_wait (&bar);
+
+  int result = work (arg, 022);
+
+  pthread_barrier_wait (&bar);
+
+  pthread_barrier_wait (&bar);
+
+  return (work (arg, 0) | result) ? (void *) -1l : NULL;
+}
+
+
+static int
+do_test (const char *fname)
+{
+  int result = 0;
+
+  umask (0);
+  result |= work (fname, 0);
+
+  pthread_barrier_init (&bar, NULL, 2);
+
+  pthread_t th;
+  if (pthread_create (&th, NULL, tf, (void *) fname) != 0)
+    {
+      puts ("cannot create thread");
+      exit (1);
+    }
+
+  umask (022);
+  result |= work (fname, 022);
+
+  pthread_barrier_wait (&bar);
+
+  pthread_barrier_wait (&bar);
+
+  umask (0);
+
+  pthread_barrier_wait (&bar);
+
+  void *res;
+  if (pthread_join (th, &res) != 0)
+    {
+      puts ("join failed");
+      exit (1);
+    }
+
+  remove (fname);
+
+  return result || res != NULL;
+}
+
+#define TEST_FUNCTION do_test (argc < 2 ? "/tmp/tst-umask.tmp" : argv[1])
+#include "../test-skeleton.c"
index d3412f6..c50748d 100644 (file)
@@ -1,6 +1,7 @@
 # uClibc pthread tests
 # Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
 
+TESTS_DISABLED += cancellation-points
 
 EXTRA_LDFLAGS := -lpthread
 
diff --git a/test/tls/Makefile b/test/tls/Makefile
new file mode 100644 (file)
index 0000000..607fec2
--- /dev/null
@@ -0,0 +1,8 @@
+# uClibc TLS tests
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+
+top_builddir=../../
+top_srcdir=../../
+include ../Rules.mak
+-include Makefile.in
+include ../Test.mak
diff --git a/test/tls/Makefile.in b/test/tls/Makefile.in
new file mode 100644 (file)
index 0000000..d19d347
--- /dev/null
@@ -0,0 +1,148 @@
+# uClibc TLS tests
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+
+TESTS := tst-tls1 tst-tls2 tst-tls3 tst-tls4 tst-tls5 tst-tls6 tst-tls7        \
+       tst-tls8 tst-tls9 tst-tls10 tst-tls11 tst-tls12 tst-tls13       \
+       tst-tls14 tst-tls15 tst-tls16 tst-tls17 tst-tls18 tst-tls-at-ctor \
+       tst-tls1-static tst-tls2-static tst-tls9-static
+TESTS_DISABLED := tst-tls1-static tst-tls2-static tst-tls9-static
+
+#all these tests require shared libraries
+ifeq ($(HAVE_SHARED),)
+TESTS_DISABLED := $(TESTS)
+endif
+
+# All these tests need tls.h, which is not installed with glibc
+GLIBC_TESTS_DISABLED := $(addsuffix _glibc,$(filter-out $(TESTS_DISABLED),$(TESTS)))
+
+
+
+PTDIR := $(top_builddir)libpthread/nptl
+SYSDEPS_DIR := $(top_srcdir)libc/sysdeps
+
+EXTRA_CFLAGS := -DNOT_IN_libc=1 \
+       -std=gnu99 -I. \
+       -I$(SYSDEPS_DIR)/linux \
+       -I$(SYSDEPS_DIR)/linux/$(TARGET_ARCH) \
+       -I$(PTDIR)      \
+       -I$(PTDIR)/sysdeps/unix/sysv/linux/$(TARGET_ARCH)       \
+       -I$(PTDIR)/sysdeps/$(TARGET_ARCH)                       \
+       -I$(PTDIR)/sysdeps/unix/sysv/linux                      \
+       -I$(PTDIR)/sysdeps/pthread                              \
+       -I$(PTDIR)/sysdeps/pthread/bits                         \
+       -I$(PTDIR)/sysdeps/generic                              \
+       -I$(top_builddir)ldso/include                           \
+       -I$(top_builddir)ldso/ldso/$(TARGET_ARCH)               \
+       -I$(top_builddir)include                                \
+       -include $(top_builddir)include/libc-symbols.h
+
+tlsmod17a-suffixes := 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
+tlsmod18a-suffixes := 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
+CFLAGS_tst-tlsmod1.so := -fPIC -DSHARED -shared
+CFLAGS_tst-tlsmod2.so := -fPIC -DSHARED -shared
+CFLAGS_tst-tlsmod3.so := -fPIC -DSHARED -shared
+CFLAGS_tst-tlsmod4.so := -fPIC -DSHARED -shared
+CFLAGS_tst-tlsmod5.so := -fPIC -DSHARED -shared
+CFLAGS_tst-tlsmod6.so := -fPIC -DSHARED -shared
+CFLAGS_tst-tlsmod7.so := -fPIC -DSHARED -shared
+CFLAGS_tst-tlsmod8.so := -fPIC -DSHARED -shared
+CFLAGS_tst-tlsmod9.so := -fPIC -DSHARED -shared
+CFLAGS_tst-tlsmod10.so := -fPIC -DSHARED -shared
+CFLAGS_tst-tlsmod11.so := -fPIC -DSHARED -shared
+CFLAGS_tst-tlsmod12.so := -fPIC -DSHARED -shared
+CFLAGS_tst-tlsmod13.so := -fPIC -DSHARED -shared
+CFLAGS_tst-tlsmod13a.so := -fPIC -DSHARED -shared
+CFLAGS_tst-tlsmod14a.so := -fPIC -DSHARED -shared
+CFLAGS_tst-tlsmod14b.so := -fPIC -DSHARED -shared
+CFLAGS_tst-tlsmod15a.so := -fPIC -DSHARED -shared
+CFLAGS_tst-tlsmod15b.so := -fPIC -DSHARED -shared
+CFLAGS_tst-tlsmod16a.so := -fPIC -DSHARED -shared
+CFLAGS_tst-tlsmod16b.so := -fPIC -DSHARED -shared
+CFLAGS_tst-tlsmod17a.so := -fPIC -DSHARED -shared
+CFLAGS_tst-tlsmod17b.so := -fPIC -DSHARED -shared
+CFLAGS_tst-tlsmod18a.so := -fPIC -DSHARED -shared
+CFLAGS_tst-tlsmod-at-ctor.so := -fPIC -DSHARED -shared
+
+LDFLAGS_tst-tlsmod1.so := -shared -static-libgcc -L$(top_builddir)lib
+LDFLAGS_tst-tlsmod2.so := -shared -static-libgcc -L$(top_builddir)lib
+LDFLAGS_tst-tlsmod3.so := -shared -static-libgcc -L$(top_builddir)lib  \
+       tst-tlsmod2.so
+LDFLAGS_tst-tlsmod4.so := -shared -static-libgcc -L$(top_builddir)lib
+LDFLAGS_tst-tlsmod5.so := -shared -static-libgcc -L$(top_builddir)lib
+LDFLAGS_tst-tlsmod6.so := -shared -static-libgcc -L$(top_builddir)lib
+LDFLAGS_tst-tlsmod7.so := -shared -static-libgcc -L$(top_builddir)lib
+LDFLAGS_tst-tlsmod8.so := -shared -static-libgcc -L$(top_builddir)lib  \
+       tst-tlsmod7.so
+LDFLAGS_tst-tlsmod9.so := -shared -static-libgcc -L$(top_builddir)lib  \
+       tst-tlsmod8.so
+LDFLAGS_tst-tlsmod10.so := -shared -static-libgcc -L$(top_builddir)lib \
+       tst-tlsmod9.so
+LDFLAGS_tst-tlsmod11.so := -shared -static-libgcc -L$(top_builddir)lib
+LDFLAGS_tst-tlsmod12.so := -shared -static-libgcc -L$(top_builddir)lib \
+       tst-tlsmod11.so
+LDFLAGS_tst-tlsmod13.so := -shared -static-libgcc -L$(top_builddir)lib
+LDFLAGS_tst-tlsmod13a.so := -shared -static-libgcc -L$(top_builddir)lib        \
+       tst-tlsmod13.so
+LDFLAGS_tst-tlsmod14a.so := -shared -static-libgcc -L$(top_builddir)lib
+LDFLAGS_tst-tlsmod14b.so := -shared -static-libgcc -L$(top_builddir)lib
+LDFLAGS_tst-tlsmod15a.so := -shared -static-libgcc -L$(top_builddir)lib
+LDFLAGS_tst-tlsmod15b.so := -shared -static-libgcc -L$(top_builddir)lib
+LDFLAGS_tst-tlsmod16a.so := -shared -static-libgcc -L$(top_builddir)lib
+LDFLAGS_tst-tlsmod16b.so := -shared -static-libgcc -L$(top_builddir)lib
+LDFLAGS_tst-tlsmod17a.so := -shared -static-libgcc -L$(top_builddir)lib
+LDFLAGS_tst-tlsmod17b.so := -shared -static-libgcc -L$(top_builddir)lib \
+       $(patsubst %,tst-tlsmod17a%.so,$(tlsmod17a-suffixes))
+LDFLAGS_tst-tlsmod18a.so := -shared -static-libgcc -L$(top_builddir)lib
+LDFLAGS_tst-tlsmod-at-ctor.so := -shared -static-libgcc -L$(top_builddir)lib
+
+LDFLAGS_tst-tls3 := tst-tlsmod1.so tst-tlsmod4.so
+LDFLAGS_tst-tls4 := -ldl
+LDFLAGS_tst-tls5 := -ldl
+LDFLAGS_tst-tls6 := -ldl
+LDFLAGS_tst-tls7 := -ldl
+LDFLAGS_tst-tls8 := -ldl
+LDFLAGS_tst-tls9 := -ldl
+LDFLAGS_tst-tls10 := -Wl,-rpath-link=. tst-tlsmod8.so
+LDFLAGS_tst-tls11 := -Wl,-rpath-link=. tst-tlsmod10.so
+LDFLAGS_tst-tls12 := -Wl,-rpath-link=. tst-tlsmod12.so
+LDFLAGS_tst-tls13 := -ldl -Wl,-rpath-link=.
+LDFLAGS_tst-tls14 := -ldl -Wl,-rpath-link=. tst-tlsmod14a.so
+LDFLAGS_tst-tls15 := -ldl -Wl,-rpath-link=.
+LDFLAGS_tst-tls16 := -ldl -Wl,-rpath-link=.
+LDFLAGS_tst-tls17 := -ldl -Wl,-rpath-link=.
+LDFLAGS_tst-tls18 := -ldl -Wl,-rpath-link=.
+LDFLAGS_tst-tls-at-ctor := tst-tlsmod-at-ctor.so
+
+tst-tls3: tst-tlsmod1.so tst-tlsmod4.so
+tst-tls4: tst-tlsmod2.so
+tst-tls5: tst-tlsmod2.so
+tst-tls6: tst-tlsmod2.so
+tst-tls7: tst-tlsmod2.so tst-tlsmod3.so
+tst-tls8: tst-tlsmod2.so tst-tlsmod3.so tst-tlsmod4.so
+tst-tls9: tst-tlsmod5.so tst-tlsmod6.so
+tst-tls10: tst-tlsmod7.so tst-tlsmod8.so
+tst-tls11: tst-tlsmod9.so tst-tlsmod10.so
+tst-tls12: tst-tlsmod11.so tst-tlsmod12.so
+tst-tls13: tst-tlsmod13.so tst-tlsmod13a.so
+tst-tls14: tst-tlsmod14a.so tst-tlsmod14b.so
+tst-tls15: tst-tlsmod15b.so
+tst-tls16: tst-tlsmod16a.so tst-tlsmod16b.so
+tst-tls17: tst-tlsmod17b.so
+tst-tlsmod17b.so: $(patsubst %,tst-tlsmod17a%.so,$(tlsmod17a-suffixes))
+tst-tlsmod17a%.so: tst-tlsmod17a.c
+       $(Q)$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_tst-tlsmod17a.so) $< -o $@ \
+       -DN=$* -Wl,-soname,$@ $(LDFLAGS) $(EXTRA_LIBS) \
+       $(LDFLAGS_tst-tlsmod17a.so)
+tst-tls18: $(patsubst %,tst-tlsmod18a%.so,$(tlsmod18a-suffixes))
+tst-tlsmod18a%.so: tst-tlsmod18a.c
+       $(Q)$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_tst-tlsmod18a.so) $< -o $@ \
+       -DN=$* -Wl,-soname,$@ $(LDFLAGS) $(EXTRA_LIBS) \
+       $(LDFLAGS_tst-tlsmod18a.so)
+tst-tls-at-ctor: tst-tlsmod-at-ctor.so
+
+RET_tst-tls13 := 1
+ifeq ($(TARGET_ARCH),mips)
+RET_tst-tls15 := 1
+endif
+
+WRAPPER := env LD_LIBRARY_PATH="$$PWD:.:$(LD_LIBRARY_PATH)"
diff --git a/test/tls/README b/test/tls/README
new file mode 100644 (file)
index 0000000..06c9eb7
--- /dev/null
@@ -0,0 +1,8 @@
+These tests were imported from 'glibc/elf' and are responsible for testing
+the TLS functionality of the dynamic loader. The file 'tls-macros-mips.h'
+is a copy of 'glibc/sysdeps/mips/tls-macros.h'. Dependency and link orders
+are critical and should NOT be changed. Even if you think you know what
+you are doing, do not touch the Makefile without posting to the uClibc
+development mailing list.
+
+-Steve <sjhill@uclibc.org>
diff --git a/test/tls/tls-macros-arm.h b/test/tls/tls-macros-arm.h
new file mode 100644 (file)
index 0000000..13d0f97
--- /dev/null
@@ -0,0 +1,51 @@
+#define TLS_LE(x)                                      \
+  ({ int *__result;                                    \
+     void *tp = __builtin_thread_pointer ();           \
+     __asm__ ("ldr %0, 1f; "                           \
+         "add %0, %1, %0; "                            \
+         "b 2f; "                                      \
+         "1: .word " #x "(tpoff); "                    \
+         "2: "                                         \
+         : "=&r" (__result) : "r" (tp));               \
+     __result; })
+
+#define TLS_IE(x)                                      \
+  ({ int *__result;                                    \
+     void *tp = __builtin_thread_pointer ();           \
+     __asm__ ("ldr %0, 1f; "                           \
+         "3: ldr %0, [pc, %0];"                        \
+         "add %0, %1, %0; "                            \
+         "b 2f; "                                      \
+         "1: .word " #x "(gottpoff) + (. - 3b - 8); "  \
+         "2: "                                         \
+         : "=&r" (__result) : "r" (tp));               \
+     __result; })
+
+#define TLS_LD(x)                                      \
+  ({ char *__result;                                   \
+     int __offset;                                     \
+     extern void *__tls_get_addr (void *);             \
+     __asm__ ("ldr %0, 2f; "                           \
+         "1: add %0, pc, %0; "                         \
+         "b 3f; "                                      \
+         "2: .word " #x "(tlsldm) + (. - 1b - 8); "    \
+         "3: "                                         \
+         : "=r" (__result));                           \
+     __result = (char *)__tls_get_addr (__result);     \
+     __asm__ ("ldr %0, 1f; "                           \
+         "b 2f; "                                      \
+         "1: .word " #x "(tlsldo); "                   \
+         "2: "                                         \
+         : "=r" (__offset));                           \
+     (int *) (__result + __offset); })
+
+#define TLS_GD(x)                                      \
+  ({ int *__result;                                    \
+     extern void *__tls_get_addr (void *);             \
+     __asm__ ("ldr %0, 2f; "                           \
+         "1: add %0, pc, %0; "                         \
+         "b 3f; "                                      \
+         "2: .word " #x "(tlsgd) + (. - 1b - 8); "     \
+         "3: "                                         \
+         : "=r" (__result));                           \
+     (int *)__tls_get_addr (__result); })
diff --git a/test/tls/tls-macros-mips.h b/test/tls/tls-macros-mips.h
new file mode 100644 (file)
index 0000000..0db3830
--- /dev/null
@@ -0,0 +1,88 @@
+/* Macros to support TLS testing in times of missing compiler support.  */
+
+#if _MIPS_SIM != _ABI64
+
+/* These versions are for o32 and n32.  */
+
+# define TLS_GD(x)                                     \
+  ({ void *__result;                                   \
+     extern void *__tls_get_addr (void *);             \
+     __asm__ ("addiu %0, $28, %%tlsgd(" #x ")"         \
+         : "=r" (__result));                           \
+     (int *)__tls_get_addr (__result); })
+#else
+# define TLS_GD(x)                                     \
+  ({ void *__result;                                   \
+     extern void *__tls_get_addr (void *);             \
+     __asm__ ("daddiu %0, $28, %%tlsgd(" #x ")"                \
+         : "=r" (__result));                           \
+     (int *)__tls_get_addr (__result); })
+#endif
+
+#if _MIPS_SIM != _ABI64
+# define TLS_LD(x)                                     \
+  ({ void *__result;                                   \
+     extern void *__tls_get_addr (void *);             \
+     __asm__ ("addiu %0, $28, %%tlsldm(" #x ")"                \
+         : "=r" (__result));                           \
+     __result = __tls_get_addr (__result);             \
+     __asm__ ("lui $3,%%dtprel_hi(" #x ")\n\t"         \
+         "addiu $3,$3,%%dtprel_lo(" #x ")\n\t"         \
+         "addu %0,%0,$3"                               \
+         : "+r" (__result) : : "$3");                  \
+     __result; })
+# define TLS_IE(x)                                     \
+  ({ void *__result;                                   \
+     __asm__ (".set push\n\t.set mips32r2\n\t"         \
+         "rdhwr\t%0,$29\n\t.set pop"                   \
+         : "=v" (__result));                           \
+     __asm__ ("lw $3,%%gottprel(" #x ")($28)\n\t"              \
+         "addu %0,%0,$3"                               \
+         : "+r" (__result) : : "$3");                  \
+     __result; })
+# define TLS_LE(x)                                     \
+  ({ void *__result;                                   \
+     __asm__ (".set push\n\t.set mips32r2\n\t"         \
+         "rdhwr\t%0,$29\n\t.set pop"                   \
+         : "=v" (__result));                           \
+     __asm__ ("lui $3,%%tprel_hi(" #x ")\n\t"          \
+         "addiu $3,$3,%%tprel_lo(" #x ")\n\t"          \
+         "addu %0,%0,$3"                               \
+         : "+r" (__result) : : "$3");                  \
+     __result; })
+
+#else
+
+/* These versions are for n64.  */
+
+# define TLS_LD(x)                                     \
+  ({ void *__result;                                   \
+     extern void *__tls_get_addr (void *);             \
+     __asm__ ("daddiu %0, $28, %%tlsldm(" #x ")"               \
+         : "=r" (__result));                           \
+     __result = __tls_get_addr (__result);             \
+     __asm__ ("lui $3,%%dtprel_hi(" #x ")\n\t"         \
+         "daddiu $3,$3,%%dtprel_lo(" #x ")\n\t"        \
+         "daddu %0,%0,$3"                              \
+         : "+r" (__result) : : "$3");                  \
+     __result; })
+# define TLS_IE(x)                                     \
+  ({ void *__result;                                   \
+     __asm__ (".set push\n\t.set mips32r2\n\t"         \
+         "rdhwr\t%0,$29\n\t.set pop"                   \
+         : "=v" (__result));                           \
+     __asm__ ("ld $3,%%gottprel(" #x ")($28)\n\t"              \
+         "daddu %0,%0,$3"                              \
+         : "+r" (__result) : : "$3");                  \
+     __result; })
+# define TLS_LE(x)                                     \
+  ({ void *__result;                                   \
+     __asm__ (".set push\n\t.set mips32r2\n\t"         \
+         "rdhwr\t%0,$29\n\t.set pop"                   \
+         : "=v" (__result));                           \
+     __asm__ ("lui $3,%%tprel_hi(" #x ")\n\t"          \
+         "daddiu $3,$3,%%tprel_lo(" #x ")\n\t"         \
+         "daddu %0,%0,$3"                              \
+         : "+r" (__result) : : "$3");                  \
+     __result; })
+#endif
diff --git a/test/tls/tls-macros-thumb.h b/test/tls/tls-macros-thumb.h
new file mode 100644 (file)
index 0000000..dfa6582
--- /dev/null
@@ -0,0 +1,57 @@
+#define TLS_LE(x)                                      \
+  ({ int *__result;                                    \
+     void *tp = __builtin_thread_pointer ();           \
+     __asm__ ("ldr %0, 1f; "                           \
+         "add %0, %1, %0; "                            \
+         "b 2f; "                                      \
+         ".align 2; "                                  \
+         "1: .word " #x "(tpoff); "                    \
+         "2: "                                         \
+         : "=&r" (__result) : "r" (tp));               \
+     __result; })
+
+#define TLS_IE(x)                                      \
+  ({ int *__result;                                    \
+     int tmp;                                          \
+     void *tp = __builtin_thread_pointer ();           \
+     __asm__ ("ldr %0, 1f; "                           \
+         "adr %1, 1f; "                                \
+         "ldr %0, [%1, %0]; "                          \
+         "add %0, %2, %0; "                            \
+         "b 2f; "                                      \
+         ".align 2; "                                  \
+         "1: .word " #x "(gottpoff); "                 \
+         "2: "                                         \
+         : "=&r" (__result), "=&r"(tmp) : "r" (tp));   \
+     __result; })
+
+#define TLS_LD(x)                                      \
+  ({ char *__result;                                   \
+     int __offset;                                     \
+     extern void *__tls_get_addr (void *);             \
+     __asm__ ("ldr %0, 2f; "                           \
+         ".align 2; "                                  \
+         "1: add %0, pc, %0; "                         \
+         "b 3f; "                                      \
+         "2: .word " #x "(tlsldm) + (. - 1b - 4); "    \
+         "3: "                                         \
+         : "=r" (__result));                           \
+     __result = (char *)__tls_get_addr (__result);     \
+     __asm__ ("ldr %0, 1f; "                           \
+         "b 2f; "                                      \
+         "1: .word " #x "(tlsldo); "                   \
+         "2: "                                         \
+         : "=r" (__offset));                           \
+     (int *) (__result + __offset); })
+
+#define TLS_GD(x)                                      \
+  ({ int *__result;                                    \
+     extern void *__tls_get_addr (void *);             \
+     __asm__ ("ldr %0, 2f; "                           \
+         ".align 2; "                                  \
+         "1: add %0, pc, %0; "                         \
+         "b 3f; "                                      \
+         "2: .word " #x "(tlsgd) + (. - 1b - 4); "     \
+         "3: "                                         \
+         : "=r" (__result));                           \
+     (int *)__tls_get_addr (__result); })
diff --git a/test/tls/tls-macros.h b/test/tls/tls-macros.h
new file mode 100644 (file)
index 0000000..0eaca65
--- /dev/null
@@ -0,0 +1,861 @@
+/* Macros to support TLS testing in times of missing compiler support.  */
+
+#define COMMON_INT_DEF(x) \
+  __asm__ (".tls_common " #x ",4,4")
+/* XXX Until we get compiler support we don't need declarations.  */
+#define COMMON_INT_DECL(x)
+
+/* XXX This definition will probably be machine specific, too.  */
+#define VAR_INT_DEF(x) \
+  __asm__ (".section .tdata\n\t"                                                     \
+       ".globl " #x "\n"                                                     \
+       ".balign 4\n"                                                         \
+       #x ":\t.long 0\n\t"                                                   \
+       ".size " #x ",4\n\t"                                                  \
+       ".previous")
+/* XXX Until we get compiler support we don't need declarations.  */
+#define VAR_INT_DECL(x)
+
+#ifdef __mips__
+#include <tls-macros-mips.h>
+#endif
+
+#ifdef __arm__
+#ifdef __thumb__
+#include <tls-macros-thumb.h>
+#else
+#include <tls-macros-arm.h>
+#endif
+#endif
+
+  /* XXX Each architecture must have its own asm for now.  */
+#ifdef __i386__
+# define TLS_LE(x) \
+  ({ int *__l;                                                               \
+     __asm__ ("movl %%gs:0,%0\n\t"                                                   \
+         "subl $" #x "@tpoff,%0"                                             \
+         : "=r" (__l));                                                      \
+     __l; })
+
+# ifdef __PIC__
+#  define TLS_IE(x) \
+  ({ int *__l;                                                               \
+     __asm__ ("movl %%gs:0,%0\n\t"                                                   \
+         "subl " #x "@gottpoff(%%ebx),%0"                                    \
+         : "=r" (__l));                                                      \
+     __l; })
+# else
+#  define TLS_IE(x) \
+  ({ int *__l;                                                               \
+     __asm__ ("call 1f\n\t"                                                          \
+         ".subsection 1\n"                                                   \
+         "1:\tmovl (%%esp), %%ebx\n\t"                                       \
+         "ret\n\t"                                                           \
+         ".previous\n\t"                                                     \
+         "addl $_GLOBAL_OFFSET_TABLE_, %%ebx\n\t"                            \
+         "movl %%gs:0,%0\n\t"                                                \
+         "subl " #x "@gottpoff(%%ebx),%0"                                    \
+         : "=r" (__l));                                                      \
+     __l; })
+# endif
+
+# ifdef __PIC__
+#  define TLS_LD(x) \
+  ({ int *__l, __c, __d;                                                     \
+     __asm__ ("leal " #x "@tlsldm(%%ebx),%%eax\n\t"                                  \
+         "call ___tls_get_addr@plt\n\t"                                      \
+         "leal " #x "@dtpoff(%%eax), %%eax"                                  \
+         : "=a" (__l), "=&c" (__c), "=&d" (__d));                            \
+     __l; })
+# else
+#  define TLS_LD(x) \
+  ({ int *__l, __b, __c, __d;                                                \
+     __asm__ ("call 1f\n\t"                                                          \
+         ".subsection 1\n"                                                   \
+         "1:\tmovl (%%esp), %%ebx\n\t"                                       \
+         "ret\n\t"                                                           \
+         ".previous\n\t"                                                     \
+         "addl $_GLOBAL_OFFSET_TABLE_, %%ebx\n\t"                            \
+         "leal " #x "@tlsldm(%%ebx),%%eax\n\t"                               \
+         "call ___tls_get_addr@plt\n\t"                                      \
+         "leal " #x "@dtpoff(%%eax), %%eax"                                  \
+         : "=a" (__l), "=&b" (__b), "=&c" (__c), "=&d" (__d));               \
+     __l; })
+# endif
+
+# ifdef __PIC__
+#  define TLS_GD(x) \
+  ({ int *__l, __c, __d;                                                     \
+     __asm__ ("leal " #x "@tlsgd(%%ebx),%%eax\n\t"                                   \
+         "call ___tls_get_addr@plt\n\t"                                      \
+         "nop"                                                               \
+         : "=a" (__l), "=&c" (__c), "=&d" (__d));                            \
+     __l; })
+# else
+#  define TLS_GD(x) \
+  ({ int *__l, __c, __d;                                                     \
+     __asm__ ("call 1f\n\t"                                                          \
+         ".subsection 1\n"                                                   \
+         "1:\tmovl (%%esp), %%ebx\n\t"                                       \
+         "ret\n\t"                                                           \
+         ".previous\n\t"                                                     \
+         "addl $_GLOBAL_OFFSET_TABLE_, %%ebx\n\t"                            \
+         "leal " #x "@tlsgd(%%ebx),%%eax\n\t"                                \
+         "call ___tls_get_addr@plt\n\t"                                      \
+         "nop"                                                               \
+         : "=a" (__l), "=&c" (__c), "=&d" (__d));                            \
+     __l; })
+# endif
+
+#elif defined __x86_64__
+
+# define TLS_LE(x) \
+  ({ int *__l;                                                               \
+     __asm__ ("movq %%fs:0,%0\n\t"                                                   \
+         "leaq " #x "@tpoff(%0), %0"                                         \
+         : "=r" (__l));                                                      \
+     __l; })
+
+# define TLS_IE(x) \
+  ({ int *__l;                                                               \
+     __asm__ ("movq %%fs:0,%0\n\t"                                                   \
+         "addq " #x "@gottpoff(%%rip),%0"                                    \
+         : "=r" (__l));                                                      \
+     __l; })
+
+# define TLS_LD(x) \
+  ({ int *__l, __c, __d;                                                     \
+     __asm__ ("leaq " #x "@tlsld(%%rip),%%rdi\n\t"                                   \
+         "call __tls_get_addr@plt\n\t"                                       \
+         "leaq " #x "@dtpoff(%%rax), %%rax"                                  \
+         : "=a" (__l), "=&c" (__c), "=&d" (__d)                              \
+         : : "rdi", "rsi", "r8", "r9", "r10", "r11");                        \
+     __l; })
+
+# define TLS_GD(x) \
+  ({ int *__l, __c, __d;                                                     \
+     __asm__ (".byte 0x66\n\t"                                               \
+         "leaq " #x "@tlsgd(%%rip),%%rdi\n\t"                                \
+         ".word 0x6666\n\t"                                                  \
+         "rex64\n\t"                                                         \
+         "call __tls_get_addr@plt"                                           \
+         : "=a" (__l), "=&c" (__c), "=&d" (__d)                              \
+         : : "rdi", "rsi", "r8", "r9", "r10", "r11");                        \
+     __l; })
+
+#elif defined __sh__
+
+# define TLS_LE(x) \
+  ({ int *__l; void *__tp;                                                   \
+     __asm__ ("stc gbr,%1\n\t"                                               \
+         "mov.l 1f,%0\n\t"                                                   \
+         "bra 2f\n\t"                                                        \
+         " add %1,%0\n\t"                                                    \
+         ".align 2\n\t"                                                      \
+         "1: .long " #x "@tpoff\n\t"                                         \
+         "2:"                                                                \
+         : "=r" (__l), "=r" (__tp));                                         \
+     __l; })
+
+# ifdef __PIC__
+#  define TLS_IE(x) \
+  ({ int *__l; void *__tp;                                                   \
+     register void *__gp __asm__("r12");                                     \
+     __asm__ ("mov.l 1f,r0\n\t"                                                      \
+         "stc gbr,%1\n\t"                                                    \
+         "mov.l @(r0,r12),%0\n\t"                                            \
+         "bra 2f\n\t"                                                        \
+         " add %1,%0\n\t"                                                    \
+         ".align 2\n\t"                                                      \
+         "1: .long " #x "@gottpoff\n\t"                                      \
+         "2:"                                                                \
+         : "=r" (__l), "=r" (__tp) : "r" (__gp) : "r0");                     \
+     __l; })
+# else
+#  define TLS_IE(x) \
+  ({ int *__l; void *__tp;                                                   \
+     __asm__ ("mov.l r12,@-r15\n\t"                                                  \
+         "mova 0f,r0\n\t"                                                    \
+         "mov.l 0f,r12\n\t"                                                  \
+         "add r0,r12\n\t"                                                    \
+         "mov.l 1f,r0\n\t"                                                   \
+         "stc gbr,%1\n\t"                                                    \
+         "mov.l @(r0,r12),%0\n\t"                                            \
+         "bra 2f\n\t"                                                        \
+         " add %1,%0\n\t"                                                    \
+         ".align 2\n\t"                                                      \
+         "1: .long " #x "@gottpoff\n\t"                                      \
+         "0: .long _GLOBAL_OFFSET_TABLE_\n\t"                                \
+         "2: mov.l @r15+,r12"                                                \
+         : "=r" (__l), "=r" (__tp) : : "r0");                                \
+     __l; })
+#endif
+
+# ifdef __PIC__
+#  define TLS_LD(x) \
+  ({ int *__l;                                                               \
+     register void *__gp __asm__("r12");                                     \
+     __asm__ ("mov.l 1f,r4\n\t"                                                      \
+         "mova 2f,r0\n\t"                                                    \
+         "mov.l 2f,r1\n\t"                                                   \
+         "add r0,r1\n\t"                                                     \
+         "jsr @r1\n\t"                                                       \
+         " add r12,r4\n\t"                                                   \
+         "bra 4f\n\t"                                                        \
+         " nop\n\t"                                                          \
+         ".align 2\n\t"                                                      \
+         "1: .long " #x "@tlsldm\n\t"                                        \
+         "2: .long __tls_get_addr@plt\n\t"                                   \
+         "4: mov.l 3f,%0\n\t"                                                \
+         "bra 5f\n\t"                                                        \
+         " add r0,%0\n\t"                                                    \
+         ".align 2\n\t"                                                      \
+         "3: .long " #x "@dtpoff\n\t"                                        \
+         "5:"                                                                \
+         : "=r" (__l) : "r" (__gp) : "r0", "r1", "r2", "r3", "r4", "r5",     \
+                                     "r6", "r7", "pr", "t");                 \
+     __l; })
+# else
+#  define TLS_LD(x) \
+  ({ int *__l;                                                               \
+     __asm__ ("mov.l r12,@-r15\n\t"                                                  \
+         "mova 0f,r0\n\t"                                                    \
+         "mov.l 0f,r12\n\t"                                                  \
+         "add r0,r12\n\t"                                                    \
+         "mov.l 1f,r4\n\t"                                                   \
+         "mova 2f,r0\n\t"                                                    \
+         "mov.l 2f,r1\n\t"                                                   \
+         "add r0,r1\n\t"                                                     \
+         "jsr @r1\n\t"                                                       \
+         " add r12,r4\n\t"                                                   \
+         "bra 4f\n\t"                                                        \
+         " nop\n\t"                                                          \
+         ".align 2\n\t"                                                      \
+         "1: .long " #x "@tlsldm\n\t"                                        \
+         "2: .long __tls_get_addr@plt\n\t"                                   \
+         "0: .long _GLOBAL_OFFSET_TABLE_\n\t"                                \
+         "4: mov.l 3f,%0\n\t"                                                \
+         "bra 5f\n\t"                                                        \
+         " add r0,%0\n\t"                                                    \
+         ".align 2\n\t"                                                      \
+         "3: .long " #x "@dtpoff\n\t"                                        \
+         "5: mov.l @r15+,r12"                                                \
+         : "=r" (__l) : : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",    \
+                          "pr", "t");                                        \
+     __l; })
+#endif
+
+# ifdef __PIC__
+#  define TLS_GD(x) \
+  ({ int *__l;                                                               \
+     register void *__gp __asm__("r12");                                     \
+     __asm__ ("mov.l 1f,r4\n\t"                                                      \
+         "mova 2f,r0\n\t"                                                    \
+         "mov.l 2f,r1\n\t"                                                   \
+         "add r0,r1\n\t"                                                     \
+         "jsr @r1\n\t"                                                       \
+         " add r12,r4\n\t"                                                   \
+         "bra 3f\n\t"                                                        \
+         " mov r0,%0\n\t"                                                    \
+         ".align 2\n\t"                                                      \
+         "1: .long " #x "@tlsgd\n\t"                                         \
+         "2: .long __tls_get_addr@plt\n\t"                                   \
+         "3:"                                                                \
+         : "=r" (__l) : "r" (__gp) : "r0", "r1", "r2", "r3", "r4", "r5",     \
+                                     "r6", "r7", "pr", "t");                 \
+     __l; })
+# else
+#  define TLS_GD(x) \
+  ({ int *__l;                                                               \
+     __asm__ ("mov.l r12,@-r15\n\t"                                                  \
+         "mova 0f,r0\n\t"                                                    \
+         "mov.l 0f,r12\n\t"                                                  \
+         "add r0,r12\n\t"                                                    \
+         "mov.l 1f,r4\n\t"                                                   \
+         "mova 2f,r0\n\t"                                                    \
+         "mov.l 2f,r1\n\t"                                                   \
+         "add r0,r1\n\t"                                                     \
+         "jsr @r1\n\t"                                                       \
+         " add r12,r4\n\t"                                                   \
+         "bra 3f\n\t"                                                        \
+         " mov r0,%0\n\t"                                                    \
+         ".align 2\n\t"                                                      \
+         "1: .long " #x "@tlsgd\n\t"                                         \
+         "2: .long __tls_get_addr@plt\n\t"                                   \
+         "0: .long _GLOBAL_OFFSET_TABLE_\n\t"                                \
+         "3: mov.l @r15+,r12"                                                \
+         : "=r" (__l) : : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",    \
+                          "pr", "t");                                        \
+     __l; })
+#endif
+
+#elif defined __alpha__
+
+register void *__gp __asm__("$29");
+
+# define TLS_LE(x) \
+  ({ int *__l;                                                               \
+     __asm__ ("call_pal 158\n\tlda $0," #x "($0)\t\t!tprel" : "=v"(__l));            \
+     __l; })
+
+# define TLS_IE(x) \
+  ({ char *__tp; unsigned long __o;                                          \
+     __asm__ ("call_pal 158\n\tldq %1," #x "($gp)\t\t!gottprel"                      \
+         : "=v"(__tp), "=r"(__o) : "r"(__gp));                               \
+     (int *)(__tp + __o); })
+
+# define TLS_LD(x) \
+  ({ extern void *__tls_get_addr(void *); int *__l; void *__i;               \
+     __asm__ ("lda %0," #x "($gp)\t\t!tlsldm" : "=r" (__i) : "r"(__gp));             \
+     __i = __tls_get_addr(__i);                                                      \
+     __asm__ ("lda %0, " #x "(%1)\t\t!dtprel" : "=r"(__l) : "r"(__i));       \
+     __l; })
+
+# define TLS_GD(x) \
+  ({ extern void *__tls_get_addr(void *); void *__i;                         \
+     __asm__ ("lda %0," #x "($gp)\t\t!tlsgd" : "=r" (__i) : "r"(__gp));              \
+     (int *) __tls_get_addr(__i); })
+
+
+#elif defined __ia64__
+
+# define TLS_LE(x) \
+  ({ void *__l;                                                                      \
+     __asm__ ("mov r2=r13\n\t"                                               \
+         ";;\n\t"                                                            \
+         "addl %0=@tprel(" #x "),r2\n\t"                                     \
+         : "=r" (__l) : : "r2"  ); __l; })
+
+# define TLS_IE(x) \
+  ({ void *__l;                                                                      \
+     register long __gp __asm__ ("gp");                                              \
+     __asm__ (";;\n\t"                                                       \
+        "addl r16=@ltoff(@tprel(" #x ")),gp\n\t"                             \
+         ";;\n\t"                                                            \
+         "ld8 r17=[r16]\n\t"                                                 \
+         ";;\n\t"                                                            \
+         "add %0=r13,r17\n\t"                                                \
+         ";;\n\t"                                                            \
+         : "=r" (__l) : "r" (__gp) : "r16", "r17" ); __l; })
+
+# define __TLS_CALL_CLOBBERS \
+  "r2", "r3", "r8", "r9", "r10", "r11", "r14", "r15", "r16", "r17",          \
+  "r18", "r19", "r20", "r21", "r22", "r23", "r24", "r25", "r26",             \
+  "r27", "r28", "r29", "r30", "r31",                                         \
+  "p6", "p7", "p8", "p9", "p10", "p11", "p12", "p13", "p14", "p15",          \
+  "f6", "f7", "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",          \
+  "b6", "b7",                                                                \
+  "out0", "out1", "out2", "out3", "out4", "out5", "out6", "out7"
+
+# define TLS_LD(x) \
+  ({ void *__l;                                                                      \
+     register long __gp __asm__ ("gp");                                              \
+     __asm__ (";;\n\t"                                                       \
+        "mov loc0=gp\n\t"                                                    \
+         "addl r16=@ltoff(@dtpmod(" #x ")),gp\n\t"                           \
+         "addl out1=@dtprel(" #x "),r0\n\t"                                  \
+         ";;\n\t"                                                            \
+         "ld8 out0=[r16]\n\t"                                                \
+         "br.call.sptk.many b0=__tls_get_addr"                               \
+         ";;\n\t"                                                            \
+         "mov gp=loc0\n\t"                                                   \
+         "mov %0=r8\n\t"                                                     \
+         ";;\n\t"                                                            \
+         : "=r" (__l) : "r" (__gp) : "loc0", __TLS_CALL_CLOBBERS);           \
+     __l; })
+
+# define TLS_GD(x) \
+  ({ void *__l;                                                                      \
+     register long __gp __asm__ ("gp");                                              \
+     __asm__ (";;\n\t"                                                       \
+        "mov loc0=gp\n\t"                                                    \
+         "addl r16=@ltoff(@dtpmod(" #x ")),gp\n\t"                           \
+         "addl r17=@ltoff(@dtprel(" #x ")),gp\n\t"                           \
+         ";;\n\t"                                                            \
+         "ld8 out0=[r16]\n\t"                                                \
+         "ld8 out1=[r17]\n\t"                                                \
+         "br.call.sptk.many b0=__tls_get_addr"                               \
+         ";;\n\t"                                                            \
+         "mov gp=loc0\n\t"                                                   \
+         "mov %0=r8\n\t"                                                     \
+         ";;\n\t"                                                            \
+          : "=r" (__l) : "r" (__gp) : "loc0", __TLS_CALL_CLOBBERS);          \
+     __l; })
+
+#elif defined __sparc__ && !defined __arch64__
+
+# define TLS_LE(x) \
+  ({ int *__l;                                                               \
+     __asm__ ("sethi %%tle_hix22(" #x "), %0" : "=r" (__l));                 \
+     __asm__ ("xor %1, %%tle_lox10(" #x "), %0" : "=r" (__l) : "r" (__l));           \
+     __asm__ ("add %%g7, %1, %0" : "=r" (__l) : "r" (__l));                          \
+     __l; })
+
+# ifdef __PIC__
+#  define TLS_LOAD_PIC \
+  ({ register long pc __asm__ ("%o7");                                       \
+     long got;                                                               \
+     __asm__ ("sethi %%hi(_GLOBAL_OFFSET_TABLE_-4), %1\n\t"                          \
+         "call .+8\n\t"                                                      \
+         "add %1, %%lo(_GLOBAL_OFFSET_TABLE_+4), %1\n\t"                     \
+         "add %1, %0, %1\n\t"                                                \
+         : "=r" (pc), "=r" (got));                                           \
+     got; })
+# else
+#  define TLS_LOAD_PIC \
+   ({ long got;                                                                      \
+      __asm__ (".hidden _GLOBAL_OFFSET_TABLE_\n\t"                                   \
+          "sethi %%hi(_GLOBAL_OFFSET_TABLE_), %0\n\t"                        \
+          "or %0, %%lo(_GLOBAL_OFFSET_TABLE_), %0"                           \
+          : "=r" (got));                                                     \
+      got; })
+# endif
+
+# define TLS_IE(x) \
+  ({ int *__l;                                                               \
+     __asm__ ("sethi %%tie_hi22(" #x "), %0" : "=r" (__l));                          \
+     __asm__ ("add %1, %%tie_lo10(" #x "), %0" : "=r" (__l) : "r" (__l));            \
+     __asm__ ("ld [%1 + %2], %0, %%tie_ld(" #x ")"                                   \
+         : "=r" (__l) : "r" (TLS_LOAD_PIC), "r" (__l));                      \
+     __asm__ ("add %%g7, %1, %0, %%tie_add(" #x ")" : "=r" (__l) : "r" (__l));    \
+     __l; })
+
+# define TLS_LD(x) \
+  ({ int *__l; register void *__o0 __asm__ ("%o0");                                  \
+     long __o;                                                               \
+     __asm__ ("sethi %%tldm_hi22(" #x "), %0" : "=r" (__l));                 \
+     __asm__ ("add %1, %%tldm_lo10(" #x "), %0" : "=r" (__l) : "r" (__l));           \
+     __asm__ ("add %1, %2, %0, %%tldm_add(" #x ")"                                   \
+         : "=r" (__o0) : "r" (TLS_LOAD_PIC), "r" (__l));                     \
+     __asm__ ("call __tls_get_addr, %%tgd_call(" #x ")\n\t"                          \
+         " nop"                                                              \
+         : "=r" (__o0) : "0" (__o0)                                          \
+         : "g1", "g2", "g3", "g4", "g5", "g6", "o1", "o2", "o3", "o4",       \
+           "o5", "o7", "cc");                                                \
+     __asm__ ("sethi %%tldo_hix22(" #x "), %0" : "=r" (__o));                \
+     __asm__ ("xor %1, %%tldo_lox10(" #x "), %0" : "=r" (__o) : "r" (__o));          \
+     __asm__ ("add %1, %2, %0, %%tldo_add(" #x ")" : "=r" (__l)                      \
+         : "r" (__o0), "r" (__o));                                           \
+     __l; })
+
+# define TLS_GD(x) \
+  ({ int *__l; register void *__o0 __asm__ ("%o0");                                  \
+     __asm__ ("sethi %%tgd_hi22(" #x "), %0" : "=r" (__l));                          \
+     __asm__ ("add %1, %%tgd_lo10(" #x "), %0" : "=r" (__l) : "r" (__l));            \
+     __asm__ ("add %1, %2, %0, %%tgd_add(" #x ")"                                    \
+         : "=r" (__o0) : "r" (TLS_LOAD_PIC), "r" (__l));                     \
+     __asm__ ("call __tls_get_addr, %%tgd_call(" #x ")\n\t"                          \
+         " nop"                                                              \
+         : "=r" (__o0) : "0" (__o0)                                          \
+         : "g1", "g2", "g3", "g4", "g5", "g6", "o1", "o2", "o3", "o4",       \
+           "o5", "o7", "cc");                                                \
+     __o0; })
+
+#elif defined __sparc__ && defined __arch64__
+
+# define TLS_LE(x) \
+  ({ int *__l;                                                               \
+     __asm__ ("sethi %%tle_hix22(" #x "), %0" : "=r" (__l));                 \
+     __asm__ ("xor %1, %%tle_lox10(" #x "), %0" : "=r" (__l) : "r" (__l));           \
+     __asm__ ("add %%g7, %1, %0" : "=r" (__l) : "r" (__l));                          \
+     __l; })
+
+# ifdef __PIC__
+#  define TLS_LOAD_PIC \
+  ({ long pc, got;                                                           \
+     __asm__ ("sethi %%hi(_GLOBAL_OFFSET_TABLE_-4), %1\n\t"                          \
+         "rd %%pc, %0\n\t"                                                   \
+         "add %1, %%lo(_GLOBAL_OFFSET_TABLE_+4), %1\n\t"                     \
+         "add %1, %0, %1\n\t"                                                \
+         : "=r" (pc), "=r" (got));                                           \
+     got; })
+# else
+#  define TLS_LOAD_PIC \
+   ({ long got;                                                                      \
+      __asm__ (".hidden _GLOBAL_OFFSET_TABLE_\n\t"                                   \
+          "sethi %%hi(_GLOBAL_OFFSET_TABLE_), %0\n\t"                        \
+          "or %0, %%lo(_GLOBAL_OFFSET_TABLE_), %0"                           \
+          : "=r" (got));                                                     \
+      got; })
+# endif
+
+# define TLS_IE(x) \
+  ({ int *__l;                                                               \
+     __asm__ ("sethi %%tie_hi22(" #x "), %0" : "=r" (__l));                          \
+     __asm__ ("add %1, %%tie_lo10(" #x "), %0" : "=r" (__l) : "r" (__l));            \
+     __asm__ ("ldx [%1 + %2], %0, %%tie_ldx(" #x ")"                         \
+         : "=r" (__l) : "r" (TLS_LOAD_PIC), "r" (__l));                      \
+     __asm__ ("add %%g7, %1, %0, %%tie_add(" #x ")" : "=r" (__l) : "r" (__l));    \
+     __l; })
+
+# define TLS_LD(x) \
+  ({ int *__l; register void *__o0 __asm__ ("%o0");                                  \
+     long __o;                                                               \
+     __asm__ ("sethi %%tldm_hi22(" #x "), %0" : "=r" (__l));                 \
+     __asm__ ("add %1, %%tldm_lo10(" #x "), %0" : "=r" (__l) : "r" (__l));           \
+     __asm__ ("add %1, %2, %0, %%tldm_add(" #x ")"                                   \
+         : "=r" (__o0) : "r" (TLS_LOAD_PIC), "r" (__l));                     \
+     __asm__ ("call __tls_get_addr, %%tgd_call(" #x ")\n\t"                          \
+         " nop"                                                              \
+         : "=r" (__o0) : "0" (__o0)                                          \
+         : "g1", "g2", "g3", "g4", "g5", "g6", "o1", "o2", "o3", "o4",       \
+           "o5", "o7", "cc");                                                \
+     __asm__ ("sethi %%tldo_hix22(" #x "), %0" : "=r" (__o));                \
+     __asm__ ("xor %1, %%tldo_lox10(" #x "), %0" : "=r" (__o) : "r" (__o));          \
+     __asm__ ("add %1, %2, %0, %%tldo_add(" #x ")" : "=r" (__l)                      \
+         : "r" (__o0), "r" (__o));                                           \
+     __l; })
+
+# define TLS_GD(x) \
+  ({ int *__l; register void *__o0 __asm__ ("%o0");                                  \
+     __asm__ ("sethi %%tgd_hi22(" #x "), %0" : "=r" (__l));                          \
+     __asm__ ("add %1, %%tgd_lo10(" #x "), %0" : "=r" (__l) : "r" (__l));            \
+     __asm__ ("add %1, %2, %0, %%tgd_add(" #x ")"                                    \
+         : "=r" (__o0) : "r" (TLS_LOAD_PIC), "r" (__l));                     \
+     __asm__ ("call __tls_get_addr, %%tgd_call(" #x ")\n\t"                          \
+         " nop"                                                              \
+         : "=r" (__o0) : "0" (__o0)                                          \
+         : "g1", "g2", "g3", "g4", "g5", "g6", "o1", "o2", "o3", "o4",       \
+           "o5", "o7", "cc");                                                \
+     __o0; })
+
+#elif defined __s390x__
+
+# define TLS_LE(x) \
+  ({ unsigned long __offset;                                                 \
+     __asm__ ("bras %0,1f\n"                                                 \
+         "0:\t.quad " #x "@ntpoff\n"                                         \
+         "1:\tlg %0,0(%0)"                                                   \
+         : "=a" (__offset) : : "cc" );                                       \
+     (int *) (__builtin_thread_pointer() + __offset); })
+
+# ifdef __PIC__
+#  define TLS_IE(x) \
+  ({ unsigned long __offset;                                                 \
+     __asm__ ("bras %0,1f\n"                                                 \
+         "0:\t.quad " #x "@gotntpoff\n"                                      \
+         "1:\tlg %0,0(%0)\n\t"                                               \
+         "lg %0,0(%0,%%r12):tls_load:" #x                                    \
+         : "=&a" (__offset) : : "cc" );                                      \
+     (int *) (__builtin_thread_pointer() + __offset); })
+# else
+#  define TLS_IE(x) \
+  ({ unsigned long  __offset;                                                \
+     __asm__ ("bras %0,1f\n"                                                 \
+         "0:\t.quad " #x "@indntpoff\n"                                      \
+         "1:\t lg %0,0(%0)\n\t"                                              \
+         "lg %0,0(%0):tls_load:" #x                                          \
+         : "=&a" (__offset) : : "cc" );                                      \
+     (int *) (__builtin_thread_pointer() + __offset); })
+# endif
+
+# ifdef __PIC__
+#  define TLS_LD(x) \
+  ({ unsigned long __offset, __save12;                                       \
+     __asm__ ("bras %0,1f\n"                                                 \
+         "0:\t.quad " #x "@tlsldm\n\t"                                       \
+         ".quad " #x "@dtpoff\n"                                             \
+         "1:\tlgr %1,%%r12\n\t"                                              \
+          "larl %%r12,_GLOBAL_OFFSET_TABLE_\n\t"                             \
+          "lg %%r2,0(%0)\n\t"                                                \
+         "brasl %%r14,__tls_get_offset@plt:tls_ldcall:" #x "\n\t"            \
+         "lg %0,8(%0)\n\t"                                                   \
+         "algr %0,%%r2\n\t"                                                  \
+          "lgr %%r12,%1"                                                     \
+         : "=&a" (__offset), "=&a" (__save12)                                \
+          : : "cc", "0", "1", "2", "3", "4", "5", "14" );                    \
+     (int *) (__builtin_thread_pointer() + __offset); })
+# else
+#  define TLS_LD(x) \
+  ({ unsigned long __offset;                                                 \
+     __asm__ ("bras %0,1f\n"                                                 \
+         "0:\t.quad " #x "@tlsldm\n\t"                                       \
+         ".quad " #x "@dtpoff\n"                                             \
+         "1:\tlarl %%r12,_GLOBAL_OFFSET_TABLE_\n\t"                          \
+          "lg %%r2,0(%0)\n\t"                                                \
+         "brasl %%r14,__tls_get_offset@plt:tls_ldcall:" #x "\n\t"            \
+         "lg %0,8(%0)\n\t"                                                   \
+         "algr %0,%%r2"                                                      \
+         : "=&a" (__offset)                                                  \
+         : : "cc", "0", "1", "2", "3", "4", "5", "12", "14" );               \
+     (int *) (__builtin_thread_pointer() + __offset); })
+# endif
+
+# ifdef __PIC__
+#  define TLS_GD(x) \
+  ({ unsigned long __offset, __save12;                                       \
+     __asm__ ("bras %0,1f\n"                                                 \
+         "0:\t.quad " #x "@tlsgd\n"                                          \
+         "1:\tlgr %1,%%r12\n\t"                                              \
+         "larl %%r12,_GLOBAL_OFFSET_TABLE_\n\t"                              \
+          "lg %%r2,0(%0)\n\t"                                                \
+         "brasl %%r14,__tls_get_offset@plt:tls_gdcall:" #x "\n\t"            \
+          "lgr %0,%%r2\n\t"                                                  \
+          "lgr %%r12,%1"                                                     \
+         : "=&a" (__offset), "=&a" (__save12)                                \
+          : : "cc", "0", "1", "2", "3", "4", "5", "14" );                    \
+     (int *) (__builtin_thread_pointer() + __offset); })
+# else
+#  define TLS_GD(x) \
+  ({ unsigned long __offset;                                                 \
+     __asm__ ("bras %0,1f\n"                                                 \
+         "0:\t.quad " #x "@tlsgd\n"                                          \
+         "1:\tlarl %%r12,_GLOBAL_OFFSET_TABLE_\n\t"                          \
+         "lg %%r2,0(%0)\n\t"                                                 \
+         "brasl %%r14,__tls_get_offset@plt:tls_gdcall:" #x "\n\t"            \
+          "lgr %0,%%r2"                                                              \
+         : "=&a" (__offset)                                                  \
+         : : "cc", "0", "1", "2", "3", "4", "5", "12", "14" );               \
+     (int *) (__builtin_thread_pointer() + __offset); })
+# endif
+
+#elif defined __s390__
+
+# define TLS_LE(x) \
+  ({ unsigned long __offset;                                                 \
+     __asm__ ("bras %0,1f\n"                                                 \
+         "0:\t.long " #x "@ntpoff\n"                                         \
+         "1:\tl %0,0(%0)"                                                    \
+         : "=a" (__offset) : : "cc" );                                       \
+     (int *) (__builtin_thread_pointer() + __offset); })
+
+# ifdef __PIC__
+#  define TLS_IE(x) \
+  ({ unsigned long __offset;                                                 \
+     __asm__ ("bras %0,1f\n"                                                 \
+         "0:\t.long " #x "@gotntpoff\n"                                      \
+         "1:\tl %0,0(%0)\n\t"                                                \
+         "l %0,0(%0,%%r12):tls_load:" #x                                     \
+         : "=&a" (__offset) : : "cc" );                                      \
+     (int *) (__builtin_thread_pointer() + __offset); })
+# else
+#  define TLS_IE(x) \
+  ({ unsigned long  __offset;                                                \
+     __asm__ ("bras %0,1f\n"                                                 \
+         "0:\t.long " #x "@indntpoff\n"                                      \
+         "1:\t l %0,0(%0)\n\t"                                               \
+         "l %0,0(%0):tls_load:" #x                                           \
+         : "=&a" (__offset) : : "cc" );                                      \
+     (int *) (__builtin_thread_pointer() + __offset); })
+# endif
+
+# ifdef __PIC__
+#  define TLS_LD(x) \
+  ({ unsigned long __offset, __save12;                                       \
+     __asm__ ("bras %0,1f\n"                                                 \
+         "0:\t.long _GLOBAL_OFFSET_TABLE_-0b\n\t"                            \
+         ".long __tls_get_offset@plt-0b\n\t"                                 \
+         ".long " #x "@tlsldm\n\t"                                           \
+         ".long " #x "@dtpoff\n"                                             \
+         "1:\tlr %1,%%r12\n\t"                                               \
+          "l %%r12,0(%0)\n\t"                                                \
+          "la %%r12,0(%%r12,%0)\n\t"                                         \
+         "l %%r1,4(%0)\n\t"                                                  \
+         "l %%r2,8(%0)\n\t"                                                  \
+         "bas %%r14,0(%%r1,%0):tls_ldcall:" #x "\n\t"                        \
+         "l %0,12(%0)\n\t"                                                   \
+         "alr %0,%%r2\n\t"                                                   \
+          "lr %%r12,%1"                                                              \
+         : "=&a" (__offset), "=&a" (__save12)                                \
+          : : "cc", "0", "1", "2", "3", "4", "5" );                          \
+     (int *) (__builtin_thread_pointer() + __offset); })
+# else
+#  define TLS_LD(x) \
+  ({ unsigned long __offset;                                                 \
+     __asm__ ("bras %0,1f\n"                                                 \
+         "0:\t.long _GLOBAL_OFFSET_TABLE_\n\t"                               \
+         ".long __tls_get_offset@plt\n\t"                                    \
+         ".long " #x "@tlsldm\n\t"                                           \
+         ".long " #x "@dtpoff\n"                                             \
+         "1:\tl %%r12,0(%0)\n\t"                                             \
+         "l %%r1,4(%0)\n\t"                                                  \
+         "l %%r2,8(%0)\n\t"                                                  \
+         "bas %%r14,0(%%r1):tls_ldcall:" #x "\n\t"                           \
+         "l %0,12(%0)\n\t"                                                   \
+         "alr %0,%%r2"                                                       \
+         : "=&a" (__offset) : : "cc", "0", "1", "2", "3", "4", "5", "12" );  \
+     (int *) (__builtin_thread_pointer() + __offset); })
+# endif
+
+# ifdef __PIC__
+#  define TLS_GD(x) \
+  ({ unsigned long __offset, __save12;                                       \
+     __asm__ ("bras %0,1f\n"                                                 \
+         "0:\t.long _GLOBAL_OFFSET_TABLE_-0b\n\t"                            \
+         ".long __tls_get_offset@plt-0b\n\t"                                 \
+         ".long " #x "@tlsgd\n"                                              \
+         "1:\tlr %1,%%r12\n\t"                                               \
+          "l %%r12,0(%0)\n\t"                                                \
+          "la %%r12,0(%%r12,%0)\n\t"                                         \
+         "l %%r1,4(%0)\n\t"                                                  \
+         "l %%r2,8(%0)\n\t"                                                  \
+         "bas %%r14,0(%%r1,%0):tls_gdcall:" #x "\n\t"                        \
+          "lr %0,%%r2\n\t"                                                   \
+          "lr %%r12,%1"                                                              \
+         : "=&a" (__offset), "=&a" (__save12)                                \
+          : : "cc", "0", "1", "2", "3", "4", "5" );                          \
+     (int *) (__builtin_thread_pointer() + __offset); })
+# else
+#  define TLS_GD(x) \
+  ({ unsigned long __offset;                                                 \
+     __asm__ ("bras %0,1f\n"                                                 \
+         "0:\t.long _GLOBAL_OFFSET_TABLE_\n\t"                               \
+         ".long __tls_get_offset@plt\n\t"                                    \
+         ".long " #x "@tlsgd\n"                                              \
+         "1:\tl %%r12,0(%0)\n\t"                                             \
+         "l %%r1,4(%0)\n\t"                                                  \
+         "l %%r2,8(%0)\n\t"                                                  \
+         "bas %%r14,0(%%r1):tls_gdcall:" #x "\n\t"                           \
+          "lr %0,%%r2"                                                       \
+         : "=&a" (__offset) : : "cc", "0", "1", "2", "3", "4", "5", "12" );  \
+     (int *) (__builtin_thread_pointer() + __offset); })
+# endif
+
+#elif defined __powerpc__ && !defined __powerpc64__
+
+#include "config.h"
+
+# define __TLS_CALL_CLOBBERS                                           \
+       "0", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12",       \
+       "lr", "ctr", "cr0", "cr1", "cr5", "cr6", "cr7"
+
+/* PowerPC32 Local Exec TLS access.  */
+# define TLS_LE(x)                             \
+  ({ int *__result;                            \
+     __asm__ ("addi %0,2," #x "@tprel"         \
+         : "=r" (__result));                   \
+     __result; })
+
+/* PowerPC32 Initial Exec TLS access.  */
+# ifdef HAVE_ASM_PPC_REL16
+#  define TLS_IE(x)                                    \
+  ({ int *__result;                                    \
+     __asm__ ("bcl 20,31,1f\n1:\t"                             \
+         "mflr %0\n\t"                                 \
+         "addis %0,%0,_GLOBAL_OFFSET_TABLE_-1b@ha\n\t" \
+         "addi %0,%0,_GLOBAL_OFFSET_TABLE_-1b@l\n\t"   \
+         "lwz %0," #x "@got@tprel(%0)\n\t"             \
+         "add %0,%0," #x "@tls"                        \
+         : "=b" (__result) :                           \
+         : "lr");                                      \
+     __result; })
+# else
+#  define TLS_IE(x)                                    \
+  ({ int *__result;                                    \
+     __asm__ ("bl _GLOBAL_OFFSET_TABLE_@local-4\n\t"   \
+         "mflr %0\n\t"                                 \
+         "lwz %0," #x "@got@tprel(%0)\n\t"             \
+         "add %0,%0," #x "@tls"                        \
+         : "=b" (__result) :                           \
+         : "lr");                                      \
+     __result; })
+# endif
+
+/* PowerPC32 Local Dynamic TLS access.  */
+# ifdef HAVE_ASM_PPC_REL16
+#  define TLS_LD(x)                                    \
+  ({ int *__result;                                    \
+     __asm__ ("bcl 20,31,1f\n1:\t"                             \
+         "mflr 3\n\t"                                  \
+         "addis 3,3,_GLOBAL_OFFSET_TABLE_-1b@ha\n\t"   \
+         "addi 3,3,_GLOBAL_OFFSET_TABLE_-1b@l\n\t"     \
+         "addi 3,3," #x "@got@tlsld\n\t"               \
+         "bl __tls_get_addr@plt\n\t"                   \
+         "addi %0,3," #x "@dtprel"                     \
+         : "=r" (__result) :                           \
+         : __TLS_CALL_CLOBBERS);                       \
+     __result; })
+# else
+#  define TLS_LD(x)                                    \
+  ({ int *__result;                                    \
+     __asm__ ("bl _GLOBAL_OFFSET_TABLE_@local-4\n\t"   \
+         "mflr 3\n\t"                                  \
+         "addi 3,3," #x "@got@tlsld\n\t"               \
+         "bl __tls_get_addr@plt\n\t"                   \
+         "addi %0,3," #x "@dtprel"                     \
+         : "=r" (__result) :                           \
+         : __TLS_CALL_CLOBBERS);                       \
+     __result; })
+# endif
+
+/* PowerPC32 General Dynamic TLS access.  */
+# ifdef HAVE_ASM_PPC_REL16
+#  define TLS_GD(x)                                    \
+  ({ register int *__result __asm__ ("r3");            \
+     __asm__ ("bcl 20,31,1f\n1:\t"                             \
+         "mflr 3\n\t"                                  \
+         "addis 3,3,_GLOBAL_OFFSET_TABLE_-1b@ha\n\t"   \
+         "addi 3,3,_GLOBAL_OFFSET_TABLE_-1b@l\n\t"     \
+         "addi 3,3," #x "@got@tlsgd\n\t"               \
+         "bl __tls_get_addr@plt"                       \
+         : :                                           \
+         : __TLS_CALL_CLOBBERS);                       \
+     __result; })
+# else
+#  define TLS_GD(x)                                    \
+  ({ register int *__result __asm__ ("r3");            \
+     __asm__ ("bl _GLOBAL_OFFSET_TABLE_@local-4\n\t"   \
+         "mflr 3\n\t"                                  \
+         "addi 3,3," #x "@got@tlsgd\n\t"               \
+         "bl __tls_get_addr@plt"                       \
+         : :                                           \
+         : __TLS_CALL_CLOBBERS);                       \
+     __result; })
+# endif
+
+#elif defined __powerpc__ && defined __powerpc64__
+
+/* PowerPC64 Local Exec TLS access.  */
+# define TLS_LE(x) \
+  ({  int * __result;  \
+      __asm__ ( \
+        "  addis %0,13," #x "@tprel@ha\n"  \
+        "  addi  %0,%0," #x "@tprel@l\n"   \
+        : "=b" (__result) );  \
+      __result;  \
+  })
+/* PowerPC64 Initial Exec TLS access.  */
+#  define TLS_IE(x) \
+  ({  int * __result;  \
+      __asm__ (  \
+        "  ld  %0," #x "@got@tprel(2)\n"  \
+        "  add %0,%0," #x "@tls\n"   \
+        : "=b" (__result) );  \
+      __result;  \
+  })
+/* PowerPC64 Local Dynamic TLS access.  */
+#  define TLS_LD(x) \
+  ({  int * __result;  \
+      __asm__ (  \
+        "  addi  3,2," #x "@got@tlsld\n"  \
+        "  bl    .__tls_get_addr\n"  \
+        "  nop   \n"  \
+        "  addis %0,3," #x "@dtprel@ha\n"  \
+        "  addi  %0,%0," #x "@dtprel@l\n"  \
+        : "=b" (__result) :  \
+        : "0", "3", "4", "5", "6", "7",    \
+          "8", "9", "10", "11", "12",      \
+          "lr", "ctr",  \
+          "cr0", "cr1", "cr5", "cr6", "cr7");  \
+      __result;  \
+  })
+/* PowerPC64 General Dynamic TLS access.  */
+#  define TLS_GD(x) \
+  ({  int * __result;  \
+      __asm__ (  \
+        "  addi  3,2," #x "@got@tlsgd\n"  \
+        "  bl    .__tls_get_addr\n"  \
+        "  nop   \n"  \
+        "  mr    %0,3\n"  \
+        : "=b" (__result) :  \
+        : "0", "3", "4", "5", "6", "7",    \
+          "8", "9", "10", "11", "12",      \
+          "lr", "ctr",  \
+          "cr0", "cr1", "cr5", "cr6", "cr7");  \
+      __result;  \
+  })
+
+#elif !defined TLS_LE || !defined TLS_IE \
+      || !defined TLS_LD || !defined TLS_GD
+# error "No support for this architecture so far."
+#endif
diff --git a/test/tls/tst-tls-at-ctor.c b/test/tls/tst-tls-at-ctor.c
new file mode 100644 (file)
index 0000000..53aece1
--- /dev/null
@@ -0,0 +1,21 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <tls.h>
+
+#define TLS_VAR_INIT_VALUE 99
+
+#ifdef USE_TLS
+extern __thread int tls_var;
+#endif
+
+int main(void)
+{
+       int ret = EXIT_SUCCESS;
+#ifdef USE_TLS
+       if (tls_var != TLS_VAR_INIT_VALUE) {
+               printf("tls_var = %d - Expected value = %d\n", tls_var, TLS_VAR_INIT_VALUE);
+               ret = EXIT_FAILURE;
+       }
+#endif
+       return ret;
+}
diff --git a/test/tls/tst-tls1-static.c b/test/tls/tst-tls1-static.c
new file mode 100644 (file)
index 0000000..a010080
--- /dev/null
@@ -0,0 +1 @@
+#include "tst-tls1.c"
diff --git a/test/tls/tst-tls1.c b/test/tls/tst-tls1.c
new file mode 100644 (file)
index 0000000..f5ac6d2
--- /dev/null
@@ -0,0 +1,92 @@
+/* glibc test for TLS in ld.so.  */
+#undef _LIBC
+#include <stdio.h>
+
+#include <tls.h>
+
+#ifdef USE_TLS
+# include "tls-macros.h"
+
+
+/* Two common 'int' variables in TLS.  */
+COMMON_INT_DEF(foo);
+COMMON_INT_DEF(bar);
+#endif
+
+
+#define TEST_FUNCTION do_test ()
+static int
+do_test (void)
+{
+#ifdef USE_TLS
+  int result = 0;
+  int *ap, *bp;
+
+
+  /* Set the variable using the local exec model.  */
+  puts ("set bar to 1 (LE)");
+  ap = TLS_LE (bar);
+  *ap = 1;
+
+
+  /* Get variables using initial exec model.  */
+  fputs ("get sum of foo and bar (IE)", stdout);
+  ap = TLS_IE (foo);
+  bp = TLS_IE (bar);
+  printf (" = %d\n", *ap + *bp);
+  result |= *ap + *bp != 1;
+  if (*ap != 0)
+    {
+      printf ("foo = %d\n", *ap);
+      result = 1;
+    }
+  if (*bp != 1)
+    {
+      printf ("bar = %d\n", *bp);
+      result = 1;
+    }
+
+
+  /* Get variables using local dynamic model.  */
+  fputs ("get sum of foo and bar (LD)", stdout);
+  ap = TLS_LD (foo);
+  bp = TLS_LD (bar);
+  printf (" = %d\n", *ap + *bp);
+  result |= *ap + *bp != 1;
+  if (*ap != 0)
+    {
+      printf ("foo = %d\n", *ap);
+      result = 1;
+    }
+  if (*bp != 1)
+    {
+      printf ("bar = %d\n", *bp);
+      result = 1;
+    }
+
+
+  /* Get variables using generic dynamic model.  */
+  fputs ("get sum of foo and bar (GD)", stdout);
+  ap = TLS_GD (foo);
+  bp = TLS_GD (bar);
+  printf (" = %d\n", *ap + *bp);
+  result |= *ap + *bp != 1;
+  if (*ap != 0)
+    {
+      printf ("foo = %d\n", *ap);
+      result = 1;
+    }
+  if (*bp != 1)
+    {
+      printf ("bar = %d\n", *bp);
+      result = 1;
+    }
+
+  return result;
+#else
+  return 0;
+#endif
+}
+
+
+#include "../test-skeleton.c"
diff --git a/test/tls/tst-tls10.c b/test/tls/tst-tls10.c
new file mode 100644 (file)
index 0000000..fc06770
--- /dev/null
@@ -0,0 +1,40 @@
+#include "tst-tls10.h"
+
+#ifdef USE_TLS__THREAD
+__thread int dummy __attribute__((visibility ("hidden"))) = 12;
+__thread struct A local = { 1, 2, 3 };
+#endif
+
+#define CHECK(N, S)                                    \
+  p = f##N##a ();                                      \
+  if (p->a != S || p->b != S + 1 || p->c != S + 2)     \
+    abort ()
+
+int
+main (void)
+{
+  struct A *p;
+  if (local.a != 1 || local.b != 2 || local.c != 3)
+    abort ();
+#ifdef USE_TLS__THREAD
+  if (a1.a != 4 || a1.b != 5 || a1.c != 6)
+    abort ();
+  if (a2.a != 22 || a2.b != 23 || a2.c != 24)
+    abort ();
+  if (a3.a != 10 || a3.b != 11 || a3.c != 12)
+    abort ();
+  if (a4.a != 25 || a4.b != 26 || a4.c != 27)
+    abort ();
+  check1 ();
+  check2 ();
+  if (f1a () != &a1 || f2a () != &a2 || f3a () != &a3 || f4a () != &a4)
+    abort ();
+  CHECK (5, 16);
+  CHECK (6, 19);
+  if (f7a () != &a2 || f8a () != &a4)
+    abort ();
+  CHECK (9, 28);
+  CHECK (10, 31);
+#endif
+  exit (0);
+}
diff --git a/test/tls/tst-tls10.h b/test/tls/tst-tls10.h
new file mode 100644 (file)
index 0000000..1be6adc
--- /dev/null
@@ -0,0 +1,38 @@
+#include <tls.h>
+#include <stdlib.h>
+
+#if defined USE_TLS && defined HAVE___THREAD \
+    && defined HAVE_TLS_MODEL_ATTRIBUTE
+# define USE_TLS__THREAD
+
+struct A
+{
+  char a;
+  int b;
+  long long c;
+};
+
+extern __thread struct A a1, a2, a3, a4;
+extern struct A *f1a (void);
+extern struct A *f2a (void);
+extern struct A *f3a (void);
+extern struct A *f4a (void);
+extern struct A *f5a (void);
+extern struct A *f6a (void);
+extern struct A *f7a (void);
+extern struct A *f8a (void);
+extern struct A *f9a (void);
+extern struct A *f10a (void);
+extern int f1b (void);
+extern int f2b (void);
+extern int f3b (void);
+extern int f4b (void);
+extern int f5b (void);
+extern int f6b (void);
+extern int f7b (void);
+extern int f8b (void);
+extern int f9b (void);
+extern int f10b (void);
+extern void check1 (void);
+extern void check2 (void);
+#endif
diff --git a/test/tls/tst-tls11.c b/test/tls/tst-tls11.c
new file mode 100644 (file)
index 0000000..816cf5c
--- /dev/null
@@ -0,0 +1,27 @@
+#include "tst-tls10.h"
+
+#define CHECK(N, S)                                    \
+  p = f##N##a ();                                      \
+  if (p->a != S || p->b != S + 1 || p->c != S + 2)     \
+    abort ()
+
+int
+main (void)
+{
+#ifdef USE_TLS__THREAD
+  struct A *p;
+  check1 ();
+  check2 ();
+  CHECK (1, 4);
+  CHECK (2, 22);
+  CHECK (3, 10);
+  CHECK (4, 25);
+  CHECK (5, 16);
+  CHECK (6, 19);
+  CHECK (7, 22);
+  CHECK (8, 25);
+  CHECK (9, 28);
+  CHECK (10, 31);
+#endif
+  exit (0);
+}
diff --git a/test/tls/tst-tls12.c b/test/tls/tst-tls12.c
new file mode 100644 (file)
index 0000000..84aa7d3
--- /dev/null
@@ -0,0 +1,18 @@
+#include "tst-tls10.h"
+
+#define CHECK(N, S)                                    \
+  p = &a##N;                                           \
+  if (p->a != S || p->b != S + 1 || p->c != S + 2)     \
+    abort ()
+
+int
+main (void)
+{
+#ifdef USE_TLS__THREAD
+  struct A *p;
+  check1 ();
+  CHECK (1, 4);
+  CHECK (2, 7);
+#endif
+  exit (0);
+}
diff --git a/test/tls/tst-tls13.c b/test/tls/tst-tls13.c
new file mode 100644 (file)
index 0000000..55fb62e
--- /dev/null
@@ -0,0 +1,30 @@
+/* Check unloading modules with data in static TLS block.  */
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+static int
+do_test (void)
+{
+  int i;
+  for (i = 0; i < 1000;)
+    {
+      printf ("round %d\n",++i);
+
+      void *h = dlopen ("tst-tlsmod13a.so", RTLD_LAZY);
+      if (h == NULL)
+       {
+         printf ("cannot load: %s\n", dlerror ());
+         exit (1);
+       }
+
+      dlclose (h);
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#define TIMEOUT 3
+#include "../test-skeleton.c"
diff --git a/test/tls/tst-tls14.c b/test/tls/tst-tls14.c
new file mode 100644 (file)
index 0000000..428fd52
--- /dev/null
@@ -0,0 +1,66 @@
+/* Check alignment of TLS variable.  */
+#include <dlfcn.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <tls.h>
+
+#if USE_TLS && HAVE___THREAD
+
+#define AL 4096
+struct foo
+{
+  int i;
+} __attribute ((aligned (AL)));
+
+static __thread struct foo f;
+static struct foo g;
+
+
+extern int in_dso1 (void);
+
+
+static int
+do_test (void)
+{
+  int result = 0;
+
+  int fail = (((uintptr_t) &f) & (AL - 1)) != 0;
+  printf ("&f = %p %s\n", &f, fail ? "FAIL" : "OK");
+  result |= fail;
+
+  fail = (((uintptr_t) &g) & (AL - 1)) != 0;
+  printf ("&g = %p %s\n", &g, fail ? "FAIL" : "OK");
+  result |= fail;
+
+  result |= in_dso1 ();
+
+  void *h = dlopen ("tst-tlsmod14b.so", RTLD_LAZY);
+  if (h == NULL)
+    {
+      printf ("cannot open tst-tlsmod14b.so: %m\n");
+      exit (1);
+    }
+
+  int (*fp) (void) = (int (*) (void)) dlsym (h, "in_dso2");
+  if (fp == NULL)
+    {
+      puts ("cannot find in_dso2");
+      exit (1);
+    }
+
+  result |= fp ();
+
+  return result;
+}
+
+#define TEST_FUNCTION do_test ()
+
+#else
+
+#define TEST_FUNCTION 0
+
+#endif
+
+#include "../test-skeleton.c"
diff --git a/test/tls/tst-tls15.c b/test/tls/tst-tls15.c
new file mode 100644 (file)
index 0000000..2c2df25
--- /dev/null
@@ -0,0 +1,33 @@
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static int
+do_test (void)
+{
+  void *h = dlopen ("tst-tlsmod15a.so", RTLD_NOW);
+  if (h != NULL)
+    {
+      puts ("unexpectedly succeeded to open tst-tlsmod15a.so");
+      exit (1);
+    }
+
+  h = dlopen ("tst-tlsmod15b.so", RTLD_NOW);
+  if (h == NULL)
+    {
+      puts ("failed to open tst-tlsmod15b.so");
+      exit (1);
+    }
+
+  int (*fp) (void) = (int (*) (void)) dlsym (h, "in_dso");
+  if (fp == NULL)
+    {
+      puts ("cannot find in_dso");
+      exit (1);
+    }
+
+  return fp ();
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/tls/tst-tls16.c b/test/tls/tst-tls16.c
new file mode 100644 (file)
index 0000000..17912dc
--- /dev/null
@@ -0,0 +1,53 @@
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static int
+do_test (void)
+{
+  void *h = dlopen ("tst-tlsmod16a.so", RTLD_LAZY | RTLD_GLOBAL);
+  if (h == NULL)
+    {
+      puts ("unexpectedly failed to open tst-tlsmod16a.so");
+      exit (1);
+    }
+
+  void *p = dlsym (h, "tlsvar");
+
+  /* This dlopen should indeed fail, because tlsvar was assigned to
+     dynamic TLS, and the new module requests it to be in static TLS.
+     However, there's a possibility that dlopen succeeds if the
+     variable is, for whatever reason, assigned to static TLS, or if
+     the module fails to require static TLS, or even if TLS is not
+     supported.  */
+  h = dlopen ("tst-tlsmod16b.so", RTLD_NOW | RTLD_GLOBAL);
+  if (h == NULL)
+    {
+      return 0;
+    }
+
+  puts ("unexpectedly succeeded to open tst-tlsmod16b.so");
+
+
+  void *(*fp) (void) = (void *(*) (void)) dlsym (h, "in_dso");
+  if (fp == NULL)
+    {
+      puts ("cannot find in_dso");
+      exit (1);
+    }
+
+  /* If the dlopen passes, at least make sure the address returned by
+     dlsym is the same as that returned by the initial-exec access.
+     If the variable was assigned to dynamic TLS during dlsym, this
+     portion will fail.  */
+  if (fp () != p)
+    {
+      puts ("returned values do not match");
+      exit (1);
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/tls/tst-tls17.c b/test/tls/tst-tls17.c
new file mode 100644 (file)
index 0000000..c1bc7d8
--- /dev/null
@@ -0,0 +1,29 @@
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static int
+do_test (void)
+{
+  void *h = dlopen ("tst-tlsmod17b.so", RTLD_LAZY);
+  if (h == NULL)
+    {
+      puts ("unexpectedly failed to open tst-tlsmod17b.so");
+      exit (1);
+    }
+
+  int (*fp) (void) = (int (*) (void)) dlsym (h, "tlsmod17b");
+  if (fp == NULL)
+    {
+      puts ("cannot find tlsmod17b");
+      exit (1);
+    }
+
+  if (fp ())
+    exit (1);
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/tls/tst-tls18.c b/test/tls/tst-tls18.c
new file mode 100644 (file)
index 0000000..00dcdff
--- /dev/null
@@ -0,0 +1,38 @@
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static int
+do_test (void)
+{
+  char modname[sizeof "tst-tlsmod18aXX.so"];
+  void *h[20];
+  for (int i = 0; i < 20; i++)
+    {
+      snprintf (modname, sizeof modname, "tst-tlsmod18a%d.so", i);
+      h[i] = dlopen (modname, RTLD_LAZY);
+      if (h[i] == NULL)
+       {
+         printf ("unexpectedly failed to open %s", modname);
+         exit (1);
+       }
+    }
+
+  for (int i = 0; i < 20; i++)
+    {
+      int (*fp) (void) = (int (*) (void)) dlsym (h[i], "test");
+      if (fp == NULL)
+       {
+         printf ("cannot find test in tst-tlsmod18a%d.so", i);
+         exit (1);
+       }
+
+      if (fp ())
+       exit (1);
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/tls/tst-tls2-static.c b/test/tls/tst-tls2-static.c
new file mode 100644 (file)
index 0000000..55ffa57
--- /dev/null
@@ -0,0 +1 @@
+#include "tst-tls2.c"
diff --git a/test/tls/tst-tls2.c b/test/tls/tst-tls2.c
new file mode 100644 (file)
index 0000000..4174899
--- /dev/null
@@ -0,0 +1,91 @@
+/* glibc test for TLS in ld.so.  */
+#include <stdio.h>
+
+#include <tls.h>
+
+#ifdef USE_TLS
+# include "tls-macros.h"
+
+
+/* Two 'int' variables in TLS.  */
+VAR_INT_DEF(foo);
+VAR_INT_DEF(bar);
+#endif
+
+
+#define TEST_FUNCTION do_test ()
+static int
+do_test (void)
+{
+#ifdef USE_TLS
+  int result = 0;
+  int *ap, *bp;
+
+
+  /* Set the variable using the local exec model.  */
+  puts ("set bar to 1 (LE)");
+  ap = TLS_LE (bar);
+  *ap = 1;
+
+
+  /* Get variables using initial exec model.  */
+  fputs ("get sum of foo and bar (IE)", stdout);
+  ap = TLS_IE (foo);
+  bp = TLS_IE (bar);
+  printf (" = %d\n", *ap + *bp);
+  result |= *ap + *bp != 1;
+  if (*ap != 0)
+    {
+      printf ("foo = %d\n", *ap);
+      result = 1;
+    }
+  if (*bp != 1)
+    {
+      printf ("bar = %d\n", *bp);
+      result = 1;
+    }
+
+
+  /* Get variables using local dynamic model.  */
+  fputs ("get sum of foo and bar (LD)", stdout);
+  ap = TLS_LD (foo);
+  bp = TLS_LD (bar);
+  printf (" = %d\n", *ap + *bp);
+  result |= *ap + *bp != 1;
+  if (*ap != 0)
+    {
+      printf ("foo = %d\n", *ap);
+      result = 1;
+    }
+  if (*bp != 1)
+    {
+      printf ("bar = %d\n", *bp);
+      result = 1;
+    }
+
+
+  /* Get variables using generic dynamic model.  */
+  fputs ("get sum of foo and bar (GD)", stdout);
+  ap = TLS_GD (foo);
+  bp = TLS_GD (bar);
+  printf (" = %d\n", *ap + *bp);
+  result |= *ap + *bp != 1;
+  if (*ap != 0)
+    {
+      printf ("foo = %d\n", *ap);
+      result = 1;
+    }
+  if (*bp != 1)
+    {
+      printf ("bar = %d\n", *bp);
+      result = 1;
+    }
+
+  return result;
+#else
+  return 0;
+#endif
+}
+
+
+#include "../test-skeleton.c"
diff --git a/test/tls/tst-tls3.c b/test/tls/tst-tls3.c
new file mode 100644 (file)
index 0000000..84be435
--- /dev/null
@@ -0,0 +1,76 @@
+/* glibc test for TLS in ld.so.  */
+#include <stdio.h>
+
+#include <tls.h>
+
+#ifdef USE_TLS
+# include "tls-macros.h"
+
+
+/* One define int variable, two externs.  */
+COMMON_INT_DECL(foo);
+VAR_INT_DECL(bar);
+VAR_INT_DEF(baz);
+#endif
+
+
+extern int in_dso (void);
+
+
+#define TEST_FUNCTION do_test ()
+static int
+do_test (void)
+{
+#ifdef USE_TLS
+  int result = 0;
+  int *ap, *bp, *cp;
+
+
+  /* Set the variable using the local exec model.  */
+  puts ("set baz to 3 (LE)");
+  ap = TLS_LE (baz);
+  *ap = 3;
+
+
+  /* Get variables using initial exec model.  */
+  puts ("set variables foo and bar (IE)");
+  ap = TLS_IE (foo);
+  *ap = 1;
+  bp = TLS_IE (bar);
+  *bp = 2;
+
+
+  /* Get variables using local dynamic model.  */
+  fputs ("get sum of foo, bar (GD) and baz (LD)", stdout);
+  ap = TLS_GD (foo);
+  bp = TLS_GD (bar);
+  cp = TLS_LD (baz);
+  printf (" = %d\n", *ap + *bp + *cp);
+  result |= *ap + *bp + *cp != 6;
+  if (*ap != 1)
+    {
+      printf ("foo = %d\n", *ap);
+      result = 1;
+    }
+  if (*bp != 2)
+    {
+      printf ("bar = %d\n", *bp);
+      result = 1;
+    }
+  if (*cp != 3)
+    {
+      printf ("baz = %d\n", *cp);
+      result = 1;
+    }
+
+
+  result |= in_dso ();
+
+  return result;
+#else
+  return 0;
+#endif
+}
+
+
+#include "../test-skeleton.c"
diff --git a/test/tls/tst-tls4.c b/test/tls/tst-tls4.c
new file mode 100644 (file)
index 0000000..f92ee53
--- /dev/null
@@ -0,0 +1,56 @@
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <tls.h>
+
+
+#define TEST_FUNCTION do_test ()
+static int
+do_test (void)
+{
+#ifdef USE_TLS
+  static const char modname[] = "tst-tlsmod2.so";
+  int result = 0;
+  int *foop;
+  int (*fp) (int, int *);
+  void *h;
+
+  h = dlopen (modname, RTLD_LAZY);
+  if (h == NULL)
+    {
+      printf ("cannot open '%s': %s\n", modname, dlerror ());
+      exit (1);
+    }
+
+  fp = dlsym (h, "in_dso");
+  if (fp == NULL)
+    {
+      printf ("cannot get symbol 'in_dso': %s\n", dlerror ());
+      exit (1);
+    }
+
+  result |= fp (0, NULL);
+
+  foop = dlsym (h, "foo");
+  if (foop == NULL)
+    {
+      printf ("cannot get symbol 'foo' the second time: %s\n", dlerror ());
+      exit (1);
+    }
+  if (*foop != 16)
+    {
+      puts ("foo != 16");
+      result = 1;
+    }
+
+  dlclose (h);
+
+  return result;
+#else
+  return 0;
+#endif
+}
+
+
+#include "../test-skeleton.c"
diff --git a/test/tls/tst-tls5.c b/test/tls/tst-tls5.c
new file mode 100644 (file)
index 0000000..a571d2c
--- /dev/null
@@ -0,0 +1,72 @@
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <tls.h>
+
+
+#define TEST_FUNCTION do_test ()
+static int
+do_test (void)
+{
+#ifdef USE_TLS
+  static const char modname[] = "tst-tlsmod2.so";
+  int result = 0;
+  int *foop;
+  int *foop2;
+  int (*fp) (int, int *);
+  void *h;
+
+  h = dlopen (modname, RTLD_LAZY);
+  if (h == NULL)
+    {
+      printf ("cannot open '%s': %s\n", modname, dlerror ());
+      exit (1);
+    }
+
+  foop = dlsym (h, "foo");
+  if (foop == NULL)
+    {
+      printf ("cannot get symbol 'foo': %s\n", dlerror ());
+      exit (1);
+    }
+
+  *foop = 42;
+
+  fp = dlsym (h, "in_dso");
+  if (fp == NULL)
+    {
+      printf ("cannot get symbol 'in_dso': %s\n", dlerror ());
+      exit (1);
+    }
+
+  result |= fp (42, foop);
+
+  foop2 = dlsym (h, "foo");
+  if (foop2 == NULL)
+    {
+      printf ("cannot get symbol 'foo' the second time: %s\n", dlerror ());
+      exit (1);
+    }
+
+  if (foop != foop2)
+    {
+      puts ("address of 'foo' different the second time");
+      result = 1;
+    }
+  else if (*foop != 16)
+    {
+      puts ("foo != 16");
+      result = 1;
+    }
+
+  dlclose (h);
+
+  return result;
+#else
+  return 0;
+#endif
+}
+
+
+#include "../test-skeleton.c"
diff --git a/test/tls/tst-tls6.c b/test/tls/tst-tls6.c
new file mode 100644 (file)
index 0000000..e692aca
--- /dev/null
@@ -0,0 +1,108 @@
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <tls.h>
+#include <link.h>
+#ifdef __UCLIBC__
+#include "dl-elf.h"
+#include "dl-hash.h"
+#endif
+
+
+#define TEST_FUNCTION do_test ()
+static int
+do_test (void)
+{
+#ifdef USE_TLS
+  static const char modname[] = "tst-tlsmod2.so";
+  int result = 0;
+  int *foop;
+  int *foop2;
+  int (*fp) (int, int *);
+  void *h;
+  int i;
+  int modid = -1;
+
+  for (i = 0; i < 10; ++i)
+    {
+      h = dlopen (modname, RTLD_LAZY);
+      if (h == NULL)
+       {
+         printf ("cannot open '%s': %s\n", modname, dlerror ());
+         exit (1);
+       }
+
+      /* Dirty test code here: we peek into a private data structure.
+        We make sure that the module gets assigned the same ID every
+        time.  The value of the first round is used.  */
+#ifdef __UCLIBC__
+      if (modid == -1)
+       modid = ((struct link_map *)((struct dyn_elf *)h)->dyn)->l_tls_modid;
+      else if (((struct link_map *)((struct dyn_elf *)h)->dyn)->l_tls_modid
+        != (size_t) modid)
+       {
+         printf ("round %d: modid now %zu, initially %d\n",
+                 i,
+                 ((struct link_map *)((struct dyn_elf *)h)->dyn)->l_tls_modid,
+                 modid);
+         result = 1;
+       }
+#else
+      if (modid == -1)
+       modid = ((struct link_map *) h)->l_tls_modid;
+      else if (((struct link_map *) h)->l_tls_modid != modid)
+       {
+         printf ("round %d: modid now %zd, initially %d\n",
+                 i, ((struct link_map *) h)->l_tls_modid, modid);
+         result = 1;
+       }
+#endif
+
+      foop = dlsym (h, "foo");
+      if (foop == NULL)
+       {
+         printf ("cannot get symbol 'foo': %s\n", dlerror ());
+         exit (1);
+       }
+
+      *foop = 42 + i;
+
+      fp = dlsym (h, "in_dso");
+      if (fp == NULL)
+       {
+         printf ("cannot get symbol 'in_dso': %s\n", dlerror ());
+         exit (1);
+       }
+
+      result |= fp (42 + i, foop);
+
+      foop2 = dlsym (h, "foo");
+      if (foop2 == NULL)
+       {
+         printf ("cannot get symbol 'foo' the second time: %s\n", dlerror ());
+         exit (1);
+       }
+
+      if (foop != foop2)
+       {
+         puts ("address of 'foo' different the second time");
+         result = 1;
+       }
+      else if (*foop != 16)
+       {
+         puts ("foo != 16");
+         result = 1;
+       }
+
+      dlclose (h);
+    }
+
+  return result;
+#else
+  return 0;
+#endif
+}
+
+
+#include "../test-skeleton.c"
diff --git a/test/tls/tst-tls7.c b/test/tls/tst-tls7.c
new file mode 100644 (file)
index 0000000..41da270
--- /dev/null
@@ -0,0 +1,79 @@
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <tls.h>
+#include <link.h>
+#ifdef __UCLIBC__
+#include "dl-elf.h"
+#include "dl-hash.h"
+#endif
+
+
+#define TEST_FUNCTION do_test ()
+static int
+do_test (void)
+{
+#ifdef USE_TLS
+  static const char modname[] = "tst-tlsmod3.so";
+  int result = 0;
+  int (*fp) (void);
+  void *h;
+  int i;
+  int modid = -1;
+
+  for (i = 0; i < 10; ++i)
+    {
+      h = dlopen (modname, RTLD_LAZY);
+      if (h == NULL)
+       {
+         printf ("cannot open '%s': %s\n", modname, dlerror ());
+         exit (1);
+       }
+
+      /* Dirty test code here: we peek into a private data structure.
+        We make sure that the module gets assigned the same ID every
+        time.  The value of the first round is used.  */
+#ifdef __UCLIBC__
+      if (modid == -1)
+       modid = ((struct link_map *)((struct dyn_elf *)h)->dyn)->l_tls_modid;
+      else if (((struct link_map *)((struct dyn_elf *)h)->dyn)->l_tls_modid
+        != (size_t) modid)
+       {
+         printf ("round %d: modid now %zu, initially %d\n",
+                 i,
+                 ((struct link_map *)((struct dyn_elf *)h)->dyn)->l_tls_modid,
+                 modid);
+         result = 1;
+       }
+#else
+      if (modid == -1)
+       modid = ((struct link_map *) h)->l_tls_modid;
+      else if (((struct link_map *) h)->l_tls_modid != (size_t) modid)
+       {
+         printf ("round %d: modid now %zu, initially %d\n",
+                 i, ((struct link_map *) h)->l_tls_modid, modid);
+         result = 1;
+       }
+#endif
+
+      fp = dlsym (h, "in_dso2");
+      if (fp == NULL)
+       {
+         printf ("cannot get symbol 'in_dso2': %s\n", dlerror ());
+         exit (1);
+       }
+
+      result |= fp ();
+
+      dlclose (h);
+    }
+
+  return result;
+#else
+  return 0;
+#endif
+}
+
+
+#include "../test-skeleton.c"
diff --git a/test/tls/tst-tls8.c b/test/tls/tst-tls8.c
new file mode 100644 (file)
index 0000000..2541609
--- /dev/null
@@ -0,0 +1,230 @@
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <tls.h>
+#include <link.h>
+#ifdef __UCLIBC__
+#include "dl-elf.h"
+#include "dl-hash.h"
+#endif
+
+
+#define TEST_FUNCTION do_test ()
+static int
+do_test (void)
+{
+#ifdef USE_TLS
+  static const char modname1[] = "tst-tlsmod3.so";
+  static const char modname2[] = "tst-tlsmod4.so";
+  int result = 0;
+  int (*fp1) (void);
+  int (*fp2) (int, int *);
+  void *h1;
+  void *h2;
+  int i;
+  size_t modid1 = (size_t) -1;
+  size_t modid2 = (size_t) -1;
+  int *bazp;
+
+  for (i = 0; i < 10; ++i)
+    {
+      h1 = dlopen (modname1, RTLD_LAZY);
+      if (h1 == NULL)
+       {
+         printf ("cannot open '%s': %s\n", modname1, dlerror ());
+         exit (1);
+       }
+
+      /* Dirty test code here: we peek into a private data structure.
+        We make sure that the module gets assigned the same ID every
+        time.  The value of the first round is used.  */
+#ifdef __UCLIBC__
+      if (modid1 == (size_t) -1)
+       modid1 = ((struct link_map *)((struct dyn_elf *)h1)->dyn)->l_tls_modid;
+      else if (((struct link_map *)((struct dyn_elf *)h1)->dyn)->l_tls_modid
+        != (size_t) modid1)
+       {
+         printf ("round %d: modid now %zd, initially %zd\n",
+                 i,
+                 ((struct link_map *)((struct dyn_elf *)h1)->dyn)->l_tls_modid,
+                 modid1);
+         result = 1;
+       }
+#else
+      if (modid1 == (size_t) -1)
+       modid1 = ((struct link_map *) h1)->l_tls_modid;
+      else if (((struct link_map *) h1)->l_tls_modid != modid1)
+       {
+         printf ("round %d: modid now %zd, initially %zd\n",
+                 i, ((struct link_map *) h1)->l_tls_modid, modid1);
+         result = 1;
+       }
+#endif
+
+      fp1 = dlsym (h1, "in_dso2");
+      if (fp1 == NULL)
+       {
+         printf ("cannot get symbol 'in_dso2' in %s\n", modname1);
+         exit (1);
+       }
+
+      result |= fp1 ();
+
+
+
+      h2 = dlopen (modname2, RTLD_LAZY);
+      if (h2 == NULL)
+       {
+         printf ("cannot open '%s': %s\n", modname2, dlerror ());
+         exit (1);
+       }
+
+      /* Dirty test code here: we peek into a private data structure.
+        We make sure that the module gets assigned the same ID every
+        time.  The value of the first round is used.  */
+#ifdef __UCLIBC__
+      if (modid2 == (size_t) -1)
+       modid2 = ((struct link_map *)((struct dyn_elf *)h1)->dyn)->l_tls_modid;
+      else if (((struct link_map *)((struct dyn_elf *)h1)->dyn)->l_tls_modid
+        != (size_t) modid2)
+       {
+         printf ("round %d: modid now %zd, initially %zd\n",
+                 i,
+                 ((struct link_map *)((struct dyn_elf *)h1)->dyn)->l_tls_modid,
+                 modid2);
+         result = 1;
+       }
+#else
+      if (modid2 == (size_t) -1)
+       modid2 = ((struct link_map *) h1)->l_tls_modid;
+      else if (((struct link_map *) h1)->l_tls_modid != modid2)
+       {
+         printf ("round %d: modid now %zd, initially %zd\n",
+                 i, ((struct link_map *) h1)->l_tls_modid, modid2);
+         result = 1;
+       }
+#endif
+
+      bazp = dlsym (h2, "baz");
+      if (bazp == NULL)
+       {
+         printf ("cannot get symbol 'baz' in %s\n", modname2);
+         exit (1);
+       }
+
+      *bazp = 42 + i;
+
+      fp2 = dlsym (h2, "in_dso");
+      if (fp2 == NULL)
+       {
+         printf ("cannot get symbol 'in_dso' in %s\n", modname2);
+         exit (1);
+       }
+
+      result |= fp2 (42 + i, bazp);
+
+      dlclose (h1);
+      dlclose (h2);
+
+
+      h1 = dlopen (modname1, RTLD_LAZY);
+      if (h1 == NULL)
+       {
+         printf ("cannot open '%s': %s\n", modname1, dlerror ());
+         exit (1);
+       }
+
+      /* Dirty test code here: we peek into a private data structure.
+        We make sure that the module gets assigned the same ID every
+        time.  The value of the first round is used.  */
+#ifdef __UCLIBC__
+      if (((struct link_map *)((struct dyn_elf *)h1)->dyn)->l_tls_modid
+        != modid1)
+       {
+         printf ("round %d: modid now %zd, initially %zd\n",
+                 i,
+                 ((struct link_map *)((struct dyn_elf *)h1)->dyn)->l_tls_modid,
+                 modid1);
+         result = 1;
+       }
+#else
+      if (((struct link_map *) h1)->l_tls_modid != modid1)
+       {
+         printf ("round %d: modid now %zd, initially %zd\n",
+                 i, ((struct link_map *) h1)->l_tls_modid, modid1);
+         result = 1;
+       }
+#endif
+
+      fp1 = dlsym (h1, "in_dso2");
+      if (fp1 == NULL)
+       {
+         printf ("cannot get symbol 'in_dso2' in %s\n", modname1);
+         exit (1);
+       }
+
+      result |= fp1 ();
+
+
+
+      h2 = dlopen (modname2, RTLD_LAZY);
+      if (h2 == NULL)
+       {
+         printf ("cannot open '%s': %s\n", modname2, dlerror ());
+         exit (1);
+       }
+
+      /* Dirty test code here: we peek into a private data structure.
+        We make sure that the module gets assigned the same ID every
+        time.  The value of the first round is used.  */
+#ifdef __UCLIBC__
+      if (((struct link_map *)((struct dyn_elf *)h1)->dyn)->l_tls_modid
+        != modid2)
+       {
+         printf ("round %d: modid now %zd, initially %zd\n",
+                 i,
+                 ((struct link_map *)((struct dyn_elf *)h1)->dyn)->l_tls_modid,
+                 modid2);
+         result = 1;
+       }
+#else
+      if (((struct link_map *) h1)->l_tls_modid != modid2)
+       {
+         printf ("round %d: modid now %zd, initially %zd\n",
+                 i, ((struct link_map *) h1)->l_tls_modid, modid2);
+         result = 1;
+       }
+#endif
+
+      bazp = dlsym (h2, "baz");
+      if (bazp == NULL)
+       {
+         printf ("cannot get symbol 'baz' in %s\n", modname2);
+         exit (1);
+       }
+
+      *bazp = 62 + i;
+
+      fp2 = dlsym (h2, "in_dso");
+      if (fp2 == NULL)
+       {
+         printf ("cannot get symbol 'in_dso' in %s\n", modname2);
+         exit (1);
+       }
+
+      result |= fp2 (62 + i, bazp);
+
+      /* This time the dlclose calls are in reverse order.  */
+      dlclose (h2);
+      dlclose (h1);
+    }
+
+  return result;
+#else
+  return 0;
+#endif
+}
+
+
+#include "../test-skeleton.c"
diff --git a/test/tls/tst-tls9-static.c b/test/tls/tst-tls9-static.c
new file mode 100644 (file)
index 0000000..51812cc
--- /dev/null
@@ -0,0 +1 @@
+#include "tst-tls9.c"
diff --git a/test/tls/tst-tls9.c b/test/tls/tst-tls9.c
new file mode 100644 (file)
index 0000000..e317696
--- /dev/null
@@ -0,0 +1,42 @@
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <link.h>
+#include <tls.h>
+
+#define TEST_FUNCTION do_test ()
+static int
+do_test (void)
+{
+#ifdef USE_TLS
+  static const char modname1[] = "tst-tlsmod5.so";
+  static const char modname2[] = "tst-tlsmod6.so";
+  int result = 0;
+
+  void *h1 = dlopen (modname1, RTLD_LAZY);
+  if (h1 == NULL)
+    {
+      printf ("cannot open '%s': %s\n", modname1, dlerror ());
+      result = 1;
+    }
+  void *h2 = dlopen (modname2, RTLD_LAZY);
+  if (h2 == NULL)
+    {
+      printf ("cannot open '%s': %s\n", modname2, dlerror ());
+      result = 1;
+    }
+
+  if (h1 != NULL)
+    dlclose (h1);
+  if (h2 != NULL)
+    dlclose (h2);
+
+  return result;
+#else
+  return 0;
+#endif
+}
+
+
+#include "../test-skeleton.c"
diff --git a/test/tls/tst-tlsmod-at-ctor.c b/test/tls/tst-tlsmod-at-ctor.c
new file mode 100644 (file)
index 0000000..bd04b50
--- /dev/null
@@ -0,0 +1,25 @@
+#include <stdio.h>
+#include <tls.h>
+
+#define TLS_VAR_INIT_VALUE 99
+
+#ifdef USE_TLS
+__thread int tls_var  __attribute__((tls_model("global-dynamic")));
+static __thread int local_tls_var __attribute__((tls_model("local-dynamic")));
+#endif
+
+void __attribute__((constructor)) libtls_ctor(void);
+void libtls_ctor(void)
+{
+       printf("libtls: constructor!\n");
+#ifdef USE_TLS
+       local_tls_var = TLS_VAR_INIT_VALUE;
+       tls_var = local_tls_var;
+#endif
+}
+
+void __attribute__((destructor)) libtls_dtor(void);
+void libtls_dtor(void)
+{
+       printf("libtls: destructor!\n");
+}
diff --git a/test/tls/tst-tlsmod1.c b/test/tls/tst-tlsmod1.c
new file mode 100644 (file)
index 0000000..b4954ca
--- /dev/null
@@ -0,0 +1,68 @@
+#include <stdio.h>
+
+#include <tls.h>
+
+#ifdef USE_TLS
+#include "tls-macros.h"
+
+
+/* One define int variable, two externs.  */
+COMMON_INT_DEF(foo);
+VAR_INT_DEF(bar);
+VAR_INT_DECL(baz);
+#endif
+
+extern int in_dso (void);
+
+int
+in_dso (void)
+{
+  int result = 0;
+#ifdef USE_TLS
+  int *ap, *bp, *cp;
+
+  /* Get variables using initial exec model.  */
+  fputs ("get sum of foo and bar (IE)", stdout);
+  __asm__ ("" ::: "memory");
+  ap = TLS_IE (foo);
+  bp = TLS_IE (bar);
+  printf (" = %d\n", *ap + *bp);
+  result |= *ap + *bp != 3;
+  if (*ap != 1)
+    {
+      printf ("foo = %d\n", *ap);
+      result = 1;
+    }
+  if (*bp != 2)
+    {
+      printf ("bar = %d\n", *bp);
+      result = 1;
+    }
+
+
+  /* Get variables using generic dynamic model.  */
+  fputs ("get sum of foo and bar and baz (GD)", stdout);
+  ap = TLS_GD (foo);
+  bp = TLS_GD (bar);
+  cp = TLS_GD (baz);
+  printf (" = %d\n", *ap + *bp + *cp);
+  result |= *ap + *bp + *cp != 6;
+  if (*ap != 1)
+    {
+      printf ("foo = %d\n", *ap);
+      result = 1;
+    }
+  if (*bp != 2)
+    {
+      printf ("bar = %d\n", *bp);
+      result = 1;
+    }
+  if (*cp != 3)
+    {
+      printf ("baz = %d\n", *cp);
+      result = 1;
+    }
+#endif
+
+  return result;
+}
diff --git a/test/tls/tst-tlsmod10.c b/test/tls/tst-tlsmod10.c
new file mode 100644 (file)
index 0000000..32e54f3
--- /dev/null
@@ -0,0 +1 @@
+#include "tst-tlsmod8.c"
diff --git a/test/tls/tst-tlsmod11.c b/test/tls/tst-tlsmod11.c
new file mode 100644 (file)
index 0000000..9938b57
--- /dev/null
@@ -0,0 +1,6 @@
+#include "tst-tls10.h"
+
+#ifdef USE_TLS__THREAD
+__thread struct A a1 = { 4, 5, 6 };
+__thread struct A a2 = { 7, 8, 9 };
+#endif
diff --git a/test/tls/tst-tlsmod12.c b/test/tls/tst-tlsmod12.c
new file mode 100644 (file)
index 0000000..4602709
--- /dev/null
@@ -0,0 +1,14 @@
+#include "tst-tls10.h"
+
+#ifdef USE_TLS__THREAD
+extern __thread struct A a2 __attribute__((tls_model("initial-exec")));
+
+void
+check1 (void)
+{
+  if (a1.a != 4 || a1.b != 5 || a1.c != 6)
+    abort ();
+  if (a2.a != 7 || a2.b != 8 || a2.c != 9)
+    abort ();
+}
+#endif
diff --git a/test/tls/tst-tlsmod13.c b/test/tls/tst-tlsmod13.c
new file mode 100644 (file)
index 0000000..beca89f
--- /dev/null
@@ -0,0 +1,14 @@
+#include <tls.h>
+
+#if defined USE_TLS && defined HAVE___THREAD \
+    && defined HAVE_TLS_MODEL_ATTRIBUTE
+__thread int a[2] __attribute__ ((tls_model ("initial-exec")));
+#else
+int a[2];
+#endif
+
+int
+foo (void)
+{
+  return a[0];
+}
diff --git a/test/tls/tst-tlsmod13a.c b/test/tls/tst-tlsmod13a.c
new file mode 100644 (file)
index 0000000..14b12b0
--- /dev/null
@@ -0,0 +1,16 @@
+#include <tls.h>
+
+#if defined USE_TLS && defined HAVE___THREAD \
+    && defined HAVE_TLS_MODEL_ATTRIBUTE
+__thread int b[2] __attribute__ ((tls_model ("initial-exec")));
+#else
+int b[2];
+#endif
+
+extern int foo (void);
+
+int
+bar (void)
+{
+  return foo () + b[0];
+}
diff --git a/test/tls/tst-tlsmod14a.c b/test/tls/tst-tlsmod14a.c
new file mode 100644 (file)
index 0000000..0bb393d
--- /dev/null
@@ -0,0 +1,41 @@
+#include <stdint.h>
+#include <stdio.h>
+
+#include <tls.h>
+
+#if USE_TLS && HAVE___THREAD
+
+#define AL 4096
+struct foo
+{
+  int i;
+} __attribute ((aligned (AL)));
+
+static __thread struct foo f;
+static struct foo g;
+
+
+#ifndef FCT
+# define FCT in_dso1
+#endif
+
+
+int
+FCT (void)
+{
+  puts (__func__);
+
+  int result = 0;
+
+  int fail = (((uintptr_t) &f) & (AL - 1)) != 0;
+  printf ("&f = %p %s\n", &f, fail ? "FAIL" : "OK");
+  result |= fail;
+
+  fail = (((uintptr_t) &g) & (AL - 1)) != 0;
+  printf ("&g = %p %s\n", &g, fail ? "FAIL" : "OK");
+  result |= fail;
+
+  return result;
+}
+
+#endif
diff --git a/test/tls/tst-tlsmod14b.c b/test/tls/tst-tlsmod14b.c
new file mode 100644 (file)
index 0000000..24d9cea
--- /dev/null
@@ -0,0 +1,2 @@
+#define FCT in_dso2
+#include "tst-tlsmod14a.c"
diff --git a/test/tls/tst-tlsmod15a.c b/test/tls/tst-tlsmod15a.c
new file mode 100644 (file)
index 0000000..66c7071
--- /dev/null
@@ -0,0 +1,6 @@
+extern int nonexistent_dummy_var;
+int *
+foo (void)
+{
+  return &nonexistent_dummy_var;
+}
diff --git a/test/tls/tst-tlsmod15b.c b/test/tls/tst-tlsmod15b.c
new file mode 100644 (file)
index 0000000..4f63eab
--- /dev/null
@@ -0,0 +1,17 @@
+#include "tst-tls10.h"
+
+#ifdef USE_TLS__THREAD
+__thread int mod15b_var __attribute__((tls_model("initial-exec")));
+
+int
+in_dso (void)
+{
+  return mod15b_var;
+}
+#else
+int
+in_dso (void)
+{
+  return 0;
+}
+#endif
diff --git a/test/tls/tst-tlsmod16a.c b/test/tls/tst-tlsmod16a.c
new file mode 100644 (file)
index 0000000..847c809
--- /dev/null
@@ -0,0 +1,7 @@
+#include <tls.h>
+
+#if defined HAVE___THREAD && defined HAVE_TLS_MODEL_ATTRIBUTE
+int __thread tlsvar;
+#else
+int tlsvar;
+#endif
diff --git a/test/tls/tst-tlsmod16b.c b/test/tls/tst-tlsmod16b.c
new file mode 100644 (file)
index 0000000..308e6ba
--- /dev/null
@@ -0,0 +1,13 @@
+#include <tls.h>
+
+#if defined HAVE___THREAD && defined HAVE_TLS_MODEL_ATTRIBUTE
+extern __thread int tlsvar __attribute__((tls_model("initial-exec")));
+#else
+extern int tlsvar;
+#endif
+
+void *
+in_dso (void)
+{
+  return &tlsvar;
+}
diff --git a/test/tls/tst-tlsmod17a.c b/test/tls/tst-tlsmod17a.c
new file mode 100644 (file)
index 0000000..eb599e7
--- /dev/null
@@ -0,0 +1,23 @@
+#include <stdio.h>
+
+#ifndef N
+#define N 0
+#endif
+#define CONCAT1(s, n) s##n
+#define CONCAT(s, n) CONCAT1(s, n)
+
+__thread int CONCAT (v, N) = 4;
+
+int
+CONCAT (tlsmod17a, N) (void)
+{
+  int *p = &CONCAT (v, N);
+  /* GCC assumes &var is never NULL, add optimization barrier.  */
+  __asm __volatile ("" : "+r" (p));
+  if (p == NULL || *p != 4)
+    {
+      printf ("fail %d %p\n", N, p);
+      return 1;
+    }
+  return 0;
+}
diff --git a/test/tls/tst-tlsmod17b.c b/test/tls/tst-tlsmod17b.c
new file mode 100644 (file)
index 0000000..6178828
--- /dev/null
@@ -0,0 +1,15 @@
+#define P(N) extern int tlsmod17a##N (void);
+#define PS P(0) P(1) P(2) P(3) P(4) P(5) P(6) P(7) P(8) P(9) \
+          P(10) P(12) P(13) P(14) P(15) P(16) P(17) P(18) P(19)
+PS
+#undef P
+
+int
+tlsmod17b (void)
+{
+  int res = 0;
+#define P(N) res |= tlsmod17a##N ();
+  PS
+#undef P
+  return res;
+}
diff --git a/test/tls/tst-tlsmod18a.c b/test/tls/tst-tlsmod18a.c
new file mode 100644 (file)
index 0000000..9aba607
--- /dev/null
@@ -0,0 +1,21 @@
+#include <stdio.h>
+
+#ifndef N
+# define N 0
+#endif
+
+static __thread int var = 4;
+
+int
+test (void)
+{
+  int *p = &var;
+  /* GCC assumes &var is never NULL, add optimization barrier.  */
+  __asm __volatile ("" : "+r" (p));
+  if (p == NULL || *p != 4)
+    {
+      printf ("fail %d %p\n", N, p);
+      return 1;
+    }
+  return 0;
+}
diff --git a/test/tls/tst-tlsmod2.c b/test/tls/tst-tlsmod2.c
new file mode 100644 (file)
index 0000000..4547c97
--- /dev/null
@@ -0,0 +1,38 @@
+#include <stdio.h>
+
+#include <tls.h>
+
+#ifdef USE_TLS
+#include "tls-macros.h"
+
+
+COMMON_INT_DEF(foo);
+
+
+int
+in_dso (int n, int *caller_foop)
+{
+  int *foop;
+  int result = 0;
+
+  puts ("foo");                        /* Make sure PLT is used before macros.  */
+  __asm__ ("" ::: "memory");
+
+  foop = TLS_GD (foo);
+
+  if (caller_foop != NULL && foop != caller_foop)
+    {
+      printf ("callers address of foo differs: %p vs %p\n", caller_foop, foop);
+      result = 1;
+    }
+  else if (*foop != n)
+    {
+      printf ("foo != %d\n", n);
+      result = 1;
+    }
+
+  *foop = 16;
+
+  return result;
+}
+#endif
diff --git a/test/tls/tst-tlsmod3.c b/test/tls/tst-tlsmod3.c
new file mode 100644 (file)
index 0000000..12505f6
--- /dev/null
@@ -0,0 +1,41 @@
+#include <stdio.h>
+
+#include <tls.h>
+
+#ifdef USE_TLS
+# include "tls-macros.h"
+
+extern int in_dso (int n, int *caller_foop);
+
+COMMON_INT_DEF(comm_n);
+
+
+
+
+int
+in_dso2 (void)
+{
+  int *foop;
+  int result = 0;
+  static int n;
+  int *np;
+
+  puts ("foo");                        /* Make sure PLT is used before macros.  */
+  __asm__ ("" ::: "memory");
+
+  foop = TLS_GD (foo);
+  np = TLS_GD (comm_n);
+
+  if (n != *np)
+    {
+      printf ("n = %d != comm_n = %d\n", n, *np);
+      result = 1;
+    }
+
+  result |= in_dso (*foop = 42 + n++, foop);
+
+  *foop = 16;
+
+  return result;
+}
+#endif
diff --git a/test/tls/tst-tlsmod4.c b/test/tls/tst-tlsmod4.c
new file mode 100644 (file)
index 0000000..4893cda
--- /dev/null
@@ -0,0 +1,38 @@
+#include <stdio.h>
+
+#include <tls.h>
+
+#ifdef USE_TLS
+# include "tls-macros.h"
+
+
+COMMON_INT_DEF(baz);
+
+
+int
+in_dso (int n, int *caller_bazp)
+{
+  int *bazp;
+  int result = 0;
+
+  puts ("foo");                        /* Make sure PLT is used before macros.  */
+  __asm__ ("" ::: "memory");
+
+  bazp = TLS_GD (baz);
+
+  if (caller_bazp != NULL && bazp != caller_bazp)
+    {
+      printf ("callers address of baz differs: %p vs %p\n", caller_bazp, bazp);
+      result = 1;
+    }
+  else if (*bazp != n)
+    {
+      printf ("baz != %d\n", n);
+      result = 1;
+    }
+
+  *bazp = 16;
+
+  return result;
+}
+#endif
diff --git a/test/tls/tst-tlsmod5.c b/test/tls/tst-tlsmod5.c
new file mode 100644 (file)
index 0000000..2ec69e1
--- /dev/null
@@ -0,0 +1,7 @@
+#include <tls.h>
+
+#ifdef USE_TLS
+#include "tls-macros.h"
+
+COMMON_INT_DEF(foo);
+#endif
diff --git a/test/tls/tst-tlsmod6.c b/test/tls/tst-tlsmod6.c
new file mode 100644 (file)
index 0000000..0fda51b
--- /dev/null
@@ -0,0 +1,7 @@
+#include <tls.h>
+
+#ifdef USE_TLS
+#include "tls-macros.h"
+
+COMMON_INT_DEF(bar);
+#endif
diff --git a/test/tls/tst-tlsmod7.c b/test/tls/tst-tlsmod7.c
new file mode 100644 (file)
index 0000000..944b97f
--- /dev/null
@@ -0,0 +1,103 @@
+#include "tst-tls10.h"
+
+#ifdef USE_TLS__THREAD
+__thread int dummy __attribute__((visibility ("hidden"))) = 12;
+__thread struct A a1 = { 4, 5, 6 };
+__thread struct A a2 = { 7, 8, 9 };
+__thread struct A a3 __attribute__((tls_model("initial-exec")))
+  = { 10, 11, 12 };
+__thread struct A a4 __attribute__((tls_model("initial-exec")))
+  = { 13, 14, 15 };
+static __thread struct A local1 = { 16, 17, 18 };
+static __thread struct A local2 __attribute__((tls_model("initial-exec")))
+  = { 19, 20, 21 };
+
+void
+check1 (void)
+{
+  if (a1.a != 4 || a1.b != 5 || a1.c != 6)
+    abort ();
+  if (a2.a != 22 || a2.b != 23 || a2.c != 24)
+    abort ();
+  if (a3.a != 10 || a3.b != 11 || a3.c != 12)
+    abort ();
+  if (a4.a != 25 || a4.b != 26 || a4.c != 27)
+    abort ();
+  if (local1.a != 16 || local1.b != 17 || local1.c != 18)
+    abort ();
+  if (local2.a != 19 || local2.b != 20 || local2.c != 21)
+    abort ();
+}
+
+struct A *
+f1a (void)
+{
+  return &a1;
+}
+
+struct A *
+f2a (void)
+{
+  return &a2;
+}
+
+struct A *
+f3a (void)
+{
+  return &a3;
+}
+
+struct A *
+f4a (void)
+{
+  return &a4;
+}
+
+struct A *
+f5a (void)
+{
+  return &local1;
+}
+
+struct A *
+f6a (void)
+{
+  return &local2;
+}
+
+int
+f1b (void)
+{
+  return a1.a;
+}
+
+int
+f2b (void)
+{
+  return a2.b;
+}
+
+int
+f3b (void)
+{
+  return a3.c;
+}
+
+int
+f4b (void)
+{
+  return a4.a;
+}
+
+int
+f5b (void)
+{
+  return local1.b;
+}
+
+int
+f6b (void)
+{
+  return local2.c;
+}
+#endif
diff --git a/test/tls/tst-tlsmod8.c b/test/tls/tst-tlsmod8.c
new file mode 100644 (file)
index 0000000..c1822fc
--- /dev/null
@@ -0,0 +1,72 @@
+#include "tst-tls10.h"
+
+#ifdef USE_TLS__THREAD
+__thread long long dummy __attribute__((visibility ("hidden"))) = 12;
+__thread struct A a2 = { 22, 23, 24 };
+__thread struct A a4 __attribute__((tls_model("initial-exec")))
+  = { 25, 26, 27 };
+static __thread struct A local1 = { 28, 29, 30 };
+static __thread struct A local2 __attribute__((tls_model("initial-exec")))
+  = { 31, 32, 33 };
+
+void
+check2 (void)
+{
+  if (a2.a != 22 || a2.b != 23 || a2.c != 24)
+    abort ();
+  if (a4.a != 25 || a4.b != 26 || a4.c != 27)
+    abort ();
+  if (local1.a != 28 || local1.b != 29 || local1.c != 30)
+    abort ();
+  if (local2.a != 31 || local2.b != 32 || local2.c != 33)
+    abort ();
+}
+
+struct A *
+f7a (void)
+{
+  return &a2;
+}
+
+struct A *
+f8a (void)
+{
+  return &a4;
+}
+
+struct A *
+f9a (void)
+{
+  return &local1;
+}
+
+struct A *
+f10a (void)
+{
+  return &local2;
+}
+
+int
+f7b (void)
+{
+  return a2.b;
+}
+
+int
+f8b (void)
+{
+  return a4.a;
+}
+
+int
+f9b (void)
+{
+  return local1.b;
+}
+
+int
+f10b (void)
+{
+  return local2.c;
+}
+#endif
diff --git a/test/tls/tst-tlsmod9.c b/test/tls/tst-tlsmod9.c
new file mode 100644 (file)
index 0000000..e124144
--- /dev/null
@@ -0,0 +1,101 @@
+#include "tst-tls10.h"
+
+#ifdef USE_TLS__THREAD
+__thread int dummy __attribute__((visibility ("hidden"))) = 12;
+__thread struct A a1 = { 4, 5, 6 };
+__thread struct A a3 __attribute__((tls_model("initial-exec")))
+  = { 10, 11, 12 };
+extern __thread struct A a4 __attribute__((tls_model("initial-exec")));
+static __thread struct A local1 = { 16, 17, 18 };
+static __thread struct A local2 __attribute__((tls_model("initial-exec")))
+  = { 19, 20, 21 };
+
+void
+check1 (void)
+{
+  if (a1.a != 4 || a1.b != 5 || a1.c != 6)
+    abort ();
+  if (a2.a != 22 || a2.b != 23 || a2.c != 24)
+    abort ();
+  if (a3.a != 10 || a3.b != 11 || a3.c != 12)
+    abort ();
+  if (a4.a != 25 || a4.b != 26 || a4.c != 27)
+    abort ();
+  if (local1.a != 16 || local1.b != 17 || local1.c != 18)
+    abort ();
+  if (local2.a != 19 || local2.b != 20 || local2.c != 21)
+    abort ();
+}
+
+struct A *
+f1a (void)
+{
+  return &a1;
+}
+
+struct A *
+f2a (void)
+{
+  return &a2;
+}
+
+struct A *
+f3a (void)
+{
+  return &a3;
+}
+
+struct A *
+f4a (void)
+{
+  return &a4;
+}
+
+struct A *
+f5a (void)
+{
+  return &local1;
+}
+
+struct A *
+f6a (void)
+{
+  return &local2;
+}
+
+int
+f1b (void)
+{
+  return a1.a;
+}
+
+int
+f2b (void)
+{
+  return a2.b;
+}
+
+int
+f3b (void)
+{
+  return a3.c;
+}
+
+int
+f4b (void)
+{
+  return a4.a;
+}
+
+int
+f5b (void)
+{
+  return local1.b;
+}
+
+int
+f6b (void)
+{
+  return local2.c;
+}
+#endif
index 5b2ee47..7cdfa90 100644 (file)
@@ -8,3 +8,5 @@ ldd
 ldd.host
 locale
 locale.host
+getconf
+getconf.host