⚝
One Hat Cyber Team
⚝
Your IP:
216.73.216.184
Server IP:
65.21.180.239
Server:
Linux gowhm.eplangoweb.com 5.4.0-216-generic #236-Ubuntu SMP Fri Apr 11 19:53:21 UTC 2025 x86_64
Server Software:
Apache
PHP Version:
8.0.30
Buat File
|
Buat Folder
Eksekusi
Dir :
~
/
usr
/
src
/
glibc
/
debian
/
patches
/
kfreebsd
/
Edit File: local-fbtl.diff
--- /dev/null +++ b/fbtl/ANNOUNCE @@ -0,0 +1,92 @@ +Now that the Linux kernel is once again able to run all the tests we +have and since glibc 2.3 was released it was time for a new code drop. +I've uploaded the second code drop for the Native POSIX Thread +Library: + + ftp://people.redhat.com/drepper/nptl/nptl-0.2.tar.bz2 + +You need + +- the latest of Linus' kernel from BitKeeper (or 2.5.41 when it + is released); + +- glibc 2.3 + +- the very latest in tools such as + + + gcc either from the current development branch or the gcc 3.2 + from Red Hat Linux 8; + + + binutils preferrably from CVS, from H.J. Lu's latest release for + Linux, or from RHL 8. + + +Compiling glibc should proceed smoothly. But there are a number of +tests which fail, mostly because some functionality is missing in +glibc. Ignore those errors. It is only important that all tests in +nptl/ are passing. Run + + make subdirs=nptl check + +to run all thread tests. + + +This version features several improvements: + +- all APIs are now implemented; + +- fork handling has been improved; stacks in the child are freed; + atfork handlers are removed if they were registered from a module + which gets unloaded. + +- pthread_tryjoin_np and pthread_timedjoin_np are implemented + +- TSD handling corrected and optimized. + +- many more tests which also test the underlying kernel implementation. + +- the build infrastructure has been implemented so that the DSO and + archives are built in usable form and with correct named. + +- libthread_db has been implemented. This is the library which is + needed by all program which need to get access to internals of + libpthread (mainly debuggers). + +- the CPU clock functions are implemented + + + +The white paper hasn't yet been updated. It's still available at + + http://people.redhat.com/drepper/nptl-design.pdf + + +This release should be ready for some serious testing. I know it is +hard to compile which I why I'm looking into providing binary RPMs. +They can be used on non-critical systems. I'll only be able to +provide binaries for RHL8 based systems, though, and the kernel still +must be installed separately. + + +The next steps will include: + +- write more tests and fix the bugs which are discovered this way + +- update the white paper + +- write and run more performance tests + +- port to IA-64 + + +Interested parties are once again invited to join the mailing we +created: + + + phil-list@redhat.com + +Go to + + https://listman.redhat.com/mailman/listinfo/phil-list + +to subscribe, unsubscribe, or review the archive. --- /dev/null +++ b/fbtl/Banner @@ -0,0 +1 @@ +Native POSIX Threads Library by Ulrich Drepper et al --- /dev/null +++ b/fbtl/ChangeLog @@ -0,0 +1,12903 @@ +2013-06-24 Vladimir Nikulichev <v.nikulichev@gmail.com> + + [BZ #12310] + * pthread_exit.c: Add reference to pthread_create. + +2013-06-22 Joseph Myers <joseph@codesourcery.com> + + * pthread_getattr_default_np.c: Include <string.h>. + +2013-06-15 Siddhesh Poyarekar <siddhesh@redhat.com> + + * Versions (libpthread): Add GLIBC_2.18. + (GLIBC_2.18): Add pthread_setattr_default_np and + pthread_getattr_default_np. + * allocatestack.c (allocate_stack): Synchronize read from + __default_pthread_attr. + (__reclaim_stacks): Initialize __default_pthread_attr_lock. + * nptl-init.c (__pthread_initialize_minimal_internal): + Synchronize write to __default_pthread_attr. + * pthreadP.h (__default_pthread_attr_lock): Declare. + * pthread_attr_getstacksize (__pthread_attr_getstacksize): + Synchronize read from __default_pthread_attr. + * pthread_create.c (__pthread_create_2_1): Make a local copy of + __default_pthread_attr. Check value of flags in IATTR even if + input ATTR is NULL. + * pthread_getattr_default_np.c: New file. + * pthread_setattr_default_np.c: New file. + * sysdeps/pthread/pthread.h [__USE_GNU] + (pthread_getattr_default_np, pthread_setattr_default_np): + Declare. + * tst-default-attr.c: New test case. + * Makefile (libpthread-routines): Add + pthread_setattr_default_np and pthread_getattr_default_np. + (tests): Add tst-default-attr. + * vars.c (__default_pthread_attr_lock): Declare and initialize. + +2013-06-13 Siddhesh Poyarekar <siddhesh@redhat.com> + Carlos O'Donell <carlos@redhat.com> + + [BZ #15618] + * tst-pthread-attr-affinity: New test case. + * Makefile (tests): Add it. + * sysdeps/unix/sysv/linux/pthread_attr_getaffinity.c + (__pthread_attr_getaffinity_new): Copy minimum of source and + destination sizes to avoid a buffer overrun. + +2013-06-10 Carlos O'Donell <carlos@redhat.com> + + * sysdeps/unix/sysv/linux/i386/lowlevellock.h + (lll_futex_wake): Return syscall error. + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h + (lll_futex_wake): Return syscall error. + +2013-08-06 Ondřej Bílka <neleai@seznam.cz> + + * sysdeps/pthread/allocalim.h: (__libc_use_alloca): Fix warning. + +2013-06-06 Ondřej Bílka <neleai@seznam.cz> + + * tst-cond22.c: Fix leading whitespaces. + * tst-umask1.c: Likewise. + +2013-06-06 Joseph Myers <joseph@codesourcery.com> + + * sysdeps/unix/sysv/linux/i386/i486/pthread_barrier_wait.S: Remove + trailing whitespace. + * sysdeps/unix/sysv/linux/powerpc/pt-longjmp.c: Likewise. + * sysdeps/unix/sysv/linux/sh/lowlevellock.h: Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_barrier_wait.S: Likewise. + * 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_once.S: Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_rdlock.S: Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_unlock.S: Likewise. + * sysdeps/unix/sysv/linux/sparc/lowlevellock.h: Likewise. + * tst-mutexpp10.c: Likewise. + * tst-stackguard1.c: Likewise. + +2013-05-31 Joseph Myers <joseph@codesourcery.com> + + * Makefile ($(objpfx)libpthread.so): Remove dependencies on libc + and ld.so. + +2013-05-16 Ryan S. Arnold <rsa@linux.vnet.ibm.com> + + * pthread_create.c: Add missing #include <stdint.h> due to uint64_t or + uint32_t usage. + * sysdeps/pthread/createthread.c: Likewise. + +2013-05-14 Andreas Jaeger <aj@suse.de> + + [BZ #10686] + * sysdeps/x86_64/tls.h (struct tcbhead_t): Add __private_ss field. + * sysdeps/i386/tls.h (struct tcbhead_t): Likewise. + +2013-05-09 Andi Kleen <ak@linux.intel.com> + + * tst-mutex8.c (do_test): Check for ENABLE_PI. + +2013-04-22 Siddhesh Poyarekar <siddhesh@redhat.com> + + * pthreadP.h (check_sched_policy_attr): New inline function. + (check_sched_priority_attr): Likewise. + (check_stacksize_attr): Likewise. + (__kernel_cpumask_size, __determine_cpumask_size): Declare + extern. + (check_cpuset_attr): New inline function. + * pthread_attr_setschedparam (__pthread_attr_setschedparam): + Use check_sched_priority_attr. + * pthread_attr_setschedpolicy.c + (__pthread_attr_setschedpolicy): Use check_sched_policy_attr. + * pthread_attr_setstack.c (__pthread_attr_setstack): Use + check_stacksize_attr. + * pthread_attr_setstacksize.c (__pthread_attr_setstacksize): + Likewise. + * sysdeps/unix/sysv/linux/pthread_attr_setaffinity.c + (__pthread_attr_setaffinity_new): Use check_cpuset_attr. + +2013-04-11 Andreas Schwab <schwab@suse.de> + + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S + (__pthread_cond_timedwait): If possible use FUTEX_WAIT_BITSET to + directly use absolute timeout. + +2013-04-07 Carlos O'Donell <carlos@redhat.com> + + * sysdeps/unix/sysv/linux/sem_post.c: Include atomic.h. + +2013-04-04 Siddhesh Poyarekar <siddhesh@redhat.com> + + [BZ #15337] + * sysdeps/unix/sysv/linux/x86_64/cancellation.S + [IS_IN_libpthread] + [SHARED && defined DO_VERSIONING && !defined NO_HIDDEN]: Mark + __pthread_unwind hidden. + +2013-03-28 Roland McGrath <roland@hack.frob.com> + + * pthread_create.c (start_thread) [!SHARED]: + Call __call_tls_dtors only if it's not NULL. + +2013-03-19 Siddhesh Poyarekar <siddhesh@redhat.com> + + * allocatestack.c (allocate_stack): Use __default_pthread_attr + instead of __default_stacksize. + * nptl-init.c (__pthread_initialize_minimal_internal): + Likewise. Initialize guardsize. + * pthreadP.h (__default_pthread_attr): Declare. + * pthread_attr_getstacksize.c (__pthread_attr_getstacksize): + Use __default_pthread_attr instead of __default_stacksize. + * pthread_create.c (default_attr): Remove. + (__pthread_create_2_1): Use __default_pthread_attr instead of + default_attr. + * vars.c (__default_stacksize): Remove. + (__default_pthread_attr): New static variable to store + default thread attributes. + +2013-03-18 Siddhesh Poyarekar <siddhesh@redhat.com> + + * pthread_barrier_init.c (default_attr): Rename to + default_barrierattr. + (pthread_barrier_init): Adjust for the rename. + * pthread_mutex_init.c (default_attr): Rename to + default_mutexattr. + (__pthread_mutex_init): Adjust for the rename. + * pthread_rwlock_init.c (default_attr): Rebane to + default_rwlockattr. + (__pthread_rwlock_init): Adjust for the rename. + +2013-03-12 Carlos O'Donell <carlos@redhat.com> + + * sysdeps/unix/sysv/linux/lowlevellock.c: Include <atomic.h>. + +2013-03-04 Roland McGrath <roland@hack.frob.com> + + * sysdeps/unix/sysv/linux/i386/i686/dl-sysdep.h: + Change multiple inclusion guard to _LINUX_I686_DL_SYSDEP_H. + Use #include_next. + (HAVE_DL_DISCOVER_OSVERSION): Remove definition, now redundant. + (RTLD_PRIVATE_ERRNO): Likewise. + (NEED_DL_SYSINFO, DL_SYSINFO_DEFAULT, DL_SYSINFO_IMPLEMENTATION): + Move macros and associated declaration to ... + * sysdeps/unix/sysv/linux/i386/dl-sysdep.h: ... here. + Change multiple include guard to _LINUX_I386_DL_SYSDEP_H. + Use #include_next. + +2013-03-01 Carlos O'Donell <carlos@redhat.com> + + * Makefile (tests): Revert last change. + (tst-pthread-stack-env-ENV): Likewise. + * nptl-init.c (set_default_stacksize): Likewise. + (__pthread_initialize_minimal_internal): Likewise. + * tst-pthread-stack-env.c: Likewise. + +2013-03-01 Siddhesh Poyarekar <siddhesh@redhat.com> + + * tst-oddstacklimit.c: Include stdlib.h. + + * Makefile (tests): Add tst-pthread-stack-env. + (tst-pthread-stack-env-ENV): Set environment for test. + * nptl-init.c (set_default_stacksize): New function. + (__pthread_initialize_minimal_internal): Accept ARGC, ARGV and + ENVP. Initialize __ENVIRON and set __DEFAULT_STACKSIZE. + * tst-pthread-stack-env.c: New test case. + +2013-02-21 David S. Miller <davem@davemloft.net> + + * sysdeps/unix/sysv/linux/sparc/lowlevellock.h + (FUTEX_WAIT_REQUEUE_PI): Define. + (FUTEX_CMP_REQUEUE_PI): Likewise. + (lll_futex_wait_requeue_pi): Likewise. + (lll_futex_timed_wait_requeue_pi): Likewise. + (lll_futex_cmp_requeue_pi): Likewise. + +2013-02-21 Carlos O'Donell <carlos@redhat.com> + + * sysdeps/unix/sysv/linux/fork.c: Fix comment typo. + +2013-02-18 Siddhesh Poyarekar <siddhesh@redhat.com> + + * sysdeps/pthread/tst-timer.c: Include stdlib.h for declaration + of exit. + * tst-barrier4.c: Likewise. + * tst-robust7.c: Likewise. + + [BZ #14920] + * pthreadP.h (USE_REQUEUE_PI): New macro to check if mutex is + PI-aware. + * pthread_cond_broadcast.c (__pthread_cond_broadcast): Use + PI-aware futex operations if available and mutex is PI-aware. + * pthread_cond_signal.c (__pthread_cond_signal): Likewise. + * nptl/pthread_cond_timedwait.c (__pthread_cond_timedwait): + Likewise. + * pthread_cond_wait.c (__condvar_cleanup): Adjust lock if + cancellation occurred just after futex returned successfully + from a PI operation with the mutex held. + (__pthread_cond_wait): Use PI-aware futex operations if + available and mutex is PI-aware. + * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h + (FUTEX_WAIT_REQUEUE_PI): Define. + (FUTEX_CMP_REQUEUE_PI): Likewise. + (lll_futex_wait_requeue_pi): Likewise. + (lll_futex_timed_wait_requeue_pi): Likewise. + (lll_futex_cmp_requeue_pi): Likewise. + * nptl/sysdeps/unix/sysv/linux/s390/lowlevellock.h + (FUTEX_WAIT_REQUEUE_PI): Define. + (FUTEX_CMP_REQUEUE_PI): Likewise. + (lll_futex_wait_requeue_pi): Likewise. + (lll_futex_timed_wait_requeue_pi): Likewise. + (lll_futex_cmp_requeue_pi): Likewise. + * sysdeps/unix/sysv/linux/kernel-features.h: Define + __ASSUME_REQUEUE_PI for Linux version higher than 2.6.31. + +2013-02-04 Andreas Schwab <schwab@suse.de> + + [BZ #14142] + * tst-cancel14.c: Include <sys/time.h>. + * tst-cancel15.c: Likewise. + * tst-mutex9.c: Include <stdint.h>, <stdlib.h> and <sys/time.h>. + * tst-stackguard1.c: Include <tls.h> + +2013-01-16 Andreas Schwab <schwab@suse.de> + + [BZ #14327] + * sem_open.c (sem_open): Use __mktemp instead of mktemp. + +2013-01-11 Carlos O'Donell <codonell@redhat.com> + + * allocatestack.c (allocate_stack): Add comment. Remove assert + on attr. + +2013-01-11 H.J. Lu <hongjiu.lu@intel.com> + + * Makefile (tst-cancel7-ARGS: Replace $(host-built-program-cmd) + with $(host-test-program-cmd). + (tst-exec4-ARGS): Likewise. + (tst-stackguard1-ARGS): Likewise. + ($(objpfx)tst-tls6.out): Don't pass $(elf-objpfx) to tst-tls6.sh. + Replace $(rtld-installed-name) with $(test-via-rtld-prefix). + * tst-tls6.sh (elf_objpfx): Removed. + (rtld_installed_name): Renamed to ... + (test_via_rtld_prefix): This. + (tst_tls5): Prepend ${test_via_rtld_prefix}. + +2013-01-02 Joseph Myers <joseph@codesourcery.com> + + * All files with FSF copyright notices: Update copyright dates + using scripts/update-copyrights. + +2013-01-01 Joseph Myers <joseph@codesourcery.com> + + * sysdeps/unix/sysv/linux/x86_64/lowlevelrobustlock.S: Reformat + copyright notice. + +2012-12-28 Andi Kleen <ak@linux.intel.com> + + * pthread_rwlock_tryrdlock.c (__pthread_rwlock_tryrdlock): Convert + to prototype. + * pthread_rwlock_trywrlock.c (__pthread_rwlock_trywrlock): + Likewise. + +2012-12-27 David S. Miller <davem@davemloft.net> + + * sysdeps/unix/sysv/linux/sparc/lowlevellock.h + (lll_futex_timed_wait_bitset): New macro. + +2012-12-27 Siddhesh Poyarekar <siddhesh@redhat.com> + + * sysdeps/unix/sysv/linux/s390/lowlevellock.h (SYS_futex): + Remove definition. + (lll_futex_timed_wait): Replace assembly code with + INTERNAL_SYSCALL. + (lll_futex_timed_wait_bitset): Likewise. + (lll_futex_wake): Likewise. + (lll_futex_requeue): Likewise. + (lll_futex_wake_unlock): Likewise. + +2012-12-08 Siddhesh Poyarekar <siddhesh@redhat.com> + + * sysdeps/unix/sysv/linux/s390/jmp-unwind.c (_longjmp_unwind): + Declare LOCAL_VAR as char. + +2012-12-04 Joseph Myers <joseph@codesourcery.com> + + * sysdeps/unix/sysv/linux/powerpc/sem_post.c (__old_sem_post): + Cast result of atomic_increment_val to (void) instead of storing + in otherwise-unused variable. + +2012-12-03 Allan McRae <allan@archlinux.org> + + * Makefile (LDFLAGS-tst-cond24, LDFLAGS-tst-cond25): Remove. + +2012-11-26 H.J. Lu <hongjiu.lu@intel.com> + + * unwind.c (__pthread_unwind): Pass address of unwind_cleanup + to THREAD_SETMEM. + * sysdeps/i386/tls.h: Include <libc-internal.h>. + (THREAD_SETMEM): Use cast_to_integer before casting to uint64_t. + (THREAD_SETMEM_NC): Likewise. + * sysdeps/x86_64/tls.h: Include <libc-internal.h>. + (THREAD_SETMEM): Use cast_to_integer before casting to uint64_t. + (THREAD_SETMEM_NC): Likewise. + +2012-11-21 Joseph Myers <joseph@codesourcery.com> + + * sysdeps/unix/sysv/linux/sem_post.c (__old_sem_post): Cast result + of atomic_increment_val to (void) instead of storing in + otherwise-unused variable. + + * pthread_cond_timedwait.c (__pthread_cond_timedwait) + [__NR_clock_gettime]: Cast result of INTERNAL_VSYSCALL to void + instead of storing in otherwise-unused variable. + +2012-11-14 Marcus Shawcroft <marcus.shawcroft@linaro.org> + + * Makefile (CFLAGS-open.c, CFLAGS-open64.c, CFLAGS-pause.c) + (CFLAGS-recv.c, CFLAGS-send.c): Define. + +2012-11-06 Chris Metcalf <cmetcalf@tilera.com> + + * tst-sem14.c (TIMEOUT): Set timeout to 10 seconds. + * tst-cond24.c (TIMEOUT): Increase from 10 to 20 seconds. + +2012-11-05 Siddhesh Poyarekar <siddhesh@redhat.com> + + * pthread_cond_timedwait.c (__pthread_cond_timedwait): Time out + if absolute timeout is negative. + [__ASSUME_FUTEX_CLOCK_REALTIME && + lll_futex_timed_wait_bitset]: Use lll_futex_timed_wait_bitset. + * pthread_rwlock_timedrdlock.c (pthread_rwlock_timedrdlock): + Likewise. + * pthread_rwlock_timedwrlock.c (pthread_rwlock_timedwrlock): + Likewise. + * sysdeps/unix/sysv/linux/lowlevelrobustlock.c + (__lll_robust_timedlock_wait): Likewise. + * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h + (lll_futex_timed_wait_bitset): New macro. + * sysdeps/unix/sysv/linux/s390/lowlevellock.h + (lll_futex_timed_wait_bitset): Likewise. + +2012-11-03 David S. Miller <davem@davemloft.net> + + * sysdeps/unix/sysv/linux/sparc/lowlevellock.h (BUSY_WAIT_NOP): + Add missing spaces. + (__cpu_relax): Likewise. + +2012-11-02 H.J. Lu <hongjiu.lu@intel.com> + + * sysdeps/x86_64/tls.h: Don't include <xmmintrin.h>. + (__128bits): New struct typedef. + (tcbhead_t): Replace __m128 with __128bits. + +2012-10-30 Aurelien Jarno <aurelien@aurel32.net> + Joseph Myers <joseph@codesourcery.com> + + * Makefile (tst-cancel7-ARGS): Use exec in --command argument. + +2012-10-28 David S. Miller <davem@davemloft.net> + + * sysdeps/unix/sysv/linux/sparc/lowlevellock.h (BUSY_WAIT_NOP): + Define when we have v9 instructions available. + * sysdeps/unix/sysv/linux/sparc/sparc64/cpu_relax.S: New file. + * sysdeps/unix/sysv/linux/sparc/sparc32/sparcv9/cpu_relax.S: New + file. + * sysdeps/unix/sysv/linux/sparc/sparc32/sparcv9/Makefile: New + file. + * sysdeps/unix/sysv/linux/sparc/sparc64/Makefile: Add cpu_relax + to libpthread-routines. + +2012-10-25 Roland McGrath <roland@hack.frob.com> + + * tst-cond-except.c (TEST_FUNCTION): New macro. + +2012-10-25 Joseph Myers <joseph@codesourcery.com> + + * Makefile ($(objpfx)tst-tls6.out): Use $(BASH) not $(SHELL) to + run tst-tls6.sh. + * tst-tls6.sh: Use /bin/bash not /bin/sh. + +2012-10-25 Roland McGrath <roland@hack.frob.com> + + * tst-basic2.c (do_test): Return RESULT, not always zero. + + * tst-cond25.c: Include <stdint.h> + (waiter): Add casts to uintptr_t between casting integer<->pointer. + (timed_waiter): Likewise. + (do_test_wait): Likewise. + * tst-cond-except.c (thr): Likewise. + (do_test): Use prototype definition. + +2012-10-24 Joseph Myers <joseph@codesourcery.com> + Jim Blandy <jimb@codesourcery.com> + + * Makefile ($(objpfx)tst-tls6.out): Pass $(test-wrapper-env) to + tst-tls6.sh. + * tst-tls6.sh (test_wrapper_env): New variable. Use it to run + programs with LD_PRELOAD set. + +2012-10-24 Roland McGrath <roland@hack.frob.com> + + * Makefile ($(objpfx)tst-cond11, $(objpfx)tst-cond19): Targets removed. + ($(objpfx)tst-sem5, $(objpfx)tst-cancel18): Likewise. + ((objpfx)tst-cancelx18, $(objpfx)tst-clock2): Likewise. + ($(objpfx)tst-rwlock14): Likewise. + +2012-10-24 Joseph Myers <joseph@codesourcery.com> + + * Makefile (tests): Remove tst-oddstacklimit. + (test-srcs): New variable. + (tst-oddstacklimit-ENV): Remove. + [$(run-built-tests) = yes] (tests): Depend on + $(objpfx)tst-oddstacklimit.out. + [$(run-built-tests) = yes] ($(objpfx)tst-oddstacklimit.out): New + target. + * tst-oddstacklimit.c: Do not include "tst-basic1.c". Use + setrlimit before executing tst-basic1 test passed to --command. + +2012-10-23 Joseph Myers <joseph@codesourcery.com> + + * Makefile [$(cross-compiling) = no]: Change condition to + [$(run-built-tests) = yes]. + +2012-10-23 Jim Blandy <jimb@codesourcery.com> + Joseph Myers <joseph@codesourcery.com> + + * Makefile (tst-cancel7-ARGS): Use $(host-built-program-cmd). + (tst-exec4-ARGS): Likewise. + (tst-stackguard1-ARGS): Likewise. + +2012-10-21 Jim Blandy <jimb@codesourcery.com> + Joseph Myers <joseph@codesourcery.com> + + * Makefile ($(objpfx)tst-cancel-wrappers.out): Pass $(NM) to + tst-cancel-wrappers.sh. + * tst-cancel-wrappers.sh: Use nm program given as first argument, + not hardcoded "nm". + +2012-10-17 Siddhesh Poyarekar <siddhesh@redhat.com> + + * tst-cond25.c (do_test_wait): Don't check for return value from + pthread_cancel. + +2012-10-16 Siddhesh Poyarekar <siddhesh@redhat.com> + + [BZ #14652] + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S + (__condvar_tw_cleanup): Adjust the mutex data structure if it + was locked by FUTEX_WAIT_REQUEUE_PI. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait + (__condvar_w_cleanup): Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S + (__condvar_cleanup2): Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S + (__condvar_cleanup1): Likewise. + +2012-10-10 Carlos O'Donell <carlos@systemhalted.org> + + * sysdeps/pthread/pthread.h [!(defined __GNUC__ && + defined __EXCEPTIONS) && defined __USE_GNU] + (pthread_cleanup_push_defer_np): Fix formatting. + +2012-10-10 Siddhesh Poyarekar <siddhesh@redhat.com> + + [BZ #14652] + * Makefile (tests): New test case tst-cond25. + (LDFLAGS-tst-cond25): Link tst-cond25 against librt. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S + (__condvar_tw_cleanup): Lock mutex only if we don't already + own it. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S + (__condvar_w_cleanup): Likewise. + * sysdeps/unix/sysv/linux/pthread-pi-defines.sym: Add TID_MASK. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S + (__condvar_cleanup2): Lock mutex only if we don't already + own it. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S + (__condvar_cleanup1): Likewise. + * tst-cond25.c: New test case. + +2012-10-09 Roland McGrath <roland@hack.frob.com> + + * sysdeps/pthread/configure: Regenerated. + * sysdeps/x86_64/configure: Regenerated. + +2012-10-05 David S. Miller <davem@davemloft.net> + + [BZ #14568] + * sysdeps/sparc/tls.h (DB_THREAD_SELF_INCLUDE): Delete. + (DB_THREAD_SELF): Use constants for the register offsets. Correct + the case of a 64-bit debugger with a 32-bit inferior. + +2012-10-05 H.J. Lu <hongjiu.lu@intel.com> + + [BZ #14557] + * Makefile (tests-static): Add tst-cancel24-static, + tst-cond8-static tst-mutex8-static, tst-mutexpi8-static, + tst-sem11-static and tst-sem12-static. + (tests): Likewise. + (LDLIBS-tst-cancel24-static): New macro. + * tst-cancel24-static.cc: New file. + * tst-cond8-static.c: Likewise. + * tst-mutex8-static.c: Likewise. + * tst-mutexpi8-static.c: Likewise. + * tst-sem11-static.c: Likewise. + * tst-sem12-static.c: Likewise. + +2012-10-05 Siddhesh Poyarekar <siddhesh@redhat.com> + + [BZ #14417] + * Makefile (tests): New test case tst-cond24. + (LDFLAGS-tst-cond24): Link tst-cond24 against librt. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S + (__pthread_cond_timedwait): Unlock mutex before going back to + wait in PI case. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S + (__pthread_cond_wait): Likewise. Revert handling of EAGAIN + return from futex_wait. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S + (__pthread_cond_timedwait): Unlock mutex before going back to + wait in PI case. Set requeue_pi flag only if wait returned 0. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S + (__pthread_cond_wait): Likewise. Revert handling of EAGAIN + return from futex_wait. + * tst-cond24.c: New test case. + +2012-10-04 Roland McGrath <roland@hack.frob.com> + + * pthread_create.c (start_thread): Use __madvise, not madvise. + +2012-10-02 H.J. Lu <hongjiu.lu@intel.com> + + * sysdeps/i386/tls.h: Update copyright years. + +2012-10-02 Siddhesh Poyarekar <siddhesh@redhat.com> + + * pthread_create.c (start_thread): Fix clone flag name in + comment to CLONE_CHILD_CLEARTID. + * sysdeps/unix/sysv/linux/i386/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/x86_64/lowlevellock.h: Likewise. + +2012-10-01 Siddhesh Poyarekar <siddhesh@redhat.com> + + [BZ #14477] + * Makefile (tests): Add tst-cond-except. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S + (__pthread_cond_timedwait): Mark instructions where %ebx is + incremented in PI case. + (.gcc_except_table): Add entry to jump to __condvar_tw_cleanup2 + for the marked PI case instructions. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S + (__pthread_cond_wait): Mark instructions where %ebx is + incremented in PI case. + (.gcc_except_table): Add entry to jump to __condvar_w_cleanup2 + for the marked PI case instructions. + * tst-cond-except.c: New test case. + +2012-09-24 Dmitry V. Levin <ldv@altlinux.org> + + * tst-tls6.sh: Add "set -e". + * Makefile: Do not specify -e option when running testsuite + shell scripts. + + * tst-tls6.sh: Add copyright header. + +2012-09-24 H.J. Lu <hongjiu.lu@intel.com> + + * sysdeps/x86_64/tls.h (THREAD_SETMEM): Add "()" when casting + to uint64_t for 64-bit store. + (THREAD_SETMEM_NC): Likewise. + +2012-09-19 H.J. Lu <hongjiu.lu@intel.com> + + * sysdeps/i386/tls.h (THREAD_SETMEM): Cast to uint64_t for + 64-bit store. + (THREAD_SETMEM_NC): Likewise. + +2012-09-14 Jeff Law <law@redhat.com> + + [BZ #14583] + * sysdeps/pthread/pthread.h: Fix prototype of __sigsetjmp. + +2012-09-13 H.J. Lu <hongjiu.lu@intel.com> + + [BZ #14576] + * sysdeps/pthread/bits/libc-lockP.h (__rtld_lock_init_recursive): + Removed. + +2012-09-07 H.J. Lu <hongjiu.lu@intel.com> + + * Makefile (LDFLAGS-tst-cancel24): Renamed to ... + (LDLIBS-tst-cancel24): This. + +2012-09-06 H.J. Lu <hongjiu.lu@intel.com> + + [BZ #14545] + * Makefile (tests-static): Add tst-cancel21-static. + (tests): Likewise. + * tst-cancel21-static.c: New file. + +2012-09-01 Joseph Myers <joseph@codesourcery.com> + + * sysdeps/unix/sysv/linux/pthread_getcpuclockid.c + [!__ASSUME_POSIX_CPU_TIMERS]: Remove conditional code. + [__NR_clock_getres]: Make code unconditional. + (pthread_getcpuclockid): Remove code left unreachable by removal + of conditionals. + +2012-08-31 Joseph Myers <joseph@codesourcery.com> + + [BZ #14532] + * sysdeps/unix/sysv/linux/sem_post.c (__new_sem_post): Use + atomic_compare_and_exchange_bool_rel. + * tst-sem14.c: New file. + * Makefile (tests): Add tst-sem14. + +2012-08-15 Roland McGrath <roland@hack.frob.com> + + * Makefile (CFLAGS-flockfile.c): Use $(libio-mtsafe) instead + of -D_IO_MTSAFE_IO. + (CFLAGS-ftrylockfile.c, CFLAGS-funlockfile.c): Likewise. + * sysdeps/unix/sysv/linux/Makefile (CFLAGS-fork.c): Likewise. + +2012-08-16 Joseph Myers <joseph@codesourcery.com> + + * pthread_cond_timedwait.c (__pthread_cond_timedwait) + [!__ASSUME_POSIX_TIMERS]: Remove conditional code. + * pthread_condattr_setclock.c (pthread_condattr_setclock) + [!__ASSUME_POSIX_TIMERS]: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S + (__pthread_cond_timedwait) [!__ASSUME_POSIX_TIMERS]: Likewise. + * sysdeps/unix/sysv/linux/pthread_getcpuclockid.c + [!__ASSUME_POSIX_TIMERS]: Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_cond_timedwait.S + (__pthread_cond_timedwait) [!__ASSUME_POSIX_TIMERS]: Likewise. + * sysdeps/unix/sysv/linux/timer_create.c [__NR_timer_create]: Make + code unconditional. + [!__NR-timer_create]: Remove conditional code. + (timer_create) [!__ASSUME_POSIX_TIMERS]: Likewise. + * sysdeps/unix/sysv/linux/timer_delete.c [__NR_timer_delete]: Make + code unconditional. + [!__NR_timer_delete]: Remove conditional code. + (timer_delete) [!__ASSUME_POSIX_TIMERS]: Likewise. + * sysdeps/unix/sysv/linux/timer_getoverr.c + [__NR_timer_getoverrun]: Make code unconditional. + [!__NR_timer_getoverrun]: Remove conditional code. + (timer_getoverrun) [!__ASSUME_POSIX_TIMERS]: Likewise. + * sysdeps/unix/sysv/linux/timer_gettime.c [__NR_timer_gettime]: + Make code unconditional. + [!__NR_timer_gettime]: Remove conditional code. + (timer_gettime) [!__ASSUME_POSIX_TIMERS]: Likewise. + * sysdeps/unix/sysv/linux/timer_routines.c [__NR_timer_create]: + Make code unconditional. + [!__ASSUME_POSIX_TIMERS]: Remove conditional code. + * sysdeps/unix/sysv/linux/timer_settime.c [__NR_timer_settime]: + Make code unconditional. + [!__NR_timer_settime]: Remove conditional code. + (timer_settime) [!__ASSUME_POSIX_TIMERS]: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S + (__pthread_cond_timedwait) [!__ASSUME_POSIX_TIMERS]: Remove + conditional code. + +2012-08-15 Tom de Vries <vries@codesourcery.com> + Maxim Kuvyrkov <maxim@codesourcery.com> + + * sysdeps/pthread/bits/libc-lockP.h (__libc_lock_lock) + (__libc_lock_trylock): Allow pre-existing definitions. + +2012-08-15 Maxim Kuvyrkov <maxim@codesourcery.com> + + * pthread_spin_lock.c: New file. + * pthread_spin_trylock.c: New file. + +2012-08-08 Joseph Myers <joseph@codesourcery.com> + + * allocatestack.c (setxid_signal_thread) [__ASSUME_TGKILL]: Make + code unconditional. + (setxid_signal_thread) [!__ASSUME_TGKILL]: Remove conditional code. + * pthread_cancel.c (pthread_cancel) [__ASSUME_TGKILL]: Make code + unconditional. + (pthread_cancel) [!__ASSUME_TGKILL]: Remove conditional code. + * sysdeps/pthread/createthread.c (do_clone) [__ASSUME_TGKILL]: + Make code unconditional. + (do_clone) [!__ASSUME_TGKILL]: Remove conditional code. + * sysdeps/unix/sysv/linux/pt-raise.c (raise) [__ASSUME_TGKILL || + __NR_tgkill]: Make code unconditional. + (raise) [__ASSUME_TGKILL]: Likewise. + (raise) [!__ASSUME_TGKILL]: Remove conditional code. + * sysdeps/unix/sysv/linux/pthread_kill.c (__pthread_kill) + [__ASSUME_TGKILL]: Make code unconditional. + (__pthread_kill) [!__ASSUME_TGKILL]: Remove conditional code. + * sysdeps/unix/sysv/linux/raise.c (raise) [__ASSUME_TGKILL || + __NR_tgkill]: Make code unconditional. + (raise) [__ASSUME_TGKILL]: Likewise. + (raise) [!__ASSUME_TGKILL]: Remove conditional code. + +2012-08-07 Joseph Myers <joseph@codesourcery.com> + + * sysdeps/pthread/createthread.c (create_thread) + [!__ASSUME_NO_CLONE_DETACHED]: Remove conditional code. + +2012-08-03 Joseph Myers <joseph@codesourcery.com> + + * nptl-init.c (sigcancel_handler) [__ASSUME_CORRECT_SI_PID]: Make + code unconditional. + (sighandler_setxid) [__ASSUME_CORRECT_SI_PID]: Likewise. + +2012-07-28 Siddhesh Poyarekar <siddhesh@redhat.com> + + * tst-pthread-getattr.c (MAX_STACK_SIZE): New macro. + (pagesize): New static variable. + (allocate_and_test): Return MEM. Rename parameter to TARGET. + (check_stack_top): New local variables MEM and PAGEMASK. Cap + stack size to MAX_STACK_SIZE. Call allocate_and_test for + halfway up the stack top page. Verify that the top page was + written into. + (do_test): Get pagesize using sysconf. + +2012-07-25 Andreas Schwab <schwab@linux-m68k.org> + + * sysdeps/unix/sysv/linux/i386/pt-vfork.S: Remove pseudo_end + label. + * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h (PSEUDO): Likewise. + * sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h (PSEUDO): + Likewise. + +2012-07-25 Siddhesh Poyarekar <siddhesh@redhat.com> + + * tst-pthread-getattr.c: Revert last change. + +2012-07-20 Siddhesh Poyarekar <siddhesh@redhat.com> + + * tst-pthread-getattr.c (MAX_STACK_SIZE): New max cap for stack + size. + (_MIN): New macro. + (allocate_and_test): Return STACKADDR. Access STACKADDR instead + of MEM to test. + (check_stack_top): Read valued written into STACKADDR in + allocate_and_test. Cap stack size to MAX_STACK_SIZE. + +2012-07-19 Siddhesh Poyarekar <siddhesh@redhat.com> + + * nptl-init.c (sighandler_setxid): Fix the comment that + describes it. + +2012-06-23 Thomas Schwinge <thomas@codesourcery.com> + + * sysdeps/unix/sysv/linux/sh/lowlevelrobustlock.S + (__lll_robust_timedlock_wait): Simplify CFI directives. + +2012-06-20 Siddhesh Poyarekar <siddhesh@redhat.com> + + [BZ #12416] + * Makefile (tests): Add test case. + * pthread_getattr_np.c (pthread_getattr_np): Deduct pages below + the __libc_stack_end page from stacksize. Truncate stacksize to + make it page aligned when it is computed from RLIMIT_STACK. + * tst-pthread-getattr.c: New test case. Verify that stackaddr is + accessible. + +2012-06-07 Carlos Sánchez de La Lama <csanchezdll@gmail.com> + + [BZ #14205] + * sysdeps/sparc/sparc32/pthread_spin_lock.S: Do not use v9 + branches. + +2012-06-04 Siddhesh Poyarekar <siddhesh@redhat.com> + Jakub Jelinek <jakub@redhat.com> + + [BZ #14188] + * sysdeps/pthread/pthread.h + [!(defined __GNUC__ && defined __EXCEPTIONS)] + (pthread_cleanup_push, pthread_cleanup_push_defer_np): Use + __libc_unlikely instead of __builtin_expect. + +2012-05-30 H.J. Lu <hongjiu.lu@intel.com> + + [BZ #14117] + * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h: Removed. + * sysdeps/unix/sysv/linux/i386/bits/semaphore.h: Likewise. + * sysdeps/unix/sysv/linux/i386/Implies: New file. + * sysdeps/unix/sysv/linux/x86_64/Implies: Likewise. + * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: Renamed + to ... + * sysdeps/unix/sysv/linux/x86/bits/pthreadtypes.h: This. + * sysdeps/unix/sysv/linux/x86_64/bits/semaphore.h: Renamed + to ... + * sysdeps/unix/sysv/linux/x86/bits/semaphore.h: This. + +2012-05-30 Andreas Schwab <schwab@linux-m68k.org> + + [BZ #14132] + * nptl-init.c (pthread_functions): Remove use of INTUSE and + _internal aliases. + (__pthread_initialize_minimal_internal): Likewise. + * sem_open.c: Likewise. + * sem_unlink.c: Likewise. + * pthreadP.h: Replace _internal aliases by hidden_proto + declarations. + * pthread_getspecific.c: Replace _internal alias by hidden_def. + * pthread_key_create.c: Likewise. + * pthread_mutex_destroy.c: Likewise. + * pthread_mutex_init.c: Likewise. + * pthread_mutex_lock.c: Likewise. + * pthread_mutex_unlock.c: Likewise. + * pthread_once.c: Likewise. + * pthread_rwlock_rdlock.c: Likewise. + * pthread_rwlock_unlock.c: Likewise. + * pthread_rwlock_wrlock.c: Likewise. + * pthread_setspecific.c: 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/pthread_once.S: Likewise. + * sysdeps/unix/sysv/linux/powerpc/pthread_once.c: Likewise. + * sysdeps/unix/sysv/linux/s390/pthread_once.c: Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_once.S: Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_rdlock.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/sparc/pthread_once.c: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_once.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_rdlock.S: + Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_unlock.S: + Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_wrlock.S: + Likewise. + +2012-05-27 Chung-Lin Tang <cltang@codesourcery.com> + + * sysdeps/unix/sysv/linux/sh/sysdep-cancel.h (PSEUDO, LOAD_ARGS_1) + (LOAD_ARGS_2 ,LOAD_ARGS_3 ,LOAD_ARGS_4): Add CFI restores. + + * sysdeps/unix/sysv/linux/sh/lowlevellock.S (__lll_lock_wait_private) + (__lll_lock_wait, __lll_timedlock_wait, __lll_timedwait_tid): Add CFI + directives. + * sysdeps/unix/sysv/linux/sh/lowlevelrobustlock.S + (__lll_robust_lock_wait, __lll_robust_timedlock_wait): Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_barrier_wait.S + (pthread_barrier_wait): Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_cond_broadcast.S + (__pthread_cond_broadcast): Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_cond_signal.S + (__pthread_cond_signal): Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_cond_timedwait.S + (__pthread_cond_timedwait): Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_cond_wait.S (__pthread_cond_wait): + Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_rdlock.S + (__pthread_rwlock_rdlock): 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. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_wrlock.S + (__pthread_rwlock_wrlock): Likewise. + * 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. + +2012-05-26 Siddhesh Poyarekar <siddhesh@redhat.com> + + [BZ #12416] + * nptl/pthread_getattr_np.c (pthread_getattr_np): Use + __libc_stack_end rounded to the end of containing page as the + real stack end. + +2012-05-25 Rayson Ho <rho@redhat.com> + + * sysdeps/unix/sysv/linux/i386/lowlevellock.h: Low-level SystemTap + probes for i386. + * sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S: 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/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_wrlock.S: Likewise. + +2012-05-25 Rayson Ho <rho@redhat.com> + Roland McGrath <roland@hack.frob.com> + + * DESIGN-systemtap-probes.txt: New file. + * pthread_cond_broadcast.c: SystemTap probes. + * pthread_cond_init.c: Likewise. + * pthread_cond_signal.c: Likewise. + * pthread_cond_wait.c: Likewise. + * pthread_cond_destroy.c: Likewise. + * pthread_create.c: Likewise. + * pthread_join.c: Likewise. + * pthread_mutex_destroy.c: Likewise. + * pthread_mutex_init.c: Likewise. + * pthread_mutex_lock.c: Likewise. + * pthread_mutex_timedlock.c: Likewise. + * pthread_mutex_unlock.c: Likewise. + * pthread_rwlock_destroy.c: Likewise. + * pthread_rwlock_rdlock.c: Likewise. + * pthread_rwlock_unlock.c: Likewise. + * pthread_rwlock_wrlock.c: Likewise. + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_signal.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_wrlock.S: Likewise. + +2012-05-24 Roland McGrath <roland@hack.frob.com> + + * pthread_create.c (start_thread): Define pthread_start LIBC_PROBE. + +2012-05-17 Andreas Jaeger <aj@suse.de> + + * sysdeps/unix/sysv/linux/i386/i686/dl-sysdep.h + (HAVE_DL_DISCOVER_OSVERSION): Don't declare _dl_discover_osversion + only for older kernels. + +2012-05-15 Joseph Myers <joseph@codesourcery.com> + + * pthreadP.h [!__NR_set_robust_list] (__NR_set_robust_list): Do + not define. + +2012-05-15 H.J. Lu <hongjiu.lu@intel.com> + + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h (lll_lock): Load + futex pointer into RDI_LP. Use RSP_LP to operate on stack. + (lll_robust_lock): Likewise. + (lll_cond_lock): Likewise. + (lll_robust_cond_lock): Likewise. + (lll_timedlock): Likewise. + (lll_robust_timedlock): Likewise. + (lll_unlock): Likewise. + (lll_robust_unlock): Likewise. + +2012-05-15 H.J. Lu <hongjiu.lu@intel.com> + + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_signal.S: Use + LP_OP(cmp) and RCX_LP on dep_mutex pointer. + +2012-05-15 H.J. Lu <hongjiu.lu@intel.com> + + * sysdeps/unix/sysv/linux/x86_64/sem_wait.S: Use LP_OP(op) + on NWAITERS. + (__gcc_personality_v0): Replace 8-byte data alignment with + LP_SIZE alignment and .quad with ASM_ADDR. + +2012-05-15 H.J. Lu <hongjiu.lu@intel.com> + + * sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S: Use LP_OP(op) + on NWAITERS. + (__gcc_personality_v0): Replace 8-byte data alignment with + LP_SIZE alignment and .quad with ASM_ADDR. + +2012-05-15 H.J. Lu <hongjiu.lu@intel.com> + + * sysdeps/unix/sysv/linux/x86_64/sem_post.S: Use LP_OP(cmp) on + NWAITERS, which is unsigned long int. + +2012-05-15 H.J. Lu <hongjiu.lu@intel.com> + + * sysdeps/unix/sysv/linux/x86_64/pthread_once.S + (__gcc_personality_v0): Replace 8-byte data alignment with + LP_SIZE alignment and .quad with ASM_ADDR. + +2012-05-15 H.J. Lu <hongjiu.lu@intel.com> + + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S: Use + LP_OP(cmp), RSI_LP and R8_LP on dep_mutex pointer. Load + __vdso_clock_gettime pointer into RAX_LP. + (__gcc_personality_v0): Replace 8-byte data alignment with + LP_SIZE alignment and .quad with ASM_ADDR. + +2012-05-15 H.J. Lu <hongjiu.lu@intel.com> + + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: Use + LP_OP(cmp), RSI_LP and R8_LP on dep_mutex pointer. Load + __vdso_clock_gettime pointer into RAX_LP. + (__gcc_personality_v0): Replace 8-byte data alignment with + LP_SIZE alignment and .quad with ASM_ADDR. + +2012-05-15 H.J. Lu <hongjiu.lu@intel.com> + + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S: Use + LP_OP(cmp) and R8_LP on dep_mutex pointer. + +2012-05-15 H.J. Lu <hongjiu.lu@intel.com> + + * sysdeps/unix/sysv/linux/x86_64/cancellation.S: Use LP_OP(mov) + to update pointer in memory. Load pointer into RDI_LP. + +2012-05-15 H.J. Lu <hongjiu.lu@intel.com> + + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h + (LLL_STUB_UNWIND_INFO_START): Align label to LP_SIZE instead + of 8. + (LLL_STUB_UNWIND_INFO_END): Likewise. + (lll_timedlock): Load timeout pointer into RDX_LP. + (lll_robust_timedlock): Likewise. + +2012-05-15 Siddhesh Poyarekar <siddhesh@redhat.com> + Jakub Jelinek <jakub@redhat.com> + + [BZ #13613] + * Makefile (tests): Add test cases. + * descr.h (struct pthread): Add a comment describing multiple_threads. + * pthreadP.h (__pthread_multiple_threads): Expand comment to include + single-process case. + * pthread_cancel.c (pthread_cancel): Enable multiple_threads + before setting cancelstate of the thread. + * sysdeps/unix/sysv/linux/libc_multiple_threads.c + (__libc_multiple_threads): Add explanatory comment. + * tst-cancel-self-cancelstate.c: New test case. + * tst-cancel-self-canceltype.c: Likewise. + * tst-cancel-self-cleanup.c: Supporting file for test cases. + * tst-cancel-self-testcancel.c: New test case. + * tst-cancel-self.c: Likewise. + * vars.c: Expand comment to include single-process case. + +2012-05-14 H.J. Lu <hongjiu.lu@intel.com> + + * sysdeps/x86_64/tls.h: Don't include <bits/wordsize.h>. + (tcbhead_t): Remove __x86_64__ check. Align rtld_savespace_sse + to 32 bytes. + +2012-05-14 H.J. Lu <hongjiu.lu@intel.com> + + * sysdeps/pthread/pthread.h (__PTHREAD_RWLOCK_INT_FLAGS_SHARED): + New. + (PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP): Check + __PTHREAD_RWLOCK_INT_FLAGS_SHARED instead of __WORDSIZE. + +2012-05-14 H.J. Lu <hongjiu.lu@intel.com> + + * shlib-versions: Move x86_64-.*-linux.* entry to ... + * sysdeps/x86_64/64/shlib-versions: Here. New file. + * sysdeps/x86_64/x32/shlib-versions: New file. + +2012-05-14 H.J. Lu <hongjiu.lu@intel.com> + + * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: Define x32 + __SIZEOF_PTHREAD_XXX_T. + (__pthread_internal_list): Check __x86_64__ instead of __WORDSIZE. + (pthread_mutex_t): Likewise. + (pthread_rwlock_t): Likewise. + (__PTHREAD_RWLOCK_INT_FLAGS_SHARED): New. Defined if __x86_64__ + is defined. + +2012-05-11 H.J. Lu <hongjiu.lu@intel.com> + + * sysdeps/x86_64/x32/tls.h: New file. + +2012-05-11 H.J. Lu <hongjiu.lu@intel.com> + + * sysdeps/x86_64/tls.h (THREAD_SETMEM): Use uint64_t on 64-bit + integer. + (THREAD_SETMEM_NC): Likewise. + +2012-05-11 H.J. Lu <hongjiu.lu@intel.com> + + * sysdeps/x86_64/tls.h (THREAD_SELF): Replace movq/%q0 with + mov/%0. + +2012-05-11 H.J. Lu <hongjiu.lu@intel.com> + + * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h + (__cleanup_fct_attribute): Check __x86_64__ instead of + __WORDSIZE. + +2012-05-11 H.J. Lu <hongjiu.lu@intel.com> + + * sysdeps/pthread/pthread.h (PTHREAD_MUTEX_INITIALIZER): Check + __PTHREAD_MUTEX_HAVE_PREV instead of __WORDSIZE. + (PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP): Likewise. + (PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP): Likewise. + (PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP): Likewise. + +2012-05-11 H.J. Lu <hongjiu.lu@intel.com> + + * pthread_create.c (start_thread): Check __PTHREAD_MUTEX_HAVE_PREV + instead of __WORDSIZE. + +2012-05-10 Thomas Schwinge <thomas@schwinge.name> + + [BZ #3748] + * sysdeps/pthread/bits/libc-lockP.h (__libc_once_get): New macro. + +2012-05-09 Chung-Lin Tang <cltang@codesourcery.com> + + * sysdeps/unix/sysv/linux/sh/pthread_cond_timedwait.S + (__pthread_cond_timedwait): Use CFI directives. + * sysdeps/unix/sysv/linux/sh/pthread_cond_wait.S + (__pthread_cond_wait): Likewise. + * sysdeps/unix/sysv/linux/sh/sem_timedwait.S (sem_timedwait): Likewise. + * sysdeps/unix/sysv/linux/sh/sem_wait.S (__new_sem_wait): Likewise. + +2012-05-03 David S. Miller <davem@davemloft.net> + + * sysdeps/sparc/sparc64/pthread_spin_unlock.S: Fix thinko, we + always have to return 0, especially for the pthread_spin_init + alias. + * sysdeps/sparc/sparc32/pthread_spin_lock.S: Add missing trailing + newline. + * sysdeps/sparc/sparc32/sparcv9/pthread_spin_lock.S: Likewise. + * sysdeps/sparc/sparc64/pthread_spin_lock.S: Likewise. + +2012-05-02 David S. Miller <davem@davemloft.net> + + * sysdeps/sparc/sparc64/pthread_spin_lock.S: New. + * sysdeps/sparc/sparc64/pthread_spin_lock.c: Delete. + * sysdeps/sparc/sparc64/pthread_spin_unlock.S: New. + * sysdeps/sparc/sparc64/pthread_spin_unlock.c: Delete. + * sysdeps/sparc/sparc64/pthread_spin_trylock.S: New. + * sysdeps/sparc/sparc64/pthread_spin_trylock.c: Delete. + * sysdeps/sparc/sparc64/pthread_spin_init.c: New. + * sysdeps/sparc/sparc32/pthread_spin_lock.S: New. + * sysdeps/sparc/sparc32/pthread_spin_lock.c: Delete. + * sysdeps/sparc/sparc32/pthread_spin_trylock.S: New. + * sysdeps/sparc/sparc32/pthread_spin_trylock.c: Delete. + * sysdeps/sparc/sparc32/sparcv9/pthread_spin_lock.S: New. + * sysdeps/sparc/sparc32/sparcv9/pthread_spin_lock.c: Delete. + * sysdeps/sparc/sparc32/sparcv9/pthread_spin_trylock.S: New. + * sysdeps/sparc/sparc32/sparcv9/pthread_spin_trylock.c: Delete. + * sysdeps/sparc/sparc32/sparcv9/pthread_spin_unlock.S: New. + * sysdeps/sparc/sparc32/sparcv9/pthread_spin_unlock.c: Delete. + * sysdeps/sparc/sparc32/sparcv9/pthread_spin_init.c: New. + +2012-05-02 Allan McRae <allan@archlinux.org> + + * Makefile: (LDFLAGS-tst-tls5): Use $(no-as-needed). + (LDFLAGS-tst-cancel24): Likewise. + +2012-05-02 Paul Pluzhnikov <ppluzhnikov@google.com> + + * sysdeps/i386/pthread_spin_lock.S: New. + * sysdeps/i386/pthread_spin_lock.c: Delete. + * sysdeps/x86_64/pthread_spin_lock.S: New. + * sysdeps/x86_64/pthread_spin_lock.c: Delete. + +2012-04-28 Andreas Schwab <schwab@linux-m68k.org> + + * Makefile ($(objpfx)tst-stack3-mem, $(objpfx)tst-tls6.out): Don't + run when cross-compiling. + +2012-04-26 Siddhesh Poyarekar <siddhesh@redhat.com> + + * sysdeps/pthread/unwind-forcedunwind.c: Include gnu/lib-names.h + instead of libgcc_s.h. + +2012-04-20 Paul Pluzhnikov <ppluzhnikov@google.com> + + * sysdeps/x86_64/tls.h (TLS_GET_FS, TLS_SET_FS): Delete. + +2012-03-27 David S. Miller <davem@davemloft.net> + + * tst-cond16.c (do_test): Use a thread stack size which is either + PTHREAD_STACK_MIN or the page size, whichever is larger. + * tst-cond18.c (do_test): Likewise. + +2012-03-19 H.J. Lu <hongjiu.lu@intel.com> + + * sysdeps/x86_64/pthreaddef.h (CURRENT_STACK_FRAME): Use + register char * __asm__("rsp") to get stack frame. + +2012-03-19 H.J. Lu <hongjiu.lu@intel.com> + + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h (SYS_futex): Use + __NR_futex directly. + +2012-03-19 H.J. Lu <hongjiu.lu@intel.com> + + * unwind.c (unwind_stop): Cast _Unwind_GetCFA return to + _Unwind_Ptr first. + +2012-03-16 David S. Miller <davem@davemloft.net> + + [BZ #13844] + * sysdeps/unix/sysv/linux/libc-lowlevellock.c: Include using <..> + instead of "...". + * sysdeps/unix/sysv/linux/sparc/sparc32/libc-lowlevellock.c: + Delete, not needed. + +2012-03-15 David S. Miller <davem@davemloft.net> + + [BZ #13844] + * sysdeps/unix/sysv/linux/sparc/sparc32/libc-lowlevellock.c: New file. + +2012-03-09 Paul Eggert <eggert@cs.ucla.edu> + + [BZ #13673] + * pt-crti.S: Replace FSF snail mail address with URL. + +2012-03-09 Joseph Myers <joseph@codesourcery.com> + + * sysdeps/pthread/pthread.h (__need_clockid_t, __need_timespec): + Do not define before including <time.h>. + +2012-03-08 David S. Miller <davem@davemloft.net> + + * sysdeps/unix/sysv/linux/sparc/sem_post.c: Update copyright year. + +2012-03-08 Thomas Schwinge <thomas@codesourcery.com> + + * sysdeps/unix/sysv/linux/sh/lowlevellock.S (__lll_timedlock_wait): + Check for timestamp before the Epoch. + + * sysdeps/unix/sysv/linux/sh/sem_timedwait.S (sem_timedwait): Fix + updating nwaiters. + + * tst-sem13.c (do_test): Add another test case. + * sysdeps/unix/sysv/linux/i386/i486/sem_timedwait.S (sem_timedwait): + Fix updating nwaiters. + +2012-03-07 Joseph Myers <joseph@codesourcery.com> + + [BZ #10545] + * sysdeps/pthread/configure.in (libc_cv_forced_unwind): Change + link test to a compile test. + (libc_cv_c_cleanup): Likewise. Declare puts rather than including + <stdio.h>. + * sysdeps/pthread/configure: Regenerated. + +2012-03-07 Ulrich Drepper <drepper@gmail.com> + + * Makefile (distribute): Remove variable. + +2012-01-23 Thomas Schwinge <thomas@codesourcery.com> + + * sysdeps/unix/sysv/linux/sem_timedwait.c (sem_timedwait): Get rid of + superfluous assignment. + * sysdeps/unix/sysv/linux/sparc/sem_timedwait.c (sem_timedwait): + Likewise. + * sysdeps/unix/sysv/linux/sparc/sparc32/sem_timedwait.c + (sem_timedwait): Likewise. + +2012-03-06 Ulrich Drepper <drepper@gmail.com> + + * sysdeps/pthread/bits/libc-lock.h: Move information not needed in + installed headers to... + * sysdeps/pthread/bits/libc-lockP.h: ...here. New file. + +2012-03-06 David S. Miller <davem@davemloft.net> + + * sysdeps/unix/sysv/linux/sparc/sem_post.c (__new_sem_post): Use + atomic_increment and remove unused local variable. + (__old_sem_post): Likewise. + +2012-02-27 David S. Miller <davem@davemloft.net> + + * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h: Don't refer to + non-existing __pthread_attr. + * 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. + +2012-02-26 Ulrich Drepper <drepper@gmail.com> + + * sysdeps/pthread/pthread.h: Define __need_clockid_t for __USE_XOPEN2K. + + * sysdeps/pthread/pthread.h: Define __need_timespec before including + <time.h>. + * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h: Name pthread_attr_t + union. + * 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. + +2012-02-21 Joseph Myers <joseph@codesourcery.com> + + [BZ #13695] + * Makefile (generated): Remove crti.S, crtn.S, defs.h and + pt-initfini.s. + [crti.S not in sysdirs] (omit-deps): Do not append. + [crti.S not in sysdirs] (CFLAGS-pt-initfini.s): Remove variable. + [crti.S not in sysdirs] (pt-initfini.c): Remove vpath directive. + [crti.S not in sysdirs] ($(objpfx)crti.S): Remove rule. + [crti.S not in sysdirs] ($(objpfx)crtn.S): Likewise. + [crti.S not in sysdirs] ($(objpfx)defs.h): Likewise. + [crti.S not in sysdirs] ($(objpfx)crti.o): Likewise. + [crti.S not in sysdirs] ($(objpfx)crtn.o): Likewise. + [crti.S in sysdirs] (extra-objs): Append unconditionally. + [crti.S in sysdirs] ($(objpfx)crti.o): Define rule + unconditionally. + * sysdeps/pthread/pt-initfini.c: Remove file. + +2012-02-16 Richard Henderson <rth@twiddle.net> + + * sysdeps/unix/sysv/linux/s390/s390-32/pt-initfini.c: Remove file. + * sysdeps/unix/sysv/linux/s390/s390-64/pt-initfini.c: Remove file. + +2012-02-15 Kaz Kojima <kkojima@rr.iij4u.or.jp> + + * sysdeps/unix/sysv/linux/sh/pt-initfini.c: Remove file. + +2012-02-16 David S. Miller <davem@davemloft.net> + + * sysdeps/sparc/Makefile: Add -fPIC when building pt-crti.S and crtn.S + +2012-02-15 Marek Polacek <polacek@redhat.com> + + * sysdeps/unix/sysv/linux/x86_64/Makefile: Remove file. + +2012-02-09 Paul Eggert <eggert@cs.ucla.edu> + + Replace FSF snail mail address with URLs, as per GNU coding standards. + +2012-02-08 Andreas Schwab <schwab@linux-m68k.org> + + * Makefile (extra-objs) [crti.S in sysdirs]: Add pt-crti.o. + +2012-02-08 Joseph Myers <joseph@codesourcery.com> + + Support crti.S and crtn.S provided directly by architectures. + * Makefile [crti.S in sysdirs] (omit-deps): Do not append. + [crti.S in sysdirs] (CFLAGS-pt-initfini.s): Do not define variable. + [crti.S in sysdirs] ($(objpfx)pt-initfini.s): Disable rule. + [crti.S in sysdirs] ($(objpfx)crti.S): Likewise. + [crti.S in sysdirs] ($(objpfx)crtn.S): Likewise. + [crti.S in sysdirs] ($(objpfx)defs.h): Likewise. + [crti.S in sysdirs] ($(objpfx)crti.o): Likewise. + [crti.S in sysdirs] ($(objpfx)crtn.o): Likewise. + [crti.S in sysdirs] (pt-initfini.c): Remove vpath directive. + [crti.S in sysdirs] ($(objpfx)crti.o): New rule. + * pt-crti.S: New file. + * sysdeps/unix/sysv/linux/i386/Makefile: Remove file. + +2012-02-03 Joseph Myers <joseph@codesourcery.com> + + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Use + macros for PIC register setup. + * sysdeps/unix/sysv/linux/i386/i486/sem_post.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/sem_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/sem_trywait.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/sem_wait.S: Likewise. + * sysdeps/unix/sysv/linux/i386/pthread_once.S: Likewise. + +2012-01-11 Marek Polacek <polacek@redhat.com> + + * forward.c (FORWARD_NORETURN): Define macro. + (__pthread_unwind): Use FORWARD_NORETURN macro to avoid warning. + (__pthread_exit): Likewise. + +2012-01-10 Ulrich Drepper <drepper@gmail.com> + + * sysdeps/pthread/pthread.h: Add const attribute to pthread_equal. + + * pthreadP.h: Add noreturn to __pthread_exit. + * sysdeps/pthread/pthread-functions.h: Likewise for ptr___pthread_exit. + +2011-12-30 Adhemerval Zanella <azanella@linux.vnet.ibm.com> + + * sysdeps/unix/sysv/linux/aio_misc.h (__aio_create_helper_thread): + Call pthread_attr_setstacksize() with result of + __pthread_get_minstack() to account for application TLS usage. + +2012-01-08 Marek Polacek <polacek@redhat.com> + + * sysdeps/unix/sysv/linux/mq_notify.c: Include <nptl/pthreadP.h>. + +2012-01-07 Ulrich Drepper <drepper@gmail.com> + + [BZ #13553] + * pthreadP.h: Use const instead of __const. + * semaphore.h: Likewise. + * sysdeps/pthread/bits/libc-lock.h: Likewise. + * sysdeps/pthread/bits/sigthread.h: Likewise. + * sysdeps/pthread/pthread.h: Likewise. + + * Makefile: Remove elf=yes test, only ELF is supported. + + * shlib-versions: Remove entries for ports architectures. + + In case anyone cares, the IA-64 architecture could move to ports. + * sysdeps/ia64/*: Removed. + * sysdeps/unix/sysv/linux/ia64/*: Removed. + +2011-12-22 Ulrich Drepper <drepper@gmail.com> + + * sysdeps/pthread/gai_misc.h (__gai_create_helper_thread): Use + __pthread_get_minstack. + * sysdeps/unix/sysv/linux/mq_notify.c (init_mq_netlink): Likewise. + + [BZ #13088] + * sysdeps/unix/sysv/linux/timer_routines.c: Get minimum stack size + through __pthread_get_minstack. + * nptl-init.c (__pthread_initialize_minimal_internal): Get page size + directly from _rtld_global_ro. + (__pthread_get_minstack): New function. + * pthreadP.h: Declare __pthread_get_minstack. + * Versions (libpthread) [GLIBC_PRIVATE]: Add __pthread_get_minstack. + +2011-12-21 Ulrich Drepper <drepper@gmail.com> + + [BZ #13515] + * sysdeps/unix/sysv/linux/pthread_getname.c (pthread_getname_np): + Correct reading name from file. + +2011-12-14 Carlos O'Donell <carlos@systemhalted.org> + + * allocatestack.c (allocate_stack): Return errno on failure. + +2011-12-14 Jeff Law <law@redhat.com> + + [BZ #5245] + * pthread_create.c (__pthread_create_2_1): Translate ENOMEM to EAGAIN. + +2011-11-28 Andreas Schwab <schwab@redhat.com> + + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Handle + EAGAIN from FUTEX_WAIT_REQUEUE_PI. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S: Likewise. + +2011-11-15 Ulrich Drepper <drepper@gmail.com> + + * pthread_getattr_np.c (pthread_getattr_np): Set FD_CLOEXEC for + /proc/self/maps. + +2011-10-29 Ulrich Drepper <drepper@gmail.com> + + [BZ #13358] + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S + (__pthread_cond_timedwait): Initialize %r15 correctly also for code + path for kernels with FUTEX_CLOCK_REALTIME. + Debugged by H.J. Lu <hjl.tools@gmail.com>. + +2011-10-27 Andreas Schwab <schwab@redhat.com> + + [BZ #13344] + * sysdeps/pthread/pthread.h: Use __THREADNL instead of __THREAD + for memory synchronization functions. + * semaphore.h: Likewise. + +2011-10-24 Ulrich Drepper <drepper@gmail.com> + + * tst-cancel7.c: Avoid warning. + * tst-mutex6.c: Likewise. + * tst-mutex9.c: Likewise. + * tst-mutexpi6.c: Likewise. + +2011-10-23 Ulrich Drepper <drepper@gmail.com> + + * sysdeps/i386/tls.h: Remove #include <list.h>. + +2011-10-15 Ulrich Drepper <drepper@gmail.com> + + * pthread_create.c (start_thread): Call __ctype_init. + +2011-09-15 Andreas Schwab <schwab@redhat.com> + + * sysdeps/pthread/list.h: Define only list_t if __need_list_t is + defined. + (list_add): Add atomic_write_barrier. + * descr.h: Define __need_list_t before including <list.h>. + * nptl-init.c: Include <list.h> + * allocatestack.c: Likewise. + +2011-09-11 Ulrich Drepper <drepper@gmail.com> + + * sysdeps/i386/tls.h: Remove HAVE_TLS_SUPPORT test. + * 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. + +2011-09-10 Ulrich Drepper <drepper@gmail.com> + + * sysdeps/pthread/malloc-machine.h: Define MUTEX_INITIALIZER. + + * sysdeps/unix/sysv/linux/i386/i486/sem_post.S: Don't handle + !USE___THREAD. + * sysdeps/unix/sysv/linux/i386/i486/sem_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/sem_trywait.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/sem_wait.S: Likewise. + * sysdeps/unix/sysv/linux/ia64/sysdep-cancel.h: Likewise. + * sysdeps/unix/sysv/linux/sh/sem_post.S: Likewise. + * sysdeps/unix/sysv/linux/sh/sem_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/sh/sem_trywait.S: Likewise. + * sysdeps/unix/sysv/linux/sh/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_trywait.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/sem_wait.S: Likewise. + + * tst-tls1.c: Support for __thread is now mandatory. + * tst-tls2.c: Likewise. + * tst-tls3.c: Likewise. + * tst-tls3mod.c: Likewise. + * tst-tls4.c: Likewise. + * tst-tls4moda.c: Likewise. + * tst-tls4modb.c: Likewise. + * tst-tls5.h: Likewise. + +2011-09-08 Ulrich Drepper <drepper@gmail.com> + + [BZ #12403] + * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedwrlock.S + (pthread_rwlock_timedwrlock): Use correct macro in test. + Patch by H.J. Lu <hongjiu.lu@intel.com>. + +2011-09-06 Ulrich Drepper <drepper@gmail.com> + + * sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S (sem_timedwait): Don't + use gettimeofday vsyscall, just call gettimeofday. + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/lowlevelrobustlock.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_cond_timedwait.S: Likewise. + Simplify __vdso_clock_gettime use. + +2011-09-05 David S. Miller <davem@davemloft.net> + + * sysdeps/unix/sysv/linux/sem_timedwait.c (do_futex_timed_wait): + New function. + (sem_timedwait): Call it to force an exception region around + the async cancel enable and the futex operation. + * sysdeps/unix/sysv/linux/sparc/sem_timedwait.c: Likewise. + * sysdeps/unix/sysv/linux/sparc/sparc32/sem_timedwait.c: Likewise. + * sysdeps/unix/sysv/linux/sem_wait.c (do_futex_wait): New function. + (__new_sem_wait): Call it to force an exception region around + the async cancel enable and the futex operation. + * sysdeps/unix/sysv/linux/sparc/sem_wait.c: Likewise. + * sysdeps/unix/sysv/linux/sparc/sparc32/sem_wait.c: Likewise. + +2011-08-31 Andreas Schwab <schwab@redhat.com> + + * allocatestack.c (setxid_mark_thread): Ensure that the exiting + thread is woken up. + +2011-08-20 David S. Miller <davem@davemloft.net> + + * Makefile (tst-cleanup0.out): Fix typo in output redirection. + +2011-08-14 Roland McGrath <roland@hack.frob.com> + + * sysdeps/i386/pthreaddef.h (TCB_ALIGNMENT): Set to 64, optimal on Atom. + * sysdeps/x86_64/pthreaddef.h (TCB_ALIGNMENT): Likewise. + +2011-08-08 Andreas Schwab <schwab@redhat.com> + + * sysdeps/unix/sysv/linux/x86_64/cancellation.S: Maintain aligned + stack. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S: Likewise. + +2011-07-22 Ulrich Drepper <drepper@gmail.com> + + * sysdeps/pthread/unwind-forcedunwind.c (_Unwind_Resume): Add read + barrier. + (__gcc_personality_v0): Likewise. + (_Unwind_ForcedUnwind): Likewise. + (_Unwind_GetCFA): Likewise. + +2011-07-14 Roland McGrath <roland@hack.frob.com> + + * allocatestack.c (__reclaim_stacks): Use uintptr_t cast rather than + UINTMAX_C. + +2011-06-30 Ulrich Drepper <drepper@gmail.com> + + * nptl-init.c (__nptl_set_robust): New function. + (pthread_functions): Add reference. + * npthreadP.h: Declare __nptl_set_robust. + * sysdeps/pthread/pthread-functions.h (pthread_functions): Add + ptr_set_robust member. + * sysdeps/unix/sysv/linux/fork.c: Call set_robust_list syscall in + child if threads are used. + +2011-06-14 Andreas Jaeger <aj@suse.de> + + * pthread_rwlock_init.c: Include <string.h> for memset declaration. + +2011-05-11 Ulrich Drepper <drepper@gmail.com> + + [BZ #386] + * allocatestack.c (allocate_stack): Convert ENOMEM error to EAGAIN. + +2011-04-10 Ulrich Drepper <drepper@gmail.com> + + [BZ #12650] + * allocatestack.c (get_cached_stack): Deallocate DTV entries before + clearing memory. + Patch partly by Robert Rex <robert.rex@exasol.com>. + +2011-01-19 Roland McGrath <roland@redhat.com> + + * pthread_cond_wait.c (__pthread_cond_wait): Fix comment typo. + * pthread_cond_timedwait.c (__pthread_cond_timedwait): Likewise. + * pthread_rwlock_rdlock.c (__pthread_rwlock_rdlock): Likewise. + * pthread_rwlock_wrlock.c (__pthread_rwlock_wrlock): Likewise. + * pthread_rwlock_timedrdlock.c (pthread_rwlock_timedrdlock): Likewise. + * pthread_rwlock_timedwrlock.c (pthread_rwlock_timedwrlock): Likewise. + +2011-01-16 Andreas Schwab <schwab@linux-m68k.org> + + * Makefile (test-extras): Add tst-cleanup4aux. + +2011-01-14 Ulrich Drepper <drepper@gmail.com> + + [BZ #10563] + * sysdeps/pthread/setxid.h (__SETXID_1): Add cast to assignment. + (__SETXID_2): Likewise. + (__SETXID_3): Likewise. + +2011-01-13 Ulrich Drepper <drepper@gmail.com> + + [BZ #10484] + * Versions [libc] (GLIBC_PRIVATE): Export __libc_alloca_cutoff. + * alloca_cutoff.c: Add libc_hidden_def. + +2010-10-13 H.J. Lu <hongjiu.lu@intel.com> + + [BZ #12113] + * sysdeps/x86_64/pthreaddef.h (TCB_ALIGNMENT): Changed to 32. + * sysdeps/x86_64/tls.h (TLS_TCB_ALIGN): Defined with alignment + of "struct pthread". + +2010-09-21 Andreas Schwab <schwab@redhat.com> + + * sysdeps/pthread/pthread.h (pthread_cleanup_push) + [!__EXCEPTIONS]: Mangle local variable not_first_call. + (pthread_cleanup_push_defer_np): Likewise. + +2010-09-03 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/allocalim.h (__libc_use_alloca): Expect blocks are + small. + +2010-08-10 Dinakar Guniguntala <dino@in.ibm.com> + Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> + + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_signal.S: If + FUTEX_WAKE_OP fails make sure to call FUTEX_WAKE instead. + +2010-08-12 H.J. Lu <hongjiu.lu@intel.com> + + * sysdeps/unix/sysv/linux/i386/Makefile: New file. + +2010-05-01 Alan Modra <amodra@gmail.com> + + * sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h + (PSEUDO): Use correct cr save. Don't use wrong parm save area + to save temps. Correct cfi for possible later frame manipulation. + (DOCARGS_1, UNDOCARGS_1): Use the correct parm save area. + (DOCARGS_2, UNDOCARGS_2, DOCARGS_3, UNDOCARGS_3): Likewise. + (DOCARGS_4, UNDOCARGS_4, DOCARGS_5, UNDOCARGS_5): Likewise. + (DOCARGS_6, UNDOCARGS_6): Likewise. + (CENABLE, CDISABLE): Add nops for non-shared calls. + +2010-07-06 Andreas Schwab <schwab@redhat.com> + + * sysdeps/unix/sysv/linux/pthread_getname.c (pthread_getname_np): + Fix type mismatch. + +2010-07-03 Ulrich Drepper <drepper@redhat.com> + + * tst-abstime.c (do_test): Some more cleanups + +2010-07-02 Ulrich Drepper <drepper@redhat.com> + + * tst-abstime.c: Correct testing and add test for sem_timedwait. + +2010-07-01 Andreas Schwab <schwab@redhat.com> + Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add tst-abstime. + * tst-abstime.c: New file. + * sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S + (__lll_timedlock_wait): Check for timestamp before the Epoch. + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.S + (__lll_timedlock_wait): Likewise. + * sysdeps/unix/sysv/linux/x86_64/lowlevelrobustlock.S + (__lll_robust_timedlock_wait): Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S + (__pthread_cond_timedwait): Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedrdlock.S + (pthread_rwlock_timedrdlock): Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedwrlock.S + (pthread_rwlock_timedwrlock): Likewise. + * sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S (sem_timedwait): + Likewise. + +2010-07-01 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tst-_res1): Add tst-_res1mod1 to dependency list. + +2010-06-01 Takashi Yoshii <takashi.yoshii.zj@renesas.com> + + * sysdeps/unix/sysv/linux/sh/lowlevellock.S: Fix incorrect + location of ifndef __ASSUME_FUTEX_CLOCK_REALTIME. + +2010-04-09 Ulrich Drepper <drepper@redhat.com> + + [BZ #11390] + * sysdeps/unix/sysv/linux/pthread_getname.c: New file. + * sysdeps/unix/sysv/linux/pthread_setname.c: New file. + * nptl/sysdeps/pthread/pthread.h: Declare pthread_getname and + pthread_setname. + * Makefile (libpthread-routines): Add pthread_getname and + pthread_setname. + * Versions: Export pthread_getname and pthread_setname for GLIBC_2.12. + +2010-04-05 Thomas Schwinge <thomas@schwinge.name> + + * sysdeps/pthread/unwind-resume.c: Moved to main tree sysdeps/gnu/. + * sysdeps/pthread/rt-unwind-resume.c: Likewise. + * sysdeps/pthread/Makefile: Remove csu section and rt section's + unwind-resume bits, now in main tree sysdeps/gnu/Makefile instead. + +2010-03-23 Luis Machado <luisgpm@br.ibm.com> + + * pthread_cond_timedwait.c: Add check for + HAVE_CLOCK_GETTIME_VSYSCALL to use VDSO whenever possible. + (pthread_cond_timedwait): Use INTERNAL_VSYSCALL instead of + INTERNAL_SYSCALL. + +2010-03-09 Ulrich Drepper <drepper@redhat.com> + + * pthread_create.c (__pthread_create_2_1): If priorities are incorrect + and the call fails wake eventually waiting setxid threads. Don't free + stack here if we try starting a thread. + * sysdeps/pthread/createthread.c (do_clone): Only wake setxid waiter + if the clone call failed. + +2010-03-08 Andreas Schwab <schwab@redhat.com> + + * pthread_create.c (__pthread_create_2_1): Don't set setxid_futex. + * allocatestack.c (get_cached_stack): Set setxid_futex. + (allocate_stack): Likewise. + +2010-03-05 Andreas Schwab <schwab@redhat.com> + Ulrich Drepper <drepper@redhat.com> + + * allocatestack.c (setxid_mark_thread): Delay handling of thread if + it is creating a thread or it is just being created. + * pthread_create.c (start_thread): Wake setxid thread if it is + waiting. + (__pthread_create_2_1): Initialize setxid_futex. + * sysdeps/pthread/createthread.c (do_clone): Wake setxid thread if it + is waiting. + +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. --- /dev/null +++ b/fbtl/DESIGN-barrier.txt @@ -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; +} --- /dev/null +++ b/fbtl/DESIGN-condvar.txt @@ -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); +} --- /dev/null +++ b/fbtl/DESIGN-rwlock.txt @@ -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); +} --- /dev/null +++ b/fbtl/DESIGN-sem.txt @@ -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(); +} --- /dev/null +++ b/fbtl/DESIGN-systemtap-probes.txt @@ -0,0 +1,89 @@ +Systemtap is a dynamic tracing/instrumenting tool available on Linux. Probes +that are not fired at run time have close to zero overhead. + +The following probes are available for NPTL: + +Thread creation & Join Probes +============================= +pthread_create - probe for pthread_create + arg1 = pointer (pthread_t*) to thread + arg2 = pointer (pthread_attr_t*) to attr + arg3 = pointer (void *) to start_routine + arg4 = arguments to start_routine +pthread_start - probe for actual thread creation + arg1 = struct pthread (members include thread ID, process ID) + arg2 = address of start_routine + arg3 = pointer to the list of arguments +pthread_join - probe for pthread_join + arg1 = thread ID +pthread_join_ret - probe for pthread_join return + arg1 = thread ID + arg2 = return value + +Lock-related Probes +=================== +mutex_init - probe for pthread_mutex_init + arg1 = address of mutex lock +mutex_acquired - probe for succ. return of pthread_mutex_lock + arg1 = address of mutex lock +mutex_timedlock_acquired - probe for succ. return of pthread_mutex_timedlock + arg1 = address of mutex lock +mutex_entry - probe for entry to the pthread_mutex_lock function + arg1 = address of mutex lock +mutex_timedlock_entry - probe for entry to the pthread_mutex_timedlock function + arg1 = address of mutex lock, arg2 = address of timespec +mutex_release - probe for pthread_mutex_unlock after the successful release of a + mutex lock + arg1 = address of mutex lock +mutex_destroy - probe for pthread_mutex_destroy + arg1 = address of mutex lock + +wrlock_entry - probe for entry to the pthread_rwlock_wrlock function + arg1 = address of rw lock +rdlock_entry - probe for entry to the pthread_rwlock_rdlock function + arg1 = address of rw lock + +rwlock_destroy - probe for pthread_rwlock_destroy + arg1 = address of rw lock +wrlock_acquire_write - probe for pthread_rwlock_wrlock (after getting the lock) + arg1 = address of rw lock +rdlock_acquire_read - probe for pthread_rwlock_rdlock after successfully getting + the lock + arg1 = address of rw lock +rwlock_unlock - probe for pthread_rwlock_unlock + arg1 = address of rw lock + +lll_lock_wait - probe in low-level (assembly language) locking code, only fired + when futex/FUTEX_WAIT is called (i.e. when trying to acquire a + contented lock) + arg1 = pointer to futex + arg2 = flags passed to the futex system call +lll_lock_wait_private - probe in low-level (assembly language) locking code, + only fired when futex/FUTEX_WAIT is called (i.e. when + trying to acquire a contented lock) + arg1 = pointer to futex + +lll_futex_wake - probe in low-level (assembly language) locking code, only fired + when futex (FUTEX_WAKE) is called + arg1 = pointer to futex + arg2 = number of processes to wake + arg3 = additional flags + +Condition variable Probes +========================= +cond_init - probe for pthread_cond_init + arg1 = condition + arg2 = attr +cond_destroy - probe for pthread_cond_destroy + arg1 = cond +cond_wait - probe for pthread_cond_wait + arg1 = condition + arg2 = mutex lock +cond_timedwait - probe for pthread_cond_timedwait + arg1 = condition + arg2 = mutex lock + arg3 = timespec +cond_signal - probe for pthread_cond_signal + arg1 = condition +cond_broadcast - probe for pthread_cond_broadcast + arg1 = condition --- /dev/null +++ b/fbtl/Makeconfig @@ -0,0 +1,32 @@ +# Copyright (C) 2002-2013 Free Software Foundation, Inc. +# This file is part of the GNU C Library. +# Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +# The GNU C Library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. + +# The GNU C Library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. + +# You should have received a copy of the GNU Lesser General Public +# License along with the GNU C Library; if not, see +# <http://www.gnu.org/licenses/>. + +# Makeconfig fragment for NPTL add-on. +# This gets included at the end of the main glibc Makeconfig. + +have-thread-library = yes + +shared-thread-library = $(common-objpfx)fbtl/libpthread_nonshared.a \ + $(common-objpfx)fbtl/libpthread.so +static-thread-library = $(common-objpfx)fbtl/libpthread.a + +rpath-dirs += fbtl + +# This makes for ptw-*.? object rules in sysd-rules. +ptw-CPPFLAGS := -DPTW +sysd-rules-patterns += ptw-%:% --- /dev/null +++ b/fbtl/Makefile @@ -0,0 +1,642 @@ +# Copyright (C) 2002-2013 Free Software Foundation, Inc. +# This file is part of the GNU C Library. + +# The GNU C Library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. + +# The GNU C Library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. + +# You should have received a copy of the GNU Lesser General Public +# License along with the GNU C Library; if not, see +# <http://www.gnu.org/licenses/>. + +# +# Sub-makefile for NPTL portion of the library. +# +subdir := fbtl + +headers := pthread.h semaphore.h bits/semaphore.h + +extra-libs := libpthread +extra-libs-others := $(extra-libs) +install-lib-ldscripts := libpthread.so + +routines = alloca_cutoff forward libc-lowlevellock libc-cancellation \ + libc-cleanup +shared-only-routines = forward + +libpthread-routines = nptl-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_mutexattr_init pthread_mutexattr_destroy \ + pthread_mutexattr_getpshared \ + pthread_mutexattr_setpshared \ + pthread_mutexattr_gettype pthread_mutexattr_settype \ + pthread_rwlock_init pthread_rwlock_destroy \ + pthread_rwlock_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 \ + old_pthread_cond_init old_pthread_cond_destroy \ + old_pthread_cond_wait old_pthread_cond_timedwait \ + old_pthread_cond_signal old_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 \ + old_pthread_atfork pthread_atfork \ + pthread_getcpuclockid \ + pthread_clock_gettime pthread_clock_settime \ + shm-directory \ + 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 ptw-sigsuspend \ + pt-raise pt-system \ + flockfile ftrylockfile funlockfile \ + sigaction \ + herrno res pt-allocrtsig \ + pthread_kill_other_threads \ + pthread_getaffinity pthread_setaffinity \ + pthread_attr_getaffinity pthread_attr_setaffinity \ + cleanup_routine unwind-forcedunwind \ + pthread_setname pthread_getname \ + pthread_setattr_default_np pthread_getattr_default_np + +# lowlevelrobustlock +# pthread_sigqueue + +# post linuxthreads interfaces + +# pthread_mutexattr_getrobust pthread_mutexattr_setrobust \ +# pthread_mutex_consistent \ +# pthread_mutexattr_getprotocol \ +# pthread_mutexattr_setprotocol \ +# pthread_mutexattr_getprioceiling \ +# pthread_mutexattr_setprioceiling tpp \ +# pthread_mutex_getprioceiling \ +# pthread_mutex_setprioceiling \ + +# commented out also in nptl + +# pthread_setuid pthread_seteuid pthread_setreuid \ +# pthread_setresuid \ +# pthread_setgid pthread_setegid pthread_setregid \ +# pthread_setresgid + +libpthread-shared-only-routines = version pt-allocrtsig unwind-forcedunwind +libpthread-static-only-routines = pthread_atfork + +# 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. + +# nptl-init.c contains sigcancel_handler(). +CFLAGS-nptl-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-open.c = -fexceptions -fasynchronous-unwind-tables +CFLAGS-open64.c = -fexceptions -fasynchronous-unwind-tables +CFLAGS-pause.c = -fexceptions -fasynchronous-unwind-tables +CFLAGS-recv.c = -fexceptions -fasynchronous-unwind-tables +CFLAGS-send.c = -fexceptions -fasynchronous-unwind-tables + +CFLAGS-pt-system.c = -fexceptions + + +tests = tst-typesizes \ + tst-attr1 tst-attr2 tst-attr3 tst-default-attr \ + tst-mutex1 tst-mutex2 tst-mutex3 tst-mutex4 tst-mutex5 tst-mutex6 \ + tst-mutex7 tst-mutex8 tst-mutex9 tst-mutex5a tst-mutex7a \ + tst-spin1 tst-spin2 tst-spin3 \ + 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-cond22 tst-cond23 \ + tst-rwlock1 tst-rwlock2 tst-rwlock2a 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-once1 tst-once2 tst-once3 tst-once4 \ + tst-key1 tst-key2 tst-key3 tst-key4 \ + tst-sem1 tst-sem2 tst-sem3 tst-sem4 tst-sem5 tst-sem6 tst-sem7 \ + tst-sem8 tst-sem9 tst-sem10 tst-sem11 tst-sem12 tst-sem13 tst-sem14 \ + tst-barrier1 tst-barrier2 tst-barrier3 tst-barrier4 \ + tst-align tst-align2 tst-align3 \ + tst-basic1 tst-basic2 tst-basic3 tst-basic4 tst-basic5 tst-basic6 \ + tst-basic7 \ + tst-kill1 tst-kill2 tst-kill3 tst-kill4 tst-kill5 tst-kill6 \ + tst-raise1 \ + tst-join1 tst-join2 tst-join3 tst-join4 tst-join5 tst-join6 \ + tst-detach1 \ + tst-eintr1 tst-eintr2 tst-eintr3 tst-eintr4 tst-eintr5 \ + tst-tsd1 tst-tsd2 tst-tsd3 tst-tsd4 tst-tsd5 tst-tsd6 \ + tst-tls1 tst-tls2 \ + tst-fork1 tst-fork2 tst-fork3 tst-fork4 \ + tst-atfork1 \ + tst-cancel1 tst-cancel2 tst-cancel3 tst-cancel4 tst-cancel5 \ + tst-cancel6 tst-cancel7 tst-cancel8 tst-cancel9 tst-cancel10 \ + tst-cancel11 tst-cancel12 tst-cancel13 tst-cancel14 tst-cancel15 \ + tst-cancel16 tst-cancel17 tst-cancel18 tst-cancel19 tst-cancel20 \ + tst-cancel21 tst-cancel22 tst-cancel23 tst-cancel24 tst-cancel25 \ + tst-cancel-self tst-cancel-self-cancelstate \ + tst-cancel-self-canceltype tst-cancel-self-testcancel \ + tst-cleanup0 tst-cleanup1 tst-cleanup2 tst-cleanup3 tst-cleanup4 \ + tst-flock1 tst-flock2 \ + tst-signal1 tst-signal2 tst-signal3 tst-signal4 tst-signal5 \ + tst-signal6 tst-signal7 \ + tst-exec1 tst-exec2 tst-exec3 tst-exec4 \ + tst-exit1 tst-exit2 tst-exit3 \ + tst-stdio1 tst-stdio2 \ + tst-stack1 tst-stack2 tst-stack3 tst-pthread-getattr \ + tst-pthread-attr-affinity \ + tst-unload \ + tst-dlsym1 \ + tst-sysconf \ + tst-locale1 tst-locale2 \ + tst-umask1 \ + tst-popen1 \ + tst-clock1 \ + tst-context1 \ + tst-sched1 \ + tst-backtrace1 \ + tst-abstime \ + tst-vfork1 tst-vfork2 tst-vfork1x tst-vfork2x \ + tst-getpid1 tst-getpid2 tst-getpid3 \ + tst-initializers1 $(patsubst %,tst-initializers1-%,c89 gnu89 c99 gnu99) + +# These tests do not even compile due to missing pthread_* functions +# tst-mutexpi1 tst-mutexpi2 tst-mutexpi3 tst-mutexpi4 tst-mutexpi5 \ +# tst-mutexpi5a tst-mutexpi6 tst-mutexpi7 tst-mutexpi7a tst-mutexpi8 \ +# tst-mutexpi9 \ +# tst-cond24 tst-cond25 \ +# tst-cond-except \ +# tst-robust1 tst-robust2 tst-robust3 tst-robust4 tst-robust5 \ +# tst-robust6 tst-robust7 tst-robust8 tst-robust9 \ +# tst-robustpi1 tst-robustpi2 tst-robustpi3 tst-robustpi4 tst-robustpi5 \ +# tst-robustpi6 tst-robustpi7 tst-robustpi8 tst-robustpi9 \ + +xtests = tst-setuid1 tst-setuid1-static tst-mutexpp1 tst-mutexpp6 tst-mutexpp10 +test-srcs = tst-oddstacklimit + +# Files which must not be linked with libpthread. +tests-nolibpthread = tst-unload + +gen-as-const-headers = pthread-errnos.sym + +LDFLAGS-pthread.so = -Wl,--enable-new-dtags,-z,nodelete,-z,initfirst + +include ../Makeconfig + +tests += tst-cancelx2 tst-cancelx3 tst-cancelx4 tst-cancelx5 \ + tst-cancelx6 tst-cancelx7 tst-cancelx8 tst-cancelx9 tst-cancelx10 \ + tst-cancelx11 tst-cancelx12 tst-cancelx13 tst-cancelx14 tst-cancelx15 \ + tst-cancelx16 tst-cancelx17 tst-cancelx18 tst-cancelx20 tst-cancelx21 \ + tst-cleanupx0 tst-cleanupx1 tst-cleanupx2 tst-cleanupx3 tst-cleanupx4 \ + tst-oncex3 tst-oncex4 +ifeq ($(build-shared),yes) +tests += tst-atfork2 tst-tls3 tst-tls4 tst-tls5 tst-_res1 tst-fini1 \ + tst-stackguard1 +tests-nolibpthread += tst-fini1 +ifeq ($(have-z-execstack),yes) +tests += tst-execstack +endif +endif + +modules-names = tst-atfork2mod tst-tls3mod tst-tls4moda tst-tls4modb \ + tst-tls5mod tst-tls5moda tst-tls5modb tst-tls5modc \ + tst-tls5modd tst-tls5mode tst-tls5modf \ + tst-_res1mod1 tst-_res1mod2 tst-execstack-mod tst-fini1mod +extra-test-objs += $(addsuffix .os,$(strip $(modules-names))) tst-cleanup4aux.o +test-extras += $(modules-names) tst-cleanup4aux +test-modules = $(addprefix $(objpfx),$(addsuffix .so,$(modules-names))) + +tst-atfork2mod.so-no-z-defs = yes +tst-tls3mod.so-no-z-defs = yes +tst-tls5mod.so-no-z-defs = yes +tst-tls5moda.so-no-z-defs = yes +tst-tls5modb.so-no-z-defs = yes +tst-tls5modc.so-no-z-defs = yes +tst-tls5modd.so-no-z-defs = yes +tst-tls5mode.so-no-z-defs = yes +tst-tls5modf.so-no-z-defs = yes + +ifeq ($(build-shared),yes) +# Build all the modules even when not actually running test programs. +tests: $(test-modules) +endif + +ifeq ($(build-shared),yes) + +# Set the `multidir' variable by grabbing the variable from the compiler. +# We do it once and save the result in a generated makefile. +-include $(objpfx)multidir.mk +$(objpfx)multidir.mk: $(common-objpfx)config.make + $(make-target-directory) + dir=`$(CC) $(CFLAGS) $(CPPFLAGS) -print-multi-directory`; \ + echo "multidir := $$dir" > $@T + mv -f $@T $@ + +crti-objs := crti.o +crtn-objs := crtn.o +ifneq (,$(patsubst .,,$(multidir))) +generated-dirs := $(firstword $(subst /, , $(multidir))) +crti-objs += $(multidir)/crti.o +crtn-objs += $(multidir)/crtn.o +$(objpfx)$(multidir): + mkdir -p $@ +endif +extra-objs += $(crti-objs) $(crtn-objs) +extra-objs += pt-crti.o +endif + +CFLAGS-flockfile.c = $(libio-mtsafe) +CFLAGS-ftrylockfile.c = $(libio-mtsafe) +CFLAGS-funlockfile.c = $(libio-mtsafe) + +link-libc-static := $(common-objpfx)libc.a $(static-gnulib) \ + $(common-objpfx)libc.a + +tests-static += tst-locale1 tst-locale2 tst-stackguard1-static \ + tst-cancel21-static tst-cancel24-static tst-cond8-static \ + tst-mutex8-static tst-sem11-static \ + tst-sem12-static +# This test does not even compile due to missing pthread_* functions +# tst-mutexpi8-static +tests += tst-stackguard1-static tst-cancel21-static tst-cancel24-static \ + tst-cond8-static tst-mutex8-static \ + tst-sem11-static tst-sem12-static +# This test does not even compile due to missing pthread_* functions +# tst-mutexpi8-static + +xtests-static += tst-setuid1-static + +# These tests are linked with libc before libpthread +tests-reverse += tst-cancel5 tst-cancel23 tst-vfork1x tst-vfork2x + +include ../Rules + +ifeq (yes,$(build-shared)) +# Make sure these things are built in the `make lib' pass so they can be used +# to run programs during the `make others' pass. +lib-noranlib: $(addprefix $(objpfx),$(extra-objs)) + +# What we install as libpthread.so for programs to link against is in fact a +# link script. It contains references for the various libraries we need. +# The libpthread.so object is not complete since some functions are only +# defined in libpthread_nonshared.a. +# We need to use absolute paths since otherwise local copies (if they exist) +# of the files are taken by the linker. +install: $(inst_libdir)/libpthread.so + +$(inst_libdir)/libpthread.so: $(common-objpfx)format.lds \ + $(objpfx)libpthread.so$(libpthread.so-version) \ + $(inst_libdir)/$(patsubst %,$(libtype.oS),\ + $(libprefix)pthread) \ + $(+force) + (echo '/* GNU ld script';\ + echo ' Use the shared library, but some functions are only in';\ + echo ' the static library, so try that secondarily. */';\ + cat $<; \ + echo 'GROUP ( $(slibdir)/libpthread.so$(libpthread.so-version)' \ + '$(libdir)/$(patsubst %,$(libtype.oS),$(libprefix)pthread)'\ + ')' \ + ) > $@.new + mv -f $@.new $@ +endif + + +# 'pthread_self' is a simple memory or register load. Setting up the +# stack frame is more work than the actual operation. Disable the +# frame creation entirely. This will help applications which call the +# function frequently to get a thread-specific handle. +CFLAGS-pthread_self.os += -fomit-frame-pointer + +# Run the cancellation and cleanup tests also for the modern, exception-based +# implementation. For this we have to pass the -fexceptions parameter. +CFLAGS-tst-cancelx2.c += -fexceptions +CFLAGS-tst-cancelx3.c += -fexceptions +CFLAGS-tst-cancelx4.c += -fexceptions +CFLAGS-tst-cancelx5.c += -fexceptions +CFLAGS-tst-cancelx6.c += -fexceptions +CFLAGS-tst-cancelx7.c += -fexceptions +CFLAGS-tst-cancelx8.c += -fexceptions +CFLAGS-tst-cancelx9.c += -fexceptions +CFLAGS-tst-cancelx10.c += -fexceptions +CFLAGS-tst-cancelx11.c += -fexceptions +CFLAGS-tst-cancelx12.c += -fexceptions +CFLAGS-tst-cancelx13.c += -fexceptions +CFLAGS-tst-cancelx14.c += -fexceptions +CFLAGS-tst-cancelx15.c += -fexceptions +CFLAGS-tst-cancelx16.c += -fexceptions +CFLAGS-tst-cancelx17.c += -fexceptions +CFLAGS-tst-cancelx18.c += -fexceptions +CFLAGS-tst-cancelx20.c += -fexceptions -fasynchronous-unwind-tables +CFLAGS-tst-cancelx21.c += -fexceptions -fasynchronous-unwind-tables +CFLAGS-tst-cleanupx0.c += -fexceptions -fasynchronous-unwind-tables +CFLAGS-tst-cleanupx1.c += -fexceptions -fasynchronous-unwind-tables +CFLAGS-tst-cleanupx2.c += -fexceptions +CFLAGS-tst-cleanupx3.c += -fexceptions +CFLAGS-tst-cleanupx4.c += -fexceptions +CFLAGS-tst-oncex3.c += -fexceptions +CFLAGS-tst-oncex4.c += -fexceptions + +ldflags-libgcc_s = -Wl,--as-needed -lgcc_s -Wl,--no-as-needed +LDFLAGS-tst-cancelx2 += $(ldflags-libgcc_s) +LDFLAGS-tst-cancelx3 += $(ldflags-libgcc_s) +LDFLAGS-tst-cancelx4 += $(ldflags-libgcc_s) +LDFLAGS-tst-cancelx5 += $(ldflags-libgcc_s) +LDFLAGS-tst-cancelx6 += $(ldflags-libgcc_s) +LDFLAGS-tst-cancelx7 += $(ldflags-libgcc_s) +LDFLAGS-tst-cancelx8 += $(ldflags-libgcc_s) +LDFLAGS-tst-cancelx9 += $(ldflags-libgcc_s) +LDFLAGS-tst-cancelx10 += $(ldflags-libgcc_s) +LDFLAGS-tst-cancelx11 += $(ldflags-libgcc_s) +LDFLAGS-tst-cancelx12 += $(ldflags-libgcc_s) +LDFLAGS-tst-cancelx13 += $(ldflags-libgcc_s) +LDFLAGS-tst-cancelx14 += $(ldflags-libgcc_s) +LDFLAGS-tst-cancelx15 += $(ldflags-libgcc_s) +LDFLAGS-tst-cancelx16 += $(ldflags-libgcc_s) +LDFLAGS-tst-cancelx17 += $(ldflags-libgcc_s) +LDFLAGS-tst-cancelx18 += $(ldflags-libgcc_s) +LDFLAGS-tst-cancelx20 += $(ldflags-libgcc_s) +LDFLAGS-tst-cancelx21 += $(ldflags-libgcc_s) +LDFLAGS-tst-cleanupx0 += $(ldflags-libgcc_s) +LDFLAGS-tst-cleanupx1 += $(ldflags-libgcc_s) +LDFLAGS-tst-cleanupx2 += $(ldflags-libgcc_s) +LDFLAGS-tst-cleanupx3 += $(ldflags-libgcc_s) +LDFLAGS-tst-cleanupx4 += $(ldflags-libgcc_s) +LDFLAGS-tst-oncex3 += $(ldflags-libgcc_s) +LDFLAGS-tst-oncex4 += $(ldflags-libgcc_s) + +CFLAGS-tst-align.c += $(stack-align-test-flags) +CFLAGS-tst-align3.c += $(stack-align-test-flags) +CFLAGS-tst-initializers1.c = -W -Wall -Werror +CFLAGS-tst-initializers1-< = $(CFLAGS-tst-initializers1.c) \ + $(patsubst tst-initializers1-%.c,-std=%,$<) +CFLAGS-tst-initializers1-c89.c = $(CFLAGS-tst-initializers1-<) +CFLAGS-tst-initializers1-c99.c = $(CFLAGS-tst-initializers1-<) +CFLAGS-tst-initializers1-gnu89.c = $(CFLAGS-tst-initializers1-<) +CFLAGS-tst-initializers1-gnu99.c = $(CFLAGS-tst-initializers1-<) + +tst-cancel7-ARGS = --command "exec $(host-test-program-cmd)" +tst-cancelx7-ARGS = $(tst-cancel7-ARGS) +tst-umask1-ARGS = $(objpfx)tst-umask1.temp + +$(objpfx)tst-atfork2: $(libdl) $(shared-thread-library) +LDFLAGS-tst-atfork2 = -rdynamic +tst-atfork2-ENV = MALLOC_TRACE=$(objpfx)tst-atfork2.mtrace +$(objpfx)tst-atfork2mod.so: $(shared-thread-library) + +ifeq ($(run-built-tests),yes) +tests: $(objpfx)tst-stack3-mem +endif +tst-stack3-ENV = MALLOC_TRACE=$(objpfx)tst-stack3.mtrace +$(objpfx)tst-stack3-mem: $(objpfx)tst-stack3.out + $(common-objpfx)malloc/mtrace $(objpfx)tst-stack3.mtrace > $@ +generated += tst-stack3-mem tst-stack3.mtrace + +$(objpfx)tst-cleanup4: $(objpfx)tst-cleanup4aux.o $(shared-thread-library) +$(objpfx)tst-cleanupx4: $(objpfx)tst-cleanup4aux.o $(shared-thread-library) + +$(objpfx)tst-tls3: $(libdl) $(shared-thread-library) +LDFLAGS-tst-tls3 = -rdynamic +$(objpfx)tst-tls3.out: $(objpfx)tst-tls3mod.so +$(objpfx)tst-tls3mod.so: $(shared-thread-library) + +$(objpfx)tst-tls4: $(libdl) $(shared-thread-library) +$(objpfx)tst-tls4.out: $(objpfx)tst-tls4moda.so $(objpfx)tst-tls4modb.so + +$(objpfx)tst-tls5: $(objpfx)tst-tls5mod.so $(shared-thread-library) +LDFLAGS-tst-tls5 = $(no-as-needed) +LDFLAGS-tst-tls5mod.so = -Wl,-soname,tst-tls5mod.so + +ifeq ($(build-shared),yes) +ifeq ($(run-built-tests),yes) +tests: $(objpfx)tst-tls6.out +endif +$(objpfx)tst-tls6.out: tst-tls6.sh $(objpfx)tst-tls5 \ + $(objpfx)tst-tls5moda.so $(objpfx)tst-tls5modb.so \ + $(objpfx)tst-tls5modc.so $(objpfx)tst-tls5modd.so \ + $(objpfx)tst-tls5mode.so $(objpfx)tst-tls5modf.so + $(BASH) $< $(common-objpfx) '$(test-via-rtld-prefix)' \ + '$(test-wrapper-env)' +endif + +$(objpfx)tst-dlsym1: $(libdl) $(shared-thread-library) + +$(objpfx)tst-fini1: $(shared-thread-library) $(objpfx)tst-fini1mod.so + +ifeq (yes,$(build-shared)) +librt = $(common-objpfx)rt/librt.so +else +librt = $(common-objpfx)rt/librt.a +endif + +$(objpfx)tst-cancel17: $(librt) +$(objpfx)tst-cancelx17: $(librt) +$(objpfx)tst-_res1mod2.so: $(objpfx)tst-_res1mod1.so +LDFLAGS-tst-_res1mod1.so = -Wl,-soname,tst-_res1mod1.so +LDFLAGS-tst-_res1mod2.so = -Wl,-soname,tst-_res1mod2.so +$(objpfx)tst-_res1: $(objpfx)tst-_res1mod1.so $(objpfx)tst-_res1mod2.so \ + $(shared-thread-library) + +LDLIBS-tst-cancel24 = $(no-as-needed) -lstdc++ +LDLIBS-tst-cancel24-static = $(LDLIBS-tst-cancel24) + +extra-B-pthread.so = -B$(common-objpfx)fbtl/ +$(objpfx)libpthread.so: $(addprefix $(objpfx),$(crti-objs) $(crtn-objs)) +$(objpfx)libpthread.so: +preinit += $(addprefix $(objpfx),$(crti-objs)) +$(objpfx)libpthread.so: +postinit += $(addprefix $(objpfx),$(crtn-objs)) + +# Make sure we link with the thread library. +ifeq ($(build-shared),yes) +$(addprefix $(objpfx), \ + $(filter-out $(tests-static) $(xtests-static) $(tests-reverse) \ + $(tests-nolibpthread), \ + $(tests) $(xtests) $(test-srcs))): $(objpfx)libpthread.so \ + $(objpfx)libpthread_nonshared.a +$(objpfx)tst-unload: $(common-objpfx)dlfcn/libdl.so +# $(objpfx)../libc.so is used instead of $(common-objpfx)libc.so, +# since otherwise libpthread.so comes before libc.so when linking. +$(addprefix $(objpfx), $(tests-reverse)): \ + $(objpfx)../libc.so $(objpfx)libpthread.so \ + $(objpfx)libpthread_nonshared.a +$(objpfx)../libc.so: $(common-objpfx)libc.so ; +$(addprefix $(objpfx),$(tests-static) $(xtests-static)): $(objpfx)libpthread.a + +$(objpfx)tst-atfork2.out: $(objpfx)tst-atfork2mod.so +else +$(addprefix $(objpfx),$(tests) $(test-srcs)): $(objpfx)libpthread.a +endif + +ifeq ($(build-shared),yes) + +$(objpfx)tst-cleanup0.out: /dev/null $(objpfx)tst-cleanup0 + $(make-test-out) 2>&1 | cmp - tst-cleanup0.expect > $@ + +$(objpfx)crti.o: $(objpfx)pt-crti.o + ln -f $< $@ + +ifneq ($(multidir),.) +$(objpfx)$(multidir)/crti.o: $(objpfx)crti.o $(objpfx)$(multidir)/ + ln -f $< $@ + +$(objpfx)$(multidir)/crtn.o: $(objpfx)crtn.o $(objpfx)$(multidir)/ + ln -f $< $@ +endif + +generated += libpthread_nonshared.a \ + multidir.mk tst-atfork2.mtrace tst-cancel-wrappers.out \ + tst-tls6.out + +generated += $(objpfx)tst-atfork2.mtrace \ + $(addsuffix .so,$(strip $(modules-names))) + +$(objpfx)version.d: $(objpfx)banner.h +$(objpfx)version.os: $(objpfx)banner.h +$(objpfx)banner.h: Banner + sed 's/\(.*\)/"\1\\n"/' $< > $@ +generated += banner.h +# Give libpthread.so an entry point and make it directly runnable itself. +LDFLAGS-pthread.so += -e __nptl_main +endif + +ifeq ($(run-built-tests),yes) +ifeq (yes,$(build-shared)) +tests: $(objpfx)tst-cancel-wrappers.out +$(objpfx)tst-cancel-wrappers.out: tst-cancel-wrappers.sh + $(SHELL) $< '$(NM)' \ + $(common-objpfx)libc_pic.a \ + $(common-objpfx)libc.a \ + $(objpfx)libpthread_pic.a \ + $(objpfx)libpthread.a > $@ +endif +endif + +tst-exec4-ARGS = $(host-test-program-cmd) + +$(objpfx)tst-execstack: $(libdl) +$(objpfx)tst-execstack.out: $(objpfx)tst-execstack-mod.so +LDFLAGS-tst-execstack = -Wl,-z,noexecstack + +$(objpfx)tst-fini1mod.so: $(shared-thread-library) + +tst-stackguard1-ARGS = --command "$(host-test-program-cmd) --child" +tst-stackguard1-static-ARGS = --command "$(objpfx)tst-stackguard1-static --child" + +ifeq ($(run-built-tests),yes) +tests: $(objpfx)tst-oddstacklimit.out + +$(objpfx)tst-oddstacklimit.out: $(objpfx)tst-oddstacklimit $(objpfx)tst-basic1 + $(test-program-prefix) $< --command '$(host-test-program-cmd)' > $@ +endif + +# The tests here better do not run in parallel +ifneq ($(filter %tests,$(MAKECMDGOALS)),) +.NOTPARALLEL: +endif --- /dev/null +++ b/fbtl/TODO @@ -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 --- /dev/null +++ b/fbtl/TODO-kernel @@ -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. --- /dev/null +++ b/fbtl/TODO-testing @@ -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? --- /dev/null +++ b/fbtl/Versions @@ -0,0 +1,251 @@ +libc { + GLIBC_2.0 { + pthread_attr_destroy; pthread_attr_init; + pthread_attr_getdetachstate; pthread_attr_setdetachstate; + pthread_attr_getinheritsched; pthread_attr_setinheritsched; + pthread_attr_getschedparam; pthread_attr_setschedparam; + pthread_attr_getschedpolicy; pthread_attr_setschedpolicy; + pthread_attr_getscope; pthread_attr_setscope; + pthread_condattr_destroy; pthread_condattr_init; + pthread_cond_broadcast; pthread_cond_destroy; + pthread_cond_init; pthread_cond_signal; pthread_cond_wait; + pthread_cond_timedwait; + pthread_equal; pthread_exit; + pthread_getschedparam; pthread_setschedparam; + pthread_mutex_destroy; pthread_mutex_init; + pthread_mutex_lock; pthread_mutex_unlock; + pthread_self; + pthread_setcancelstate; pthread_setcanceltype; + } + GLIBC_2.1 { + pthread_attr_init; + } + GLIBC_2.3.2 { + # Changed pthread_cond_t. + pthread_cond_init; pthread_cond_destroy; + pthread_cond_wait; pthread_cond_signal; + pthread_cond_broadcast; pthread_cond_timedwait; + } + GLIBC_PRIVATE { + __libc_alloca_cutoff; + # Internal libc interface to libpthread + __libc_dl_error_tsd; + } +} + +libpthread { + GLIBC_2.0 { + pthread_create; pthread_join; pthread_self; pthread_equal; + pthread_exit; pthread_detach; + + pthread_getschedparam; pthread_setschedparam; + + pthread_attr_init; pthread_attr_destroy; + pthread_attr_getdetachstate; pthread_attr_setdetachstate; + pthread_attr_getschedparam; pthread_attr_setschedparam; + pthread_attr_getschedpolicy; pthread_attr_setschedpolicy; + pthread_attr_getinheritsched; pthread_attr_setinheritsched; + pthread_attr_getscope; pthread_attr_setscope; + + pthread_mutex_init; pthread_mutex_destroy; + pthread_mutex_lock; pthread_mutex_trylock; pthread_mutex_unlock; + + pthread_mutexattr_init; pthread_mutexattr_destroy; + + pthread_cond_init; pthread_cond_destroy; + pthread_cond_wait; pthread_cond_timedwait; + pthread_cond_signal; pthread_cond_broadcast; + + pthread_condattr_destroy; pthread_condattr_init; + + pthread_cancel; pthread_testcancel; + pthread_setcancelstate; pthread_setcanceltype; + + pthread_sigmask; pthread_kill; + + pthread_key_create; pthread_key_delete; + pthread_getspecific; pthread_setspecific; + + pthread_once; + + pthread_atfork; + + flockfile; funlockfile; ftrylockfile; + + # Non-standard POSIX1.x functions. + pthread_mutexattr_getkind_np; pthread_mutexattr_setkind_np; + + # Protected names for functions used in other shared objects. + __pthread_mutex_init; __pthread_mutex_destroy; + __pthread_mutex_lock; __pthread_mutex_trylock; __pthread_mutex_unlock; + __pthread_mutexattr_init; __pthread_mutexattr_destroy; + __pthread_mutexattr_settype; + __pthread_key_create; __pthread_getspecific; __pthread_setspecific; + __pthread_once; __pthread_atfork; + _IO_flockfile; _IO_ftrylockfile; _IO_funlockfile; + + # Hidden entry point (through macros). + #_pthread_cleanup_pop; _pthread_cleanup_pop_restore; _pthread_cleanup_push; + #_pthread_cleanup_push_defer; + + # Semaphores. + sem_destroy; sem_getvalue; sem_init; sem_post; sem_trywait; sem_wait; + + # Special fork handling. + fork; __fork; vfork; + + # Cancellation points. + close; __close; fcntl; __fcntl; read; __read; write; __write; accept; + connect; __connect; recv; recvfrom; recvmsg; send; __send; sendmsg; sendto; + fsync; lseek; __lseek; msync; nanosleep; open; __open; pause; tcdrain; + system; wait; __wait; waitpid; + + # Hidden entry point (through macros). + _pthread_cleanup_push; _pthread_cleanup_pop; + _pthread_cleanup_push_defer; _pthread_cleanup_pop_restore; + + pthread_kill_other_threads_np; + + # The error functions. + __errno_location; __h_errno_location; + + # Functions which previously have been overwritten. + sigwait; sigaction; __sigaction; _exit; _Exit; longjmp; siglongjmp; + raise; + } + + GLIBC_2.1 { + pthread_create; + pthread_attr_init; + + pthread_attr_getguardsize; pthread_attr_setguardsize; + pthread_attr_getstackaddr; pthread_attr_setstackaddr; + pthread_attr_getstacksize; pthread_attr_setstacksize; + + pthread_mutexattr_gettype; pthread_mutexattr_settype; + + pthread_rwlock_init; pthread_rwlock_destroy; + pthread_rwlock_rdlock; pthread_rwlock_wrlock; pthread_rwlock_unlock; + pthread_rwlock_tryrdlock; pthread_rwlock_trywrlock; + + pthread_rwlockattr_init; pthread_rwlockattr_destroy; + pthread_rwlockattr_getpshared; pthread_rwlockattr_setpshared; + pthread_rwlockattr_getkind_np; pthread_rwlockattr_setkind_np; + + pthread_getconcurrency; pthread_setconcurrency; + + # Semaphores. + sem_destroy; sem_getvalue; sem_init; sem_post; sem_trywait; sem_wait; + + __libc_current_sigrtmin; __libc_current_sigrtmax; + __libc_allocate_rtsig; + } + + GLIBC_2.1.1 { + sem_close; sem_open; sem_unlink; + } + + GLIBC_2.1.2 { + __vfork; + } + + GLIBC_2.2 { + pthread_mutexattr_getpshared; pthread_mutexattr_setpshared; + + pthread_condattr_getpshared; pthread_condattr_setpshared; + + # New functions from IEEE Std. 1003.1-2001. + pthread_mutex_timedlock; + + pthread_rwlock_timedrdlock; pthread_rwlock_timedwrlock; + + pthread_attr_getstack; pthread_attr_setstack; + + pthread_spin_destroy; pthread_spin_init; pthread_spin_lock; + pthread_spin_trylock; pthread_spin_unlock; + + pthread_barrier_init; pthread_barrier_destroy; pthread_barrier_wait; + pthread_barrierattr_destroy; pthread_barrierattr_init; + pthread_barrierattr_setpshared; + + sem_timedwait; + + pthread_yield; + + pthread_getcpuclockid; + + # Cancellation points. + lseek64; open64; __open64; pread; pread64; __pread64; pwrite; pwrite64; + __pwrite64; + + # Names used internally. + __pthread_rwlock_init; __pthread_rwlock_destroy; + __pthread_rwlock_rdlock; __pthread_rwlock_tryrdlock; + __pthread_rwlock_wrlock; __pthread_rwlock_trywrlock; + __pthread_rwlock_unlock; + + __res_state; + } + + GLIBC_2.2.3 { + # Extensions. + pthread_getattr_np; + } + + GLIBC_2.2.6 { + # Cancellation wrapper + __nanosleep; + } + + GLIBC_2.3.2 { + # Changed pthread_cond_t. + pthread_cond_init; pthread_cond_destroy; + pthread_cond_wait; pthread_cond_timedwait; + pthread_cond_signal; pthread_cond_broadcast; + } + + GLIBC_2.3.3 { + # 1003.1-2001 function accidentally left out in 2.2. + pthread_barrierattr_getpshared; + + # Unix CS option. + pthread_condattr_getclock; pthread_condattr_setclock; + + # Proposed API extensions. + pthread_tryjoin_np; pthread_timedjoin_np; + + # New cancellation cleanup handling. + __pthread_register_cancel; __pthread_unregister_cancel; + __pthread_register_cancel_defer; __pthread_unregister_cancel_restore; + __pthread_unwind_next; + __pthread_cleanup_routine; + + # affinity interfaces without size parameter + # have not been in linuxthreads and + # will be overriden by version from GLIBC_2.3.4 + pthread_getaffinity_np; pthread_setaffinity_np; + pthread_attr_getaffinity_np; pthread_attr_setaffinity_np; + } + + GLIBC_2.3.4 { + # New affinity interfaces. + pthread_getaffinity_np; pthread_setaffinity_np; + pthread_attr_getaffinity_np; pthread_attr_setaffinity_np; + } + + GLIBC_2.12 { + pthread_setname_np; pthread_getname_np; + }; + + GLIBC_2.18 { + pthread_getattr_default_np; + pthread_setattr_default_np; + } + + GLIBC_PRIVATE { + __pthread_initialize_minimal; + __pthread_clock_gettime; __pthread_clock_settime; + __pthread_unwind; __pthread_get_minstack; + __shm_directory; + } +} --- /dev/null +++ b/fbtl/alloca_cutoff.c @@ -0,0 +1,36 @@ +/* Determine whether block of given size can be allocated on the stack or not. + Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General 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, see <http://www.gnu.org/licenses/>. */ + +#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)); +} +libc_hidden_def (__libc_alloca_cutoff) --- /dev/null +++ b/fbtl/allocatestack.c @@ -0,0 +1,1258 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <assert.h> +#include <errno.h> +#include <signal.h> +#include <stdint.h> +#include <string.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/param.h> +#include <dl-sysdep.h> +#include <dl-tls.h> +#include <tls.h> +#include <list.h> +#include <lowlevellock.h> +#include <kernel-features.h> +#include <stack-aliasing.h> + + +#if !(defined(NEED_SEPARATE_REGISTER_STACK) || defined(NEED_STACK_SIZE_FOR_PTH_CREATE)) + +/* 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 + +/* + Unfortunately, under FreeBSD mmap fails with addr=NULL, flags=MAP_STACK + + See http://www.freebsd.org/cgi/query-pr.cgi?pr=158755 + + do not use MAP_STACK at all +*/ + +#undef MAP_STACK + + +/* 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 TLS_TCB_AT_TP +# define TLS_TPADJ(pd) (pd) +#elif TLS_DTV_AT_TP +# define TLS_TPADJ(pd) ((struct pthread *)((char *) (pd) + TLS_PRE_TCB_SIZE)) +#endif + +/* Cache handling for not-yet free stacks. */ + +/* Maximum size in kB of cache. */ +static size_t stack_cache_maxsize = 40 * 1024 * 1024; /* 40MiBi by default. */ +static size_t stack_cache_actsize; + +/* Mutex protecting this variable. */ +static 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 <= KTID_TERMINATED) + + +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; + } + + /* Don't allow setxid until cloned. */ + result->setxid_futex = -1; + + /* 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)); + for (size_t cnt = 0; cnt < dtv[-1].counter; ++cnt) + free (dtv[1 + cnt].pointer.to_free); + 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 (__glibc_unlikely (stack_cache_actsize > stack_cache_maxsize)) + __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; +} + + +/* Returns a usable stack for a new thread either by allocating a + new stack or reusing a cached stack of sufficient size. + ATTR must be non-NULL and point to a valid pthread_attr. + PDP must be non-NULL. */ +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 (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. */ + if (attr->stacksize != 0) + size = attr->stacksize; + else + { + lll_lock (__default_pthread_attr_lock, LLL_PRIVATE); + size = __default_pthread_attr.stacksize; + lll_unlock (__default_pthread_attr_lock, LLL_PRIVATE); + } + + /* Get memory for the stack. */ + if (__glibc_unlikely (attr->flags & ATTR_FLAG_STACKADDR)) + { + uintptr_t adj; + + /* If the user also specified the size of the stack make sure it + is large enough. */ + if (attr->stacksize != 0 + && attr->stacksize < (__static_tls_size + MINIMAL_REST_STACK)) + return EINVAL; + + /* Adjust stack size for alignment of the TLS block. */ +#if TLS_TCB_AT_TP + adj = ((uintptr_t) attr->stackaddr - TLS_TCB_SIZE) + & __static_tls_align_m1; + assert (size > adj + TLS_TCB_SIZE); +#elif TLS_DTV_AT_TP + adj = ((uintptr_t) attr->stackaddr - __static_tls_size) + & __static_tls_align_m1; + assert (size > adj); +#endif + + /* The user provided some memory. Let's hope it matches the + size... We do not allocate guard pages if the user provided + the stack. It is the user's responsibility to do this if it + is wanted. */ +#if TLS_TCB_AT_TP + pd = (struct pthread *) ((uintptr_t) attr->stackaddr + - TLS_TCB_SIZE - adj); +#elif TLS_DTV_AT_TP + pd = (struct pthread *) (((uintptr_t) attr->stackaddr + - __static_tls_size - adj) + - TLS_PRE_TCB_SIZE); +#endif + + /* The user provided stack memory needs to be cleared. */ + memset (pd, '\0', sizeof (struct pthread)); + + /* The first TSD block is included in the TCB. */ + pd->specific[0] = pd->specific_1stblock; + + /* Remember the stack-related values. */ + pd->stackblock = (char *) attr->stackaddr - size; + pd->stackblock_size = size; + + /* This is a user-provided stack. It will not be queued in the + stack cache nor will the memory (except the TLS memory) be freed. */ + pd->user_stack = true; + + /* This is at least the second thread. */ + pd->header.multiple_threads = 1; +#ifndef TLS_MULTIPLE_THREADS_IN_TCB + __pthread_multiple_threads = *__libc_multiple_threads_ptr = 1; +#endif + +#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 + + /* Don't allow setxid until cloned. */ + pd->setxid_futex = -1; + + /* Allocate the DTV for this thread. */ + if (_dl_allocate_tls (TLS_TPADJ (pd)) == NULL) + { + /* Something went wrong. */ + assert (errno == ENOMEM); + return errno; + } + + + /* 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; + const int prot = (PROT_READ | PROT_WRITE + | ((GL(dl_stack_flags) & PF_X) ? PROT_EXEC : 0)); + +#if COLORING_INCREMENT != 0 + /* Add one more page for stack coloring. Don't do it for stacks + with 16 times pagesize or larger. This might just cause + unnecessary misalignment. */ + if (size <= 16 * pagesize_m1) + size += pagesize_m1 + 1; +#endif + + /* Adjust the stack size for alignment. */ + size &= ~__static_tls_align_m1; + assert (size != 0); + + /* Make sure the size of the stack is enough for the guard and + eventually the thread descriptor. */ + guardsize = (attr->guardsize + pagesize_m1) & ~pagesize_m1; + if (__builtin_expect (size < ((guardsize + __static_tls_size + + MINIMAL_REST_STACK + pagesize_m1) + & ~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 (__glibc_unlikely (mem == MAP_FAILED)) + 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 (__glibc_unlikely ((coloring & __static_tls_align_m1) != 0)) + coloring = (((coloring + __static_tls_align_m1) + & ~(__static_tls_align_m1)) + & ~pagesize_m1); +#else + /* Unless specified we do not make any adjustments. */ +# define coloring 0 +#endif + + /* Place the thread descriptor at the end of the stack. */ +#if TLS_TCB_AT_TP + pd = (struct pthread *) ((char *) mem + size - coloring) - 1; +#elif TLS_DTV_AT_TP + pd = (struct pthread *) ((((uintptr_t) mem + size - coloring + - __static_tls_size) + & ~__static_tls_align_m1) + - TLS_PRE_TCB_SIZE); +#endif + + /* Remember the stack-related values. */ + pd->stackblock = mem; + pd->stackblock_size = size; + + /* We allocated the first block thread-specific data array. + This address will not change for the lifetime of this + descriptor. */ + pd->specific[0] = pd->specific_1stblock; + + /* This is at least the second thread. */ + pd->header.multiple_threads = 1; +#ifndef TLS_MULTIPLE_THREADS_IN_TCB + __pthread_multiple_threads = *__libc_multiple_threads_ptr = 1; +#endif + +#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 + + /* Don't allow setxid until cloned. */ + pd->setxid_futex = -1; + + /* 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 errno; + } + + + /* 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); + + + /* There might have been a race. Another thread might have + caused the stacks to get exec permission while this new + stack was prepared. Detect if this was possible and + change the permission if necessary. */ + if (__builtin_expect ((GL(dl_stack_flags) & PF_X) != 0 + && (prot & PROT_EXEC) == 0, 0)) + { + int err = change_stack_perm (pd +#ifdef NEED_SEPARATE_REGISTER_STACK + , ~pagesize_m1 +#endif + ); + if (err != 0) + { + /* Free the stack memory we just allocated. */ + (void) munmap (mem, size); + + return err; + } + } + + + /* Note that all of the stack and the thread descriptor is + zeroed. This means we do not have to initialize fields + with initial value zero. This is specifically true for + the 'tid' field which is always set back to zero once the + stack is not used anymore and for the 'guardsize' field + which will be read next. */ + } + + /* Create or resize the guard area if necessary. */ + if (__glibc_unlikely (guardsize > pd->guardsize)) + { +#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) + { + mprot_error: + 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 errno; + } + + 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 TLS_TCB_AT_TP + /* The stack begins before the TCB and the static TLS block. */ + stacktop = ((char *) (pd + 1) - __static_tls_size); +#elif TLS_DTV_AT_TP + stacktop = (char *) (pd - 1); +#endif + +#if defined(NEED_SEPARATE_REGISTER_STACK) || defined(NEED_STACK_SIZE_FOR_PTH_CREATE) + *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 (__glibc_likely (! pd->user_stack)) + (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 = _dl_make_stack_executable (stack_endp); + if (err != 0) + return err; + +#ifdef NEED_SEPARATE_REGISTER_STACK + const size_t pagemask = ~(__getpagesize () - 1); +#endif + + lll_lock (stack_cache_lock, 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 & ~(uintptr_t) 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; + + /* 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; + } + } + } + } + + /* 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 (__glibc_unlikely (THREAD_GETMEM (self, user_stack))) + 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 locks. */ + stack_cache_lock = LLL_LOCK_INITIALIZER; + __default_pthread_attr_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; + + /* Wait until this thread is cloned. */ + if (t->setxid_futex == -1 + && ! atomic_compare_and_exchange_bool_acq (&t->setxid_futex, -2, -1)) + do + lll_futex_wait (&t->setxid_futex, -2, LLL_PRIVATE); + while (t->setxid_futex == -2); + + /* 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) + { + /* Release the futex if there is no other setxid in + progress. */ + if ((ch & SETXID_BITMASK) == 0) + { + t->setxid_futex = 1; + lll_futex_wake (&t->setxid_futex, 1, LLL_PRIVATE); + } + 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; + +#warning setxid fixup needed +#if 0 + int val; + pid_t pid = __getpid (); + INTERNAL_SYSCALL_DECL (err); + val = INTERNAL_SYSCALL (tgkill, err, pid, t->tid, SIGSETXID); + + /* 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 +#endif + return 0; +} + + +int +attribute_hidden +__nptl_setxid (struct xid_command *cmdp) +{ +#warning setxid fixup needed +#if 0 + 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; +#endif +} + +static inline void __attribute__((always_inline)) +init_one_static_tls (struct pthread *curp, struct link_map *map) +{ +# if TLS_TCB_AT_TP + void *dest = (char *) curp - map->l_tls_offset; +# elif TLS_DTV_AT_TP + void *dest = (char *) curp + map->l_tls_offset + TLS_PRE_TCB_SIZE; +# else +# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined" +# endif + + /* We cannot delay the initialization of the Static TLS area, since + it can be accessed with LE or IE, but since the DTV is only used + by GD and LD, we can delay its update to avoid a race. */ + 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); +} --- /dev/null +++ b/fbtl/cancellation.c @@ -0,0 +1,99 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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 (__glibc_likely (curval == oldval)) + { + 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 (__glibc_likely (curval == oldval)) + 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); + } +} --- /dev/null +++ b/fbtl/cleanup.c @@ -0,0 +1,48 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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) --- /dev/null +++ b/fbtl/cleanup_compat.c @@ -0,0 +1,50 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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) --- /dev/null +++ b/fbtl/cleanup_defer.c @@ -0,0 +1,91 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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 (__glibc_unlikely (cancelhandling & CANCELTYPE_BITMASK)) + while (1) + { + int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, + cancelhandling + & ~CANCELTYPE_BITMASK, + cancelhandling); + if (__glibc_likely (curval == cancelhandling)) + /* 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 (__glibc_likely (curval == cancelhandling)) + /* Successfully replaced the value. */ + break; + + /* Prepare for the next round. */ + cancelhandling = curval; + } + + CANCELLATION_P (self); + } +} --- /dev/null +++ b/fbtl/cleanup_defer_compat.c @@ -0,0 +1,94 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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 (__glibc_unlikely (cancelhandling & CANCELTYPE_BITMASK)) + while (1) + { + int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, + cancelhandling + & ~CANCELTYPE_BITMASK, + cancelhandling); + if (__glibc_likely (curval == cancelhandling)) + /* 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 (__glibc_likely (curval == cancelhandling)) + /* 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) --- /dev/null +++ b/fbtl/cleanup_routine.c @@ -0,0 +1,27 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#include <pthread.h> + + +void +__pthread_cleanup_routine (struct __pthread_cleanup_frame *f) +{ + if (f->__do_it) + f->__cancel_routine (f->__cancel_arg); +} --- /dev/null +++ b/fbtl/cond-perf.c @@ -0,0 +1,103 @@ +#include <pthread.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <atomic.h> + +static pthread_cond_t cond1 = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t mut1 = PTHREAD_MUTEX_INITIALIZER; + +static pthread_cond_t cond2 = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t mut2 = PTHREAD_MUTEX_INITIALIZER; + +static bool last_round; +static int ntogo; +static bool alldone; + + +static void * +cons (void *arg) +{ + pthread_mutex_lock (&mut1); + + do + { + if (atomic_decrement_and_test (&ntogo)) + { + pthread_mutex_lock (&mut2); + alldone = true; + pthread_cond_signal (&cond2); + pthread_mutex_unlock (&mut2); + } + + pthread_cond_wait (&cond1, &mut1); + } + while (! last_round); + + pthread_mutex_unlock (&mut1); + + return NULL; +} + + +int +main (int argc, char *argv[]) +{ + int opt; + int err; + int nthreads = 10; + int nrounds = 100; + bool keeplock = false; + + while ((opt = getopt (argc, argv, "n:r:k")) != -1) + switch (opt) + { + case 'n': + nthreads = atol (optarg); + break; + case 'r': + nrounds = atol (optarg); + break; + case 'k': + keeplock = true; + break; + } + + ntogo = nthreads; + + pthread_t th[nthreads]; + int i; + for (i = 0; __builtin_expect (i < nthreads, 1); ++i) + if (__glibc_unlikely ((err = pthread_create (&th[i], NULL, cons, (void *) (long) i)) != 0)) + printf ("pthread_create: %s\n", strerror (err)); + + for (i = 0; __builtin_expect (i < nrounds, 1); ++i) + { + pthread_mutex_lock (&mut2); + while (! alldone) + pthread_cond_wait (&cond2, &mut2); + pthread_mutex_unlock (&mut2); + + pthread_mutex_lock (&mut1); + if (! keeplock) + pthread_mutex_unlock (&mut1); + + ntogo = nthreads; + alldone = false; + if (i + 1 >= nrounds) + last_round = true; + + pthread_cond_broadcast (&cond1); + + if (keeplock) + pthread_mutex_unlock (&mut1); + } + + for (i = 0; i < nthreads; ++i) + if ((err = pthread_join (th[i], NULL)) != 0) + printf ("pthread_create: %s\n", strerror (err)); + + return 0; +} --- /dev/null +++ b/fbtl/configure @@ -0,0 +1,13 @@ +# This is a shell script fragment sourced by the main configure script. +# We're obliged to give here the canonical name that will be used to +# as a subdirectory to search for in other add-ons' sysdeps trees. + +libc_add_on_canonical=fbtl + +# Only linux configurations support NPTL. +if test $add_ons_automatic = yes; then + case "$config_os" in +# *linux*) ;; + *) libc_add_on= ;; + esac +fi --- /dev/null +++ b/fbtl/descr.h @@ -0,0 +1,406 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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> +#define __need_list_t +#include <list.h> +#include <lowlevellock.h> +#include <pthreaddef.h> +#include <dl-sysdep.h> +#include "../fbtl_db/thread_db.h" +#include <tls.h> +#include <unwind.h> +#define __need_res_state +#include <resolv.h> +#include <kernel-features.h> +#include <fpu_control.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 !TLS_DTV_AT_TP + /* This overlaps the TCB as used for TLS without threads (see tls.h). */ + tcbhead_t header; +#else + struct + { + /* multiple_threads is enabled either when the process has spawned at + least one thread or when a single-threaded process cancels itself. + This enables additional code to introduce locking before doing some + compare_and_exchange operations and also enable cancellation points. + The concepts of multiple threads and cancellation points ideally + should be separate, since it is not necessary for multiple threads to + have been created for cancellation points to be enabled, as is the + case is when single-threaded process cancels itself. + + Since enabling multiple_threads enables additional code in + cancellation points and compare_and_exchange operations, there is a + potential for an unneeded performance hit when it is enabled in a + single-threaded, self-canceling process. This is OK though, since a + single-threaded process will enable async cancellation only when it + looks to cancel itself and is hence going to end anyway. */ + 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. */ +#if (__BYTE_ORDER == __LITTLE_ENDIAN) || (__WORDSIZE == 32) + union { + pid_t tid; + long ktid; + }; +#else +#error untested padding layout: + union { + struct { + int __pad_tid; + pid_t tid; + }; + long ktid; + }; +#endif + + /* Process ID - thread group ID in kernel speak. */ + pid_t pid_unused; + + /* 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; + + /* Machine-specific unwind info. */ + struct _Unwind_Exception exc; + + /* 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; + + /* FPU initial control word */ + fpu_control_t fpu_control_init; + + /* 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 */ --- /dev/null +++ b/fbtl/eintr.c @@ -0,0 +1,88 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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); + } +} --- /dev/null +++ b/fbtl/errno-loc.c @@ -0,0 +1 @@ +#include "../csu/errno-loc.c" --- /dev/null +++ b/fbtl/events.c @@ -0,0 +1,33 @@ +/* Event functions used while debugging. + Copyright (C) 1999-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General 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, see <http://www.gnu.org/licenses/>. */ + +/* 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) --- /dev/null +++ b/fbtl/forward.c @@ -0,0 +1,219 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <dlfcn.h> +#include <pthreadP.h> +#include <signal.h> +#include <stdlib.h> + +#include <shlib-compat.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); \ +} + +/* Same as FORWARD2, only without return. */ +#define FORWARD_NORETURN(name, rettype, decl, params, defaction) \ +rettype \ +name decl \ +{ \ + if (!__libc_pthread_functions_init) \ + defaction; \ + \ + 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) + +#if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_1) +FORWARD (__pthread_attr_init_2_0, (pthread_attr_t *attr), (attr), 0) +compat_symbol (libc, __pthread_attr_init_2_0, pthread_attr_init, GLIBC_2_0); +#endif + +FORWARD (__pthread_attr_init_2_1, (pthread_attr_t *attr), (attr), 0) +versioned_symbol (libc, __pthread_attr_init_2_1, pthread_attr_init, GLIBC_2_1); + +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) + +#if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_3_2) +FORWARD2 (__pthread_cond_broadcast_2_0, int attribute_compat_text_section, + (pthread_cond_2_0_t *cond), (cond), return 0) +compat_symbol (libc, __pthread_cond_broadcast_2_0, pthread_cond_broadcast, + GLIBC_2_0); +#endif +FORWARD (__pthread_cond_broadcast, (pthread_cond_t *cond), (cond), 0) +versioned_symbol (libc, __pthread_cond_broadcast, pthread_cond_broadcast, + GLIBC_2_3_2); + +#if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_3_2) +FORWARD2 (__pthread_cond_destroy_2_0, int attribute_compat_text_section, + (pthread_cond_2_0_t *cond), (cond), return 0) +compat_symbol (libc, __pthread_cond_destroy_2_0, pthread_cond_destroy, + GLIBC_2_0); +#endif +FORWARD (__pthread_cond_destroy, (pthread_cond_t *cond), (cond), 0) +versioned_symbol (libc, __pthread_cond_destroy, pthread_cond_destroy, + GLIBC_2_3_2); + +#if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_3_2) +FORWARD2 (__pthread_cond_init_2_0, int attribute_compat_text_section, + (pthread_cond_2_0_t *cond, const pthread_condattr_t *cond_attr), + (cond, cond_attr), return 0) +compat_symbol (libc, __pthread_cond_init_2_0, pthread_cond_init, GLIBC_2_0); +#endif +FORWARD (__pthread_cond_init, + (pthread_cond_t *cond, const pthread_condattr_t *cond_attr), + (cond, cond_attr), 0) +versioned_symbol (libc, __pthread_cond_init, pthread_cond_init, GLIBC_2_3_2); + +#if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_3_2) +FORWARD2 (__pthread_cond_signal_2_0, int attribute_compat_text_section, + (pthread_cond_2_0_t *cond), (cond), return 0) +compat_symbol (libc, __pthread_cond_signal_2_0, pthread_cond_signal, + GLIBC_2_0); +#endif +FORWARD (__pthread_cond_signal, (pthread_cond_t *cond), (cond), 0) +versioned_symbol (libc, __pthread_cond_signal, pthread_cond_signal, + GLIBC_2_3_2); + +#if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_3_2) +FORWARD2 (__pthread_cond_wait_2_0, int attribute_compat_text_section, + (pthread_cond_2_0_t *cond, pthread_mutex_t *mutex), (cond, mutex), + return 0) +compat_symbol (libc, __pthread_cond_wait_2_0, pthread_cond_wait, + GLIBC_2_0); +#endif +FORWARD (__pthread_cond_wait, (pthread_cond_t *cond, pthread_mutex_t *mutex), + (cond, mutex), 0) +versioned_symbol (libc, __pthread_cond_wait, pthread_cond_wait, + GLIBC_2_3_2); + +#if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_3_2) +FORWARD2 (__pthread_cond_timedwait_2_0, int attribute_compat_text_section, + (pthread_cond_2_0_t *cond, pthread_mutex_t *mutex, + const struct timespec *abstime), (cond, mutex, abstime), + return 0) +compat_symbol (libc, __pthread_cond_timedwait_2_0, pthread_cond_timedwait, + GLIBC_2_0); +#endif +FORWARD (__pthread_cond_timedwait, + (pthread_cond_t *cond, pthread_mutex_t *mutex, + const struct timespec *abstime), (cond, mutex, abstime), 0) +versioned_symbol (libc, __pthread_cond_timedwait, pthread_cond_timedwait, + GLIBC_2_3_2); + + +FORWARD (pthread_equal, (pthread_t thread1, pthread_t thread2), + (thread1, thread2), 1) + + +FORWARD_NORETURN (__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) +strong_alias (__pthread_setcancelstate, pthread_setcancelstate) + +FORWARD (pthread_setcanceltype, (int type, int *oldtype), (type, oldtype), 0) + +FORWARD_NORETURN(__pthread_unwind, + void attribute_hidden __attribute ((noreturn)) __cleanup_fct_attribute + attribute_compat_text_section, + (__pthread_unwind_buf_t *buf), (buf), { + /* We cannot call abort() here. */ +#if 1 +#warning the kill syscall have two arguments, not one ... +#warning elaborate what to do properly + asm("hlt"); +#else + INTERNAL_SYSCALL_DECL (err); + INTERNAL_SYSCALL (kill, err, 1, SIGKILL); +#endif + }) --- /dev/null +++ b/fbtl/herrno.c @@ -0,0 +1,34 @@ +/* Copyright (C) 1996-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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; +} --- /dev/null +++ b/fbtl/libc-cancellation.c @@ -0,0 +1,24 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include "pthreadP.h" + + +#define __pthread_enable_asynccancel __libc_enable_asynccancel +#define __pthread_disable_asynccancel __libc_disable_asynccancel +#include <fbtl/cancellation.c> --- /dev/null +++ b/fbtl/libc-cleanup.c @@ -0,0 +1,27 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include "pthreadP.h" + + +void +__libc_cleanup_routine (struct __pthread_cleanup_frame *f) +{ + if (f->__do_it) + f->__cancel_routine (f->__cancel_arg); +} --- /dev/null +++ b/fbtl/lowlevellock.h @@ -0,0 +1,83 @@ +/* Low level locking macros used in NPTL implementation. Stub version. + Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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)) --- /dev/null +++ b/fbtl/nptl-init.c @@ -0,0 +1,460 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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 <list.h> +#include <fork.h> +#include <version.h> +#include <shlib-compat.h> +#include <smp.h> +#include <lowlevellock.h> +#include <kernel-features.h> +#include <libc-internal.h> + +/* Size and alignment of static TLS block. */ +size_t __static_tls_size; +size_t __static_tls_align_m1; + +#warning TODO whole file +#if 1 +# define set_robust_list_not_avail() do { } while (0) +#else +#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 +#endif + +/* Version of the library, used in libthread_db to detect mismatches. */ +static const char nptl_version[] __attribute_used__ = VERSION; + + +#ifdef SHARED +static +#else +extern +#endif +void __nptl_set_robust (struct pthread *); + +#ifdef SHARED +static void nptl_freeres (void); + + +static const struct pthread_functions pthread_functions = + { + .ptr_pthread_attr_destroy = __pthread_attr_destroy, +# if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_1) + .ptr___pthread_attr_init_2_0 = __pthread_attr_init_2_0, +# endif + .ptr___pthread_attr_init_2_1 = __pthread_attr_init_2_1, + .ptr_pthread_attr_getdetachstate = __pthread_attr_getdetachstate, + .ptr_pthread_attr_setdetachstate = __pthread_attr_setdetachstate, + .ptr_pthread_attr_getinheritsched = __pthread_attr_getinheritsched, + .ptr_pthread_attr_setinheritsched = __pthread_attr_setinheritsched, + .ptr_pthread_attr_getschedparam = __pthread_attr_getschedparam, + .ptr_pthread_attr_setschedparam = __pthread_attr_setschedparam, + .ptr_pthread_attr_getschedpolicy = __pthread_attr_getschedpolicy, + .ptr_pthread_attr_setschedpolicy = __pthread_attr_setschedpolicy, + .ptr_pthread_attr_getscope = __pthread_attr_getscope, + .ptr_pthread_attr_setscope = __pthread_attr_setscope, + .ptr_pthread_condattr_destroy = __pthread_condattr_destroy, + .ptr_pthread_condattr_init = __pthread_condattr_init, + .ptr___pthread_cond_broadcast = __pthread_cond_broadcast, + .ptr___pthread_cond_destroy = __pthread_cond_destroy, + .ptr___pthread_cond_init = __pthread_cond_init, + .ptr___pthread_cond_signal = __pthread_cond_signal, + .ptr___pthread_cond_wait = __pthread_cond_wait, + .ptr___pthread_cond_timedwait = __pthread_cond_timedwait, +# if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_3_2) + .ptr___pthread_cond_broadcast_2_0 = __pthread_cond_broadcast_2_0, + .ptr___pthread_cond_destroy_2_0 = __pthread_cond_destroy_2_0, + .ptr___pthread_cond_init_2_0 = __pthread_cond_init_2_0, + .ptr___pthread_cond_signal_2_0 = __pthread_cond_signal_2_0, + .ptr___pthread_cond_wait_2_0 = __pthread_cond_wait_2_0, + .ptr___pthread_cond_timedwait_2_0 = __pthread_cond_timedwait_2_0, +# endif + .ptr_pthread_equal = __pthread_equal, + .ptr___pthread_exit = __pthread_exit, + .ptr_pthread_getschedparam = __pthread_getschedparam, + .ptr_pthread_setschedparam = __pthread_setschedparam, + .ptr_pthread_mutex_destroy = __pthread_mutex_destroy, + .ptr_pthread_mutex_init = __pthread_mutex_init, + .ptr_pthread_mutex_lock = __pthread_mutex_lock, + .ptr_pthread_mutex_unlock = __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, + .ptr___pthread_rwlock_rdlock = __pthread_rwlock_rdlock, + .ptr___pthread_rwlock_wrlock = __pthread_rwlock_wrlock, + .ptr___pthread_rwlock_unlock = __pthread_rwlock_unlock, + .ptr___pthread_key_create = __pthread_key_create, + .ptr___pthread_getspecific = __pthread_getspecific, + .ptr___pthread_setspecific = __pthread_setspecific, + .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, + .ptr_set_robust = __nptl_set_robust + }; +# 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); +} + + +static +#endif +void +__nptl_set_robust (struct pthread *self) +{ +#if 0 + INTERNAL_SYSCALL_DECL (err); + INTERNAL_SYSCALL (set_robust_list, err, 2, &self->robust_head, + sizeof (struct robust_list_head)); +#endif +} + + +/* For asynchronous cancellation we use a signal. This is the handler. */ +static void +sigcancel_handler (int sig, siginfo_t *si, void *ctx) +{ + /* Safety check. It would be possible to call this function for + other signals and send a signal from another process. This is not + correct and might even be a security problem. Try to catch as + many incorrect invocations as possible. */ + if (sig != SIGCANCEL + || si->si_pid != __getpid() +#if 1 + ) +#else + || si->si_code != SI_TKILL) +#endif + 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; + +/* We use the SIGSETXID signal in the setuid, setgid, etc. implementations to + tell each thread to call the respective setxid syscall on itself. This is + the handler. */ +static void +sighandler_setxid (int sig, siginfo_t *si, void *ctx) +{ +#if 0 + /* 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 + || si->si_pid != pid + || 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]); +#endif + /* 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 ((unsigned int *)&__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) +{ + /* Minimal initialization of the thread descriptor. */ + struct pthread *pd = THREAD_SELF; +#if 1 + INLINE_SYSCALL(thr_self, 1, &(pd->ktid)); +#else + INTERNAL_SYSCALL_DECL (err); + pd->tid = INTERNAL_SYSCALL (set_tid_address, err, 1, &pd->tid); +#endif + THREAD_SETMEM (pd, specific[0], &pd->specific_1stblock[0]); + THREAD_SETMEM (pd, user_stack, true); + if (LLL_LOCK_INITIALIZER != 0) + THREAD_SETMEM (pd, lock, LLL_LOCK_INITIALIZER); +#if HP_TIMING_AVAIL + THREAD_SETMEM (pd, cpuclock_offset, GL(dl_cpuclock_offset)); +#endif + + /* 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 (); + +#if 0 +#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 +#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); + INLINE_SYSCALL (sigprocmask, 3, SIG_UNBLOCK, &sa.sa_mask, NULL); + + /* 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; + else if (limit.rlim_cur > (4 * ARCH_STACK_DEFAULT_SIZE)) + /* The system limit is unusably high. + Use the maximal size acceptable. */ + limit.rlim_cur = (4 * ARCH_STACK_DEFAULT_SIZE); + + /* Make sure it meets the minimum size that allocate_stack + (allocatestack.c) will demand, which depends on the page size. */ + const uintptr_t pagesz = GLRO(dl_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 = ALIGN_UP (limit.rlim_cur, pagesz); + lll_lock (__default_pthread_attr_lock, LLL_PRIVATE); + __default_pthread_attr.stacksize = limit.rlim_cur; + __default_pthread_attr.guardsize = GLRO (dl_pagesize); + lll_unlock (__default_pthread_attr_lock, LLL_PRIVATE); + +#ifdef SHARED + /* Make __rtld_lock_{,un}lock_recursive use pthread_mutex_{,un}lock, + keep the lock count from the ld.so implementation. */ + GL(dl_rtld_lock_recursive) = (void *) __pthread_mutex_lock; + GL(dl_rtld_unlock_recursive) = (void *) __pthread_mutex_unlock; + unsigned int rtld_lock_count = GL(dl_load_lock).mutex.__data.__count; + GL(dl_load_lock).mutex.__data.__count = 0; + while (rtld_lock_count-- > 0) + __pthread_mutex_lock (&GL(dl_load_lock).mutex); + + GL(dl_make_stack_executable_hook) = &__make_stacks_executable; +#endif + + GL(dl_init_static_tls) = &__pthread_init_static_tls; + + GL(dl_wait_lookup_done) = &__wait_lookup_done; + + /* 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) + + +size_t +__pthread_get_minstack (const pthread_attr_t *attr) +{ + struct pthread_attr *iattr = (struct pthread_attr *) attr; + + return (GLRO(dl_pagesize) + __static_tls_size + PTHREAD_STACK_MIN + + iattr->guardsize); +} --- /dev/null +++ b/fbtl/old_pthread_atfork.c @@ -0,0 +1,26 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <shlib-compat.h> + +#if SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_3_2) +# define __pthread_atfork __dyn_pthread_atfork +# include "pthread_atfork.c" +# undef __pthread_atfork +compat_symbol (libpthread, __dyn_pthread_atfork, pthread_atfork, GLIBC_2_0); +#endif --- /dev/null +++ b/fbtl/old_pthread_cond_broadcast.c @@ -0,0 +1,56 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <stdlib.h> +#include "pthreadP.h" +#include <atomic.h> +#include <shlib-compat.h> + + +#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_3_2) +int +__pthread_cond_broadcast_2_0 (pthread_cond_2_0_t *cond) +{ + if (cond->cond == NULL) + { + pthread_cond_t *newcond; + +#if LLL_LOCK_INITIALIZER == 0 + newcond = (pthread_cond_t *) calloc (sizeof (pthread_cond_t), 1); + if (newcond == NULL) + return ENOMEM; +#else + newcond = (pthread_cond_t *) malloc (sizeof (pthread_cond_t)); + if (newcond == NULL) + return ENOMEM; + + /* Initialize the condvar. */ + (void) pthread_cond_init (newcond, NULL); +#endif + + if (atomic_compare_and_exchange_bool_acq (&cond->cond, newcond, NULL)) + /* Somebody else just initialized the condvar. */ + free (newcond); + } + + return __pthread_cond_broadcast (cond->cond); +} +compat_symbol (libpthread, __pthread_cond_broadcast_2_0, + pthread_cond_broadcast, GLIBC_2_0); +#endif --- /dev/null +++ b/fbtl/old_pthread_cond_destroy.c @@ -0,0 +1,35 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <stdlib.h> +#include "pthreadP.h" +#include <shlib-compat.h> + + +#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_3_2) +int +__pthread_cond_destroy_2_0 (pthread_cond_2_0_t *cond) +{ + /* Free the memory which was eventually allocated. */ + free (cond->cond); + + return 0; +} +compat_symbol (libpthread, __pthread_cond_destroy_2_0, pthread_cond_destroy, + GLIBC_2_0); +#endif --- /dev/null +++ b/fbtl/old_pthread_cond_init.c @@ -0,0 +1,45 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include "pthreadP.h" +#include <shlib-compat.h> + + +#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_3_2) +int +__pthread_cond_init_2_0 (pthread_cond_2_0_t *cond, + const pthread_condattr_t *cond_attr) +{ + struct pthread_condattr *icond_attr = (struct pthread_condattr *) cond_attr; + + /* The type of the first argument is actually that of the old, too + small pthread_cond_t. We use only the first word of it, as a + pointer. */ + cond->cond = NULL; + + /* We can't support PSHARED condvars in the old pthread_cond_* + functions and neither clocks other than CLOCK_REALTIME. */ + if (icond_attr != NULL && icond_attr->value) + return EINVAL; + + return 0; +} +compat_symbol (libpthread, __pthread_cond_init_2_0, pthread_cond_init, + GLIBC_2_0); +#endif --- /dev/null +++ b/fbtl/old_pthread_cond_signal.c @@ -0,0 +1,56 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <stdlib.h> +#include "pthreadP.h" +#include <atomic.h> +#include <shlib-compat.h> + + +#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_3_2) +int +__pthread_cond_signal_2_0 (pthread_cond_2_0_t *cond) +{ + if (cond->cond == NULL) + { + pthread_cond_t *newcond; + +#if LLL_LOCK_INITIALIZER == 0 + newcond = (pthread_cond_t *) calloc (sizeof (pthread_cond_t), 1); + if (newcond == NULL) + return ENOMEM; +#else + newcond = (pthread_cond_t *) malloc (sizeof (pthread_cond_t)); + if (newcond == NULL) + return ENOMEM; + + /* Initialize the condvar. */ + (void) pthread_cond_init (newcond, NULL); +#endif + + if (atomic_compare_and_exchange_bool_acq (&cond->cond, newcond, NULL)) + /* Somebody else just initialized the condvar. */ + free (newcond); + } + + return __pthread_cond_signal (cond->cond); +} +compat_symbol (libpthread, __pthread_cond_signal_2_0, pthread_cond_signal, + GLIBC_2_0); +#endif --- /dev/null +++ b/fbtl/old_pthread_cond_timedwait.c @@ -0,0 +1,57 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <stdlib.h> +#include "pthreadP.h" +#include <atomic.h> +#include <shlib-compat.h> + + +#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_3_2) +int +__pthread_cond_timedwait_2_0 (pthread_cond_2_0_t *cond, pthread_mutex_t *mutex, + const struct timespec *abstime) +{ + if (cond->cond == NULL) + { + pthread_cond_t *newcond; + +#if LLL_LOCK_INITIALIZER == 0 + newcond = (pthread_cond_t *) calloc (sizeof (pthread_cond_t), 1); + if (newcond == NULL) + return ENOMEM; +#else + newcond = (pthread_cond_t *) malloc (sizeof (pthread_cond_t)); + if (newcond == NULL) + return ENOMEM; + + /* Initialize the condvar. */ + (void) pthread_cond_init (newcond, NULL); +#endif + + if (atomic_compare_and_exchange_bool_acq (&cond->cond, newcond, NULL)) + /* Somebody else just initialized the condvar. */ + free (newcond); + } + + return __pthread_cond_timedwait (cond->cond, mutex, abstime); +} +compat_symbol (libpthread, __pthread_cond_timedwait_2_0, + pthread_cond_timedwait, GLIBC_2_0); +#endif --- /dev/null +++ b/fbtl/old_pthread_cond_wait.c @@ -0,0 +1,56 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <stdlib.h> +#include "pthreadP.h" +#include <atomic.h> +#include <shlib-compat.h> + + +#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_3_2) +int +__pthread_cond_wait_2_0 (pthread_cond_2_0_t *cond, pthread_mutex_t *mutex) +{ + if (cond->cond == NULL) + { + pthread_cond_t *newcond; + +#if LLL_LOCK_INITIALIZER == 0 + newcond = (pthread_cond_t *) calloc (sizeof (pthread_cond_t), 1); + if (newcond == NULL) + return ENOMEM; +#else + newcond = (pthread_cond_t *) malloc (sizeof (pthread_cond_t)); + if (newcond == NULL) + return ENOMEM; + + /* Initialize the condvar. */ + (void) pthread_cond_init (newcond, NULL); +#endif + + if (atomic_compare_and_exchange_bool_acq (&cond->cond, newcond, NULL)) + /* Somebody else just initialized the condvar. */ + free (newcond); + } + + return __pthread_cond_wait (cond->cond, mutex); +} +compat_symbol (libpthread, __pthread_cond_wait_2_0, pthread_cond_wait, + GLIBC_2_0); +#endif --- /dev/null +++ b/fbtl/perf.c @@ -0,0 +1,759 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#define _GNU_SOURCE 1 +#include <argp.h> +#include <error.h> +#include <errno.h> +#include <fcntl.h> +#include <inttypes.h> +#include <limits.h> +#include <pthread.h> +#include <signal.h> +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> +#include <sys/param.h> +#include <sys/types.h> + +#ifndef MAX_THREADS +# define MAX_THREADS 100000 +#endif +#ifndef DEFAULT_THREADS +# define DEFAULT_THREADS 50 +#endif + + +#define OPT_TO_THREAD 300 +#define OPT_TO_PROCESS 301 +#define OPT_SYNC_SIGNAL 302 +#define OPT_SYNC_JOIN 303 +#define OPT_TOPLEVEL 304 + + +static const struct argp_option options[] = + { + { NULL, 0, NULL, 0, "\ +This is a test for threads so we allow ther user to selection the number of \ +threads which are used at any one time. Independently the total number of \ +rounds can be selected. This is the total number of threads which will have \ +run when the process terminates:" }, + { "threads", 't', "NUMBER", 0, "Number of threads used at once" }, + { "starts", 's', "NUMBER", 0, "Total number of working threads" }, + { "toplevel", OPT_TOPLEVEL, "NUMBER", 0, + "Number of toplevel threads which start the other threads; this \ +implies --sync-join" }, + + { NULL, 0, NULL, 0, "\ +Each thread can do one of two things: sleep or do work. The latter is 100% \ +CPU bound. The work load is the probability a thread does work. All values \ +from zero to 100 (inclusive) are valid. How often each thread repeats this \ +can be determined by the number of rounds. The work cost determines how long \ +each work session (not sleeping) takes. If it is zero a thread would \ +effectively nothing. By setting the number of rounds to zero the thread \ +does no work at all and pure thread creation times can be measured." }, + { "workload", 'w', "PERCENT", 0, "Percentage of time spent working" }, + { "workcost", 'c', "NUMBER", 0, + "Factor in the cost of each round of working" }, + { "rounds", 'r', "NUMBER", 0, "Number of rounds each thread runs" }, + + { NULL, 0, NULL, 0, "\ +There are a number of different methods how thread creation can be \ +synchronized. Synchronization is necessary since the number of concurrently \ +running threads is limited." }, + { "sync-signal", OPT_SYNC_SIGNAL, NULL, 0, + "Synchronize using a signal (default)" }, + { "sync-join", OPT_SYNC_JOIN, NULL, 0, "Synchronize using pthread_join" }, + + { NULL, 0, NULL, 0, "\ +One parameter for each threads execution is the size of the stack. If this \ +parameter is not used the system's default stack size is used. If many \ +threads are used the stack size should be chosen quite small." }, + { "stacksize", 'S', "BYTES", 0, "Size of threads stack" }, + { "guardsize", 'g', "BYTES", 0, + "Size of stack guard area; must fit into the stack" }, + + { NULL, 0, NULL, 0, "Signal options:" }, + { "to-thread", OPT_TO_THREAD, NULL, 0, "Send signal to main thread" }, + { "to-process", OPT_TO_PROCESS, NULL, 0, + "Send signal to process (default)" }, + + { NULL, 0, NULL, 0, "Administrative options:" }, + { "progress", 'p', NULL, 0, "Show signs of progress" }, + { "timing", 'T', NULL, 0, + "Measure time from startup to the last thread finishing" }, + { NULL, 0, NULL, 0, NULL } + }; + +/* Prototype for option handler. */ +static error_t parse_opt (int key, char *arg, struct argp_state *state); + +/* Data structure to communicate with argp functions. */ +static struct argp argp = +{ + options, parse_opt +}; + + +static unsigned long int threads = DEFAULT_THREADS; +static unsigned long int workload = 75; +static unsigned long int workcost = 20; +static unsigned long int rounds = 10; +static long int starts = 5000; +static unsigned long int stacksize; +static long int guardsize = -1; +static bool progress; +static bool timing; +static bool to_thread; +static unsigned long int toplevel = 1; + + +static long int running; +static pthread_mutex_t running_mutex = PTHREAD_MUTEX_INITIALIZER; + +static pid_t pid; +static pthread_t tmain; + +static clockid_t cl; +static struct timespec start_time; + + +static pthread_mutex_t sum_mutex = PTHREAD_MUTEX_INITIALIZER; +unsigned int sum; + +static enum + { + sync_signal, + sync_join + } +sync_method; + + +/* We use 64bit values for the times. */ +typedef unsigned long long int hp_timing_t; + + +/* Attributes for all created threads. */ +static pthread_attr_t attr; + + +static void * +work (void *arg) +{ + unsigned long int i; + unsigned int state = (unsigned long int) arg; + + for (i = 0; i < rounds; ++i) + { + /* Determine what to do. */ + unsigned int rnum; + + /* Uniform distribution. */ + do + rnum = rand_r (&state); + while (rnum >= UINT_MAX - (UINT_MAX % 100)); + + rnum %= 100; + + if (rnum < workload) + { + int j; + int a[4] = { i, rnum, i + rnum, rnum - i }; + + if (progress) + write (STDERR_FILENO, "c", 1); + + for (j = 0; j < workcost; ++j) + { + a[0] += a[3] >> 12; + a[1] += a[2] >> 20; + a[2] += a[1] ^ 0x3423423; + a[3] += a[0] - a[1]; + } + + pthread_mutex_lock (&sum_mutex); + sum += a[0] + a[1] + a[2] + a[3]; + pthread_mutex_unlock (&sum_mutex); + } + else + { + /* Just sleep. */ + struct timespec tv; + + tv.tv_sec = 0; + tv.tv_nsec = 10000000; + + if (progress) + write (STDERR_FILENO, "w", 1); + + nanosleep (&tv, NULL); + } + } + + return NULL; +} + + +static void * +thread_function (void *arg) +{ + work (arg); + + pthread_mutex_lock (&running_mutex); + if (--running <= 0 && starts <= 0) + { + /* We are done. */ + if (progress) + write (STDERR_FILENO, "\n", 1); + + if (timing) + { + struct timespec end_time; + + if (clock_gettime (cl, &end_time) == 0) + { + end_time.tv_sec -= start_time.tv_sec; + end_time.tv_nsec -= start_time.tv_nsec; + if (end_time.tv_nsec < 0) + { + end_time.tv_nsec += 1000000000; + --end_time.tv_sec; + } + + printf ("\nRuntime: %lu.%09lu seconds\n", + (unsigned long int) end_time.tv_sec, + (unsigned long int) end_time.tv_nsec); + } + } + + printf ("Result: %08x\n", sum); + + exit (0); + } + pthread_mutex_unlock (&running_mutex); + + if (sync_method == sync_signal) + { + if (to_thread) + /* This code sends a signal to the main thread. */ + pthread_kill (tmain, SIGUSR1); + else + /* Use this code to test sending a signal to the process. */ + kill (pid, SIGUSR1); + } + + if (progress) + write (STDERR_FILENO, "f", 1); + + return NULL; +} + + +struct start_info +{ + unsigned int starts; + unsigned int threads; +}; + + +static void * +start_threads (void *arg) +{ + struct start_info *si = arg; + unsigned int starts = si->starts; + pthread_t ths[si->threads]; + unsigned int state = starts; + unsigned int n; + unsigned int i = 0; + int err; + + if (progress) + write (STDERR_FILENO, "T", 1); + + memset (ths, '\0', sizeof (pthread_t) * si->threads); + + while (starts-- > 0) + { + if (ths[i] != 0) + { + /* Wait for the threads in the order they were created. */ + err = pthread_join (ths[i], NULL); + if (err != 0) + error (EXIT_FAILURE, err, "cannot join thread"); + + if (progress) + write (STDERR_FILENO, "f", 1); + } + + err = pthread_create (&ths[i], &attr, work, + (void *) (long) (rand_r (&state) + starts + i)); + + if (err != 0) + error (EXIT_FAILURE, err, "cannot start thread"); + + if (progress) + write (STDERR_FILENO, "t", 1); + + if (++i == si->threads) + i = 0; + } + + n = i; + do + { + if (ths[i] != 0) + { + err = pthread_join (ths[i], NULL); + if (err != 0) + error (EXIT_FAILURE, err, "cannot join thread"); + + if (progress) + write (STDERR_FILENO, "f", 1); + } + + if (++i == si->threads) + i = 0; + } + while (i != n); + + if (progress) + write (STDERR_FILENO, "F", 1); + + return NULL; +} + + +int +main (int argc, char *argv[]) +{ + int remaining; + sigset_t ss; + pthread_t th; + pthread_t *ths = NULL; + int empty = 0; + int last; + bool cont = true; + + /* Parse and process arguments. */ + argp_parse (&argp, argc, argv, 0, &remaining, NULL); + + if (sync_method == sync_join) + { + ths = (pthread_t *) calloc (threads, sizeof (pthread_t)); + if (ths == NULL) + error (EXIT_FAILURE, errno, + "cannot allocate memory for thread descriptor array"); + + last = threads; + } + else + { + ths = &th; + last = 1; + } + + if (toplevel > threads) + { + printf ("resetting number of toplevel threads to %lu to not surpass number to concurrent threads\n", + threads); + toplevel = threads; + } + + if (timing) + { + if (clock_getcpuclockid (0, &cl) != 0 + || clock_gettime (cl, &start_time) != 0) + timing = false; + } + + /* We need this later. */ + pid = getpid (); + tmain = pthread_self (); + + /* We use signal SIGUSR1 for communication between the threads and + the main thread. We only want sychronous notification. */ + if (sync_method == sync_signal) + { + sigemptyset (&ss); + sigaddset (&ss, SIGUSR1); + if (sigprocmask (SIG_BLOCK, &ss, NULL) != 0) + error (EXIT_FAILURE, errno, "cannot set signal mask"); + } + + /* Create the thread attributes. */ + pthread_attr_init (&attr); + + /* If the user provided a stack size use it. */ + if (stacksize != 0 + && pthread_attr_setstacksize (&attr, stacksize) != 0) + puts ("could not set stack size; will use default"); + /* And stack guard size. */ + if (guardsize != -1 + && pthread_attr_setguardsize (&attr, guardsize) != 0) + puts ("invalid stack guard size; will use default"); + + /* All threads are created detached if we are not using pthread_join + to synchronize. */ + if (sync_method != sync_join) + pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); + + if (sync_method == sync_signal) + { + while (1) + { + int err; + bool do_wait = false; + + pthread_mutex_lock (&running_mutex); + if (starts-- < 0) + cont = false; + else + do_wait = ++running >= threads && starts > 0; + + pthread_mutex_unlock (&running_mutex); + + if (! cont) + break; + + if (progress) + write (STDERR_FILENO, "t", 1); + + err = pthread_create (&ths[empty], &attr, thread_function, + (void *) starts); + if (err != 0) + error (EXIT_FAILURE, err, "cannot start thread %lu", starts); + + if (++empty == last) + empty = 0; + + if (do_wait) + sigwaitinfo (&ss, NULL); + } + + /* Do nothing anymore. On of the threads will terminate the program. */ + sigfillset (&ss); + sigdelset (&ss, SIGINT); + while (1) + sigsuspend (&ss); + } + else + { + pthread_t ths[toplevel]; + struct start_info si[toplevel]; + unsigned int i; + + for (i = 0; i < toplevel; ++i) + { + unsigned int child_starts = starts / (toplevel - i); + unsigned int child_threads = threads / (toplevel - i); + int err; + + si[i].starts = child_starts; + si[i].threads = child_threads; + + err = pthread_create (&ths[i], &attr, start_threads, &si[i]); + if (err != 0) + error (EXIT_FAILURE, err, "cannot start thread"); + + starts -= child_starts; + threads -= child_threads; + } + + for (i = 0; i < toplevel; ++i) + { + int err = pthread_join (ths[i], NULL); + + if (err != 0) + error (EXIT_FAILURE, err, "cannot join thread"); + } + + /* We are done. */ + if (progress) + write (STDERR_FILENO, "\n", 1); + + if (timing) + { + struct timespec end_time; + + if (clock_gettime (cl, &end_time) == 0) + { + end_time.tv_sec -= start_time.tv_sec; + end_time.tv_nsec -= start_time.tv_nsec; + if (end_time.tv_nsec < 0) + { + end_time.tv_nsec += 1000000000; + --end_time.tv_sec; + } + + printf ("\nRuntime: %lu.%09lu seconds\n", + (unsigned long int) end_time.tv_sec, + (unsigned long int) end_time.tv_nsec); + } + } + + printf ("Result: %08x\n", sum); + + exit (0); + } + + /* NOTREACHED */ + return 0; +} + + +/* Handle program arguments. */ +static error_t +parse_opt (int key, char *arg, struct argp_state *state) +{ + unsigned long int num; + long int snum; + + switch (key) + { + case 't': + num = strtoul (arg, NULL, 0); + if (num <= MAX_THREADS) + threads = num; + else + printf ("\ +number of threads limited to %u; recompile with a higher limit if necessary", + MAX_THREADS); + break; + + case 'w': + num = strtoul (arg, NULL, 0); + if (num <= 100) + workload = num; + else + puts ("workload must be between 0 and 100 percent"); + break; + + case 'c': + workcost = strtoul (arg, NULL, 0); + break; + + case 'r': + rounds = strtoul (arg, NULL, 0); + break; + + case 's': + starts = strtoul (arg, NULL, 0); + break; + + case 'S': + num = strtoul (arg, NULL, 0); + if (num >= PTHREAD_STACK_MIN) + stacksize = num; + else + printf ("minimum stack size is %d\n", PTHREAD_STACK_MIN); + break; + + case 'g': + snum = strtol (arg, NULL, 0); + if (snum < 0) + printf ("invalid guard size %s\n", arg); + else + guardsize = snum; + break; + + case 'p': + progress = true; + break; + + case 'T': + timing = true; + break; + + case OPT_TO_THREAD: + to_thread = true; + break; + + case OPT_TO_PROCESS: + to_thread = false; + break; + + case OPT_SYNC_SIGNAL: + sync_method = sync_signal; + break; + + case OPT_SYNC_JOIN: + sync_method = sync_join; + break; + + case OPT_TOPLEVEL: + num = strtoul (arg, NULL, 0); + if (num < MAX_THREADS) + toplevel = num; + else + printf ("\ +number of threads limited to %u; recompile with a higher limit if necessary", + MAX_THREADS); + sync_method = sync_join; + break; + + default: + return ARGP_ERR_UNKNOWN; + } + + return 0; +} + + +static hp_timing_t +get_clockfreq (void) +{ + /* We read the information from the /proc filesystem. It contains at + least one line like + cpu MHz : 497.840237 + or also + cpu MHz : 497.841 + We search for this line and convert the number in an integer. */ + static hp_timing_t result; + int fd; + + /* If this function was called before, we know the result. */ + if (result != 0) + return result; + + fd = open ("/proc/cpuinfo", O_RDONLY); + if (__glibc_likely (fd != -1)) + { + /* XXX AFAIK the /proc filesystem can generate "files" only up + to a size of 4096 bytes. */ + char buf[4096]; + ssize_t n; + + n = read (fd, buf, sizeof buf); + if (__builtin_expect (n, 1) > 0) + { + char *mhz = memmem (buf, n, "cpu MHz", 7); + + if (__glibc_likely (mhz != NULL)) + { + char *endp = buf + n; + int seen_decpoint = 0; + int ndigits = 0; + + /* Search for the beginning of the string. */ + while (mhz < endp && (*mhz < '0' || *mhz > '9') && *mhz != '\n') + ++mhz; + + while (mhz < endp && *mhz != '\n') + { + if (*mhz >= '0' && *mhz <= '9') + { + result *= 10; + result += *mhz - '0'; + if (seen_decpoint) + ++ndigits; + } + else if (*mhz == '.') + seen_decpoint = 1; + + ++mhz; + } + + /* Compensate for missing digits at the end. */ + while (ndigits++ < 6) + result *= 10; + } + } + + close (fd); + } + + return result; +} + + +int +clock_getcpuclockid (pid_t pid, clockid_t *clock_id) +{ + /* We don't allow any process ID but our own. */ + if (pid != 0 && pid != getpid ()) + return EPERM; + +#ifdef CLOCK_PROCESS_CPUTIME_ID + /* Store the number. */ + *clock_id = CLOCK_PROCESS_CPUTIME_ID; + + return 0; +#else + /* We don't have a timer for that. */ + return ENOENT; +#endif +} + + +#ifdef i386 +#define HP_TIMING_NOW(Var) __asm__ __volatile__ ("rdtsc" : "=A" (Var)) +#elif defined __x86_64__ +# define HP_TIMING_NOW(Var) \ + ({ unsigned int _hi, _lo; \ + asm volatile ("rdtsc" : "=a" (_lo), "=d" (_hi)); \ + (Var) = ((unsigned long long int) _hi << 32) | _lo; }) +#elif defined __ia64__ +#define HP_TIMING_NOW(Var) __asm__ __volatile__ ("mov %0=ar.itc" : "=r" (Var) : : "memory") +#else +#error "HP_TIMING_NOW missing" +#endif + +/* Get current value of CLOCK and store it in TP. */ +int +clock_gettime (clockid_t clock_id, struct timespec *tp) +{ + int retval = -1; + + switch (clock_id) + { + case CLOCK_PROCESS_CPUTIME_ID: + { + + static hp_timing_t freq; + hp_timing_t tsc; + + /* Get the current counter. */ + HP_TIMING_NOW (tsc); + + if (freq == 0) + { + freq = get_clockfreq (); + if (freq == 0) + return EINVAL; + } + + /* Compute the seconds. */ + tp->tv_sec = tsc / freq; + + /* And the nanoseconds. This computation should be stable until + we get machines with about 16GHz frequency. */ + tp->tv_nsec = ((tsc % freq) * UINT64_C (1000000000)) / freq; + + retval = 0; + } + break; + + default: + errno = EINVAL; + break; + } + + return retval; +} --- /dev/null +++ b/fbtl/pt-allocrtsig.c @@ -0,0 +1,50 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <signal.h> + + +/* These are defined in libc. We want to have only one definition + so we "forward" the calls. */ +extern int __libc_current_sigrtmin_private (void); +extern int __libc_current_sigrtmax_private (void); +extern int __libc_allocate_rtsig_private (int high); + + +/* We reserve __SIGRTMIN for use as the cancellation signal and + __SIGRTMIN+1 to handle setuid et.al. These signals are used + internally. */ +int +__libc_current_sigrtmin (void) +{ + return __libc_current_sigrtmin_private (); +} + + +int +__libc_current_sigrtmax (void) +{ + return __libc_current_sigrtmax_private (); +} + + +int +__libc_allocate_rtsig (int high) +{ + return __libc_allocate_rtsig_private (high); +} --- /dev/null +++ b/fbtl/pt-cleanup.c @@ -0,0 +1,62 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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) --- /dev/null +++ b/fbtl/pt-crti.S @@ -0,0 +1,43 @@ +/* Special .init and .fini section support for libpthread. + Copyright (C) 2012-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser 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, see + <http://www.gnu.org/licenses/>. */ + +/* Arrange for __pthread_initialize_minimal_internal to be called at + libpthread startup, instead of conditionally calling + __gmon_start__. */ + +#define PREINIT_FUNCTION __pthread_initialize_minimal_internal +#define PREINIT_FUNCTION_WEAK 0 + +#include <crti.S> --- /dev/null +++ b/fbtl/pt-raise.c @@ -0,0 +1,29 @@ +/* ISO C raise function for libpthread. + Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <pthread.h> +#include <signal.h> + + +int +raise (int sig) +{ + /* This is what POSIX says must happen. */ + return pthread_kill (pthread_self (), sig); +} --- /dev/null +++ b/fbtl/pt-system.c @@ -0,0 +1,32 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <stdlib.h> +#include <sysdep.h> +#include "pthreadP.h" + + +int +system (const char *line) +{ + return __libc_system (line); +} + +/* __libc_system in libc.so handles cancellation. */ +LIBC_CANCEL_HANDLED (); --- /dev/null +++ b/fbtl/pthread-errnos.sym @@ -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 --- /dev/null +++ b/fbtl/pthreadP.h @@ -0,0 +1,661 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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 <stackinfo.h> +#include <internaltypes.h> +#include <pthread-functions.h> +#include <atomic.h> +#include <kernel-features.h> +#include <errno.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 pthread attributes. */ +extern struct pthread_attr __default_pthread_attr attribute_hidden; +extern int __default_pthread_attr_lock 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 <= KTID_TERMINATED, 0) +# define INVALID_NOT_TERMINATED_TD_P(pd) __builtin_expect ((pd)->tid < KTID_TERMINATED, 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 && !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 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 IS_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 " __SYMBOL_PREFIX "__libc_enable_asynccancel"); \ + __asm (".globl " __SYMBOL_PREFIX "__libc_disable_asynccancel") +#elif IS_IN (libpthread) +# define LIBC_CANCEL_ASYNC() CANCEL_ASYNC () +# define LIBC_CANCEL_RESET(val) CANCEL_RESET (val) +# define LIBC_CANCEL_HANDLED() \ + __asm (".globl " __SYMBOL_PREFIX "__pthread_enable_asynccancel"); \ + __asm (".globl " __SYMBOL_PREFIX "__pthread_disable_asynccancel") +#elif 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 " __SYMBOL_PREFIX "__librt_enable_asynccancel"); \ + __asm (".globl " __SYMBOL_PREFIX "__librt_disable_asynccancel") +#else +# define LIBC_CANCEL_ASYNC() 0 /* Just a dummy value. */ +# define LIBC_CANCEL_RESET(val) ((void)(val)) /* Nothing, but evaluate it. */ +# define LIBC_CANCEL_HANDLED() /* Nothing. */ +#endif + +#ifndef PTHREAD_SIGBASE +# define PTHREAD_SIGBASE __SIGRTMIN +#endif + +/* The signal used for asynchronous cancelation. */ +#define SIGCANCEL PTHREAD_SIGBASE + + +/* 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 (PTHREAD_SIGBASE + 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 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) + internal_function; +#else +extern int *__libc_pthread_init (unsigned long int *ptr, + void (*reclaim) (void), + const struct pthread_functions *functions) + internal_function; + +/* Variable set to a nonzero value either if more than one thread runs or ran, + or if a single-threaded process is trying to cancel itself. See + nptl/descr.h for more context on the single-threaded process case. */ +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; + +extern size_t __pthread_get_minstack (const pthread_attr_t *attr); + +/* 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_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_cond_lock (pthread_mutex_t *__mutex) + attribute_hidden internal_function; +extern void __pthread_mutex_cond_lock_adjust (pthread_mutex_t *__mutex) + attribute_hidden internal_function; +extern int __pthread_mutex_unlock (pthread_mutex_t *__mutex); +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_tryrdlock (pthread_rwlock_t *__rwlock); +extern int __pthread_rwlock_wrlock (pthread_rwlock_t *__rwlock); +extern int __pthread_rwlock_trywrlock (pthread_rwlock_t *__rwlock); +extern int __pthread_rwlock_unlock (pthread_rwlock_t *__rwlock); +extern int __pthread_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 void *__pthread_getspecific (pthread_key_t key); +extern int __pthread_setspecific (pthread_key_t key, const void *value); +extern int __pthread_once (pthread_once_t *once_control, + void (*init_routine) (void)); +extern int __pthread_atfork (void (*prepare) (void), void (*parent) (void), + void (*child) (void)); +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) __attribute__ ((__noreturn__)); +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; + +#if IS_IN (libpthread) +hidden_proto (__pthread_mutex_init) +hidden_proto (__pthread_mutex_destroy) +hidden_proto (__pthread_mutex_lock) +hidden_proto (__pthread_mutex_unlock) +hidden_proto (__pthread_rwlock_rdlock) +hidden_proto (__pthread_rwlock_wrlock) +hidden_proto (__pthread_rwlock_unlock) +hidden_proto (__pthread_key_create) +hidden_proto (__pthread_getspecific) +hidden_proto (__pthread_setspecific) +hidden_proto (__pthread_once) +hidden_proto (__pthread_setcancelstate) +#endif + +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; + +#if 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; +#ifndef SHARED +extern void __nptl_set_robust (struct pthread *self); +#endif + +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 + +/* Test if the mutex is suitable for the FUTEX_WAIT_REQUEUE_PI operation. */ +#if (defined lll_futex_wait_requeue_pi \ + && defined __ASSUME_REQUEUE_PI) +# define USE_REQUEUE_PI(mut) \ + ((mut) && (mut) != (void *) ~0l \ + && (((mut)->__data.__kind \ + & (PTHREAD_MUTEX_PRIO_INHERIT_NP | PTHREAD_MUTEX_ROBUST_NORMAL_NP)) \ + == PTHREAD_MUTEX_PRIO_INHERIT_NP)) +#else +# define USE_REQUEUE_PI(mut) 0 +#endif + +/* Returns 0 if POL is a valid scheduling policy. */ +static inline int +check_sched_policy_attr (int pol) +{ + if (pol == SCHED_OTHER || pol == SCHED_FIFO || pol == SCHED_RR) + return 0; + + return EINVAL; +} + +/* Returns 0 if PR is within the accepted range of priority values for + the scheduling policy POL or EINVAL otherwise. */ +static inline int +check_sched_priority_attr (int pr, int pol) +{ + int min = __sched_get_priority_min (pol); + int max = __sched_get_priority_max (pol); + + if (min >= 0 && max >= 0 && pr >= min && pr <= max) + return 0; + + return EINVAL; +} + +/* Returns 0 if ST is a valid stack size for a thread stack and EINVAL + otherwise. */ +static inline int +check_stacksize_attr (size_t st) +{ + if (st >= PTHREAD_STACK_MIN) + return 0; + + return EINVAL; +} + +/* Defined in pthread_setaffinity.c. */ +extern size_t __kernel_cpumask_size attribute_hidden; +extern int __determine_cpumask_size (pid_t tid); + +/* Returns 0 if CS and SZ are valid values for the cpuset and cpuset size + respectively. Otherwise it returns an error number. */ +static inline int +check_cpuset_attr (const cpu_set_t *cs, const size_t sz) +{ + if (__kernel_cpumask_size == 0) + { + int res = __determine_cpumask_size (THREAD_SELF->tid); + if (res) + 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 < sz; ++cnt) + if (((char *) cs)[cnt] != '\0') + /* Found a nonzero byte. This means the user request cannot be + fulfilled. */ + return EINVAL; + + return 0; +} + +#endif /* pthreadP.h */ --- /dev/null +++ b/fbtl/pthread_atfork.c @@ -0,0 +1,61 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser 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, see + <http://www.gnu.org/licenses/>. */ + +#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 +#ifndef __pthread_atfork +/* Don't mark the compatibility function as hidden. */ +attribute_hidden +#endif +__pthread_atfork (void (*prepare) (void), void (*parent) (void), + void (*child) (void)) +{ + return __register_atfork (prepare, parent, child, + &__dso_handle == NULL ? NULL : __dso_handle); +} +#ifndef __pthread_atfork +extern int pthread_atfork (void (*prepare) (void), void (*parent) (void), + void (*child) (void)) attribute_hidden; +strong_alias (__pthread_atfork, pthread_atfork) +#endif --- /dev/null +++ b/fbtl/pthread_attr_destroy.c @@ -0,0 +1,44 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <assert.h> +#include <errno.h> +#include <string.h> +#include <unistd.h> +#include "pthreadP.h" +#include <shlib-compat.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; + +#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_1) + /* In old struct pthread_attr, neither next nor cpuset are + present. */ + if (__builtin_expect ((iattr->flags & ATTR_FLAG_OLDATTR), 0) == 0) +#endif + /* The affinity CPU set might be allocated dynamically. */ + free (iattr->cpuset); + + return 0; +} +strong_alias (__pthread_attr_destroy, pthread_attr_destroy) --- /dev/null +++ b/fbtl/pthread_attr_getdetachstate.c @@ -0,0 +1,36 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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) --- /dev/null +++ b/fbtl/pthread_attr_getguardsize.c @@ -0,0 +1,34 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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; +} --- /dev/null +++ b/fbtl/pthread_attr_getinheritsched.c @@ -0,0 +1,37 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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) --- /dev/null +++ b/fbtl/pthread_attr_getschedparam.c @@ -0,0 +1,38 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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) --- /dev/null +++ b/fbtl/pthread_attr_getschedpolicy.c @@ -0,0 +1,36 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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) --- /dev/null +++ b/fbtl/pthread_attr_getscope.c @@ -0,0 +1,37 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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) --- /dev/null +++ b/fbtl/pthread_attr_getstack.c @@ -0,0 +1,38 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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) --- /dev/null +++ b/fbtl/pthread_attr_getstackaddr.c @@ -0,0 +1,42 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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'") --- /dev/null +++ b/fbtl/pthread_attr_getstacksize.c @@ -0,0 +1,45 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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; + + size_t size = iattr->stacksize; + + /* If the user has not set a stack size we return what the system + will use as the default. */ + if (size == 0) + { + lll_lock (__default_pthread_attr_lock, LLL_PRIVATE); + size = __default_pthread_attr.stacksize; + lll_unlock (__default_pthread_attr_lock, LLL_PRIVATE); + } + *stacksize = size; + + return 0; +} +strong_alias (__pthread_attr_getstacksize, pthread_attr_getstacksize) --- /dev/null +++ b/fbtl/pthread_attr_init.c @@ -0,0 +1,85 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <assert.h> +#include <errno.h> +#include <string.h> +#include <unistd.h> +#include "pthreadP.h" + +#include <shlib-compat.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; +} +versioned_symbol (libpthread, __pthread_attr_init_2_1, pthread_attr_init, + GLIBC_2_1); + + +#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_1) +int +__pthread_attr_init_2_0 (pthread_attr_t *attr) +{ + /* This code is specific to the old LinuxThread code which has a too + small pthread_attr_t definition. The struct looked like + this: */ + struct old_attr + { + int detachstate; + int schedpolicy; + struct sched_param schedparam; + int inheritsched; + int scope; + }; + 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 (struct old_attr)); + + iattr = (struct pthread_attr *) attr; + iattr->flags |= ATTR_FLAG_OLDATTR; + + /* We cannot enqueue the attribute because that member is not in the + old attribute structure. */ + return 0; +} +compat_symbol (libpthread, __pthread_attr_init_2_0, pthread_attr_init, + GLIBC_2_0); +#endif --- /dev/null +++ b/fbtl/pthread_attr_setdetachstate.c @@ -0,0 +1,45 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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) --- /dev/null +++ b/fbtl/pthread_attr_setguardsize.c @@ -0,0 +1,37 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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; +} --- /dev/null +++ b/fbtl/pthread_attr_setinheritsched.c @@ -0,0 +1,44 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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) --- /dev/null +++ b/fbtl/pthread_attr_setschedparam.c @@ -0,0 +1,45 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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 ret = check_sched_priority_attr (param->sched_priority, + iattr->schedpolicy); + if (ret) + return ret; + + /* 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) --- /dev/null +++ b/fbtl/pthread_attr_setschedpolicy.c @@ -0,0 +1,45 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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. */ + int ret = check_sched_policy_attr (policy); + if (ret) + return ret; + + /* 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) --- /dev/null +++ b/fbtl/pthread_attr_setscope.c @@ -0,0 +1,48 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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) --- /dev/null +++ b/fbtl/pthread_attr_setstack.c @@ -0,0 +1,92 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <assert.h> +#include <errno.h> +#include <limits.h> +#include "pthreadP.h" + + +#ifndef NEW_VERNUM +# define NEW_VERNUM GLIBC_2_3_3 +#endif + + +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. */ + int ret = check_stacksize_attr (stacksize); + if (ret) + return ret; + +#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 +# include <shlib-compat.h> +versioned_symbol (libpthread, __pthread_attr_setstack, pthread_attr_setstack, + NEW_VERNUM); + +# if SHLIB_COMPAT(libpthread, GLIBC_2_2, NEW_VERNUM) + +int +__old_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 < 16384) + 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; +} + +compat_symbol (libpthread, __old_pthread_attr_setstack, pthread_attr_setstack, + GLIBC_2_2); +# endif + +#endif --- /dev/null +++ b/fbtl/pthread_attr_setstackaddr.c @@ -0,0 +1,44 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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'") --- /dev/null +++ b/fbtl/pthread_attr_setstacksize.c @@ -0,0 +1,81 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <assert.h> +#include <errno.h> +#include <limits.h> +#include "pthreadP.h" + +#ifndef NEW_VERNUM +# define NEW_VERNUM GLIBC_2_3_3 +#endif + + +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. */ + int ret = check_stacksize_attr (stacksize); + if (ret) + return ret; + + iattr->stacksize = stacksize; + + return 0; +} + +#if PTHREAD_STACK_MIN == 16384 +strong_alias (__pthread_attr_setstacksize, pthread_attr_setstacksize) +#else +# include <shlib-compat.h> +versioned_symbol (libpthread, __pthread_attr_setstacksize, + pthread_attr_setstacksize, NEW_VERNUM); + +# if SHLIB_COMPAT(libpthread, GLIBC_2_1, NEW_VERNUM) + +int +__old_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 < 16384) + return EINVAL; + +# ifdef STACKSIZE_ADJUST + STACKSIZE_ADJUST; +# endif + + iattr->stacksize = stacksize; + + return 0; +} + +compat_symbol (libpthread, __old_pthread_attr_setstacksize, + pthread_attr_setstacksize, GLIBC_2_1); +# endif + +#endif --- /dev/null +++ b/fbtl/pthread_barrier_destroy.c @@ -0,0 +1,42 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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 (__glibc_likely (ibarrier->left == ibarrier->init_count)) + /* 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; +} --- /dev/null +++ b/fbtl/pthread_barrier_init.c @@ -0,0 +1,69 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include "pthreadP.h" +#include <lowlevellock.h> +#include <kernel-features.h> + + +static const struct pthread_barrierattr default_barrierattr = + { + .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 (__glibc_unlikely (count == 0)) + return EINVAL; + + const struct pthread_barrierattr *iattr + = (attr != NULL + ? iattr = (struct pthread_barrierattr *) attr + : &default_barrierattr); + + 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; +} --- /dev/null +++ b/fbtl/pthread_barrier_wait.c @@ -0,0 +1,77 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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; +} --- /dev/null +++ b/fbtl/pthread_barrierattr_destroy.c @@ -0,0 +1,28 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include "pthreadP.h" + + +int +pthread_barrierattr_destroy (pthread_barrierattr_t *attr) +{ + /* Nothing to do. */ + + return 0; +} --- /dev/null +++ b/fbtl/pthread_barrierattr_getpshared.c @@ -0,0 +1,29 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include "pthreadP.h" + + +int +pthread_barrierattr_getpshared (const pthread_barrierattr_t *attr, + int *pshared) +{ + *pshared = ((const struct pthread_barrierattr *) attr)->pshared; + + return 0; +} --- /dev/null +++ b/fbtl/pthread_barrierattr_init.c @@ -0,0 +1,28 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include "pthreadP.h" + + +int +pthread_barrierattr_init (pthread_barrierattr_t *attr) +{ + ((struct pthread_barrierattr *) attr)->pshared = PTHREAD_PROCESS_PRIVATE; + + return 0; +} --- /dev/null +++ b/fbtl/pthread_barrierattr_setpshared.c @@ -0,0 +1,37 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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; +} --- /dev/null +++ b/fbtl/pthread_cancel.c @@ -0,0 +1,101 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <signal.h> +#include "pthreadP.h" +#include "atomic.h" +#include <sysdep.h> +#include <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. */ +#warning TODO recheck +#if 1 + result = INLINE_SYSCALL(thr_kill, 2, pd->tid, SIGCANCEL); + +#else + pid_t pid = getpid (); + + INTERNAL_SYSCALL_DECL (err); + int val = INTERNAL_SYSCALL_CALL (tgkill, err, pid, pd->tid, + SIGCANCEL); + + if (INTERNAL_SYSCALL_ERROR_P (val, err)) + result = INTERNAL_SYSCALL_ERRNO (val, err); +#endif + break; + } + + /* A single-threaded process should be able to kill itself, since there is + nothing in the POSIX specification that says that it cannot. So we set + multiple_threads to true so that cancellation points get executed. */ + THREAD_SETMEM (THREAD_SELF, header.multiple_threads, 1); +#ifndef TLS_MULTIPLE_THREADS_IN_TCB + __pthread_multiple_threads = *__libc_multiple_threads_ptr = 1; +#endif + } + /* 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) --- /dev/null +++ b/fbtl/pthread_clock_gettime.c @@ -0,0 +1,68 @@ +/* Copyright (C) 2001-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General 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, see <http://www.gnu.org/licenses/>. */ + +#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 --- /dev/null +++ b/fbtl/pthread_clock_settime.c @@ -0,0 +1,55 @@ +/* Copyright (C) 2001-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General 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, see <http://www.gnu.org/licenses/>. */ + +#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 --- /dev/null +++ b/fbtl/pthread_cond_broadcast.c @@ -0,0 +1,97 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#include <endian.h> +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <pthread.h> +#include <pthreadP.h> +#include <stap-probe.h> + +#include <shlib-compat.h> +#include <kernel-features.h> + + +int +__pthread_cond_broadcast (pthread_cond_t *cond) +{ + LIBC_PROBE (cond_broadcast, 1, 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); + + /* Wake everybody. */ + pthread_mutex_t *mut = (pthread_mutex_t *) cond->__data.__mutex; + + /* Do not use requeue for pshared condvars. */ + if (mut == (void *) ~0l + || PTHREAD_MUTEX_PSHARED (mut) & PTHREAD_MUTEX_PSHARED_BIT) + goto wake_all; +# warning wake all every time +#if 0 +#if (defined lll_futex_cmp_requeue_pi \ + && defined __ASSUME_REQUEUE_PI) + int pi_flag = PTHREAD_MUTEX_PRIO_INHERIT_NP | PTHREAD_MUTEX_ROBUST_NP; + pi_flag &= mut->__data.__kind; + + if (pi_flag == PTHREAD_MUTEX_PRIO_INHERIT_NP) + { + if (lll_futex_cmp_requeue_pi (&cond->__data.__futex, 1, INT_MAX, + &mut->__data.__lock, futex_val, + LLL_PRIVATE) == 0) + return 0; + } + else +#endif + /* 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)) + return 0; +#endif +wake_all: + lll_futex_wake (&cond->__data.__futex, INT_MAX, pshared); + return 0; + } + + /* We are done. */ + lll_unlock (cond->__data.__lock, pshared); + + return 0; +} + +versioned_symbol (libpthread, __pthread_cond_broadcast, pthread_cond_broadcast, + GLIBC_2_3_2); --- /dev/null +++ b/fbtl/pthread_cond_destroy.c @@ -0,0 +1,86 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <shlib-compat.h> +#include "pthreadP.h" +#include <stap-probe.h> + + +int +__pthread_cond_destroy (pthread_cond_t *cond) +{ + int pshared = (cond->__data.__mutex == (void *) ~0l) + ? LLL_SHARED : LLL_PRIVATE; + + LIBC_PROBE (cond_destroy, 1, cond); + + /* 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; +} +versioned_symbol (libpthread, __pthread_cond_destroy, + pthread_cond_destroy, GLIBC_2_3_2); --- /dev/null +++ b/fbtl/pthread_cond_init.c @@ -0,0 +1,47 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <shlib-compat.h> +#include "pthreadP.h" +#include <stap-probe.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; + + LIBC_PROBE (cond_init, 2, cond, cond_attr); + + return 0; +} +versioned_symbol (libpthread, __pthread_cond_init, + pthread_cond_init, GLIBC_2_3_2); --- /dev/null +++ b/fbtl/pthread_cond_signal.c @@ -0,0 +1,90 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#include <endian.h> +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <pthread.h> +#include <pthreadP.h> + +#include <shlib-compat.h> +#include <kernel-features.h> +#include <stap-probe.h> + + +int +__pthread_cond_signal (pthread_cond_t *cond) +{ + int pshared = (cond->__data.__mutex == (void *) ~0l) + ? LLL_SHARED : LLL_PRIVATE; + + LIBC_PROBE (cond_signal, 1, cond); + + /* 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; + +#warning TODO/rework +#if 0 +#if (defined lll_futex_cmp_requeue_pi \ + && defined __ASSUME_REQUEUE_PI) + int pi_flag = PTHREAD_MUTEX_PRIO_INHERIT_NP | PTHREAD_MUTEX_ROBUST_NP; + pthread_mutex_t *mut = cond->__data.__mutex; + + /* Do not use requeue for pshared condvars. */ + if (mut != (void *) ~0l) + pi_flag &= mut->__data.__kind; + + if (__builtin_expect (pi_flag == PTHREAD_MUTEX_PRIO_INHERIT_NP, 0) + /* This can only really fail with a ENOSYS, since nobody can modify + futex while we have the cond_lock. */ + && lll_futex_cmp_requeue_pi (&cond->__data.__futex, 1, 0, + &mut->__data.__lock, + cond->__data.__futex, pshared) == 0) + { + lll_unlock (cond->__data.__lock, pshared); + return 0; + } + else +#endif + /* Wake one. */ + if (! __builtin_expect (lll_futex_wake_unlock (&cond->__data.__futex, + 1, 1, + &cond->__data.__lock, + pshared), 0)) + return 0; +#endif + /* Fallback if neither of them work. */ + lll_futex_wake (&cond->__data.__futex, 1, pshared); + } + + /* We are done. */ + lll_unlock (cond->__data.__lock, pshared); + + return 0; +} + +versioned_symbol (libpthread, __pthread_cond_signal, pthread_cond_signal, + GLIBC_2_3_2); --- /dev/null +++ b/fbtl/pthread_cond_timedwait.c @@ -0,0 +1,267 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#include <endian.h> +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <pthread.h> +#include <pthreadP.h> +#include <kernel-features.h> + +#include <shlib-compat.h> + +#ifndef HAVE_CLOCK_GETTIME_VSYSCALL +# undef INTERNAL_VSYSCALL +# define INTERNAL_VSYSCALL INTERNAL_SYSCALL +# undef INLINE_VSYSCALL +# define INLINE_VSYSCALL INLINE_SYSCALL +#else +# include <bits/libc-vdso.h> +#endif + +/* 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; + +#if (defined lll_futex_timed_wait_requeue_pi \ + && defined __ASSUME_REQUEUE_PI) + int pi_flag = 0; +#endif + + /* Make sure we are alone. */ + 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; + + /* Work around the fact that the kernel rejects negative timeout values + despite them being valid. */ + if (__glibc_unlikely (abstime->tv_sec < 0)) + goto timeout; + + /* 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) + { +#if (!defined __ASSUME_FUTEX_CLOCK_REALTIME \ + || !defined lll_futex_timed_wait_bitset) + struct timespec rt; + { +# if 1 /* used to be ifdef __NR_clock_gettime */ + INTERNAL_SYSCALL_DECL (err); + (void) INTERNAL_VSYSCALL (clock_gettime, err, 2, + (cond->__data.__nwaiters + & ((1 << COND_NWAITERS_SHIFT) - 1)), + &rt); + /* 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 (__glibc_unlikely (rt.tv_sec < 0)) + { + if (cbuffer.bc_seq != cond->__data.__broadcast_seq) + goto bc_out; + + goto timeout; + } +#endif + + 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 (); + +/* REQUEUE_PI was implemented after FUTEX_CLOCK_REALTIME, so it is sufficient + to check just the former. */ +#if (defined lll_futex_timed_wait_requeue_pi \ + && defined __ASSUME_REQUEUE_PI) + /* If pi_flag remained 1 then it means that we had the lock and the mutex + but a spurious waker raced ahead of us. Give back the mutex before + going into wait again. */ + if (pi_flag) + { + __pthread_mutex_cond_lock_adjust (mutex); + __pthread_mutex_unlock_usercnt (mutex, 0); + } + pi_flag = USE_REQUEUE_PI (mutex); + + if (pi_flag) + { + unsigned int clockbit = (cond->__data.__nwaiters & 1 + ? 0 : FUTEX_CLOCK_REALTIME); + err = lll_futex_timed_wait_requeue_pi (&cond->__data.__futex, + futex_val, abstime, clockbit, + &mutex->__data.__lock, + pshared); + pi_flag = (err == 0); + } + else +#endif + + { +#if (!defined __ASSUME_FUTEX_CLOCK_REALTIME \ + || !defined lll_futex_timed_wait_bitset) + /* Wait until woken by signal or broadcast. */ + err = lll_futex_timed_wait (&cond->__data.__futex, + futex_val, &rt, pshared); +#else + unsigned int clockbit = (cond->__data.__nwaiters & 1 + ? 0 : FUTEX_CLOCK_REALTIME); + err = lll_futex_timed_wait_bitset (&cond->__data.__futex, futex_val, + abstime, clockbit, pshared); +#endif + } + + /* 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 (__glibc_unlikely (err == -ETIMEDOUT)) + { + 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. */ +#if (defined lll_futex_timed_wait_requeue_pi \ + && defined __ASSUME_REQUEUE_PI) + if (pi_flag) + { + __pthread_mutex_cond_lock_adjust (mutex); + err = 0; + } + else +#endif + err = __pthread_mutex_cond_lock (mutex); + + return err ?: result; +} + +versioned_symbol (libpthread, __pthread_cond_timedwait, pthread_cond_timedwait, + GLIBC_2_3_2); --- /dev/null +++ b/fbtl/pthread_cond_wait.c @@ -0,0 +1,236 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#include <endian.h> +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <pthread.h> +#include <pthreadP.h> + +#include <shlib-compat.h> +#include <stap-probe.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. We don't try to get the mutex if we already own it. */ + if (!(USE_REQUEUE_PI (cbuffer->mutex)) + || ((cbuffer->mutex->__data.__lock & FUTEX_TID_MASK) + != THREAD_GETMEM (THREAD_SELF, tid))) + { + __pthread_mutex_cond_lock (cbuffer->mutex); + } + else + __pthread_mutex_cond_lock_adjust (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; + +#if (defined lll_futex_wait_requeue_pi \ + && defined __ASSUME_REQUEUE_PI) + int pi_flag = 0; +#endif + + LIBC_PROBE (cond_wait, 2, cond, mutex); + + /* Make sure we are alone. */ + lll_lock (cond->__data.__lock, pshared); + + /* Now we can release the mutex. */ + err = __pthread_mutex_unlock_usercnt (mutex, 0); + if (__glibc_unlikely (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; + + 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 (); + +#if (defined lll_futex_wait_requeue_pi \ + && defined __ASSUME_REQUEUE_PI) + /* If pi_flag remained 1 then it means that we had the lock and the mutex + but a spurious waker raced ahead of us. Give back the mutex before + going into wait again. */ + if (pi_flag) + { + __pthread_mutex_cond_lock_adjust (mutex); + __pthread_mutex_unlock_usercnt (mutex, 0); + } + pi_flag = USE_REQUEUE_PI (mutex); + + if (pi_flag) + { + err = lll_futex_wait_requeue_pi (&cond->__data.__futex, + futex_val, &mutex->__data.__lock, + pshared); + + pi_flag = (err == 0); + } + else +#endif + /* 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. Not needed for PI. */ +#if (defined lll_futex_wait_requeue_pi \ + && defined __ASSUME_REQUEUE_PI) + if (pi_flag) + { + __pthread_mutex_cond_lock_adjust (mutex); + return 0; + } + else +#endif + return __pthread_mutex_cond_lock (mutex); +} + +versioned_symbol (libpthread, __pthread_cond_wait, pthread_cond_wait, + GLIBC_2_3_2); --- /dev/null +++ b/fbtl/pthread_condattr_destroy.c @@ -0,0 +1,28 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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) --- /dev/null +++ b/fbtl/pthread_condattr_getclock.c @@ -0,0 +1,28 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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; +} --- /dev/null +++ b/fbtl/pthread_condattr_getpshared.c @@ -0,0 +1,28 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include "pthreadP.h" + + +int +pthread_condattr_getpshared (const pthread_condattr_t *attr, int *pshared) +{ + *pshared = ((const struct pthread_condattr *) attr)->value & 1; + + return 0; +} --- /dev/null +++ b/fbtl/pthread_condattr_init.c @@ -0,0 +1,30 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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) --- /dev/null +++ b/fbtl/pthread_condattr_setclock.c @@ -0,0 +1,46 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#include <assert.h> +#include <errno.h> +#include <stdbool.h> +#include <time.h> +#include <sysdep.h> +#include "pthreadP.h" +#include <kernel-features.h> + + +int +pthread_condattr_setclock (pthread_condattr_t *attr, clockid_t clock_id) +{ + /* Only a few clocks are allowed. */ + if (clock_id != CLOCK_MONOTONIC && 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; +} --- /dev/null +++ b/fbtl/pthread_condattr_setpshared.c @@ -0,0 +1,34 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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; +} --- /dev/null +++ b/fbtl/pthread_create.c @@ -0,0 +1,669 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <ctype.h> +#include <errno.h> +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> +#include "pthreadP.h" +#include <hp-timing.h> +#include <ldsodefs.h> +#include <atomic.h> +#include <libc-internal.h> +#include <resolv.h> +#include <kernel-features.h> +#include <exit-thread.h> + +#include <shlib-compat.h> + +#include <stap-probe.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 (__glibc_unlikely (pd->tpp != NULL)) + { + 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 + +#if 1 + _FPU_SETCW(pd->fpu_control_init); +#endif + + /* Initialize resolver state pointer. */ + __resp = &pd->res; + + /* Initialize pointers to locale data. */ + __ctype_init (); + + /* Allow setxid from now onwards. */ + if (__glibc_unlikely (atomic_exchange_acq (&pd->setxid_futex, 0) == -2)) + lll_futex_wake (&pd->setxid_futex, 1, LLL_PRIVATE); + +#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 (__glibc_unlikely (pd->parent_cancelhandling & CANCELING_BITMASK)) + { + sigset_t mask; + __sigemptyset (&mask); + __sigaddset (&mask, SIGCANCEL); + INLINE_SYSCALL (sigprocmask, 3, SIG_UNBLOCK, &mask, NULL); + } + + /* 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 (__glibc_likely (! not_first_call)) + { + /* Store the new cleanup handler info. */ + THREAD_SETMEM (pd, cleanup_jmp_buf, &unwind_buf); + + if (__glibc_unlikely (pd->stopped_start)) + { + 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); + } + + LIBC_PROBE (pthread_start, 3, (pthread_t) pd, pd->start_routine, pd->arg); + + /* 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 + } + + /* Call destructors for the thread_local TLS variables. */ +#ifndef SHARED + if (&__call_tls_dtors != NULL) +#endif + __call_tls_dtors (); + + /* Run the destructor for the thread-local data. */ + __nptl_deallocate_tsd (); + + /* Clean up any state libc stored in thread-local variables. */ + __libc_thread_freeres (); + + /* If this is the last thread we terminate the process now. We + do not notify the debugger, it might just irritate it if there + is no thread left. */ + if (__glibc_unlikely (atomic_decrement_and_test (&__nptl_nthreads))) + /* This was the last thread. */ + exit (0); + + /* Report the death of the thread if this is wanted. */ + if (__glibc_unlikely (pd->report_events)) + { + /* 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); + +#warning robust misc +#if 0 +#ifndef __ASSUME_SET_ROBUST_LIST + /* If this thread has any robust mutexes locked, handle them now. */ +# ifdef __PTHREAD_MUTEX_HAVE_PREV + 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 +#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 (__glibc_unlikely (pd->cancelhandling & SETXID_BITMASK)) + { + /* 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_CHILD_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 (); + + /* NOTREACHED */ + return 0; +} + + +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; + struct pthread_attr default_attr; + bool free_cpuset = false; + if (iattr == NULL) + { + lll_lock (__default_pthread_attr_lock, LLL_PRIVATE); + default_attr = __default_pthread_attr; + size_t cpusetsize = default_attr.cpusetsize; + if (cpusetsize > 0) + { + cpu_set_t *cpuset; + if (__glibc_likely (__libc_use_alloca (cpusetsize))) + cpuset = __alloca (cpusetsize); + else + { + cpuset = malloc (cpusetsize); + if (cpuset == NULL) + { + lll_unlock (__default_pthread_attr_lock, LLL_PRIVATE); + return ENOMEM; + } + free_cpuset = true; + } + memcpy (cpuset, default_attr.cpuset, cpusetsize); + default_attr.cpuset = cpuset; + } + lll_unlock (__default_pthread_attr_lock, LLL_PRIVATE); + iattr = &default_attr; + } + + struct pthread *pd = NULL; + int err = ALLOCATE_STACK (iattr, &pd); + int retval = 0; + + if (__glibc_unlikely (err != 0)) + /* Something went wrong. Maybe a parameter of the attributes is + invalid or we could not allocate memory. Note we have to + translate error codes. */ + { + retval = err == ENOMEM ? EAGAIN : err; + goto out; + } + + + /* 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; + +#if 1 + _FPU_GETCW(pd->fpu_control_init); +#endif + + /* 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 + +#warning scheduling parameters +#if 0 + /* Determine scheduling parameters for the thread. */ + if (__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) + { + /* Perhaps a thread wants to change the IDs and if waiting + for this stillborn thread. */ + if (__builtin_expect (atomic_exchange_acq (&pd->setxid_futex, 0) + == -2, 0)) + lll_futex_wake (&pd->setxid_futex, 1, LLL_PRIVATE); + + __deallocate_stack (pd); + + retval = EINVAL; + goto out; + } + } +#endif + + /* Pass the descriptor to the caller. */ + *newthread = (pthread_t) pd; + + LIBC_PROBE (pthread_create, 4, newthread, attr, start_routine, arg); + + /* Start the thread. */ + retval = create_thread (pd, iattr, STACK_VARIABLES_ARGS); + + out: + if (__glibc_unlikely (free_cpuset)) + free (default_attr.cpuset); + + return retval; +} +versioned_symbol (libpthread, __pthread_create_2_1, pthread_create, GLIBC_2_1); + + +#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_1) +int +__pthread_create_2_0 (newthread, attr, start_routine, arg) + pthread_t *newthread; + const pthread_attr_t *attr; + void *(*start_routine) (void *); + void *arg; +{ + /* The ATTR attribute is not really of type `pthread_attr_t *'. It has + the old size and access to the new members might crash the program. + We convert the struct now. */ + struct pthread_attr new_attr; + + if (attr != NULL) + { + struct pthread_attr *iattr = (struct pthread_attr *) attr; + size_t ps = __getpagesize (); + + /* Copy values from the user-provided attributes. */ + new_attr.schedparam = iattr->schedparam; + new_attr.schedpolicy = iattr->schedpolicy; + new_attr.flags = iattr->flags; + + /* Fill in default values for the fields not present in the old + implementation. */ + new_attr.guardsize = ps; + new_attr.stackaddr = NULL; + new_attr.stacksize = 0; + new_attr.cpuset = NULL; + + /* We will pass this value on to the real implementation. */ + attr = (pthread_attr_t *) &new_attr; + } + + return __pthread_create_2_1 (newthread, attr, start_routine, arg); +} +compat_symbol (libpthread, __pthread_create_2_0, pthread_create, + GLIBC_2_0); +#endif + +/* Information for libthread_db. */ + +#include "../fbtl_db/db_info.c" + +/* If pthread_create is present, libgcc_eh.a and libsupc++.a expects some other POSIX thread + functions to be present as well. */ +PTHREAD_STATIC_FN_REQUIRE (pthread_mutex_lock) +PTHREAD_STATIC_FN_REQUIRE (pthread_mutex_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) --- /dev/null +++ b/fbtl/pthread_detach.c @@ -0,0 +1,55 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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; +} --- /dev/null +++ b/fbtl/pthread_equal.c @@ -0,0 +1,27 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include "pthreadP.h" + + +int +__pthread_equal (pthread_t thread1, pthread_t thread2) +{ + return thread1 == thread2; +} +strong_alias (__pthread_equal, pthread_equal) --- /dev/null +++ b/fbtl/pthread_exit.c @@ -0,0 +1,34 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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) + +/* After a thread terminates, __libc_start_main decrements + __nptl_nthreads defined in pthread_create.c. */ +PTHREAD_STATIC_FN_REQUIRE (pthread_create) --- /dev/null +++ b/fbtl/pthread_getattr_default_np.c @@ -0,0 +1,37 @@ +/* Get the default attributes used by pthread_create in the process. + Copyright (C) 2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <stdlib.h> +#include <pthreadP.h> +#include <assert.h> + +int +pthread_getattr_default_np (pthread_attr_t *out) +{ + struct pthread_attr *real_out; + + assert (sizeof (*out) >= sizeof (struct pthread_attr)); + real_out = (struct pthread_attr *) out; + + lll_lock (__default_pthread_attr_lock, LLL_PRIVATE); + *real_out = __default_pthread_attr; + lll_unlock (__default_pthread_attr_lock, LLL_PRIVATE); + + return 0; +} --- /dev/null +++ b/fbtl/pthread_getattr_np.c @@ -0,0 +1,198 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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 (__glibc_likely (thread->stackblock != NULL)) + { + 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. */ + + /* 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", "rce"); + 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 consider the main process stack to have ended with + the page containing __libc_stack_end. There is stuff below + it in the stack too, like the program arguments, environment + variables and auxv info, but we ignore those pages when + returning size so that the output is consistent when the + stack is marked executable due to a loaded DSO requiring + it. */ + void *stack_end = (void *) ((uintptr_t) __libc_stack_end + & -(uintptr_t) GLRO(dl_pagesize)); +#if _STACK_GROWS_DOWN + stack_end += GLRO(dl_pagesize); +#endif + /* 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->stackaddr = stack_end; + iattr->stacksize = + rl.rlim_cur - (size_t) (to - (uintptr_t) stack_end); + + /* Cut it down to align it to page size since otherwise we + risk going beyond rlimit when the kernel rounds up the + stack extension request. */ + iattr->stacksize = (iattr->stacksize + & -(intptr_t) GLRO(dl_pagesize)); + + /* 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; +#if 1 +#warning not yet pthread_getaffinity_np + ret = ENOSYS; +#else + ret = __pthread_getaffinity_np (thread_id, size, cpuset); +#endif + } + /* 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; +} --- /dev/null +++ b/fbtl/pthread_getconcurrency.c @@ -0,0 +1,26 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include "pthreadP.h" + + +int +pthread_getconcurrency (void) +{ + return __concurrency_level; +} --- /dev/null +++ b/fbtl/pthread_getcpuclockid.c @@ -0,0 +1,54 @@ +/* Copyright (C) 2000-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General 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, see <http://www.gnu.org/licenses/>. */ + +#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 +} --- /dev/null +++ b/fbtl/pthread_getschedparam.c @@ -0,0 +1,72 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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) --- /dev/null +++ b/fbtl/pthread_getspecific.c @@ -0,0 +1,67 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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 (__glibc_likely (key < PTHREAD_KEY_2NDLEVEL_SIZE)) + 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 (__glibc_unlikely (seq != __pthread_keys[key].seq)) + result = data->data = NULL; + } + + return result; +} +strong_alias (__pthread_getspecific, pthread_getspecific) +hidden_def (__pthread_getspecific) --- /dev/null +++ b/fbtl/pthread_join.c @@ -0,0 +1,117 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <stdlib.h> + +#include <atomic.h> +#include "pthreadP.h" + +#include <stap-probe.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; + + LIBC_PROBE (pthread_join, 1, threadid); + + /* 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->ktid); + + + /* Restore cancellation mode. */ + CANCEL_RESET (oldtype); + + /* Remove the handler. */ + pthread_cleanup_pop (0); + + + if (__glibc_likely (result == 0)) + { + /* 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); + } + + LIBC_PROBE (pthread_join_ret, 3, threadid, result, pd->result); + + return result; +} --- /dev/null +++ b/fbtl/pthread_key_create.c @@ -0,0 +1,51 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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) +hidden_def (__pthread_key_create) --- /dev/null +++ b/fbtl/pthread_key_delete.c @@ -0,0 +1,41 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include "pthreadP.h" +#include <atomic.h> + + +int +pthread_key_delete (pthread_key_t key) +{ + int result = EINVAL; + + if (__glibc_likely (key < PTHREAD_KEYS_MAX)) + { + 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; +} --- /dev/null +++ b/fbtl/pthread_kill_other_threads.c @@ -0,0 +1,36 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <shlib-compat.h> + + +#ifdef SHARED +/* This function does not serve a useful purpose in the thread library + implementation anymore. It used to be necessary when then kernel + could not shut down "processes" but this is not the case anymore. + + We could theoretically provide an equivalent implementation but + this is not necessary since the kernel already does a much better + job than we ever could. */ +void +__pthread_kill_other_threads_np (void) +{ +} +compat_symbol (libpthread, __pthread_kill_other_threads_np, + pthread_kill_other_threads_np, GLIBC_2_0); +#endif --- /dev/null +++ b/fbtl/pthread_mutex_consistent.c @@ -0,0 +1,35 @@ +/* Copyright (C) 2005-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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) --- /dev/null +++ b/fbtl/pthread_mutex_destroy.c @@ -0,0 +1,40 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include "pthreadP.h" + +#include <stap-probe.h> + + +int +__pthread_mutex_destroy (pthread_mutex_t *mutex) +{ + LIBC_PROBE (mutex_destroy, 1, 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) +hidden_def (__pthread_mutex_destroy) --- /dev/null +++ b/fbtl/pthread_mutex_getprioceiling.c @@ -0,0 +1,35 @@ +/* Get current priority ceiling of pthread_mutex_t. + Copyright (C) 2006-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <pthreadP.h> + + +int +pthread_mutex_getprioceiling (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; +} --- /dev/null +++ b/fbtl/pthread_mutex_init.c @@ -0,0 +1,149 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <assert.h> +#include <errno.h> +#include <string.h> +#include <kernel-features.h> +#include "pthreadP.h" + +#include <stap-probe.h> + +static const struct pthread_mutexattr default_mutexattr = + { + /* 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_mutexattr); + + /* 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; +#if 0 + case PTHREAD_PRIO_INHERIT << PTHREAD_MUTEXATTR_PROTOCOL_SHIFT: +#ifndef __ASSUME_FUTEX_LOCK_PI + if (__glibc_unlikely (tpi_supported == 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 (__glibc_unlikely (tpi_supported < 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; +#else + default: + return ENOTSUP; +#endif + } + + /* 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; + +#warning not supported protocols +#if 0 + 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; + } +#endif + /* 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 + + LIBC_PROBE (mutex_init, 1, mutex); + + return 0; +} +strong_alias (__pthread_mutex_init, pthread_mutex_init) +hidden_def (__pthread_mutex_init) --- /dev/null +++ b/fbtl/pthread_mutex_lock.c @@ -0,0 +1,504 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <assert.h> +#include <errno.h> +#include <stdlib.h> +#include <unistd.h> +#include <not-cancel.h> +#include "pthreadP.h" +#include <lowlevellock.h> +#include <stap-probe.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); + + LIBC_PROBE (mutex_entry, 1, 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 (__glibc_unlikely (mutex->__data.__count + 1 == 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 (__glibc_unlikely (mutex->__data.__owner == id)) + return EDEADLK; + goto simple; + } + + /* Record the ownership. */ + mutex->__data.__owner = id; +#ifndef NO_INCR + ++mutex->__data.__nusers; +#endif + + LIBC_PROBE (mutex_acquired, 1, mutex); + + return 0; +} + +static int +__pthread_mutex_lock_full (pthread_mutex_t *mutex) +{ +#if 1 + return EINVAL; +#else + 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 (__glibc_unlikely ((oldval & FUTEX_TID_MASK) == id)) + { + 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 (__glibc_unlikely (mutex->__data.__count + 1 == 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 (__glibc_unlikely ((oldval & FUTEX_TID_MASK) == id)) + { + 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 (__glibc_unlikely (mutex->__data.__count + 1 == 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 (__glibc_unlikely (oldval & FUTEX_OWNER_DIED)) + { + 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 (__glibc_unlikely (mutex->__data.__count + 1 == 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 + + LIBC_PROBE (mutex_acquired, 1, mutex); + + return 0; +#endif +} +#ifndef __pthread_mutex_lock +strong_alias (__pthread_mutex_lock, pthread_mutex_lock) +hidden_def (__pthread_mutex_lock) +#endif + + +#ifdef NO_INCR +void +internal_function +__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 --- /dev/null +++ b/fbtl/pthread_mutex_setprioceiling.c @@ -0,0 +1,116 @@ +/* Set current priority ceiling of pthread_mutex_t. + Copyright (C) 2006-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#include <stdbool.h> +#include <errno.h> +#include <pthreadP.h> + + +int +pthread_mutex_setprioceiling (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; +} --- /dev/null +++ b/fbtl/pthread_mutex_timedlock.c @@ -0,0 +1,495 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <assert.h> +#include <errno.h> +#include <time.h> +#include "pthreadP.h" +#include <lowlevellock.h> +#include <not-cancel.h> + +#include <stap-probe.h> + + +int +pthread_mutex_timedlock (pthread_mutex_t *mutex, + const struct timespec *abstime) +{ + int oldval; + pid_t id = THREAD_GETMEM (THREAD_SELF, tid); + int result = 0; + + LIBC_PROBE (mutex_timedlock_entry, 2, mutex, abstime); + + /* 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 (__glibc_unlikely (mutex->__data.__count + 1 == 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 (__glibc_unlikely (mutex->__data.__owner == id)) + 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; + +#if 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 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 (__glibc_unlikely ((oldval & FUTEX_TID_MASK) == id)) + { + 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 (__glibc_unlikely (mutex->__data.__count + 1 == 0)) + /* Overflow of the counter. */ + return EAGAIN; + + ++mutex->__data.__count; + + LIBC_PROBE (mutex_timedlock_acquired, 1, mutex); + + 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 (__glibc_unlikely ((oldval & FUTEX_TID_MASK) == id)) + { + 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 (__glibc_unlikely (mutex->__data.__count + 1 == 0)) + /* Overflow of the counter. */ + return EAGAIN; + + ++mutex->__data.__count; + + LIBC_PROBE (mutex_timedlock_acquired, 1, mutex); + + 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 (__glibc_unlikely (oldval & FUTEX_OWNER_DIED)) + { + 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 (__glibc_unlikely (mutex->__data.__count + 1 == 0)) + /* Overflow of the counter. */ + return EAGAIN; + + ++mutex->__data.__count; + + LIBC_PROBE (mutex_timedlock_acquired, 1, mutex); + + 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; +#endif + default: + /* Correct code cannot set any other type. */ + return EINVAL; + } + + if (result == 0) + { + /* Record the ownership. */ + mutex->__data.__owner = id; + ++mutex->__data.__nusers; + + LIBC_PROBE (mutex_timedlock_acquired, 1, mutex); + } + + out: + return result; +} --- /dev/null +++ b/fbtl/pthread_mutex_trylock.c @@ -0,0 +1,380 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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 (__glibc_unlikely (mutex->__data.__count + 1 == 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; +#if 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 (__glibc_unlikely ((oldval & FUTEX_TID_MASK) == id)) + { + 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 (__glibc_unlikely (mutex->__data.__count + 1 == 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 (__glibc_unlikely ((oldval & FUTEX_TID_MASK) == id)) + { + 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 (__glibc_unlikely (mutex->__data.__count + 1 == 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 (__glibc_unlikely (oldval & FUTEX_OWNER_DIED)) + { + 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 (__glibc_unlikely (mutex->__data.__count + 1 == 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; +#endif + default: + /* Correct code cannot set any other type. */ + return EINVAL; + } + + return EBUSY; +} +strong_alias (__pthread_mutex_trylock, pthread_mutex_trylock) --- /dev/null +++ b/fbtl/pthread_mutex_unlock.c @@ -0,0 +1,312 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <assert.h> +#include <errno.h> +#include <stdlib.h> +#include "pthreadP.h" +#include <lowlevellock.h> +#include <stap-probe.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)); + + LIBC_PROBE (mutex_release, 1, 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) +{ +#if 1 + return EINVAL; +#else + 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. Load all necessary mutex data before releasing the mutex + to not violate the mutex destruction requirements (see + lll_unlock). */ + int robust = mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP; + int private = (robust + ? PTHREAD_ROBUST_MUTEX_PSHARED (mutex) + : PTHREAD_MUTEX_PSHARED (mutex)); + /* Unlock the mutex using a CAS unless there are futex waiters or our + TID is not the value of __lock anymore, in which case we let the + kernel take care of the situation. Use release MO in the CAS to + synchronize with acquire MO in lock acquisitions. */ + int l = atomic_load_relaxed (&mutex->__data.__lock); + do + { + if (((l & FUTEX_WAITERS) != 0) + || (l != THREAD_GETMEM (THREAD_SELF, tid))) + { + INTERNAL_SYSCALL_DECL (__err); + INTERNAL_SYSCALL (futex, __err, 2, &mutex->__data.__lock, + __lll_private_flag (FUTEX_UNLOCK_PI, private)); + break; + } + } + while (!atomic_compare_exchange_weak_release (&mutex->__data.__lock, + &l, 0)); + + 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; + + LIBC_PROBE (mutex_release, 1, mutex); + + return __pthread_tpp_change_priority (oldprio, -1); + + default: + /* Correct code cannot set any other type. */ + return EINVAL; + } + + LIBC_PROBE (mutex_release, 1, mutex); + return 0; +#endif +} + + +int +__pthread_mutex_unlock (pthread_mutex_t *mutex) +{ + return __pthread_mutex_unlock_usercnt (mutex, 1); +} +strong_alias (__pthread_mutex_unlock, pthread_mutex_unlock) +hidden_def (__pthread_mutex_unlock) --- /dev/null +++ b/fbtl/pthread_mutexattr_destroy.c @@ -0,0 +1,27 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <pthreadP.h> + + +int +__pthread_mutexattr_destroy (pthread_mutexattr_t *attr) +{ + return 0; +} +strong_alias (__pthread_mutexattr_destroy, pthread_mutexattr_destroy) --- /dev/null +++ b/fbtl/pthread_mutexattr_getprioceiling.c @@ -0,0 +1,46 @@ +/* Get priority ceiling setting from pthread_mutexattr_t. + Copyright (C) 2006-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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; +} --- /dev/null +++ b/fbtl/pthread_mutexattr_getprotocol.c @@ -0,0 +1,34 @@ +/* Get priority protocol setting from pthread_mutexattr_t. + Copyright (C) 2006-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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; +} --- /dev/null +++ b/fbtl/pthread_mutexattr_getpshared.c @@ -0,0 +1,33 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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; +} --- /dev/null +++ b/fbtl/pthread_mutexattr_getrobust.c @@ -0,0 +1,34 @@ +/* Copyright (C) 2005-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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) --- /dev/null +++ b/fbtl/pthread_mutexattr_gettype.c @@ -0,0 +1,33 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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) --- /dev/null +++ b/fbtl/pthread_mutexattr_init.c @@ -0,0 +1,36 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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) --- /dev/null +++ b/fbtl/pthread_mutexattr_setprioceiling.c @@ -0,0 +1,44 @@ +/* Change priority ceiling setting in pthread_mutexattr_t. + Copyright (C) 2006-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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; +} --- /dev/null +++ b/fbtl/pthread_mutexattr_setprotocol.c @@ -0,0 +1,38 @@ +/* Change priority protocol setting in pthread_mutexattr_t. + Copyright (C) 2006-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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; +} --- /dev/null +++ b/fbtl/pthread_mutexattr_setpshared.c @@ -0,0 +1,40 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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; +} --- /dev/null +++ b/fbtl/pthread_mutexattr_setrobust.c @@ -0,0 +1,41 @@ +/* Copyright (C) 2005-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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) --- /dev/null +++ b/fbtl/pthread_mutexattr_settype.c @@ -0,0 +1,38 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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) --- /dev/null +++ b/fbtl/pthread_once.c @@ -0,0 +1,54 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include "pthreadP.h" +#include <lowlevellock.h> + + + +static int once_lock = LLL_LOCK_INITIALIZER; + + +int +__pthread_once (once_control, init_routine) + 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) +hidden_def (__pthread_once) --- /dev/null +++ b/fbtl/pthread_rwlock_destroy.c @@ -0,0 +1,31 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include "pthreadP.h" +#include <stap-probe.h> + + +int +__pthread_rwlock_destroy (pthread_rwlock_t *rwlock) +{ + LIBC_PROBE (rwlock_destroy, 1, rwlock); + + /* Nothing to be done. For now. */ + return 0; +} +strong_alias (__pthread_rwlock_destroy, pthread_rwlock_destroy) --- /dev/null +++ b/fbtl/pthread_rwlock_init.c @@ -0,0 +1,72 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include "pthreadP.h" +#include <string.h> +#include <kernel-features.h> + + +static const struct pthread_rwlockattr default_rwlockattr = + { + .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_rwlockattr; + + 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) --- /dev/null +++ b/fbtl/pthread_rwlock_rdlock.c @@ -0,0 +1,99 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <pthread.h> +#include <pthreadP.h> +#include <stap-probe.h> + + +/* Acquire read lock for RWLOCK. */ +int +__pthread_rwlock_rdlock (pthread_rwlock_t *rwlock) +{ + int result = 0; + + LIBC_PROBE (rdlock_entry, 1, rwlock); + + /* Make sure we are alone. */ + 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 (__glibc_unlikely (++rwlock->__data.__nr_readers == 0)) + { + /* Overflow on number of readers. */ + --rwlock->__data.__nr_readers; + result = EAGAIN; + } + else + LIBC_PROBE (rdlock_acquire_read, 1, rwlock); + + 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 (__glibc_unlikely (++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. */ + 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) +hidden_def (__pthread_rwlock_rdlock) --- /dev/null +++ b/fbtl/pthread_rwlock_timedrdlock.c @@ -0,0 +1,154 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <pthread.h> +#include <pthreadP.h> +#include <sys/time.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 alone. */ + 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; + } + + /* Work around the fact that the kernel rejects negative timeout values + despite them being valid. */ + if (__glibc_unlikely (abstime->tv_sec < 0)) + { + result = ETIMEDOUT; + break; + } + +#if (!defined __ASSUME_FUTEX_CLOCK_REALTIME \ + || !defined lll_futex_timed_wait_bitset) + /* 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; + } +#endif + + /* 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. */ +#if (!defined __ASSUME_FUTEX_CLOCK_REALTIME \ + || !defined lll_futex_timed_wait_bitset) + err = lll_futex_timed_wait (&rwlock->__data.__readers_wakeup, + waitval, &rt, rwlock->__data.__shared); +#else + err = lll_futex_timed_wait_bitset (&rwlock->__data.__readers_wakeup, + waitval, abstime, + FUTEX_CLOCK_REALTIME, + rwlock->__data.__shared); +#endif + + /* 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; +} --- /dev/null +++ b/fbtl/pthread_rwlock_timedwrlock.c @@ -0,0 +1,145 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <pthread.h> +#include <pthreadP.h> +#include <sys/time.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 alone. */ + 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; + } + + /* Work around the fact that the kernel rejects negative timeout values + despite them being valid. */ + if (__glibc_unlikely (abstime->tv_sec < 0)) + { + result = ETIMEDOUT; + break; + } + +#if (!defined __ASSUME_FUTEX_CLOCK_REALTIME \ + || !defined lll_futex_timed_wait_bitset) + /* 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; + } +#endif + + /* 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. */ +#if (!defined __ASSUME_FUTEX_CLOCK_REALTIME \ + || !defined lll_futex_timed_wait_bitset) + err = lll_futex_timed_wait (&rwlock->__data.__writer_wakeup, + waitval, &rt, rwlock->__data.__shared); +#else + err = lll_futex_timed_wait_bitset (&rwlock->__data.__writer_wakeup, + waitval, abstime, + FUTEX_CLOCK_REALTIME, + rwlock->__data.__shared); +#endif + + /* 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; +} --- /dev/null +++ b/fbtl/pthread_rwlock_tryrdlock.c @@ -0,0 +1,48 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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 (__glibc_unlikely (++rwlock->__data.__nr_readers == 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) --- /dev/null +++ b/fbtl/pthread_rwlock_trywrlock.c @@ -0,0 +1,41 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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) --- /dev/null +++ b/fbtl/pthread_rwlock_unlock.c @@ -0,0 +1,61 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <pthread.h> +#include <pthreadP.h> +#include <stap-probe.h> + +/* Unlock RWLOCK. */ +int +__pthread_rwlock_unlock (pthread_rwlock_t *rwlock) +{ + LIBC_PROBE (rwlock_unlock, 1, 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) +hidden_def (__pthread_rwlock_unlock) --- /dev/null +++ b/fbtl/pthread_rwlock_wrlock.c @@ -0,0 +1,91 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <pthread.h> +#include <pthreadP.h> +#include <stap-probe.h> + + +/* Acquire write lock for RWLOCK. */ +int +__pthread_rwlock_wrlock (pthread_rwlock_t *rwlock) +{ + int result = 0; + + LIBC_PROBE (wrlock_entry, 1, rwlock); + + /* Make sure we are alone. */ + 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); + + LIBC_PROBE (wrlock_acquire_write, 1, rwlock); + 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) +hidden_def (__pthread_rwlock_wrlock) --- /dev/null +++ b/fbtl/pthread_rwlockattr_destroy.c @@ -0,0 +1,28 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include "pthreadP.h" + + +int +pthread_rwlockattr_destroy (pthread_rwlockattr_t *attr) +{ + /* Nothing to do. For now. */ + + return 0; +} --- /dev/null +++ b/fbtl/pthread_rwlockattr_getkind_np.c @@ -0,0 +1,28 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include "pthreadP.h" + + +int +pthread_rwlockattr_getkind_np (const pthread_rwlockattr_t *attr, int *pref) +{ + *pref = ((const struct pthread_rwlockattr *) attr)->lockkind; + + return 0; +} --- /dev/null +++ b/fbtl/pthread_rwlockattr_getpshared.c @@ -0,0 +1,28 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include "pthreadP.h" + + +int +pthread_rwlockattr_getpshared (const pthread_rwlockattr_t *attr, int *pshared) +{ + *pshared = ((const struct pthread_rwlockattr *) attr)->pshared; + + return 0; +} --- /dev/null +++ b/fbtl/pthread_rwlockattr_init.c @@ -0,0 +1,33 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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; +} --- /dev/null +++ b/fbtl/pthread_rwlockattr_setkind_np.c @@ -0,0 +1,38 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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; +} --- /dev/null +++ b/fbtl/pthread_rwlockattr_setpshared.c @@ -0,0 +1,37 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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; +} --- /dev/null +++ b/fbtl/pthread_self.c @@ -0,0 +1,28 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include "pthreadP.h" +#include <tls.h> + + +pthread_t +__pthread_self (void) +{ + return (pthread_t) THREAD_SELF; +} +strong_alias (__pthread_self, pthread_self) --- /dev/null +++ b/fbtl/pthread_setattr_default_np.c @@ -0,0 +1,116 @@ +/* Set the default attributes to be used by pthread_create in the process. + Copyright (C) 2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <stdlib.h> +#include <pthreadP.h> +#include <assert.h> +#include <string.h> + +int +pthread_setattr_default_np (const pthread_attr_t *in) +{ + const struct pthread_attr *real_in; + struct pthread_attr attrs; + int ret; + + assert (sizeof (*in) >= sizeof (struct pthread_attr)); + real_in = (struct pthread_attr *) in; + +#if 1 +#warning scheduling attributes not yet supported +#else + + /* Catch invalid values. */ + int policy = real_in->schedpolicy; + ret = check_sched_policy_attr (policy); + if (ret) + return ret; + + const struct sched_param *param = &real_in->schedparam; + if (param->sched_priority > 0) + { + ret = check_sched_priority_attr (param->sched_priority, policy); + if (ret) + return ret; + } + + ret = check_cpuset_attr (real_in->cpuset, real_in->cpusetsize); + if (ret) + return ret; +#endif + + /* stacksize == 0 is fine. It means that we don't change the current + value. */ + if (real_in->stacksize != 0) + { + ret = check_stacksize_attr (real_in->stacksize); + if (ret) + return ret; + } + + /* Having a default stack address is wrong. */ + if (real_in->flags & ATTR_FLAG_STACKADDR) + return EINVAL; + + attrs = *real_in; + + /* Now take the lock because we start writing into + __default_pthread_attr. */ + lll_lock (__default_pthread_attr_lock, LLL_PRIVATE); + + /* Free the cpuset if the input is 0. Otherwise copy in the cpuset + contents. */ + size_t cpusetsize = attrs.cpusetsize; + if (cpusetsize == 0) + { + free (__default_pthread_attr.cpuset); + __default_pthread_attr.cpuset = NULL; + } + else if (cpusetsize == __default_pthread_attr.cpusetsize) + { + attrs.cpuset = __default_pthread_attr.cpuset; + memcpy (attrs.cpuset, real_in->cpuset, cpusetsize); + } + else + { + /* This may look wrong at first sight, but it isn't. We're freeing + __default_pthread_attr.cpuset and allocating to attrs.cpuset because + we'll copy over all of attr to __default_pthread_attr later. */ + cpu_set_t *newp = realloc (__default_pthread_attr.cpuset, + cpusetsize); + + if (newp == NULL) + { + ret = ENOMEM; + goto out; + } + + attrs.cpuset = newp; + memcpy (attrs.cpuset, real_in->cpuset, cpusetsize); + } + + /* We don't want to accidentally set the default stacksize to zero. */ + if (attrs.stacksize == 0) + attrs.stacksize = __default_pthread_attr.stacksize; + __default_pthread_attr = attrs; + + out: + lll_unlock (__default_pthread_attr_lock, LLL_PRIVATE); + return ret; +} --- /dev/null +++ b/fbtl/pthread_setcancelstate.c @@ -0,0 +1,71 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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 (__glibc_likely (curval == oldval)) + { + 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) +hidden_def (__pthread_setcancelstate) --- /dev/null +++ b/fbtl/pthread_setcanceltype.c @@ -0,0 +1,73 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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 (__glibc_likely (curval == oldval)) + { + 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) --- /dev/null +++ b/fbtl/pthread_setconcurrency.c @@ -0,0 +1,39 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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; +} --- /dev/null +++ b/fbtl/pthread_setegid.c @@ -0,0 +1,3 @@ +#define SINGLE_THREAD +#define setegid pthread_setegid_np +#include <setegid.c> --- /dev/null +++ b/fbtl/pthread_seteuid.c @@ -0,0 +1,3 @@ +#define SINGLE_THREAD +#define seteuid pthread_seteuid_np +#include <seteuid.c> --- /dev/null +++ b/fbtl/pthread_setgid.c @@ -0,0 +1,3 @@ +#define SINGLE_THREAD +#define __setgid pthread_setgid_np +#include <setgid.c> --- /dev/null +++ b/fbtl/pthread_setregid.c @@ -0,0 +1,3 @@ +#define SINGLE_THREAD +#define __setregid pthread_setregid_np +#include <setregid.c> --- /dev/null +++ b/fbtl/pthread_setresgid.c @@ -0,0 +1,3 @@ +#define SINGLE_THREAD +#define __setresgid pthread_setresgid_np +#include <setresgid.c> --- /dev/null +++ b/fbtl/pthread_setresuid.c @@ -0,0 +1,3 @@ +#define SINGLE_THREAD +#define __setresuid pthread_setresuid_np +#include <setresuid.c> --- /dev/null +++ b/fbtl/pthread_setreuid.c @@ -0,0 +1,3 @@ +#define SINGLE_THREAD +#define __setreuid pthread_setreuid_np +#include <setreuid.c> --- /dev/null +++ b/fbtl/pthread_setschedparam.c @@ -0,0 +1,71 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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) --- /dev/null +++ b/fbtl/pthread_setschedprio.c @@ -0,0 +1,63 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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 (__glibc_unlikely (sched_setparam (pd->tid, ¶m) == -1)) + result = errno; + else + { + /* We succeeded changing the kernel information. Reflect this + change in the thread descriptor. */ + param.sched_priority = prio; + memcpy (&pd->schedparam, ¶m, sizeof (struct sched_param)); + pd->flags |= ATTR_FLAG_SCHED_SET; + } + + lll_unlock (pd->lock, LLL_PRIVATE); + + return result; +} --- /dev/null +++ b/fbtl/pthread_setspecific.c @@ -0,0 +1,93 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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 (__glibc_likely (key < PTHREAD_KEY_2NDLEVEL_SIZE)) + { + /* 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) +hidden_def (__pthread_setspecific) --- /dev/null +++ b/fbtl/pthread_setuid.c @@ -0,0 +1,3 @@ +#define SINGLE_THREAD +#define __setuid pthread_setuid_np +#include <setuid.c> --- /dev/null +++ b/fbtl/pthread_spin_destroy.c @@ -0,0 +1,27 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include "pthreadP.h" + + +int +pthread_spin_destroy (pthread_spinlock_t *lock) +{ + /* Nothing to do. */ + return 0; +} --- /dev/null +++ b/fbtl/pthread_spin_init.c @@ -0,0 +1,27 @@ +/* pthread_spin_init -- initialize a spin lock. Generic version. + Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#include "pthreadP.h" + +int +pthread_spin_init (pthread_spinlock_t *lock, int pshared) +{ + *lock = 0; + return 0; +} --- /dev/null +++ b/fbtl/pthread_spin_lock.c @@ -0,0 +1,69 @@ +/* pthread_spin_lock -- lock a spin lock. Generic version. + Copyright (C) 2012-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <atomic.h> +#include "pthreadP.h" + +/* A machine-specific version can define SPIN_LOCK_READS_BETWEEN_CMPXCHG + to the number of plain reads that it's optimal to spin on between uses + of atomic_compare_and_exchange_val_acq. If spinning forever is optimal + then use -1. If no plain reads here would ever be optimal, use 0. */ +#ifndef SPIN_LOCK_READS_BETWEEN_CMPXCHG +# warning machine-dependent file should define SPIN_LOCK_READS_BETWEEN_CMPXCHG +# define SPIN_LOCK_READS_BETWEEN_CMPXCHG 1000 +#endif + +int +pthread_spin_lock (pthread_spinlock_t *lock) +{ + /* atomic_exchange usually takes less instructions than + atomic_compare_and_exchange. On the other hand, + atomic_compare_and_exchange potentially generates less bus traffic + when the lock is locked. + We assume that the first try mostly will be successful, and we use + atomic_exchange. For the subsequent tries we use + atomic_compare_and_exchange. */ + if (atomic_exchange_acq (lock, 1) == 0) + return 0; + + do + { + /* The lock is contended and we need to wait. Going straight back + to cmpxchg is not a good idea on many targets as that will force + expensive memory synchronizations among processors and penalize other + running threads. + On the other hand, we do want to update memory state on the local core + once in a while to avoid spinning indefinitely until some event that + will happen to update local memory as a side-effect. */ + if (SPIN_LOCK_READS_BETWEEN_CMPXCHG >= 0) + { + int wait = SPIN_LOCK_READS_BETWEEN_CMPXCHG; + + while (*lock != 0 && wait > 0) + --wait; + } + else + { + while (*lock != 0) + ; + } + } + while (atomic_compare_and_exchange_val_acq (lock, 1, 0) != 0); + + return 0; +} --- /dev/null +++ b/fbtl/pthread_spin_trylock.c @@ -0,0 +1,27 @@ +/* pthread_spin_trylock -- trylock a spin lock. Generic version. + Copyright (C) 2012-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <atomic.h> +#include "pthreadP.h" + +int +pthread_spin_trylock (pthread_spinlock_t *lock) +{ + return atomic_exchange_acq (lock, 1) ? EBUSY : 0; +} --- /dev/null +++ b/fbtl/pthread_spin_unlock.c @@ -0,0 +1,29 @@ +/* pthread_spin_unlock -- unlock a spin lock. Generic version. + Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#include "pthreadP.h" +#include <atomic.h> + +int +pthread_spin_unlock (pthread_spinlock_t *lock) +{ + atomic_full_barrier (); + *lock = 0; + return 0; +} --- /dev/null +++ b/fbtl/pthread_testcancel.c @@ -0,0 +1,27 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <stdlib.h> +#include "pthreadP.h" + + +void +pthread_testcancel (void) +{ + CANCELLATION_P (THREAD_SELF); +} --- /dev/null +++ b/fbtl/pthread_timedjoin.c @@ -0,0 +1,104 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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->ktid, 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; +} --- /dev/null +++ b/fbtl/pthread_tryjoin.c @@ -0,0 +1,72 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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 != KTID_TERMINATED) + 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; +} --- /dev/null +++ b/fbtl/res.c @@ -0,0 +1,26 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <features.h> +#include <resolv.h> +#include <tls.h> + +struct __res_state * +__res_state (void) +{ + return __resp; +} --- /dev/null +++ b/fbtl/sem_close.c @@ -0,0 +1,79 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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; +} --- /dev/null +++ b/fbtl/sem_destroy.c @@ -0,0 +1,36 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <semaphore.h> +#include <shlib-compat.h> +#include "semaphoreP.h" + + +int +__new_sem_destroy (sem_t *sem) +{ + /* XXX Check for valid parameter. */ + + /* Nothing to do. */ + return 0; +} +versioned_symbol (libpthread, __new_sem_destroy, sem_destroy, GLIBC_2_1); +#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_1) +strong_alias (__new_sem_destroy, __old_sem_destroy) +compat_symbol (libpthread, __old_sem_destroy, sem_destroy, GLIBC_2_0); +#endif --- /dev/null +++ b/fbtl/sem_getvalue.c @@ -0,0 +1,39 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <semaphore.h> +#include <shlib-compat.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; +} +versioned_symbol (libpthread, __new_sem_getvalue, sem_getvalue, GLIBC_2_1); +#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_1) +strong_alias (__new_sem_getvalue, __old_sem_getvalue) +compat_symbol (libpthread, __old_sem_getvalue, sem_getvalue, GLIBC_2_0); +#endif --- /dev/null +++ b/fbtl/sem_init.c @@ -0,0 +1,81 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <semaphore.h> +#include <lowlevellock.h> +#include <shlib-compat.h> +#include "semaphoreP.h" +#include <kernel-features.h> + + +int +__new_sem_init (sem_t *sem, int pshared, unsigned int value) +{ + /* Parameter sanity check. */ + if (__glibc_unlikely (value > SEM_VALUE_MAX)) + { + __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; +} +versioned_symbol (libpthread, __new_sem_init, sem_init, GLIBC_2_1); + + + +#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_1) +int +attribute_compat_text_section +__old_sem_init (sem_t *sem, int pshared, unsigned int value) +{ + /* Parameter sanity check. */ + if (__glibc_unlikely (value > SEM_VALUE_MAX)) + { + __set_errno (EINVAL); + return -1; + } + + /* Map to the internal type. */ + struct old_sem *isem = (struct old_sem *) sem; + + /* Use the value the user provided. */ + isem->value = value; + + /* We cannot store the PSHARED attribute. So we always use the + operations needed for shared semaphores. */ + + return 0; +} +compat_symbol (libpthread, __old_sem_init, sem_init, GLIBC_2_0); +#endif --- /dev/null +++ b/fbtl/sem_open.c @@ -0,0 +1,300 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <fcntl.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 "semaphoreP.h" +#include <shm-directory.h> + + +/* 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. */ + struct stat64 st; + if (__fxstat64 (_STAT_VER, fd, &st) == 0) + { + /* 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. */ + int saved_errno = errno; + munmap(existing, sizeof (sem_t)); + errno = saved_errno; + } + + return result; +} + + +sem_t * +sem_open (const char *name, int oflag, ...) +{ + int fd; + sem_t *result; + + /* Create the name of the final file in local variable SHM_NAME. */ + SHM_GET_NAME (EINVAL, SEM_FAILED, SEM_SHM_PREFIX); + + /* If the semaphore object has to exist simply open it. */ + if ((oflag & O_CREAT) == 0 || (oflag & O_EXCL) == 0) + { + try_again: + fd = __libc_open (shm_name, + (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); + +#if 0 + mode = va_arg (ap, mode_t); +#else + mode = va_arg (ap, int); +#endif + 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 (shm_dirlen + sizeof SEM_SHM_PREFIX + 6); + char *xxxxxx = __mempcpy (tmpfname, shm_dir, shm_dirlen); + + int retries = 0; +#define NRETRIES 50 + while (1) + { + /* Add the suffix for mktemp. */ + strcpy (xxxxxx, "XXXXXX"); + + /* We really want to use mktemp here. We cannot use mkstemp + since the file must be opened with a specific mode. The + mode cannot later be set since then we cannot apply the + file create mask. */ + if (__mktemp (tmpfname) == NULL) + return SEM_FAILED; + + /* Open the file. Make sure we do not overwrite anything. */ + fd = __libc_open (tmpfname, O_RDWR | O_CREAT | O_EXCL, mode); + if (fd == -1) + { + if (errno == EEXIST) + { + if (++retries < NRETRIES) + continue; + + __set_errno (EAGAIN); + } + + return SEM_FAILED; + } + + /* We got a file. */ + break; + } + + if (TEMP_FAILURE_RETRY (__libc_write (fd, &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, shm_name) != 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. */ + int save = errno; + __libc_close (fd); + errno = save; + } + + return result; +} --- /dev/null +++ b/fbtl/sem_unlink.c @@ -0,0 +1,38 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <semaphore.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "semaphoreP.h" +#include <shm-directory.h> + +int +sem_unlink (const char *name) +{ + /* Construct the filename. */ + SHM_GET_NAME (ENOENT, -1, SEM_SHM_PREFIX); + + /* Now try removing it. */ + int ret = unlink (shm_name); + if (ret < 0 && errno == EPERM) + __set_errno (EACCES); + return ret; +} --- /dev/null +++ b/fbtl/semaphore.h @@ -0,0 +1,78 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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) __THROWNL; + +/* Post SEM. */ +extern int sem_post (sem_t *__sem) __THROWNL; + +/* 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 */ --- /dev/null +++ b/fbtl/semaphoreP.h @@ -0,0 +1,54 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <semaphore.h> +#include "pthreadP.h" + +#define SEM_SHM_PREFIX "sem." + +/* Keeping track of currently used mappings. */ +struct inuse_sem +{ + dev_t dev; + ino_t ino; + int refcnt; + sem_t *sem; + char name[0]; +}; + + +/* 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; + + +/* 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); --- /dev/null +++ b/fbtl/shlib-versions @@ -0,0 +1 @@ +libpthread=0 GLIBC_2.3 --- /dev/null +++ b/fbtl/sigaction.c @@ -0,0 +1,43 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + + +/* This is no complete implementation. The file is meant to be + included in the real implementation to provide the wrapper around + __libc_sigaction. */ + +#include <fbtl/pthreadP.h> + +/* We use the libc implementation but we tell it to not allow + SIGCANCEL or SIGTIMER to be handled. */ +#define LIBC_SIGACTION 1 + + +int +__sigaction (int sig, const struct sigaction *act, struct sigaction *oact) +{ + if (__glibc_unlikely (sig == SIGCANCEL || sig == SIGSETXID)) + { + __set_errno (EINVAL); + return -1; + } + + return __libc_sigaction (sig, act, oact); +} +libc_hidden_weak (__sigaction) +weak_alias (__sigaction, sigaction) --- /dev/null +++ b/fbtl/sockperf.c @@ -0,0 +1,594 @@ +#define _GNU_SOURCE +#include <argp.h> +#include <complex.h> +#include <errno.h> +#include <error.h> +#include <fcntl.h> +#include <gd.h> +#include <inttypes.h> +#include <pthread.h> +#include <signal.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> +#include <sys/param.h> +#include <sys/poll.h> +#include <sys/socket.h> +#include <sys/un.h> + + +#define size_x 320 +#define size_y 240 + + +#define PATH "/tmp/s.sockperf" + + +struct thread_param +{ + unsigned int from; + unsigned int to; + unsigned int nserv; +}; + +struct coord +{ + unsigned int x; + unsigned int y; + complex double z; +}; + + +/* We use 64bit values for the times. */ +typedef unsigned long long int hp_timing_t; + + +static unsigned int nclients = 2; +static unsigned int nservers = 2; + +static bool timing; +static int points; + + +static complex double top_left = -0.7 + 0.2i; +static complex double bottom_right = -0.5 - 0.0i; + + +static int colors[256]; +static gdImagePtr image; +static pthread_mutex_t image_lock; + +static int sock; + + +static void * +client (void *arg) +{ + struct thread_param *param = arg; + unsigned int cnt; + unsigned int nserv = param->nserv; + int clisock[nserv]; + struct pollfd servpoll[nserv]; + struct sockaddr_un servaddr; + socklen_t servlen; + struct coord c; + + bool new_coord (void) + { + if (cnt >= param->to) + return false; + + unsigned int row = cnt / size_x; + unsigned int col = cnt % size_x; + + c.x = col; + c.y = row; + c.z = (top_left + + ((col + * (creal (bottom_right) - creal (top_left))) / size_x) + + (_Complex_I * (row * (cimag (bottom_right) - cimag (top_left))) + / size_y)); + + ++cnt; + + return true; + } + + + for (cnt = 0; cnt < nserv; ++cnt) + { + servpoll[cnt].fd = socket (AF_UNIX, SOCK_STREAM, 0); + if (clisock < 0) + { + puts ("cannot create socket in client"); + return NULL; + } + + memset (&servaddr, '\0', sizeof (servaddr)); + servaddr.sun_family = AF_UNIX; + strncpy (servaddr.sun_path, PATH, sizeof (servaddr.sun_path)); + servlen = offsetof (struct sockaddr_un, sun_path) + strlen (PATH) + 1; + + + int err; + while (1) + { + err = TEMP_FAILURE_RETRY (connect (servpoll[cnt].fd, &servaddr, + servlen)); + if (err != -1 || errno != ECONNREFUSED) + break; + + pthread_yield (); + } + + if (err == -1) + { + printf ("cannot connect: %m (%d)\n", errno); + exit (1); + } + + servpoll[cnt].events = POLLOUT; + servpoll[cnt].revents = 0; + } + + cnt = param->from; + + new_coord (); + bool z_valid = true; + + while (1) + { + int i; + int n = poll (servpoll, nserv, -1); + if (n == -1) + { + puts ("poll returned error"); + break; + } + + bool cont = false; + for (i = 0; i < nserv && n > 0; ++i) + if (servpoll[i].revents != 0) + { + if (servpoll[i].revents == POLLIN) + { + unsigned int vals[3]; + if (TEMP_FAILURE_RETRY (read (servpoll[i].fd, &vals, + sizeof (vals))) + != sizeof (vals)) + { + puts ("read error in client"); + return NULL; + } + + pthread_mutex_lock (&image_lock); + + gdImageSetPixel (image, vals[0], vals[1], vals[2]); + ++points; + + pthread_mutex_unlock (&image_lock); + + servpoll[i].events = POLLOUT; + } + else + { + if (servpoll[i].revents != POLLOUT) + printf ("revents: %hd != POLLOUT ???\n", + servpoll[i].revents); + + if (z_valid) + { + if (TEMP_FAILURE_RETRY (write (servpoll[i].fd, &c, + sizeof (c))) != sizeof (c)) + { + puts ("write error in client"); + return NULL; + } + cont = true; + servpoll[i].events = POLLIN; + + z_valid = new_coord (); + if (! z_valid) + /* No more to do. Clear the event fields. */ + for (i = 0; i < nserv; ++i) + if (servpoll[i].events == POLLOUT) + servpoll[i].events = servpoll[i].revents = 0; + } + else + servpoll[i].events = servpoll[i].revents = 0; + } + + --n; + } + else if (servpoll[i].events != 0) + cont = true; + + if (! cont && ! z_valid) + break; + } + + c.x = 0xffffffff; + c.y = 0xffffffff; + for (cnt = 0; cnt < nserv; ++cnt) + { + TEMP_FAILURE_RETRY (write (servpoll[cnt].fd, &c, sizeof (c))); + close (servpoll[cnt].fd); + } + + return NULL; +} + + +static void * +server (void *arg) +{ + struct sockaddr_un cliaddr; + socklen_t clilen; + int clisock = TEMP_FAILURE_RETRY (accept (sock, &cliaddr, &clilen)); + + if (clisock == -1) + { + puts ("accept failed"); + return NULL; + } + + while (1) + { + struct coord c; + + if (TEMP_FAILURE_RETRY (read (clisock, &c, sizeof (c))) != sizeof (c)) + { + printf ("server read failed: %m (%d)\n", errno); + break; + } + + if (c.x == 0xffffffff && c.y == 0xffffffff) + break; + + unsigned int rnds = 0; + complex double z = c.z; + while (cabs (z) < 4.0) + { + z = z * z - 1; + if (++rnds == 255) + break; + } + + unsigned int vals[3] = { c.x, c.y, rnds }; + if (TEMP_FAILURE_RETRY (write (clisock, vals, sizeof (vals))) + != sizeof (vals)) + { + puts ("server write error"); + return NULL; + } + } + + close (clisock); + + return NULL; +} + + +static const char *outfilename = "test.png"; + + +static const struct argp_option options[] = + { + { "clients", 'c', "NUMBER", 0, "Number of client threads" }, + { "servers", 's', "NUMBER", 0, "Number of server threads per client" }, + { "timing", 'T', NULL, 0, + "Measure time from startup to the last thread finishing" }, + { NULL, 0, NULL, 0, NULL } + }; + +/* Prototype for option handler. */ +static error_t parse_opt (int key, char *arg, struct argp_state *state); + +/* Data structure to communicate with argp functions. */ +static struct argp argp = +{ + options, parse_opt +}; + + +int +main (int argc, char *argv[]) +{ + int cnt; + FILE *outfile; + struct sockaddr_un servaddr; + socklen_t servlen; + int remaining; + + /* Parse and process arguments. */ + argp_parse (&argp, argc, argv, 0, &remaining, NULL); + + + pthread_t servth[nservers * nclients]; + pthread_t clntth[nclients]; + struct thread_param clntparam[nclients]; + + + image = gdImageCreate (size_x, size_y); + if (image == NULL) + { + puts ("gdImageCreate failed"); + return 1; + } + + for (cnt = 0; cnt < 255; ++cnt) + colors[cnt] = gdImageColorAllocate (image, 256 - cnt, 256 - cnt, + 256 - cnt); + /* Black. */ + colors[cnt] = gdImageColorAllocate (image, 0, 0, 0); + + + sock = socket (AF_UNIX, SOCK_STREAM, 0); + if (sock < 0) + error (EXIT_FAILURE, errno, "cannot create socket"); + + memset (&servaddr, '\0', sizeof (servaddr)); + servaddr.sun_family = AF_UNIX; + strncpy (servaddr.sun_path, PATH, sizeof (servaddr.sun_path)); + servlen = offsetof (struct sockaddr_un, sun_path) + strlen (PATH) + 1; + + if (bind (sock, &servaddr, servlen) == -1) + error (EXIT_FAILURE, errno, "bind failed"); + + listen (sock, SOMAXCONN); + + pthread_mutex_init (&image_lock, NULL); + + + struct sigaction sa; + sa.sa_handler = SIG_IGN; + sigemptyset (&sa.sa_mask); + sa.sa_flags = 0; + + clockid_t cl; + struct timespec start_time; + if (timing) + { + if (clock_getcpuclockid (0, &cl) != 0 + || clock_gettime (cl, &start_time) != 0) + timing = false; + } + + /* Start the servers. */ + for (cnt = 0; cnt < nservers * nclients; ++cnt) + { + if (pthread_create (&servth[cnt], NULL, server, NULL) != 0) + { + puts ("pthread_create for server failed"); + exit (1); + } + } + + for (cnt = 0; cnt < nclients; ++cnt) + { + clntparam[cnt].from = cnt * (size_x * size_y) / nclients; + clntparam[cnt].to = MIN ((cnt + 1) * (size_x * size_y) / nclients, + size_x * size_y); + clntparam[cnt].nserv = nservers; + + if (pthread_create (&clntth[cnt], NULL, client, &clntparam[cnt]) != 0) + { + puts ("pthread_create for client failed"); + exit (1); + } + } + + + /* Wait for the clients. */ + for (cnt = 0; cnt < nclients; ++cnt) + if (pthread_join (clntth[cnt], NULL) != 0) + { + puts ("client pthread_join failed"); + exit (1); + } + + /* Wait for the servers. */ + for (cnt = 0; cnt < nclients * nservers; ++cnt) + if (pthread_join (servth[cnt], NULL) != 0) + { + puts ("server pthread_join failed"); + exit (1); + } + + + if (timing) + { + struct timespec end_time; + + if (clock_gettime (cl, &end_time) == 0) + { + end_time.tv_sec -= start_time.tv_sec; + end_time.tv_nsec -= start_time.tv_nsec; + if (end_time.tv_nsec < 0) + { + end_time.tv_nsec += 1000000000; + --end_time.tv_sec; + } + + printf ("\nRuntime: %lu.%09lu seconds\n%d points computed\n", + (unsigned long int) end_time.tv_sec, + (unsigned long int) end_time.tv_nsec, + points); + } + } + + + outfile = fopen (outfilename, "w"); + if (outfile == NULL) + error (EXIT_FAILURE, errno, "cannot open output file '%s'", outfilename); + + gdImagePng (image, outfile); + + fclose (outfile); + + unlink (PATH); + + return 0; +} + + +/* Handle program arguments. */ +static error_t +parse_opt (int key, char *arg, struct argp_state *state) +{ + switch (key) + { + case 'c': + nclients = strtoul (arg, NULL, 0); + break; + + case 's': + nservers = strtoul (arg, NULL, 0); + break; + + case 'T': + timing = true; + break; + + default: + return ARGP_ERR_UNKNOWN; + } + + return 0; +} + + +static hp_timing_t +get_clockfreq (void) +{ + /* We read the information from the /proc filesystem. It contains at + least one line like + cpu MHz : 497.840237 + or also + cpu MHz : 497.841 + We search for this line and convert the number in an integer. */ + static hp_timing_t result; + int fd; + + /* If this function was called before, we know the result. */ + if (result != 0) + return result; + + fd = open ("/proc/cpuinfo", O_RDONLY); + if (__glibc_likely (fd != -1)) + { + /* XXX AFAIK the /proc filesystem can generate "files" only up + to a size of 4096 bytes. */ + char buf[4096]; + ssize_t n; + + n = read (fd, buf, sizeof buf); + if (__builtin_expect (n, 1) > 0) + { + char *mhz = memmem (buf, n, "cpu MHz", 7); + + if (__glibc_likely (mhz != NULL)) + { + char *endp = buf + n; + int seen_decpoint = 0; + int ndigits = 0; + + /* Search for the beginning of the string. */ + while (mhz < endp && (*mhz < '0' || *mhz > '9') && *mhz != '\n') + ++mhz; + + while (mhz < endp && *mhz != '\n') + { + if (*mhz >= '0' && *mhz <= '9') + { + result *= 10; + result += *mhz - '0'; + if (seen_decpoint) + ++ndigits; + } + else if (*mhz == '.') + seen_decpoint = 1; + + ++mhz; + } + + /* Compensate for missing digits at the end. */ + while (ndigits++ < 6) + result *= 10; + } + } + + close (fd); + } + + return result; +} + + +int +clock_getcpuclockid (pid_t pid, clockid_t *clock_id) +{ + /* We don't allow any process ID but our own. */ + if (pid != 0 && pid != getpid ()) + return EPERM; + +#ifdef CLOCK_PROCESS_CPUTIME_ID + /* Store the number. */ + *clock_id = CLOCK_PROCESS_CPUTIME_ID; + + return 0; +#else + /* We don't have a timer for that. */ + return ENOENT; +#endif +} + + +#define HP_TIMING_NOW(Var) __asm__ __volatile__ ("rdtsc" : "=A" (Var)) + +/* Get current value of CLOCK and store it in TP. */ +int +clock_gettime (clockid_t clock_id, struct timespec *tp) +{ + int retval = -1; + + switch (clock_id) + { + case CLOCK_PROCESS_CPUTIME_ID: + { + + static hp_timing_t freq; + hp_timing_t tsc; + + /* Get the current counter. */ + HP_TIMING_NOW (tsc); + + if (freq == 0) + { + freq = get_clockfreq (); + if (freq == 0) + return EINVAL; + } + + /* Compute the seconds. */ + tp->tv_sec = tsc / freq; + + /* And the nanoseconds. This computation should be stable until + we get machines with about 16GHz frequency. */ + tp->tv_nsec = ((tsc % freq) * UINT64_C (1000000000)) / freq; + + retval = 0; + } + break; + + default: + errno = EINVAL; + break; + } + + return retval; +} --- /dev/null +++ b/fbtl/sysdeps/i386/Makefile @@ -0,0 +1,26 @@ +# Copyright (C) 2002-2013 Free Software Foundation, Inc. +# This file is part of the GNU C Library. + +# The GNU C Library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. + +# The GNU C Library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. + +# You should have received a copy of the GNU Lesser General Public +# License along with the GNU C Library; if not, see +# <http://www.gnu.org/licenses/>. + +ifeq ($(subdir),csu) +gen-as-const-headers += tcb-offsets.sym +endif + +ifeq ($(subdir),fbtl) +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 --- /dev/null +++ b/fbtl/sysdeps/i386/i486/pthread_spin_trylock.S @@ -0,0 +1,46 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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 --- /dev/null +++ b/fbtl/sysdeps/i386/i586/pthread_spin_trylock.S @@ -0,0 +1,19 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include "../i486/pthread_spin_trylock.S" --- /dev/null +++ b/fbtl/sysdeps/i386/i686/Makefile @@ -0,0 +1,31 @@ +# Copyright (C) 2003-2013 Free Software Foundation, Inc. +# This file is part of the GNU C Library. +# Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +# The GNU C Library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. + +# The GNU C Library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. + +# You should have received a copy of the GNU Lesser General Public +# License along with the GNU C Library; if not, see +# <http://www.gnu.org/licenses/>. + +ifeq ($(subdir),fbtl) +# 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 --- /dev/null +++ b/fbtl/sysdeps/i386/i686/pthread_spin_trylock.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#define HAVE_CMOV 1 +#include "../i486/pthread_spin_trylock.S" --- /dev/null +++ b/fbtl/sysdeps/i386/i686/tls.h @@ -0,0 +1,35 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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 */ --- /dev/null +++ b/fbtl/sysdeps/i386/pthread_spin_init.c @@ -0,0 +1,19 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +/* Not needed. pthread_spin_init is an alias for pthread_spin_unlock. */ --- /dev/null +++ b/fbtl/sysdeps/i386/pthread_spin_lock.S @@ -0,0 +1,37 @@ +/* Copyright (C) 2012-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <lowlevellock.h> + + .globl pthread_spin_lock + .type pthread_spin_lock,@function + .align 16 +pthread_spin_lock: + mov 4(%esp), %eax +1: LOCK + decl 0(%eax) + jne 2f + xor %eax, %eax + ret + + .align 16 +2: rep + nop + cmpl $0, 0(%eax) + jg 1b + jmp 2b + .size pthread_spin_lock,.-pthread_spin_lock --- /dev/null +++ b/fbtl/sysdeps/i386/pthread_spin_unlock.S @@ -0,0 +1,31 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + + .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 --- /dev/null +++ b/fbtl/sysdeps/i386/pthreaddef.h @@ -0,0 +1,40 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +/* 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. + + Some processors such as Intel Atom pay a big penalty on every + access using a segment override if that segment's base is not + aligned to the size of a cache line. (See Intel 64 and IA-32 + Architectures Optimization Reference Manual, section 13.3.3.3, + "Segment Base".) On such machines, a cache line is 64 bytes. */ +#define TCB_ALIGNMENT 64 + + +/* Location of current stack frame. */ +#define CURRENT_STACK_FRAME __builtin_frame_address (0) --- /dev/null +++ b/fbtl/sysdeps/i386/tcb-offsets.sym @@ -0,0 +1,16 @@ +#include <sysdep.h> +#include <tls.h> + +RESULT offsetof (struct pthread, result) +TID offsetof (struct pthread, tid) +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 --- /dev/null +++ b/fbtl/sysdeps/i386/tls.h @@ -0,0 +1,459 @@ +/* Definition for thread-local data handling. nptl/i386 version. + Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#ifndef _TLS_H +#define _TLS_H 1 + +#include <dl-sysdep.h> +#ifndef __ASSEMBLER__ +# include <stdbool.h> +# include <stddef.h> +# include <stdint.h> +# include <stdlib.h> +# include <sysdep.h> +# include <libc-internal.h> +# include <kernel-features.h> +# include <dl-dtv.h> + +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 __glibc_reserved1; +#endif + /* Reservation of some values for the TM ABI. */ + void *__private_tm[4]; + /* GCC split stack support. */ + void *__private_ss; +} tcbhead_t; + +# define TLS_MULTIPLE_THREADS_IN_TCB 1 + +#else /* __ASSEMBLER__ */ +# include <tcb-offsets.h> +#endif + + +/* 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]; +}; + + +/* 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 +# define TLS_DTV_AT_TP 0 + +/* Get the thread descriptor definition. */ +# include <fbtl/descr.h> + + +/* 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) \ + ({ 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. */ \ + _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" ((uint64_t) cast_to_integer (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" ((uint64_t) cast_to_integer (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 */ --- /dev/null +++ b/fbtl/sysdeps/pthread/Makefile @@ -0,0 +1,39 @@ +# Copyright (C) 2002-2013 Free Software Foundation, Inc. +# This file is part of the GNU C Library. +# Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +# The GNU C Library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. + +# The GNU C Library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. + +# You should have received a copy of the GNU Lesser General Public +# License along with the GNU C Library; if not, see +# <http://www.gnu.org/licenses/>. + +ifeq ($(subdir),fbtl) +libpthread-sysdep_routines += errno-loc +endif + +ifeq ($(subdir),rt) +librt-sysdep_routines += timer_routines librt-cancellation +CFLAGS-librt-cancellation.c += -fexceptions -fasynchronous-unwind-tables + +ifeq (yes,$(build-shared)) +$(objpfx)tst-timer: $(objpfx)librt.so $(shared-thread-library) +else +$(objpfx)tst-timer: $(objpfx)librt.a $(static-thread-library) +endif + +tests += tst-mqueue8x +CFLAGS-tst-mqueue8x.c += -fexceptions +endif + +ifeq ($(subdir),posix) +CFLAGS-confstr.c += -DLIBPTHREAD_VERSION='"FBTL $(version)"' +endif --- /dev/null +++ b/fbtl/sysdeps/pthread/Subdirs @@ -0,0 +1,2 @@ +fbtl +fbtl_db --- /dev/null +++ b/fbtl/sysdeps/pthread/aio_misc.h @@ -0,0 +1,74 @@ +/* Copyright (C) 2006-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +/* We define a special synchronization primitive for AIO. POSIX + conditional variables would be ideal but the pthread_cond_*wait + operations do not return on EINTR. This is a requirement for + correct aio_suspend and lio_listio implementations. */ + +#include <assert.h> +#include <pthreadP.h> +#include <lowlevellock.h> + +#define DONT_NEED_AIO_MISC_COND 1 + +#define AIO_MISC_NOTIFY(waitlist) \ + do { \ + if (*waitlist->counterp > 0 && --*waitlist->counterp == 0) \ + lll_futex_wake (waitlist->counterp, 1, LLL_PRIVATE); \ + } while (0) + +#define AIO_MISC_WAIT(result, futex, timeout, cancel) \ + do { \ + volatile int *futexaddr = &futex; \ + int oldval = futex; \ + \ + if (oldval != 0) \ + { \ + pthread_mutex_unlock (&__aio_requests_mutex); \ + \ + int oldtype; \ + if (cancel) \ + oldtype = LIBC_CANCEL_ASYNC (); \ + \ + int status; \ + do \ + { \ + status = lll_futex_timed_wait (futexaddr, oldval, timeout, \ + LLL_PRIVATE); \ + if (status != EWOULDBLOCK) \ + break; \ + \ + oldval = *futexaddr; \ + } \ + while (oldval != 0); \ + \ + if (cancel) \ + LIBC_CANCEL_RESET (oldtype); \ + \ + if (status == EINTR) \ + result = EINTR; \ + else if (status == ETIMEDOUT) \ + result = EAGAIN; \ + else \ + assert (status == 0 || status == EWOULDBLOCK); \ + \ + pthread_mutex_lock (&__aio_requests_mutex); \ + } \ + } while (0) + +#include_next <aio_misc.h> --- /dev/null +++ b/fbtl/sysdeps/pthread/allocalim.h @@ -0,0 +1,29 @@ +/* Determine whether block of given size can be allocated on the stack or not. + Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General 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, see <http://www.gnu.org/licenses/>. */ + +#include <alloca.h> +#include <limits.h> + + +extern __always_inline +int +__libc_use_alloca (size_t size) +{ + return (__builtin_expect (size <= PTHREAD_STACK_MIN / 4, 1) + || __builtin_expect (__libc_alloca_cutoff (size), 1)); +} --- /dev/null +++ b/fbtl/sysdeps/pthread/bits/sigthread.h @@ -0,0 +1,43 @@ +/* Signal handling function for threaded programs. + Copyright (C) 1998-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General 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, see <http://www.gnu.org/licenses/>. */ + +#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 */ --- /dev/null +++ b/fbtl/sysdeps/pthread/createthread.c @@ -0,0 +1,298 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <sched.h> +#include <setjmp.h> +#include <signal.h> +#include <stdlib.h> +#include <atomic.h> +#include <ldsodefs.h> +#include <tls.h> +#include <stdint.h> + +#include "kernel-features.h" + + +#define CLONE_SIGNAL (CLONE_SIGHAND | CLONE_THREAD) + +/* Unless otherwise specified, the thread "register" is going to be + initialized with a pointer to the TCB. */ +#ifndef TLS_VALUE +# define TLS_VALUE pd +#endif + +#ifndef ARCH_CLONE +# define ARCH_CLONE __clone +#endif + + +#ifndef TLS_MULTIPLE_THREADS_IN_TCB +/* Pointer to the corresponding variable in libc. */ +int *__libc_multiple_threads_ptr attribute_hidden; +#endif + + +struct rtprio; +struct thr_param { + int (*start_func)(void *); /* thread entry function. */ + void *arg; /* argument for entry function. */ + char *stack_base; /* stack base address. */ + size_t stack_size; /* stack size. */ + char *tls_base; /* tls base address. */ + size_t tls_size; /* tls size. */ + long *child_tid; /* address to store new TID. */ + long *parent_tid; /* parent accesses the new TID here. */ + int flags; /* thread flags. */ + struct rtprio *rtp; /* Real-time scheduling priority */ + void *spare[3]; /* TODO: cpu affinity mask etc. */ +}; + + +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 + + struct thr_param p; + + if (__glibc_unlikely (stopped != 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 0 + int rc = ARCH_CLONE (fct, STACK_VARIABLES_ARGS, clone_flags, + pd, &pd->tid, TLS_VALUE, &pd->tid); + +#else + memset(&p, 0, sizeof(p)); + p.start_func = fct; + p.arg = pd; + p.stack_base = stackaddr; /* first in STACK_VARIABLES_ARGS */ + p.stack_size = stacksize; /* second in STACK_VARIABLES_ARGS */ + p.tls_base = (char*)pd; + p.child_tid = &(pd->ktid); + + int rc = INLINE_SYSCALL(thr_new, 2, &p, sizeof(p)); + + if (rc) + { + errno = rc; + rc = -1;; + } +#endif + + + if (__glibc_unlikely (rc == -1)) + { + atomic_decrement (&__nptl_nthreads); /* Oops, we lied for a second. */ + pd->ktid = 0; + + /* Perhaps a thread wants to change the IDs and if waiting + for this stillborn thread. */ + if (__builtin_expect (atomic_exchange_acq (&pd->setxid_futex, 0) + == -2, 0)) + lll_futex_wake (&pd->setxid_futex, 1, LLL_PRIVATE); + + /* Free the resources. */ + __deallocate_stack (pd); + + /* We have to translate error codes. */ + return errno == ENOMEM ? EAGAIN : errno; + } +#warning set scheduling parameters +#if 0 + /* Now we have the possibility to set scheduling parameters etc. */ + if (__glibc_unlikely (stopped != 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 (__glibc_unlikely (INTERNAL_SYSCALL_ERROR_P (res, err))) + { + /* The operation failed. We have to kill the thread. First + send it the cancellation signal. */ + INTERNAL_SYSCALL_DECL (err2); + err_out: + (void) INTERNAL_SYSCALL (tgkill, err2, 3, + THREAD_GETMEM (THREAD_SELF, pid), + pd->tid, SIGCANCEL); + + /* We do not free the stack here because the canceled thread + itself will do this. */ + + 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 (__glibc_unlikely (INTERNAL_SYSCALL_ERROR_P (res, err))) + goto err_out; + } + } +#endif + + /* We now have for sure more than one thread. The main thread might + not yet have the flag set. No need to set the global variable + again if this is what we use. */ + THREAD_SETMEM (THREAD_SELF, header.multiple_threads, 1); + + return 0; +} + + +static int +create_thread (struct pthread *pd, const struct pthread_attr *attr, + STACK_VARIABLES_PARMS) +{ +#ifdef TLS_TCB_AT_TP + assert (pd->header.tcb != NULL); +#endif + + /* We rely heavily on various flags the CLONE function understands: + + CLONE_VM, CLONE_FS, CLONE_FILES + These flags select semantics with shared address space and + file descriptors according to what POSIX requires. + + CLONE_SIGNAL + This flag selects the POSIX signal semantics. + + CLONE_SETTLS + The sixth parameter to CLONE determines the TLS area for the + new thread. + + CLONE_PARENT_SETTID + The kernels writes the thread ID of the newly created thread + into the location pointed to by the fifth parameters to CLONE. + + Note that it would be semantically equivalent to use + CLONE_CHILD_SETTID but it is be more expensive in the kernel. + + CLONE_CHILD_CLEARTID + The kernels clears the thread ID of a thread that has called + sys_exit() in the location pointed to by the seventh parameter + to CLONE. + + The termination signal is chosen to be zero which means no signal + is sent. */ +#if 1 +#define clone_flags 123456 +#warning clone +#else + int clone_flags = (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGNAL + | CLONE_SETTLS | CLONE_PARENT_SETTID + | CLONE_CHILD_CLEARTID | CLONE_SYSVSEM + | 0); +#endif + + if (__glibc_unlikely (THREAD_GETMEM (THREAD_SELF, report_events))) + { + /* 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; +} --- /dev/null +++ b/fbtl/sysdeps/pthread/flockfile.c @@ -0,0 +1,32 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <pthread.h> +#include <stdio.h> +#include <libio.h> +#include <stdio-lock.h> + + +void +__flockfile (stream) + FILE *stream; +{ + _IO_lock_lock (*stream->_lock); +} +strong_alias (__flockfile, _IO_flockfile) +weak_alias (__flockfile, flockfile) --- /dev/null +++ b/fbtl/sysdeps/pthread/ftrylockfile.c @@ -0,0 +1,32 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdio-lock.h> + + +int +__ftrylockfile (stream) + FILE *stream; +{ + return _IO_lock_trylock (*stream->_lock); +} +strong_alias (__ftrylockfile, _IO_ftrylockfile) +weak_alias (__ftrylockfile, ftrylockfile) --- /dev/null +++ b/fbtl/sysdeps/pthread/funlockfile.c @@ -0,0 +1,32 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <pthread.h> +#include <stdio.h> +#include <libio.h> +#include <stdio-lock.h> + + +void +__funlockfile (stream) + FILE *stream; +{ + _IO_lock_unlock (*stream->_lock); +} +strong_alias (__funlockfile, _IO_funlockfile) +weak_alias (__funlockfile, funlockfile) --- /dev/null +++ b/fbtl/sysdeps/pthread/gai_misc.h @@ -0,0 +1,121 @@ +/* Copyright (C) 2006-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +/* We define a special synchronization primitive for AIO. POSIX + conditional variables would be ideal but the pthread_cond_*wait + operations do not return on EINTR. This is a requirement for + correct aio_suspend and lio_listio implementations. */ + +#include <assert.h> +#include <signal.h> +#include <pthreadP.h> +#include <lowlevellock.h> + +#define DONT_NEED_GAI_MISC_COND 1 + +#define GAI_MISC_NOTIFY(waitlist) \ + do { \ + if (*waitlist->counterp > 0 && --*waitlist->counterp == 0) \ + lll_futex_wake ((unsigned int *) waitlist->counterp, 1, LLL_PRIVATE); \ + } while (0) + +#define GAI_MISC_WAIT(result, futex, timeout, cancel) \ + do { \ + volatile int *futexaddr = &futex; \ + int oldval = futex; \ + \ + if (oldval != 0) \ + { \ + pthread_mutex_unlock (&__gai_requests_mutex); \ + \ + int oldtype; \ + if (cancel) \ + oldtype = LIBC_CANCEL_ASYNC (); \ + \ + int status; \ + do \ + { \ + status = lll_futex_timed_wait ((unsigned int *) futexaddr, oldval,\ + timeout, LLL_PRIVATE); \ + if (status != EWOULDBLOCK) \ + break; \ + \ + oldval = *futexaddr; \ + } \ + while (oldval != 0); \ + \ + if (cancel) \ + LIBC_CANCEL_RESET (oldtype); \ + \ + if (status == EINTR) \ + result = EINTR; \ + else if (status == ETIMEDOUT) \ + result = EAGAIN; \ + else \ + assert (status == 0 || status == EWOULDBLOCK); \ + \ + pthread_mutex_lock (&__gai_requests_mutex); \ + } \ + } while (0) + + +#define gai_start_notify_thread __gai_start_notify_thread +#define gai_create_helper_thread __gai_create_helper_thread + +extern inline void +__gai_start_notify_thread (void) +{ + sigset_t ss; + sigemptyset (&ss); + INTERNAL_SYSCALL_DECL (err); + INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_SETMASK, &ss, NULL, _NSIG / 8); +} + +extern inline int +__gai_create_helper_thread (pthread_t *threadp, void *(*tf) (void *), + void *arg) +{ + pthread_attr_t attr; + + /* Make sure the thread is created detached. */ + pthread_attr_init (&attr); + pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); + + /* The helper thread needs only very little resources. */ + (void) pthread_attr_setstacksize (&attr, + __pthread_get_minstack (&attr) + + 4 * PTHREAD_STACK_MIN); + + /* Block all signals in the helper thread. To do this thoroughly we + temporarily have to block all signals here. */ + sigset_t ss; + sigset_t oss; + sigfillset (&ss); + INTERNAL_SYSCALL_DECL (err); + INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_SETMASK, &ss, &oss, _NSIG / 8); + + int ret = pthread_create (threadp, &attr, tf, arg); + + /* Restore the signal mask. */ + INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_SETMASK, &oss, NULL, + _NSIG / 8); + + (void) pthread_attr_destroy (&attr); + return ret; +} + +#include_next <gai_misc.h> --- /dev/null +++ b/fbtl/sysdeps/pthread/libc-lock.h @@ -0,0 +1,187 @@ +/* libc-internal interface for mutex locks. NPTL version. + Copyright (C) 1996-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General 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, see <http://www.gnu.org/licenses/>. */ + +#ifndef _LIBC_LOCK_H +#define _LIBC_LOCK_H 1 + +#include <pthread.h> +#define __need_NULL +#include <stddef.h> + + +/* Mutex type. */ +#if defined _LIBC || defined _IO_MTSAFE_IO +# if (!IS_IN (libc) && !IS_IN (libpthread)) || !defined _LIBC +typedef struct { pthread_mutex_t mutex; } __libc_lock_recursive_t; +# else +typedef struct { int lock; int cnt; void *owner; } __libc_lock_recursive_t; +# endif +#else +typedef struct __libc_lock_recursive_opaque__ __libc_lock_recursive_t; +#endif + +/* 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_recursive(CLASS,NAME) \ + CLASS __libc_lock_recursive_t NAME; + +/* Define an initialized recursive lock variable NAME with storage + class CLASS. */ +#if defined _LIBC && (IS_IN (libc) || IS_IN (libpthread)) +# define __libc_lock_define_initialized_recursive(CLASS, NAME) \ + CLASS __libc_lock_recursive_t NAME = _LIBC_LOCK_RECURSIVE_INITIALIZER; +# 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 + +/* Initialize a recursive mutex. */ +#if defined _LIBC && (IS_IN (libc) || IS_IN (libpthread)) +# define __libc_lock_init_recursive(NAME) \ + ((void) ((NAME) = (__libc_lock_recursive_t) _LIBC_LOCK_RECURSIVE_INITIALIZER)) +#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 + +/* Finalize recursive named lock. */ +#if defined _LIBC && (IS_IN (libc) || 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).mutex), 0) +#endif + +/* Lock the recursive named lock variable. */ +#if defined _LIBC && (IS_IN (libc) || 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 recursive named lock variable. */ +#if defined _LIBC && (IS_IN (libc) || 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).mutex), 0) +#endif + +/* Unlock the recursive named lock variable. */ +#if defined _LIBC && (IS_IN (libc) || 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).mutex), 0) +#endif + +/* Note that for I/O cleanup handling we are using the old-style + cancel handling. It does not have to be integrated with C++ since + 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_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); \ + } + + +/* Hide the definitions which are only supposed to be used inside libc in + a separate file. This file is not present in the installation! */ +#ifdef _LIBC +# include "libc-lockP.h" +#endif + +#endif /* libc-lock.h */ --- /dev/null +++ b/fbtl/sysdeps/pthread/libc-lockP.h @@ -0,0 +1,438 @@ +/* Private libc-internal interface for mutex locks. NPTL version. + Copyright (C) 1996-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General 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, see <http://www.gnu.org/licenses/>. */ + +#ifndef _LIBC_LOCKP_H +#define _LIBC_LOCKP_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. */ +#include <lowlevellock.h> +#include <tls.h> +#include <pthread-functions.h> + +#if IS_IN (libpthread) +/* This gets us the declarations of the __pthread_* internal names, + and hidden_proto for them. */ +# include <fbtl/pthreadP.h> +#endif + +/* Mutex type. */ +#if !IS_IN (libc) && !IS_IN (libpthread) +typedef pthread_mutex_t __libc_lock_t; +#else +typedef int __libc_lock_t; +#endif +typedef struct { pthread_mutex_t mutex; } __rtld_lock_recursive_t; +typedef pthread_rwlock_t __libc_rwlock_t; + +/* Type for key to thread-specific data. */ +typedef pthread_key_t __libc_key_t; + +/* 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 __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.) */ + +#define _LIBC_LOCK_INITIALIZER LLL_LOCK_INITIALIZER +#if IS_IN (libc) || 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 +# define __libc_lock_define_initialized(CLASS,NAME) \ + CLASS __libc_lock_t NAME; +#endif + +#define __libc_rwlock_define_initialized(CLASS,NAME) \ + CLASS __libc_rwlock_t NAME = PTHREAD_RWLOCK_INITIALIZER; + +#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 && IS_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) +#elif IS_IN (libpthread) +# define PTFAVAIL(NAME) 1 +# define __libc_ptf_call(FUNC, ARGS, ELSE) \ + FUNC ARGS +# define __libc_ptf_call_always(FUNC, ARGS) \ + 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 IS_IN (libc) || IS_IN (libpthread) +# define __libc_lock_init(NAME) \ + ((void) ((NAME) = LLL_LOCK_INITIALIZER)) +#else +# define __libc_lock_init(NAME) \ + __libc_maybe_call (__pthread_mutex_init, (&(NAME), NULL), 0) +#endif +#if defined SHARED && IS_IN (libc) +/* ((NAME) = (__libc_rwlock_t) PTHREAD_RWLOCK_INITIALIZER) is inefficient. */ +# define __libc_rwlock_init(NAME) \ + ((void) __builtin_memset (&(NAME), '\0', sizeof (NAME))) +#else +# define __libc_rwlock_init(NAME) \ + __libc_maybe_call (__pthread_rwlock_init, (&(NAME), NULL), 0) +#endif + +/* 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 IS_IN (libc) || 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 && IS_IN (libc) +# define __libc_rwlock_fini(NAME) ((void) 0) +#else +# define __libc_rwlock_fini(NAME) \ + __libc_maybe_call (__pthread_rwlock_destroy, (&(NAME)), 0) +#endif + +/* Lock the named lock variable. */ +#if IS_IN (libc) || IS_IN (libpthread) +# ifndef __libc_lock_lock +# define __libc_lock_lock(NAME) \ + ({ lll_lock (NAME, LLL_PRIVATE); 0; }) +# endif +#else +# undef __libc_lock_lock +# 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) + +/* Try to lock the named lock variable. */ +#if IS_IN (libc) || IS_IN (libpthread) +# ifndef __libc_lock_trylock +# define __libc_lock_trylock(NAME) \ + lll_trylock (NAME) +# endif +#else +# undef __libc_lock_trylock +# 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) + +#define __rtld_lock_trylock_recursive(NAME) \ + __libc_maybe_call (__pthread_mutex_trylock, (&(NAME).mutex), 0) + +/* Unlock the named lock variable. */ +#if IS_IN (libc) || 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) + +#ifdef 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) + +/* Get once control variable. */ +#define __libc_once_get(ONCE_CONTROL) ((ONCE_CONTROL) != PTHREAD_ONCE_INIT) + +/* 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); + +/* 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); + +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); + +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)); + +extern int __pthread_setcancelstate (int state, int *oldstate); + + +/* 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) +weak_extern (__pthread_setcancelstate) +weak_extern (_pthread_cleanup_push_defer) +weak_extern (_pthread_cleanup_pop_restore) +# 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_setcancelstate +# pragma weak _pthread_cleanup_push_defer +# pragma weak _pthread_cleanup_pop_restore +# endif +#endif + +#endif /* libc-lockP.h */ --- /dev/null +++ b/fbtl/sysdeps/pthread/librt-cancellation.c @@ -0,0 +1,24 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include "pthreadP.h" + + +#define __pthread_enable_asynccancel __librt_enable_asynccancel +#define __pthread_disable_asynccancel __librt_disable_asynccancel +#include <fbtl/cancellation.c> --- /dev/null +++ b/fbtl/sysdeps/pthread/list.h @@ -0,0 +1,117 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#ifndef _LIST_H + +#ifndef __need_list_t +# define _LIST_H 1 +#endif + +/* 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. */ + + +#if defined __need_list_t || defined _LIST_H +# ifndef __list_t_defined +# define __list_t_defined +/* Basic type for the double-link list. */ +typedef struct list_head +{ + struct list_head *next; + struct list_head *prev; +} list_t; +# endif +# undef __need_list_t +#endif + +#ifdef _LIST_H + +# include <atomic.h> + +/* 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; + atomic_write_barrier (); + 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 */ + +#endif /* list.h */ --- /dev/null +++ b/fbtl/sysdeps/pthread/malloc-machine.h @@ -0,0 +1,28 @@ +/* Basic platform-independent macro definitions for mutexes, + thread-specific data and parameters for malloc. + Copyright (C) 2003-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#ifndef _MALLOC_MACHINE_H +#define _MALLOC_MACHINE_H + +#include <atomic.h> +#include <libc-lock.h> + +#include <sysdeps/generic/malloc-machine.h> + +#endif /* !defined(_MALLOC_MACHINE_H) */ --- /dev/null +++ b/fbtl/sysdeps/pthread/posix-timer.h @@ -0,0 +1,196 @@ +/* Definitions for POSIX timer implementation on top of NPTL. + Copyright (C) 2000-2013 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, see <http://www.gnu.org/licenses/>. */ + +#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); --- /dev/null +++ b/fbtl/sysdeps/pthread/pt-longjmp.c @@ -0,0 +1,28 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <setjmp.h> +#include <stdlib.h> +#include "pthreadP.h" + +void +longjmp (jmp_buf env, int val) +{ + __libc_longjmp (env, val); +} +weak_alias (longjmp, siglongjmp) --- /dev/null +++ b/fbtl/sysdeps/pthread/pthread-functions.h @@ -0,0 +1,117 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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 *) __attribute__ ((__noreturn__)); + 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); + void (*ptr_set_robust) (struct pthread *); +}; + +/* 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 */ --- /dev/null +++ b/fbtl/sysdeps/pthread/pthread.h @@ -0,0 +1,1177 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#ifndef _PTHREAD_H +#define _PTHREAD_H 1 + +#include <features.h> +#include <endian.h> +#include <sched.h> +#include <time.h> + +#include <bits/pthreadtypes.h> +#include <bits/setjmp.h> +#include <bits/wordsize.h> + + +/* 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 _LIBC /* not yet supported, so do not expose outside libc */ + +#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 + + +#if defined __USE_POSIX199506 || defined __USE_UNIX98 +/* Mutex protocols. */ +enum +{ + PTHREAD_PRIO_NONE, + PTHREAD_PRIO_INHERIT, + PTHREAD_PRIO_PROTECT +}; +#endif + +#endif /* not yet supported, so do not expose outside libc */ + +/* Mutex initializers. */ +#ifdef __PTHREAD_MUTEX_HAVE_PREV +# 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 +}; + +/* Define __PTHREAD_RWLOCK_INT_FLAGS_SHARED to 1 if pthread_rwlock_t + has the shared field. All 64-bit architectures have the shared field + in pthread_rwlock_t. */ +#ifndef __PTHREAD_RWLOCK_INT_FLAGS_SHARED +# if __WORDSIZE == 64 +# define __PTHREAD_RWLOCK_INT_FLAGS_SHARED 1 +# endif +#endif + +/* Read-write lock initializers. */ +# define PTHREAD_RWLOCK_INITIALIZER \ + { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } +# ifdef __USE_GNU +# ifdef __PTHREAD_RWLOCK_INT_FLAGS_SHARED +# 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) __THROWNL __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 __attribute__ ((__const__)); + + +/* 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)); + +#ifdef _LIBC /* not yet supported, so do not expose outside libc */ + +/* Get the default attributes used by pthread_create in this process. */ +extern int pthread_getattr_default_np (pthread_attr_t *__attr) + __THROW __nonnull ((1)); + +/* Set the default attributes to be used by pthread_create in this + process. */ +extern int pthread_setattr_default_np (const pthread_attr_t *__attr) + __THROW __nonnull ((1)); + +#endif /* not yet supported, so do not expose outside libc */ + +/* 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)); + + +#ifdef _LIBC /* not yet supported, so do not expose outside libc */ + +/* Set the scheduling priority for TARGET_THREAD. */ +extern int pthread_setschedprio (pthread_t __target_thread, int __prio) + __THROW; +#endif /* not yet supported, so do not expose outside libc */ + + +#ifdef __USE_GNU +/* Get thread name visible in the kernel and its interfaces. */ +extern int pthread_getname_np (pthread_t __target_thread, char *__buf, + size_t __buflen) + __THROW __nonnull ((2)); + +/* Set thread name visible in the kernel and its interfaces. */ +extern int pthread_setname_np (pthread_t __target_thread, const char *__name) + __THROW __nonnull ((2)); +#endif + + +#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 (__glibc_unlikely (__not_first_call)) \ + { \ + __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 (__glibc_unlikely (__not_first_call)) \ + { \ + __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) __THROWNL; + + +/* 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) + __THROWNL __nonnull ((1)); + +/* Lock a mutex. */ +extern int pthread_mutex_lock (pthread_mutex_t *__mutex) + __THROWNL __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) __THROWNL __nonnull ((1, 2)); +#endif + +/* Unlock a mutex. */ +extern int pthread_mutex_unlock (pthread_mutex_t *__mutex) + __THROWNL __nonnull ((1)); + +#ifdef _LIBC /* not yet supported, so do not expose outside libc */ + +/* 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 + +#endif /* not yet supported, so do not expose outside libc */ + +/* 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 + +#ifdef _LIBC /* not yet supported, so do not expose outside libc */ + +/* 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 + +#endif /* not yet supported, so do not expose outside libc */ + +#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) + __THROWNL __nonnull ((1)); + +/* Try to acquire read lock for RWLOCK. */ +extern int pthread_rwlock_tryrdlock (pthread_rwlock_t *__rwlock) + __THROWNL __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) __THROWNL __nonnull ((1, 2)); +# endif + +/* Acquire write lock for RWLOCK. */ +extern int pthread_rwlock_wrlock (pthread_rwlock_t *__rwlock) + __THROWNL __nonnull ((1)); + +/* Try to acquire write lock for RWLOCK. */ +extern int pthread_rwlock_trywrlock (pthread_rwlock_t *__rwlock) + __THROWNL __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) __THROWNL __nonnull ((1, 2)); +# endif + +/* Unlock RWLOCK. */ +extern int pthread_rwlock_unlock (pthread_rwlock_t *__rwlock) + __THROWNL __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) + __THROWNL __nonnull ((1)); + +/* Wake up all threads waiting for condition variables COND. */ +extern int pthread_cond_broadcast (pthread_cond_t *__cond) + __THROWNL __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) + __THROWNL __nonnull ((1)); + +/* Try to lock spinlock LOCK. */ +extern int pthread_spin_trylock (pthread_spinlock_t *__lock) + __THROWNL __nonnull ((1)); + +/* Release spinlock LOCK. */ +extern int pthread_spin_unlock (pthread_spinlock_t *__lock) + __THROWNL __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) + __THROWNL __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 */ --- /dev/null +++ b/fbtl/sysdeps/pthread/pthread_sigmask.c @@ -0,0 +1,57 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <signal.h> +#include <pthreadP.h> +#include <sysdep.h> + + +int +pthread_sigmask (how, newmask, oldmask) + int how; + const sigset_t *newmask; + sigset_t *oldmask; +{ + sigset_t local_newmask; + + /* The only thing we have to make sure here is that SIGCANCEL and + SIGSETXID is not blocked. */ + if (newmask != NULL + && (__builtin_expect (__sigismember (newmask, SIGCANCEL), 0) + || __builtin_expect (__sigismember (newmask, SIGSETXID), 0))) + { + local_newmask = *newmask; + __sigdelset (&local_newmask, SIGCANCEL); + __sigdelset (&local_newmask, SIGSETXID); + newmask = &local_newmask; + } + +#ifdef INTERNAL_SYSCALL + /* We know that realtime signals are available if NPTL is used. */ + INTERNAL_SYSCALL_DECL (err); + int result = INTERNAL_SYSCALL (rt_sigprocmask, err, 4, how, newmask, + oldmask, _NSIG / 8); + + return (INTERNAL_SYSCALL_ERROR_P (result, err) + ? INTERNAL_SYSCALL_ERRNO (result, err) + : 0); +#else + return sigprocmask (how, newmask, oldmask) == -1 ? errno : 0; +#endif +} --- /dev/null +++ b/fbtl/sysdeps/pthread/setxid.h @@ -0,0 +1,62 @@ +/* Copyright (C) 2004-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <pthreadP.h> +#include <sysdep.h> + +#define __SETXID_1(cmd, arg1) \ + cmd.id[0] = (long int) arg1 +#define __SETXID_2(cmd, arg1, arg2) \ + __SETXID_1 (cmd, arg1); cmd.id[1] = (long int) arg2 +#define __SETXID_3(cmd, arg1, arg2, arg3) \ + __SETXID_2 (cmd, arg1, arg2); cmd.id[2] = (long int) 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 (__glibc_unlikely (__nptl_setxid != NULL)) \ + { \ + 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 --- /dev/null +++ b/fbtl/sysdeps/pthread/shm-directory.h @@ -0,0 +1,31 @@ +/* Header for directory for shm/sem files. NPTL version. + Copyright (C) 2014-2015 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#ifndef _SHM_DIRECTORY_H + +#include <sysdeps/posix/shm-directory.h> + +/* For NPTL the __shm_directory function lives in libpthread. + We don't want PLT calls from there. But it's also used from + librt, so it cannot just be declared hidden. */ + +#if IS_IN (libpthread) +hidden_proto (__shm_directory) +#endif + +#endif /* shm-directory.h */ --- /dev/null +++ b/fbtl/sysdeps/pthread/sigfillset.c @@ -0,0 +1,20 @@ +/* Copyright (C) 2003-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <fbtl/pthreadP.h> + +#include <signal/sigfillset.c> --- /dev/null +++ b/fbtl/sysdeps/pthread/sigprocmask.c @@ -0,0 +1,19 @@ +/* Copyright (C) 1997-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <fbtl/pthreadP.h> +#include <sysdeps/unix/bsd/sigprocmask.c> --- /dev/null +++ b/fbtl/sysdeps/pthread/stdio-lock.h @@ -0,0 +1,110 @@ +/* Thread package specific definitions of stream lock type. NPTL version. + Copyright (C) 2000-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#ifndef _STDIO_LOCK_H +#define _STDIO_LOCK_H 1 + +#include <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) \ + ((void) ((_name) = (_IO_lock_t) _IO_lock_initializer)) + +#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 && IS_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 /* stdio-lock.h */ --- /dev/null +++ b/fbtl/sysdeps/pthread/tcb-offsets.h @@ -0,0 +1 @@ +/* This is overridden by generated tcb-offsets.h on arches which need it. */ --- /dev/null +++ b/fbtl/sysdeps/pthread/timer_create.c @@ -0,0 +1,169 @@ +/* Copyright (C) 2000-2013 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, see <http://www.gnu.org/licenses/>. */ + +#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 (clock_id, evp, timerid) + 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 (__glibc_unlikely (newtimer == NULL)) + { + __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 (__glibc_unlikely (thread == NULL)) + { + __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; +} --- /dev/null +++ b/fbtl/sysdeps/pthread/timer_delete.c @@ -0,0 +1,69 @@ +/* Copyright (C) 2000-2013 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, see <http://www.gnu.org/licenses/>. */ + +#include <assert.h> +#include <errno.h> +#include <pthread.h> +#include <time.h> + +#include "posix-timer.h" + + +/* Delete timer TIMERID. */ +int +timer_delete (timerid) + 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; +} --- /dev/null +++ b/fbtl/sysdeps/pthread/timer_getoverr.c @@ -0,0 +1,44 @@ +/* Copyright (C) 2000-2013 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, see <http://www.gnu.org/licenses/>. */ + +#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; +} --- /dev/null +++ b/fbtl/sysdeps/pthread/timer_gettime.c @@ -0,0 +1,76 @@ +/* Copyright (C) 2000-2013 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, see <http://www.gnu.org/licenses/>. */ + +#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; +} --- /dev/null +++ b/fbtl/sysdeps/pthread/timer_routines.c @@ -0,0 +1,577 @@ +/* Helper code for POSIX timer implementation on NPTL. + Copyright (C) 2000-2013 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, see <http://www.gnu.org/licenses/>. */ + +#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); +} --- /dev/null +++ b/fbtl/sysdeps/pthread/timer_settime.c @@ -0,0 +1,136 @@ +/* Copyright (C) 2000-2013 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, see <http://www.gnu.org/licenses/>. */ + +#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; +} --- /dev/null +++ b/fbtl/sysdeps/pthread/tst-mqueue8x.c @@ -0,0 +1 @@ +#include <rt/tst-mqueue8.c> --- /dev/null +++ b/fbtl/sysdeps/pthread/tst-timer.c @@ -0,0 +1,159 @@ +/* Tests for POSIX timer implementation. + Copyright (C) 2000-2013 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, see <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <signal.h> +#include <stdio.h> +#include <time.h> +#include <unistd.h> +#include <stdlib.h> + + +static void +notify_func1 (union sigval sigval) +{ + puts ("notify_func1"); +} + + +static void +notify_func2 (union sigval sigval) +{ + puts ("notify_func2"); +} + + +static void +signal_func (int sig) +{ + static const char text[] = "signal_func\n"; + signal (sig, signal_func); + write (STDOUT_FILENO, text, sizeof text - 1); +} + +static void +intr_sleep (int sec) +{ + struct timespec ts; + + ts.tv_sec = sec; + ts.tv_nsec = 0; + + while (nanosleep (&ts, &ts) == -1 && errno == EINTR) + ; +} + +#define ZSIGALRM 14 + + +int +main (void) +{ + struct timespec ts; + timer_t timer_sig, timer_thr1, timer_thr2; + int retval; + struct sigevent sigev1 = + { + .sigev_notify = SIGEV_SIGNAL, + .sigev_signo = ZSIGALRM + }; + struct sigevent sigev2; + struct itimerspec itimer1 = { { 0, 200000000 }, { 0, 200000000 } }; + struct itimerspec itimer2 = { { 0, 100000000 }, { 0, 500000000 } }; + struct itimerspec itimer3 = { { 0, 150000000 }, { 0, 300000000 } }; + struct itimerspec old; + + retval = clock_gettime (CLOCK_REALTIME, &ts); + + sigev2.sigev_notify = SIGEV_THREAD; + sigev2.sigev_notify_function = notify_func1; + sigev2.sigev_notify_attributes = NULL; + /* It is unnecessary to do the following but to set a good example + we do it anyhow. */ + sigev2.sigev_value.sival_ptr = NULL; + + setvbuf (stdout, 0, _IOLBF, 0); + + printf ("clock_gettime returned %d, timespec = { %ld, %ld }\n", + retval, ts.tv_sec, ts.tv_nsec); + + retval = clock_getres (CLOCK_REALTIME, &ts); + + printf ("clock_getres returned %d, timespec = { %ld, %ld }\n", + retval, ts.tv_sec, ts.tv_nsec); + + if (timer_create (CLOCK_REALTIME, &sigev1, &timer_sig) != 0) + { + printf ("timer_create for timer_sig failed: %m\n"); + exit (1); + } + if (timer_create (CLOCK_REALTIME, &sigev2, &timer_thr1) != 0) + { + printf ("timer_create for timer_thr1 failed: %m\n"); + exit (1); + } + sigev2.sigev_notify_function = notify_func2; + if (timer_create (CLOCK_REALTIME, &sigev2, &timer_thr2) != 0) + { + printf ("timer_create for timer_thr2 failed: %m\n"); + exit (1); + } + + if (timer_settime (timer_thr1, 0, &itimer2, &old) != 0) + { + printf ("timer_settime for timer_thr1 failed: %m\n"); + exit (1); + } + if (timer_settime (timer_thr2, 0, &itimer3, &old) != 0) + { + printf ("timer_settime for timer_thr2 failed: %m\n"); + exit (1); + } + + signal (ZSIGALRM, signal_func); + + if (timer_settime (timer_sig, 0, &itimer1, &old) != 0) + { + printf ("timer_settime for timer_sig failed: %m\n"); + exit (1); + } + + intr_sleep (3); + + if (timer_delete (timer_sig) != 0) + { + printf ("timer_delete for timer_sig failed: %m\n"); + exit (1); + } + if (timer_delete (timer_thr1) != 0) + { + printf ("timer_delete for timer_thr1 failed: %m\n"); + exit (1); + } + + intr_sleep (3); + + if (timer_delete (timer_thr2) != 0) + { + printf ("timer_delete for timer_thr2 failed: %m\n"); + exit (1); + } + + return 0; +} --- /dev/null +++ b/fbtl/sysdeps/pthread/unwind-forcedunwind.c @@ -0,0 +1,151 @@ +/* Copyright (C) 2003-2013 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, see <http://www.gnu.org/licenses/>. */ + +#include <dlfcn.h> +#include <stdio.h> +#include <unwind.h> +#include <pthreadP.h> +#include <sysdep.h> +#include <gnu/lib-names.h> + +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 (__glibc_likely (libgcc_s_handle != NULL)) + { + /* 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 + ) + __libc_fatal (LIBGCC_S_SO " must be installed for pthread_cancel to work\n"); + + 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 (__glibc_unlikely (libgcc_s_handle == NULL)) + pthread_cancel_init (); + else + atomic_read_barrier (); + + 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 (__glibc_unlikely (libgcc_s_handle == NULL)) + pthread_cancel_init (); + else + atomic_read_barrier (); + + _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 (__glibc_unlikely (libgcc_s_handle == NULL)) + pthread_cancel_init (); + else + atomic_read_barrier (); + + _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 (__glibc_unlikely (libgcc_s_handle == NULL)) + pthread_cancel_init (); + else + atomic_read_barrier (); + + _Unwind_Word (*getcfa) (struct _Unwind_Context *) = libgcc_s_getcfa; + PTR_DEMANGLE (getcfa); + return getcfa (context); +} --- /dev/null +++ b/fbtl/sysdeps/x86_64/Makefile @@ -0,0 +1,27 @@ +# Copyright (C) 2002-2013 Free Software Foundation, Inc. +# This file is part of the GNU C Library. + +# The GNU C Library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. + +# The GNU C Library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. + +# You should have received a copy of the GNU Lesser General Public +# License along with the GNU C Library; if not, see +# <http://www.gnu.org/licenses/>. + +ifeq ($(subdir),csu) +gen-as-const-headers += tcb-offsets.sym +endif + +ifeq ($(subdir),fbtl) +# P4s have problems with 4M aliasing. We disturb the allocation of stacks +# just enough so the subsequent allocations do not use stack address +# (mod 4M) == 0. +CFLAGS-pthread_create.c += -DMULTI_PAGE_ALIASING=65536 +endif --- /dev/null +++ b/fbtl/sysdeps/x86_64/pthread_spin_init.c @@ -0,0 +1 @@ +#include "../i386/pthread_spin_init.c" --- /dev/null +++ b/fbtl/sysdeps/x86_64/pthread_spin_lock.S @@ -0,0 +1,36 @@ +/* Copyright (C) 2012-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <lowlevellock.h> + + .globl pthread_spin_lock + .type pthread_spin_lock,@function + .align 16 +pthread_spin_lock: +1: LOCK + decl 0(%rdi) + jne 2f + xor %eax, %eax + ret + + .align 16 +2: rep + nop + cmpl $0, 0(%rdi) + jg 1b + jmp 2b + .size pthread_spin_lock,.-pthread_spin_lock --- /dev/null +++ b/fbtl/sysdeps/x86_64/pthread_spin_trylock.S @@ -0,0 +1,39 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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 --- /dev/null +++ b/fbtl/sysdeps/x86_64/pthread_spin_unlock.S @@ -0,0 +1,30 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + + .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 --- /dev/null +++ b/fbtl/sysdeps/x86_64/pthreaddef.h @@ -0,0 +1,44 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +/* 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. + + We need to store post-AVX vector registers in the TCB and we want the + storage to be aligned to at least 32 bytes. + + Some processors such as Intel Atom pay a big penalty on every + access using a segment override if that segment's base is not + aligned to the size of a cache line. (See Intel 64 and IA-32 + Architectures Optimization Reference Manual, section 13.3.3.3, + "Segment Base".) On such machines, a cache line is 64 bytes. */ +#define TCB_ALIGNMENT 64 + + +/* Location of current stack frame. The frame pointer is not usable. */ +#define CURRENT_STACK_FRAME \ + ({ register char *frame __asm__("rsp"); frame; }) --- /dev/null +++ b/fbtl/sysdeps/x86_64/tcb-offsets.sym @@ -0,0 +1,26 @@ +#include <sysdep.h> +#include <tls.h> + +RESULT offsetof (struct pthread, result) +TID offsetof (struct pthread, tid) +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 + +-- 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 --- /dev/null +++ b/fbtl/sysdeps/x86_64/tls.h @@ -0,0 +1,379 @@ +/* Definition for thread-local data handling. nptl/x86_64 version. + Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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 <libc-internal.h> +# include <kernel-features.h> +# include <dl-dtv.h> + +/* Replacement type for __m128 since this file is included by ld.so, + which is compiled with -mno-sse. It must not change the alignment + of rtld_savespace_sse. */ +typedef struct +{ + int i[4]; +} __128bits; + + + +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 __glibc_reserved1; +# endif + int __glibc_unused1; + /* Reservation of some values for the TM ABI. */ + void *__private_tm[4]; + /* GCC split stack support. */ + void *__private_ss; + long int __glibc_reserved2; + /* Must be kept even if it is no longer used by glibc since programs, + like AddressSanitizer, depend on the size of tcbhead_t. */ + __128bits __glibc_unused2[8][4] __attribute__ ((aligned (32))); + + void *__padding[8]; +} tcbhead_t; + +#else /* __ASSEMBLER__ */ +# include <tcb-offsets.h> +#endif + + +/* Alignment requirement for the stack. */ +#define STACK_ALIGN 16 + + +#ifndef __ASSEMBLER__ +/* Get system call information. */ +# include <sysdep.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) + +/* 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 +# define TLS_DTV_AT_TP 0 + +/* Get the thread descriptor definition. */ +# include <fbtl/descr.h> + + +/* 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) + + +/* 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) \ + ({ 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 ("mov %%fs:%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_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 ((uint64_t) cast_to_integer (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 ((uint64_t) cast_to_integer (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) () + +#endif /* __ASSEMBLER__ */ + +#endif /* tls.h */ --- /dev/null +++ b/fbtl/tpp.c @@ -0,0 +1,171 @@ +/* Thread Priority Protect helpers. + Copyright (C) 2006-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#include <assert.h> +#include <atomic.h> +#include <errno.h> +#include <pthreadP.h> +#include <sched.h> +#include <stdlib.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; +} --- /dev/null +++ b/fbtl/tst-_res1.c @@ -0,0 +1,68 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +/* Test whether _res in glibc 2.1.x and earlier (before __res_state() + was introduced) works. Portable programs should never do the + dirty things below. */ + +#include <pthread.h> +#include <resolv.h> +#include <stdlib.h> +#include <stdio.h> + +void *tf (void *resp) +{ + if (resp == &_res || resp == __res_state ()) + abort (); + _res.retry = 24; + return NULL; +} + +void do_test (struct __res_state *resp) +{ + if (resp != &_res || resp != __res_state ()) + abort (); + if (_res.retry != 12) + abort (); +} + +int main (void) +{ +#undef _res + extern struct __res_state _res; + pthread_t th; + + _res.retry = 12; + if (pthread_create (&th, NULL, tf, &_res) != 0) + { + puts ("create failed"); + exit (1); + } + + do_test (&_res); + + if (pthread_join (th, NULL) != 0) + { + puts ("join failed"); + exit (1); + } + + do_test (&_res); + + exit (0); +} --- /dev/null +++ b/fbtl/tst-_res1mod1.c @@ -0,0 +1,22 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#include <resolv.h> +#undef _res + +struct __res_state _res; --- /dev/null +++ b/fbtl/tst-_res1mod2.c @@ -0,0 +1 @@ +/* Nothing. */ --- /dev/null +++ b/fbtl/tst-abstime.c @@ -0,0 +1,97 @@ +/* Copyright (C) 2010-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Andreas Schwab <schwab@redhat.com>, 2010. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <pthread.h> +#include <semaphore.h> +#include <stdio.h> + +static pthread_cond_t c = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t m1 = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t m2 = PTHREAD_MUTEX_INITIALIZER; +static pthread_rwlock_t rw1 = PTHREAD_RWLOCK_INITIALIZER; +static pthread_rwlock_t rw2 = PTHREAD_RWLOCK_INITIALIZER; +static sem_t sem; + +static void * +th (void *arg) +{ + long int res = 0; + int r; + struct timespec t = { -2, 0 }; + + r = pthread_mutex_timedlock (&m1, &t); + if (r != ETIMEDOUT) + { + puts ("pthread_mutex_timedlock did not return ETIMEDOUT"); + res = 1; + } + r = pthread_rwlock_timedrdlock (&rw1, &t); + if (r != ETIMEDOUT) + { + puts ("pthread_rwlock_timedrdlock did not return ETIMEDOUT"); + res = 1; + } + r = pthread_rwlock_timedwrlock (&rw2, &t); + if (r != ETIMEDOUT) + { + puts ("pthread_rwlock_timedwrlock did not return ETIMEDOUT"); + res = 1; + } + return (void *) res; +} + +static int +do_test (void) +{ + int res = 0; + int r; + struct timespec t = { -2, 0 }; + pthread_t pth; + + sem_init (&sem, 0, 0); + r = sem_timedwait (&sem, &t); + if (r != -1 || errno != ETIMEDOUT) + { + puts ("sem_timedwait did not fail with ETIMEDOUT"); + res = 1; + } + + pthread_mutex_lock (&m1); + pthread_rwlock_wrlock (&rw1); + pthread_rwlock_rdlock (&rw2); + pthread_mutex_lock (&m2); + if (pthread_create (&pth, 0, th, 0) != 0) + { + puts ("cannot create thread"); + return 1; + } + r = pthread_cond_timedwait (&c, &m2, &t); + if (r != ETIMEDOUT) + { + puts ("pthread_cond_timedwait did not return ETIMEDOUT"); + res = 1; + } + void *thres; + pthread_join (pth, &thres); + return res | (thres != NULL); +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" --- /dev/null +++ b/fbtl/tst-align.c @@ -0,0 +1,70 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-align2.c @@ -0,0 +1,95 @@ +/* Copyright (C) 2004-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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> +#include <stackinfo.h> + +static int +f (void *arg) +{ + bool ok = true; + + puts ("in f"); + + 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] __attribute__ ((aligned)); +# if _STACK_GROWS_DOWN + pid_t p = clone (f, st + sizeof (st), 0, 0); +# elif _STACK_GROWS_UP + pid_t p = clone (f, st, 0, 0); +# else +# error "Define either _STACK_GROWS_DOWN or _STACK_GROWS_UP" +# endif +#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" --- /dev/null +++ b/fbtl/tst-align3.c @@ -0,0 +1,56 @@ +/* Copyright (C) 2005-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#include <pthread.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <tst-stack-align.h> + +static bool ok = true; +static pthread_once_t once = PTHREAD_ONCE_INIT; + +static void +once_test (void) +{ + puts ("in once_test"); + + if (TEST_STACK_ALIGN ()) + ok = false; +} + +static int +do_test (void) +{ + puts ("in main"); + + if (TEST_STACK_ALIGN ()) + ok = false; + + if (pthread_once (&once, once_test)) + { + puts ("pthread once failed"); + return 1; + } + + return ok ? 0 : 1; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" --- /dev/null +++ b/fbtl/tst-atfork1.c @@ -0,0 +1,120 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-atfork2.c @@ -0,0 +1,158 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#include <dlfcn.h> +#include <errno.h> +#include <mcheck.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/wait.h> + + +/* Must be exported. */ +int val; + +static void +prepare (void) +{ + val *= 2; +} + +static void +parent (void) +{ + val += 4; +} + +static void +child (void) +{ + val += 8; +} + + +static int +do_test (void) +{ + mtrace (); + + if (pthread_atfork (prepare, parent, child) != 0) + { + puts ("do_test: atfork failed"); + exit (1); + } + + void *h = dlopen ("tst-atfork2mod.so", RTLD_LAZY); + if (h == NULL) + { + printf ("dlopen failed: %s\n", dlerror ()); + exit (1); + } + + /* First trial of fork. */ + pid_t pid = fork (); + if (pid == -1) + { + puts ("1st fork failed"); + exit (1); + } + + if (pid == 0) + { + /* Child. */ + if (val != 80) + { + printf ("1st: expected val=%d, got %d\n", 80, val); + exit (2); + } + + exit (0); + } + + /* Parent. */ + if (val != 24) + { + printf ("1st: expected val=%d, got %d\n", 24, val); + exit (1); + } + + int status; + if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid) + { + puts ("1st waitpid failed"); + exit (1); + } + + if (status != 0) + exit (status); + + puts ("unloading now"); + + /* Unload the module. */ + if (dlclose (h) != 0) + { + puts ("dlclose failed"); + exit (1); + } + + puts ("2nd fork"); + + /* Second fork trial. */ + val = 1; + pid = fork (); + if (pid == -1) + { + puts ("2nd fork failed"); + exit (1); + } + + if (pid == 0) + { + /* Child. */ + if (val != 10) + { + printf ("2nd: expected val=%d, got %d\n", 10, val); + exit (3); + } + + exit (0); + } + + /* Parent. */ + if (val != 6) + { + printf ("2nd: expected val=%d, got %d\n", 6, val); + exit (1); + } + + if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid) + { + puts ("2nd waitpid failed"); + exit (1); + } + + if (status != 0) + exit (status); + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" --- /dev/null +++ b/fbtl/tst-atfork2mod.c @@ -0,0 +1,57 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> + + +extern int val; + + +static void +prepare (void) +{ + ++val; +} + +static void +parent (void) +{ + val *= 4; +} + +static void +child (void) +{ + val *= 8; +} + +static void +__attribute__ ((constructor)) +init (void) +{ + extern void *__dso_handle; + printf ("dsohandle = %p\n", __dso_handle); + + if (pthread_atfork (prepare, parent, child) != 0) + { + puts ("init: atfork failed"); + exit (1); + } +} --- /dev/null +++ b/fbtl/tst-attr1.c @@ -0,0 +1,305 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-attr2.c @@ -0,0 +1,316 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-attr3.c @@ -0,0 +1,421 @@ +/* pthread_getattr_np test. + Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <error.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <stackinfo.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" --- /dev/null +++ b/fbtl/tst-backtrace1.c @@ -0,0 +1,85 @@ +/* Copyright (C) 2004-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#include <execinfo.h> +#include <pthread.h> +#include <stdio.h> + +#define BT_SIZE 64 +void *bt_array[BT_SIZE]; +int bt_cnt; + +int +do_bt (void) +{ + bt_cnt = backtrace (bt_array, BT_SIZE); + return 56; +} + +int +call_do_bt (void) +{ + return do_bt () + 1; +} + +void * +tf (void *arg) +{ + if (call_do_bt () != 57) + return (void *) 1L; + return NULL; +} + +int +do_test (void) +{ + pthread_t th; + if (pthread_create (&th, NULL, tf, NULL)) + { + puts ("create failed"); + return 1; + } + + void *res; + if (pthread_join (th, &res)) + { + puts ("join failed"); + return 1; + } + + if (res != NULL) + { + puts ("thread failed"); + return 1; + } + + char **text = backtrace_symbols (bt_array, bt_cnt); + if (text == NULL) + { + puts ("backtrace_symbols failed"); + return 1; + } + + for (int i = 0; i < bt_cnt; ++i) + puts (text[i]); + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" --- /dev/null +++ b/fbtl/tst-barrier1.c @@ -0,0 +1,70 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-barrier2.c @@ -0,0 +1,184 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-barrier3.c @@ -0,0 +1,153 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +/* 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" --- /dev/null +++ b/fbtl/tst-barrier4.c @@ -0,0 +1,121 @@ +/* Copyright (C) 2004-2013 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, see + <http://www.gnu.org/licenses/>. */ + +/* 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" --- /dev/null +++ b/fbtl/tst-basic1.c @@ -0,0 +1,81 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-basic2.c @@ -0,0 +1,120 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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 result; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" --- /dev/null +++ b/fbtl/tst-basic3.c @@ -0,0 +1,86 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-basic4.c @@ -0,0 +1,100 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-basic5.c @@ -0,0 +1,73 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-basic6.c @@ -0,0 +1,131 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-basic7.c @@ -0,0 +1,74 @@ +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/resource.h> + +static void use_stack (size_t needed); + +void (*use_stack_ptr) (size_t) = use_stack; + +static void +use_stack (size_t needed) +{ + size_t sz = sysconf (_SC_PAGESIZE); + char *buf = alloca (sz); + memset (buf, '\0', sz); + + if (needed > sz) + use_stack_ptr (needed - sz); +} + +static void +use_up_memory (void) +{ + struct rlimit rl; + getrlimit (RLIMIT_AS, &rl); + rl.rlim_cur = 10 * 1024 * 1024; + setrlimit (RLIMIT_AS, &rl); + + char *c; + int PAGESIZE = getpagesize (); + while (1) + { + c = mmap (NULL, PAGESIZE, PROT_NONE, MAP_ANON | MAP_PRIVATE, -1, 0); + if (c == MAP_FAILED) + break; + } +} + +static void * +child (void *arg) +{ + sleep (1); + return arg; +} + +static int +do_test (void) +{ + int err; + pthread_t tid; + + /* Allocate the memory needed for the stack. */ + use_stack_ptr (PTHREAD_STACK_MIN); + + use_up_memory (); + + err = pthread_create (&tid, NULL, child, NULL); + if (err != 0) + { + printf ("pthread_create returns %d: %s\n", err, + err == EAGAIN ? "OK" : "FAIL"); + return err != EAGAIN; + } + + /* We did not fail to allocate memory despite the preparation. Oh well. */ + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" --- /dev/null +++ b/fbtl/tst-cancel-self-cancelstate.c @@ -0,0 +1,65 @@ +/* Copyright (C) 2012-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "tst-cancel-self-cleanup.c" + + +static int +do_test (void) +{ + int ret = 0; + volatile int should_fail = 1; + + pthread_cleanup_push (cleanup, &should_fail); + + if ((ret = pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL)) != 0) + { + printf ("setcancelstate(disable) failed: %s\n", strerror (ret)); + exit (1); + } + + if ((ret = pthread_cancel (pthread_self ())) != 0) + { + printf ("cancel failed: %s\n", strerror (ret)); + exit (1); + } + + usleep (100); + should_fail = 0; + + if ((ret = pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL)) != 0) + { + printf ("setcancelstate(enable) failed: %s\n", strerror (ret)); + exit (1); + } + + /* The write syscall within this printf should give us our cancellation + point. */ + printf ("Could not cancel self.\n"); + pthread_cleanup_pop (0); + + return 1; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" --- /dev/null +++ b/fbtl/tst-cancel-self-canceltype.c @@ -0,0 +1,53 @@ +/* Copyright (C) 2012-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "tst-cancel-self-cleanup.c" + + +static int +do_test (void) +{ + int ret = 0, should_fail = 0; + + pthread_cleanup_push (cleanup, &should_fail); + + if ((ret = pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL)) != 0) + { + printf ("setcanceltype failed: %s\n", strerror (ret)); + exit (1); + } + + if ((ret = pthread_cancel (pthread_self ())) != 0) + { + printf ("cancel failed: %s\n", strerror (ret)); + exit (1); + } + + /* Wait to be canceled. Don't give any cancellation points to play with. */ + while (1); + pthread_cleanup_pop (0); + + return 1; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" --- /dev/null +++ b/fbtl/tst-cancel-self-cleanup.c @@ -0,0 +1,23 @@ +/* Copyright (C) 2012-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +static void +cleanup (void *cleanup_should_fail) +{ + printf ("Main thread got cancelled and is being cleaned up now\n"); + exit (*(int *)cleanup_should_fail); +} --- /dev/null +++ b/fbtl/tst-cancel-self-testcancel.c @@ -0,0 +1,48 @@ +/* Copyright (C) 2012-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "tst-cancel-self-cleanup.c" + + +static int +do_test (void) +{ + int ret = 0, should_fail = 0; + + pthread_cleanup_push (cleanup, &should_fail); + if ((ret = pthread_cancel (pthread_self ())) != 0) + { + printf ("cancel failed: %s\n", strerror (ret)); + exit (1); + } + + pthread_testcancel (); + + printf ("Could not cancel self.\n"); + pthread_cleanup_pop (0); + + return 1; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" --- /dev/null +++ b/fbtl/tst-cancel-self.c @@ -0,0 +1,48 @@ +/* Copyright (C) 2012-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "tst-cancel-self-cleanup.c" + + +static int +do_test (void) +{ + int ret = 0, should_fail = 0; + + pthread_cleanup_push (cleanup, &should_fail); + if ((ret = pthread_cancel (pthread_self ())) != 0) + { + printf ("cancel failed: %s\n", strerror (ret)); + exit (1); + } + + /* The write syscall within this printf should give us our cancellation + point. */ + printf ("Could not cancel self.\n"); + pthread_cleanup_pop (0); + + return 1; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" --- /dev/null +++ b/fbtl/tst-cancel-wrappers.sh @@ -0,0 +1,92 @@ +#! /bin/sh +# Test whether all cancelable functions are cancelable. +# Copyright (C) 2002-2013 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, see +# <http://www.gnu.org/licenses/>. + +NM="$1"; shift +while [ $# -gt 0 ]; do + ( $NM -P $1; echo 'end[end]:' ) | gawk ' BEGIN { +C["accept"]=1 +C["close"]=1 +C["connect"]=1 +C["creat"]=1 +C["fcntl"]=1 +C["fdatasync"]=1 +C["fsync"]=1 +C["msgrcv"]=1 +C["msgsnd"]=1 +C["msync"]=1 +C["nanosleep"]=1 +C["open"]=1 +C["open64"]=1 +C["pause"]=1 +C["poll"]=1 +C["pread"]=1 +C["pread64"]=1 +C["pselect"]=1 +C["pwrite"]=1 +C["pwrite64"]=1 +C["read"]=1 +C["readv"]=1 +C["recv"]=1 +C["recvfrom"]=1 +C["recvmsg"]=1 +C["select"]=1 +C["send"]=1 +C["sendmsg"]=1 +C["sendto"]=1 +C["sigpause"]=1 +C["sigsuspend"]=1 +C["sigwait"]=1 +C["sigwaitinfo"]=1 +C["tcdrain"]=1 +C["wait"]=1 +C["waitid"]=1 +C["waitpid"]=1 +C["write"]=1 +C["writev"]=1 +C["__xpg_sigpause"]=1 +} +/:$/ { + if (seen) + { + if (!seen_enable || !seen_disable) + { + printf "in '$1'(%s) %s'\''s cancellation missing\n", object, seen + ret = 1 + } + } + seen="" + seen_enable="" + seen_disable="" + object=gensub(/^.*\[(.*)\]:$/,"\\1","",$0) + next +} +{ + if (C[$1] && $2 ~ /^[TW]$/) + seen=$1 + else if ($1 ~ /^([.]|)__(libc|pthread)_enable_asynccancel$/ && $2 == "U") + seen_enable=1 + else if ($1 ~ /^([.]|)__(libc|pthread)_disable_asynccancel$/ && $2 == "U") + seen_disable=1 +} +END { + exit ret +}' || exit + shift +done --- /dev/null +++ b/fbtl/tst-cancel1.c @@ -0,0 +1,162 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-cancel10.c @@ -0,0 +1,125 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-cancel11.c @@ -0,0 +1,122 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-cancel12.c @@ -0,0 +1,126 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-cancel13.c @@ -0,0 +1,128 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-cancel14.c @@ -0,0 +1,136 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-cancel15.c @@ -0,0 +1,141 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-cancel16.c @@ -0,0 +1,230 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-cancel17.c @@ -0,0 +1,340 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#include <aio.h> +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + + +static pthread_barrier_t b; + + +/* Cleanup handling test. */ +static int cl_called; + +static void +cl (void *arg) +{ + ++cl_called; +} + + +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); + + const struct aiocb *l[1] = { arg }; + + TEMP_FAILURE_RETRY (aio_suspend (l, 1, NULL)); + + pthread_cleanup_pop (0); + + puts ("tf: aio_suspend returned"); + + exit (1); +} + + +static void * +tf2 (void *arg) +{ + int r = pthread_barrier_wait (&b); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("tf2: barrier_wait failed"); + exit (1); + } + + pthread_cleanup_push (cl, NULL); + + const struct aiocb *l[1] = { arg }; + struct timespec ts = { .tv_sec = 1000, .tv_nsec = 0 }; + + TEMP_FAILURE_RETRY (aio_suspend (l, 1, &ts)); + + pthread_cleanup_pop (0); + + puts ("tf2: aio_suspend returned"); + + exit (1); +} + + +static int +do_test (void) +{ + int fds[2]; + if (pipe (fds) != 0) + { + puts ("pipe failed"); + return 1; + } + + struct aiocb a, a2, *ap; + char mem[1]; + memset (&a, '\0', sizeof (a)); + a.aio_fildes = fds[0]; + a.aio_buf = mem; + a.aio_nbytes = sizeof (mem); + if (aio_read (&a) != 0) + { + puts ("aio_read failed"); + return 1; + } + + if (pthread_barrier_init (&b, NULL, 2) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + pthread_t th; + if (pthread_create (&th, NULL, tf, &a) != 0) + { + puts ("1st create failed"); + return 1; + } + + int r = pthread_barrier_wait (&b); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + exit (1); + } + + struct timespec ts = { .tv_sec = 0, .tv_nsec = 100000000 }; + while (nanosleep (&ts, &ts) != 0) + continue; + + puts ("going to cancel tf in-time"); + if (pthread_cancel (th) != 0) + { + puts ("1st cancel failed"); + return 1; + } + + void *status; + if (pthread_join (th, &status) != 0) + { + puts ("1st join failed"); + return 1; + } + if (status != PTHREAD_CANCELED) + { + puts ("1st thread not canceled"); + return 1; + } + + if (cl_called == 0) + { + puts ("tf cleanup handler not called"); + return 1; + } + if (cl_called > 1) + { + puts ("tf cleanup handler called more than once"); + return 1; + } + + cl_called = 0; + + if (pthread_create (&th, NULL, tf2, &a) != 0) + { + puts ("2nd create failed"); + return 1; + } + + r = pthread_barrier_wait (&b); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("2nd barrier_wait failed"); + exit (1); + } + + ts.tv_sec = 0; + ts.tv_nsec = 100000000; + while (nanosleep (&ts, &ts) != 0) + continue; + + puts ("going to cancel tf2 in-time"); + if (pthread_cancel (th) != 0) + { + puts ("2nd cancel failed"); + return 1; + } + + if (pthread_join (th, &status) != 0) + { + puts ("2nd join failed"); + return 1; + } + if (status != PTHREAD_CANCELED) + { + puts ("2nd thread not canceled"); + return 1; + } + + if (cl_called == 0) + { + puts ("tf2 cleanup handler not called"); + return 1; + } + if (cl_called > 1) + { + puts ("tf2 cleanup handler called more than once"); + return 1; + } + + puts ("in-time cancellation succeeded"); + + ap = &a; + if (aio_cancel (fds[0], &a) != AIO_CANCELED) + { + puts ("aio_cancel failed"); + /* If aio_cancel failed, we cannot reuse aiocb a. */ + ap = &a2; + } + + + cl_called = 0; + + size_t len2 = fpathconf (fds[1], _PC_PIPE_BUF); + size_t page_size = sysconf (_SC_PAGESIZE); + len2 = 20 * (len2 < page_size ? page_size : len2) + sizeof (mem) + 1; + char *mem2 = malloc (len2); + if (mem2 == NULL) + { + puts ("could not allocate memory for pipe write"); + return 1; + } + + memset (ap, '\0', sizeof (*ap)); + ap->aio_fildes = fds[1]; + ap->aio_buf = mem2; + ap->aio_nbytes = len2; + if (aio_write (ap) != 0) + { + puts ("aio_write failed"); + return 1; + } + + if (pthread_create (&th, NULL, tf, ap) != 0) + { + puts ("3rd create failed"); + return 1; + } + + puts ("going to cancel tf early"); + if (pthread_cancel (th) != 0) + { + puts ("3rd cancel failed"); + return 1; + } + + r = pthread_barrier_wait (&b); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("3rd barrier_wait failed"); + exit (1); + } + + if (pthread_join (th, &status) != 0) + { + puts ("3rd join failed"); + return 1; + } + if (status != PTHREAD_CANCELED) + { + puts ("3rd thread not canceled"); + return 1; + } + + if (cl_called == 0) + { + puts ("tf cleanup handler not called"); + return 1; + } + if (cl_called > 1) + { + puts ("tf cleanup handler called more than once"); + return 1; + } + + cl_called = 0; + + if (pthread_create (&th, NULL, tf2, ap) != 0) + { + puts ("4th create failed"); + return 1; + } + + puts ("going to cancel tf2 early"); + if (pthread_cancel (th) != 0) + { + puts ("4th cancel failed"); + return 1; + } + + r = pthread_barrier_wait (&b); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("4th barrier_wait failed"); + exit (1); + } + + if (pthread_join (th, &status) != 0) + { + puts ("4th join failed"); + return 1; + } + if (status != PTHREAD_CANCELED) + { + puts ("4th thread not canceled"); + return 1; + } + + if (cl_called == 0) + { + puts ("tf2 cleanup handler not called"); + return 1; + } + if (cl_called > 1) + { + puts ("tf2 cleanup handler called more than once"); + return 1; + } + + puts ("early cancellation succeeded"); + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" --- /dev/null +++ b/fbtl/tst-cancel18.c @@ -0,0 +1,173 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <unistd.h> + + +static pthread_barrier_t b; + + +/* Cleanup handling test. */ +static int cl_called; + +static void +cl (void *arg) +{ + ++cl_called; +} + + +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); + } + + pthread_cleanup_push (cl, NULL); + + struct timespec ts = { .tv_sec = arg == NULL ? 10000000 : 0, .tv_nsec = 0 }; + TEMP_FAILURE_RETRY (clock_nanosleep (CLOCK_REALTIME, 0, &ts, &ts)); + + pthread_cleanup_pop (0); + + puts ("clock_nanosleep returned"); + + 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 ("1st create failed"); + return 1; + } + + int r = pthread_barrier_wait (&b); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + exit (1); + } + + struct timespec ts = { .tv_sec = 0, .tv_nsec = 100000000 }; + while (nanosleep (&ts, &ts) != 0) + continue; + + puts ("going to cancel in-time"); + if (pthread_cancel (th) != 0) + { + puts ("1st cancel failed"); + return 1; + } + + void *status; + if (pthread_join (th, &status) != 0) + { + puts ("1st join failed"); + return 1; + } + if (status != PTHREAD_CANCELED) + { + puts ("1st thread not canceled"); + return 1; + } + + if (cl_called == 0) + { + puts ("cleanup handler not called"); + return 1; + } + if (cl_called > 1) + { + puts ("cleanup handler called more than once"); + return 1; + } + + puts ("in-time cancellation succeeded"); + + + cl_called = 0; + + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("2nd create failed"); + return 1; + } + + puts ("going to cancel early"); + if (pthread_cancel (th) != 0) + { + puts ("2nd cancel failed"); + return 1; + } + + r = pthread_barrier_wait (&b); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + exit (1); + } + + if (pthread_join (th, &status) != 0) + { + puts ("2nd join failed"); + return 1; + } + if (status != PTHREAD_CANCELED) + { + puts ("2nd thread not canceled"); + return 1; + } + + if (cl_called == 0) + { + printf ("cleanup handler not called\n"); + return 1; + } + if (cl_called > 1) + { + printf ("cleanup handler called more than once\n"); + return 1; + } + + puts ("early cancellation succeeded"); + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" --- /dev/null +++ b/fbtl/tst-cancel19.c @@ -0,0 +1,286 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-cancel2.c @@ -0,0 +1,95 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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]; + + while (write (fd[1], buf, sizeof (buf)) > 0); + + 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" --- /dev/null +++ b/fbtl/tst-cancel20.c @@ -0,0 +1,263 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-cancel21-static.c @@ -0,0 +1 @@ +#include "tst-cancel21.c" --- /dev/null +++ b/fbtl/tst-cancel21.c @@ -0,0 +1,293 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-cancel22.c @@ -0,0 +1,120 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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 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 (int 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" --- /dev/null +++ b/fbtl/tst-cancel23.c @@ -0,0 +1 @@ +#include "tst-cancel22.c" --- /dev/null +++ b/fbtl/tst-cancel24-static.cc @@ -0,0 +1 @@ +#include "tst-cancel24.cc" --- /dev/null +++ b/fbtl/tst-cancel24.cc @@ -0,0 +1,113 @@ +#include <pthread.h> +#include <semaphore.h> +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> + + +static volatile bool destr_called; +static volatile bool except_caught; + +static pthread_barrier_t b; + + +struct monitor +{ + // gcc is broken and would generate a warning without this dummy + // constructor. + monitor () { } + ~monitor() { destr_called = true; } +}; + + +static void * +tf (void *arg) +{ + sem_t *s = static_cast<sem_t *> (arg); + + try + { + monitor m; + + pthread_barrier_wait (&b); + + while (1) + sem_wait (s); + } + catch (...) + { + except_caught = true; + throw; + } + + return NULL; +} + + +static int +do_test () +{ + if (pthread_barrier_init (&b, NULL, 2) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + sem_t s; + if (sem_init (&s, 0, 0) != 0) + { + puts ("sem_init failed"); + return 1; + } + + pthread_t th; + if (pthread_create (&th, NULL, tf, &s) != 0) + { + puts ("pthread_create failed"); + return 1; + } + + pthread_barrier_wait (&b); + + /* There is unfortunately no better method to try to assure the + child thread reached the sem_wait call and is actually waiting + than to sleep here. */ + sleep (1); + + if (pthread_cancel (th) != 0) + { + puts ("cancel failed"); + return 1; + } + + void *res; + if (pthread_join (th, &res) != 0) + { + puts ("join failed"); + return 1; + } + + if (res != PTHREAD_CANCELED) + { + puts ("thread was not canceled"); + return 1; + } + + if (! except_caught) + { + puts ("exception not caught"); + return 1; + } + + if (! destr_called) + { + puts ("destructor not called"); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#define TIMEOUT 3 +#include "../test-skeleton.c" --- /dev/null +++ b/fbtl/tst-cancel25.c @@ -0,0 +1,171 @@ +#include <pthreadP.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> + + +static pthread_barrier_t b; +static pthread_t th2; + + +static void * +tf2 (void *arg) +{ + sigset_t mask; + if (pthread_sigmask (SIG_SETMASK, NULL, &mask) != 0) + { + puts ("pthread_sigmask failed"); + exit (1); + } + if (sigismember (&mask, SIGCANCEL)) + { + puts ("SIGCANCEL blocked in new thread"); + exit (1); + } + + /* Sync with the main thread so that we do not test anything else. */ + int e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + exit (1); + } + + while (1) + { + /* Just a cancelable call. */ + struct timespec ts = { 10000, 0 }; + nanosleep (&ts, 0); + } + + return NULL; +} + + +static void +unwhand (void *arg) +{ + if (pthread_create (&th2, NULL, tf2, NULL) != 0) + { + puts ("unwhand: create failed"); + exit (1); + } +} + + +static void * +tf (void *arg) +{ + pthread_cleanup_push (unwhand, NULL); + + /* Sync with the main thread so that we do not test anything else. */ + int e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + exit (1); + } + + while (1) + { + /* Just a cancelable call. */ + struct timespec ts = { 10000, 0 }; + nanosleep (&ts, 0); + } + + pthread_cleanup_pop (0); + + return NULL; +} + + +static int +do_test (void) +{ + if (pthread_barrier_init (&b, NULL, 2) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + pthread_t th1; + if (pthread_create (&th1, 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; + } + + /* Make sure tf1 enters nanosleep. */ + struct timespec ts = { 0, 500000000 }; + while (nanosleep (&ts, &ts) != 0) + ; + + if (pthread_cancel (th1) != 0) + { + puts ("1st cancel failed"); + return 1; + } + + void *res; + if (pthread_join (th1, &res) != 0) + { + puts ("1st join failed"); + return 1; + } + if (res != PTHREAD_CANCELED) + { + puts ("1st thread not canceled"); + return 1; + } + + e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + return 1; + } + + /* Make sure tf2 enters nanosleep. */ + ts.tv_sec = 0; + ts.tv_nsec = 500000000; + while (nanosleep (&ts, &ts) != 0) + ; + + puts ("calling pthread_cancel the second time"); + if (pthread_cancel (th2) != 0) + { + puts ("2nd cancel failed"); + return 1; + } + + puts ("calling pthread_join the second time"); + if (pthread_join (th2, &res) != 0) + { + puts ("2nd join failed"); + return 1; + } + if (res != PTHREAD_CANCELED) + { + puts ("2nd thread not canceled"); + return 1; + } + + if (pthread_barrier_destroy (&b) != 0) + { + puts ("barrier_destroy failed"); + return 0; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#define TIMEOUT 4 +#include "../test-skeleton.c" --- /dev/null +++ b/fbtl/tst-cancel3.c @@ -0,0 +1,97 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-cancel4.c @@ -0,0 +1,2375 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +/* NOTE: this tests functionality beyond POSIX. POSIX does not allow + exit to be called more than once. */ + +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <pthread.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/msg.h> +#include <sys/poll.h> +#include <sys/select.h> +#include <sys/socket.h> +#include <sys/uio.h> +#include <sys/un.h> +#include <sys/wait.h> + +#include "pthreadP.h" + + +/* Since STREAMS are not supported in the standard Linux kernel and + there we don't advertise STREAMS as supported is no need to test + the STREAMS related functions. This affects + getmsg() getpmsg() putmsg() + putpmsg() + + lockf() and fcntl() are tested in tst-cancel16. + + pthread_join() is tested in tst-join5. + + pthread_testcancel()'s only purpose is to allow cancellation. This + is tested in several places. + + sem_wait() and sem_timedwait() are checked in tst-cancel1[2345] tests. + + mq_send(), mq_timedsend(), mq_receive() and mq_timedreceive() are checked + in tst-mqueue8{,x} tests. + + aio_suspend() is tested in tst-cancel17. + + clock_nanosleep() is tested in tst-cancel18. +*/ + +/* Pipe descriptors. */ +static int fds[2]; + +/* Temporary file descriptor, to be closed after each round. */ +static int tempfd = -1; +static int tempfd2 = -1; +/* Name of temporary file to be removed after each round. */ +static char *tempfname; +/* Temporary message queue. */ +static int tempmsg = -1; + +/* Often used barrier for two threads. */ +static pthread_barrier_t b2; + + +#ifndef IPC_ADDVAL +# define IPC_ADDVAL 0 +#endif + +#define WRITE_BUFFER_SIZE 4096 + +/* Cleanup handling test. */ +static int cl_called; + +static void +cl (void *arg) +{ + ++cl_called; +} + + + +static void * +tf_read (void *arg) +{ + int fd; + int r; + + if (arg == NULL) + fd = fds[0]; + else + { + char fname[] = "/tmp/tst-cancel4-fd-XXXXXX"; + tempfd = fd = mkstemp (fname); + if (fd == -1) + printf ("%s: mkstemp failed\n", __FUNCTION__); + unlink (fname); + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + ssize_t s; + pthread_cleanup_push (cl, NULL); + + char buf[100]; + s = read (fd, buf, sizeof (buf)); + + pthread_cleanup_pop (0); + + printf ("%s: read returns with %zd\n", __FUNCTION__, s); + + exit (1); +} + + +static void * +tf_readv (void *arg) +{ + int fd; + int r; + + if (arg == NULL) + fd = fds[0]; + else + { + char fname[] = "/tmp/tst-cancel4-fd-XXXXXX"; + tempfd = fd = mkstemp (fname); + if (fd == -1) + printf ("%s: mkstemp failed\n", __FUNCTION__); + unlink (fname); + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + ssize_t s; + pthread_cleanup_push (cl, NULL); + + char buf[100]; + struct iovec iov[1] = { [0] = { .iov_base = buf, .iov_len = sizeof (buf) } }; + s = readv (fd, iov, 1); + + pthread_cleanup_pop (0); + + printf ("%s: readv returns with %zd\n", __FUNCTION__, s); + + exit (1); +} + + +static void * +tf_write (void *arg) +{ + int fd; + int r; + + if (arg == NULL) + fd = fds[1]; + else + { + char fname[] = "/tmp/tst-cancel4-fd-XXXXXX"; + tempfd = fd = mkstemp (fname); + if (fd == -1) + printf ("%s: mkstemp failed\n", __FUNCTION__); + unlink (fname); + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + ssize_t s; + pthread_cleanup_push (cl, NULL); + + char buf[WRITE_BUFFER_SIZE]; + memset (buf, '\0', sizeof (buf)); + s = write (fd, buf, sizeof (buf)); + + pthread_cleanup_pop (0); + + printf ("%s: write returns with %zd\n", __FUNCTION__, s); + + exit (1); +} + + +static void * +tf_writev (void *arg) +{ + int fd; + int r; + + if (arg == NULL) + fd = fds[1]; + else + { + char fname[] = "/tmp/tst-cancel4-fd-XXXXXX"; + tempfd = fd = mkstemp (fname); + if (fd == -1) + printf ("%s: mkstemp failed\n", __FUNCTION__); + unlink (fname); + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + ssize_t s; + pthread_cleanup_push (cl, NULL); + + char buf[WRITE_BUFFER_SIZE]; + memset (buf, '\0', sizeof (buf)); + struct iovec iov[1] = { [0] = { .iov_base = buf, .iov_len = sizeof (buf) } }; + s = writev (fd, iov, 1); + + pthread_cleanup_pop (0); + + printf ("%s: writev returns with %zd\n", __FUNCTION__, s); + + exit (1); +} + + +static void * +tf_sleep (void *arg) +{ + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + if (arg != NULL) + { + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + pthread_cleanup_push (cl, NULL); + + sleep (arg == NULL ? 1000000 : 0); + + pthread_cleanup_pop (0); + + printf ("%s: sleep returns\n", __FUNCTION__); + + exit (1); +} + + +static void * +tf_usleep (void *arg) +{ + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + if (arg != NULL) + { + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + pthread_cleanup_push (cl, NULL); + + usleep (arg == NULL ? (useconds_t) ULONG_MAX : 0); + + pthread_cleanup_pop (0); + + printf ("%s: usleep returns\n", __FUNCTION__); + + exit (1); +} + + +static void * +tf_nanosleep (void *arg) +{ + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + if (arg != NULL) + { + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + pthread_cleanup_push (cl, NULL); + + struct timespec ts = { .tv_sec = arg == NULL ? 10000000 : 0, .tv_nsec = 0 }; + TEMP_FAILURE_RETRY (nanosleep (&ts, &ts)); + + pthread_cleanup_pop (0); + + printf ("%s: nanosleep returns\n", __FUNCTION__); + + exit (1); +} + + +static void * +tf_select (void *arg) +{ + int fd; + int r; + + if (arg == NULL) + fd = fds[0]; + else + { + char fname[] = "/tmp/tst-cancel4-fd-XXXXXX"; + tempfd = fd = mkstemp (fname); + if (fd == -1) + printf ("%s: mkstemp failed\n", __FUNCTION__); + unlink (fname); + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + fd_set rfs; + FD_ZERO (&rfs); + FD_SET (fd, &rfs); + + int s; + pthread_cleanup_push (cl, NULL); + + s = select (fd + 1, &rfs, NULL, NULL, NULL); + + pthread_cleanup_pop (0); + + printf ("%s: select returns with %d (%s)\n", __FUNCTION__, s, + strerror (errno)); + + exit (1); +} + + +static void * +tf_pselect (void *arg) +{ + int fd; + int r; + + if (arg == NULL) + fd = fds[0]; + else + { + char fname[] = "/tmp/tst-cancel4-fd-XXXXXX"; + tempfd = fd = mkstemp (fname); + if (fd == -1) + printf ("%s: mkstemp failed\n", __FUNCTION__); + unlink (fname); + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + fd_set rfs; + FD_ZERO (&rfs); + FD_SET (fd, &rfs); + + int s; + pthread_cleanup_push (cl, NULL); + + s = pselect (fd + 1, &rfs, NULL, NULL, NULL, NULL); + + pthread_cleanup_pop (0); + + printf ("%s: pselect returns with %d (%s)\n", __FUNCTION__, s, + strerror (errno)); + + exit (1); +} + + +static void * +tf_poll (void *arg) +{ + int fd; + int r; + + if (arg == NULL) + fd = fds[0]; + else + { + char fname[] = "/tmp/tst-cancel4-fd-XXXXXX"; + tempfd = fd = mkstemp (fname); + if (fd == -1) + printf ("%s: mkstemp failed\n", __FUNCTION__); + unlink (fname); + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + struct pollfd rfs[1] = { [0] = { .fd = fd, .events = POLLIN } }; + + int s; + pthread_cleanup_push (cl, NULL); + + s = poll (rfs, 1, -1); + + pthread_cleanup_pop (0); + + printf ("%s: poll returns with %d (%s)\n", __FUNCTION__, s, + strerror (errno)); + + exit (1); +} + + +static void * +tf_ppoll (void *arg) +{ + int fd; + int r; + + if (arg == NULL) + fd = fds[0]; + else + { + char fname[] = "/tmp/tst-cancel4-fd-XXXXXX"; + tempfd = fd = mkstemp (fname); + if (fd == -1) + printf ("%s: mkstemp failed\n", __FUNCTION__); + unlink (fname); + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + struct pollfd rfs[1] = { [0] = { .fd = fd, .events = POLLIN } }; + + int s; + pthread_cleanup_push (cl, NULL); + + s = ppoll (rfs, 1, NULL, NULL); + + pthread_cleanup_pop (0); + + printf ("%s: ppoll returns with %d (%s)\n", __FUNCTION__, s, + strerror (errno)); + + exit (1); +} + + +static void * +tf_wait (void *arg) +{ + pid_t pid = fork (); + if (pid == -1) + { + puts ("fork failed"); + exit (1); + } + + if (pid == 0) + { + /* Make the program disappear after a while. */ + if (arg == NULL) + sleep (10); + exit (0); + } + + int r; + if (arg != NULL) + { + struct timespec ts = { .tv_sec = 0, .tv_nsec = 100000000 }; + while (nanosleep (&ts, &ts) != 0) + continue; + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + int s; + pthread_cleanup_push (cl, NULL); + + s = wait (NULL); + + pthread_cleanup_pop (0); + + printf ("%s: wait returns with %d (%s)\n", __FUNCTION__, s, + strerror (errno)); + + exit (1); +} + + +static void * +tf_waitpid (void *arg) +{ + + pid_t pid = fork (); + if (pid == -1) + { + puts ("fork failed"); + exit (1); + } + + if (pid == 0) + { + /* Make the program disappear after a while. */ + if (arg == NULL) + sleep (10); + exit (0); + } + + int r; + if (arg != NULL) + { + struct timespec ts = { .tv_sec = 0, .tv_nsec = 100000000 }; + while (nanosleep (&ts, &ts) != 0) + continue; + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + int s; + pthread_cleanup_push (cl, NULL); + + s = waitpid (-1, NULL, 0); + + pthread_cleanup_pop (0); + + printf ("%s: waitpid returns with %d (%s)\n", __FUNCTION__, s, + strerror (errno)); + + exit (1); +} + + +static void * +tf_waitid (void *arg) +{ + pid_t pid = fork (); + if (pid == -1) + { + puts ("fork failed"); + exit (1); + } + + if (pid == 0) + { + /* Make the program disappear after a while. */ + if (arg == NULL) + sleep (10); + exit (0); + } + + int r; + if (arg != NULL) + { + struct timespec ts = { .tv_sec = 0, .tv_nsec = 100000000 }; + while (nanosleep (&ts, &ts) != 0) + continue; + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + int s; + pthread_cleanup_push (cl, NULL); + +#ifndef WEXITED +# define WEXITED 0 +#endif + siginfo_t si; + s = waitid (P_PID, pid, &si, WEXITED); + + pthread_cleanup_pop (0); + + printf ("%s: waitid returns with %d (%s)\n", __FUNCTION__, s, + strerror (errno)); + + exit (1); +} + + +static void * +tf_sigpause (void *arg) +{ + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + if (arg != NULL) + { + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + pthread_cleanup_push (cl, NULL); + + /* Just for fun block the cancellation signal. We need to use + __xpg_sigpause since otherwise we will get the BSD version. */ + __xpg_sigpause (SIGCANCEL); + + pthread_cleanup_pop (0); + + printf ("%s: sigpause returned\n", __FUNCTION__); + + exit (1); +} + + +static void * +tf_sigsuspend (void *arg) +{ + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + if (arg != NULL) + { + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + pthread_cleanup_push (cl, NULL); + + /* Just for fun block all signals. */ + sigset_t mask; + sigfillset (&mask); + sigsuspend (&mask); + + pthread_cleanup_pop (0); + + printf ("%s: sigsuspend returned\n", __FUNCTION__); + + exit (1); +} + + +static void * +tf_sigwait (void *arg) +{ + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + if (arg != NULL) + { + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + /* Block SIGUSR1. */ + sigset_t mask; + sigemptyset (&mask); + sigaddset (&mask, SIGUSR1); + if (pthread_sigmask (SIG_BLOCK, &mask, NULL) != 0) + { + printf ("%s: pthread_sigmask failed\n", __FUNCTION__); + exit (1); + } + + int sig; + pthread_cleanup_push (cl, NULL); + + /* Wait for SIGUSR1. */ + sigwait (&mask, &sig); + + pthread_cleanup_pop (0); + + printf ("%s: sigwait returned with signal %d\n", __FUNCTION__, sig); + + exit (1); +} + + +static void * +tf_sigwaitinfo (void *arg) +{ + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + if (arg != NULL) + { + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + /* Block SIGUSR1. */ + sigset_t mask; + sigemptyset (&mask); + sigaddset (&mask, SIGUSR1); + if (pthread_sigmask (SIG_BLOCK, &mask, NULL) != 0) + { + printf ("%s: pthread_sigmask failed\n", __FUNCTION__); + exit (1); + } + + siginfo_t info; + pthread_cleanup_push (cl, NULL); + + /* Wait for SIGUSR1. */ + sigwaitinfo (&mask, &info); + + pthread_cleanup_pop (0); + + printf ("%s: sigwaitinfo returned with signal %d\n", __FUNCTION__, + info.si_signo); + + exit (1); +} + + +static void * +tf_sigtimedwait (void *arg) +{ + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + if (arg != NULL) + { + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + /* Block SIGUSR1. */ + sigset_t mask; + sigemptyset (&mask); + sigaddset (&mask, SIGUSR1); + if (pthread_sigmask (SIG_BLOCK, &mask, NULL) != 0) + { + printf ("%s: pthread_sigmask failed\n", __FUNCTION__); + exit (1); + } + + /* Wait for SIGUSR1. */ + siginfo_t info; + struct timespec ts = { .tv_sec = 60, .tv_nsec = 0 }; + pthread_cleanup_push (cl, NULL); + + sigtimedwait (&mask, &info, &ts); + + pthread_cleanup_pop (0); + + printf ("%s: sigtimedwait returned with signal %d\n", __FUNCTION__, + info.si_signo); + + exit (1); +} + + +static void * +tf_pause (void *arg) +{ + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + if (arg != NULL) + { + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + pthread_cleanup_push (cl, NULL); + + pause (); + + pthread_cleanup_pop (0); + + printf ("%s: pause returned\n", __FUNCTION__); + + exit (1); +} + + +static void * +tf_accept (void *arg) +{ + struct sockaddr_un sun; + /* To test a non-blocking accept call we make the call file by using + a datagrame socket. */ + int pf = arg == NULL ? SOCK_STREAM : SOCK_DGRAM; + + tempfd = socket (AF_UNIX, pf, 0); + if (tempfd == -1) + { + printf ("%s: socket call failed\n", __FUNCTION__); + exit (1); + } + + int tries = 0; + do + { + if (++tries > 10) + { + printf ("%s: too many unsuccessful bind calls\n", __FUNCTION__); + } + + strcpy (sun.sun_path, "/tmp/tst-cancel4-socket-1-XXXXXX"); + if (mktemp (sun.sun_path) == NULL) + { + printf ("%s: cannot generate temp file name\n", __FUNCTION__); + exit (1); + } + + sun.sun_family = AF_UNIX; + } + while (bind (tempfd, (struct sockaddr *) &sun, + offsetof (struct sockaddr_un, sun_path) + + strlen (sun.sun_path) + 1) != 0); + + unlink (sun.sun_path); + + listen (tempfd, 5); + + socklen_t len = sizeof (sun); + + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + if (arg != NULL) + { + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + pthread_cleanup_push (cl, NULL); + + accept (tempfd, (struct sockaddr *) &sun, &len); + + pthread_cleanup_pop (0); + + printf ("%s: accept returned\n", __FUNCTION__); + + exit (1); +} + + +static void * +tf_send (void *arg) +{ + struct sockaddr_un sun; + + tempfd = socket (AF_UNIX, SOCK_STREAM, 0); + if (tempfd == -1) + { + printf ("%s: first socket call failed\n", __FUNCTION__); + exit (1); + } + + int tries = 0; + do + { + if (++tries > 10) + { + printf ("%s: too many unsuccessful bind calls\n", __FUNCTION__); + } + + strcpy (sun.sun_path, "/tmp/tst-cancel4-socket-2-XXXXXX"); + if (mktemp (sun.sun_path) == NULL) + { + printf ("%s: cannot generate temp file name\n", __FUNCTION__); + exit (1); + } + + sun.sun_family = AF_UNIX; + } + while (bind (tempfd, (struct sockaddr *) &sun, + offsetof (struct sockaddr_un, sun_path) + + strlen (sun.sun_path) + 1) != 0); + + listen (tempfd, 5); + + tempfd2 = socket (AF_UNIX, SOCK_STREAM, 0); + if (tempfd2 == -1) + { + printf ("%s: second socket call failed\n", __FUNCTION__); + exit (1); + } + + if (connect (tempfd2, (struct sockaddr *) &sun, sizeof (sun)) != 0) + { + printf ("%s: connect failed\n", __FUNCTION__); + exit(1); + } + + unlink (sun.sun_path); + + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + if (arg != NULL) + { + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + pthread_cleanup_push (cl, NULL); + + /* Very large block, so that the send call blocks. */ + char mem[700000]; + + send (tempfd2, mem, arg == NULL ? sizeof (mem) : 1, 0); + + pthread_cleanup_pop (0); + + printf ("%s: send returned\n", __FUNCTION__); + + exit (1); +} + + +static void * +tf_recv (void *arg) +{ + struct sockaddr_un sun; + + tempfd = socket (AF_UNIX, SOCK_STREAM, 0); + if (tempfd == -1) + { + printf ("%s: first socket call failed\n", __FUNCTION__); + exit (1); + } + + int tries = 0; + do + { + if (++tries > 10) + { + printf ("%s: too many unsuccessful bind calls\n", __FUNCTION__); + } + + strcpy (sun.sun_path, "/tmp/tst-cancel4-socket-3-XXXXXX"); + if (mktemp (sun.sun_path) == NULL) + { + printf ("%s: cannot generate temp file name\n", __FUNCTION__); + exit (1); + } + + sun.sun_family = AF_UNIX; + } + while (bind (tempfd, (struct sockaddr *) &sun, + offsetof (struct sockaddr_un, sun_path) + + strlen (sun.sun_path) + 1) != 0); + + listen (tempfd, 5); + + tempfd2 = socket (AF_UNIX, SOCK_STREAM, 0); + if (tempfd2 == -1) + { + printf ("%s: second socket call failed\n", __FUNCTION__); + exit (1); + } + + if (connect (tempfd2, (struct sockaddr *) &sun, sizeof (sun)) != 0) + { + printf ("%s: connect failed\n", __FUNCTION__); + exit(1); + } + + unlink (sun.sun_path); + + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + if (arg != NULL) + { + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + pthread_cleanup_push (cl, NULL); + + char mem[70]; + + recv (tempfd2, mem, arg == NULL ? sizeof (mem) : 0, 0); + + pthread_cleanup_pop (0); + + printf ("%s: recv returned\n", __FUNCTION__); + + exit (1); +} + + +static void * +tf_recvfrom (void *arg) +{ + struct sockaddr_un sun; + + tempfd = socket (AF_UNIX, SOCK_DGRAM, 0); + if (tempfd == -1) + { + printf ("%s: first socket call failed\n", __FUNCTION__); + exit (1); + } + + int tries = 0; + do + { + if (++tries > 10) + { + printf ("%s: too many unsuccessful bind calls\n", __FUNCTION__); + } + + strcpy (sun.sun_path, "/tmp/tst-cancel4-socket-4-XXXXXX"); + if (mktemp (sun.sun_path) == NULL) + { + printf ("%s: cannot generate temp file name\n", __FUNCTION__); + exit (1); + } + + sun.sun_family = AF_UNIX; + } + while (bind (tempfd, (struct sockaddr *) &sun, + offsetof (struct sockaddr_un, sun_path) + + strlen (sun.sun_path) + 1) != 0); + + tempfname = strdup (sun.sun_path); + + tempfd2 = socket (AF_UNIX, SOCK_DGRAM, 0); + if (tempfd2 == -1) + { + printf ("%s: second socket call failed\n", __FUNCTION__); + exit (1); + } + + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + if (arg != NULL) + { + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + pthread_cleanup_push (cl, NULL); + + char mem[70]; + socklen_t len = sizeof (sun); + + recvfrom (tempfd2, mem, arg == NULL ? sizeof (mem) : 0, 0, + (struct sockaddr *) &sun, &len); + + pthread_cleanup_pop (0); + + printf ("%s: recvfrom returned\n", __FUNCTION__); + + exit (1); +} + + +static void * +tf_recvmsg (void *arg) +{ + struct sockaddr_un sun; + + tempfd = socket (AF_UNIX, SOCK_DGRAM, 0); + if (tempfd == -1) + { + printf ("%s: first socket call failed\n", __FUNCTION__); + exit (1); + } + + int tries = 0; + do + { + if (++tries > 10) + { + printf ("%s: too many unsuccessful bind calls\n", __FUNCTION__); + } + + strcpy (sun.sun_path, "/tmp/tst-cancel4-socket-5-XXXXXX"); + if (mktemp (sun.sun_path) == NULL) + { + printf ("%s: cannot generate temp file name\n", __FUNCTION__); + exit (1); + } + + sun.sun_family = AF_UNIX; + } + while (bind (tempfd, (struct sockaddr *) &sun, + offsetof (struct sockaddr_un, sun_path) + + strlen (sun.sun_path) + 1) != 0); + + tempfname = strdup (sun.sun_path); + + tempfd2 = socket (AF_UNIX, SOCK_DGRAM, 0); + if (tempfd2 == -1) + { + printf ("%s: second socket call failed\n", __FUNCTION__); + exit (1); + } + + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + if (arg != NULL) + { + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + pthread_cleanup_push (cl, NULL); + + char mem[70]; + struct iovec iov[1]; + iov[0].iov_base = mem; + iov[0].iov_len = arg == NULL ? sizeof (mem) : 0; + + struct msghdr m; + m.msg_name = &sun; + m.msg_namelen = sizeof (sun); + m.msg_iov = iov; + m.msg_iovlen = 1; + m.msg_control = NULL; + m.msg_controllen = 0; + + recvmsg (tempfd2, &m, 0); + + pthread_cleanup_pop (0); + + printf ("%s: recvmsg returned\n", __FUNCTION__); + + exit (1); +} + + +static void * +tf_open (void *arg) +{ + if (arg == NULL) + // XXX If somebody can provide a portable test case in which open() + // blocks we can enable this test to run in both rounds. + abort (); + + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + pthread_cleanup_push (cl, NULL); + + open ("Makefile", O_RDONLY); + + pthread_cleanup_pop (0); + + printf ("%s: open returned\n", __FUNCTION__); + + exit (1); +} + + +static void * +tf_close (void *arg) +{ + if (arg == NULL) + // XXX If somebody can provide a portable test case in which close() + // blocks we can enable this test to run in both rounds. + abort (); + + char fname[] = "/tmp/tst-cancel-fd-XXXXXX"; + tempfd = mkstemp (fname); + if (tempfd == -1) + { + printf ("%s: mkstemp failed\n", __FUNCTION__); + exit (1); + } + unlink (fname); + + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + pthread_cleanup_push (cl, NULL); + + close (tempfd); + + pthread_cleanup_pop (0); + + printf ("%s: close returned\n", __FUNCTION__); + + exit (1); +} + + +static void * +tf_pread (void *arg) +{ + if (arg == NULL) + // XXX If somebody can provide a portable test case in which pread() + // blocks we can enable this test to run in both rounds. + abort (); + + tempfd = open ("Makefile", O_RDONLY); + if (tempfd == -1) + { + printf ("%s: cannot open Makefile\n", __FUNCTION__); + exit (1); + } + + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + pthread_cleanup_push (cl, NULL); + + char mem[10]; + pread (tempfd, mem, sizeof (mem), 0); + + pthread_cleanup_pop (0); + + printf ("%s: pread returned\n", __FUNCTION__); + + exit (1); +} + + +static void * +tf_pwrite (void *arg) +{ + if (arg == NULL) + // XXX If somebody can provide a portable test case in which pwrite() + // blocks we can enable this test to run in both rounds. + abort (); + + char fname[] = "/tmp/tst-cancel4-fd-XXXXXX"; + tempfd = mkstemp (fname); + if (tempfd == -1) + { + printf ("%s: mkstemp failed\n", __FUNCTION__); + exit (1); + } + unlink (fname); + + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + pthread_cleanup_push (cl, NULL); + + char mem[10]; + pwrite (tempfd, mem, sizeof (mem), 0); + + pthread_cleanup_pop (0); + + printf ("%s: pwrite returned\n", __FUNCTION__); + + exit (1); +} + + +static void * +tf_fsync (void *arg) +{ + if (arg == NULL) + // XXX If somebody can provide a portable test case in which fsync() + // blocks we can enable this test to run in both rounds. + abort (); + + tempfd = open ("Makefile", O_RDONLY); + if (tempfd == -1) + { + printf ("%s: cannot open Makefile\n", __FUNCTION__); + exit (1); + } + + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + pthread_cleanup_push (cl, NULL); + + fsync (tempfd); + + pthread_cleanup_pop (0); + + printf ("%s: fsync returned\n", __FUNCTION__); + + exit (1); +} + + +static void * +tf_fdatasync (void *arg) +{ + if (arg == NULL) + // XXX If somebody can provide a portable test case in which fdatasync() + // blocks we can enable this test to run in both rounds. + abort (); + + tempfd = open ("Makefile", O_RDONLY); + if (tempfd == -1) + { + printf ("%s: cannot open Makefile\n", __FUNCTION__); + exit (1); + } + + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + pthread_cleanup_push (cl, NULL); + + fdatasync (tempfd); + + pthread_cleanup_pop (0); + + printf ("%s: fdatasync returned\n", __FUNCTION__); + + exit (1); +} + + +static void * +tf_msync (void *arg) +{ + if (arg == NULL) + // XXX If somebody can provide a portable test case in which msync() + // blocks we can enable this test to run in both rounds. + abort (); + + tempfd = open ("Makefile", O_RDONLY); + if (tempfd == -1) + { + printf ("%s: cannot open Makefile\n", __FUNCTION__); + exit (1); + } + void *p = mmap (NULL, 10, PROT_READ, MAP_SHARED, tempfd, 0); + if (p == MAP_FAILED) + { + printf ("%s: mmap failed\n", __FUNCTION__); + exit (1); + } + + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + pthread_cleanup_push (cl, NULL); + + msync (p, 10, 0); + + pthread_cleanup_pop (0); + + printf ("%s: msync returned\n", __FUNCTION__); + + exit (1); +} + + +static void * +tf_sendto (void *arg) +{ + if (arg == NULL) + // XXX If somebody can provide a portable test case in which sendto() + // blocks we can enable this test to run in both rounds. + abort (); + + struct sockaddr_un sun; + + tempfd = socket (AF_UNIX, SOCK_DGRAM, 0); + if (tempfd == -1) + { + printf ("%s: first socket call failed\n", __FUNCTION__); + exit (1); + } + + int tries = 0; + do + { + if (++tries > 10) + { + printf ("%s: too many unsuccessful bind calls\n", __FUNCTION__); + } + + strcpy (sun.sun_path, "/tmp/tst-cancel4-socket-6-XXXXXX"); + if (mktemp (sun.sun_path) == NULL) + { + printf ("%s: cannot generate temp file name\n", __FUNCTION__); + exit (1); + } + + sun.sun_family = AF_UNIX; + } + while (bind (tempfd, (struct sockaddr *) &sun, + offsetof (struct sockaddr_un, sun_path) + + strlen (sun.sun_path) + 1) != 0); + tempfname = strdup (sun.sun_path); + + tempfd2 = socket (AF_UNIX, SOCK_DGRAM, 0); + if (tempfd2 == -1) + { + printf ("%s: second socket call failed\n", __FUNCTION__); + exit (1); + } + + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + pthread_cleanup_push (cl, NULL); + + char mem[1]; + + sendto (tempfd2, mem, arg == NULL ? sizeof (mem) : 1, 0, + (struct sockaddr *) &sun, + offsetof (struct sockaddr_un, sun_path) + strlen (sun.sun_path) + 1); + + pthread_cleanup_pop (0); + + printf ("%s: sendto returned\n", __FUNCTION__); + + exit (1); +} + + +static void * +tf_sendmsg (void *arg) +{ + if (arg == NULL) + // XXX If somebody can provide a portable test case in which sendmsg() + // blocks we can enable this test to run in both rounds. + abort (); + + struct sockaddr_un sun; + + tempfd = socket (AF_UNIX, SOCK_DGRAM, 0); + if (tempfd == -1) + { + printf ("%s: first socket call failed\n", __FUNCTION__); + exit (1); + } + + int tries = 0; + do + { + if (++tries > 10) + { + printf ("%s: too many unsuccessful bind calls\n", __FUNCTION__); + } + + strcpy (sun.sun_path, "/tmp/tst-cancel4-socket-7-XXXXXX"); + if (mktemp (sun.sun_path) == NULL) + { + printf ("%s: cannot generate temp file name\n", __FUNCTION__); + exit (1); + } + + sun.sun_family = AF_UNIX; + } + while (bind (tempfd, (struct sockaddr *) &sun, + offsetof (struct sockaddr_un, sun_path) + + strlen (sun.sun_path) + 1) != 0); + tempfname = strdup (sun.sun_path); + + tempfd2 = socket (AF_UNIX, SOCK_DGRAM, 0); + if (tempfd2 == -1) + { + printf ("%s: second socket call failed\n", __FUNCTION__); + exit (1); + } + + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + pthread_cleanup_push (cl, NULL); + + char mem[1]; + struct iovec iov[1]; + iov[0].iov_base = mem; + iov[0].iov_len = 1; + + struct msghdr m; + m.msg_name = &sun; + m.msg_namelen = (offsetof (struct sockaddr_un, sun_path) + + strlen (sun.sun_path) + 1); + m.msg_iov = iov; + m.msg_iovlen = 1; + m.msg_control = NULL; + m.msg_controllen = 0; + + sendmsg (tempfd2, &m, 0); + + pthread_cleanup_pop (0); + + printf ("%s: sendmsg returned\n", __FUNCTION__); + + exit (1); +} + + +static void * +tf_creat (void *arg) +{ + if (arg == NULL) + // XXX If somebody can provide a portable test case in which sendmsg() + // blocks we can enable this test to run in both rounds. + abort (); + + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + pthread_cleanup_push (cl, NULL); + + creat ("tmp/tst-cancel-4-should-not-exist", 0666); + + pthread_cleanup_pop (0); + + printf ("%s: creat returned\n", __FUNCTION__); + + exit (1); +} + + +static void * +tf_connect (void *arg) +{ + if (arg == NULL) + // XXX If somebody can provide a portable test case in which connect() + // blocks we can enable this test to run in both rounds. + abort (); + + struct sockaddr_un sun; + + tempfd = socket (AF_UNIX, SOCK_STREAM, 0); + if (tempfd == -1) + { + printf ("%s: first socket call failed\n", __FUNCTION__); + exit (1); + } + + int tries = 0; + do + { + if (++tries > 10) + { + printf ("%s: too many unsuccessful bind calls\n", __FUNCTION__); + } + + strcpy (sun.sun_path, "/tmp/tst-cancel4-socket-2-XXXXXX"); + if (mktemp (sun.sun_path) == NULL) + { + printf ("%s: cannot generate temp file name\n", __FUNCTION__); + exit (1); + } + + sun.sun_family = AF_UNIX; + } + while (bind (tempfd, (struct sockaddr *) &sun, + offsetof (struct sockaddr_un, sun_path) + + strlen (sun.sun_path) + 1) != 0); + tempfname = strdup (sun.sun_path); + + listen (tempfd, 5); + + tempfd2 = socket (AF_UNIX, SOCK_STREAM, 0); + if (tempfd2 == -1) + { + printf ("%s: second socket call failed\n", __FUNCTION__); + exit (1); + } + + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + if (arg != NULL) + { + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + pthread_cleanup_push (cl, NULL); + + connect (tempfd2, (struct sockaddr *) &sun, sizeof (sun)); + + pthread_cleanup_pop (0); + + printf ("%s: connect returned\n", __FUNCTION__); + + exit (1); +} + + +static void * +tf_tcdrain (void *arg) +{ + if (arg == NULL) + // XXX If somebody can provide a portable test case in which tcdrain() + // blocks we can enable this test to run in both rounds. + abort (); + + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + if (arg != NULL) + { + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + pthread_cleanup_push (cl, NULL); + + /* Regardless of stderr being a terminal, the tcdrain call should be + canceled. */ + tcdrain (STDERR_FILENO); + + pthread_cleanup_pop (0); + + printf ("%s: tcdrain returned\n", __FUNCTION__); + + exit (1); +} + + +static void * +tf_msgrcv (void *arg) +{ + tempmsg = msgget (IPC_PRIVATE, 0666 | IPC_CREAT); + if (tempmsg == -1) + { + printf ("%s: msgget failed: %s\n", __FUNCTION__, strerror (errno)); + exit (1); + } + + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + if (arg != NULL) + { + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + ssize_t s; + + pthread_cleanup_push (cl, NULL); + + struct + { + long int type; + char mem[10]; + } m; + int randnr; + /* We need a positive random number. */ + do + randnr = random () % 64000; + while (randnr <= 0); + do + { + errno = 0; + s = msgrcv (tempmsg, (struct msgbuf *) &m, 10, randnr, 0); + } + while (errno == EIDRM || errno == EINTR); + + pthread_cleanup_pop (0); + + printf ("%s: msgrcv returned %zd with errno = %m\n", __FUNCTION__, s); + + msgctl (tempmsg, IPC_RMID, NULL); + + exit (1); +} + + +static void * +tf_msgsnd (void *arg) +{ + if (arg == NULL) + // XXX If somebody can provide a portable test case in which msgsnd() + // blocks we can enable this test to run in both rounds. + abort (); + + tempmsg = msgget (IPC_PRIVATE, 0666 | IPC_CREAT); + if (tempmsg == -1) + { + printf ("%s: msgget failed: %s\n", __FUNCTION__, strerror (errno)); + exit (1); + } + + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + pthread_cleanup_push (cl, NULL); + + struct + { + long int type; + char mem[1]; + } m; + /* We need a positive random number. */ + do + m.type = random () % 64000; + while (m.type <= 0); + msgsnd (tempmsg, (struct msgbuf *) &m, sizeof (m.mem), 0); + + pthread_cleanup_pop (0); + + printf ("%s: msgsnd returned\n", __FUNCTION__); + + msgctl (tempmsg, IPC_RMID, NULL); + + exit (1); +} + + +static struct +{ + const char *name; + void *(*tf) (void *); + int nb; + int only_early; +} tests[] = +{ +#define ADD_TEST(name, nbar, early) { #name, tf_##name, nbar, early } + ADD_TEST (read, 2, 0), + ADD_TEST (readv, 2, 0), + ADD_TEST (select, 2, 0), + ADD_TEST (pselect, 2, 0), + ADD_TEST (poll, 2, 0), + ADD_TEST (ppoll, 2, 0), + ADD_TEST (write, 2, 0), + ADD_TEST (writev, 2, 0), + ADD_TEST (sleep, 2, 0), + ADD_TEST (usleep, 2, 0), + ADD_TEST (nanosleep, 2, 0), + ADD_TEST (wait, 2, 0), + ADD_TEST (waitid, 2, 0), + ADD_TEST (waitpid, 2, 0), + ADD_TEST (sigpause, 2, 0), + ADD_TEST (sigsuspend, 2, 0), + ADD_TEST (sigwait, 2, 0), + ADD_TEST (sigwaitinfo, 2, 0), + ADD_TEST (sigtimedwait, 2, 0), + ADD_TEST (pause, 2, 0), + ADD_TEST (accept, 2, 0), + ADD_TEST (send, 2, 0), + ADD_TEST (recv, 2, 0), + ADD_TEST (recvfrom, 2, 0), + ADD_TEST (recvmsg, 2, 0), + ADD_TEST (open, 2, 1), + ADD_TEST (close, 2, 1), + ADD_TEST (pread, 2, 1), + ADD_TEST (pwrite, 2, 1), + ADD_TEST (fsync, 2, 1), + ADD_TEST (fdatasync, 2, 1), + ADD_TEST (msync, 2, 1), + ADD_TEST (sendto, 2, 1), + ADD_TEST (sendmsg, 2, 1), + ADD_TEST (creat, 2, 1), + ADD_TEST (connect, 2, 1), + ADD_TEST (tcdrain, 2, 1), + ADD_TEST (msgrcv, 2, 0), + ADD_TEST (msgsnd, 2, 1), +}; +#define ntest_tf (sizeof (tests) / sizeof (tests[0])) + + +static int +do_test (void) +{ + int val; + socklen_t len; + +#ifdef __FreeBSD_kernel__ + if (socketpair (AF_UNIX, SOCK_STREAM, 0, fds) != 0) +#else + if (socketpair (AF_UNIX, SOCK_STREAM, PF_UNIX, fds) != 0) +#endif + { + perror ("socketpair"); + exit (1); + } + + val = 1; + len = sizeof(val); + setsockopt (fds[1], SOL_SOCKET, SO_SNDBUF, &val, sizeof(val)); + if (getsockopt (fds[1], SOL_SOCKET, SO_SNDBUF, &val, &len) < 0) + { + perror ("getsockopt"); + exit (1); + } + if (val >= WRITE_BUFFER_SIZE) + { + puts ("minimum write buffer size too large"); + exit (1); + } + setsockopt (fds[1], SOL_SOCKET, SO_SNDBUF, &val, sizeof(val)); + + int result = 0; + size_t cnt; + for (cnt = 0; cnt < ntest_tf; ++cnt) + { + if (tests[cnt].only_early) + continue; + + if (pthread_barrier_init (&b2, NULL, tests[cnt].nb) != 0) + { + puts ("b2 init failed"); + exit (1); + } + + /* Reset the counter for the cleanup handler. */ + cl_called = 0; + + pthread_t th; + if (pthread_create (&th, NULL, tests[cnt].tf, NULL) != 0) + { + printf ("create for '%s' test failed\n", tests[cnt].name); + result = 1; + continue; + } + + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + result = 1; + continue; + } + + struct timespec ts = { .tv_sec = 0, .tv_nsec = 100000000 }; + while (nanosleep (&ts, &ts) != 0) + continue; + + if (pthread_cancel (th) != 0) + { + printf ("cancel for '%s' failed\n", tests[cnt].name); + result = 1; + continue; + } + + void *status; + if (pthread_join (th, &status) != 0) + { + printf ("join for '%s' failed\n", tests[cnt].name); + result = 1; + continue; + } + if (status != PTHREAD_CANCELED) + { + printf ("thread for '%s' not canceled\n", tests[cnt].name); + result = 1; + continue; + } + + if (pthread_barrier_destroy (&b2) != 0) + { + puts ("barrier_destroy failed"); + result = 1; + continue; + } + + if (cl_called == 0) + { + printf ("cleanup handler not called for '%s'\n", tests[cnt].name); + result = 1; + continue; + } + if (cl_called > 1) + { + printf ("cleanup handler called more than once for '%s'\n", + tests[cnt].name); + result = 1; + continue; + } + + printf ("in-time cancel test of '%s' successful\n", tests[cnt].name); + + if (tempfd != -1) + { + close (tempfd); + tempfd = -1; + } + if (tempfd2 != -1) + { + close (tempfd2); + tempfd2 = -1; + } + if (tempfname != NULL) + { + unlink (tempfname); + free (tempfname); + tempfname = NULL; + } + if (tempmsg != -1) + { + msgctl (tempmsg, IPC_RMID, NULL); + tempmsg = -1; + } + } + + for (cnt = 0; cnt < ntest_tf; ++cnt) + { + if (pthread_barrier_init (&b2, NULL, tests[cnt].nb) != 0) + { + puts ("b2 init failed"); + exit (1); + } + + /* Reset the counter for the cleanup handler. */ + cl_called = 0; + + pthread_t th; + if (pthread_create (&th, NULL, tests[cnt].tf, (void *) 1l) != 0) + { + printf ("create for '%s' test failed\n", tests[cnt].name); + result = 1; + continue; + } + + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + result = 1; + continue; + } + + if (pthread_cancel (th) != 0) + { + printf ("cancel for '%s' failed\n", tests[cnt].name); + result = 1; + continue; + } + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + result = 1; + continue; + } + + void *status; + if (pthread_join (th, &status) != 0) + { + printf ("join for '%s' failed\n", tests[cnt].name); + result = 1; + continue; + } + if (status != PTHREAD_CANCELED) + { + printf ("thread for '%s' not canceled\n", tests[cnt].name); + result = 1; + continue; + } + + if (pthread_barrier_destroy (&b2) != 0) + { + puts ("barrier_destroy failed"); + result = 1; + continue; + } + + if (cl_called == 0) + { + printf ("cleanup handler not called for '%s'\n", tests[cnt].name); + result = 1; + continue; + } + if (cl_called > 1) + { + printf ("cleanup handler called more than once for '%s'\n", + tests[cnt].name); + result = 1; + continue; + } + + printf ("early cancel test of '%s' successful\n", tests[cnt].name); + + if (tempfd != -1) + { + close (tempfd); + tempfd = -1; + } + if (tempfd2 != -1) + { + close (tempfd2); + tempfd2 = -1; + } + if (tempfname != NULL) + { + unlink (tempfname); + free (tempfname); + tempfname = NULL; + } + if (tempmsg != -1) + { + msgctl (tempmsg, IPC_RMID, NULL); + tempmsg = -1; + } + } + + return result; +} + +#define TIMEOUT 60 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" --- /dev/null +++ b/fbtl/tst-cancel5.c @@ -0,0 +1 @@ +#include "tst-cancel4.c" --- /dev/null +++ b/fbtl/tst-cancel6.c @@ -0,0 +1,78 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-cancel7.c @@ -0,0 +1,210 @@ +/* Copyright (C) 2002-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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; +} + +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); +} + +#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" --- /dev/null +++ b/fbtl/tst-cancel8.c @@ -0,0 +1,142 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-cancel9.c @@ -0,0 +1,125 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-cancelx1.c @@ -0,0 +1 @@ +#include "tst-cancel1.c" --- /dev/null +++ b/fbtl/tst-cancelx10.c @@ -0,0 +1 @@ +#include "tst-cancel10.c" --- /dev/null +++ b/fbtl/tst-cancelx11.c @@ -0,0 +1 @@ +#include "tst-cancel11.c" --- /dev/null +++ b/fbtl/tst-cancelx12.c @@ -0,0 +1 @@ +#include "tst-cancel12.c" --- /dev/null +++ b/fbtl/tst-cancelx13.c @@ -0,0 +1 @@ +#include "tst-cancel13.c" --- /dev/null +++ b/fbtl/tst-cancelx14.c @@ -0,0 +1 @@ +#include "tst-cancel14.c" --- /dev/null +++ b/fbtl/tst-cancelx15.c @@ -0,0 +1 @@ +#include "tst-cancel15.c" --- /dev/null +++ b/fbtl/tst-cancelx16.c @@ -0,0 +1 @@ +#include "tst-cancel16.c" --- /dev/null +++ b/fbtl/tst-cancelx17.c @@ -0,0 +1 @@ +#include "tst-cancel17.c" --- /dev/null +++ b/fbtl/tst-cancelx18.c @@ -0,0 +1 @@ +#include "tst-cancel18.c" --- /dev/null +++ b/fbtl/tst-cancelx2.c @@ -0,0 +1 @@ +#include "tst-cancel2.c" --- /dev/null +++ b/fbtl/tst-cancelx20.c @@ -0,0 +1 @@ +#include "tst-cancel20.c" --- /dev/null +++ b/fbtl/tst-cancelx21.c @@ -0,0 +1 @@ +#include "tst-cancel21.c" --- /dev/null +++ b/fbtl/tst-cancelx3.c @@ -0,0 +1 @@ +#include "tst-cancel3.c" --- /dev/null +++ b/fbtl/tst-cancelx4.c @@ -0,0 +1 @@ +#include "tst-cancel4.c" --- /dev/null +++ b/fbtl/tst-cancelx5.c @@ -0,0 +1 @@ +#include "tst-cancel5.c" --- /dev/null +++ b/fbtl/tst-cancelx6.c @@ -0,0 +1 @@ +#include "tst-cancel6.c" --- /dev/null +++ b/fbtl/tst-cancelx7.c @@ -0,0 +1 @@ +#include "tst-cancel7.c" --- /dev/null +++ b/fbtl/tst-cancelx8.c @@ -0,0 +1 @@ +#include "tst-cancel8.c" --- /dev/null +++ b/fbtl/tst-cancelx9.c @@ -0,0 +1 @@ +#include "tst-cancel9.c" --- /dev/null +++ b/fbtl/tst-cleanup0.c @@ -0,0 +1,75 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-cleanup0.expect @@ -0,0 +1,3 @@ +ch (3) +ch (2) +ch (1) --- /dev/null +++ b/fbtl/tst-cleanup1.c @@ -0,0 +1,99 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-cleanup2.c @@ -0,0 +1,62 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-cleanup3.c @@ -0,0 +1,97 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-cleanup4.c @@ -0,0 +1,197 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-cleanup4aux.c @@ -0,0 +1,120 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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); +} --- /dev/null +++ b/fbtl/tst-cleanupx0.c @@ -0,0 +1 @@ +#include "tst-cleanup0.c" --- /dev/null +++ b/fbtl/tst-cleanupx0.expect @@ -0,0 +1,3 @@ +ch (3) +ch (2) +ch (1) --- /dev/null +++ b/fbtl/tst-cleanupx1.c @@ -0,0 +1 @@ +#include "tst-cleanup1.c" --- /dev/null +++ b/fbtl/tst-cleanupx2.c @@ -0,0 +1 @@ +#include "tst-cleanup2.c" --- /dev/null +++ b/fbtl/tst-cleanupx3.c @@ -0,0 +1 @@ +#include "tst-cleanup3.c" --- /dev/null +++ b/fbtl/tst-cleanupx4.c @@ -0,0 +1 @@ +#include "tst-cleanup4.c" --- /dev/null +++ b/fbtl/tst-clock1.c @@ -0,0 +1,50 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-clock2.c @@ -0,0 +1,201 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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 0; + } +# 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" --- /dev/null +++ b/fbtl/tst-cond-except.c @@ -0,0 +1,110 @@ +/* Verify that exception table for pthread_cond_wait is correct. + Copyright (C) 2012-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <pthread.h> +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <unistd.h> + +pthread_mutex_t mutex; +pthread_cond_t cond; + +#define CHECK_RETURN_VAL_OR_FAIL(ret,str) \ + ({ if ((ret) != 0) \ + { \ + printf ("%s failed: %s\n", (str), strerror (ret)); \ + ret = 1; \ + goto out; \ + } \ + }) + + +void +clean (void *arg) +{ + puts ("clean: Unlocking mutex..."); + pthread_mutex_unlock ((pthread_mutex_t *) arg); + puts ("clean: Mutex unlocked..."); +} + +void * +thr (void *arg) +{ + int ret = 0; + pthread_mutexattr_t mutexAttr; + ret = pthread_mutexattr_init (&mutexAttr); + CHECK_RETURN_VAL_OR_FAIL (ret, "pthread_mutexattr_init"); + + ret = pthread_mutexattr_setprotocol (&mutexAttr, PTHREAD_PRIO_INHERIT); + CHECK_RETURN_VAL_OR_FAIL (ret, "pthread_mutexattr_setprotocol"); + + ret = pthread_mutex_init (&mutex, &mutexAttr); + CHECK_RETURN_VAL_OR_FAIL (ret, "pthread_mutex_init"); + + ret = pthread_cond_init (&cond, 0); + CHECK_RETURN_VAL_OR_FAIL (ret, "pthread_cond_init"); + + puts ("th: Init done, entering wait..."); + + pthread_cleanup_push (clean, (void *) &mutex); + ret = pthread_mutex_lock (&mutex); + CHECK_RETURN_VAL_OR_FAIL (ret, "pthread_mutex_lock"); + while (1) + { + ret = pthread_cond_wait (&cond, &mutex); + CHECK_RETURN_VAL_OR_FAIL (ret, "pthread_cond_wait"); + } + pthread_cleanup_pop (1); + +out: + return (void *) (uintptr_t) ret; +} + +int +do_test (void) +{ + pthread_t thread; + int ret = 0; + void *thr_ret = 0; + ret = pthread_create (&thread, 0, thr, &thr_ret); + CHECK_RETURN_VAL_OR_FAIL (ret, "pthread_create"); + + puts ("main: Thread created, waiting a bit..."); + sleep (2); + + puts ("main: Cancelling thread..."); + ret = pthread_cancel (thread); + CHECK_RETURN_VAL_OR_FAIL (ret, "pthread_cancel"); + + puts ("main: Joining th..."); + ret = pthread_join (thread, NULL); + CHECK_RETURN_VAL_OR_FAIL (ret, "pthread_join"); + + if (thr_ret != NULL) + return 1; + + puts ("main: Joined thread, done!"); + +out: + return ret; +} + +#define TEST_FUNCTION do_test () +#define TIMEOUT 5 +#include "../test-skeleton.c" --- /dev/null +++ b/fbtl/tst-cond1.c @@ -0,0 +1,93 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-cond10.c @@ -0,0 +1,172 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-cond11.c @@ -0,0 +1,204 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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; + } + + struct timespec ts2; + if (clock_gettime (cl, &ts2) != 0) + { + puts ("second clock_gettime failed"); + return 1; + } + + if (ts2.tv_sec < ts.tv_sec + || (ts2.tv_sec == ts.tv_sec && ts2.tv_nsec < ts.tv_nsec)) + { + puts ("timeout too short"); + 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" --- /dev/null +++ b/fbtl/tst-cond12.c @@ -0,0 +1,195 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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; +} --- /dev/null +++ b/fbtl/tst-cond13.c @@ -0,0 +1,2 @@ +#define USE_COND_SIGNAL 1 +#include "tst-cond12.c" --- /dev/null +++ b/fbtl/tst-cond14.c @@ -0,0 +1,117 @@ +/* Copyright (C) 2004-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-cond15.c @@ -0,0 +1,159 @@ +/* Copyright (C) 2004-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-cond16.c @@ -0,0 +1,110 @@ +/* Copyright (C) 2004-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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]; + pthread_attr_t attr; + int i, ret, sz; + pthread_attr_init (&attr); + sz = __getpagesize (); + if (sz < PTHREAD_STACK_MIN) + sz = PTHREAD_STACK_MIN; + pthread_attr_setstacksize (&attr, sz); + for (i = 0; i < count; ++i) + if ((ret = pthread_create (&th[i], &attr, 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" --- /dev/null +++ b/fbtl/tst-cond17.c @@ -0,0 +1,2 @@ +#define UNLOCK_AFTER_BROADCAST 1 +#include "tst-cond16.c" --- /dev/null +++ b/fbtl/tst-cond18.c @@ -0,0 +1,122 @@ +/* Copyright (C) 2004-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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]; + pthread_attr_t attr; + int i, ret, sz; + pthread_attr_init (&attr); + sz = __getpagesize (); + if (sz < PTHREAD_STACK_MIN) + sz = PTHREAD_STACK_MIN; + pthread_attr_setstacksize (&attr, sz); + + for (i = 0; i <= count; ++i) + if ((ret = pthread_create (&th[i], &attr, 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" --- /dev/null +++ b/fbtl/tst-cond19.c @@ -0,0 +1,75 @@ +/* Copyright (C) 2004-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-cond2.c @@ -0,0 +1,162 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-cond20.c @@ -0,0 +1,169 @@ +/* Copyright (C) 2004-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-cond21.c @@ -0,0 +1,3 @@ +#include <sys/time.h> +#define TIMED 1 +#include "tst-cond20.c" --- /dev/null +++ b/fbtl/tst-cond22.c @@ -0,0 +1,160 @@ +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> + + +static pthread_barrier_t b; +static pthread_cond_t c = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; + + +static void +cl (void *arg) +{ + pthread_mutex_unlock (&m); +} + + +static void * +tf (void *arg) +{ + if (pthread_mutex_lock (&m) != 0) + { + printf ("%s: mutex_lock failed\n", __func__); + exit (1); + } + int e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __func__); + exit (1); + } + pthread_cleanup_push (cl, NULL); + /* We have to loop here because the cancellation might come after + the cond_wait call left the cancelable area and is then waiting + on the mutex. In this case the beginning of the second cond_wait + call will cause the cancellation to happen. */ + do + if (pthread_cond_wait (&c, &m) != 0) + { + printf ("%s: cond_wait failed\n", __func__); + exit (1); + } + while (arg == NULL); + pthread_cleanup_pop (0); + if (pthread_mutex_unlock (&m) != 0) + { + printf ("%s: mutex_unlock failed\n", __func__); + exit (1); + } + return NULL; +} + + +static int +do_test (void) +{ + int status = 0; + + 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 ("1st create failed"); + return 1; + } + int 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) + { + puts ("1st mutex_lock failed"); + return 1; + } + if (pthread_cond_signal (&c) != 0) + { + puts ("1st cond_signal failed"); + return 1; + } + if (pthread_cancel (th) != 0) + { + puts ("cancel failed"); + return 1; + } + if (pthread_mutex_unlock (&m) != 0) + { + puts ("1st mutex_unlock failed"); + return 1; + } + void *res; + if (pthread_join (th, &res) != 0) + { + puts ("1st join failed"); + return 1; + } + if (res != PTHREAD_CANCELED) + { + puts ("first thread not canceled"); + status = 1; + } + + printf ("cond = { %d, %x, %lld, %lld, %lld, %p, %u, %u }\n", + c.__data.__lock, c.__data.__futex, c.__data.__total_seq, + c.__data.__wakeup_seq, c.__data.__woken_seq, c.__data.__mutex, + c.__data.__nwaiters, c.__data.__broadcast_seq); + + if (pthread_create (&th, NULL, tf, (void *) 1l) != 0) + { + puts ("2nd create failed"); + return 1; + } + 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) + { + puts ("2nd mutex_lock failed"); + return 1; + } + if (pthread_cond_signal (&c) != 0) + { + puts ("2nd cond_signal failed"); + return 1; + } + if (pthread_mutex_unlock (&m) != 0) + { + puts ("2nd mutex_unlock failed"); + return 1; + } + if (pthread_join (th, &res) != 0) + { + puts ("2nd join failed"); + return 1; + } + if (res != NULL) + { + puts ("2nd thread canceled"); + status = 1; + } + + printf ("cond = { %d, %x, %lld, %lld, %lld, %p, %u, %u }\n", + c.__data.__lock, c.__data.__futex, c.__data.__total_seq, + c.__data.__wakeup_seq, c.__data.__woken_seq, c.__data.__mutex, + c.__data.__nwaiters, c.__data.__broadcast_seq); + + return status; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" --- /dev/null +++ b/fbtl/tst-cond23.c @@ -0,0 +1,183 @@ +/* Copyright (C) 2008-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2008. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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 +check (pthread_condattr_t *condattr, int pshared, clockid_t cl) +{ + 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; + } + + int p; + if (pthread_condattr_getpshared (condattr, &p) != 0) + { + puts ("condattr_getpshared failed"); + return 1; + } + else if (p != pshared) + { + printf ("condattr_getpshared returned wrong value: %d, expected %d\n", + p, pshared); + return 1; + } + + return 0; +} + +static int +run_test (clockid_t cl) +{ + pthread_condattr_t condattr; + + printf ("clock = %d\n", (int) cl); + + if (pthread_condattr_init (&condattr) != 0) + { + puts ("condattr_init failed"); + return 1; + } + + if (check (&condattr, PTHREAD_PROCESS_PRIVATE, CLOCK_REALTIME)) + return 1; + + if (pthread_condattr_setpshared (&condattr, PTHREAD_PROCESS_SHARED) != 0) + { + puts ("1st condattr_setpshared failed"); + return 1; + } + + if (check (&condattr, PTHREAD_PROCESS_SHARED, CLOCK_REALTIME)) + return 1; + + if (pthread_condattr_setclock (&condattr, cl) != 0) + { + puts ("1st condattr_setclock failed"); + return 1; + } + + if (check (&condattr, PTHREAD_PROCESS_SHARED, cl)) + return 1; + + if (pthread_condattr_setpshared (&condattr, PTHREAD_PROCESS_PRIVATE) != 0) + { + puts ("2nd condattr_setpshared failed"); + return 1; + } + + if (check (&condattr, PTHREAD_PROCESS_PRIVATE, cl)) + return 1; + + if (pthread_condattr_setclock (&condattr, CLOCK_REALTIME) != 0) + { + puts ("2nd condattr_setclock failed"); + return 1; + } + + if (check (&condattr, PTHREAD_PROCESS_PRIVATE, CLOCK_REALTIME)) + return 1; + + if (pthread_condattr_setclock (&condattr, cl) != 0) + { + puts ("3rd condattr_setclock failed"); + return 1; + } + + if (check (&condattr, PTHREAD_PROCESS_PRIVATE, cl)) + return 1; + + if (pthread_condattr_setpshared (&condattr, PTHREAD_PROCESS_SHARED) != 0) + { + puts ("3rd condattr_setpshared failed"); + return 1; + } + + if (check (&condattr, PTHREAD_PROCESS_SHARED, cl)) + return 1; + + if (pthread_condattr_setclock (&condattr, CLOCK_REALTIME) != 0) + { + puts ("4th condattr_setclock failed"); + return 1; + } + + if (check (&condattr, PTHREAD_PROCESS_SHARED, CLOCK_REALTIME)) + return 1; + + if (pthread_condattr_destroy (&condattr) != 0) + { + puts ("condattr_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 TEST_FUNCTION do_test () +#include "../test-skeleton.c" --- /dev/null +++ b/fbtl/tst-cond24.c @@ -0,0 +1,249 @@ +/* Verify that condition variables synchronized by PI mutexes don't hang. + Copyright (C) 2012-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/syscall.h> +#include <unistd.h> +#include <sys/time.h> +#include <time.h> + +#define THREADS_NUM 5 +#define MAXITER 50000 + +static pthread_mutex_t mutex; +static pthread_mutexattr_t mutex_attr; +static pthread_cond_t cond; +static pthread_t threads[THREADS_NUM]; +static int pending = 0; + +typedef void * (*threadfunc) (void *); + +void * +thread_fun_timed (void *arg) +{ + int *ret = arg; + int rv, i; + + printf ("Started thread_fun_timed[%d]\n", *ret); + + for (i = 0; i < MAXITER / THREADS_NUM; i++) + { + rv = pthread_mutex_lock (&mutex); + if (rv) + { + printf ("pthread_mutex_lock: %s(%d)\n", strerror (rv), rv); + *ret = 1; + goto out; + } + + while (!pending) + { + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + ts.tv_sec += 20; + rv = pthread_cond_timedwait (&cond, &mutex, &ts); + + /* There should be no timeout either. */ + if (rv) + { + printf ("pthread_cond_wait: %s(%d)\n", strerror (rv), rv); + *ret = 1; + goto out; + } + } + + pending--; + + rv = pthread_mutex_unlock (&mutex); + if (rv) + { + printf ("pthread_mutex_unlock: %s(%d)\n", strerror (rv), rv); + *ret = 1; + goto out; + } + } + + *ret = 0; + +out: + return ret; +} + +void * +thread_fun (void *arg) +{ + int *ret = arg; + int rv, i; + + printf ("Started thread_fun[%d]\n", *ret); + + for (i = 0; i < MAXITER / THREADS_NUM; i++) + { + rv = pthread_mutex_lock (&mutex); + if (rv) + { + printf ("pthread_mutex_lock: %s(%d)\n", strerror (rv), rv); + *ret = 1; + goto out; + } + + while (!pending) + { + rv = pthread_cond_wait (&cond, &mutex); + + if (rv) + { + printf ("pthread_cond_wait: %s(%d)\n", strerror (rv), rv); + *ret = 1; + goto out; + } + } + + pending--; + + rv = pthread_mutex_unlock (&mutex); + if (rv) + { + printf ("pthread_mutex_unlock: %s(%d)\n", strerror (rv), rv); + *ret = 1; + goto out; + } + } + + *ret = 0; + +out: + return ret; +} + +static int +do_test_wait (threadfunc f) +{ + int i; + int rv; + int counter = 0; + int retval[THREADS_NUM]; + + puts ("Starting test"); + + rv = pthread_mutexattr_init (&mutex_attr); + if (rv) + { + printf ("pthread_mutexattr_init: %s(%d)\n", strerror (rv), rv); + return 1; + } + + rv = pthread_mutexattr_setprotocol (&mutex_attr, PTHREAD_PRIO_INHERIT); + if (rv) + { + printf ("pthread_mutexattr_setprotocol: %s(%d)\n", strerror (rv), rv); + return 1; + } + + rv = pthread_mutex_init (&mutex, &mutex_attr); + if (rv) + { + printf ("pthread_mutex_init: %s(%d)\n", strerror (rv), rv); + return 1; + } + + rv = pthread_cond_init (&cond, NULL); + if (rv) + { + printf ("pthread_cond_init: %s(%d)\n", strerror (rv), rv); + return 1; + } + + for (i = 0; i < THREADS_NUM; i++) + { + retval[i] = i; + rv = pthread_create (&threads[i], NULL, f, &retval[i]); + if (rv) + { + printf ("pthread_create: %s(%d)\n", strerror (rv), rv); + return 1; + } + } + + for (; counter < MAXITER; counter++) + { + rv = pthread_mutex_lock (&mutex); + if (rv) + { + printf ("pthread_mutex_lock: %s(%d)\n", strerror (rv), rv); + return 1; + } + + if (!(counter % 100)) + printf ("counter: %d\n", counter); + pending += 1; + + rv = pthread_cond_signal (&cond); + if (rv) + { + printf ("pthread_cond_signal: %s(%d)\n", strerror (rv), rv); + return 1; + } + + rv = pthread_mutex_unlock (&mutex); + if (rv) + { + printf ("pthread_mutex_unlock: %s(%d)\n", strerror (rv), rv); + return 1; + } + } + + for (i = 0; i < THREADS_NUM; i++) + { + void *ret; + rv = pthread_join (threads[i], &ret); + if (rv) + { + printf ("pthread_join: %s(%d)\n", strerror (rv), rv); + return 1; + } + if (ret && *(int *)ret) + { + printf ("Thread %d returned with an error\n", i); + return 1; + } + } + + return 0; +} + +static int +do_test (void) +{ + puts ("Testing pthread_cond_wait"); + int ret = do_test_wait (thread_fun); + if (ret) + return ret; + + puts ("Testing pthread_cond_timedwait"); + return do_test_wait (thread_fun_timed); +} + +#define TIMEOUT 20 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" --- /dev/null +++ b/fbtl/tst-cond25.c @@ -0,0 +1,281 @@ +/* Verify that condition variables synchronized by PI mutexes don't hang on + on cancellation. + Copyright (C) 2012-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/syscall.h> +#include <unistd.h> +#include <sys/time.h> +#include <time.h> + +#define NUM 5 +#define ITERS 10000 +#define COUNT 100 + +typedef void *(*thr_func) (void *); + +pthread_mutex_t mutex; +pthread_cond_t cond; + +void cleanup (void *u) +{ + /* pthread_cond_wait should always return with the mutex locked. */ + if (pthread_mutex_unlock (&mutex)) + abort (); +} + +void * +signaller (void *u) +{ + int i, ret = 0; + void *tret = NULL; + + for (i = 0; i < ITERS; i++) + { + if ((ret = pthread_mutex_lock (&mutex)) != 0) + { + tret = (void *)1; + printf ("signaller:mutex_lock failed: %s\n", strerror (ret)); + goto out; + } + if ((ret = pthread_cond_signal (&cond)) != 0) + { + tret = (void *)1; + printf ("signaller:signal failed: %s\n", strerror (ret)); + goto unlock_out; + } + if ((ret = pthread_mutex_unlock (&mutex)) != 0) + { + tret = (void *)1; + printf ("signaller:mutex_unlock failed: %s\n", strerror (ret)); + goto out; + } + pthread_testcancel (); + } + +out: + return tret; + +unlock_out: + if ((ret = pthread_mutex_unlock (&mutex)) != 0) + printf ("signaller:mutex_unlock[2] failed: %s\n", strerror (ret)); + goto out; +} + +void * +waiter (void *u) +{ + int i, ret = 0; + void *tret = NULL; + int seq = (uintptr_t) u; + + for (i = 0; i < ITERS / NUM; i++) + { + if ((ret = pthread_mutex_lock (&mutex)) != 0) + { + tret = (void *) (uintptr_t) 1; + printf ("waiter[%u]:mutex_lock failed: %s\n", seq, strerror (ret)); + goto out; + } + pthread_cleanup_push (cleanup, NULL); + + if ((ret = pthread_cond_wait (&cond, &mutex)) != 0) + { + tret = (void *) (uintptr_t) 1; + printf ("waiter[%u]:wait failed: %s\n", seq, strerror (ret)); + goto unlock_out; + } + + if ((ret = pthread_mutex_unlock (&mutex)) != 0) + { + tret = (void *) (uintptr_t) 1; + printf ("waiter[%u]:mutex_unlock failed: %s\n", seq, strerror (ret)); + goto out; + } + pthread_cleanup_pop (0); + } + +out: + puts ("waiter tests done"); + return tret; + +unlock_out: + if ((ret = pthread_mutex_unlock (&mutex)) != 0) + printf ("waiter:mutex_unlock[2] failed: %s\n", strerror (ret)); + goto out; +} + +void * +timed_waiter (void *u) +{ + int i, ret; + void *tret = NULL; + int seq = (uintptr_t) u; + + for (i = 0; i < ITERS / NUM; i++) + { + struct timespec ts; + + if ((ret = clock_gettime(CLOCK_REALTIME, &ts)) != 0) + { + tret = (void *) (uintptr_t) 1; + printf ("%u:clock_gettime failed: %s\n", seq, strerror (errno)); + goto out; + } + ts.tv_sec += 20; + + if ((ret = pthread_mutex_lock (&mutex)) != 0) + { + tret = (void *) (uintptr_t) 1; + printf ("waiter[%u]:mutex_lock failed: %s\n", seq, strerror (ret)); + goto out; + } + pthread_cleanup_push (cleanup, NULL); + + /* We should not time out either. */ + if ((ret = pthread_cond_timedwait (&cond, &mutex, &ts)) != 0) + { + tret = (void *) (uintptr_t) 1; + printf ("waiter[%u]:timedwait failed: %s\n", seq, strerror (ret)); + goto unlock_out; + } + if ((ret = pthread_mutex_unlock (&mutex)) != 0) + { + tret = (void *) (uintptr_t) 1; + printf ("waiter[%u]:mutex_unlock failed: %s\n", seq, strerror (ret)); + goto out; + } + pthread_cleanup_pop (0); + } + +out: + puts ("timed_waiter tests done"); + return tret; + +unlock_out: + if ((ret = pthread_mutex_unlock (&mutex)) != 0) + printf ("waiter[%u]:mutex_unlock[2] failed: %s\n", seq, strerror (ret)); + goto out; +} + +int +do_test_wait (thr_func f) +{ + pthread_t w[NUM]; + pthread_t s; + pthread_mutexattr_t attr; + int i, j, ret = 0; + void *thr_ret; + + for (i = 0; i < COUNT; i++) + { + if ((ret = pthread_mutexattr_init (&attr)) != 0) + { + printf ("mutexattr_init failed: %s\n", strerror (ret)); + goto out; + } + + if ((ret = pthread_mutexattr_setprotocol (&attr, + PTHREAD_PRIO_INHERIT)) != 0) + { + printf ("mutexattr_setprotocol failed: %s\n", strerror (ret)); + goto out; + } + + if ((ret = pthread_cond_init (&cond, NULL)) != 0) + { + printf ("cond_init failed: %s\n", strerror (ret)); + goto out; + } + + if ((ret = pthread_mutex_init (&mutex, &attr)) != 0) + { + printf ("mutex_init failed: %s\n", strerror (ret)); + goto out; + } + + for (j = 0; j < NUM; j++) + if ((ret = pthread_create (&w[j], NULL, + f, (void *) (uintptr_t) j)) != 0) + { + printf ("waiter[%d]: create failed: %s\n", j, strerror (ret)); + goto out; + } + + if ((ret = pthread_create (&s, NULL, signaller, NULL)) != 0) + { + printf ("signaller: create failed: %s\n", strerror (ret)); + goto out; + } + + for (j = 0; j < NUM; j++) + { + pthread_cancel (w[j]); + + if ((ret = pthread_join (w[j], &thr_ret)) != 0) + { + printf ("waiter[%d]: join failed: %s\n", j, strerror (ret)); + goto out; + } + + if (thr_ret != NULL && thr_ret != PTHREAD_CANCELED) + { + ret = 1; + goto out; + } + } + + /* The signalling thread could have ended before it was cancelled. */ + pthread_cancel (s); + + if ((ret = pthread_join (s, &thr_ret)) != 0) + { + printf ("signaller: join failed: %s\n", strerror (ret)); + goto out; + } + + if (thr_ret != NULL && thr_ret != PTHREAD_CANCELED) + { + ret = 1; + goto out; + } + } + +out: + return ret; +} + +int +do_test (int argc, char **argv) +{ + int ret = do_test_wait (waiter); + + if (ret) + return ret; + + return do_test_wait (timed_waiter); +} + +#define TIMEOUT 5 +#include "../test-skeleton.c" --- /dev/null +++ b/fbtl/tst-cond3.c @@ -0,0 +1,111 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +static int do_test (void); + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" + +/* 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. */ + xpthread_cond_wait (&cond, &mut); + puts ("error: pthread_cond_wait in tf returned"); + + /* 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; + } + } + + delayed_exit (1); + + /* This call should never return. */ + xpthread_cond_wait (&cond, &mut); + + puts ("error: pthread_cond_wait in do_test returned"); + return 1; +} --- /dev/null +++ b/fbtl/tst-cond4.c @@ -0,0 +1,262 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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> + + +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" --- /dev/null +++ b/fbtl/tst-cond5.c @@ -0,0 +1,105 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-cond6.c @@ -0,0 +1,232 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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> + + +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" --- /dev/null +++ b/fbtl/tst-cond7.c @@ -0,0 +1,167 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-cond8-static.c @@ -0,0 +1 @@ +#include "tst-cond8.c" --- /dev/null +++ b/fbtl/tst-cond8.c @@ -0,0 +1,276 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-cond9.c @@ -0,0 +1,149 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-context1.c @@ -0,0 +1,205 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <error.h> +#include <limits.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <ucontext.h> + +#define N 4 +#if __WORDSIZE == 64 +#define GUARD_PATTERN 0xdeadbeafdeadbeaf +#else +#define GUARD_PATTERN 0xdeadbeaf +#endif + +typedef struct { + ucontext_t uctx; + unsigned long guard[3]; + } tst_context_t; + +static char stacks[N][2 * PTHREAD_STACK_MIN]; +static tst_context_t ctx[N][2]; +static volatile int failures; + + +static void +fct (long int n) +{ + char on_stack[1]; + + /* Just to use the thread local descriptor. */ + printf ("%ld: in %s now, on_stack = %p\n", n, __FUNCTION__, on_stack); + errno = 0; + + if (ctx[n][1].uctx.uc_link != &ctx[n][0].uctx) + { + printf ("context[%ld][1] uc_link damaged, = %p\n", n, + ctx[n][1].uctx.uc_link); + exit (1); + } + + if ((ctx[n][0].guard[0] != GUARD_PATTERN) + || (ctx[n][0].guard[1] != GUARD_PATTERN) + || (ctx[n][0].guard[2] != GUARD_PATTERN)) + { + printf ("%ld: %s context[0] overflow detected!\n", n, __FUNCTION__); + ++failures; + } + + if ((ctx[n][1].guard[0] != GUARD_PATTERN) + || (ctx[n][1].guard[1] != GUARD_PATTERN) + || (ctx[n][1].guard[2] != GUARD_PATTERN)) + { + printf ("%ld: %s context[1] overflow detected!\n", n, __FUNCTION__); + ++failures; + } + + if (n < 0 || n >= N) + { + printf ("%ld out of range\n", n); + exit (1); + } + + if (on_stack < stacks[n] || on_stack >= stacks[n] + sizeof (stacks[0])) + { + printf ("%ld: on_stack not on appropriate stack\n", n); + exit (1); + } +} + + +static void * +tf (void *arg) +{ + int n = (int) (long int) arg; + + ctx[n][0].guard[0] = GUARD_PATTERN; + ctx[n][0].guard[1] = GUARD_PATTERN; + ctx[n][0].guard[2] = GUARD_PATTERN; + + ctx[n][1].guard[0] = GUARD_PATTERN; + ctx[n][1].guard[1] = GUARD_PATTERN; + ctx[n][1].guard[2] = GUARD_PATTERN; + + if (getcontext (&ctx[n][1].uctx) != 0) + { + printf ("%d: cannot get context: %m\n", n); + exit (1); + } + + printf ("%d: %s: before makecontext\n", n, __FUNCTION__); + + ctx[n][1].uctx.uc_stack.ss_sp = stacks[n]; + ctx[n][1].uctx.uc_stack.ss_size = sizeof (stacks[n]); + ctx[n][1].uctx.uc_link = &ctx[n][0].uctx; + makecontext (&ctx[n][1].uctx, (void (*) (void)) fct, 1, (long int) n); + + printf ("%d: %s: before swapcontext\n", n, __FUNCTION__); + + if (swapcontext (&ctx[n][0].uctx, &ctx[n][1].uctx) != 0) + { + ++failures; + printf ("%d: %s: swapcontext failed\n", n, __FUNCTION__); + } + else + printf ("%d: back in %s\n", n, __FUNCTION__); + + return NULL; +} + + +static volatile int global; + + +static int +do_test (void) +{ + int n; + pthread_t th[N]; + ucontext_t mctx; + + puts ("making contexts"); + if (getcontext (&mctx) != 0) + { + if (errno == ENOSYS) + { + puts ("context handling not supported"); + exit (0); + } + + printf ("%s: getcontext: %m\n", __FUNCTION__); + exit (1); + } + + /* Play some tricks with this context. */ + if (++global == 1) + if (setcontext (&mctx) != 0) + { + puts ("setcontext failed"); + exit (1); + } + if (global != 2) + { + puts ("global not incremented twice"); + exit (1); + } + puts ("global OK"); + + 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 (n = 0; n < N; ++n) + if (pthread_create (&th[n], &at, tf, (void *) (long int) n) != 0) + { + puts ("create failed"); + exit (1); + } + + if (pthread_attr_destroy (&at) != 0) + { + puts ("attr_destroy failed"); + return 1; + } + + for (n = 0; n < N; ++n) + if (pthread_join (th[n], NULL) != 0) + { + puts ("join failed"); + exit (1); + } + + return failures; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" --- /dev/null +++ b/fbtl/tst-default-attr.c @@ -0,0 +1,385 @@ +/* Verify that pthread_[gs]etattr_default_np work correctly. + + Copyright (C) 2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <pthread.h> +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <stdbool.h> + +#define RETURN_IF_FAIL(f, ...) \ + ({ \ + int ret = f (__VA_ARGS__); \ + if (ret != 0) \ + { \ + printf ("%s:%d: %s returned %d (errno = %d)\n", __FILE__, __LINE__, \ + #f, ret, errno); \ + return ret; \ + } \ + }) + +static int (*verify_result) (pthread_attr_t *); +static size_t stacksize = 1024 * 1024; +static size_t guardsize; +static bool do_join = true; +static int running = 0; +static int detach_failed = 0; +static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t c = PTHREAD_COND_INITIALIZER; + +static void * +thr (void *unused __attribute__ ((unused))) +{ + pthread_attr_t attr; + int ret; + + memset (&attr, 0xab, sizeof attr); + /* To verify that the pthread_setattr_default_np worked. */ + if ((ret = pthread_getattr_default_np (&attr)) != 0) + { + printf ("pthread_getattr_default_np failed: %s\n", strerror (ret)); + goto out; + } + + if ((ret = (*verify_result) (&attr)) != 0) + goto out; + + memset (&attr, 0xab, sizeof attr); + /* To verify that the attributes actually got applied. */ + if ((ret = pthread_getattr_np (pthread_self (), &attr)) != 0) + { + printf ("pthread_getattr_default_np failed: %s\n", strerror (ret)); + goto out; + } + + ret = (*verify_result) (&attr); + +out: + if (!do_join) + { + pthread_mutex_lock (&m); + running--; + pthread_cond_signal (&c); + pthread_mutex_unlock (&m); + + detach_failed |= ret; + } + + return (void *) (uintptr_t) ret; +} + +static int +run_threads (const pthread_attr_t *attr) +{ + pthread_t t; + void *tret = NULL; + + RETURN_IF_FAIL (pthread_setattr_default_np, attr); + + /* Run twice to ensure that the attributes do not get overwritten in the + first run somehow. */ + for (int i = 0; i < 2; i++) + { + RETURN_IF_FAIL (pthread_create, &t, NULL, thr, NULL); + if (do_join) + RETURN_IF_FAIL (pthread_join, t, &tret); + else + { + pthread_mutex_lock (&m); + running++; + pthread_mutex_unlock (&m); + } + + if (tret != NULL) + { + puts ("Thread failed"); + return 1; + } + } + + /* Stay in sync for detached threads and get their status. */ + while (!do_join) + { + pthread_mutex_lock (&m); + if (running == 0) + { + pthread_mutex_unlock (&m); + break; + } + pthread_cond_wait (&c, &m); + pthread_mutex_unlock (&m); + } + + return 0; +} + +static int +verify_detach_result (pthread_attr_t *attr) +{ + int state; + + RETURN_IF_FAIL (pthread_attr_getdetachstate, attr, &state); + + if (state != PTHREAD_CREATE_DETACHED) + { + puts ("failed to set detach state"); + return 1; + } + + return 0; +} + +static int +do_detach_test (void) +{ + pthread_attr_t attr; + + do_join = false; + RETURN_IF_FAIL (pthread_attr_init, &attr); + RETURN_IF_FAIL (pthread_attr_setdetachstate, &attr, PTHREAD_CREATE_DETACHED); + + RETURN_IF_FAIL (run_threads, &attr); + return detach_failed; +} + +static int +verify_affinity_result (pthread_attr_t *attr) +{ + cpu_set_t cpuset; + + RETURN_IF_FAIL (pthread_attr_getaffinity_np, attr, sizeof (cpuset), &cpuset); + if (!CPU_ISSET (0, &cpuset)) + { + puts ("failed to set cpu affinity"); + return 1; + } + + return 0; +} + +static int +do_affinity_test (void) +{ + pthread_attr_t attr; + + RETURN_IF_FAIL (pthread_attr_init, &attr); + + /* Processor affinity. Like scheduling policy, this could fail if the user + does not have the necessary privileges. So we only spew a warning if + pthread_create fails with EPERM. A computer has at least one CPU. */ + cpu_set_t cpuset; + CPU_ZERO (&cpuset); + CPU_SET (0, &cpuset); + RETURN_IF_FAIL (pthread_attr_setaffinity_np, &attr, sizeof (cpuset), &cpuset); + + int ret = run_threads (&attr); + + if (ret == EPERM) + { + printf ("Skipping CPU Affinity test: %s\n", strerror (ret)); + return 0; + } + else if (ret != 0) + return ret; + + return 0; +} + +static int +verify_sched_result (pthread_attr_t *attr) +{ + int inherited, policy; + struct sched_param param; + + RETURN_IF_FAIL (pthread_attr_getinheritsched, attr, &inherited); + if (inherited != PTHREAD_EXPLICIT_SCHED) + { + puts ("failed to set EXPLICIT_SCHED (%d != %d)"); + return 1; + } + + RETURN_IF_FAIL (pthread_attr_getschedpolicy, attr, &policy); + if (policy != SCHED_RR) + { + printf ("failed to set SCHED_RR (%d != %d)\n", policy, SCHED_RR); + return 1; + } + + RETURN_IF_FAIL (pthread_attr_getschedparam, attr, ¶m); + if (param.sched_priority != 42) + { + printf ("failed to set sched_priority (%d != %d)\n", + param.sched_priority, 42); + return 1; + } + + return 0; +} + +static int +do_sched_test (void) +{ + pthread_attr_t attr; + + RETURN_IF_FAIL (pthread_attr_init, &attr); + + /* Scheduling policy. Note that we don't always test these since it's + possible that the user the tests run as don't have the appropriate + privileges. */ + RETURN_IF_FAIL (pthread_attr_setinheritsched, &attr, PTHREAD_EXPLICIT_SCHED); + RETURN_IF_FAIL (pthread_attr_setschedpolicy, &attr, SCHED_RR); + + struct sched_param param; + param.sched_priority = 42; + RETURN_IF_FAIL (pthread_attr_setschedparam, &attr, ¶m); + + int ret = run_threads (&attr); + + if (ret == EPERM) + { + printf ("Skipping Scheduler Attributes test: %s\n", strerror (ret)); + return 0; + } + else if (ret != 0) + return ret; + + return 0; +} + +static int +verify_guardsize_result (pthread_attr_t *attr) +{ + size_t guard; + + RETURN_IF_FAIL (pthread_attr_getguardsize, attr, &guard); + + if (guardsize != guard) + { + printf ("failed to set guardsize (%zu, %zu)\n", guardsize, guard); + return 1; + } + + return 0; +} + +static int +do_guardsize_test (void) +{ + long int pagesize = sysconf (_SC_PAGESIZE); + pthread_attr_t attr; + + if (pagesize < 0) + { + printf ("sysconf failed: %s\n", strerror (errno)); + return 1; + } + + RETURN_IF_FAIL (pthread_getattr_default_np, &attr); + + /* Increase default guardsize by a page. */ + RETURN_IF_FAIL (pthread_attr_getguardsize, &attr, &guardsize); + guardsize += pagesize; + RETURN_IF_FAIL (pthread_attr_setguardsize, &attr, guardsize); + RETURN_IF_FAIL (run_threads, &attr); + + return 0; +} + +static int +verify_stacksize_result (pthread_attr_t *attr) +{ + size_t stack; + + RETURN_IF_FAIL (pthread_attr_getstacksize, attr, &stack); + + if (stacksize != stack) + { + printf ("failed to set default stacksize (%zu, %zu)\n", stacksize, stack); + return 1; + } + + return 0; +} + +static int +do_stacksize_test (void) +{ + long int pagesize = sysconf (_SC_PAGESIZE); + pthread_attr_t attr; + + if (pagesize < 0) + { + printf ("sysconf failed: %s\n", strerror (errno)); + return 1; + } + + /* Perturb the size by a page so that we're not aligned on the 64K boundary. + pthread_create does this perturbation on x86 to avoid causing the 64k + aliasing conflict. We want to prevent pthread_create from doing that + since it is not consistent for all architectures. */ + stacksize += pagesize; + + RETURN_IF_FAIL (pthread_attr_init, &attr); + + /* Run twice to ensure that we don't give a false positive. */ + RETURN_IF_FAIL (pthread_attr_setstacksize, &attr, stacksize); + RETURN_IF_FAIL (run_threads, &attr); + stacksize *= 2; + RETURN_IF_FAIL (pthread_attr_setstacksize, &attr, stacksize); + RETURN_IF_FAIL (run_threads, &attr); + return 0; +} + +/* We test each attribute separately because sched and affinity tests may need + additional user privileges that may not be available during the test run. + Each attribute test is a set of two functions, viz. a function to set the + default attribute (do_foo_test) and another to verify its result + (verify_foo_result). Each test spawns a thread and checks (1) if the + attribute values were applied correctly and (2) if the change in the default + value reflected. */ +static int +do_test (void) +{ + puts ("stacksize test"); + verify_result = verify_stacksize_result; + RETURN_IF_FAIL (do_stacksize_test); + + puts ("guardsize test"); + verify_result = verify_guardsize_result; + RETURN_IF_FAIL (do_guardsize_test); + + puts ("sched test"); + verify_result = verify_sched_result; + RETURN_IF_FAIL (do_sched_test); + + puts ("affinity test"); + verify_result = verify_affinity_result; + RETURN_IF_FAIL (do_affinity_test); + + puts ("detach test"); + verify_result = verify_detach_result; + RETURN_IF_FAIL (do_detach_test); + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" --- /dev/null +++ b/fbtl/tst-detach1.c @@ -0,0 +1,55 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-dlsym1.c @@ -0,0 +1,66 @@ +/* Test case by Hui Huang <hui.huang@sun.com>. */ +#include <dlfcn.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> + + +static void * +start_routine (void *args) +{ + int i; + void **addrs = (void **) args; + for (i = 0; i < 10000; ++i) + addrs[i % 1024] = dlsym (NULL, "does_not_exist"); + + return addrs; +} + + +static int +do_test (void) +{ + pthread_t tid1, tid2, tid3; + + void *addrs1[1024]; + void *addrs2[1024]; + void *addrs3[1024]; + + if (pthread_create (&tid1, NULL, start_routine, addrs1) != 0) + { + puts ("1st create failed"); + exit (1); + } + if (pthread_create (&tid2, NULL, start_routine, addrs2) != 0) + { + puts ("2nd create failed"); + exit (1); + } + if (pthread_create (&tid3, NULL, start_routine, addrs3) != 0) + { + puts ("3rd create failed"); + exit (1); + } + + if (pthread_join (tid1, NULL) != 0) + { + puts ("1st join failed"); + exit (1); + } + if (pthread_join (tid2, NULL) != 0) + { + puts ("2nd join failed"); + exit (1); + } + if (pthread_join (tid3, NULL) != 0) + { + puts ("2rd join failed"); + exit (1); + } + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" --- /dev/null +++ b/fbtl/tst-eintr1.c @@ -0,0 +1,104 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +static int do_test (void); + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" + +#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); + } + } + + delayed_exit (3); + /* This call must never return. */ + (void) tf1 (NULL); + return 1; +} --- /dev/null +++ b/fbtl/tst-eintr2.c @@ -0,0 +1,118 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/time.h> + +static int do_test (void); + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" + +#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); + } + + delayed_exit (3); + /* This call must never return. */ + e = pthread_mutex_lock (&m1); + printf ("main: mutex_lock returned: %s\n", + strerror_r (e, buf, sizeof (buf))); + + return 1; +} --- /dev/null +++ b/fbtl/tst-eintr3.c @@ -0,0 +1,69 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +static int do_test (void); + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" + +#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); + } + + delayed_exit (1); + /* This call must never return. */ + xpthread_join (th); + puts ("error: pthread_join returned"); + return 1; +} --- /dev/null +++ b/fbtl/tst-eintr4.c @@ -0,0 +1,53 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +static int do_test (void); + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" + +#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); + } + + delayed_exit (1); + /* This call must never return. */ + xpthread_barrier_wait (&b); + puts ("error: pthread_barrier_wait returned"); + return 1; +} --- /dev/null +++ b/fbtl/tst-eintr5.c @@ -0,0 +1,79 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/time.h> + +static int do_test (void); + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" + +#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); + } + + delayed_exit (3); + /* This call must never return. */ + xpthread_cond_wait (&c, &m); + puts ("error: pthread_cond_wait returned"); + return 1; +} --- /dev/null +++ b/fbtl/tst-exec1.c @@ -0,0 +1,159 @@ +/* Simple exec test, only a thread in the parent. + Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <paths.h> +#include <pthread.h> +#include <signal.h> +#include <spawn.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); + } + + posix_spawn_file_actions_t a; + if (posix_spawn_file_actions_init (&a) != 0) + { + puts ("spawn_file_actions_init failed"); + exit (1); + } + + if (posix_spawn_file_actions_adddup2 (&a, fd[1], STDOUT_FILENO) != 0) + { + puts ("spawn_file_actions_adddup2 failed"); + exit (1); + } + + if (posix_spawn_file_actions_addclose (&a, fd[0]) != 0) + { + puts ("spawn_file_actions_addclose"); + exit (1); + } + + pthread_t th; + if (pthread_create (&th, NULL, tf, (void *) pthread_self ()) != 0) + { + puts ("create failed"); + exit (1); + } + + pid_t pid; + char *argv[] = { (char *) _PATH_BSHELL, (char *) "-c", (char *) "echo $$", + NULL }; + if (posix_spawn (&pid, _PATH_BSHELL, &a, NULL, argv, NULL) != 0) + { + puts ("spawn 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); + } + + puts ("read correct PID"); + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" --- /dev/null +++ b/fbtl/tst-exec2.c @@ -0,0 +1,154 @@ +/* Thread with running thread calls exec. + Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <paths.h> +#include <pthread.h> +#include <signal.h> +#include <spawn.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" --- /dev/null +++ b/fbtl/tst-exec3.c @@ -0,0 +1,152 @@ +/* Thread calls exec. + Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <paths.h> +#include <pthread.h> +#include <signal.h> +#include <spawn.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" --- /dev/null +++ b/fbtl/tst-exec4.c @@ -0,0 +1,115 @@ +/* Signal handler and mask set in thread which calls exec. + Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-execstack-mod.c @@ -0,0 +1 @@ +#include "../elf/tst-execstack-mod.c" --- /dev/null +++ b/fbtl/tst-execstack.c @@ -0,0 +1,2 @@ +#define USE_PTHREADS 1 +#include "../elf/tst-execstack.c" --- /dev/null +++ b/fbtl/tst-exit1.c @@ -0,0 +1,78 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +/* 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" --- /dev/null +++ b/fbtl/tst-exit2.c @@ -0,0 +1,42 @@ +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +static int do_test (void); + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" + +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; + } + + delayed_exit (1); + + /* Terminate only this thread. */ + pthread_exit (NULL); + + /* NOTREACHED */ + return 1; +} --- /dev/null +++ b/fbtl/tst-exit3.c @@ -0,0 +1,83 @@ +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +static int do_test (void); + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" + +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); + } + + delayed_exit (3); + + /* Terminate only this thread. */ + pthread_exit (NULL); + + /* NOTREACHED */ + return 1; +} --- /dev/null +++ b/fbtl/tst-fini1.c @@ -0,0 +1,34 @@ +/* Copyright (C) 2004-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#include <unistd.h> + +extern void m (void); + +int +main (void) +{ + alarm (5); + + m (); + + /* The destructor is supposed to run now. Make sure that if it is + not we will notice it by using 42 as the exit code. In case the + destructor is run it will terminate with status zero. */ + return 42; +} --- /dev/null +++ b/fbtl/tst-fini1mod.c @@ -0,0 +1,71 @@ +/* Copyright (C) 2004-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + + +static void * +tf (void *arg) +{ + int fds[2]; + if (pipe (fds) != 0) + { + puts ("pipe failed"); + exit (1); + } + + char buf[10]; + read (fds[0], buf, sizeof (buf)); + + puts ("read returned"); + exit (1); +} + +static pthread_t th; + +static void +__attribute ((destructor)) +dest (void) +{ + if (pthread_cancel (th) != 0) + { + puts ("cancel failed"); + _exit (1); + } + void *r; + if (pthread_join (th, &r) != 0) + { + puts ("join failed"); + _exit (1); + } + /* Exit successfully. */ + _exit (0); +} + +void +m (void) +{ + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + _exit (1); + } +} --- /dev/null +++ b/fbtl/tst-flock1.c @@ -0,0 +1,92 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-flock2.c @@ -0,0 +1,259 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-fork1.c @@ -0,0 +1,119 @@ +/* Copyright (C) 2002-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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; +} --- /dev/null +++ b/fbtl/tst-fork2.c @@ -0,0 +1,89 @@ +/* Copyright (C) 2002-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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; +} --- /dev/null +++ b/fbtl/tst-fork3.c @@ -0,0 +1,106 @@ +/* Copyright (C) 2002-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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; +} --- /dev/null +++ b/fbtl/tst-fork4.c @@ -0,0 +1,64 @@ +/* Test of fork updating child universe's pthread structures. + Copyright (C) 2003-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-getpid1.c @@ -0,0 +1,122 @@ +#include <sched.h> +#include <signal.h> +#include <string.h> +#include <stdio.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <stackinfo.h> + +#ifndef TEST_CLONE_FLAGS +#define TEST_CLONE_FLAGS 0 +#endif + +static int sig; + +static int +f (void *a) +{ + puts ("in f"); + union sigval sival; + sival.sival_int = getpid (); + printf ("pid = %d\n", sival.sival_int); + if (sigqueue (getppid (), sig, sival) != 0) + return 1; + return 0; +} + + +static int +do_test (void) +{ + int mypid = getpid (); + + sig = SIGRTMIN; + sigset_t ss; + sigemptyset (&ss); + sigaddset (&ss, sig); + if (sigprocmask (SIG_BLOCK, &ss, NULL) != 0) + { + printf ("sigprocmask failed: %m\n"); + return 1; + } + +#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] __attribute__ ((aligned)); + pid_t p = __clone2 (f, st, sizeof (st), TEST_CLONE_FLAGS, 0); +#else + char st[128 * 1024] __attribute__ ((aligned)); +# if _STACK_GROWS_DOWN + pid_t p = clone (f, st + sizeof (st), TEST_CLONE_FLAGS, 0); +# elif _STACK_GROWS_UP + pid_t p = clone (f, st, TEST_CLONE_FLAGS, 0); +# else +# error "Define either _STACK_GROWS_DOWN or _STACK_GROWS_UP" +# endif +#endif + if (p == -1) + { + printf("clone failed: %m\n"); + return 1; + } + printf ("new thread: %d\n", (int) p); + + siginfo_t si; + do + if (sigwaitinfo (&ss, &si) < 0) + { + printf("sigwaitinfo failed: %m\n"); + kill (p, SIGKILL); + return 1; + } + while (si.si_signo != sig || si.si_code != SI_QUEUE); + + 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) + { + printf ("exit code %d\n", WEXITSTATUS (e)); + return 1; + } + + if (si.si_int != (int) p) + { + printf ("expected PID %d, got si_int %d\n", (int) p, si.si_int); + kill (p, SIGKILL); + return 1; + } + + if (si.si_pid != p) + { + printf ("expected PID %d, got si_pid %d\n", (int) p, (int) si.si_pid); + kill (p, SIGKILL); + return 1; + } + + if (getpid () != mypid) + { + puts ("my PID changed"); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" --- /dev/null +++ b/fbtl/tst-getpid2.c @@ -0,0 +1,2 @@ +#define TEST_CLONE_FLAGS CLONE_VM +#include "tst-getpid1.c" --- /dev/null +++ b/fbtl/tst-getpid3.c @@ -0,0 +1,114 @@ +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/wait.h> + + +static pid_t pid; + +static void * +pid_thread (void *arg) +{ + if (pid != getpid ()) + { + printf ("pid wrong in thread: should be %d, is %d\n", + (int) pid, (int) getpid ()); + return (void *) 1L; + } + + return NULL; +} + +static int +do_test (void) +{ + pid = getpid (); + + pthread_t thr; + int ret = pthread_create (&thr, NULL, pid_thread, NULL); + if (ret) + { + printf ("pthread_create failed: %d\n", ret); + return 1; + } + + void *thr_ret; + ret = pthread_join (thr, &thr_ret); + if (ret) + { + printf ("pthread_create failed: %d\n", ret); + return 1; + } + else if (thr_ret) + { + printf ("thread getpid failed\n"); + return 1; + } + + pid_t child = fork (); + if (child == -1) + { + printf ("fork failed: %m\n"); + return 1; + } + else if (child == 0) + { + if (pid == getpid ()) + { + puts ("pid did not change after fork"); + exit (1); + } + + pid = getpid (); + ret = pthread_create (&thr, NULL, pid_thread, NULL); + if (ret) + { + printf ("pthread_create failed: %d\n", ret); + return 1; + } + + ret = pthread_join (thr, &thr_ret); + if (ret) + { + printf ("pthread_create failed: %d\n", ret); + return 1; + } + else if (thr_ret) + { + printf ("thread getpid failed\n"); + return 1; + } + + return 0; + } + + int status; + if (TEMP_FAILURE_RETRY (waitpid (child, &status, 0)) != child) + { + puts ("waitpid failed"); + kill (child, SIGKILL); + return 1; + } + + if (!WIFEXITED (status)) + { + if (WIFSIGNALED (status)) + printf ("died from signal %s\n", strsignal (WTERMSIG (status))); + else + puts ("did not terminate correctly"); + return 1; + } + if (WEXITSTATUS (status) != 0) + { + printf ("exit code %d\n", WEXITSTATUS (status)); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" --- /dev/null +++ b/fbtl/tst-initializers1-c89.c @@ -0,0 +1 @@ +#include "tst-initializers1.c" --- /dev/null +++ b/fbtl/tst-initializers1-c99.c @@ -0,0 +1 @@ +#include "tst-initializers1.c" --- /dev/null +++ b/fbtl/tst-initializers1-gnu89.c @@ -0,0 +1 @@ +#include "tst-initializers1.c" --- /dev/null +++ b/fbtl/tst-initializers1-gnu99.c @@ -0,0 +1 @@ +#include "tst-initializers1.c" --- /dev/null +++ b/fbtl/tst-initializers1.c @@ -0,0 +1,57 @@ +/* Copyright (C) 2005-2013 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, see + <http://www.gnu.org/licenses/>. */ + +/* We test the code undef conditions outside of glibc. */ +#undef _LIBC + +#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 2; + if (mtx_errorchk.__data.__kind != PTHREAD_MUTEX_ERRORCHECK_NP) + return 3; + if (mtx_adaptive.__data.__kind != PTHREAD_MUTEX_ADAPTIVE_NP) + return 4; + if (rwl_normal.__data.__flags != PTHREAD_RWLOCK_PREFER_READER_NP) + return 5; + if (rwl_writer.__data.__flags + != PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP) + return 6; + /* <libc-lock.h> __libc_rwlock_init definition for libc.so + relies on PTHREAD_RWLOCK_INITIALIZER being all zeros. If + that ever changes, <libc-lock.h> needs updating. */ + size_t i; + for (i = 0; i < sizeof (rwl_normal); i++) + if (((char *) &rwl_normal)[i] != '\0') + return 7; + return 0; +} --- /dev/null +++ b/fbtl/tst-join1.c @@ -0,0 +1,82 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-join2.c @@ -0,0 +1,103 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-join3.c @@ -0,0 +1,122 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-join4.c @@ -0,0 +1,124 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-join5.c @@ -0,0 +1,210 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <unistd.h> +#include <sys/syscall.h> + +#if !defined(__NR_nanosleep) && defined(SYS_nanosleep) +# define __NR_nanosleep SYS_nanosleep +#endif + +#define wait_code() \ + do { \ + struct timespec ts = { .tv_sec = 0, .tv_nsec = 200000000 }; \ + while (syscall (__NR_nanosleep, &ts, &ts) < 0) \ + /* nothing */; \ + } while (0) + + +#ifdef WAIT_IN_CHILD +static pthread_barrier_t b; +#endif + + +static void * +tf1 (void *arg) +{ +#ifdef WAIT_IN_CHILD + int e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __func__); + exit (1); + } + + wait_code (); +#endif + + pthread_join ((pthread_t) arg, NULL); + + exit (42); +} + + +static void * +tf2 (void *arg) +{ +#ifdef WAIT_IN_CHILD + int e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __func__); + exit (1); + } + + wait_code (); +#endif + pthread_join ((pthread_t) arg, NULL); + + exit (43); +} + + +static int +do_test (void) +{ +#ifdef WAIT_IN_CHILD + if (pthread_barrier_init (&b, NULL, 2) != 0) + { + puts ("barrier_init failed"); + return 1; + } +#endif + + pthread_t th; + + int err = pthread_join (pthread_self (), NULL); + if (err == 0) + { + puts ("1st circular join succeeded"); + return 1; + } + if (err != EDEADLK) + { + printf ("1st circular join %d, not EDEADLK\n", err); + return 1; + } + + if (pthread_create (&th, NULL, tf1, (void *) pthread_self ()) != 0) + { + puts ("1st create failed"); + return 1; + } + +#ifndef WAIT_IN_CHILD + wait_code (); +#endif + + if (pthread_cancel (th) != 0) + { + puts ("cannot cancel 1st thread"); + return 1; + } + +#ifdef WAIT_IN_CHILD + int e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __func__); + return 1; + } +#endif + + void *r; + err = pthread_join (th, &r); + if (err != 0) + { + printf ("cannot join 1st thread: %d\n", err); + return 1; + } + if (r != PTHREAD_CANCELED) + { + puts ("1st thread not canceled"); + return 1; + } + + err = pthread_join (pthread_self (), NULL); + if (err == 0) + { + puts ("2nd circular join succeeded"); + return 1; + } + if (err != EDEADLK) + { + printf ("2nd circular join %d, not EDEADLK\n", err); + return 1; + } + + if (pthread_create (&th, NULL, tf2, (void *) pthread_self ()) != 0) + { + puts ("2nd create failed"); + return 1; + } + +#ifndef WAIT_IN_CHILD + wait_code (); +#endif + + if (pthread_cancel (th) != 0) + { + puts ("cannot cancel 2nd thread"); + return 1; + } + +#ifdef WAIT_IN_CHILD + e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __func__); + return 1; + } +#endif + + if (pthread_join (th, &r) != 0) + { + puts ("cannot join 2nd thread"); + return 1; + } + if (r != PTHREAD_CANCELED) + { + puts ("2nd thread not canceled"); + return 1; + } + + err = pthread_join (pthread_self (), NULL); + if (err == 0) + { + puts ("3rd circular join succeeded"); + return 1; + } + if (err != EDEADLK) + { + printf ("3rd circular join %d, not EDEADLK\n", err); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" --- /dev/null +++ b/fbtl/tst-join6.c @@ -0,0 +1,2 @@ +#define WAIT_IN_CHILD 1 +#include "tst-join5.c" --- /dev/null +++ b/fbtl/tst-key1.c @@ -0,0 +1,88 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-key2.c @@ -0,0 +1,114 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-key3.c @@ -0,0 +1,155 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-key4.c @@ -0,0 +1,136 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-kill1.c @@ -0,0 +1,99 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-kill2.c @@ -0,0 +1,138 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-kill3.c @@ -0,0 +1,158 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-kill4.c @@ -0,0 +1,90 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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_attr_t at; + if (pthread_attr_init (&at) != 0) + { + puts ("attr_create failed"); + exit (1); + } + + /* Limit thread stack size, because if it is too large, pthread_join + will free it immediately rather than put it into stack cache. */ + if (pthread_attr_setstacksize (&at, 2 * 1024 * 1024) != 0) + { + puts ("setstacksize failed"); + exit (1); + } + + pthread_t th; + if (pthread_create (&th, &at, tf, NULL) != 0) + { + puts ("create failed"); + exit (1); + } + + pthread_attr_destroy (&at); + + 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 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" --- /dev/null +++ b/fbtl/tst-kill5.c @@ -0,0 +1,48 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-kill6.c @@ -0,0 +1,161 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-locale1.c @@ -0,0 +1,18 @@ +/* Test that the thread-local locale works right in the main thread + when statically linked. */ + +#include "../locale/tst-C-locale.c" + +#include <pthread.h> +#include <signal.h> + +/* This is never called, just here to get pthreads linked in. */ +int +useless (void) +{ + pthread_t th; + pthread_create (&th, 0, (void *(*) (void *)) useless, 0); + /* This is to check __libc_current_sigrt* can be used in statically + linked apps. */ + return SIGRTMIN; +} --- /dev/null +++ b/fbtl/tst-locale2.c @@ -0,0 +1,15 @@ +/* Test that the thread-local locale works right in the main thread + when statically linked. */ + +#include "../argp/tst-argp1.c" + +#include <pthread.h> + +/* This is never called, just here to get pthreads linked in. */ +void * +useless (void *a) +{ + pthread_t th; + pthread_create (&th, 0, useless, a); + return NULL; +} --- /dev/null +++ b/fbtl/tst-mutex1.c @@ -0,0 +1,76 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <pthread.h> +#include <stdio.h> +#include <errno.h> + + +#ifndef ATTR +# define ATTR NULL +#endif + + +static int +do_test (void) +{ + pthread_mutex_t m; + + int e = pthread_mutex_init (&m, ATTR); + if (ATTR != NULL && e == ENOTSUP) + { + puts ("cannot support selected type of mutexes"); + return 0; + } + else if (e != 0) + { + puts ("mutex_init failed"); + return 1; + } + + if (ATTR != NULL && pthread_mutexattr_destroy (ATTR) != 0) + { + puts ("mutexattr_destroy 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; +} + +#ifndef TEST_FUNCTION +# define TEST_FUNCTION do_test () +#endif +#include "../test-skeleton.c" --- /dev/null +++ b/fbtl/tst-mutex2.c @@ -0,0 +1,241 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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"); + return 1; + } + + if (pthread_mutexattr_settype (&a, PTHREAD_MUTEX_ERRORCHECK) != 0) + { + puts ("mutexattr_settype failed"); + return 1; + } + +#ifdef ENABLE_PI + if (pthread_mutexattr_setprotocol (&a, PTHREAD_PRIO_INHERIT) != 0) + { + puts ("pthread_mutexattr_setprotocol failed"); + return 1; + } +#endif + + e = pthread_mutex_init (&m, &a); + if (e != 0) + { +#ifdef ENABLE_PI + if (e == ENOTSUP) + { + puts ("PI mutexes unsupported"); + return 0; + } +#endif + puts ("mutex_init failed"); + return 1; + } + + if (pthread_barrier_init (&b, NULL, 2) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + e = pthread_mutex_unlock (&m); + if (e == 0) + { + puts ("1st mutex_unlock succeeded"); + return 1; + } + else if (e != EPERM) + { + puts ("1st mutex_unlock error != EPERM"); + return 1; + } + + if (pthread_mutex_lock (&m) != 0) + { + puts ("mutex_lock failed"); + return 1; + } + + e = pthread_mutex_lock (&m); + if (e == 0) + { + puts ("2nd mutex_lock succeeded"); + return 1; + } + else if (e != EDEADLK) + { + puts ("2nd mutex_lock error != EDEADLK"); + return 1; + } + + pthread_t th; + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + return 1; + } + + e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("1st barrier_wait failed"); + return 1; + } + + if (pthread_mutex_unlock (&m) != 0) + { + puts ("2nd mutex_unlock failed"); + return 1; + } + + e = pthread_mutex_unlock (&m); + if (e == 0) + { + puts ("3rd mutex_unlock succeeded"); + return 1; + } + else if (e != EPERM) + { + puts ("3rd mutex_unlock error != EPERM"); + return 1; + } + + e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("2nd barrier_wait failed"); + return 1; + } + + if (pthread_join (th, NULL) != 0) + { + puts ("join failed"); + return 1; + } + + if (pthread_mutex_destroy (&m) != 0) + { + puts ("mutex_destroy failed"); + return 1; + } + + if (pthread_barrier_destroy (&b) != 0) + { + puts ("barrier_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" --- /dev/null +++ b/fbtl/tst-mutex3.c @@ -0,0 +1,241 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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; + } + +#ifdef ENABLE_PI + if (pthread_mutexattr_setprotocol (&a, PTHREAD_PRIO_INHERIT) != 0) + { + puts ("pthread_mutexattr_setprotocol failed"); + return 1; + } +#endif + + int e; + e = pthread_mutex_init (&m, &a); + if (e != 0) + { +#ifdef ENABLE_PI + if (e == ENOTSUP) + { + puts ("PI mutexes unsupported"); + return 0; + } +#endif + 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; + } + + 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" --- /dev/null +++ b/fbtl/tst-mutex4.c @@ -0,0 +1,277 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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; + pthread_barrier_t *b; + pthread_barrierattr_t ba; + + 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) - 1) + & ~(__alignof (pthread_mutex_t) - 1)); + b = (pthread_barrier_t *) (((uintptr_t) (m + 1) + + __alignof (pthread_barrier_t) - 1) + & ~(__alignof (pthread_barrier_t) - 1)); + p = (char *) (b + 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; + } + +#ifdef ENABLE_PI + if (pthread_mutexattr_setprotocol (&a, PTHREAD_PRIO_INHERIT) != 0) + { + puts ("pthread_mutexattr_setprotocol failed"); + return 1; + } +#endif + + if ((err = pthread_mutex_init (m, &a)) != 0) + { +#ifdef ENABLE_PI + if (err == ENOTSUP) + { + puts ("PI mutexes unsupported"); + return 0; + } +#endif + 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; + } + + 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; + } + + 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; + + if (pthread_mutex_unlock (m) != 0) + { + puts ("parent: 1st mutex_unlock 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 (m) != 0) + { + puts ("child: mutex_lock failed"); + return 1; + } + + int e = pthread_barrier_wait (b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("child: barrier_wait failed"); + return 1; + } + + if ((*p)++ != 0) + { + puts ("child: *p != 0"); + return 1; + } + + if (pthread_mutex_unlock (m) != 0) + { + puts ("child: mutex_unlock failed"); + return 1; + } + + puts ("child done"); + } + else + { + int e = pthread_barrier_wait (b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("parent: barrier_wait failed"); + return 1; + } + + if (pthread_mutex_lock (m) != 0) + { + puts ("parent: 2nd mutex_lock failed"); + return 1; + } + + if (*p != 1) + { + puts ("*p != 1"); + return 1; + } + + if (pthread_mutex_unlock (m) != 0) + { + puts ("parent: 2nd mutex_unlock failed"); + return 1; + } + + if (pthread_mutex_destroy (m) != 0) + { + puts ("mutex_destroy failed"); + return 1; + } + + if (pthread_barrier_destroy (b) != 0) + { + puts ("barrier_destroy failed"); + return 1; + } + + puts ("parent done"); + } + + return 0; +} + +#define TIMEOUT 4 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" --- /dev/null +++ b/fbtl/tst-mutex5.c @@ -0,0 +1,201 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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; + } + +#ifdef ENABLE_PI + if (pthread_mutexattr_setprotocol (&a, PTHREAD_PRIO_INHERIT) != 0) + { + puts ("pthread_mutexattr_setprotocol failed"); + return 1; + } +#endif + + err = pthread_mutex_init (&m, &a); + if (err != 0) + { +#ifdef ENABLE_PI + if (err == ENOTSUP) + { + puts ("PI mutexes unsupported"); + return 0; + } +#endif + 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" --- /dev/null +++ b/fbtl/tst-mutex5a.c @@ -0,0 +1,2 @@ +#define TYPE PTHREAD_MUTEX_ADAPTIVE_NP +#include "tst-mutex5.c" --- /dev/null +++ b/fbtl/tst-mutex6.c @@ -0,0 +1,72 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <unistd.h> +#include <errno.h> + +#ifndef TEST_FUNCTION +static int do_test (void); +# define TEST_FUNCTION do_test () +#endif +#include "../test-skeleton.c" + +#ifndef ATTR +pthread_mutexattr_t *attr; +# define ATTR attr +#endif + + +static int +do_test (void) +{ + pthread_mutex_t m; + + int e = pthread_mutex_init (&m, ATTR); + if (ATTR != NULL && e == ENOTSUP) + { + puts ("cannot support selected type of mutexes"); + e = pthread_mutex_init (&m, NULL); + } + if (e != 0) + { + puts ("mutex_init failed"); + return 1; + } + + if (ATTR != NULL && pthread_mutexattr_destroy (ATTR) != 0) + { + puts ("mutexattr_destroy failed"); + return 1; + } + + if (pthread_mutex_lock (&m) != 0) + { + puts ("1st mutex_lock failed"); + return 1; + } + + delayed_exit (1); + /* This call should never return. */ + xpthread_mutex_lock (&m); + + puts ("2nd mutex_lock returned"); + return 1; +} --- /dev/null +++ b/fbtl/tst-mutex7.c @@ -0,0 +1,164 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> + + +#ifndef TYPE +# define TYPE PTHREAD_MUTEX_DEFAULT +#endif + + +static pthread_mutex_t lock; + + +#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_mutexattr_t a; + + if (pthread_mutexattr_init (&a) != 0) + { + puts ("mutexattr_init failed"); + exit (1); + } + + if (pthread_mutexattr_settype (&a, TYPE) != 0) + { + puts ("mutexattr_settype failed"); + exit (1); + } + +#ifdef ENABLE_PI + if (pthread_mutexattr_setprotocol (&a, PTHREAD_PRIO_INHERIT) != 0) + { + puts ("pthread_mutexattr_setprotocol failed"); + return 1; + } +#endif + + int e = pthread_mutex_init (&lock, &a); + if (e != 0) + { +#ifdef ENABLE_PI + if (e == ENOTSUP) + { + puts ("PI mutexes unsupported"); + return 0; + } +#endif + puts ("mutex_init failed"); + return 1; + } + + if (pthread_mutexattr_destroy (&a) != 0) + { + puts ("mutexattr_destroy failed"); + return 1; + } + + 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" --- /dev/null +++ b/fbtl/tst-mutex7a.c @@ -0,0 +1,2 @@ +#define TYPE PTHREAD_MUTEX_ADAPTIVE_NP +#include "tst-mutex7.c" --- /dev/null +++ b/fbtl/tst-mutex8-static.c @@ -0,0 +1 @@ +#include "tst-mutex8.c" --- /dev/null +++ b/fbtl/tst-mutex8.c @@ -0,0 +1,380 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +/* 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; + } +#ifdef ENABLE_PI + if (pthread_mutexattr_setprotocol (&ma, PTHREAD_PRIO_INHERIT)) + { + puts ("1st pthread_mutexattr_setprotocol failed"); + return 1; + } +#endif + 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; + } +#ifdef ENABLE_PI + if (pthread_mutexattr_setprotocol (&ma, PTHREAD_PRIO_INHERIT)) + { + puts ("2nd pthread_mutexattr_setprotocol failed"); + return 1; + } +#endif + 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" --- /dev/null +++ b/fbtl/tst-mutex9.c @@ -0,0 +1,202 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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/time.h> +#include <sys/wait.h> + + +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; + + 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)); + + 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; + } + +#ifdef ENABLE_PI + if (pthread_mutexattr_setprotocol (&a, PTHREAD_PRIO_INHERIT) != 0) + { + puts ("pthread_mutexattr_setprotocol failed"); + return 1; + } +#endif + + int e; + if ((e = pthread_mutex_init (m, &a)) != 0) + { +#ifdef ENABLE_PI + if (e == ENOTSUP) + { + puts ("PI mutexes unsupported"); + return 0; + } +#endif + 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; + } + + 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" --- /dev/null +++ b/fbtl/tst-mutexpi1.c @@ -0,0 +1,27 @@ +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> + + +static pthread_mutexattr_t a; + +static void +prepare (void) +{ + if (pthread_mutexattr_init (&a) != 0) + { + puts ("mutexattr_init failed"); + exit (1); + } + + if (pthread_mutexattr_setprotocol (&a, PTHREAD_PRIO_INHERIT) != 0) + { + puts ("mutexattr_setprotocol failed"); + exit (1); + } +} +#define PREPARE(argc, argv) prepare () + + +#define ATTR &a +#include "tst-mutex1.c" --- /dev/null +++ b/fbtl/tst-mutexpi2.c @@ -0,0 +1,2 @@ +#define ENABLE_PI 1 +#include "tst-mutex2.c" --- /dev/null +++ b/fbtl/tst-mutexpi3.c @@ -0,0 +1,2 @@ +#define ENABLE_PI 1 +#include "tst-mutex3.c" --- /dev/null +++ b/fbtl/tst-mutexpi4.c @@ -0,0 +1,2 @@ +#define ENABLE_PI 1 +#include "tst-mutex4.c" --- /dev/null +++ b/fbtl/tst-mutexpi5.c @@ -0,0 +1,2 @@ +#define ENABLE_PI 1 +#include "tst-mutex5.c" --- /dev/null +++ b/fbtl/tst-mutexpi5a.c @@ -0,0 +1,2 @@ +#define ENABLE_PI 1 +#include "tst-mutex5a.c" --- /dev/null +++ b/fbtl/tst-mutexpi6.c @@ -0,0 +1,29 @@ +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> + + +pthread_mutexattr_t a; +pthread_mutexattr_t *attr; + +static void +prepare (void) +{ + attr = &a; + if (pthread_mutexattr_init (&a) != 0) + { + puts ("mutexattr_init failed"); + exit (1); + } + + if (pthread_mutexattr_setprotocol (&a, PTHREAD_PRIO_INHERIT) != 0) + { + puts ("mutexattr_setprotocol failed"); + exit (1); + } +} +#define PREPARE(argc, argv) prepare () + + +#define ATTR attr +#include "tst-mutex6.c" --- /dev/null +++ b/fbtl/tst-mutexpi7.c @@ -0,0 +1,2 @@ +#define ENABLE_PI 1 +#include "tst-mutex7.c" --- /dev/null +++ b/fbtl/tst-mutexpi7a.c @@ -0,0 +1,2 @@ +#define ENABLE_PI 1 +#include "tst-mutex7a.c" --- /dev/null +++ b/fbtl/tst-mutexpi8-static.c @@ -0,0 +1 @@ +#include "tst-mutexpi8.c" --- /dev/null +++ b/fbtl/tst-mutexpi8.c @@ -0,0 +1,2 @@ +#define ENABLE_PI 1 +#include "tst-mutex8.c" --- /dev/null +++ b/fbtl/tst-mutexpi9.c @@ -0,0 +1,2 @@ +#define ENABLE_PI 1 +#include "tst-mutex9.c" --- /dev/null +++ b/fbtl/tst-mutexpp1.c @@ -0,0 +1,45 @@ +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> + +#include "tst-tpp.h" + +static pthread_mutexattr_t a; + +static void +prepare (void) +{ + init_tpp_test (); + + if (pthread_mutexattr_init (&a) != 0) + { + puts ("mutexattr_init failed"); + exit (1); + } + + if (pthread_mutexattr_setprotocol (&a, PTHREAD_PRIO_PROTECT) != 0) + { + puts ("mutexattr_setprotocol failed"); + exit (1); + } + + if (pthread_mutexattr_setprioceiling (&a, 6) != 0) + { + puts ("mutexattr_setprioceiling failed"); + exit (1); + } +} +#define PREPARE(argc, argv) prepare () + +static int do_test (void); + +static int +do_test_wrapper (void) +{ + init_tpp_test (); + return do_test (); +} +#define TEST_FUNCTION do_test_wrapper () + +#define ATTR &a +#include "tst-mutex1.c" --- /dev/null +++ b/fbtl/tst-mutexpp10.c @@ -0,0 +1,333 @@ +/* Copyright (C) 2006-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <limits.h> +#include <pthread.h> +#include <sched.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "tst-tpp.h" + +static int +do_test (void) +{ + int ret = 0; + + init_tpp_test (); + + pthread_mutexattr_t ma; + if (pthread_mutexattr_init (&ma)) + { + puts ("mutexattr_init failed"); + return 1; + } + if (pthread_mutexattr_setprotocol (&ma, PTHREAD_PRIO_PROTECT)) + { + puts ("mutexattr_setprotocol failed"); + return 1; + } + + int prioceiling; + if (pthread_mutexattr_getprioceiling (&ma, &prioceiling)) + { + puts ("mutexattr_getprioceiling failed"); + return 1; + } + + if (prioceiling < fifo_min || prioceiling > fifo_max) + { + printf ("prioceiling %d not in %d..%d range\n", + prioceiling, fifo_min, fifo_max); + return 1; + } + + if (fifo_max < INT_MAX + && pthread_mutexattr_setprioceiling (&ma, fifo_max + 1) != EINVAL) + { + printf ("mutexattr_setprioceiling %d did not fail with EINVAL\n", + fifo_max + 1); + return 1; + } + + if (fifo_min > 0 + && pthread_mutexattr_setprioceiling (&ma, fifo_min - 1) != EINVAL) + { + printf ("mutexattr_setprioceiling %d did not fail with EINVAL\n", + fifo_min - 1); + return 1; + } + + if (pthread_mutexattr_setprioceiling (&ma, fifo_min)) + { + puts ("mutexattr_setprioceiling failed"); + return 1; + } + + if (pthread_mutexattr_setprioceiling (&ma, fifo_max)) + { + puts ("mutexattr_setprioceiling failed"); + return 1; + } + + if (pthread_mutexattr_setprioceiling (&ma, 6)) + { + puts ("mutexattr_setprioceiling failed"); + return 1; + } + + if (pthread_mutexattr_getprioceiling (&ma, &prioceiling)) + { + puts ("mutexattr_getprioceiling failed"); + return 1; + } + + if (prioceiling != 6) + { + printf ("mutexattr_getprioceiling returned %d != 6\n", + prioceiling); + return 1; + } + + pthread_mutex_t m1, m2, m3; + int e = pthread_mutex_init (&m1, &ma); + if (e == ENOTSUP) + { + puts ("cannot support selected type of mutexes"); + return 0; + } + else if (e != 0) + { + puts ("mutex_init failed"); + return 1; + } + + if (pthread_mutexattr_setprioceiling (&ma, 8)) + { + puts ("mutexattr_setprioceiling failed"); + return 1; + } + + if (pthread_mutex_init (&m2, &ma)) + { + puts ("mutex_init failed"); + return 1; + } + + if (pthread_mutexattr_setprioceiling (&ma, 5)) + { + puts ("mutexattr_setprioceiling failed"); + return 1; + } + + if (pthread_mutex_init (&m3, &ma)) + { + puts ("mutex_init failed"); + return 1; + } + + CHECK_TPP_PRIORITY (4, 4); + + if (pthread_mutex_lock (&m1) != 0) + { + puts ("mutex_lock failed"); + return 1; + } + + CHECK_TPP_PRIORITY (4, 6); + + if (pthread_mutex_trylock (&m2) != 0) + { + puts ("mutex_lock failed"); + return 1; + } + + CHECK_TPP_PRIORITY (4, 8); + + if (pthread_mutex_lock (&m3) != 0) + { + puts ("mutex_lock failed"); + return 1; + } + + CHECK_TPP_PRIORITY (4, 8); + + if (pthread_mutex_unlock (&m2) != 0) + { + puts ("mutex_unlock failed"); + return 1; + } + + CHECK_TPP_PRIORITY (4, 6); + + if (pthread_mutex_unlock (&m1) != 0) + { + puts ("mutex_unlock failed"); + return 1; + } + + CHECK_TPP_PRIORITY (4, 5); + + if (pthread_mutex_lock (&m2) != 0) + { + puts ("mutex_lock failed"); + return 1; + } + + CHECK_TPP_PRIORITY (4, 8); + + if (pthread_mutex_unlock (&m2) != 0) + { + puts ("mutex_unlock failed"); + return 1; + } + + CHECK_TPP_PRIORITY (4, 5); + + if (pthread_mutex_getprioceiling (&m1, &prioceiling)) + { + puts ("mutex_getprioceiling m1 failed"); + return 1; + } + else if (prioceiling != 6) + { + printf ("unexpected m1 prioceiling %d != 6\n", prioceiling); + return 1; + } + + if (pthread_mutex_getprioceiling (&m2, &prioceiling)) + { + puts ("mutex_getprioceiling m2 failed"); + return 1; + } + else if (prioceiling != 8) + { + printf ("unexpected m2 prioceiling %d != 8\n", prioceiling); + return 1; + } + + if (pthread_mutex_getprioceiling (&m3, &prioceiling)) + { + puts ("mutex_getprioceiling m3 failed"); + return 1; + } + else if (prioceiling != 5) + { + printf ("unexpected m3 prioceiling %d != 5\n", prioceiling); + return 1; + } + + if (pthread_mutex_setprioceiling (&m1, 7, &prioceiling)) + { + printf ("mutex_setprioceiling failed"); + return 1; + } + else if (prioceiling != 6) + { + printf ("unexpected m1 old prioceiling %d != 6\n", prioceiling); + return 1; + } + + if (pthread_mutex_getprioceiling (&m1, &prioceiling)) + { + puts ("mutex_getprioceiling m1 failed"); + return 1; + } + else if (prioceiling != 7) + { + printf ("unexpected m1 prioceiling %d != 7\n", prioceiling); + return 1; + } + + CHECK_TPP_PRIORITY (4, 5); + + if (pthread_mutex_unlock (&m3) != 0) + { + puts ("mutex_unlock failed"); + return 1; + } + + CHECK_TPP_PRIORITY (4, 4); + + if (pthread_mutex_trylock (&m1) != 0) + { + puts ("mutex_lock failed"); + return 1; + } + + CHECK_TPP_PRIORITY (4, 7); + + struct sched_param sp; + memset (&sp, 0, sizeof (sp)); + sp.sched_priority = 8; + if (pthread_setschedparam (pthread_self (), SCHED_FIFO, &sp)) + { + puts ("cannot set scheduling params"); + return 1; + } + + CHECK_TPP_PRIORITY (8, 8); + + if (pthread_mutex_unlock (&m1) != 0) + { + puts ("mutex_unlock failed"); + return 1; + } + + CHECK_TPP_PRIORITY (8, 8); + + if (pthread_mutex_lock (&m3) != EINVAL) + { + puts ("pthread_mutex_lock didn't fail with EINVAL"); + return 1; + } + + CHECK_TPP_PRIORITY (8, 8); + + if (pthread_mutex_destroy (&m1) != 0) + { + puts ("mutex_destroy failed"); + return 1; + } + + if (pthread_mutex_destroy (&m2) != 0) + { + puts ("mutex_destroy failed"); + return 1; + } + + if (pthread_mutex_destroy (&m3) != 0) + { + puts ("mutex_destroy failed"); + return 1; + } + + if (pthread_mutexattr_destroy (&ma) != 0) + { + puts ("mutexattr_destroy failed"); + return 1; + } + + return ret; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" --- /dev/null +++ b/fbtl/tst-mutexpp6.c @@ -0,0 +1,45 @@ +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> + +#include "tst-tpp.h" + +static pthread_mutexattr_t a; + +static void +prepare (void) +{ + init_tpp_test (); + + if (pthread_mutexattr_init (&a) != 0) + { + puts ("mutexattr_init failed"); + exit (1); + } + + if (pthread_mutexattr_setprotocol (&a, PTHREAD_PRIO_PROTECT) != 0) + { + puts ("mutexattr_setprotocol failed"); + exit (1); + } + + if (pthread_mutexattr_setprioceiling (&a, 6) != 0) + { + puts ("mutexattr_setprioceiling failed"); + exit (1); + } +} +#define PREPARE(argc, argv) prepare () + +static int do_test (void); + +static int +do_test_wrapper (void) +{ + init_tpp_test (); + return do_test (); +} +#define TEST_FUNCTION do_test_wrapper () + +#define ATTR &a +#include "tst-mutex6.c" --- /dev/null +++ b/fbtl/tst-oddstacklimit.c @@ -0,0 +1,73 @@ +/* Test NPTL with stack limit that is not a multiple of the page size. + Copyright (C) 2012-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <sys/resource.h> +#include <sys/wait.h> +#include <stdlib.h> + +/* This sets the stack resource limit to 1023kb, which is not a multiple + of the page size since every architecture's page size is > 1k. */ +#ifndef ODD_STACK_LIMIT +# define ODD_STACK_LIMIT (1023 * 1024) +#endif + +static const char *command; + +static int +do_test (void) +{ + int ret; + struct rlimit rlim; + + ret = getrlimit (RLIMIT_STACK, &rlim); + if (ret != 0) + { + printf ("getrlimit failed: %s\n", strerror (errno)); + return 1; + } + rlim.rlim_cur = ODD_STACK_LIMIT; + ret = setrlimit (RLIMIT_STACK, &rlim); + if (ret != 0) + { + printf ("setrlimit failed: %s\n", strerror (errno)); + return 1; + } + ret = system (command); + if (ret == -1) + { + printf ("system failed: %s\n", strerror (errno)); + return 1; + } + if (WIFEXITED (ret)) + return WEXITSTATUS (ret); + else + return 1; +} + +#define OPT_COMMAND 10000 +#define CMDLINE_OPTIONS \ + { "command", required_argument, NULL, OPT_COMMAND }, +#define CMDLINE_PROCESS \ + case OPT_COMMAND: \ + command = optarg; \ + break; +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" --- /dev/null +++ b/fbtl/tst-once1.c @@ -0,0 +1,50 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-once2.c @@ -0,0 +1,103 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-once3.c @@ -0,0 +1,166 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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); + } + + puts ("once_handler1: going to wait on cond"); + + 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; + } + puts ("joined successfully"); + + printf ("once = %d\n", *(int *) &once); + + 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" --- /dev/null +++ b/fbtl/tst-once4.c @@ -0,0 +1,201 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-oncex3.c @@ -0,0 +1 @@ +#include "tst-once3.c" --- /dev/null +++ b/fbtl/tst-oncex4.c @@ -0,0 +1 @@ +#include "tst-once4.c" --- /dev/null +++ b/fbtl/tst-popen1.c @@ -0,0 +1,59 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-pthread-attr-affinity.c @@ -0,0 +1,63 @@ +/* Make sure that pthread_attr_getaffinity_np does not crash when the input + cpuset size is smaller than that in the attribute structure. + + Copyright (C) 2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <pthread.h> +#include <stdio.h> +#include <sched.h> +#include <errno.h> +#include <sys/param.h> + + +#define RETURN_IF_FAIL(f, ...) \ + ({ \ + int ret = f (__VA_ARGS__); \ + if (ret != 0) \ + { \ + printf ("%s:%d: %s returned %d (errno = %d)\n", __FILE__, __LINE__, \ + #f, ret, errno); \ + return ret; \ + } \ + }) + +static int +do_test (void) +{ + for (int i = 0; i < 10; i++) + { + pthread_attr_t attr; + cpu_set_t *cpuset = CPU_ALLOC (512); + size_t cpusetsize = CPU_ALLOC_SIZE (512); + CPU_ZERO_S (cpusetsize, cpuset); + + RETURN_IF_FAIL (pthread_attr_init, &attr); + RETURN_IF_FAIL (pthread_attr_setaffinity_np, &attr, cpusetsize, cpuset); + CPU_FREE (cpuset); + + cpuset = CPU_ALLOC (1); + cpusetsize = CPU_ALLOC_SIZE (1); + RETURN_IF_FAIL (pthread_attr_getaffinity_np, &attr, cpusetsize, cpuset); + CPU_FREE (cpuset); + } + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" --- /dev/null +++ b/fbtl/tst-pthread-getattr.c @@ -0,0 +1,161 @@ +/* Make sure that the stackaddr returned by pthread_getattr_np is + reachable. + + Copyright (C) 2012-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <stdio.h> +#include <string.h> +#include <sys/resource.h> +#include <sys/param.h> +#include <pthread.h> +#include <alloca.h> +#include <assert.h> +#include <unistd.h> +#include <inttypes.h> + +/* There is an obscure bug in the kernel due to which RLIMIT_STACK is sometimes + returned as unlimited when it is not, which may cause this test to fail. + There is also the other case where RLIMIT_STACK is intentionally set as + unlimited or very high, which may result in a vma that is too large and again + results in a test case failure. To avoid these problems, we cap the stack + size to one less than 8M. See the following mailing list threads for more + information about this problem: + <http://sourceware.org/ml/libc-alpha/2012-06/msg00599.html> + <http://sourceware.org/ml/libc-alpha/2012-06/msg00713.html>. */ +#define MAX_STACK_SIZE (8192 * 1024 - 1) + +static size_t pagesize; + +/* Check if the page in which TARGET lies is accessible. This will segfault + if it fails. */ +static volatile char * +allocate_and_test (char *target) +{ + volatile char *mem = (char *) &mem; + /* FIXME: mem >= target for _STACK_GROWSUP. */ + mem = alloca ((size_t) (mem - target)); + + *mem = 42; + return mem; +} + +static int +get_self_pthread_attr (const char *id, void **stackaddr, size_t *stacksize) +{ + pthread_attr_t attr; + int ret; + pthread_t me = pthread_self (); + + if ((ret = pthread_getattr_np (me, &attr)) < 0) + { + printf ("%s: pthread_getattr_np failed: %s\n", id, strerror (ret)); + return 1; + } + + if ((ret = pthread_attr_getstack (&attr, stackaddr, stacksize)) < 0) + { + printf ("%s: pthread_attr_getstack returned error: %s\n", id, + strerror (ret)); + return 1; + } + + return 0; +} + +/* Verify that the stack size returned by pthread_getattr_np is usable when + the returned value is subject to rlimit. */ +static int +check_stack_top (void) +{ + struct rlimit stack_limit; + void *stackaddr; + volatile void *mem; + size_t stacksize = 0; + int ret; + uintptr_t pagemask = ~(pagesize - 1); + + puts ("Verifying that stack top is accessible"); + + ret = getrlimit (RLIMIT_STACK, &stack_limit); + if (ret) + { + perror ("getrlimit failed"); + return 1; + } + + printf ("current rlimit_stack is %zu\n", (size_t) stack_limit.rlim_cur); + + if (get_self_pthread_attr ("check_stack_top", &stackaddr, &stacksize)) + return 1; + + /* Reduce the rlimit to a page less that what is currently being returned + (subject to a maximum of MAX_STACK_SIZE) so that we ensure that + pthread_getattr_np uses rlimit. The figure is intentionally unaligned so + to verify that pthread_getattr_np returns an aligned stacksize that + correctly fits into the rlimit. We don't bother about the case where the + stack is limited by the vma below it and not by the rlimit because the + stacksize returned in that case is computed from the end of that vma and is + hence safe. */ + stack_limit.rlim_cur = MIN (stacksize - pagesize + 1, MAX_STACK_SIZE); + printf ("Adjusting RLIMIT_STACK to %zu\n", (size_t) stack_limit.rlim_cur); + if ((ret = setrlimit (RLIMIT_STACK, &stack_limit)) < 0) + { + perror ("setrlimit failed"); + return 1; + } + + if (get_self_pthread_attr ("check_stack_top2", &stackaddr, &stacksize)) + return 1; + + printf ("Adjusted rlimit: stacksize=%zu, stackaddr=%p\n", stacksize, + stackaddr); + + /* A lot of targets tend to write stuff on top of the user stack during + context switches, so we cannot possibly safely go up to the very top of + stack and test access there. It is however sufficient to simply check if + the top page is accessible, so we target our access halfway up the top + page. Thanks Chris Metcalf for this idea. */ + mem = allocate_and_test (stackaddr + pagesize / 2); + + /* Before we celebrate, make sure we actually did test the same page. */ + if (((uintptr_t) stackaddr & pagemask) != ((uintptr_t) mem & pagemask)) + { + printf ("We successfully wrote into the wrong page.\n" + "Expected %#" PRIxPTR ", but got %#" PRIxPTR "\n", + (uintptr_t) stackaddr & pagemask, (uintptr_t) mem & pagemask); + + return 1; + } + + puts ("Stack top tests done"); + + return 0; +} + +/* TODO: Similar check for thread stacks once the thread stack sizes are + fixed. */ +static int +do_test (void) +{ + pagesize = sysconf (_SC_PAGESIZE); + return check_stack_top (); +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" --- /dev/null +++ b/fbtl/tst-raise1.c @@ -0,0 +1,61 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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); +} --- /dev/null +++ b/fbtl/tst-robust1.c @@ -0,0 +1,338 @@ +/* Copyright (C) 2005-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> + + +static pthread_mutex_t m1; +static pthread_mutex_t m2; +static pthread_barrier_t b; + + +#ifndef LOCK +# define LOCK(m) pthread_mutex_lock (m) +#endif + + +static void * +tf (void *arg) +{ + long int round = (long int) arg; + + if (pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL) != 0) + { + printf ("%ld: setcancelstate failed\n", round); + exit (1); + } + + int e = LOCK (&m1); + if (e != 0) + { + printf ("%ld: child: mutex_lock m1 failed with error %d\n", round, e); + exit (1); + } + + e = LOCK (&m2); + if (e != 0) + { + printf ("%ld: child: mutex_lock m2 failed with error %d\n", round, e); + exit (1); + } + + e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%ld: child: 1st barrier_wait failed\n", round); + exit (1); + } + + e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%ld: child: 2nd barrier_wait failed\n", round); + exit (1); + } + + pthread_testcancel (); + + printf ("%ld: testcancel returned\n", round); + exit (1); +} + + +static int +do_test (void) +{ +#ifdef PREPARE_TMO + PREPARE_TMO; +#endif + + pthread_mutexattr_t a; + if (pthread_mutexattr_init (&a) != 0) + { + puts ("mutexattr_init failed"); + return 1; + } + if (pthread_mutexattr_setrobust_np (&a, PTHREAD_MUTEX_ROBUST_NP) != 0) + { + puts ("mutexattr_setrobust failed"); + return 1; + } + +#ifdef ENABLE_PI + if (pthread_mutexattr_setprotocol (&a, PTHREAD_PRIO_INHERIT) != 0) + { + puts ("pthread_mutexattr_setprotocol failed"); + return 1; + } + else + { + int e = pthread_mutex_init (&m1, &a); + if (e == ENOTSUP) + { + puts ("PI robust mutexes not supported"); + return 0; + } + else if (e != 0) + { + puts ("mutex_init m1 failed"); + return 1; + } + pthread_mutex_destroy (&m1); + } +#endif + +#ifndef NOT_CONSISTENT + if (pthread_mutex_init (&m1, &a) != 0) + { + puts ("mutex_init m1 failed"); + return 1; + } + + if (pthread_mutex_init (&m2, &a) != 0) + { + puts ("mutex_init m2 failed"); + return 1; + } +#endif + + if (pthread_barrier_init (&b, NULL, 2) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + for (long int round = 1; round < 5; ++round) + { +#ifdef NOT_CONSISTENT + if (pthread_mutex_init (&m1 , &a) != 0) + { + puts ("mutex_init m1 failed"); + return 1; + } + if (pthread_mutex_init (&m2 , &a) != 0) + { + puts ("mutex_init m2 failed"); + return 1; + } +#endif + + pthread_t th; + if (pthread_create (&th, NULL, tf, (void *) round) != 0) + { + printf ("%ld: create failed\n", round); + return 1; + } + + int e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%ld: parent: 1st barrier_wait failed\n", round); + return 1; + } + + if (pthread_cancel (th) != 0) + { + printf ("%ld: cancel failed\n", round); + return 1; + } + + e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%ld: parent: 2nd barrier_wait failed\n", round); + return 1; + } + +#ifndef AFTER_JOIN + if (round & 1) +#endif + { + void *res; + if (pthread_join (th, &res) != 0) + { + printf ("%ld: join failed\n", round); + return 1; + } + if (res != PTHREAD_CANCELED) + { + printf ("%ld: thread not canceled\n", round); + return 1; + } + } + + e = LOCK (&m1); + if (e == 0) + { + printf ("%ld: parent: mutex_lock m1 succeeded\n", round); + return 1; + } + if (e != EOWNERDEAD) + { + printf ("%ld: parent: mutex_lock m1 returned wrong code\n", round); + return 1; + } + + e = LOCK (&m2); + if (e == 0) + { + printf ("%ld: parent: mutex_lock m2 succeeded\n", round); + return 1; + } + if (e != EOWNERDEAD) + { + printf ("%ld: parent: mutex_lock m2 returned wrong code\n", round); + return 1; + } + +#ifndef AFTER_JOIN + if ((round & 1) == 0) + { + void *res; + if (pthread_join (th, &res) != 0) + { + printf ("%ld: join failed\n", round); + return 1; + } + if (res != PTHREAD_CANCELED) + { + printf ("%ld: thread not canceled\n", round); + return 1; + } + } +#endif + +#ifndef NOT_CONSISTENT + e = pthread_mutex_consistent_np (&m1); + if (e != 0) + { + printf ("%ld: mutex_consistent m1 failed with error %d\n", round, e); + return 1; + } + + e = pthread_mutex_consistent_np (&m2); + if (e != 0) + { + printf ("%ld: mutex_consistent m2 failed with error %d\n", round, e); + return 1; + } +#endif + + e = pthread_mutex_unlock (&m1); + if (e != 0) + { + printf ("%ld: mutex_unlock m1 failed with %d\n", round, e); + return 1; + } + + e = pthread_mutex_unlock (&m2); + if (e != 0) + { + printf ("%ld: mutex_unlock m2 failed with %d\n", round, e); + return 1; + } + +#ifdef NOT_CONSISTENT + e = LOCK (&m1); + if (e == 0) + { + printf ("%ld: locking inconsistent mutex m1 succeeded\n", round); + return 1; + } + if (e != ENOTRECOVERABLE) + { + printf ("%ld: locking inconsistent mutex m1 failed with error %d\n", + round, e); + return 1; + } + + if (pthread_mutex_destroy (&m1) != 0) + { + puts ("mutex_destroy m1 failed"); + return 1; + } + + e = LOCK (&m2); + if (e == 0) + { + printf ("%ld: locking inconsistent mutex m2 succeeded\n", round); + return 1; + } + if (e != ENOTRECOVERABLE) + { + printf ("%ld: locking inconsistent mutex m2 failed with error %d\n", + round, e); + return 1; + } + + if (pthread_mutex_destroy (&m2) != 0) + { + puts ("mutex_destroy m2 failed"); + return 1; + } +#endif + } + +#ifndef NOT_CONSISTENT + if (pthread_mutex_destroy (&m1) != 0) + { + puts ("mutex_destroy m1 failed"); + return 1; + } + + if (pthread_mutex_destroy (&m2) != 0) + { + puts ("mutex_destroy m2 failed"); + return 1; + } +#endif + + if (pthread_mutexattr_destroy (&a) != 0) + { + puts ("mutexattr_destroy failed"); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" --- /dev/null +++ b/fbtl/tst-robust2.c @@ -0,0 +1,3 @@ +#define AFTER_JOIN 1 +#define LOCK(m) pthread_mutex_trylock (m) +#include "tst-robust1.c" --- /dev/null +++ b/fbtl/tst-robust3.c @@ -0,0 +1,20 @@ +#include <time.h> +#include <sys/time.h> + + +static struct timespec tmo; + + +#define PREPARE_TMO \ + do { \ + struct timeval tv; \ + gettimeofday (&tv, NULL); \ + \ + /* Define the timeout as one hour in the future. */ \ + tmo.tv_sec = tv.tv_sec + 3600; \ + tmo.tv_nsec = 0; \ + } while (0) + + +#define LOCK(m) pthread_mutex_timedlock (m, &tmo) +#include "tst-robust1.c" --- /dev/null +++ b/fbtl/tst-robust4.c @@ -0,0 +1,2 @@ +#define NOT_CONSISTENT 1 +#include "tst-robust1.c" --- /dev/null +++ b/fbtl/tst-robust5.c @@ -0,0 +1,2 @@ +#define NOT_CONSISTENT 1 +#include "tst-robust2.c" --- /dev/null +++ b/fbtl/tst-robust6.c @@ -0,0 +1,2 @@ +#define NOT_CONSISTENT 1 +#include "tst-robust3.c" --- /dev/null +++ b/fbtl/tst-robust7.c @@ -0,0 +1,212 @@ +/* Copyright (C) 2005-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <pthread.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> + + +static pthread_barrier_t b; +static pthread_cond_t c = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t m; +static bool first = true; + + +static void * +tf (void *arg) +{ + long int n = (long int) arg; + + if (pthread_mutex_lock (&m) != 0) + { + printf ("thread %ld: mutex_lock failed\n", n + 1); + exit (1); + } + + int e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("thread %ld: barrier_wait failed\n", n + 1); + exit (1); + } + + e = pthread_cond_wait (&c, &m); + if (first) + { + if (e != 0) + { + printf ("thread %ld: cond_wait failed\n", n + 1); + exit (1); + } + first = false; + } + else + { + if (e != EOWNERDEAD) + { + printf ("thread %ld: cond_wait did not return EOWNERDEAD\n", n + 1); + exit (1); + } + } + + if (pthread_cancel (pthread_self ()) != 0) + { + printf ("thread %ld: cancel failed\n", n + 1); + exit (1); + } + + pthread_testcancel (); + + printf ("thread %ld: testcancel returned\n", n + 1); + exit (1); +} + + +static int +do_test (void) +{ + pthread_mutexattr_t a; + if (pthread_mutexattr_init (&a) != 0) + { + puts ("mutexattr_init failed"); + return 1; + } + + if (pthread_mutexattr_setrobust_np (&a, PTHREAD_MUTEX_ROBUST_NP) != 0) + { + puts ("mutexattr_setrobust failed"); + return 1; + } + +#ifdef ENABLE_PI + if (pthread_mutexattr_setprotocol (&a, PTHREAD_PRIO_INHERIT) != 0) + { + puts ("pthread_mutexattr_setprotocol failed"); + return 1; + } +#endif + + int e; + e = pthread_mutex_init (&m, &a); + if (e != 0) + { +#ifdef ENABLE_PI + if (e == ENOTSUP) + { + puts ("PI robust mutexes not supported"); + return 0; + } +#endif + puts ("mutex_init failed"); + return 1; + } + + if (pthread_mutexattr_destroy (&a) != 0) + { + puts ("mutexattr_destroy failed"); + return 1; + } + + if (pthread_barrier_init (&b, NULL, 2) != 0) + { + puts ("barrier_init failed"); + return 1; + } + +#define N 5 + pthread_t th[N]; + for (long int n = 0; n < N; ++n) + { + if (pthread_create (&th[n], NULL, tf, (void *) n) != 0) + { + printf ("pthread_create loop %ld failed\n", n + 1); + return 1; + } + + e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("parent: barrier_wait failed in round %ld\n", n + 1); + return 1; + } + } + + if (pthread_mutex_lock (&m) != 0) + { + puts ("parent: mutex_lock failed"); + return 1; + } + + if (pthread_mutex_unlock (&m) != 0) + { + puts ("parent: mutex_unlock failed"); + return 1; + } + + if (pthread_cond_broadcast (&c) != 0) + { + puts ("cond_broadcast failed"); + return 1; + } + + for (int n = 0; n < N; ++n) + { + void *res; + if (pthread_join (th[n], &res) != 0) + { + printf ("join round %d failed\n", n + 1); + return 1; + } + if (res != PTHREAD_CANCELED) + { + printf ("thread %d not canceled\n", n + 1); + return 1; + } + } + + e = pthread_mutex_lock (&m); + if (e == 0) + { + puts ("parent: 2nd mutex_lock succeeded"); + return 1; + } + if (e != EOWNERDEAD) + { + puts ("parent: mutex_lock did not return EOWNERDEAD"); + return 1; + } + + if (pthread_mutex_unlock (&m) != 0) + { + puts ("parent: 2nd 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" --- /dev/null +++ b/fbtl/tst-robust8.c @@ -0,0 +1,275 @@ +#include <pthread.h> +#include <signal.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 void prepare (void); +#define PREPARE(argc, argv) prepare () +static int do_test (void); +#define TEST_FUNCTION do_test () +#define TIMEOUT 5 +#include "../test-skeleton.c" + + +static int fd; +#define N 100 + +static void +prepare (void) +{ + fd = create_temp_file ("tst-robust8", NULL); + if (fd == -1) + exit (1); +} + + +#define THESIGNAL SIGKILL +#define ROUNDS 5 +#define THREADS 9 + + +static const struct timespec before = { 0, 0 }; + + +static pthread_mutex_t *map; + + +static void * +tf (void *arg) +{ + long int nr = (long int) arg; + int fct = nr % 3; + + uint8_t state[N]; + memset (state, '\0', sizeof (state)); + + while (1) + { + int r = random () % N; + if (state[r] == 0) + { + int e; + + switch (fct) + { + case 0: + e = pthread_mutex_lock (&map[r]); + if (e != 0) + { + printf ("mutex_lock of %d in thread %ld failed with %d\n", + r, nr, e); + exit (1); + } + state[r] = 1; + break; + case 1: + e = pthread_mutex_timedlock (&map[r], &before); + if (e != 0 && e != ETIMEDOUT) + { + printf ("\ +mutex_timedlock of %d in thread %ld failed with %d\n", + r, nr, e); + exit (1); + } + break; + default: + e = pthread_mutex_trylock (&map[r]); + if (e != 0 && e != EBUSY) + { + printf ("mutex_trylock of %d in thread %ld failed with %d\n", + r, nr, e); + exit (1); + } + break; + } + + if (e == EOWNERDEAD) + pthread_mutex_consistent_np (&map[r]); + + if (e == 0 || e == EOWNERDEAD) + state[r] = 1; + } + else + { + int e = pthread_mutex_unlock (&map[r]); + if (e != 0) + { + printf ("mutex_unlock of %d in thread %ld failed with %d\n", + r, nr, e); + exit (1); + } + + state[r] = 0; + } + } +} + + +static void +child (int round) +{ + for (int thread = 1; thread <= THREADS; ++thread) + { + pthread_t th; + if (pthread_create (&th, NULL, tf, (void *) (long int) thread) != 0) + { + printf ("cannot create thread %d in round %d\n", thread, round); + exit (1); + } + } + + struct timespec ts; + ts.tv_sec = 0; + ts.tv_nsec = 1000000000 / ROUNDS; + while (nanosleep (&ts, &ts) != 0) + /* nothing */; + + /* Time to die. */ + kill (getpid (), THESIGNAL); + + /* We better never get here. */ + abort (); +} + + +static int +do_test (void) +{ + if (ftruncate (fd, N * sizeof (pthread_mutex_t)) != 0) + { + puts ("cannot size new file"); + return 1; + } + + map = mmap (NULL, N * sizeof (pthread_mutex_t), PROT_READ | PROT_WRITE, + MAP_SHARED, fd, 0); + if (map == MAP_FAILED) + { + puts ("mapping failed"); + return 1; + } + + pthread_mutexattr_t ma; + if (pthread_mutexattr_init (&ma) != 0) + { + puts ("mutexattr_init failed"); + return 0; + } + if (pthread_mutexattr_setrobust_np (&ma, PTHREAD_MUTEX_ROBUST_NP) != 0) + { + puts ("mutexattr_setrobust failed"); + return 1; + } + if (pthread_mutexattr_setpshared (&ma, PTHREAD_PROCESS_SHARED) != 0) + { + puts ("mutexattr_setpshared failed"); + return 1; + } +#ifdef ENABLE_PI + if (pthread_mutexattr_setprotocol (&ma, PTHREAD_PRIO_INHERIT) != 0) + { + puts ("pthread_mutexattr_setprotocol failed"); + return 1; + } +#endif + + for (int round = 1; round <= ROUNDS; ++round) + { + for (int n = 0; n < N; ++n) + { + int e = pthread_mutex_init (&map[n], &ma); + if (e == ENOTSUP) + { +#ifdef ENABLE_PI + puts ("cannot support pshared robust PI mutexes"); +#else + puts ("cannot support pshared robust mutexes"); +#endif + return 0; + } + if (e != 0) + { + printf ("mutex_init %d in round %d failed\n", n + 1, round); + return 1; + } + } + + pid_t p = fork (); + if (p == -1) + { + printf ("fork in round %d failed\n", round); + return 1; + } + if (p == 0) + child (round); + + int status; + if (TEMP_FAILURE_RETRY (waitpid (p, &status, 0)) != p) + { + printf ("waitpid in round %d failed\n", round); + return 1; + } + if (!WIFSIGNALED (status)) + { + printf ("child did not die of a signal in round %d\n", round); + return 1; + } + if (WTERMSIG (status) != THESIGNAL) + { + printf ("child did not die of signal %d in round %d\n", + THESIGNAL, round); + return 1; + } + + for (int n = 0; n < N; ++n) + { + int e = pthread_mutex_lock (&map[n]); + if (e != 0 && e != EOWNERDEAD) + { + printf ("mutex_lock %d failed in round %d\n", n + 1, round); + return 1; + } + } + + for (int n = 0; n < N; ++n) + if (pthread_mutex_unlock (&map[n]) != 0) + { + printf ("mutex_unlock %d failed in round %d\n", n + 1, round); + return 1; + } + + for (int n = 0; n < N; ++n) + { + int e = pthread_mutex_destroy (&map[n]); + if (e != 0) + { + printf ("mutex_destroy %d in round %d failed with %d\n", + n + 1, round, e); + printf("nusers = %d\n", (int) map[n].__data.__nusers); + return 1; + } + } + } + + if (pthread_mutexattr_destroy (&ma) != 0) + { + puts ("mutexattr_destroy failed"); + return 1; + } + + if (munmap (map, N * sizeof (pthread_mutex_t)) != 0) + { + puts ("munmap failed"); + return 1; + } + + return 0; +} --- /dev/null +++ b/fbtl/tst-robust9.c @@ -0,0 +1,94 @@ +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <pthread.h> +#include <unistd.h> +#include <sys/time.h> + + +static pthread_mutex_t m; + +static void * +tf (void *data) +{ + int err = pthread_mutex_lock (&m); + if (err == EOWNERDEAD) + { + err = pthread_mutex_consistent_np (&m); + if (err) + { + puts ("pthread_mutex_consistent_np"); + exit (1); + } + } + else if (err) + { + puts ("pthread_mutex_lock"); + exit (1); + } + printf ("thread%ld got the lock.\n", (long int) data); + sleep (1); + /* exit without unlock */ + return NULL; +} + +static int +do_test (void) +{ + int err, i; + pthread_t t[3]; + pthread_mutexattr_t ma; + + pthread_mutexattr_init (&ma); + err = pthread_mutexattr_setrobust_np (&ma, PTHREAD_MUTEX_ROBUST_NP); + if (err) + { + puts ("pthread_mutexattr_setrobust_np"); + return 1; + } +#ifdef ENABLE_PI + if (pthread_mutexattr_setprotocol (&ma, PTHREAD_PRIO_INHERIT) != 0) + { + puts ("pthread_mutexattr_setprotocol failed"); + return 1; + } +#endif + err = pthread_mutex_init (&m, &ma); +#ifdef ENABLE_PI + if (err == ENOTSUP) + { + puts ("PI robust mutexes not supported"); + return 0; + } +#endif + if (err) + { + puts ("pthread_mutex_init"); + return 1; + } + + for (i = 0; i < sizeof (t) / sizeof (t[0]); i++) + { + err = pthread_create (&t[i], NULL, tf, (void *) (long int) i); + if (err) + { + puts ("pthread_create"); + return 1; + } + } + + for (i = 0; i < sizeof (t) / sizeof (t[0]); i++) + { + err = pthread_join (t[i], NULL); + if (err) + { + puts ("pthread_join"); + return 1; + } + } + return 0; +} + +#define TIMEOUT 5 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" --- /dev/null +++ b/fbtl/tst-robustpi1.c @@ -0,0 +1,2 @@ +#define ENABLE_PI 1 +#include "tst-robust1.c" --- /dev/null +++ b/fbtl/tst-robustpi2.c @@ -0,0 +1,2 @@ +#define ENABLE_PI 1 +#include "tst-robust2.c" --- /dev/null +++ b/fbtl/tst-robustpi3.c @@ -0,0 +1,2 @@ +#define ENABLE_PI 1 +#include "tst-robust3.c" --- /dev/null +++ b/fbtl/tst-robustpi4.c @@ -0,0 +1,2 @@ +#define ENABLE_PI 1 +#include "tst-robust4.c" --- /dev/null +++ b/fbtl/tst-robustpi5.c @@ -0,0 +1,2 @@ +#define ENABLE_PI 1 +#include "tst-robust5.c" --- /dev/null +++ b/fbtl/tst-robustpi6.c @@ -0,0 +1,2 @@ +#define ENABLE_PI 1 +#include "tst-robust6.c" --- /dev/null +++ b/fbtl/tst-robustpi7.c @@ -0,0 +1,2 @@ +#define ENABLE_PI 1 +#include "tst-robust7.c" --- /dev/null +++ b/fbtl/tst-robustpi8.c @@ -0,0 +1,2 @@ +#define ENABLE_PI 1 +#include "tst-robust8.c" --- /dev/null +++ b/fbtl/tst-robustpi9.c @@ -0,0 +1,2 @@ +#define ENABLE_PI 1 +#include "tst-robust9.c" --- /dev/null +++ b/fbtl/tst-rwlock1.c @@ -0,0 +1,116 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-rwlock10.c @@ -0,0 +1,20 @@ +/* Test program for timedout read/write lock functions. + Copyright (C) 2003-2013 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, see <http://www.gnu.org/licenses/>. */ + +#define INIT PTHREAD_RWLOCK_INITIALIZER +#include "tst-rwlock8.c" --- /dev/null +++ b/fbtl/tst-rwlock11.c @@ -0,0 +1,20 @@ +/* Test program for timedout read/write lock functions. + Copyright (C) 2003-2013 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, see <http://www.gnu.org/licenses/>. */ + +#define INIT PTHREAD_RWLOCK_INITIALIZER +#include "tst-rwlock9.c" --- /dev/null +++ b/fbtl/tst-rwlock12.c @@ -0,0 +1,207 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-rwlock13.c @@ -0,0 +1,70 @@ +/* Copyright (C) 2004-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-rwlock14.c @@ -0,0 +1,168 @@ +/* Copyright (C) 2004-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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 = (__typeof (ts.tv_nsec)) 0x100001000LL; + if ((__typeof (ts.tv_nsec)) 0x100001000LL != 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" --- /dev/null +++ b/fbtl/tst-rwlock2.c @@ -0,0 +1,168 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> + + +static int +do_test (void) +{ + pthread_rwlock_t r; + pthread_rwlockattr_t at; + int e; + + if (pthread_rwlockattr_init (&at) != 0) + { + puts ("rwlockattr_init failed"); + return 1; + } + puts ("rwlockattr_init succeeded"); + +#ifndef TYPE +# define TYPE PTHREAD_RWLOCK_PREFER_READER_NP +#endif + + if (pthread_rwlockattr_setkind_np (&at, TYPE) != 0) + { + puts ("rwlockattr_setkind failed"); + return 1; + } + puts ("rwlockattr_setkind succeeded"); + + if (pthread_rwlock_init (&r, &at) != 0) + { + puts ("rwlock_init failed"); + return 1; + } + puts ("rwlock_init succeeded"); + + if (pthread_rwlockattr_destroy (&at) != 0) + { + puts ("rwlockattr_destroy failed"); + return 1; + } + puts ("rwlockattr_destroy 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" --- /dev/null +++ b/fbtl/tst-rwlock2a.c @@ -0,0 +1,2 @@ +#define TYPE PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP +#include "tst-rwlock2.c" --- /dev/null +++ b/fbtl/tst-rwlock3.c @@ -0,0 +1,92 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +/* 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" --- /dev/null +++ b/fbtl/tst-rwlock4.c @@ -0,0 +1,189 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-rwlock5.c @@ -0,0 +1,84 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +static int do_test (void); + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" + +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; + } + + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + return 1; + } + + delayed_exit (1); + /* This call should never return. */ + xpthread_mutex_lock (&m); + + puts ("2nd mutex_lock returned"); + return 1; +} --- /dev/null +++ b/fbtl/tst-rwlock6.c @@ -0,0 +1,225 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-rwlock7.c @@ -0,0 +1,181 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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); + } + puts ("child: timedwrlock failed with ETIMEDOUT"); + + 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); + } + puts ("child: timedwrlock failed with EINVAL"); + + 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); + } + printf ("%zu: got timedrdlock\n", cnt); + + 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" --- /dev/null +++ b/fbtl/tst-rwlock8.c @@ -0,0 +1,163 @@ +/* Test program for timedout read/write lock functions. + Copyright (C) 2000-2013 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, see <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-rwlock9.c @@ -0,0 +1,202 @@ +/* Test program for timedout read/write lock functions. + Copyright (C) 2000-2013 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, see <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-sched1.c @@ -0,0 +1,97 @@ +/* Copyright (C) 2003-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-sem1.c @@ -0,0 +1,88 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-sem10.c @@ -0,0 +1,87 @@ +/* Copyright (C) 2007-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2007. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <pthread.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; + if (sem_init (&s, 0, 0) == -1) + { + puts ("sem_init failed"); + return 1; + } + + struct timeval tv; + if (gettimeofday (&tv, NULL) != 0) + { + puts ("gettimeofday failed"); + return 1; + } + + struct timespec ts; + TIMEVAL_TO_TIMESPEC (&tv, &ts); + + /* Set ts to yesterday. */ + ts.tv_sec -= 86400; + + int type_before; + if (pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, &type_before) != 0) + { + puts ("first pthread_setcanceltype failed"); + return 1; + } + + 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; + } + + int type_after; + if (pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, &type_after) != 0) + { + puts ("second pthread_setcanceltype failed"); + return 1; + } + if (type_after != PTHREAD_CANCEL_DEFERRED) + { + puts ("sem_timedwait changed cancellation type"); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" --- /dev/null +++ b/fbtl/tst-sem11-static.c @@ -0,0 +1 @@ +#include "tst-sem11.c" --- /dev/null +++ b/fbtl/tst-sem11.c @@ -0,0 +1,78 @@ +#include <semaphore.h> +#include <stdio.h> +#include <unistd.h> +#include <pthread.h> +#include <internaltypes.h> + +#ifndef SEM_WAIT +# define SEM_WAIT(s) sem_wait (s) +#endif + +static void * +tf (void *arg) +{ +#ifdef PREPARE + PREPARE +#endif + SEM_WAIT (arg); + return NULL; +} + +int +main (void) +{ + int tries = 5; + pthread_t th; + union + { + sem_t s; + struct new_sem ns; + } u; + again: + if (sem_init (&u.s, 0, 0) != 0) + { + puts ("sem_init failed"); + return 1; + } + + if (u.ns.nwaiters != 0) + { + puts ("nwaiters not initialized"); + return 1; + } + + if (pthread_create (&th, NULL, tf, &u.s) != 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; + } + if (r != PTHREAD_CANCELED && --tries > 0) + { + /* Maybe we get the scheduling right the next time. */ + sem_destroy (&u.s); + goto again; + } + + if (u.ns.nwaiters != 0) + { + puts ("nwaiters not reset"); + return 1; + } + + return 0; +} --- /dev/null +++ b/fbtl/tst-sem12-static.c @@ -0,0 +1 @@ +#include "tst-sem12.c" --- /dev/null +++ b/fbtl/tst-sem12.c @@ -0,0 +1,14 @@ +#include <time.h> +#include <sys/time.h> + + +#define PREPARE \ + struct timespec ts; \ + struct timeval tv; \ + gettimeofday (&tv, NULL); \ + TIMEVAL_TO_TIMESPEC (&tv, &ts); \ + ts.tv_sec += 60; + +#define SEM_WAIT(s) sem_timedwait (s, &ts) + +#include "tst-sem11.c" --- /dev/null +++ b/fbtl/tst-sem13.c @@ -0,0 +1,65 @@ +#include <errno.h> +#include <semaphore.h> +#include <stdio.h> +#include <unistd.h> +#include <pthread.h> +#include <internaltypes.h> + + +static int +do_test (void) +{ + union + { + sem_t s; + struct new_sem ns; + } u; + + if (sem_init (&u.s, 0, 0) != 0) + { + puts ("sem_init failed"); + return 1; + } + + struct timespec ts = { 0, 1000000001 }; /* Invalid. */ + errno = 0; + if (sem_timedwait (&u.s, &ts) >= 0) + { + puts ("sem_timedwait did not fail"); + return 1; + } + if (errno != EINVAL) + { + perror ("sem_timedwait did not fail with EINVAL"); + return 1; + } + if (u.ns.nwaiters != 0) + { + printf ("sem_timedwait modified nwaiters: %ld\n", u.ns.nwaiters); + return 1; + } + + ts.tv_sec = /* Invalid. */ -2; + ts.tv_nsec = 0; + errno = 0; + if (sem_timedwait (&u.s, &ts) >= 0) + { + puts ("2nd sem_timedwait did not fail"); + return 1; + } + if (errno != ETIMEDOUT) + { + perror ("2nd sem_timedwait did not fail with ETIMEDOUT"); + return 1; + } + if (u.ns.nwaiters != 0) + { + printf ("2nd sem_timedwait modified nwaiters: %ld\n", u.ns.nwaiters); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" --- /dev/null +++ b/fbtl/tst-sem14.c @@ -0,0 +1,92 @@ +/* Test for sem_post race: bug 14532. + Copyright (C) 2012-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <pthread.h> +#include <semaphore.h> +#include <stdio.h> + +#define NTHREADS 10 +#define NITER 100000 + +sem_t sem; +int c; +volatile int thread_fail; + +static void * +tf (void *arg) +{ + for (int i = 0; i < NITER; i++) + { + if (sem_wait (&sem) != 0) + { + perror ("sem_wait"); + thread_fail = 1; + } + ++c; + if (sem_post (&sem) != 0) + { + perror ("sem_post"); + thread_fail = 1; + } + } + return NULL; +} + +static int +do_test (void) +{ + if (sem_init (&sem, 0, 0) != 0) + { + perror ("sem_init"); + return 1; + } + + pthread_t th[NTHREADS]; + for (int i = 0; i < NTHREADS; i++) + { + if (pthread_create (&th[i], NULL, tf, NULL) != 0) + { + puts ("pthread_create failed"); + return 1; + } + } + + if (sem_post (&sem) != 0) + { + perror ("sem_post"); + return 1; + } + + for (int i = 0; i < NTHREADS; i++) + if (pthread_join (th[i], NULL) != 0) + { + puts ("pthread_join failed"); + return 1; + } + + if (c != NTHREADS * NITER) + { + printf ("c = %d, should be %d\n", c, NTHREADS * NITER); + return 1; + } + return thread_fail; +} + +#define TIMEOUT 10 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" --- /dev/null +++ b/fbtl/tst-sem2.c @@ -0,0 +1,53 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <pthread.h> +#include <semaphore.h> +#include <signal.h> +#include <stdio.h> +#include <unistd.h> + +static int do_test (void); + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" + +static int +do_test (void) +{ + sem_t s; + + if (sem_init (&s, 0, 0) == -1) + { + puts ("init failed"); + return 1; + } + + delayed_exit (1); + + if (TEMP_FAILURE_RETRY (sem_wait (&s)) == -1) + { + puts ("wait failed"); + return 1; + } + + /* We should never get here. */ + puts ("wait succeeded"); + return 1; +} --- /dev/null +++ b/fbtl/tst-sem3.c @@ -0,0 +1,141 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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); +} --- /dev/null +++ b/fbtl/tst-sem4.c @@ -0,0 +1,146 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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; +} --- /dev/null +++ b/fbtl/tst-sem5.c @@ -0,0 +1,93 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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; + } + + struct timespec ts2; + if (clock_gettime (CLOCK_REALTIME, &ts2) != 0) + { + puts ("clock_gettime failed"); + return 1; + } + + if (ts2.tv_sec < ts.tv_sec + || (ts2.tv_sec == ts.tv_sec && ts2.tv_nsec < ts.tv_nsec)) + { + puts ("timeout too short"); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" --- /dev/null +++ b/fbtl/tst-sem6.c @@ -0,0 +1,80 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-sem7.c @@ -0,0 +1,108 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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; +} --- /dev/null +++ b/fbtl/tst-sem8.c @@ -0,0 +1,73 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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; +} --- /dev/null +++ b/fbtl/tst-sem9.c @@ -0,0 +1,80 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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; +} --- /dev/null +++ b/fbtl/tst-setuid1-static.c @@ -0,0 +1 @@ +#include "tst-setuid1.c" --- /dev/null +++ b/fbtl/tst-setuid1.c @@ -0,0 +1,1084 @@ +/* Copyright (C) 2004-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jaku@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, see + <http://www.gnu.org/licenses/>. */ + +#include <pthread.h> +#include <pwd.h> +#include <grp.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/wait.h> +#include <unistd.h> + + +static pthread_barrier_t b3, b4; +static uid_t prev_ruid, prev_euid, prev_suid, nobody_uid; +static gid_t prev_rgid, prev_egid, prev_sgid, nobody_gid; +enum ACTION { PREPARE, SET, CHECK_BEFORE, CHECK_AFTER }; +#define TESTNO(arg) ((long int) (arg) & 0xff) +#define THREADNO(arg) ((long int) (arg) >> 8) + + +static void +check_prev_uid (int tno) +{ + uid_t ruid, euid, suid; + if (getresuid (&ruid, &euid, &suid) < 0) + { + printf ("getresuid failed: %d %m\n", tno); + exit (1); + } + + if (ruid != prev_ruid || euid != prev_euid || suid != prev_suid) + { + printf ("uids before in %d (%d %d %d) != (%d %d %d)\n", tno, + ruid, euid, suid, prev_ruid, prev_euid, prev_suid); + exit (1); + } +} + + +static void +check_prev_gid (int tno) +{ + gid_t rgid, egid, sgid; + if (getresgid (&rgid, &egid, &sgid) < 0) + { + printf ("getresgid failed: %d %m\n", tno); + exit (1); + } + + if (rgid != prev_rgid || egid != prev_egid || sgid != prev_sgid) + { + printf ("gids before in %d (%d %d %d) != (%d %d %d)\n", tno, + rgid, egid, sgid, prev_rgid, prev_egid, prev_sgid); + exit (1); + } +} + + +static void +test_setuid1 (enum ACTION action, int tno) +{ + if (action == PREPARE) + return; + + if (action != CHECK_AFTER) + check_prev_uid (tno); + + if (action == SET && setuid (nobody_uid) < 0) + { + printf ("setuid failed: %m\n"); + exit (1); + } + + if (action != CHECK_BEFORE) + { + uid_t ruid, euid, suid; + if (getresuid (&ruid, &euid, &suid) < 0) + { + printf ("getresuid failed: %d %m\n", tno); + exit (1); + } + + if (ruid != nobody_uid || euid != nobody_uid || suid != nobody_uid) + { + printf ("after setuid %d (%d %d %d) != (%d %d %d)\n", tno, + ruid, euid, suid, nobody_uid, nobody_uid, nobody_uid); + exit (1); + } + } +} + + +static void +test_setuid2 (enum ACTION action, int tno) +{ + if (action == PREPARE) + { + if (setresuid (nobody_uid, nobody_uid, -1) < 0) + { + printf ("setresuid failed: %m\n"); + exit (1); + } + + prev_ruid = nobody_uid; + prev_euid = nobody_uid; + return; + } + + if (action != CHECK_AFTER) + check_prev_uid (tno); + + if (action == SET && setuid (prev_suid) < 0) + { + printf ("setuid failed: %m\n"); + exit (1); + } + + if (action != CHECK_BEFORE) + { + uid_t ruid, euid, suid; + if (getresuid (&ruid, &euid, &suid) < 0) + { + printf ("getresuid failed: %d %m\n", tno); + exit (1); + } + + if (ruid != nobody_uid || euid != prev_suid || suid != prev_suid) + { + printf ("after setuid %d (%d %d %d) != (%d %d %d)\n", tno, + ruid, euid, suid, nobody_uid, prev_suid, prev_suid); + exit (1); + } + } +} + + +static void +test_seteuid1 (enum ACTION action, int tno) +{ + if (action == PREPARE) + return; + + if (action != CHECK_AFTER) + check_prev_uid (tno); + + if (action == SET && seteuid (nobody_uid) < 0) + { + printf ("seteuid failed: %m\n"); + exit (1); + } + + if (action != CHECK_BEFORE) + { + uid_t ruid, euid, suid; + if (getresuid (&ruid, &euid, &suid) < 0) + { + printf ("getresuid failed: %d %m\n", tno); + exit (1); + } + + if (ruid != prev_ruid || euid != nobody_uid || suid != prev_suid) + { + printf ("after seteuid %d (%d %d %d) != (%d %d %d)\n", tno, + ruid, euid, suid, prev_ruid, nobody_uid, prev_suid); + exit (1); + } + } +} + + +static void +test_seteuid2 (enum ACTION action, int tno) +{ + if (action == PREPARE) + { + if (setresuid (nobody_uid, nobody_uid, -1) < 0) + { + printf ("setresuid failed: %m\n"); + exit (1); + } + + prev_ruid = nobody_uid; + prev_euid = nobody_uid; + nobody_uid = prev_suid; + return; + } + + test_seteuid1 (action, tno); +} + + +static void +test_setreuid1 (enum ACTION action, int tno) +{ + if (action == PREPARE) + return; + + if (action != CHECK_AFTER) + check_prev_uid (tno); + + if (action == SET && setreuid (-1, nobody_uid) < 0) + { + printf ("setreuid failed: %m\n"); + exit (1); + } + + if (action != CHECK_BEFORE) + { + uid_t ruid, euid, suid, esuid; + if (getresuid (&ruid, &euid, &suid) < 0) + { + printf ("getresuid failed: %d %m\n", tno); + exit (1); + } + + if (prev_ruid != nobody_uid) + esuid = nobody_uid; + else + esuid = prev_suid; + + if (ruid != prev_ruid || euid != nobody_uid || suid != esuid) + { + printf ("after setreuid %d (%d %d %d) != (%d %d %d)\n", tno, + ruid, euid, suid, prev_ruid, nobody_uid, esuid); + exit (1); + } + } +} + + +static void +test_setreuid2 (enum ACTION action, int tno) +{ + if (action == PREPARE) + return; + + if (action != CHECK_AFTER) + check_prev_uid (tno); + + if (action == SET && setreuid (nobody_uid, -1) < 0) + { + printf ("setreuid failed: %m\n"); + exit (1); + } + + if (action != CHECK_BEFORE) + { + uid_t ruid, euid, suid; + if (getresuid (&ruid, &euid, &suid) < 0) + { + printf ("getresuid failed: %d %m\n", tno); + exit (1); + } + + if (ruid != nobody_uid || euid != prev_euid || suid != prev_euid) + { + printf ("after setreuid %d (%d %d %d) != (%d %d %d)\n", tno, + ruid, euid, suid, nobody_uid, prev_euid, prev_euid); + exit (1); + } + } +} + + +static void +test_setreuid3 (enum ACTION action, int tno) +{ + if (action == PREPARE) + return; + + if (action != CHECK_AFTER) + check_prev_uid (tno); + + if (action == SET && setreuid (nobody_uid, nobody_uid) < 0) + { + printf ("setreuid failed: %m\n"); + exit (1); + } + + if (action != CHECK_BEFORE) + { + uid_t ruid, euid, suid; + if (getresuid (&ruid, &euid, &suid) < 0) + { + printf ("getresuid failed: %d %m\n", tno); + exit (1); + } + + if (ruid != nobody_uid || euid != nobody_uid || suid != nobody_uid) + { + printf ("after setreuid %d (%d %d %d) != (%d %d %d)\n", tno, + ruid, euid, suid, nobody_uid, nobody_uid, nobody_uid); + exit (1); + } + } +} + + +static void +test_setreuid4 (enum ACTION action, int tno) +{ + if (action == PREPARE) + { + if (setresuid (nobody_uid, nobody_uid, -1) < 0) + { + printf ("setresuid failed: %m\n"); + exit (1); + } + + prev_ruid = nobody_uid; + prev_euid = nobody_uid; + nobody_uid = prev_suid; + return; + } + + test_setreuid1 (action, tno); +} + + +static void +test_setresuid1 (enum ACTION action, int tno) +{ + if (action == PREPARE) + return; + + if (action != CHECK_AFTER) + check_prev_uid (tno); + + if (action == SET && setresuid (-1, nobody_uid, -1) < 0) + { + printf ("setresuid failed: %m\n"); + exit (1); + } + + if (action != CHECK_BEFORE) + { + uid_t ruid, euid, suid; + if (getresuid (&ruid, &euid, &suid) < 0) + { + printf ("getresuid failed: %d %m\n", tno); + exit (1); + } + + if (ruid != prev_ruid || euid != nobody_uid || suid != prev_suid) + { + printf ("after setresuid %d (%d %d %d) != (%d %d %d)\n", tno, + ruid, euid, suid, prev_ruid, nobody_uid, prev_suid); + exit (1); + } + } +} + + +static void +test_setresuid2 (enum ACTION action, int tno) +{ + if (action == PREPARE) + return; + + if (action != CHECK_AFTER) + check_prev_uid (tno); + + if (action == SET && setresuid (prev_euid, nobody_uid, nobody_uid) < 0) + { + printf ("setresuid failed: %m\n"); + exit (1); + } + + if (action != CHECK_BEFORE) + { + uid_t ruid, euid, suid; + if (getresuid (&ruid, &euid, &suid) < 0) + { + printf ("getresuid failed: %d %m\n", tno); + exit (1); + } + + if (ruid != prev_euid || euid != nobody_uid || suid != nobody_uid) + { + printf ("after setresuid %d (%d %d %d) != (%d %d %d)\n", tno, + ruid, euid, suid, prev_euid, nobody_uid, nobody_uid); + exit (1); + } + } +} + + +static void +test_setresuid3 (enum ACTION action, int tno) +{ + if (action == PREPARE) + return; + + if (action != CHECK_AFTER) + check_prev_uid (tno); + + if (action == SET && setresuid (nobody_uid, nobody_uid, nobody_uid) < 0) + { + printf ("setresuid failed: %m\n"); + exit (1); + } + + if (action != CHECK_BEFORE) + { + uid_t ruid, euid, suid; + if (getresuid (&ruid, &euid, &suid) < 0) + { + printf ("getresuid failed: %d %m\n", tno); + exit (1); + } + + if (ruid != nobody_uid || euid != nobody_uid || suid != nobody_uid) + { + printf ("after setresuid %d (%d %d %d) != (%d %d %d)\n", tno, + ruid, euid, suid, nobody_uid, nobody_uid, nobody_uid); + exit (1); + } + } +} + + +static void +test_setresuid4 (enum ACTION action, int tno) +{ + if (action == PREPARE) + { + if (setresuid (nobody_uid, nobody_uid, -1) < 0) + { + printf ("setresuid failed: %m\n"); + exit (1); + } + + prev_ruid = nobody_uid; + prev_euid = nobody_uid; + nobody_uid = prev_suid; + return; + } + + test_setresuid1 (action, tno); +} + + +static void +test_setgid1 (enum ACTION action, int tno) +{ + if (action == PREPARE) + return; + + if (action != CHECK_AFTER) + check_prev_gid (tno); + + if (action == SET && setgid (nobody_gid) < 0) + { + printf ("setgid failed: %m\n"); + exit (1); + } + + if (action != CHECK_BEFORE) + { + gid_t rgid, egid, sgid; + if (getresgid (&rgid, &egid, &sgid) < 0) + { + printf ("getresgid failed: %d %m\n", tno); + exit (1); + } + + if (rgid != nobody_gid || egid != nobody_gid || sgid != nobody_gid) + { + printf ("after setgid %d (%d %d %d) != (%d %d %d)\n", tno, + rgid, egid, sgid, nobody_gid, nobody_gid, nobody_gid); + exit (1); + } + } +} + + +static void +test_setgid2 (enum ACTION action, int tno) +{ + if (action == PREPARE) + { + if (setresgid (nobody_gid, nobody_gid, -1) < 0) + { + printf ("setresgid failed: %m\n"); + exit (1); + } + + prev_rgid = nobody_gid; + prev_egid = nobody_gid; + + if (setresuid (nobody_uid, nobody_uid, -1) < 0) + { + printf ("setresuid failed: %m\n"); + exit (1); + } + + prev_ruid = nobody_uid; + prev_euid = nobody_uid; + return; + } + + if (action != CHECK_AFTER) + check_prev_gid (tno); + + if (action == SET && setgid (prev_sgid) < 0) + { + printf ("setgid failed: %m\n"); + exit (1); + } + + if (action != CHECK_BEFORE) + { + gid_t rgid, egid, sgid; + if (getresgid (&rgid, &egid, &sgid) < 0) + { + printf ("getresgid failed: %d %m\n", tno); + exit (1); + } + + if (rgid != nobody_gid || egid != prev_sgid || sgid != prev_sgid) + { + printf ("after setgid %d (%d %d %d) != (%d %d %d)\n", tno, + rgid, egid, sgid, nobody_gid, prev_sgid, prev_sgid); + exit (1); + } + } +} + + +static void +test_setegid1 (enum ACTION action, int tno) +{ + if (action == PREPARE) + return; + + if (action != CHECK_AFTER) + check_prev_gid (tno); + + if (action == SET && setegid (nobody_gid) < 0) + { + printf ("setegid failed: %m\n"); + exit (1); + } + + if (action != CHECK_BEFORE) + { + gid_t rgid, egid, sgid; + if (getresgid (&rgid, &egid, &sgid) < 0) + { + printf ("getresgid failed: %d %m\n", tno); + exit (1); + } + + if (rgid != prev_rgid || egid != nobody_gid || sgid != prev_sgid) + { + printf ("after setegid %d (%d %d %d) != (%d %d %d)\n", tno, + rgid, egid, sgid, prev_rgid, nobody_gid, prev_sgid); + exit (1); + } + } +} + + +static void +test_setegid2 (enum ACTION action, int tno) +{ + if (action == PREPARE) + { + if (setresgid (nobody_gid, nobody_gid, -1) < 0) + { + printf ("setresgid failed: %m\n"); + exit (1); + } + + prev_rgid = nobody_gid; + prev_egid = nobody_gid; + nobody_gid = prev_sgid; + return; + } + + test_setegid1 (action, tno); +} + + +static void +test_setregid1 (enum ACTION action, int tno) +{ + if (action == PREPARE) + return; + + if (action != CHECK_AFTER) + check_prev_gid (tno); + + if (action == SET && setregid (-1, nobody_gid) < 0) + { + printf ("setregid failed: %m\n"); + exit (1); + } + + if (action != CHECK_BEFORE) + { + gid_t rgid, egid, sgid, esgid; + if (getresgid (&rgid, &egid, &sgid) < 0) + { + printf ("getresgid failed: %d %m\n", tno); + exit (1); + } + + if (prev_rgid != nobody_gid) + esgid = nobody_gid; + else + esgid = prev_sgid; + + if (rgid != prev_rgid || egid != nobody_gid || sgid != esgid) + { + printf ("after setregid %d (%d %d %d) != (%d %d %d)\n", tno, + rgid, egid, sgid, prev_rgid, nobody_gid, esgid); + exit (1); + } + } +} + + +static void +test_setregid2 (enum ACTION action, int tno) +{ + if (action == PREPARE) + return; + + if (action != CHECK_AFTER) + check_prev_gid (tno); + + if (action == SET && setregid (nobody_gid, -1) < 0) + { + printf ("setregid failed: %m\n"); + exit (1); + } + + if (action != CHECK_BEFORE) + { + gid_t rgid, egid, sgid; + if (getresgid (&rgid, &egid, &sgid) < 0) + { + printf ("getresgid failed: %d %m\n", tno); + exit (1); + } + + if (rgid != nobody_gid || egid != prev_egid || sgid != prev_egid) + { + printf ("after setregid %d (%d %d %d) != (%d %d %d)\n", tno, + rgid, egid, sgid, nobody_gid, prev_egid, prev_egid); + exit (1); + } + } +} + + +static void +test_setregid3 (enum ACTION action, int tno) +{ + if (action == PREPARE) + return; + + if (action != CHECK_AFTER) + check_prev_gid (tno); + + if (action == SET && setregid (nobody_gid, nobody_gid) < 0) + { + printf ("setregid failed: %m\n"); + exit (1); + } + + if (action != CHECK_BEFORE) + { + gid_t rgid, egid, sgid; + if (getresgid (&rgid, &egid, &sgid) < 0) + { + printf ("getresgid failed: %d %m\n", tno); + exit (1); + } + + if (rgid != nobody_gid || egid != nobody_gid || sgid != nobody_gid) + { + printf ("after setregid %d (%d %d %d) != (%d %d %d)\n", tno, + rgid, egid, sgid, nobody_gid, nobody_gid, nobody_gid); + exit (1); + } + } +} + + +static void +test_setregid4 (enum ACTION action, int tno) +{ + if (action == PREPARE) + { + if (setresgid (nobody_gid, nobody_gid, -1) < 0) + { + printf ("setresgid failed: %m\n"); + exit (1); + } + + prev_rgid = nobody_gid; + prev_egid = nobody_gid; + nobody_gid = prev_sgid; + return; + } + + test_setregid1 (action, tno); +} + + +static void +test_setresgid1 (enum ACTION action, int tno) +{ + if (action == PREPARE) + return; + + if (action != CHECK_AFTER) + check_prev_gid (tno); + + if (action == SET && setresgid (-1, nobody_gid, -1) < 0) + { + printf ("setresgid failed: %m\n"); + exit (1); + } + + if (action != CHECK_BEFORE) + { + gid_t rgid, egid, sgid; + if (getresgid (&rgid, &egid, &sgid) < 0) + { + printf ("getresgid failed: %d %m\n", tno); + exit (1); + } + + if (rgid != prev_rgid || egid != nobody_gid || sgid != prev_sgid) + { + printf ("after setresgid %d (%d %d %d) != (%d %d %d)\n", tno, + rgid, egid, sgid, prev_rgid, nobody_gid, prev_sgid); + exit (1); + } + } +} + + +static void +test_setresgid2 (enum ACTION action, int tno) +{ + if (action == PREPARE) + return; + + if (action != CHECK_AFTER) + check_prev_gid (tno); + + if (action == SET && setresgid (prev_egid, nobody_gid, nobody_gid) < 0) + { + printf ("setresgid failed: %m\n"); + exit (1); + } + + if (action != CHECK_BEFORE) + { + gid_t rgid, egid, sgid; + if (getresgid (&rgid, &egid, &sgid) < 0) + { + printf ("getresgid failed: %d %m\n", tno); + exit (1); + } + + if (rgid != prev_egid || egid != nobody_gid || sgid != nobody_gid) + { + printf ("after setresgid %d (%d %d %d) != (%d %d %d)\n", tno, + rgid, egid, sgid, prev_egid, nobody_gid, nobody_gid); + exit (1); + } + } +} + + +static void +test_setresgid3 (enum ACTION action, int tno) +{ + if (action == PREPARE) + return; + + if (action != CHECK_AFTER) + check_prev_gid (tno); + + if (action == SET && setresgid (nobody_gid, nobody_gid, nobody_gid) < 0) + { + printf ("setresgid failed: %m\n"); + exit (1); + } + + if (action != CHECK_BEFORE) + { + gid_t rgid, egid, sgid; + if (getresgid (&rgid, &egid, &sgid) < 0) + { + printf ("getresgid failed: %d %m\n", tno); + exit (1); + } + + if (rgid != nobody_gid || egid != nobody_gid || sgid != nobody_gid) + { + printf ("after setresgid %d (%d %d %d) != (%d %d %d)\n", tno, + rgid, egid, sgid, nobody_gid, nobody_gid, nobody_gid); + exit (1); + } + } +} + + +static void +test_setresgid4 (enum ACTION action, int tno) +{ + if (action == PREPARE) + { + if (setresgid (nobody_gid, nobody_gid, -1) < 0) + { + printf ("setresgid failed: %m\n"); + exit (1); + } + + prev_rgid = nobody_gid; + prev_egid = nobody_gid; + nobody_gid = prev_sgid; + return; + } + + test_setresgid1 (action, tno); +} + + +static struct setuid_test +{ + const char *name; + void (*test) (enum ACTION, int tno); +} setuid_tests[] = +{ + { "setuid1", test_setuid1 }, + { "setuid2", test_setuid2 }, + { "seteuid1", test_seteuid1 }, + { "seteuid2", test_seteuid2 }, + { "setreuid1", test_setreuid1 }, + { "setreuid2", test_setreuid2 }, + { "setreuid3", test_setreuid3 }, + { "setreuid4", test_setreuid4 }, + { "setresuid1", test_setresuid1 }, + { "setresuid2", test_setresuid2 }, + { "setresuid3", test_setresuid3 }, + { "setresuid4", test_setresuid4 }, + { "setgid1", test_setgid1 }, + { "setgid2", test_setgid2 }, + { "setegid1", test_setegid1 }, + { "setegid2", test_setegid2 }, + { "setregid1", test_setregid1 }, + { "setregid2", test_setregid2 }, + { "setregid3", test_setregid3 }, + { "setregid4", test_setregid4 }, + { "setresgid1", test_setresgid1 }, + { "setresgid2", test_setresgid2 }, + { "setresgid3", test_setresgid3 }, + { "setresgid4", test_setresgid4 } +}; + + +static void * +tf2 (void *arg) +{ + int e = pthread_barrier_wait (&b4); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + exit (1); + } + + setuid_tests[TESTNO (arg)].test (CHECK_AFTER, THREADNO (arg)); + return NULL; +} + + +static void * +tf (void *arg) +{ + setuid_tests[TESTNO (arg)].test (CHECK_BEFORE, THREADNO (arg)); + + int e = pthread_barrier_wait (&b3); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + exit (1); + } + + return tf2 (arg); +} + + +static int +do_one_test (long int testno) +{ + printf ("%s test\n", setuid_tests[testno].name); + + pid_t pid = fork (); + if (pid == 0) + { + setuid_tests[testno].test (PREPARE, 0); + setuid_tests[testno].test (SET, 0); + exit (0); + } + + if (pid < 0) + { + printf ("fork failed: %m\n"); + exit (1); + } + + int status; + if (waitpid (pid, &status, 0) < 0) + { + printf ("waitpid failed: %m\n"); + exit (1); + } + + if (!WIFEXITED (status)) + { + puts ("child did not exit"); + exit (1); + } + + if (WEXITSTATUS (status)) + { + printf ("skipping %s test\n", setuid_tests[testno].name); + return 0; + } + + pid = fork (); + if (pid == 0) + { + setuid_tests[testno].test (PREPARE, 0); + + pthread_t th; + int e = pthread_create (&th, NULL, tf, (void *) (testno | 0x100L)); + if (e != 0) + { + printf ("create failed: %m\n"); + exit (1); + } + + pthread_t th2; + e = pthread_create (&th2, NULL, tf, (void *) (testno | 0x200L)); + if (e != 0) + { + printf ("create failed: %m\n"); + exit (1); + } + + e = pthread_barrier_wait (&b3); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + exit (1); + } + + setuid_tests[testno].test (SET, 0); + + pthread_t th3; + e = pthread_create (&th3, NULL, tf2, (void *) (testno | 0x300L)); + if (e != 0) + { + printf ("create failed: %m\n"); + exit (1); + } + + e = pthread_barrier_wait (&b4); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + exit (1); + } + + exit (0); + } + + if (pid < 0) + { + printf ("fork failed: %m\n"); + exit (1); + } + + if (waitpid (pid, &status, 0) < 0) + { + printf ("waitpid failed: %m\n"); + exit (1); + } + + if (!WIFEXITED (status)) + { + puts ("second child did not exit"); + exit (1); + } + + if (WEXITSTATUS (status)) + exit (WEXITSTATUS (status)); + + return 0; +} + + +static int +do_test (void) +{ + struct passwd *pwd = getpwnam ("nobody"); + if (pwd == NULL) + { + puts ("User nobody doesn't exist"); + return 0; + } + nobody_uid = pwd->pw_uid; + nobody_gid = pwd->pw_gid; + + if (getresuid (&prev_ruid, &prev_euid, &prev_suid) < 0) + { + printf ("getresuid failed: %m\n"); + exit (1); + } + + if (getresgid (&prev_rgid, &prev_egid, &prev_sgid) < 0) + { + printf ("getresgid failed: %m\n"); + exit (1); + } + + if (prev_ruid == nobody_uid || prev_euid == nobody_uid + || prev_suid == nobody_uid) + { + puts ("already running as user nobody, skipping tests"); + exit (0); + } + + if (prev_rgid == nobody_gid || prev_egid == nobody_gid + || prev_sgid == nobody_gid) + { + puts ("already running as group nobody, skipping tests"); + exit (0); + } + + if (pthread_barrier_init (&b3, NULL, 3) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + if (pthread_barrier_init (&b4, NULL, 4) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + for (unsigned long int testno = 0; + testno < sizeof (setuid_tests) / sizeof (setuid_tests[0]); + ++testno) + do_one_test (testno); + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" --- /dev/null +++ b/fbtl/tst-signal1.c @@ -0,0 +1,188 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-signal2.c @@ -0,0 +1,197 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-signal3.c @@ -0,0 +1,260 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-signal4.c @@ -0,0 +1,59 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-signal5.c @@ -0,0 +1,110 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-signal6.c @@ -0,0 +1,191 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-signal7.c @@ -0,0 +1,58 @@ +/* Copyright (C) 2005-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <pthreadP.h> +#include <signal.h> +#include <stdio.h> + + +static int +do_test (void) +{ + int result = 0; + + errno = 0; + if (sigaction (SIGCANCEL, NULL, NULL) == 0) + { + puts ("sigaction(SIGCANCEL) did not fail"); + result = 1; + } + else if (errno != EINVAL) + { + puts ("sigaction(SIGCANCEL) did not set errno to EINVAL"); + result = 1; + } + + errno = 0; + if (sigaction (SIGSETXID, NULL, NULL) == 0) + { + puts ("sigaction(SIGSETXID) did not fail"); + result = 1; + } + else if (errno != EINVAL) + { + puts ("sigaction(SIGSETXID) did not set errno to EINVAL"); + result = 1; + } + + return result; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" --- /dev/null +++ b/fbtl/tst-spin1.c @@ -0,0 +1,56 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-spin2.c @@ -0,0 +1,158 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-spin3.c @@ -0,0 +1,53 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <unistd.h> + +static int do_test (void); + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" + +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; + } + + delayed_exit (1); + + /* This call should never return. */ + xpthread_spin_lock (&s); + + puts ("2nd spin_lock returned"); + return 1; +} --- /dev/null +++ b/fbtl/tst-stack1.c @@ -0,0 +1,145 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-stack2.c @@ -0,0 +1,78 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +/* Test whether it is possible to create a thread with PTHREAD_STACK_MIN + stack size. */ + +#include <pthread.h> +#include <stdlib.h> +#include <stdio.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" --- /dev/null +++ b/fbtl/tst-stack3.c @@ -0,0 +1,100 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +/* Test whether pthread_create/pthread_join with user defined stacks + doesn't leak memory. + NOTE: this tests functionality beyond POSIX. In POSIX user defined + stacks cannot be ever freed once used by pthread_create nor they can + be reused for other thread. */ + +#include <limits.h> +#include <mcheck.h> +#include <pthread.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +static int seen; + +static void * +tf (void *p) +{ + ++seen; + return NULL; +} + +static int +do_test (void) +{ + mtrace (); + + void *stack; + int res = posix_memalign (&stack, getpagesize (), 4 * PTHREAD_STACK_MIN); + if (res) + { + printf ("malloc failed %s\n", strerror (res)); + return 1; + } + + pthread_attr_t attr; + pthread_attr_init (&attr); + + int result = 0; + res = pthread_attr_setstack (&attr, stack, 4 * PTHREAD_STACK_MIN); + if (res) + { + printf ("pthread_attr_setstack failed %d\n", res); + result = 1; + } + + for (int i = 0; i < 16; ++i) + { + /* 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; + } + } + } + + pthread_attr_destroy (&attr); + + if (seen != 16) + { + printf ("seen %d != 16\n", seen); + result = 1; + } + + free (stack); + return result; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" --- /dev/null +++ b/fbtl/tst-stackguard1-static.c @@ -0,0 +1 @@ +#include "tst-stackguard1.c" --- /dev/null +++ b/fbtl/tst-stackguard1.c @@ -0,0 +1,226 @@ +/* Copyright (C) 2005-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <pthread.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/wait.h> +#include <stackguard-macros.h> +#include <tls.h> +#include <unistd.h> + +static const char *command; +static bool child; +static uintptr_t stack_chk_guard_copy; +static bool stack_chk_guard_copy_set; +static int fds[2]; + +static void __attribute__ ((constructor)) +con (void) +{ + stack_chk_guard_copy = STACK_CHK_GUARD; + stack_chk_guard_copy_set = true; +} + +static int +uintptr_t_cmp (const void *a, const void *b) +{ + if (*(uintptr_t *) a < *(uintptr_t *) b) + return 1; + if (*(uintptr_t *) a > *(uintptr_t *) b) + return -1; + return 0; +} + +static void * +tf (void *arg) +{ + if (stack_chk_guard_copy != STACK_CHK_GUARD) + { + puts ("STACK_CHK_GUARD changed in thread"); + return (void *) 1L; + } + return NULL; +} + +static int +do_test (void) +{ + if (!stack_chk_guard_copy_set) + { + puts ("constructor has not been run"); + return 1; + } + + if (stack_chk_guard_copy != STACK_CHK_GUARD) + { + puts ("STACK_CHK_GUARD changed between constructor and do_test"); + return 1; + } + + if (child) + { + int i; + pthread_t th[4]; + void *ret; + for (i = 0; i < 4; ++i) + if (pthread_create (&th[i], NULL, tf, NULL)) + { + puts ("thread creation failed"); + return 1; + } + for (i = 0; i < 4; ++i) + if (pthread_join (th[i], &ret)) + { + puts ("thread join failed"); + return 1; + } + else if (ret != NULL) + return 1; + + write (2, &stack_chk_guard_copy, sizeof (stack_chk_guard_copy)); + return 0; + } + + if (command == NULL) + { + puts ("missing --command or --child argument"); + return 1; + } + +#define N 16 + uintptr_t child_stack_chk_guards[N + 1]; + child_stack_chk_guards[N] = stack_chk_guard_copy; + int i; + for (i = 0; i < N; ++i) + { + if (pipe (fds) < 0) + { + printf ("couldn't create pipe: %m\n"); + return 1; + } + + pid_t pid = fork (); + if (pid < 0) + { + printf ("fork failed: %m\n"); + return 1; + } + + if (!pid) + { + if (stack_chk_guard_copy != STACK_CHK_GUARD) + { + puts ("STACK_CHK_GUARD changed after fork"); + exit (1); + } + + close (fds[0]); + close (2); + dup2 (fds[1], 2); + close (fds[1]); + + system (command); + exit (0); + } + + close (fds[1]); + + if (TEMP_FAILURE_RETRY (read (fds[0], &child_stack_chk_guards[i], + sizeof (uintptr_t))) != sizeof (uintptr_t)) + { + puts ("could not read stack_chk_guard value from child"); + return 1; + } + + close (fds[0]); + + pid_t termpid; + int status; + termpid = TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)); + if (termpid == -1) + { + printf ("waitpid failed: %m\n"); + return 1; + } + else if (termpid != pid) + { + printf ("waitpid returned %ld != %ld\n", + (long int) termpid, (long int) pid); + return 1; + } + else if (!WIFEXITED (status) || WEXITSTATUS (status)) + { + puts ("child hasn't exited with exit status 0"); + return 1; + } + } + + qsort (child_stack_chk_guards, N + 1, sizeof (uintptr_t), uintptr_t_cmp); + + uintptr_t default_guard = 0; + unsigned char *p = (unsigned char *) &default_guard; + p[sizeof (uintptr_t) - 1] = 255; + p[sizeof (uintptr_t) - 2] = '\n'; + p[0] = 0; + + /* Test if the stack guard canaries are either randomized, + or equal to the default stack guard canary value. + Even with randomized stack guards it might happen + that the random number generator generates the same + values, but if that happens in more than half from + the 16 runs, something is very wrong. */ + int ndifferences = 0; + int ndefaults = 0; + for (i = 0; i < N; ++i) + { + if (child_stack_chk_guards[i] != child_stack_chk_guards[i+1]) + ndifferences++; + else if (child_stack_chk_guards[i] == default_guard) + ndefaults++; + } + + printf ("differences %d defaults %d\n", ndifferences, ndefaults); + + if (ndifferences < N / 2 && ndefaults < N / 2) + { + puts ("stack guard canaries are not randomized enough"); + puts ("nor equal to the default canary value"); + return 1; + } + + return 0; +} + +#define OPT_COMMAND 10000 +#define OPT_CHILD 10001 +#define CMDLINE_OPTIONS \ + { "command", required_argument, NULL, OPT_COMMAND }, \ + { "child", no_argument, NULL, OPT_CHILD }, +#define CMDLINE_PROCESS \ + case OPT_COMMAND: \ + command = optarg; \ + break; \ + case OPT_CHILD: \ + child = true; \ + break; +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" --- /dev/null +++ b/fbtl/tst-stdio1.c @@ -0,0 +1,56 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <unistd.h> + +static int do_test (void); + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" + +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); + } + + delayed_exit (1); + xpthread_join (th); + + puts ("join returned"); + + return 1; +} --- /dev/null +++ b/fbtl/tst-stdio2.c @@ -0,0 +1,81 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-sysconf.c @@ -0,0 +1,47 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-tls1.c @@ -0,0 +1,111 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> + + +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; +} + + +int +do_test (void) +{ + 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; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" --- /dev/null +++ b/fbtl/tst-tls2.c @@ -0,0 +1,205 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <pthread.h> +#include <signal.h> +#include <semaphore.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + + +#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; +} + + +int +do_test (void) +{ + 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; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" --- /dev/null +++ b/fbtl/tst-tls3.c @@ -0,0 +1,206 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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> + +#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 ((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); + } + + 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; +} + + +#define TIMEOUT 5 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" --- /dev/null +++ b/fbtl/tst-tls3mod.c @@ -0,0 +1,88 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#include <pthread.h> +#include <semaphore.h> +#include <signal.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <pthreaddef.h> + + +extern pthread_barrier_t b; + +#define TOTAL_SIGS 1000 +extern int nsigs; + +extern sem_t s; + + +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 * +tf (void *arg) +{ + if ((uintptr_t) pthread_self () & (TCB_ALIGNMENT - 1)) + { + puts ("thread's struct pthread not aligned enough"); + exit (1); + } + + if (fp != NULL) + { + 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; +} --- /dev/null +++ b/fbtl/tst-tls4.c @@ -0,0 +1,182 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#include <dlfcn.h> +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <tls.h> + + +#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 () +#include "../test-skeleton.c" --- /dev/null +++ b/fbtl/tst-tls4moda.c @@ -0,0 +1,52 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <tls.h> + + +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; + } +} --- /dev/null +++ b/fbtl/tst-tls4modb.c @@ -0,0 +1,61 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <tls.h> + + +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]; + } +} --- /dev/null +++ b/fbtl/tst-tls5.c @@ -0,0 +1,119 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +/* Check alignment, overlapping and layout of TLS variables. */ +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <pthread.h> +#include <pthreadP.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 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 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" --- /dev/null +++ b/fbtl/tst-tls5.h @@ -0,0 +1,25 @@ +#include <stdint.h> +#include <stdlib.h> +#include <tls.h> + + +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); \ +} --- /dev/null +++ b/fbtl/tst-tls5mod.c @@ -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 --- /dev/null +++ b/fbtl/tst-tls5moda.c @@ -0,0 +1,6 @@ +#include <tst-tls5.h> + +#ifdef TLS_REGISTER +static __thread char a [32] __attribute__ ((aligned (64))); +TLS_REGISTER (a) +#endif --- /dev/null +++ b/fbtl/tst-tls5modb.c @@ -0,0 +1,6 @@ +#include <tst-tls5.h> + +#ifdef TLS_REGISTER +static __thread int b; +TLS_REGISTER (b) +#endif --- /dev/null +++ b/fbtl/tst-tls5modc.c @@ -0,0 +1,6 @@ +#include <tst-tls5.h> + +#ifdef TLS_REGISTER +static __thread int c; +TLS_REGISTER (c) +#endif --- /dev/null +++ b/fbtl/tst-tls5modd.c @@ -0,0 +1,6 @@ +#include <tst-tls5.h> + +#ifdef TLS_REGISTER +static __thread int d; +TLS_REGISTER (d) +#endif --- /dev/null +++ b/fbtl/tst-tls5mode.c @@ -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 --- /dev/null +++ b/fbtl/tst-tls5modf.c @@ -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 --- /dev/null +++ b/fbtl/tst-tls6.sh @@ -0,0 +1,76 @@ +#! /bin/bash +# A tls test. +# Copyright (C) 2003-2013 Free Software Foundation, Inc. +# This file is part of the GNU C Library. + +# The GNU C Library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. + +# The GNU C Library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. + +# You should have received a copy of the GNU Lesser General Public +# License along with the GNU C Library; if not, see +# <http://www.gnu.org/licenses/>. + +set -e + +common_objpfx=$1; shift +test_via_rtld_prefix=$1; shift +test_wrapper_env=$1; shift +logfile=$common_objpfx/fbtl/tst-tls6.out + +# We have to find libc and fbtl +library_path=${common_objpfx}:${common_objpfx}fbtl +tst_tls5="${test_via_rtld_prefix} ${common_objpfx}/fbtl/tst-tls5" + +LC_ALL=C +export LC_ALL +LANG=C +export LANG + +> $logfile +fail=0 + +for aligned in a e f; do + echo "preload tst-tls5mod{$aligned,b,c,d}.so" >> $logfile + echo "===============" >> $logfile + ${test_wrapper_env} \ + LD_PRELOAD="`echo ${common_objpfx}fbtl/tst-tls5mod{$aligned,b,c,d}.so \ + | sed 's/:$//;s/: /:/g'`" ${tst_tls5} >> $logfile || fail=1 + echo >> $logfile + + echo "preload tst-tls5mod{b,$aligned,c,d}.so" >> $logfile + echo "===============" >> $logfile + ${test_wrapper_env} \ + LD_PRELOAD="`echo ${common_objpfx}fbtl/tst-tls5mod{b,$aligned,c,d}.so \ + | sed 's/:$//;s/: /:/g'`" ${tst_tls5} >> $logfile || fail=1 + echo >> $logfile + + echo "preload tst-tls5mod{b,c,d,$aligned}.so" >> $logfile + echo "===============" >> $logfile + ${test_wrapper_env} \ + LD_PRELOAD="`echo ${common_objpfx}fbtl/tst-tls5mod{b,c,d,$aligned}.so \ + | sed 's/:$//;s/: /:/g'`" ${tst_tls5} >> $logfile || fail=1 + echo >> $logfile +done + +echo "preload tst-tls5mod{d,a,b,c,e}" >> $logfile +echo "===============" >> $logfile +${test_wrapper_env} \ +LD_PRELOAD="`echo ${common_objpfx}fbtl/tst-tls5mod{d,a,b,c,e}.so \ + | sed 's/:$//;s/: /:/g'`" ${tst_tls5} >> $logfile || fail=1 +echo >> $logfile + +echo "preload tst-tls5mod{d,a,b,e,f}" >> $logfile +echo "===============" >> $logfile +${test_wrapper_env} \ +LD_PRELOAD="`echo ${common_objpfx}fbtl/tst-tls5mod{d,a,b,e,f}.so \ + | sed 's/:$//;s/: /:/g'`" ${tst_tls5} >> $logfile || fail=1 +echo >> $logfile + +exit $fail --- /dev/null +++ b/fbtl/tst-tpp.h @@ -0,0 +1,93 @@ +/* Copyright (C) 2006-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <pthread.h> +#include <sched.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/syscall.h> + +/* This test is Linux specific. */ +#define CHECK_TPP_PRIORITY(normal, boosted) \ + do \ + { \ + pid_t tid = syscall (__NR_gettid); \ + \ + struct sched_param cep_sp; \ + int cep_policy; \ + if (pthread_getschedparam (pthread_self (), &cep_policy, \ + &cep_sp) != 0) \ + { \ + puts ("getschedparam failed"); \ + ret = 1; \ + } \ + else if (cep_sp.sched_priority != (normal)) \ + { \ + printf ("unexpected priority %d != %d\n", \ + cep_sp.sched_priority, (normal)); \ + } \ + if (syscall (__NR_sched_getparam, tid, &cep_sp) == 0 \ + && cep_sp.sched_priority != (boosted)) \ + { \ + printf ("unexpected boosted priority %d != %d\n", \ + cep_sp.sched_priority, (boosted)); \ + ret = 1; \ + } \ + } \ + while (0) + +int fifo_min, fifo_max; + +void +init_tpp_test (void) +{ + fifo_min = sched_get_priority_min (SCHED_FIFO); + if (fifo_min < 0) + { + printf ("couldn't get min priority for SCHED_FIFO: %m\n"); + exit (1); + } + + fifo_max = sched_get_priority_max (SCHED_FIFO); + if (fifo_max < 0) + { + printf ("couldn't get max priority for SCHED_FIFO: %m\n"); + exit (1); + } + + if (fifo_min > 4 || fifo_max < 10) + { + printf ("%d..%d SCHED_FIFO priority interval not suitable for this test\n", + fifo_min, fifo_max); + exit (0); + } + + struct sched_param sp; + memset (&sp, 0, sizeof (sp)); + sp.sched_priority = 4; + int e = pthread_setschedparam (pthread_self (), SCHED_FIFO, &sp); + if (e != 0) + { + errno = e; + printf ("cannot set scheduling params: %m\n"); + exit (0); + } +} --- /dev/null +++ b/fbtl/tst-tsd1.c @@ -0,0 +1,117 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-tsd2.c @@ -0,0 +1,96 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-tsd3.c @@ -0,0 +1,128 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-tsd4.c @@ -0,0 +1,102 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-tsd5.c @@ -0,0 +1,80 @@ +/* Copyright (C) 2004-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-tsd6.c @@ -0,0 +1,89 @@ +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/wait.h> + +#define NKEYS 100 +static pthread_key_t keys[NKEYS]; +static pthread_barrier_t b; + + +static void * +tf (void *arg) +{ + void *res = NULL; + for (int i = 0; i < NKEYS; ++i) + { + void *p = pthread_getspecific (keys[i]); + pthread_setspecific (keys[i], (void *) 7); + if (p != NULL) + res = p; + } + if (arg != NULL) + { + pthread_barrier_wait (arg); + pthread_barrier_wait (arg); + } + return res; +} + + +static int +do_test (void) +{ + pthread_barrier_init (&b, NULL, 2); + + for (int i = 0; i < NKEYS; ++i) + if (pthread_key_create (&keys[i], NULL) != 0) + { + puts ("cannot create keys"); + return 1; + } + + pthread_t th; + if (pthread_create (&th, NULL, tf, &b) != 0) + { + puts ("cannot create thread in parent"); + return 1; + } + + pthread_barrier_wait (&b); + + pid_t pid = fork (); + if (pid == 0) + { + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("cannot create thread in child"); + exit (1); + } + + void *res; + pthread_join (th, &res); + + exit (res != NULL); + } + else if (pid == -1) + { + puts ("cannot create child process"); + return 1; + } + + int s; + if (TEMP_FAILURE_RETRY (waitpid (pid, &s, 0)) != pid) + { + puts ("failing to wait for child process"); + return 1; + } + + pthread_barrier_wait (&b); + pthread_join (th, NULL); + + return !WIFEXITED (s) ? 2 : WEXITSTATUS (s); +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" --- /dev/null +++ b/fbtl/tst-typesizes.c @@ -0,0 +1,95 @@ +/* Copyright (C) 2005-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#include <stdio.h> +#include <pthreadP.h> +#include <semaphore.h> + +static const struct +{ + const char *name; + size_t expected; + size_t is; +} types[] = + { +#define T(t, c) \ + { #t, c, sizeof (t) } + T (pthread_attr_t, __SIZEOF_PTHREAD_ATTR_T), + T (pthread_mutex_t, __SIZEOF_PTHREAD_MUTEX_T), + T (pthread_mutexattr_t, __SIZEOF_PTHREAD_MUTEXATTR_T), + T (pthread_cond_t, __SIZEOF_PTHREAD_COND_T), + T (pthread_condattr_t, __SIZEOF_PTHREAD_CONDATTR_T), + T (pthread_rwlock_t, __SIZEOF_PTHREAD_RWLOCK_T), + T (pthread_rwlockattr_t, __SIZEOF_PTHREAD_RWLOCKATTR_T), + T (pthread_barrier_t, __SIZEOF_PTHREAD_BARRIER_T), + T (pthread_barrierattr_t, __SIZEOF_PTHREAD_BARRIERATTR_T) + }; + +static int +do_test (void) +{ + int result = 0; + +#define TEST_TYPE(name) \ + printf ("%s: ", #name); \ + if (sizeof (name) != sizeof (((name *) 0)->__size)) \ + { \ + printf ("expected %zu, is %zu\n", \ + sizeof (((name *) 0)->__size), sizeof (name)); \ + result = 1; \ + } \ + else \ + puts ("OK") + + TEST_TYPE (pthread_mutex_t); + TEST_TYPE (pthread_cond_t); + TEST_TYPE (pthread_rwlock_t); + +#define TEST_TYPE2(name, internal) \ + printf ("%s: ", #name); \ + if (sizeof (((name *) 0)->__size) < sizeof (internal)) \ + { \ + printf ("expected %zu, is %zu\n", \ + sizeof (((name *) 0)->__size), sizeof (internal)); \ + result = 1; \ + } \ + else \ + puts ("OK") + + TEST_TYPE2 (pthread_attr_t, struct pthread_attr); + TEST_TYPE2 (pthread_mutexattr_t, struct pthread_mutexattr); + TEST_TYPE2 (pthread_condattr_t, struct pthread_condattr); + TEST_TYPE2 (pthread_rwlockattr_t, struct pthread_rwlockattr); + TEST_TYPE2 (pthread_barrier_t, struct pthread_barrier); + TEST_TYPE2 (pthread_barrierattr_t, struct pthread_barrierattr); + TEST_TYPE2 (sem_t, struct new_sem); + TEST_TYPE2 (sem_t, struct old_sem); + + for (size_t i = 0; i < sizeof (types) / sizeof (types[0]); ++i) + if (types[i].expected != types[i].is) + { + printf ("%s: expected %zu, is %zu\n", + types[i].name, types[i].expected, types[i].is); + result = 1; + } + + return result; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" --- /dev/null +++ b/fbtl/tst-umask1.c @@ -0,0 +1,136 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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" --- /dev/null +++ b/fbtl/tst-unload.c @@ -0,0 +1,47 @@ +/* Tests for non-unloading of libpthread. + Copyright (C) 2000-2013 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, see <http://www.gnu.org/licenses/>. */ + +#include <dlfcn.h> +#include <stdio.h> +#include <stdlib.h> +#include <gnu/lib-names.h> + +static int +do_test (void) +{ + void *p = dlopen (LIBPTHREAD_SO, RTLD_LAZY); + + if (p == NULL) + { + puts ("failed to load " LIBPTHREAD_SO); + return 1; + } + + if (dlclose (p) != 0) + { + puts ("dlclose (" LIBPTHREAD_SO ") failed"); + return 1; + } + + puts ("seems to work"); + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" --- /dev/null +++ b/fbtl/tst-vfork1.c @@ -0,0 +1 @@ +#include <posix/tst-vfork1.c> --- /dev/null +++ b/fbtl/tst-vfork1x.c @@ -0,0 +1 @@ +#include <posix/tst-vfork1.c> --- /dev/null +++ b/fbtl/tst-vfork2.c @@ -0,0 +1 @@ +#include <posix/tst-vfork2.c> --- /dev/null +++ b/fbtl/tst-vfork2x.c @@ -0,0 +1 @@ +#include <posix/tst-vfork2.c> --- /dev/null +++ b/fbtl/unwind.c @@ -0,0 +1,148 @@ +/* Copyright (C) 2003-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#include <setjmp.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "pthreadP.h" +#include <jmpbuf-unwind.h> + +#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 (__glibc_unlikely (curp != NULL)) + { + /* 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_Ptr) _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. */ +#if 0 // does not work due to multiple macro expansions +# 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")); +#else +# define UNWIND_FAILED_MSG "FATAL: exception not rethrown\n" + INTERNAL_SYSCALL_DECL (err); + INTERNAL_SYSCALL (write, err, 3, STDERR_FILENO, + UNWIND_FAILED_MSG, strlen(UNWIND_FAILED_MSG)); +#endif + abort (); +} + + +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; + + /* 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); + /* 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) --- /dev/null +++ b/fbtl/vars.c @@ -0,0 +1,43 @@ +/* Copyright (C) 2004-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <pthreadP.h> +#include <stdlib.h> +#include <tls.h> +#include <unistd.h> + +/* Default thread attributes for the case when the user does not + provide any. */ +struct pthread_attr __default_pthread_attr attribute_hidden; + +/* Mutex protecting __default_pthread_attr. */ +int __default_pthread_attr_lock = LLL_LOCK_INITIALIZER; + +/* 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 either if more than one thread runs or ran, + or if a single-threaded process is trying to cancel itself. See + nptl/descr.h for more context on the single-threaded process case. */ +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) --- /dev/null +++ b/fbtl/version.c @@ -0,0 +1,42 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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" +"Forced unwind support included.\n" +; + + +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); +} --- /dev/null +++ b/fbtl_db/ChangeLog @@ -0,0 +1,333 @@ +2013-05-31 Joseph Myers <joseph@codesourcery.com> + + * Makefile ($(objpfx)libthread_db.so): Remove dependencies on + libc. + +2013-05-16 Ryan S. Arnold <rsa@linux.vnet.ibm.com> + + * db_info.c: Add missing #include <stdint.h> due to uint64_t or + uint32_t usage. + * fetch-value.c: Likewise. + * td_ta_clear_event.c: Likewise. + * td_ta_set_event.c: Likewise. + * td_ta_tsd_iter.c: Likewise. + * td_thr_clear_event.c: Likewise. + * td_thr_get_info.c: Likewise. + * td_thr_set_event.c: Likewise. + * td_thr_tsd.c: Likewise. + +2013-01-02 Joseph Myers <joseph@codesourcery.com> + + * All files with FSF copyright notices: Update copyright dates + using scripts/update-copyrights. + +2013-01-01 Joseph Myers <joseph@codesourcery.com> + + * td_ta_thr_iter.c: Reformat copyright notice. + * td_thr_validate.c: Likewise. + +2012-11-23 Mike Frysinger <vapier@gentoo.org> + + * Makefile ($(objpfx)db-symbols.out): Change readelf to $(READELF). + +2012-10-08 Jonathan Nieder <jrnieder@gmail.com> + + [BZ #14661] + * Makefile ($(objpfx)db-symbols.out): Force C locale when running + readelf -s. + +2012-03-07 Ulrich Drepper <drepper@gmail.com> + + * Makefile (distribute): Remove variable. + +2011-09-15 Andreas Schwab <schwab@redhat.com> + + * thread_dbP.h: Include <list.h> + +2009-08-23 Roland McGrath <roland@redhat.com> + + * td_ta_map_lwp2thr.c (__td_ta_lookup_th_unique): Move ta_ok check + and LOG call back to ... + (td_ta_map_lwp2thr): ... here. + Reported by Maciej W. Rozycki <macro@codesourcery.com>. + +2009-05-25 Aurelien Jarno <aurelien@aurel32.net> + + [BZ #10200] + * db-symbols.awk: Use the last field for the symbol name instead + of the 8th one. + +2009-03-19 Roland McGrath <roland@redhat.com> + + * td_symbol_list.c (DB_LOOKUP_NAME, DB_LOOKUP_NAME_TH_UNIQUE): + Use STRINGIFY macro in place of #argument. + +2009-02-27 Roland McGrath <roland@redhat.com> + + * td_symbol_list.c (symbol_list_arr): Move initializer guts to ... + * db-symbols.h: ... here, new file. + * db-symbols.awk: New file. + * Makefile (distribute): Add them. + ($(objpfx)db-symbols.out): New target. + (tests): Depend on it. + ($(objpfx)db-symbols.v.i): New dependent rule. + +2009-02-06 Ulrich Drepper <drepper@redhat.com> + + * td_thr_get_info.c (td_thr_get_info): Initialize schedpolicy in + the special case [Coverity CID 251]. + +2008-03-25 Roland McGrath <roland@redhat.com> + + [BZ #5983] + * structs.def: Add pid field of struct pthread. + * td_ta_thr_iter.c (iterate_thread_list): Take new arg MATCH_PID. + If a thread's pid does not match nor is < 0 while its tid matches + nor is < 0 and equal to -MATCH_PID, ignore it. + * td_thr_validate.c (td_thr_validate): Validate thread's pid/tid. + +2007-05-16 Roland McGrath <roland@redhat.com> + + * td_thr_get_info.c: Fake the results for TH->th_unique == 0. + * td_thr_validate.c: Likewise. + * td_thr_setgregs.c: Likewise. + * td_thr_setfpregs.c: Likewise. + * td_thr_getgregs.c: Likewise. + * td_thr_getfpregs.c: Likewise. + * td_thr_tlsbase.c: Likewise. + + * structs.def: Add DB_VARIABLE (__nptl_initial_report_events). + * db_info.c: Add necessary declaration. + * td_thr_event_enable.c: Set __nptl_initial_report_events too. + + * td_ta_thr_iter.c (iterate_thread_list): Make FAKE_EMPTY bool. + Use th_unique=0 in fake descriptor before initialization. + + * td_ta_map_lwp2thr.c (__td_ta_lookup_th_unique): New function, broken + out of ... + (td_ta_map_lwp2thr): ... here, call it. But don't before __stack_user + is initialized, then fake a handle with th_unique=0. + * thread_dbP.h: Declare it. + +2006-10-26 Pete Eberlein <eberlein@us.ibm.com> + + * nptl_db/db_info.c [TLS_DTV_AT_TP]: Fixed size init for dtvp + to sizeof a pointer, instead of sizeof the union. + +2006-10-27 Ulrich Drepper <drepper@redhat.com> + + * structs.def: USE_TLS support is now default. + +2006-02-03 Roland McGrath <roland@redhat.com> + + * structs.def: Add a descriptor for pointer.val field of dtv_t. + * td_thr_tlsbase.c (td_thr_tlsbase): Extract pointer.val field from + DTV slot. + +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. --- /dev/null +++ b/fbtl_db/Makefile @@ -0,0 +1,59 @@ +# Copyright (C) 2002-2013 Free Software Foundation, Inc. +# This file is part of the GNU C Library. + +# The GNU C Library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. + +# The GNU C Library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. + +# You should have received a copy of the GNU Lesser General Public +# License along with the GNU C Library; if not, see +# <http://www.gnu.org/licenses/>. + +# Makefile for NPTL debug library subdirectory of GNU C Library. + +subdir := fbtl_db + +fbtl_db-version = 1.0 + +extra-libs = libthread_db +extra-libs-others := $(extra-libs) + +headers = thread_db.h + +libthread_db-routines = td_init td_log td_ta_new td_ta_delete \ + td_ta_get_nthreads td_ta_get_ph \ + td_ta_map_id2thr td_ta_map_lwp2thr \ + td_ta_thr_iter td_ta_tsd_iter \ + td_thr_get_info td_thr_getfpregs td_thr_getgregs \ + td_thr_getxregs td_thr_getxregsize td_thr_setfpregs \ + td_thr_setgregs td_thr_setprio td_thr_setsigpending \ + td_thr_setxregs td_thr_sigsetmask td_thr_tsd \ + td_thr_validate td_thr_dbsuspend td_thr_dbresume \ + td_ta_setconcurrency td_ta_enable_stats \ + td_ta_reset_stats td_ta_get_stats td_ta_event_addr \ + td_thr_event_enable td_thr_set_event \ + td_thr_clear_event td_thr_event_getmsg \ + td_ta_set_event td_ta_event_getmsg \ + td_ta_clear_event td_symbol_list \ + td_thr_tlsbase td_thr_tls_get_addr \ + fetch-value + +libthread_db-inhibit-o = $(filter-out .os,$(object-suffixes)) + +# The ps_* callback functions are not defined. +libthread_db.so-no-z-defs = yes + +include ../Rules + +tests: $(objpfx)db-symbols.out +$(objpfx)db-symbols.out: $(objpfx)db-symbols.v.i \ + $(common-objpfx)fbtl/libpthread.so + LC_ALL=C $(READELF) -W -s $(filter %.so,$^) | $(AWK) -f $< > $@ + +$(objpfx)db-symbols.v.i: db-symbols.awk --- /dev/null +++ b/fbtl_db/Versions @@ -0,0 +1,24 @@ +libthread_db { + GLIBC_2.1.3 { + # t* + td_init; td_log; td_ta_clear_event; td_ta_delete; td_ta_enable_stats; + td_ta_event_addr; td_ta_event_getmsg; td_ta_get_nthreads; td_ta_get_ph; + td_ta_get_stats; td_ta_map_id2thr; td_ta_map_lwp2thr; td_ta_new; + td_ta_reset_stats; td_ta_set_event; td_ta_setconcurrency; + td_ta_thr_iter; td_ta_tsd_iter; td_thr_clear_event; td_thr_dbresume; + td_thr_dbsuspend; td_thr_event_enable; td_thr_event_getmsg; + td_thr_get_info; td_thr_getfpregs; td_thr_getgregs; td_thr_getxregs; + td_thr_getxregsize; td_thr_set_event; td_thr_setfpregs; td_thr_setgregs; + td_thr_setprio; td_thr_setsigpending; td_thr_setxregs; td_thr_sigsetmask; + td_thr_tsd; td_thr_validate; + } + GLIBC_2.2.3 { + td_symbol_list; + } + GLIBC_2.3 { + td_thr_tls_get_addr; + } + GLIBC_2.3.3 { + td_thr_tlsbase; + } +} --- /dev/null +++ b/fbtl_db/db-symbols.awk @@ -0,0 +1,47 @@ +# This script processes the output of 'readelf -W -s' on the libpthread.so +# we've just built. It checks for all the symbols used in td_symbol_list. + +BEGIN { +%define DB_RTLD_VARIABLE(name) /* Nothing. */ +%define DB_MAIN_VARIABLE(name) /* Nothing. */ +%define DB_LOOKUP_NAME(idx, name) required[STRINGIFY (name)] = 1; +%define DB_LOOKUP_NAME_TH_UNIQUE(idx, name) th_unique[STRINGIFY (name)] = 1; +%include "db-symbols.h" + + in_symtab = 0; +} + +/Symbol table '.symtab'/ { in_symtab=1; next } +NF == 0 { in_symtab=0; next } + +!in_symtab { next } + +NF >= 8 && $7 != "UND" { seen[$NF] = 1 } + +END { + status = 0; + + for (s in required) { + if (s in seen) print s, "ok"; + else { + status = 1; + print s, "***MISSING***"; + } + } + + any = ""; + for (s in th_unique) { + if (s in seen) { + any = s; + break; + } + } + if (any) + print "th_unique:", any; + else { + status = 1; + print "th_unique:", "***MISSING***"; + } + + exit(status); +} --- /dev/null +++ b/fbtl_db/db-symbols.h @@ -0,0 +1,55 @@ +/* List of symbols in libpthread examined by libthread_db. + Copyright (C) 2009-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_ASM_GLOBAL_DOT_NAME +# define DOT(x) .##x /* PPC64 requires . prefix on code symbols. */ +#else +# define DOT(x) x /* No prefix. */ +#endif + +#define STRINGIFY(name) STRINGIFY_1(name) +#define STRINGIFY_1(name) #name + +#define DB_STRUCT(type) \ + DB_LOOKUP_NAME (SYM_SIZEOF_##type, _thread_db_sizeof_##type) +#define DB_STRUCT_FIELD(type, field) \ + DB_LOOKUP_NAME (SYM_##type##_FIELD_##field, _thread_db_##type##_##field) +#define DB_SYMBOL(name) \ + DB_LOOKUP_NAME (SYM_##name, name) +#define DB_FUNCTION(name) \ + DB_LOOKUP_NAME (SYM_##name, DOT (name)) +#define DB_VARIABLE(name) \ + DB_LOOKUP_NAME (SYM_##name, name) \ + DB_LOOKUP_NAME (SYM_DESC_##name, _thread_db_##name) + +# include "structs.def" + +# undef DB_STRUCT +# undef DB_FUNCTION +# undef DB_SYMBOL +# undef DB_VARIABLE +# undef DOT + +DB_LOOKUP_NAME_TH_UNIQUE (SYM_TH_UNIQUE_REGISTER64, _thread_db_register64) +DB_LOOKUP_NAME_TH_UNIQUE (SYM_TH_UNIQUE_REGISTER32, _thread_db_register32) +DB_LOOKUP_NAME_TH_UNIQUE (SYM_TH_UNIQUE_CONST_THREAD_AREA, + _thread_db_const_thread_area) +DB_LOOKUP_NAME_TH_UNIQUE (SYM_TH_UNIQUE_REGISTER32_THREAD_AREA, + _thread_db_register32_thread_area) +DB_LOOKUP_NAME_TH_UNIQUE (SYM_TH_UNIQUE_REGISTER64_THREAD_AREA, + _thread_db_register64_thread_area) --- /dev/null +++ b/fbtl_db/db_info.c @@ -0,0 +1,109 @@ +/* This file is included by pthread_create.c to define in libpthread + all the magic symbols required by libthread_db. + + Copyright (C) 2003-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <stdint.h> +#include "thread_dbP.h" +#include <tls.h> +#include <ldsodefs.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; +typedef struct rtld_global rtld_global; +typedef struct dtv_slotinfo_list dtv_slotinfo_list; +typedef struct dtv_slotinfo dtv_slotinfo; + +/* Actually static in nptl/init.c, but we only need it for typeof. */ +extern bool __nptl_initial_report_events; + +#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 TLS_TCB_AT_TP +# define dtvp header.dtv +#elif 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 --- /dev/null +++ b/fbtl_db/fetch-value.c @@ -0,0 +1,285 @@ +/* Helper routines for libthread_db. + Copyright (C) 2003-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include "thread_dbP.h" +#include <byteswap.h> +#include <assert.h> +#include <stdint.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 && DB_DESC_NELEM (desc) != 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; +} --- /dev/null +++ b/fbtl_db/proc_service.h @@ -0,0 +1,86 @@ +/* Callback interface for libthread_db, functions users must define. + Copyright (C) 1999-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +/* 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); --- /dev/null +++ b/fbtl_db/shlib-versions @@ -0,0 +1,2 @@ +# The thread debug library +libthread_db=1 --- /dev/null +++ b/fbtl_db/structs.def @@ -0,0 +1,123 @@ +/* List of types and symbols in libpthread examined by libthread_db. + Copyright (C) 2003-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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 + +#ifndef DB_RTLD_VARIABLE +# define DB_RTLD_VARIABLE(name) DB_VARIABLE (name) +#endif + +#ifndef DB_MAIN_VARIABLE +# define DB_MAIN_VARIABLE(name) DB_VARIABLE (name) +#endif + +#ifndef DB_RTLD_GLOBAL_FIELD +# if !IS_IN (libpthread) +# define DB_RTLD_GLOBAL_FIELD(field) \ + DB_STRUCT_FIELD (rtld_global, _##field) \ + DB_MAIN_VARIABLE (_##field) +# elif defined SHARED +# define DB_RTLD_GLOBAL_FIELD(field) \ + DB_STRUCT_FIELD (rtld_global, _##field) +# else +# define DB_RTLD_GLOBAL_FIELD(field) \ + DB_MAIN_VARIABLE (_##field) +# endif +#endif /* DB_RTLD_GLOBAL_FIELD */ + +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_VARIABLE (__nptl_initial_report_events) + +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) + +DB_STRUCT_FIELD (link_map, l_tls_modid) +DB_STRUCT_FIELD (link_map, l_tls_offset) + +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) +DB_STRUCT_FIELD (dtv_t, counter) +#if !IS_IN (libpthread) || TLS_TCB_AT_TP +DB_STRUCT_FIELD (pthread, dtvp) +#endif + +#if !(IS_IN (libpthread) && !defined SHARED) +DB_STRUCT (rtld_global) +DB_RTLD_VARIABLE (_rtld_global) +#endif +DB_RTLD_GLOBAL_FIELD (dl_tls_dtv_slotinfo_list) + +DB_STRUCT (dtv_slotinfo_list) +DB_STRUCT_FIELD (dtv_slotinfo_list, len) +DB_STRUCT_FIELD (dtv_slotinfo_list, next) +DB_STRUCT_ARRAY_FIELD (dtv_slotinfo_list, slotinfo) + +DB_STRUCT (dtv_slotinfo) +DB_STRUCT_FIELD (dtv_slotinfo, gen) +DB_STRUCT_FIELD (dtv_slotinfo, map) + +#ifdef STRUCTS_DEF_DEFAULTS +# undef DB_STRUCT_ARRAY_FIELD +# undef DB_ARRAY_VARIABLE +# undef STRUCTS_DEF_DEFAULTS +#endif --- /dev/null +++ b/fbtl_db/td_init.c @@ -0,0 +1,31 @@ +/* Initialization function of thread debugger support library. + Copyright (C) 1999-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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; +} --- /dev/null +++ b/fbtl_db/td_log.c @@ -0,0 +1,31 @@ +/* Noop, left for historical reasons. + Copyright (C) 1999-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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; +} --- /dev/null +++ b/fbtl_db/td_symbol_list.c @@ -0,0 +1,59 @@ +/* Return list of symbols the library can request. + Copyright (C) 2001-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#include <assert.h> +#include "thread_dbP.h" + +static const char *symbol_list_arr[] = +{ +# define DB_LOOKUP_NAME(idx, name) [idx] = STRINGIFY (name), +# define DB_LOOKUP_NAME_TH_UNIQUE(idx, name) [idx] = STRINGIFY (name), +# include "db-symbols.h" +# undef DB_LOOKUP_NAME +# undef DB_LOOKUP_NAME_TH_UNIQUE + + [SYM_NUM_MESSAGES] = NULL +}; + + +const char ** +td_symbol_list (void) +{ + return symbol_list_arr; +} + + +ps_err_e +td_mod_lookup (struct ps_prochandle *ps, const char *mod, + int idx, psaddr_t *sym_addr) +{ + ps_err_e result; + assert (idx >= 0 && idx < SYM_NUM_MESSAGES); + result = ps_pglobal_lookup (ps, mod, 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; +} --- /dev/null +++ b/fbtl_db/td_ta_clear_event.c @@ -0,0 +1,77 @@ +/* Globally disable events. + Copyright (C) 1999-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#include <stdint.h> +#include "thread_dbP.h" + + +td_err_e +td_ta_clear_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; +} --- /dev/null +++ b/fbtl_db/td_ta_delete.c @@ -0,0 +1,41 @@ +/* Detach to target process. + Copyright (C) 1999-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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; +} --- /dev/null +++ b/fbtl_db/td_ta_enable_stats.c @@ -0,0 +1,34 @@ +/* Enable collection of statistics for process. + Copyright (C) 1999-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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; +} --- /dev/null +++ b/fbtl_db/td_ta_event_addr.c @@ -0,0 +1,60 @@ +/* Get event address. + Copyright (C) 1999-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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; + + 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; +} --- /dev/null +++ b/fbtl_db/td_ta_event_getmsg.c @@ -0,0 +1,104 @@ +/* Retrieve event. + Copyright (C) 1999-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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; + + /* 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; +} --- /dev/null +++ b/fbtl_db/td_ta_get_nthreads.c @@ -0,0 +1,41 @@ +/* Get the number of threads in the process. + Copyright (C) 1999-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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; +} --- /dev/null +++ b/fbtl_db/td_ta_get_ph.c @@ -0,0 +1,35 @@ +/* Get external process handle. + Copyright (C) 1999-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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; +} --- /dev/null +++ b/fbtl_db/td_ta_get_stats.c @@ -0,0 +1,34 @@ +/* Retrieve statistics for process. + Copyright (C) 1999-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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; +} --- /dev/null +++ b/fbtl_db/td_ta_map_id2thr.c @@ -0,0 +1,37 @@ +/* Map thread ID to thread handle. + Copyright (C) 1999-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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; +} --- /dev/null +++ b/fbtl_db/td_ta_map_lwp2thr.c @@ -0,0 +1,208 @@ +/* Which thread is running on an LWP? + Copyright (C) 2003-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include "thread_dbP.h" +#include <stdlib.h> +#include <byteswap.h> +#include <sys/procfs.h> + + +td_err_e +__td_ta_lookup_th_unique (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; + + 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) + { + 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 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, a register holds the 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 = ta; + + return TD_OK; +} + +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; + + LOG ("td_ta_map_lwp2thr"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + /* We cannot rely on thread registers and such information at all + before __pthread_initialize_minimal has gotten far enough. They + sometimes contain garbage that would confuse us, left by the kernel + at exec. So if it looks like initialization is incomplete, we only + fake a special descriptor for the initial thread. */ + + psaddr_t list; + td_err_e err = DB_GET_SYMBOL (list, ta, __stack_user); + if (err != TD_OK) + return err; + + err = DB_GET_FIELD (list, ta, list, list_t, next, 0); + if (err != TD_OK) + return err; + + if (list == 0) + { + if (ps_getpid (ta->ph) != lwpid) + return TD_ERR; + th->th_ta_p = ta; + th->th_unique = 0; + return TD_OK; + } + + return __td_ta_lookup_th_unique (ta_arg, lwpid, th); +} --- /dev/null +++ b/fbtl_db/td_ta_new.c @@ -0,0 +1,64 @@ +/* Attach to target process. + Copyright (C) 1999-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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; +} --- /dev/null +++ b/fbtl_db/td_ta_reset_stats.c @@ -0,0 +1,34 @@ +/* Reset statistics. + Copyright (C) 1999-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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; +} --- /dev/null +++ b/fbtl_db/td_ta_set_event.c @@ -0,0 +1,77 @@ +/* Globally enable events. + Copyright (C) 1999-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#include <stdint.h> +#include "thread_dbP.h" + + +td_err_e +td_ta_set_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; +} --- /dev/null +++ b/fbtl_db/td_ta_setconcurrency.c @@ -0,0 +1,34 @@ +/* Set suggested concurrency level for process. + Copyright (C) 1999-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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; +} --- /dev/null +++ b/fbtl_db/td_ta_thr_iter.c @@ -0,0 +1,150 @@ +/* Iterate over a process's threads. + Copyright (C) 1999-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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, bool fake_empty, pid_t match_pid) +{ + 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. We cannot rely on its thread register. They + sometimes contain garbage that would confuse us, left by the + kernel at exec. So if it looks like initialization is incomplete, + we only fake a special descriptor for the initial thread. */ + td_thrhandle_t th = { ta, 0 }; + return callback (&th, cbdata_p) != 0 ? TD_DBERR : TD_OK; + } + + /* 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. */ + + pid_t pid = ps_getpid (ta->ph); + err = DB_GET_SYMBOL (list, ta, __stack_user); + if (err == TD_OK) + err = iterate_thread_list (ta, callback, cbdata_p, state, ti_pri, + list, true, pid); + + /* 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, false, pid); + + return err; +} --- /dev/null +++ b/fbtl_db/td_ta_tsd_iter.c @@ -0,0 +1,81 @@ +/* Iterate over a process's thread-specific data. + Copyright (C) 1999-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#include <stdint.h> +#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; +} --- /dev/null +++ b/fbtl_db/td_thr_clear_event.c @@ -0,0 +1,75 @@ +/* Disable specific event for thread. + Copyright (C) 1999-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#include <stddef.h> +#include <stdint.h> + +#include "thread_dbP.h" + + +td_err_e +td_thr_clear_event (const td_thrhandle_t *th, td_thr_events_t *event) +{ + td_err_e err; + psaddr_t eventmask; + void *copy; + + 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; +} --- /dev/null +++ b/fbtl_db/td_thr_dbresume.c @@ -0,0 +1,29 @@ +/* Resume execution of given thread. + Copyright (C) 1999-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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; +} --- /dev/null +++ b/fbtl_db/td_thr_dbsuspend.c @@ -0,0 +1,29 @@ +/* Suspend execution of given thread. + Copyright (C) 1999-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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; +} --- /dev/null +++ b/fbtl_db/td_thr_event_enable.c @@ -0,0 +1,49 @@ +/* Enable event process-wide. + Copyright (C) 1999-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#include "thread_dbP.h" + + +td_err_e +td_thr_event_enable (const td_thrhandle_t *th, int onoff) +{ + LOG ("td_thr_event_enable"); + + if (th->th_unique != 0) + { + /* Write the new value into the thread data structure. */ + td_err_e err = DB_PUT_FIELD (th->th_ta_p, th->th_unique, pthread, + report_events, 0, + (psaddr_t) 0 + (onoff != 0)); + if (err != TD_OK) + return err; + + /* Just in case we are in the window between initializing __stack_user + and copying from __nptl_initial_report_events, we set it too. + It doesn't hurt to do this for non-initial threads, since it + won't be consulted again anyway. It would take another fetch + to get the tid and determine this isn't the initial thread, + so just do it always. */ + } + + /* We are faking it for the initial thread before its thread + descriptor is set up. */ + return DB_PUT_VALUE (th->th_ta_p, __nptl_initial_report_events, 0, + (psaddr_t) 0 + (onoff != 0)); +} --- /dev/null +++ b/fbtl_db/td_thr_event_getmsg.c @@ -0,0 +1,118 @@ +/* Retrieve event. + Copyright (C) 1999-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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; + + 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; +} --- /dev/null +++ b/fbtl_db/td_thr_get_info.c @@ -0,0 +1,126 @@ +/* Get thread information. + Copyright (C) 1999-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#include <stddef.h> +#include <string.h> +#include <stdint.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"); + + if (th->th_unique == 0) + { + /* Special case for the main thread before initialization. */ + copy = NULL; + tls = 0; + cancelhandling = 0; + schedpolicy = SCHED_OTHER; + schedprio = 0; + tid = 0; + err = DB_GET_VALUE (report_events, th->th_ta_p, + __nptl_initial_report_events, 0); + } + else + { + /* 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; + + if (copy != NULL) + err = DB_GET_FIELD_LOCAL (infop->ti_startfunc, th->th_ta_p, copy, pthread, + start_routine, 0); + if (copy != NULL && 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; +} --- /dev/null +++ b/fbtl_db/td_thr_getfpregs.c @@ -0,0 +1,57 @@ +/* Get a thread's floating-point register set. + Copyright (C) 1999-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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"); + + if (th->th_unique == 0) + /* Special case for the main thread before initialization. */ + return ps_lgetfpregs (th->th_ta_p->ph, ps_getpid (th->th_ta_p->ph), + regset) != PS_OK ? TD_ERR : TD_OK; + + /* 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; +} --- /dev/null +++ b/fbtl_db/td_thr_getgregs.c @@ -0,0 +1,57 @@ +/* Get a thread's general register set. + Copyright (C) 1999-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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"); + + if (th->th_unique == 0) + /* Special case for the main thread before initialization. */ + return ps_lgetregs (th->th_ta_p->ph, ps_getpid (th->th_ta_p->ph), + regset) != PS_OK ? TD_ERR : TD_OK; + + /* 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; +} --- /dev/null +++ b/fbtl_db/td_thr_getxregs.c @@ -0,0 +1,29 @@ +/* Get a thread's extra state register set. + Copyright (C) 1999-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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; +} --- /dev/null +++ b/fbtl_db/td_thr_getxregsize.c @@ -0,0 +1,29 @@ +/* Get the size of the extra state register set for this architecture. + Copyright (C) 1999-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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; +} --- /dev/null +++ b/fbtl_db/td_thr_set_event.c @@ -0,0 +1,75 @@ +/* Enable specific event for thread. + Copyright (C) 1999-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#include <stddef.h> +#include <stdint.h> + +#include "thread_dbP.h" + + +td_err_e +td_thr_set_event (const td_thrhandle_t *th, td_thr_events_t *event) +{ + td_err_e err; + psaddr_t eventmask; + void *copy; + + 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; +} --- /dev/null +++ b/fbtl_db/td_thr_setfpregs.c @@ -0,0 +1,54 @@ +/* Set a thread's floating-point register set. + Copyright (C) 1999-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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"); + + if (th->th_unique == 0) + /* Special case for the main thread before initialization. */ + return ps_lsetfpregs (th->th_ta_p->ph, ps_getpid (th->th_ta_p->ph), + fpregs) != PS_OK ? TD_ERR : TD_OK; + + /* 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; +} --- /dev/null +++ b/fbtl_db/td_thr_setgregs.c @@ -0,0 +1,54 @@ +/* Set a thread's general register set. + Copyright (C) 1999-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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"); + + if (th->th_unique == 0) + /* Special case for the main thread before initialization. */ + return ps_lsetregs (th->th_ta_p->ph, ps_getpid (th->th_ta_p->ph), + gregs) != PS_OK ? TD_ERR : TD_OK; + + /* 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; +} --- /dev/null +++ b/fbtl_db/td_thr_setprio.c @@ -0,0 +1,29 @@ +/* Set a thread's priority. + Copyright (C) 1999-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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; +} --- /dev/null +++ b/fbtl_db/td_thr_setsigpending.c @@ -0,0 +1,30 @@ +/* Raise a signal for a thread. + Copyright (C) 1999-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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; +} --- /dev/null +++ b/fbtl_db/td_thr_setxregs.c @@ -0,0 +1,29 @@ +/* Set a thread's extra state register set. + Copyright (C) 1999-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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; +} --- /dev/null +++ b/fbtl_db/td_thr_sigsetmask.c @@ -0,0 +1,29 @@ +/* Set a thread's signal mask. + Copyright (C) 1999-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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; +} --- /dev/null +++ b/fbtl_db/td_thr_tls_get_addr.c @@ -0,0 +1,42 @@ +/* Get address of thread local variable. + Copyright (C) 2002-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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; +} --- /dev/null +++ b/fbtl_db/td_thr_tlsbase.c @@ -0,0 +1,243 @@ +/* Locate TLS data for a thread. + Copyright (C) 2003-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include "thread_dbP.h" +#include <link.h> + +/* Get the DTV slotinfo list head entry from the dynamic loader state + into *LISTHEAD. */ +static td_err_e +dtv_slotinfo_list (td_thragent_t *ta, + psaddr_t *listhead) +{ + td_err_e err; + psaddr_t head; + + if (ta->ta_addr__rtld_global == 0 + && td_mod_lookup (ta->ph, LD_SO, SYM__rtld_global, + &ta->ta_addr__rtld_global) != PS_OK) + ta->ta_addr__rtld_global = (void*)-1; + + if (ta->ta_addr__rtld_global != (void*)-1) + { + err = DB_GET_FIELD (head, ta, ta->ta_addr__rtld_global, + rtld_global, _dl_tls_dtv_slotinfo_list, 0); + if (err != TD_OK) + return err; + } + else + { + if (ta->ta_addr__dl_tls_dtv_slotinfo_list == 0 + && td_mod_lookup (ta->ph, NULL, SYM__dl_tls_dtv_slotinfo_list, + &ta->ta_addr__dl_tls_dtv_slotinfo_list) != PS_OK) + return TD_ERR; + + err = _td_fetch_value (ta, ta->ta_var__dl_tls_dtv_slotinfo_list, + SYM_DESC__dl_tls_dtv_slotinfo_list, + 0, ta->ta_addr__dl_tls_dtv_slotinfo_list, &head); + if (err != TD_OK) + return err; + } + + *listhead = head; + return TD_OK; +} + +/* Get the address of the DTV slotinfo entry for MODID into + *DTVSLOTINFO. */ +static td_err_e +dtv_slotinfo (td_thragent_t *ta, + unsigned long int modid, + psaddr_t *dtvslotinfo) +{ + td_err_e err; + psaddr_t slot, temp; + size_t slbase = 0; + + err = dtv_slotinfo_list (ta, &slot); + if (err != TD_OK) + return err; + + while (slot) + { + /* Get the number of entries in this list entry's array. */ + err = DB_GET_FIELD (temp, ta, slot, dtv_slotinfo_list, len, 0); + if (err != TD_OK) + return err; + size_t len = (uintptr_t)temp; + + /* Did we find the list entry for modid? */ + if (modid < slbase + len) + break; + + /* We didn't, so get the next list entry. */ + slbase += len; + err = DB_GET_FIELD (temp, ta, slot, dtv_slotinfo_list, + next, 0); + if (err != TD_OK) + return err; + slot = temp; + } + + /* We reached the end of the list and found nothing. */ + if (!slot) + return TD_ERR; + + /* Take the slotinfo for modid from the list entry. */ + err = DB_GET_FIELD_ADDRESS (temp, ta, slot, dtv_slotinfo_list, + slotinfo, modid - slbase); + if (err != TD_OK) + return err; + slot = temp; + + *dtvslotinfo = slot; + return TD_OK; +} + +/* Return in *BASE the base address of the TLS block for MODID within + TH. + + It should return success and yield the correct pointer in any + circumstance where the TLS block for the module and thread + requested has already been initialized. + + It should fail with TD_TLSDEFER only when the thread could not + possibly have observed any values in that TLS block. That way, the + debugger can fall back to showing initial values from the PT_TLS + segment (and refusing attempts to mutate) for the TD_TLSDEFER case, + and never fail to make the values the program will actually see + available to the user of the debugger. */ +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, temp; + + if (modid < 1) + return TD_NOTLS; + + psaddr_t pd = th->th_unique; + if (pd == 0) + { + /* This is the fake handle for the main thread before libpthread + initialization. We are using 0 for its th_unique because we can't + trust that its thread register has been initialized. But we need + a real pointer to have any TLS access work. In case of dlopen'd + libpthread, initialization might not be for quite some time. So + try looking up the thread register now. Worst case, it's nonzero + uninitialized garbage and we get bogus results for TLS access + attempted too early. Tough. */ + + td_thrhandle_t main_th; + err = __td_ta_lookup_th_unique (th->th_ta_p, ps_getpid (th->th_ta_p->ph), + &main_th); + if (err == 0) + pd = main_th.th_unique; + if (pd == 0) + return TD_TLSDEFER; + } + + err = dtv_slotinfo (th->th_ta_p, modid, &temp); + if (err != TD_OK) + return err; + + psaddr_t slot; + err = DB_GET_STRUCT (slot, th->th_ta_p, temp, dtv_slotinfo); + if (err != TD_OK) + return err; + + /* Take the link_map from the slotinfo. */ + psaddr_t map; + err = DB_GET_FIELD_LOCAL (map, th->th_ta_p, slot, dtv_slotinfo, map, 0); + if (err != TD_OK) + return err; + if (!map) + return TD_ERR; + + /* Ok, the modid is good, now find out what DTV generation it + requires. */ + err = DB_GET_FIELD_LOCAL (temp, th->th_ta_p, slot, dtv_slotinfo, gen, 0); + if (err != TD_OK) + return err; + size_t modgen = (uintptr_t)temp; + + /* Get the DTV pointer from the thread descriptor. */ + err = DB_GET_FIELD (dtv, th->th_ta_p, pd, pthread, dtvp, 0); + if (err != TD_OK) + return err; + + psaddr_t dtvgenloc; + /* Get the DTV generation count at dtv[0].counter. */ + err = DB_GET_FIELD_ADDRESS (dtvgenloc, th->th_ta_p, dtv, dtv, dtv, 0); + if (err != TD_OK) + return err; + err = DB_GET_FIELD (temp, th->th_ta_p, dtvgenloc, dtv_t, counter, 0); + if (err != TD_OK) + return err; + size_t dtvgen = (uintptr_t)temp; + + /* Is the DTV current enough? */ + if (dtvgen < modgen) + { + try_static_tls: + /* If the module uses Static TLS, we're still good. */ + err = DB_GET_FIELD (temp, th->th_ta_p, map, link_map, l_tls_offset, 0); + if (err != TD_OK) + return err; + ptrdiff_t tlsoff = (uintptr_t)temp; + + if (tlsoff != FORCED_DYNAMIC_TLS_OFFSET + && tlsoff != NO_TLS_OFFSET) + { + psaddr_t tp = pd; + +#if TLS_TCB_AT_TP + dtvptr = tp - tlsoff; +#elif TLS_DTV_AT_TP + dtvptr = tp + tlsoff + TLS_PRE_TCB_SIZE; +#else +# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined" +#endif + + *base = dtvptr; + return TD_OK; + } + + return TD_TLSDEFER; + } + + /* 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) + goto try_static_tls; + + *base = dtvptr; + return TD_OK; +} --- /dev/null +++ b/fbtl_db/td_thr_tsd.c @@ -0,0 +1,96 @@ +/* Get a thread-specific data pointer for a thread. + Copyright (C) 1999-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#include <stdint.h> +#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; +} --- /dev/null +++ b/fbtl_db/td_thr_validate.c @@ -0,0 +1,84 @@ +/* Validate a thread handle. + Copyright (C) 1999-2013 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, see + <http://www.gnu.org/licenses/>. */ + +#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; + + 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 && th->th_unique == 0) + /* __pthread_initialize_minimal has not run yet. + There is only the special case thread handle. */ + err = TD_OK; + } + + return err; +} --- /dev/null +++ b/fbtl_db/thread_db.h @@ -0,0 +1,458 @@ +/* thread_db.h -- interface to libthread_db.so library for debugging -lpthread + Copyright (C) 1999-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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 */ --- /dev/null +++ b/fbtl_db/thread_dbP.h @@ -0,0 +1,258 @@ +/* Private header for thread debug library + Copyright (C) 2003-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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 "../fbtl/pthreadP.h" /* This is for *_BITMASK only. */ +#include <list.h> +#include <gnu/lib-names.h> + +/* 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 wrappers around ps_pglobal_lookup. */ +extern ps_err_e td_mod_lookup (struct ps_prochandle *ps, const char *modname, + int idx, psaddr_t *sym_addr) attribute_hidden; +#define td_lookup(ps, idx, sym_addr) \ + td_mod_lookup ((ps), LIBPTHREAD_SO, (idx), (sym_addr)) + + +/* 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; + +extern td_err_e __td_ta_lookup_th_unique (const td_thragent_t *ta, + lwpid_t lwpid, td_thrhandle_t *th); + +#endif /* thread_dbP.h */
Simpan