diff options
Diffstat (limited to 'libpthread')
679 files changed, 59920 insertions, 0 deletions
diff --git a/libpthread/nptl/.gitignore b/libpthread/nptl/.gitignore new file mode 100644 index 000000000..e20fba840 --- /dev/null +++ b/libpthread/nptl/.gitignore @@ -0,0 +1,17 @@ +# +# Never ignore these +# +!.gitignore + +# +# Generated files +# +pthread-errnos.[hcs] +tcb-offsets.[hcs] +lowlevelbarrier.[hcs] +lowlevelcond.[hcs] +lowlevelrwlock.[hcs] +unwindbuf.[hcs] +sysdeps/pthread/pt-sigaction.c +sysdeps/pthread/pt-sigfillset.c +sysdeps/pthread/pt-sigprocmask.c diff --git a/libpthread/nptl/ChangeLog b/libpthread/nptl/ChangeLog new file mode 100644 index 000000000..92bd22af7 --- /dev/null +++ b/libpthread/nptl/ChangeLog @@ -0,0 +1,7270 @@ +2005-08-23 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/timer_routines.c (timer_helper_thread): + Use __sigfillset. Document that sigfillset does the right thing wrt + to SIGSETXID. + +2005-07-11 Jakub Jelinek <jakub@redhat.com> + + [BZ #1102] + * sysdeps/pthread/pthread.h (PTHREAD_MUTEX_INITIALIZER, + PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP, + PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP, + PTHREAD_MUTEX_ADAPTIVE_NP, PTHREAD_RWLOCK_INITIALIZER, + PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP, + PTHREAD_COND_INITIALIZER): Supply zeros for all fields + in the structure. + * Makefile (tests): Add tst-initializers1. + (CFLAGS-tst-initializers1.c): Set. + * tst-initializers1.c: New test. + +2005-07-11 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h (pthread_rwlock_t): + Make sure __flags are located at offset 48 from the start of the + structure. + +2005-07-02 Roland McGrath <roland@redhat.com> + + * Makeconfig: Comment fix. + +2005-07-05 Jakub Jelinek <jakub@redhat.com> + + * descr.h (PTHREAD_STRUCT_END_PADDING): Define. + * sysdeps/ia64/tls.h (TLS_PRE_TCB_SIZE): If PTHREAD_STRUCT_END_PADDING + is smaller than 8 bytes, increase TLS_PRE_TCB_SIZE by 16 bytes. + (THREAD_SYSINFO, THREAD_SELF, DB_THREAD_SELF): Don't assume + TLS_PRE_TCB_SIZE is sizeof (struct pthread). + (THREAD_SET_STACK_GUARD, THREAD_COPY_STACK_GUARD): Define. + * sysdeps/ia64/tcb-offsets.sym (PID, TID, MULTIPLE_THREADS_OFFSET): + Use TLS_PRE_TCB_SIZE instead of sizeof (struct pthread). + * sysdeps/unix/sysv/linux/ia64/createthread.c (TLS_VALUE): Don't + assume TLS_PRE_TCB_SIZE is sizeof (struct pthread). + +2005-06-25 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/i386/tls.h (tcbhead_t): Add stack_guard field. + (THREAD_SET_STACK_GUARD, THREAD_COPY_STACK_GUARD): Define. + * sysdeps/x86_64/tls.h (tcbhead_t): Add sysinfo and stack_guard + fields. + (THREAD_SET_STACK_GUARD, THREAD_COPY_STACK_GUARD): Define. + * sysdeps/s390/tls.h (tcbhead_t): Add stack_guard + field. Put in sysinfo field unconditionally. + (THREAD_SET_STACK_GUARD, THREAD_COPY_STACK_GUARD): Define. + * sysdeps/powerpc/tls.h (tcbhead_t): Add stack_guard field. + (THREAD_SET_STACK_GUARD, THREAD_COPY_STACK_GUARD): Define. + * sysdeps/sparc/tls.h (tcbhead_t): Add sysinfo and stack_guard + fields. + (THREAD_SET_STACK_GUARD, THREAD_COPY_STACK_GUARD): Define. + * pthread_create.c (__pthread_create_2_1): Use + THREAD_COPY_STACK_GUARD macro. + * Makefile: Add rules to build and run tst-stackguard1{,-static} + tests. + * tst-stackguard1.c: New file. + * tst-stackguard1-static.c: New file. + +2005-06-14 Alan Modra <amodra@bigpond.net.au> + + * sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h (PSEUDO): + Invoke CGOTSETUP and CGOTRESTORE. + (CGOTSETUP, CGOTRESTORE): Define. + +2005-05-29 Richard Henderson <rth@redhat.com> + + * tst-cancel4.c (WRITE_BUFFER_SIZE): New. + (tf_write, tf_writev): Use it. + (do_test): Use socketpair instead of pipe. Set SO_SNDBUF to + the system minimum. + +2005-05-23 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h + [IS_IN_librt] (CENABLE, CDISABLE): Use JUMPTARGET instead of + __librt_*_asynccancel@local. + +2005-05-17 Alan Modra <amodra@bigpond.net.au> + + * sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h: Delete + all occurrences of JUMPTARGET. Instead append @local to labels. + +2005-05-20 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/i386/tls.h (TLS_INIT_TCB_SIZE, TLS_INIT_TCB_ALIGN): Define to + size/alignment of struct pthread rather than tcbhead_t. + * sysdeps/x86_64/tls.h (TLS_INIT_TCB_SIZE, TLS_INIT_TCB_ALIGN): + Likewise. + * sysdeps/s390/tls.h (TLS_INIT_TCB_SIZE, TLS_INIT_TCB_ALIGN): + Likewise. + * sysdeps/sparc/tls.h (TLS_INIT_TCB_SIZE, TLS_INIT_TCB_ALIGN): + Likewise. + +2005-05-19 Richard Henderson <rth@redhat.com> + + * sysdeps/ia64/pthread_spin_lock.c (pthread_spin_lock): Use + __sync_val_compare_and_swap, not explicit _si variant. + * sysdeps/ia64/pthread_spin_trylock.c (pthread_spin_trylock): Likewise. + +2005-05-03 Ulrich Drepper <drepper@redhat.com> + + [BZ #915] + * sysdeps/pthread/pthread.h: Avoid empty initializers. + +2005-05-03 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h: Remove explicit + .eh_frame section, use cfi_* directives. + +2005-04-27 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/pthread_getcpuclockid.c: Use <> instead + of "" includes. + +2005-04-27 Ulrich Drepper <drepper@redhat.com> + + [BZ #1075] + * tst-cancel17.c (do_test): Add arbitrary factor to make sure + aio_write blocks. + +2005-04-27 Roland McGrath <roland@redhat.com> + + * Makefile (tests): Remove tst-clock2. + + * sysdeps/unix/sysv/linux/timer_create.c (timer_create): Handle + CLOCK_PROCESS_CPUTIME_ID and CLOCK_PROCESS_THREAD_ID specially, + translating to the kernel clockid_t for our own process/thread clock. + + * sysdeps/unix/sysv/linux/pthread_getcpuclockid.c: New file. + +2005-04-15 Jakub Jelinek <jakub@redhat.com> + + * old_pthread_cond_init.c: Include <errno.h>. + (__pthread_cond_init_2_0): Fail with EINVAL if COND_ATTR is + process shared or uses clock other than CLOCK_REALTIME. + * pthread_cond_init.c (__pthread_cond_init): Remove bogus comment. + +2005-04-13 David S. Miller <davem@davemloft.net> + + * sysdeps/sparc/sparc64/jmpbuf-unwind.h: New file. + * sysdeps/sparc/sparc64/clone.S: New file. + +2005-04-05 Jakub Jelinek <jakub@redhat.com> + + [BZ #1102] + * sysdeps/pthread/pthread.h (__pthread_cleanup_routine): Use + __inline instead of inline. + * sysdeps/pthread/bits/libc-lock.h (__libc_cleanup_routine): Likewise. + +2005-03-31 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_unlock.S: Use + functionally equivalent, but shorter instructions. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedrdlock.S: + Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_barrier_wait.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_rdlock.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/sem_wait.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_wrlock.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_once.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedwrlock.S: + Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_signal.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/sem_post.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S: Likewise. + +2005-03-28 Daniel Jacobowitz <dan@codesourcery.com> + + * sysdeps/mips/Makefile: New file. + * sysdeps/mips/nptl-sysdep.S: New file. + * sysdeps/mips/tcb-offsets.sym: New file. + * sysdeps/mips/pthread_spin_lock.S: New file. + * sysdeps/mips/pthread_spin_trylock.S: New file. + * sysdeps/mips/pthreaddef.h: New file. + * sysdeps/mips/tls.h: New file. + * sysdeps/mips/jmpbuf-unwind.h: New file. + * sysdeps/unix/sysv/linux/mips/lowlevellock.h: New file. + * sysdeps/unix/sysv/linux/mips/bits/pthreadtypes.h: New file. + * sysdeps/unix/sysv/linux/mips/bits/semaphore.h: New file. + * sysdeps/unix/sysv/linux/mips/pthread_once.c: New file. + * sysdeps/unix/sysv/linux/mips/fork.c: New file. + * sysdeps/unix/sysv/linux/mips/pt-vfork.S: New file. + * sysdeps/unix/sysv/linux/mips/vfork.S: New file. + * sysdeps/unix/sysv/linux/mips/clone.S: New file. + * sysdeps/unix/sysv/linux/mips/createthread.c: New file. + * sysdeps/unix/sysv/linux/mips/sysdep-cancel.h: New file. + +2005-03-23 Ulrich Drepper <drepper@redhat.com> + + [BZ #1112] + * pthread_create.c (__pthread_create_2_1): Rename syscall error + variable to scerr. + +2005-03-10 Jakub Jelinek <jakub@redhat.com> + + * tst-getpid1.c (do_test): Align stack passed to clone{2,}. + +2005-02-25 Roland McGrath <roland@redhat.com> + + * alloca_cutoff.c: Correct license text. + * tst-unload.c: Likewise. + * sysdeps/pthread/allocalim.h: Likewise. + * sysdeps/pthread/pt-initfini.c: Likewise. + * sysdeps/pthread/bits/libc-lock.h: Likewise. + * sysdeps/pthread/bits/sigthread.h: Likewise. + * sysdeps/unix/sysv/linux/bits/local_lim.h: Likewise. + * sysdeps/unix/sysv/linux/bits/posix_opt.h: Likewise. + +2005-02-16 Roland McGrath <roland@redhat.com> + + * sysdeps/pthread/pthread-functions.h (struct pthread_functions): + Use unsigned int * for ptr_nthreads. + +2005-02-14 Alan Modra <amodra@bigpond.net.au> + + [BZ #721] + * sysdeps/powerpc/tcb-offsets.sym (thread_offsetof): Redefine to suit + gcc4. + +2005-02-07 Richard Henderson <rth@redhat.com> + + [BZ #787] + * sysdeps/pthread/pthread.h (__sigsetjmp): Use pointer as first + argument. + +2004-11-03 Marcus Brinkmann <marcus@gnu.org> + + * sysdeps/generic/lowlevellock.h (__generic_mutex_unlock): Fix + order of arguments in invocation of atomic_add_zero. + +2005-01-26 Jakub Jelinek <jakub@redhat.com> + + [BZ #737] + * sysdeps/unix/sysv/linux/i386/i486/sem_trywait.S (__new_sem_trywait): + Use direct %gs segment access or, if NO_TLS_DIRECT_SEG_REFS, + at least gotntpoff relocation and addition. + * sysdeps/unix/sysv/linux/i386/i486/sem_timedwait.S (sem_timedwait): + Likewise. + * sysdeps/unix/sysv/linux/i386/i486/sem_post.S (__new_sem_post): + Likewise. + * sysdeps/unix/sysv/linux/i386/i486/sem_wait.S (__new_sem_wait): + Likewise. + +2005-01-06 Ulrich Drepper <drepper@redhat.com> + + * allocatestack.c (init_one_static_tls): Adjust initialization of DTV + entry for static tls deallocation fix. + * sysdeps/alpha/tls.h (dtv_t): Change pointer type to be struct which + also contains information whether the memory pointed to is static + TLS or not. + * sysdeps/i386/tls.h: Likewise. + * sysdeps/ia64/tls.h: Likewise. + * sysdeps/powerpc/tls.h: Likewise. + * sysdeps/s390/tls.h: Likewise. + * sysdeps/sh/tls.h: Likewise. + * sysdeps/sparc/tls.h: Likewise. + * sysdeps/x86_64/tls.h: Likewise. + +2004-12-27 Ulrich Drepper <drepper@redhat.com> + + * init.c (__pthread_initialize_minimal_internal): Use __sigemptyset. + +2004-12-21 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/i386/tls.h (CALL_THREAD_FCT): Maintain 16 byte alignment of + %esp. + * Makefile (tests): Add tst-align2. + * tst-align2.c: New test. + * sysdeps/i386/Makefile (CFLAGS-tst-align{,2}.c): Add + -mpreferred-stack-boundary=4. + +2004-12-18 Roland McGrath <roland@redhat.com> + + * sysdeps/unix/sysv/linux/powerpc/powerpc64/bits/local_lim.h: + New file removed withdrawn for the moment. + +2004-12-17 Richard Henderson <rth@redhat.com> + + * sysdeps/unix/sysv/linux/alpha/clone.S: New file. + * sysdeps/alpha/tcb-offsets.sym (TID_OFFSET): New. + +2004-12-16 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/powerpc/powerpc64/bits/local_lim.h: New file. + Increased PTHREAD_STACK_MIN. + + * tst-context1.c (stacks): Use bigger stack size. + +2004-12-16 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/sparc/sparc32/clone.S: New file. + * sysdeps/sparc/tcb-offsets.sym: Add TID. + +2004-12-15 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/s390/s390-32/clone.S: New file. + * sysdeps/unix/sysv/linux/s390/s390-64/clone.S: New file. + * sysdeps/s390/tcb-offsets.sym (TID): Add. + +2004-12-15 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/powerpc/powerpc32/clone.S: New file. + +2004-12-14 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/powerpc/tcb-offsets.sym: Add TID. + * sysdeps/unix/sysv/linux/powerpc/powerpc64/clone.S: New file. + + * tst-getpid1.c: If child crashes, report this first. Print which + signal. + +2004-12-09 Ulrich Drepper <drepper@redhat.com> + + * init.c (__pthread_initialize_minimal_internal): Also unblock + SIGSETXID. + +2004-12-01 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/bits/posix_opt.h (_POSIX_CPUTIME, + _POSIX_THREAD_CPUTIME): Define to 0. + * sysdeps/pthread/timer_create.c (timer_create): Remove unused code + handling CLOCK_PROCESS_CPUTIME_ID and CLOCK_THREAD_CPUTIME_ID. + * sysdeps/pthread/timer_routines.c (__timer_signal_thread_pclk, + __timer_signal_thread_tclk): Remove. + (init_module): Remove their initialization. + (thread_cleanup): Remove their cleanup assertions. + * sysdeps/pthread/posix-timer.h (__timer_signal_thread_pclk, + __timer_signal_thread_tclk): Remove. + * sysdeps/unix/sysv/linux/i386/bits/posix_opt.h: Removed. + * sysdeps/unix/sysv/linux/ia64/bits/posix_opt.h: Removed. + * sysdeps/unix/sysv/linux/x86_64/bits/posix_opt.h: Removed. + +2004-12-07 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/ia64/tcb-offsets.sym (TID): Add. + * sysdeps/unix/sysv/linux/ia64/clone2.S: New file. + + * Makefile (tests): Add tst-getpid2. + * tst-getpid1.c (TEST_CLONE_FLAGS): Define. + (do_test): Use it. Use __clone2 instead of clone on ia64. + * tst-getpid2.c: New test. + +2004-12-07 Kaz Kojima <kkojima@rr.iij4u.or.jp> + + * sysdeps/unix/sysv/linux/sh/clone.S: New file. + +2004-12-04 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add tst-getpid1. + * tst-getpid1.c: New file. + * sysdeps/unix/sysv/linux/i386/clone.S: New file. + * sysdeps/unix/sysv/linux/x86_64/clone.S: New file. + +2004-12-02 Roland McGrath <roland@redhat.com> + + * Makefile (libpthread-nonshared): Variable removed. + ($(objpfx)libpthread_nonshared.a): Target removed. + ($(inst_libdir)/libpthread_nonshared.a): Likewise. + These are now handled by generic magic from + libpthread-static-only-routines being set. + +2004-11-27 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/bits/posix_opt.h (_POSIX_PRIORITIZED_IO, + _POSIX2_CHAR_TERM, _POSIX_THREAD_PRIO_INHERIT, + _POSIX_THREAD_PRIO_PROTECT): Define. + * sysdeps/unix/sysv/linux/i386/bits/posix_opt.h: Likewise. + * sysdeps/unix/sysv/linux/ia64/bits/posix_opt.h: Likewise. + * sysdeps/unix/sysv/linux/x86_64/bits/posix_opt.h: Likewise. + +2004-11-26 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/bits/posix_opt.h (_POSIX_ADVISORY_INFO, + _POSIX_SPORADIC_SERVER, _POSIX_THREAD_SPORADIC_SERVER, _POSIX_TRACE, + _POSIX_TRACE_EVENT_FILTER, _POSIX_TRACE_INHERIT, _POSIX_TRACE_LOG, + _POSIX_TYPED_MEMORY_OBJECTS, _POSIX_IPV6, _POSIX_RAW_SOCKETS): Define. + * sysdeps/unix/sysv/linux/i386/bits/posix_opt.h: Likewise. + * sysdeps/unix/sysv/linux/ia64/bits/posix_opt.h: Likewise. + * sysdeps/unix/sysv/linux/x86_64/bits/posix_opt.h: Likewise. + +2004-11-24 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/x86_64/Makefile [nptl]: Define CFLAGS-pthread_create.c. + + * Makefile (libpthread-routines): Add pthread_setschedprio. + * Versions [libpthread, GLIBC_2.3.4]: Add pthread_setschedprio. + * sysdeps/pthread/pthread.h: Declare pthread_setschedprio. + * pthread_setschedprio.c: New file. + +2004-11-20 Jakub Jelinek <jakub@redhat.com> + + * pthread_create.c (pthread_cancel): Add PTHREAD_STATIC_FN_REQUIRE. + * pthread_cancel.c (pthread_create): Likewise. + + * Makefile (libpthread-routines): Add vars. + * sysdeps/pthread/createthread.c (__pthread_multiple_threads): Remove. + * init.c (__default_stacksize, __is_smp): Remove. + * vars.c: New file. + * pthreadP.h (__find_thread_by_id): If !SHARED, add weak_function + and define a wrapper macro. + (PTHREAD_STATIC_FN_REQUIRE): Define. + * allocatestack.c (__find_thread_by_id): Undefine. + * pthread_create (__pthread_keys): Remove. + (pthread_mutex_lock, pthread_mutex_unlock, pthread_once, + pthread_key_create, pthread_setspecific, pthread_getspecific): Add + PTHREAD_STATIC_FN_REQUIRE. + +2004-11-18 Kaz Kojima <kkojima@rr.iij4u.or.jp> + + * sysdeps/sh/tls.h (DB_THREAD_SELF): Set the correct bias + parameter to REGISTER macro. + +2004-11-17 Roland McGrath <roland@redhat.com> + + * sysdeps/unix/sysv/linux/timer_routines.c (__start_helper_thread): + Make sure SIGCANCEL is blocked as well. + +2004-11-10 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/pthread/setxid.h: New file. + * sysdeps/pthread/pthread-functions.h (HAVE_PTR__NPTL_SETXID): Remove. + (struct xid_command): Add forward decl. + (struct pthread_functions): Change return type of __nptl_setxid hook + to int. + * pthreadP.h (__nptl_setxid): Change return type to int. + * allocatestack.c (__nptl_setxid): Call INTERNAL_SYSCALL_NCS in the + calling thread, return its return value and set errno on failure. + * descr.h (struct xid_command): Change id type to long array. + + * Makefile: Add rules to build and test tst-setuid1 and + tst-setuid1-static. + * tst-setuid1.c: New test. + * tst-setuid1-static.c: New test. + +2004-11-10 Jakub Jelinek <jakub@redhat.com> + + * Makefile (tests): Add tst-exit3. + * tst-exit3.c: New test. + +2004-11-09 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add tst-exit2. + * tst-exit2.c: New file. + +2004-11-09 Roland McGrath <roland@redhat.com> + + [BZ #530] + * sysdeps/pthread/createthread.c (do_clone): Increment __nptl_nthreads + here, before calling clone. + * pthread_create.c (start_thread): Don't do it here. + +2004-11-02 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/smp.h: Include <errno.h>. + +2004-10-29 Kaz Kojima <kkojima@rr.iij4u.or.jp> + + * sysdeps/unix/sysv/linux/sh/sem_timedwait.S (sem_timedwait): + Set ETIMEDOUT to errno when time is up. Tweak to avoid + assembler warning. + +2004-10-28 Jakub Jelinek <jakub@redhat.com> + + * pthread_create.c (__pthread_create_2_1): Avoid leaking stacks + if sched_priority is not between minprio and maxprio. + +2004-10-25 Kaz Kojima <kkojima@rr.iij4u.or.jp> + + * sysdeps/unix/sysv/linux/sh/pthread_cond_timedwait.S + (__pthread_cond_timedwait): Use clock_gettime syscall if exists. + + * sysdeps/unix/sysv/linux/sh/lowlevellock.S + (__lll_mutex_timedlock_wait): Fix a bad branch condition. + +2004-10-24 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/smp.h (is_smp_system): Use + not-cancelable I/O functions. + +2004-10-21 Kaz Kojima <kkojima@rr.iij4u.or.jp> + + * sysdeps/unix/sysv/linux/sh/lowlevellock.S + (__lll_mutex_timedlock_wait): If woken but cannot get the lock, + make sure 2 is stored in the futex and we looked at the old value. + Fix a few other problems to return the correct value. + +2004-10-14 Richard Henderson <rth@redhat.com> + + * sysdeps/alpha/tcb-offsets.sym (thread_offsetof): Redefine to + make gcc4 happy. + +2004-10-06 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/jmp-unwind.c: Include pthreadP.h instead + of pthread-functions.h and pthreaddef.h. + * sysdeps/unix/sysv/linux/s390/jmp-unwind.c: Likewise. + + * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h (pthread_cond_t): + Change __data.__nwaiters from int to unsigned int. + + * tst-clock2.c (do_test): Don't fail if _POSIX_THREAD_CPUTIME == 0 and + sysconf (_SC_THREAD_CPUTIME) returns negative value. + + * allocatestack.c (__find_thread_by_id): Move attribute_hidden + before return type. + + * sysdeps/s390/jmpbuf-unwind.h: Include bits/wordsize.h. + (JMPBUF_CFA_UNWINDS_ADJ): Subtract 96 resp. 160 bytes from CFA. + +2004-10-06 Ulrich Drepper <drepper@redhat.com> + + * tst-cancel4.c (tf_msgrcv): Check for failure in msgget. If the + test fails, remove message queue. + (tf_msgsnd): Likewise. + +2004-10-05 Jakub Jelinek <jakub@redhat.com> + + * tst-clock1.c: Change #ifdef to #if defined. + * tst-clock2.c: Likewise. + * tst-cond11.c: Likewise. + + * sysdeps/pthread/timer_create.c (timer_create): Use + defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0 instead of + defined CLOCK_PROCESS_CPUTIME_ID #ifs and similarly for + THREAD_CPUTIME. + +2004-10-05 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/x86_64/bits/posix_opt.h (_POSIX_CPUTIME, + _POSIX_THREAD_CPUTIME): Define to 0. + +2004-10-04 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/bits/posix_opt.h: Define _POSIX_CPUTIME + and _POSIX_THREAD_CPUTIME to zero. + * sysdeps/unix/sysv/linux/ia64/bits/posix_opt.h: Likewise. + * tst-barrier2.c: Fix testing for POSIX feature. + * tst-clock1.c: Likewise. + * tst-clock2.c: Likewise. + * tst-cond11.c: Likewise. + * tst-cond4.c: Likewise. + * tst-cond6.c: Likewise. + * tst-flock2.c: Likewise. + * tst-mutex4.c: Likewise. + * tst-mutex9.c: Likewise. + * tst-rwlock12.c: Likewise. + * tst-rwlock4.c: Likewise. + * tst-signal1.c: Likewise. + * tst-spin2.c: Likewise. + * sysdeps/pthread/posix-timer.h: Likewise. + * sysdeps/pthread/timer_create.c: Likewise. + * sysdeps/pthread/timer_routines.c: Likewise. + +2004-10-01 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.S + (__lll_mutex_timedlock_wait): Address futex correctly. + + * sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S + (__lll_mutex_timedlock_wait): If woken but cannot get the lock, + make sure 2 is stored in the futex and we looked at the old value. + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.S + (__lll_mutex_timedlock_wait): Likewise. Fix a few other problems + which might very well made the code not working at all before. + [BZ #417] + +2004-09-28 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/pthread_kill.c (__pthread_kill): Don't + allow SIGSETXID to be sent. + * sysdeps/pthread/sigaction.c (__sigaction): Don't allow action + for SIGSETXID to be defined. + * sysdeps/pthread/pthread_sigmask.c (pthread_sigmask): Make sure + SIGSETXID cannot be blocked. + + * sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h (pthread_cond_t): + Add __extension__ to long long types. + * sysdeps/unix/sysv/linux/sparc/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: Likewise. + +2004-09-25 Ulrich Drepper <drepper@redhat.com> + + * descr.h (struct pthread): Add stopped_start field. + * sysdeps/pthread/createthread.c (create_thread): Set + start_stopped flag in descriptor for new thread appropriately. + * pthread_create.c (start_thread): Only take lock to be stopped on + startup if stopped_start flag says so. + +2004-09-24 Ulrich Drepper <drepper@redhat.com> + + * pthread_create.c (__pthread_create_2_1): Remember whether thread + is created detached and if yes, do not try to free the stack in case + the thread creation failed. + * sysdeps/pthread/createthread.c (do_clone): Free stack here if clone + call fails. Don't depend on INTERNAL_SYSCALL_ERRNO return zero in + case there has been no error. [BZ #405] + + * pthread_create.c (start_thread): Don't wait for scheduler data + etc to be set at the beginning of the function. The cancellation + infrastructure must have been set up. And enable async + cancellation before potentially going to sleep. [BZ #401] + +2004-09-20 Ulrich Drepper <drepper@redhat.com> + + * Versions: Remove exports for pthread_set*id_np functions. + * sysdeps/pthread/pthread.h: Remove pthread_set*id_np prototypes + for now. + * Makefile: Don't build pthread_set*id code for now. + +2004-09-19 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/allocrtsig.c: Allocate second signal for + internal use. + * allocatestack.c (__nptl_setxid): New function. + * descr.h (struct xid_command): Define type. + * init.c (pthread_functions): Add ptr__nptl_setxid initialization. + (sighandler_setxid): New function. + (__pthread_initialize_minimal): Register sighandler_setxid for + SIGCANCEL. + * pt-allocrtsig.c: Update comment. + * pthreadP.h: Define SIGSETXID. Declare __xidcmd variable. + Declare __nptl_setxid. + * sysdeps/pthread/pthread-functions.h: Add ptr__nptl_setxid. + * sysdeps/pthread/pthread.h: Declare pthread_setgid_np, + pthread_setuid_np, pthread_setegid_np, pthread_seteuid_np, + pthread_setregid_np, pthread_setreuid_np, pthread_setresgid_np, + and pthread_setresuid_np. + * pthread_setgid_np.c: New file. + * pthread_setuid_np.c: New file. + * pthread_setegid_np.c: New file. + * pthread_seteuid_np.c: New file. + * pthread_setregid_np.c: New file. + * pthread_setreuid_np.c: New file. + * pthread_setresgid_np.c: New file. + * pthread_setresuid_np.c: New file. + * Versions [libpthread, GLIBC_2.3.4]: Add pthread_setgid_np, + pthread_setuid_np, pthread_setegid_np, pthread_seteuid_np, + pthread_setregid_np, pthread_setreuid_np, pthread_setresgid_np, + and pthread_setresuid_np. + * Makefile (libpthread-routines): Add pthread_setuid, pthread_seteuid, + pthread_setreuid, pthread_setresuid, pthread_setgid, pthread_setegid, + pthread_setregid, and pthread_setresgid. + +2004-09-18 Ulrich Drepper <drepper@redhat.com> + + * allocatestack.c (allocate_stack): Return EAGAIN instead of + ENOMEM when out of memory. + +2004-09-10 Roland McGrath <roland@redhat.com> + + [BZ #379] + * allocatestack.c (allocate_stack): Remove [__ASSUME_CLONE_STOPPED] + code, since we don't try to use the broken CLONE_STOPPED any more. + * pthread_create.c (start_thread): Likewise. + +2004-09-15 Richard Henderson <rth@redhat.com> + + * sysdeps/unix/sysv/linux/alpha/vfork.S: Use libc_hidden_def. + +2004-09-01 David Mosberger <davidm@hpl.hp.com> + + * sysdeps/unix/sysv/linux/ia64/jmpbuf-unwind.h + (__libc_unwind_longjmp): Delete macro and declare as function. + * sysdeps/unix/sysv/linux/ia64/Makefile (sysdep_routines): Mention + __ia64_longjmp, sigstack_longjmp, and __sigstack_longjmp for + nptl directory. + * sysdeps/unix/sysv/linux/ia64/__ia64_longjmp.S: New file. + * sysdeps/unix/sysv/linux/ia64/__sigstack_longjmp.c: New file. + * sysdeps/unix/sysv/linux/ia64/unwind_longjmp.c: New file. + +2004-09-12 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/pthread.h: Make rwlock prototypes available also + for __USE_XOPEN2K. + * sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h: Define rwlock + types also for __USE_XOPEN2K. + * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/sparc/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: Likewise. + [BZ #320] + +2004-09-08 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/pthread.h + (PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP): Make safe for C++. + (PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP): Likewise. + (PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP): Likewise. + (PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP): Likewise. + [BZ #375] + +2004-09-07 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h: Allow + PSEUDO to be used with . prefix. + + * sysdeps/unix/sysv/linux/alpha/pthread_once.c (__pthread_once): + Use atomic_increment instead of atomic_exchange_and_add. + * sysdeps/unix/sysv/linux/sparc/pthread_once.c (__pthread_once): + Likewise. + * sysdeps/unix/sysv/linux/ia64/pthread_once.c (__pthread_once): + Likewise. + * sysdeps/unix/sysv/linux/powerpc/pthread_once.c (__pthread_once): + Likewise. + + * allocatestack.c (allocate_stack): Use atomic_increment_val + instead of atomic_exchange_and_add. + * sysdeps/unix/sysv/linux/sem_post.c (__new_sem_post): Likewise. + * sysdeps/unix/sysv/linux/powerpc/sem_post.c (__new_sem_post): + Likewise. + * sysdeps/pthread/pthread_barrier_wait.c (pthread_barrier_wait): + Likewise. + + * sysdeps/pthread/pthread.h (pthread_once): Remove __THROW since + the initialization function might throw. + +2005-09-05 Richard Henderson <rth@redhat.com> + + * sysdeps/unix/sysv/linux/alpha/sysdep-cancel.h (SINGLE_THREAD_P): + Move definition inside libpthread, libc, librt check. Provide + definition for rtld. + +2004-09-02 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/alpha/jmpbuf-unwind.h: Define __libc_unwind_longjmp. + * sysdeps/i386/jmpbuf-unwind.h: Likewise + * sysdeps/powerpc/jmpbuf-unwind.h: Likewise. + * sysdeps/s390/jmpbuf-unwind.h: Likewise. + * sysdeps/sh/jmpbuf-unwind.h: Likewise. + * sysdeps/sparc/sparc32/jmpbuf-unwind.h: Likewise. + * sysdeps/unix/sysv/linux/ia64/jmpbuf-unwind.h: Likewise. + * sysdeps/x86_64/jmpbuf-unwind.h: Likewise. + * unwind.c: Use it. + + * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h (pthread_cond_t): + Rename __data.__clock to __data.__nwaiters, make it unsigned int. + * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h (pthread_cond_t): + Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: + Decrement __nwaiters. If pthread_cond_destroy has been called and + this is the last waiter, signal pthread_cond_destroy caller and + avoid using the pthread_cond_t structure after unlock. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Likewise. + Read clock type from the least significant bits of __nwaiters instead + of __clock. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/internaltypes.h: Define COND_CLOCK_BITS. + +2004-08-31 Jakub Jelinek <jakub@redhat.com> + + [BZ #342] + * Makefile (tests): Add tst-cond20 and tst-cond21. + * tst-cond20.c: New test. + * tst-cond21.c: New test. + * sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h + (pthread_cond_t): Rename __data.__clock to __data.__nwaiters, make + it unsigned int. + * sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h (pthread_cond_t): + Likewise. + * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h + (pthread_cond_t): Likewise. + * sysdeps/unix/sysv/linux/sparc/bits/pthreadtypes.h (pthread_cond_t): + Likewise. + * sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h (pthread_cond_t): + Likewise. + * sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h (pthread_cond_t): + Likewise. + * sysdeps/unix/sysv/linux/lowlevelcond.sym (cond_clock): Remove. + (cond_nwaiters): New. + (clock_bits): New. + * pthread_cond_destroy.c (__pthread_cond_destroy): Return EBUSY + if there are waiters not signalled yet. + Wait until all already signalled waiters wake up. + * sysdeps/pthread/pthread_cond_wait.c (__condvar_cleanup): Decrement + __nwaiters. If pthread_cond_destroy has been called and this is the + last waiter, signal pthread_cond_destroy caller and avoid using + the pthread_cond_t structure after unlock. + (__pthread_cond_wait): Increment __nwaiters in the beginning, + decrement it when leaving. If pthread_cond_destroy has been called + and this is the last waiter, signal pthread_cond_destroy caller. + * sysdeps/pthread/pthread_cond_timedwait.c (__pthread_cond_timedwait): + Likewise. Read clock type from the least significant bits of + __nwaiters instead of __clock. + * pthread_condattr_setclock.c (pthread_condattr_setclock): Check + whether clock ID can be encoded in COND_CLOCK_BITS bits. + * pthread_condattr_getclock.c (pthread_condattr_getclock): Decode + clock type just from the last COND_CLOCK_BITS bits of value. + * pthread_cond_init.c (__pthread_cond_init): Initialize __nwaiters + instead of __clock, just from second bit of condattr's value. + +2004-08-30 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: Include + bits/wordsize.h. Make the header match i386 header when __WORDSIZE + != 64. + * sysdeps/unix/sysv/linux/x86_64/bits/semaphore.h: Likewise. + +2004-08-15 Roland McGrath <roland@frob.com> + + * pthread_atfork.c: Update copyright terms including special exception + for these trivial files, which are statically linked into executables + that use dynamic linking for the significant library code. + +2004-08-09 Jakub Jelinek <jakub@redhat.com> + + * DESIGN-rwlock.txt: Add decreasing of nr_readers_queued to + pthread_rwlock_rdlock. + * sysdeps/pthread/pthread_rwlock_rdlock (__pthread_rwlock_rdlock): + Decrease __nr_readers_queued after reacquiring lock. + * sysdeps/pthread/pthread_rwlock_timedrdlock + (pthread_rwlock_timedrdlock): Likewise. + Reported by Bob Cook <bobcook47@hotmail.com>. + +2004-08-11 Jakub Jelinek <jakub@redhat.com> + + * tst-rwlock14.c (tf): Read main thread handle from *ARG + before pthread_barrier_wait. + +2004-08-07 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: + Remove unnecessary exception handling data. + +2004-07-23 Jakub Jelinek <jakub@redhat.com> + + [BZ #284] + * sysdeps/pthread/pthread.h (pthread_getcpuclockid): Use __clockid_t + instead of clockid_t. + +2004-07-21 Roland McGrath <roland@redhat.com> + + * Makefile ($(objpfx)multidir.mk): Use $(make-target-directory). + +2004-07-19 Roland McGrath <roland@redhat.com> + + * tst-cancel4.c (tf_waitid): Use WEXITED flag bit if available. + +2004-07-02 Roland McGrath <roland@redhat.com> + + * configure: Don't exit. + +2004-07-14 Kaz Kojima <kkojima@rr.iij4u.or.jp> + + * sysdeps/unix/sysv/linux/sh/pthread_cond_timedwait.S + (__pthread_cond_timedwait): Check for invalid nanosecond in + timeout value. + +2004-07-07 Ulrich Drepper <drepper@redhat.com> + + * Makefile: Add rules to build and run tst-fini1. + * tst-fini1.c: New file. + * tst-fini1mod.c: New file. + +2004-07-05 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h: Define NO_CANCELLATION + if no cancellation support is needed. + * sysdeps/unix/sysv/linux/ia64/sysdep-cancel.h: Likewise. + * sysdeps/unix/sysv/linux/sh/sysdep-cancel.h: Likewise. + * sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h: Likewise. + * sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h: Likewise. + * sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h: Likewise. + * sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h: Likewise. + * sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h: Likewise. + * sysdeps/unix/sysv/linux/sparc/sparc32/sysdep-cancel.h: Likewise. + * sysdeps/unix/sysv/linux/sparc/sparc64/sysdep-cancel.h: Likewise. + + * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h: Define __NR_futex + only if not already defined. + +2004-07-05 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h (lll_unlock): Use + constraint "m" instead of "0" for futex. + + * shlib-versions: Add powerpc64-.*-linux.*. + +2004-07-04 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedrdlock.S + (pthread_rwlock_timedrdlock): Use cmpq instead of cmpl to check + for valid tv_nsec. + * tst-rwlock14.c (do_test): Test for invalid tv_nsec equal to + 1 billion and 64-bit tv_nsec which is valid when truncated to 32 + bits. + +2004-06-29 Roland McGrath <roland@redhat.com> + + * Banner: NPTL no longer has its own version number. + * Makefile (nptl-version): Variable removed. + * sysdeps/pthread/Makefile (CFLAGS-confstr.c): Set LIBPTHREAD_VERSION + using $(version), the glibc version number. + +2004-06-29 Kaz Kojima <kkojima@rr.iij4u.or.jp> + + * sysdeps/unix/sysv/linux/sh/pthread_once.S (__pthread_once): + Fix branch offset for a PLT entry. + * sysdeps/unix/sysv/linux/sh/sem_post.S (__new_sem_post): + Likewise. + * sysdeps/unix/sysv/linux/sh/sem_timedwait.S (sem_timedwait): + Likewise. + * sysdeps/unix/sysv/linux/sh/sem_trywait.S (__new_sem_trywait): + Likewise. + * sysdeps/unix/sysv/linux/sh/sem_wait.S (__new_sem_wait): + Likewise. + +2004-06-28 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/alpha/tcb-offsets.sym (MULTIPLE_THREADS_OFFSET): Define + unconditionally. + +2004-06-28 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/pthread/pthread_rwlock_timedwrlock.c + (pthread_rwlock_timedwrlock): Return EINVAL if tv_nsec is negative, + instead of tv_sec. + * sysdeps/pthread/pthread_rwlock_timedrdlock.c + (pthread_rwlock_timedrdlock): Likewise. + +2004-06-22 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/s390/lowlevellock.h (lll_futex_requeue): + Set __r7 to val, not mutex. + +2004-06-27 Ulrich Drepper <drepper@redhat.com> + + * Makefile: Add rules to build tst-rwlock14. + * tst-rwlock14.c: New file. + +2004-06-24 Boris Hu <boris.hu@intel.com> + + * sysdeps/pthread/pthread_rwlock_timedrdlock.c: Add timeout validation + check. + * sysdeps/pthread/pthread_rwlock_timedwrlock.c: Likewise. + +2004-06-19 Andreas Jaeger <aj@suse.de> + + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: Fix + assembler in last patch. + +2004-06-17 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/pthread_cond_timedwait.c + (__pthread_cond_timedwait): Also check for negativ nanoseconds. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S + (__pthread_cond_timedwait): Check for invalid nanosecond in + timeout value. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: Likewise. + * tst-cond19.c: New file. + * Makefile: Add rules to build and run tst-cond19. + +2004-06-15 Steven Munroe <sjmunroe@us.ibm.com> + + * tst-context1.c (GUARD_PATTERN): Defined. + (tst_context_t): Define struct containing ucontext_t & guard words. + (ctx): Declare as an array of tst_context_t. + (fct): Verify uc_link & guard words are still valid. + (tf): Initialize guard words in ctx. Adjust ctx refs for new struct. + +2004-06-13 Kaz Kojima <kkojima@rr.iij4u.or.jp> + + * sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h (pthread_cond_t): + Add __data.__futex field, reshuffle __data.__clock. + * sysdeps/unix/sysv/linux/sh/pthread_cond_signal.S + (__pthread_cond_signal): Increment __futex at the same time as + __wakeup_seq or __total_seq. Pass address of __futex instead of + address of low 32-bits of __wakeup_seq to futex syscall. + * sysdeps/unix/sysv/linux/sh/pthread_cond_wait.S + (__pthread_cond_wait): Likewise. Pass __futex value from before + releasing internal lock to FUTEX_WAIT. + * sysdeps/unix/sysv/linux/sh/pthread_cond_timedwait.S + (__pthread_cond_timedwait): Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_cond_broadcast.S + (FUTEX_CMP_REQUEUE): Define. + (__pthread_cond_broadcast): Set __futex to 2 * __total_seq. + Use FUTEX_CMP_REQUEUE operation instead of FUTEX_REQUEUE. + Pass __futex value from before the unlock and __futex address instead + of address of low 32-bits of __wakeup_seq to futex syscall. + Fallback to FUTEX_WAKE all on any errors. + +2004-06-08 Jakub Jelinek <jakub@redhat.com> + + * pthread_mutexattr_getpshared.c (pthread_mutex_getpshared): Fix + comment typo. + * pthread_mutexattr_gettype.c (pthread_mutexattr_gettype): Likewise. + * pthread_mutexattr_init.c (__pthread_mutexattr_init): Likewise. + * pthread_mutexattr_settype.c (__pthread_mutexattr_settype): Likewise. + * pthread_mutexattr_setpshared.c (pthread_mutexattr_setpshared): + Likewise. Reported by Bob Cook <bobcook47@hotmail.com>. + +2004-06-11 Martin Schwidefsky <schwidefsky@de.ibm.com> + + * sysdeps/unix/sysv/linux/s390/lowlevellock.h (lll_compare_and_swap): + Add memory clobber to inline assembly. + (__lll_mutex_trylock): Likewise. + (__lll_mutex_cond_trylock): Likewise. + +2004-06-07 Martin Schwidefsky <schwidefsky@de.ibm.com> + + * sysdeps/unix/sysv/linux/s390/lowlevellock.h (lll_futex_requeue): + Pass val argument as 6th system call argument in %r7. + +2004-05-21 Jakub Jelinek <jakub@redhat.com> + + * Makefile (tests): Add tst-cond16. + * sysdeps/unix/sysv/linux/lowlevelcond.sym (cond_futex): Add. + * pthread_cond_init.c (__pthread_cond_init): Clear __data.__futex. + * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h (pthread_cond_t): + Add __data.__futex field, reshuffle __data.__clock. + * sysdeps/unix/sysv/linux/i386/pthread_cond_signal.S + (__pthread_cond_signal): Increment __futex at the same time as + __wakeup_seq or __total_seq. Pass address of __futex instead of + address of low 32-bits of __wakeup_seq to futex syscall. + * sysdeps/unix/sysv/linux/i386/pthread_cond_wait.S + (__pthread_cond_wait): Likewise. Pass __futex value from before + releasing internal lock to FUTEX_WAIT. + * sysdeps/unix/sysv/linux/i386/pthread_cond_timedwait.S + (__pthread_cond_timedwait): Likewise. + * sysdeps/unix/sysv/linux/i386/pthread_cond_broadcast.S + (FUTEX_CMP_REQUEUE): Define. + (__pthread_cond_broadcast): Set __futex to 2 * __total_seq. + Use FUTEX_CMP_REQUEUE operation instead of FUTEX_REQUEUE. + Pass __futex value from before the unlock and __futex address instead + of address of low 32-bits of __wakeup_seq to futex syscall. + Fallback to FUTEX_WAKE all on any errors. + * sysdeps/unix/sysv/linux/alpha/lowlevellock.h (FUTEX_CMP_REQUEUE): + Define. + (lll_futex_requeue): Add val argument, use FUTEX_CMP_REQUEUE + internally. Return non-zero if error, zero if success. + * sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h (pthread_cond_t): + Add __data.__futex field, reshuffle __data.__clock. + * sysdeps/unix/sysv/linux/s390/lowlevellock.h (FUTEX_CMP_REQUEUE): + Define. + (lll_futex_requeue): Add val argument, return 1 unconditionally + for the time being. + * sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h (pthread_cond_t): + Add __data.__futex field, reshuffle __data.__clock. + * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h (FUTEX_CMP_REQUEUE): + Define. + (lll_futex_requeue): Add val argument, use FUTEX_CMP_REQUEUE + internally. Return non-zero if error, zero if success. + * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h + (pthread_cond_t): Add __data.__futex field, reshuffle __data.__clock. + * sysdeps/unix/sysv/linux/sparc/lowlevellock.h (FUTEX_CMP_REQUEUE): + Define. + (lll_futex_requeue): Add val argument, use FUTEX_CMP_REQUEUE + internally. Return non-zero if error, zero if success. + * sysdeps/unix/sysv/linux/sparc/bits/pthreadtypes.h (pthread_cond_t): + Add __data.__futex field, reshuffle __data.__clock. + * sysdeps/unix/sysv/linux/ia64/lowlevellock.h (FUTEX_CMP_REQUEUE): + Define. + (lll_futex_requeue): Add val argument, use FUTEX_CMP_REQUEUE + internally. Return non-zero if error, zero if success. + * sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h (pthread_cond_t): + Add __data.__futex field, reshuffle __data.__clock. + * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h (pthread_cond_t): + Add __data.__futex field, reshuffle __data.__clock. + * sysdeps/pthread/pthread_cond_signal.c (__pthread_cond_signal): + Increment __futex at the same time as __wakeup_seq or __total_seq. + Pass address of __futex instead of address of low 32-bits of + __wakeup_seq to futex syscall. + * sysdeps/pthread/pthread_cond_wait.c (__pthread_cond_wait): Likewise. + Pass __futex value from before releasing internal lock + to FUTEX_WAIT. + * sysdeps/pthread/pthread_cond_timedwait.c (__pthread_cond_timedwait): + Likewise. Avoid unnecessary shadowing of variables. + * sysdeps/pthread/pthread_cond_broadcast.c (__pthread_cond_broadcast): + Set __futex to 2 * __total_seq. Pass __futex value from before the + unlock and __futex address instead of address of low 32-bits of + __wakeup_seq to futex_requeue macro, adjust for new return value + meaning. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_signal.S + (__pthread_cond_signal): Increment __futex at the same time as + __wakeup_seq or __total_seq. Pass address of __futex instead of + address of low 32-bits of __wakeup_seq to futex syscall. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S + (__pthread_cond_wait): Likewise. Pass __futex value from before + releasing internal lock to FUTEX_WAIT. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S + (__pthread_cond_timedwait): Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S + (FUTEX_CMP_REQUEUE): Define. + (__pthread_cond_broadcast): Set __futex to 2 * __total_seq. + Use FUTEX_CMP_REQUEUE operation instead of FUTEX_REQUEUE. + Pass __futex value from before the unlock and __futex address instead + of address of low 32-bits of __wakeup_seq to futex syscall. + Fallback to FUTEX_WAKE all on any errors. + +2004-06-03 Kaz Kojima <kkojima@rr.iij4u.or.jp> + + * sysdeps/unix/sysv/linux/sh/lowlevellock.h (lll_mutex_lock): + Add nop to align the end of critical section. + (lll_mutex_cond_lock, lll_mutex_timedlock): Likewise. + +2004-06-01 Kaz Kojima <kkojima@rr.iij4u.or.jp> + + * sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h (pthread_cond_t): + Add __broadcast_seq field. + * sysdeps/unix/sysv/linux/sh/pthread_cond_broadcast.S: Mark + all waiters as woken with woken_seq and bump broadcast counter. + * sysdeps/unix/sysv/linux/sh/pthread_cond_wait.S: Use new + __broadcast_seq. Increment __woken_seq correctly when cleanuped. + * sysdeps/unix/sysv/linux/sh/pthread_cond_timedwait.S: Likewise. + Comment typo fixes. Avoid returning -ETIMEDOUT. + +2004-06-01 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S + (__condvar_tw_cleanup): Fix access to saved broadcast_seq value. + Reported by Kaz Kojima. + +2004-05-25 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/aio_misc.h: New file. + +2004-05-21 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/pthread/pthread_cond_wait.c (__pthread_cond_wait): Compare + __broadcast_seq with bc_seq after acquiring internal lock instead of + before it. + +2004-05-18 Jakub Jelinek <jakub@redhat.com> + + * Makefile (.NOTPARALLEL): Only serialize make check/xcheck, not + compilation. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S + (__pthread_cond_timedwait): Avoid returning -ETIMEDOUT. + * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h + (pthread_cond_t): Add __data.__broadcast_seq field. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S + (FRAME_SIZE): Define. + (__pthread_cond_timedwait): Use it. Store/check broadcast_seq. + Comment typo fixes. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S (FRAME_SIZE): + Define. + (__pthread_cond_wait): Use it. Store/check broadcast_seq. Comment + typo fixes. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S + (__pthread_cond_broadcast): Increment broadcast_seq. Comment typo + fixes. + +2004-05-18 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/lowlevelcond.sym: Add broadcast_seq entry. + * sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h (pthread_cond_t): + Add __broadcast_seq field. + * sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/sparc/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S: Mark + all waiters as woken with woken_seq and bump broadcast counter. + * sysdeps/pthread/pthread_cond_broadcast.c: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Use new + __broadcast_seq field. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Likewise. + * sysdeps/pthread/pthread_cond_wait.c: Likewise. + * sysdeps/pthread/pthread_cond_timedwait.c: Likewise. + * pthread_cond_init.c: Initialize __broadcast_seq field. + * Makefile (tests): Add tst-cond17 and tst-cond18. + Add .NOTPARALLEL goal. + * tst-cond16.c: New file. From Jakub. + * tst-cond17.c: New file. From Jakub. + * tst-cond18.c: New file. From Jakub. + +2004-05-16 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/i486/sem_timedwait.S: Correct some + unwind info. + + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: + Parametrize frame size. Correct some unwind info. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Likewise. + +2004-05-04 Jakub Jelinek <jakub@redhat.com> + + * tst-stack3.c: Note testing functionality beyond POSIX. + +2004-05-04 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/ia64/sysdep-cancel.h (USE___THREAD): + Change conditional from ifdef to if. + +2004-04-23 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/ia64/sysdep-cancel.h (SYSDEP_CANCEL_ERRNO, + SYSDEP_CANCEL_ERROR): Define. + (PSEUDO): Use it. + +2004-05-01 Jakub Jelinek <jakub@redhat.com> + + * Versions (libpthread): Remove __pthread_cleanup_upto@@GLIBC_PRIVATE. + +2004-04-20 Jakub Jelinek <jakub@redhat.com> + + * sem_unlink.c (sem_unlink): Change EPERM into EACCES. + +2004-04-19 Kaz Kojima <kkojima@rr.iij4u.or.jp> + + * sysdeps/unix/sysv/linux/sh/sem_timedwait.S: Add frame info. + Use HIDDEN_JUMPTARGET to jump to __pthread_unwind. + * sysdeps/unix/sysv/linux/sh/sem_wait.S: Remove unneeded frame + info. Use HIDDEN_JUMPTARGET to jump to __pthread_unwind. + +2004-04-19 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/timer_routines.c: Make sure helper + thread has all signals blocked. + +2004-04-18 Andreas Jaeger <aj@suse.de> + + * sysdeps/unix/sysv/linux/x86_64/bits/semaphore.h + (SEM_VALUE_MAX): Add missing brace. + +2004-04-17 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/pthread/Makefile (tests): Add tst-mqueue8x + in rt subdir. + (CFLAGS-tst-mqueue8x.c): Add -fexceptions. + * sysdeps/pthread/tst-mqueue8x.c: New test. + * tst-cancel4.c: Update comment about message queues. + + * sysdeps/pthread/timer_gettime.c (timer_gettime): For expired timer + return it_value { 0, 0 }. + * sysdeps/pthread/timer_create.c (timer_create): Handle SIGEV_NONE + like SIGEV_SIGNAL. + * sysdeps/pthread/timer_routines.c (thread_expire_timer): Remove + assertion for SIGEV_NONE. + (thread_attr_compare): Compare all attributes, not just a partial + subset. + +2004-04-17 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/mq_notify.c: Include stdlib.h. + +2004-04-17 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/alpha/bits/semaphore.h (SEM_VALUE_MAX): + Just use a plain number. + * sysdeps/unix/sysv/linux/i386/bits/semaphore.h: Likewise. + * sysdeps/unix/sysv/linux/ia64/bits/semaphore.h: Likewise. + * sysdeps/unix/sysv/linux/powerpc/bits/semaphore.h: Likewise. + * sysdeps/unix/sysv/linux/s390/bits/semaphore.h: Likewise. + * sysdeps/unix/sysv/linux/sh/bits/semaphore.h: Likewise. + * sysdeps/unix/sysv/linux/sparc/bits/semaphore.h: Likewise. + * sysdeps/unix/sysv/linux/x86_64/bits/semaphore.h: Likewise. + +2004-04-16 Kaz Kojima <kkojima@rr.iij4u.or.jp> + + * sysdeps/unix/sysv/linux/sh/pthread_cond_wait.S: Remove unneeded + frame info. + * sysdeps/unix/sysv/linux/sh/pthread_cond_timedwait.S: Likewise. + +2004-04-15 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/timer_routines.c: Include errno.h. + (timer_helper_thread): Use inline rt_sigtimedwait syscall instead + of calling sigwaitinfo. + +2004-04-16 Ulrich Drepper <drepper@redhat.com> + + * allocatestack.c (allocate_stack): Set reported_guardsize + unconditionally. + * pthread_getattr_np.c (pthread_getattr_np): Use + reported_guardsize instead of guardsize. + * descr.h (struct pthread): Add reported_guardsize field. + +2004-04-13 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/mq_notify.c: Shut up GCC warning. + +2004-04-12 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/mq-notify.c: New file. + +2004-04-08 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/bits/local_lim.h (MQ_PRIO_MAX): Define. + * sysdeps/unix/sysv/linux/alpha/bits/local_lim.h (MQ_PRIO_MAX): Define. + * sysdeps/unix/sysv/linux/ia64/bits/local_lim.h (MQ_PRIO_MAX): Define. + * sysdeps/unix/sysv/linux/sparc/bits/local_lim.h (MQ_PRIO_MAX): Define. + * sysdeps/unix/sysv/linux/bits/posix_opt.h (_POSIX_MESSAGE_PASSING): + Define. + * sysdeps/unix/sysv/linux/i386/bits/posix_opt.h + (_POSIX_MESSAGE_PASSING): Define. + * sysdeps/unix/sysv/linux/ia64/bits/posix_opt.h + (_POSIX_MESSAGE_PASSING): Define. + * sysdeps/unix/sysv/linux/x86_64/bits/posix_opt.h + (_POSIX_MESSAGE_PASSING): Define. + +2004-04-04 Ulrich Drepper <drepper@redhat.com> + + * tst-context1.c (fct): Check whether correct stack is used. + +2004-04-03 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h: Never use + matching constraints for asm mem parameters. + + * tst-clock2.c (tf): Don't define unless needed. + +2004-03-30 H.J. Lu <hongjiu.lu@intel.com> + + * Makefile (link-libc-static): Use $(static-gnulib) instead of + $(gnulib). + +2004-03-30 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/pthread-functions.h: Add ptr__nptl_deallocate_tsd. + * init.c (pthread_functions): Add ptr__nptl_deallocate_tsd. + * pthreadP.h: Declare __nptl_deallocate_tsd. + * pthread_create.c (deallocate_tsd): Remove to __nptl_deallocate_tsd. + Adjust caller. + + * Makefile (tests): Add tst-tsd5. + * tst-tsd5.c: New file. + +2004-03-29 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/pthread_attr_setaffinity.c + (__pthread_attr_setaffinity_old): Prepend GLIBC_ to version names + is SHLIB_COMPAT check. + * sysdeps/unix/sysv/linux/pthread_attr_getaffinity.c + (__pthread_attr_getaffinity_old): Likewise. + * sysdeps/unix/sysv/linux/pthread_getaffinity.c + (__pthread_getaffinity_old): Likewise. + * sysdeps/unix/sysv/linux/pthread_setaffinity.c + (__pthread_setaffinity_old): Likewise. + +2004-03-26 Ulrich Drepper <drepper@redhat.com> + + * allocatestack.c (_make_stacks_executable): Call + _dl_make_stack_executable first. + +2004-03-24 Roland McGrath <roland@redhat.com> + + * sysdeps/i386/pthread_spin_lock.c (pthread_spin_lock): Use "m" + constraint instead of "0". + +2004-03-24 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h + (lll_mutex_cond_trylock): Define as wrapper around __lll_cond_trylock. + + * sysdeps/unix/sysv/linux/getpid.c (really_getpid): Reorganize + code to avoid warning. + +2004-03-24 Andreas Jaeger <aj@suse.de> + + * sysdeps/unix/sysv/linux/pthread_attr_setaffinity.c + (__pthread_attr_setaffinity_old): Remove const. + +2004-03-23 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/smp.h: New file. + * sysdeps/unix/sysv/linux/sh/smp.h: New file. + * init.c: Define __is_smp. + (__pthread_initialize_minimal_internal): Call is_smp_system to + initialize __is_smp. + * pthreadP.h: Declare __is_smp. + Define MAX_ADAPTIVE_COUNT is necessary. + * pthread_mutex_init.c: Add comment regarding __spins field. + * pthread_mutex_lock.c: Implement adaptive mutex type. + * pthread_mutex_timedlock.c: Likewise. + * sysdeps/unix/sysv/linux/pthread_mutex_cond_lock.c: Likewise. + * sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h (pthread_mutex_t): + Add __spins field. + * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/sparc/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h: Define + lll_mutex_cond_trylock. + * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/sparc/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h: Likewise. + Define BUSY_WAIT_NOP. + * sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: Likewise. + + * tst-mutex5.c: Add support for testing adaptive mutexes. + * tst-mutex7.c: Likewise. + * tst-mutex5a.c: New file. + * tst-mutex7a.c: New file. + * Makefile (tests): Add tst-mutex5a and tst-mutex7a. + + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.S + (__lll_mutex_timedlock_wait): Preserve r8 and r9 since the + vgettimeofday call might destroy the content. + + * sysdeps/ia64/pthread_spin_lock.c (pthread_spin_lock): Use hint + @pause in the loop. + + * sysdeps/unix/sysv/linux/i386/lowlevellock.h (lll_mutex_trylock): + No need to restrict type of ret. Make it int. Add comment. + + * sysdeps/unix/sysv/linux/i386/lowlevellock.h (lll_mutex_trylock): + Remove unnecessary setne instruction. + +2004-03-22 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/pthread_getaffinity.c + (__pthread_getaffinity_new): Use INT_MAX instead of UINT_MAX. + * pthread_getattr_np.c (pthread_getattr_np): Double size every cycle. + If realloc fails, break out of the loop. + +2004-03-20 Andreas Jaeger <aj@suse.de> + + * sysdeps/unix/sysv/linux/pthread_setaffinity.c + (__pthread_setaffinity_old): Fix interface. + * sysdeps/unix/sysv/linux/pthread_getaffinity.c + (__pthread_getaffinity_old): Likewise. + + * sysdeps/unix/sysv/linux/pthread_setaffinity.c + (__pthread_setaffinity_new): Remove duplicate declaration. + +2004-03-20 Kaz Kojima <kkojima@rr.iij4u.or.jp> + + * sysdeps/unix/sysv/linux/sh/sysdep-cancel.h (CENABLE): Save + the return value to a safe register. + (CDISABLE): Set the function argument correctly. + +2004-03-17 Kaz Kojima <kkojima@rr.iij4u.or.jp> + + * sysdeps/unix/sysv/linux/sh/lowlevel-atomic.h (XCHG): Define. + * sysdeps/unix/sysv/linux/sh/lowlevellock.S (__lll_mutex_lock_wait): + Rewrite so that only one locked memory operation per round is needed. + * sysdeps/unix/sysv/linux/sh/pthread_barrier_wait.S + (pthread_barrier_wait): After wakeup, release lock only when the + last thread stopped using the barrier object. + * sysdeps/unix/sysv/linux/sh/pthread_cond_wait.S + (__pthread_cond_wait): Don't store mutex address if the current + value is ~0l. Add correct cleanup support and unwind info. + * sysdeps/unix/sysv/linux/sh/pthread_cond_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_cond_broadcast.S + (__pthread_cond_broadcast): Don't use requeue for pshared condvars. + * sysdeps/unix/sysv/linux/sh/pthread_cond_signal.S: Update comment. + * sysdeps/unix/sysv/linux/sh/pthread_once.S (__pthread_once): + Add correct cleanup support and unwind info. + * sysdeps/unix/sysv/linux/sh/sem_wait.S (__new_sem_wait): Likewise. + * sysdeps/unix/sysv/linux/sh/sysdep-cancel.h: Add unwind + information for syscall wrappers. + +2004-03-18 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/internaltypes.h (struct pthread_attr): Add + cpusetsize field, remove next. + * sysdeps/pthread/pthread.h (pthread_getaffinity_np): Add new second + parameter for size of the CPU set. + (pthread_setaffinity_np): Likewise. + (pthread_attr_getaffinity_np): Likewise. + (pthread_attr_setaffinity_np): Likewise. + * sysdeps/unix/sysv/linux/pthread_attr_getaffinity.c: Implement + interface change, keep compatibility code. + * sysdeps/unix/sysv/linux/pthread_attr_setaffinity.c: Likewise. + * sysdeps/unix/sysv/linux/pthread_getaffinity.c: Likewise. + * sysdeps/unix/sysv/linux/pthread_setaffinity.c: Likewise. + * pthreadP.h: Remove hidden_proto for pthread_getaffinity_np. Declare + __pthread_getaffinity_np. + * Versions: Add version for changed interfaces. + * tst-attr3.c: Adjust test for interface change. + * pthread_getattr_np.c: Query the kernel about the affinity mask with + increasing buffer sizes. + * pthread_attr_destroy.c: Remove unused list handling. + * pthread_attr_init.c: Likewise. + +2004-03-17 Roland McGrath <roland@redhat.com> + + * sysdeps/unix/sysv/linux/timer_create.c (timer_create): Pass missing + first argument to clock_getres so we ever enable kernel timers. + +2004-03-15 Ulrich Weigand <uweigand@de.ibm.com> + + * init.c (nptl_version): Add __attribute_used__ to nptl_version. + +2004-03-12 Richard Henderson <rth@redhat.com> + + * sysdeps/unix/sysv/linux/alpha/sysdep-cancel.h: Propagate + oldvalue from CENABLE to CDISABLE. + +2004-03-12 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/bits/local_lim.h: Define HOST_NAME_MAX. + * sysdeps/unix/sysv/linux/alpha/bits/local_lim.h: Likewise. + * sysdeps/unix/sysv/linux/ia64/bits/local_lim.h: Likewise. + * sysdeps/unix/sysv/linux/sparc/bits/local_lim.h: Likewise. + +2004-03-11 Richard Henderson <rth@redhat.com> + + * sysdeps/alpha/tcb-offsets.sym (PID_OFFSET): New. + * sysdeps/unix/sysv/linux/alpha/pt-vfork.S: Save/restore PID. + * sysdeps/unix/sysv/linux/alpha/vfork.S: New file. + +2004-03-11 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/s390/s390-64/vfork.S (__vfork): Use jgnl + instead of jnl instruction to jump to SYSCALL_ERROR_LABEL. + * sysdeps/unix/sysv/linux/s390/s390-64/pt-vfork.S (__vfork): Likewise. + +2004-03-11 Jakub Jelinek <jakub@redhat.com> + + * forward.c (__pthread_cond_broadcast_2_0, + __pthread_cond_destroy_2_0, __pthread_cond_init_2_0, + __pthread_cond_signal_2_0, __pthread_cond_wait_2_0, + __pthread_cond_timedwait_2_0): Use return 0 as defaction instead of 0. + +2004-03-11 Kaz Kojima <kkojima@rr.iij4u.or.jp> + + * sysdeps/sh/tcb-offsets.sym: Add PID. + * sysdeps/unix/sysv/linux/sh/pt-vfork.S: Properly handle PID cache. + * sysdeps/unix/sysv/linux/sh/vfork.S: New file. + +2004-03-10 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/powerpc/powerpc32/vfork.S: No need to + include <sysdep-cancel.h>, vfork is no cancellation point. + * sysdeps/unix/sysv/linux/powerpc/powerpc64/vfork.S: Likewise. + * sysdeps/unix/sysv/linux/powerpc/powerpc64/pt-vfork.S: Likewise. + * sysdeps/unix/sysv/linux/powerpc/powerpc32/pt-vfork.S: Likewise. + +2004-03-10 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/s390/s390-32/vfork.S (__vfork): Add + libc_hidden_def. + * sysdeps/unix/sysv/linux/s390/s390-64/vfork.S (__vfork): Likewise. + * sysdeps/unix/sysv/linux/powerpc/powerpc32/vfork.S (__vfork): + Likewise. + * sysdeps/unix/sysv/linux/powerpc/powerpc64/vfork.S (__vfork): + Likewise. + * sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S (__vfork): Likewise. + * sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S (__vfork): Likewise. + * sysdeps/unix/sysv/linux/ia64/pt-vfork.S: Include tcb-offsets.h. + * sysdeps/unix/sysv/linux/ia64/vfork.S (__vfork): Use DO_CALL instead + of DO_CALL_VIA_BREAK. Work around a gas problem. + + * sysdeps/unix/sysv/linux/powerpc/pt-vfork.S: Remove. + * sysdeps/unix/sysv/linux/powerpc/powerpc32/vfork.S: New file. + * sysdeps/unix/sysv/linux/powerpc/powerpc32/pt-vfork.S: New file. + * sysdeps/unix/sysv/linux/powerpc/powerpc64/vfork.S: New file. + * sysdeps/unix/sysv/linux/powerpc/powerpc64/pt-vfork.S: New file. + * sysdeps/powerpc/tcb-offsets.sym: Add PID. + + * sysdeps/unix/sysv/linux/ia64/pt-vfork.S (__vfork): Don't use + a local register for saving old PID. Negate PID in parent upon exit. + + * sysdeps/unix/sysv/linux/s390/s390-32/pt-vfork.S: Include + tcb-offsets.h. + (__vfork): Negate PID if non-zero and set to INT_MIN if zero + before syscall, set to the old value in the parent afterwards. + * sysdeps/unix/sysv/linux/s390/s390-32/vfork.S: New file. + * sysdeps/unix/sysv/linux/s390/s390-64/pt-vfork.S: Include + tcb-offsets.h. + (__vfork): Negate PID if non-zero and set to INT_MIN if zero + before syscall, set to the old value in the parent afterwards. + * sysdeps/unix/sysv/linux/s390/s390-64/vfork.S: New file. + * sysdeps/s390/tcb-offsets.sym: Add PID. + + * sysdeps/unix/sysv/linux/sparc/pt-vfork.S: Remove. + * sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S: New file. + * sysdeps/unix/sysv/linux/sparc/sparc32/pt-vfork.S: New file. + * sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S: New file. + * sysdeps/unix/sysv/linux/sparc/sparc64/pt-vfork.S: New file. + * sysdeps/sparc/tcb-offsets.sym: Add PID. + +2004-03-10 Andreas Schwab <schwab@suse.de> + + * sysdeps/ia64/tcb-offsets.sym: Add PID. + * sysdeps/unix/sysv/linux/ia64/vfork.S: New file. + * sysdeps/unix/sysv/linux/ia64/pt-vfork.S: Properly handle PID cache. + +2004-03-09 Jakub Jelinek <jakub@redhat.com> + + * tst-cancel20.c (do_one_test): Clear in_sh_body first. + * tst-cancel21.c (do_one_test): Likewise. + Reported by Gordon Jin <gordon.jin@intel.com>. + +2004-02-09 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/i386/vfork.S (SAVE_PID): Negate PID + if non-zero and set to INT_MIN if zero. + * sysdeps/unix/sysv/linux/x86_64/vfork.S (SAVE_PID): Likewise. + * sysdeps/unix/sysv/linux/i386/pt-vfork.S: Include tcb-offsets.h. + (SAVE_PID, RESTORE_PID): Define. + (__vfork): Use it. + * sysdeps/unix/sysv/linux/x86_64/pt-vfork.S: Include tcb-offsets.h. + Use relative path to avoid including NPTL i386/vfork.S. + (SAVE_PID, RESTORE_PID): Define. + * sysdeps/unix/sysv/linux/raise.c: Include limits.h. + (raise): Handle THREAD_SELF->pid INT_MIN the same as 0. + * Makefile (tests): Add tst-vfork1, tst-vfork2, tst-vfork1x and + tst-vfork2x. + (tests-reverse): Add tst-vfork1x and tst-vfork2x. + * tst-vfork1.c: New test. + * tst-vfork2.c: New test. + * tst-vfork1x.c: New test. + * tst-vfork2x.c: New test. + +2004-03-08 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/i386/tcb-offsets.sym: Add PID. + * sysdeps/x86_64/tcb-offsets.sym: Likewise. + * sysdeps/unix/sysv/linux/i386/vfork.S: New file. + * sysdeps/unix/sysv/linux/x86_64/vfork.S: New file. + +2004-03-08 Steven Munroe <sjmunroe@us.ibm.com> + + * sysdeps/unix/sysv/linux/powerpc/Versions: Remove leading tabs. + +2004-03-08 H.J. Lu <hongjiu.lu@intel.com> + + * sysdeps/s390/tls.h (INIT_SYSINFO): _dl_sysinfo is now in + _rtld_global_ro. + +2004-03-07 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/ia64/tls.h (INIT_SYSINFO): _dl_sysinfo is now in + _rtld_global_ro. + + * tst-once4.c: Remove unnecessary macro definition. + + * tst-mutex7.c (do_test): Limit thread stack size. + * tst-once2.c (do_test): Likewise. + * tst-tls3.c (do_test): Likewise. + * tst-tls1.c (do_test): Likewise. + * tst-signal3.c (do_test): Likewise. + * tst-kill6.c (do_test): Likewise. + * tst-key4.c (do_test): Likewise. + * tst-join4.c (do_test): Likewise. + * tst-fork1.c (do_test): Likewise. + * tst-context1.c (do_test): Likewise. + * tst-cond2.c (do_test): Likewise. + * tst-cond10.c (do_test): Likewise. + * tst-clock2.c (do_test): Likewise. + * tst-cancel10.c (do_test): Likewise. + * tst-basic2.c (do_test): Likewise. + * tst-barrier4.c (do_test): Likewise. + +2004-03-05 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/i386/tls.h: Use GLRO instead of GL where appropriate. + +2004-03-01 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S + (__pthread_cond_timedwait): Optimize wakeup test. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S + (__pthread_cond_wait): Likewise. + * sysdeps/pthread/pthread_cond_wait.c (__pthread_cond_wait): Likewise. + * sysdeps/pthread/pthread_cond_timedwait.c (__pthread_cond_timedwait): + Likewise. + +2004-02-29 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S + (__lll_mutex_lock_wait): Optimize a bit more. Just one copy of + the atomic instruction needed. + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.S + (__lll_mutex_lock_wait): Likewise. + +2004-02-28 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add tst-cond14 and tst-cond15. + * tst-cond14.c: New file. + * tst-cond15.c: New file. + +2004-02-27 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/createthread.c (create_thread): Remove use of + CLONE_STOPPED. We cannot use SIGCONT which means CLONE_STOPPED + needs to be implemented differently to be useful. + +2004-02-26 Ulrich Drepper <drepper@redhat.com> + + * pthread_attr_setschedparam.c: Don't test priority against limits + here. Set ATTR_FLAG_SCHED_SET flag. + * pthread_attr_setschedpolicy.c: Set ATTR_FLAG_POLICY_SET flag. + * pthread_create.c (__pthread_create_2_1): Copy scheduling attributes + from parent thread to child. If attribute is used and scheduling + parameters are not inherited, copy parameters from attribute or + compute them. Check priority value. + * pthread_getschedparam.c: If the parameters aren't known yet get + them from the kernel. + * pthread_setschedparam.c: Set ATTR_FLAG_SCHED_SET and + ATTR_FLAG_POLICY_SET flag for thread. + * sysdeps/unix/sysv/linux/internaltypes.h: Define ATTR_FLAG_SCHED_SET + and ATTR_FLAG_POLICY_SET. + + * sysdeps/pthread/createthread.c: Use tgkill if possible. + + * pthread_attr_getstackaddr.c (__pthread_attr_getstackaddr): Don't + fail if stack address hasn't been set. Just return 0. + +2004-02-25 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests-nolibpthread): Add tst-unload. Don't link with + libpthread for the files in this list. + (CFLAGS-tst-unload): Removed. + * tst-unload.c (do_test): Don't use complete path for + LIBPHREAD_SO. + + * Makefile: Define sonames for tst-tls5mod, tst-_res1mod1, and + tst-_res1mod2. + +2004-02-22 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S + (__lll_mutex_lock_wait): Rewrite so that only one locked memory + operation per round is needed. + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.S + (__lll_mutex_lock_wait): Likewise. + +2004-02-20 Ulrich Drepper <drepper@redhat.com> + + * tst-cancel9.c (cleanup): Don't print to stderr. + +2004-02-20 Kaz Kojima <kkojima@rr.iij4u.or.jp> + + * sysdeps/sh/jmpbuf-unwind.h (_JMPBUF_UNWINDS_ADJ): Fix variable name. + +2004-02-20 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/sparc/sparc32/sysdep-cancel.h + (__syscall_error_handler2): Call CDISABLE. + * sysdeps/unix/sysv/linux/sparc/sparc64/sysdep-cancel.h + (__syscall_error_handler2): Call CDISABLE. + + * sysdeps/pthread/pthread_barrier_wait.c (pthread_barrier_wait): + Release lock before the loop, don't reacquire it. + + * sysdeps/unix/sysv/linux/ia64/dl-sysdep.h (DL_ARGV_NOT_RELRO): Define. + +2004-02-19 Andreas Schwab <schwab@suse.de> + + * sysdeps/pthread/pthread_barrier_wait.c (pthread_barrier_wait): + Fix last change. + +2004-02-18 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/i486/pthread_barrier_wait.S + (pthread_barrier_wait): After wakeup, release lock only when the + last thread stopped using the barrier object. + * sysdeps/unix/sysv/linux/x86_64/pthread_barrier_wait.S + (pthread_barrier_wait): Likewise. + * sysdeps/pthread/pthread_barrier_wait.c (pthread_barrier_wait): + Likewise. + * Makefile (tests): Add tst-barrier4. + * tst-barrier4.c: New file. + + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S + (__pthread_cond_timedwait): Perform timeout test while holding + internal lock to prevent wakeup race. + Patch by Dinakar Guniguntala <dgunigun@in.ibm.com>. + * sysdeps/pthread/pthread_cond_timedwait.c + (__pthread_cond_timedwait): Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S + (__pthread_cond_timedwait): Likewise. + +2004-02-18 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_unlock.S + (__pthread_rwlock_unlock): Access WRITER as 32-bit value. + * Makefile (tests): Add tst-rwlock13. + * tst-rwlock13.c: New test. + +2004-02-16 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S + (__condvar_tw_cleanup): Little optimization. + Patch by Dinakar Guniguntala <dgunigun@in.ibm.com>. + +2004-02-16 Steven Munroe <sjmunroe@us.ibm.com> + + * sysdeps/unix/sysv/linux/powerpc/pt-longjmp.c: Replace libc with + libpthread as "lib" parameter to SHLIB_COMPAT. + (__novmx_siglongjmp): Fix typo in function name. + (__novmx_longjmp): Fix typo in function name. + +2004-02-13 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/pthread_cond_wait.c (__pthread_cond_wait): Add a + __builtin_expect. + + * sysdeps/generic/pt-longjmp.c: Moved to... + * sysdeps/pthread/pt-longjmp.c: ...here. New file. + +2004-01-29 Steven Munroe <sjmunroe@us.ibm.com> + + * Makefile (libpthread-routines): Add pt-cleanup. + * pt-longjmp.c: Removed. + * pt-cleanup.c: Copied __pthread_cleanup_upto to here. New file. + * sysdeps/generic/pt-longjmp.c: Copied longjmp to here. New file. + * sysdeps/unix/sysv/linux/powerpc/Versions: New file. + Version longjmp, siglongjmp for GLIBC_2.3.4. + * sysdeps/unix/sysv/linux/powerpc/pt-longjmp.c: New File. + +2004-02-13 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/pthread_cond_timedwait.c + (__pthread_cond_timedwait): Optimize. Drop internal lock earlier. + Reuse code. Add __builtin_expects. + + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S + (__pthread_cond_timedwait): Get internal lock in case timeout has + passed before the futex syscall. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: Likewise. + +2004-01-20 Ulrich Drepper <drepper@redhat.com> + + * allocatestack.c: Pretty printing. + + * sysdeps/pthread/createthread.c (create_thread): Don't add + CLONE_DETACHED bit if it is not necessary. + +2004-01-16 Ulrich Drepper <drepper@redhat.com> + + * pthread_getattr_np.c: Include ldsodefs.h. + +2004-01-16 Richard Henderson <rth@redhat.com> + + * allocatestack.c: Don't declare __libc_stack_end. + * init.c (__pthread_initialize_minimal_internal): Likewise. + * pthread_getattr_np.c (pthread_getattr_np): Likewise. + +2004-01-15 Richard Henderson <rth@redhat.com> + + * sysdeps/alpha/tls.h (tcbhead_t): Add private. + (TLS_INIT_TCB_SIZE, TLS_INIT_TCB_ALIGN, TLS_TCB_SIZE, + TLS_PRE_TCB_SIZE, TLS_TCB_ALIGN, INSTALL_DTV, INSTALL_NEW_DTV, + GET_DTV, THREAD_DTV, THREAD_SELF, DB_THREAD_SELF): Match ia64. + (TLS_TCB_OFFSET, THREAD_ID, NO_TLS_OFFSET): Remove. + (THREAD_GETMEM, THREAD_GETMEM_NC): Simplify. + (THREAD_SETMEM, THREAD_SETMEM_NC): Likewise. + * sysdeps/unix/sysv/linux/alpha/createthread.c (TLS_VALUE): Match ia64. + +2004-01-14 Ulrich Drepper <drepper@redhat.com> + + * init.c (pthread_functions): Make array const. + +2004-01-13 Ulrich Drepper <drepper@redhat.com> + + * allocatestack.c (__make_stacks_executable): Change interface. + Check parameters. Pass parameter on to libc counterpart. + * pthreadP.h: Change declaration. + +2004-01-13 Richard Henderson <rth@redhat.com> + + * pthread_attr_setstack.c (__old_pthread_attr_setstack): Use + prototype form. + * pthread_attr_setstacksize.c (__old_pthread_attr_setstacksize): + Likewise. + + * sysdeps/alpha/Makefile: New file. + * sysdeps/alpha/tcb-offsets.sym: New file. + * sysdeps/unix/sysv/linux/alpha/sysdep-cancel.h (SINGLE_THREAD_P): + Use MULTIPLE_THREADS_OFFSET to implement !libpthread !libc version. + + * sysdeps/unix/sysv/linux/alpha/lowlevellock.h: Rewrite based + on powerpc version. + +2004-01-08 Jakub Jelinek <jakub@redhat.com> + + * Makefile (tests): Add tst-backtrace1. + * tst-backtrace1.c: New test. + +2003-12-11 Ulrich Weigand <uweigand@de.ibm.com> + + * sysdeps/alpha/tls.h (DB_THREAD_SELF): Pass bit size of thread + register as second parameter to the REGISTER macro. + * sysdeps/ia64/tls.h (DB_THREAD_SELF): Likewise. + * sysdeps/powerpc/tls.h (DB_THREAD_SELF): Likewise. + * sysdeps/sh/tls.h (DB_THREAD_SELF): Likewise. + * sysdeps/sparc/tls.h (DB_THREAD_SELF): Likewise. + * sysdeps/s390/tls.h (DB_THREAD_SELF): Pass __WORDSIZE as bit size + of thread register as second parameter to REGISTER macro in 64 case. + +2004-01-03 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/Makefile (CFLAGS-getpid.c): Removed. + (CFLAGS-getpid.o): Defined. + (CFLAGS-getpid.os): Defined. + +2003-12-31 Ulrich Drepper <drepper@redhat.com> + + * pthread_getattr_np.c (pthread_getattr_np): Make sure stack info + returned for main thread does not overlap with any other VMA. + Patch by Jakub Jelinek. + +2003-12-29 Jakub Jelinek <jakub@redhat.com> + + * tst-raise1.c: Include stdio.h. + +2003-12-23 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/raise.c (raise): Protect pid = selftid + setting with __ASSUME_TGKILL || defined __NR_tgkill. + If pid is 0, set it to selftid. + * sysdeps/unix/sysv/linux/getpid.c (really_getpid): Make inline. + Don't set self->pid but self->tid. If self->pid == 0 and self->tid + != 0, return self->tid without doing a syscall. + * descr.h (struct pthread): Move pid field after tid. + + * Makefile (tests): Add tst-raise1. + * tst-raise1.c: New file. + +2003-12-23 Roland McGrath <roland@redhat.com> + + * tst-oddstacklimit.c: New file. + * Makefile (tests): Add it. + (tst-oddstacklimit-ENV): New variable. + + * init.c (__pthread_initialize_minimal_internal): Round stack rlimit + value up to page size for __default_stacksize. + +2003-12-21 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add tst-eintr5. + * tst-eintr5.c: New file. + + * eintr.c (eintr_source): Prevent sending signal to self. + + * tst-eintr2.c (tf1): Improve error message. + +2003-12-20 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/Makefile (CFLAGS-getpid.c): Define. + * sysdeps/unix/sysv/linux/getpid.c: New file. + * pthread_cancel.c: Add comment explaining use of PID field. + * sysdeps/unix/sysv/linux/pthread_kill.c: Likewise. + * pthread_getattr_np.c: Use abs() when comparing PID and TID fields. + * sysdeps/unix/sysv/linux/fork.c: Negate PID field of parent + temporarily to signal the field must not be relied on and updated + by getpid(). + * sysdeps/unix/sysv/linux/pt-raise.c: Handle case where PID is + temporarily negative. + * sysdeps/unix/sysv/linux/raise.c: Likewise. + +2003-12-19 Ulrich Drepper <drepper@redhat.com> + + * eintr.c (setup_eintr): Add new parameter. Pass to thread function. + (eintr_source): If ARG != NULL, use pthread_kill. + * tst-eintr1.c: Adjust for this change. + * tst-eintr2.c: Likewise. + * Makefile (tests): Add tst-eintr3 and tst-eintr4. + * tst-eintr3.c: New file. + * tst-eintr4.c: New file. + +2003-12-19 Jakub Jelinek <jakub@redhat.com> + + * libc-cancellation.c (__libc_enable_asynccancel): Don't cancel + if CANCELSTATE_BITMASK is set. + * sysdeps/pthread/librt-cancellation.c (__librt_enable_asynccancel): + Likewise. + + * Makefile (tests): Add tst-cancel22 and tst-cancel23. + (tests-reverse): Add tst-cancel23. + * tst-cancel22.c: New test. + * tst-cancel23.c: New test. + +2003-12-18 Ulrich Drepper <drepper@redhat.com> + + * tst-eintr1.c: Better error messages. + + * Makefile (tests): Add tst-eintr2. + * tst-eintr2.c: New file. + +2003-12-18 Jakub Jelinek <jakub@redhat.com> + + * Makefile (tests): Add tst-cancel21 and tst-cancelx21. + (CFLAGS-tst-cancelx21.c): Set. + * tst-cancel21.c: New test. + * tst-cancelx21.c: New test. + + * unwind.c (FRAME_LEFT): Add adj argument. Subtract it from each + comparison operand. + (unwind_stop): Use _JMPBUF_CFA_UNWINDS_ADJ macro instead of + _JMPBUF_CFA_UNWINDS. Adjust FRAME_LEFT invocations. + * pt-longjmp.c: Include jmpbuf-unwind.h. + (__pthread_cleanup_upto): Use _JMPBUF_UNWINDS_ADJ macro instead of + _JMPBUF_UNWINDS. Adjust compared pointers. + * init.c (__pthread_initialize_minimal_internal): Initialize + pd->stackblock_size. + * sysdeps/pthread/jmpbuf-unwind.h: Removed. + * sysdeps/alpha/jmpbuf-unwind.h: New file. + * sysdeps/i386/jmpbuf-unwind.h: New file. + * sysdeps/powerpc/jmpbuf-unwind.h: New file. + * sysdeps/s390/jmpbuf-unwind.h: New file. + * sysdeps/sh/jmpbuf-unwind.h: New file. + * sysdeps/sparc/sparc32/jmpbuf-unwind.h: New file. + * sysdeps/x86_64/jmpbuf-unwind.h: New file. + * sysdeps/unix/sysv/linux/ia64/jmpbuf-unwind.h: Include stdint.h. + (_JMPBUF_CFA_UNWINDS): Remove. + (_JMPBUF_CFA_UNWINDS_ADJ, _JMPBUF_UNWINDS_ADJ): Define. + +2003-12-12 Jakub Jelinek <jakub@redhat.com> + + * Makefile (tests): Add tst-cancel20 and tst-cancelx20. + (CFLAGS-tst-cancelx20.c): Set. + * tst-cancel20.c: New test. + * tst-cancelx20.c: New test. + +2003-12-17 Ulrich Drepper <drepper@redhat.com> + + * init.c (__pthread_initialize_minimal_internal): Don't treat + architectures with separate register stack special here when + computing default stack size. + +2003-12-17 Roland McGrath <roland@redhat.com> + + * Makefile (tst-cancelx7-ARGS): New variable. + Reportd by Greg Schafer <gschafer@zip.com.au>. + +2003-12-17 Jakub Jelinek <jakub@redhat.com> + + * Makefile (tests): Add tst-stack3. Depend on $(objpfx)tst-stack3-mem. + (generated): Add tst-stack3.mtrace and tst-stack3-mem. + (tst-stack3-ENV): Set. + ($(objpfx)tst-stack3-mem): New. + * tst-stack3.c: New test. + +2003-12-10 David Mosberger <davidm@hpl.hp.com> + + * sysdeps/unix/sysv/linux/ia64/pt-initfini.c (_init_EPILOG_BEGINS): + Add unwind directives. Drop unused .regstk directive. + (_fini_EPILOG_BEGINS): Add unwind directives. + +2003-12-11 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/lowlevellock.h (lll_futex_wait): + Assume parameter is a pointer. + (lll_futex_wake): Likewise. + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h (lll_futex_wait): + Likewise. + (lll_futex_wake): Likewise. + Reported by Boris Hu. + * sysdeps/unix/sysv/linux/unregister-atfork.c + (__unregister_atfork): Pass pointer to refcntr to lll_futex_wait. + + * sysdeps/unix/sysv/linux/sem_wait.c (__new_sem_wait): Simplify a bit. + +2003-12-10 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/bits/libc-lock.h (__rtld_lock_initialize): Define. + * sysdeps/unix/sysv/linux/fork.c (__libc_fork): Call + __rtld_lock_initialize for ld.so lock. + Patch in part by Adam Li <adam.li@intel.com>. + +2003-12-02 David Mosberger <davidm@hpl.hp.com> + + * Makefile (link-libc-static): Remove -lgcc_eh---it's already mentioned + in $(gnulib). Also, remove stale comment. + +2003-11-12 David Mosberger <davidm@hpl.hp.com> + + * sysdeps/unix/sysv/linux/ia64/sysdep-cancel.h (PSEUDO): Take + advantage of new syscall stub and optimize accordingly. + + * sysdeps/unix/sysv/linux/ia64/lowlevellock.h (__NR_futex): Rename + from SYS_futex, to match expectations of + sysdep.h:DO_INLINE_SYSCALL. + (lll_futex_clobbers): Remove. + (lll_futex_timed_wait): Rewrite in terms of DO_INLINE_SYSCALL. + (lll_futex_wake): Likewise. + (lll_futex_requeue): Likewise. + (__lll_mutex_trylock): Rewrite to a macro, so we can include this + file before DO_INLINE_SYSCALL is defined (proposed by Jakub + Jelinek). + (__lll_mutex_lock): Likewise. + (__lll_mutex_cond_lock): Likewise. + (__lll_mutex_timed_lock): Likewise. + (__lll_mutex_unlock): Likewise. + (__lll_mutex_unlock_force): Likewise. + + * sysdeps/ia64/tls.h: Move declaration of __thread_self up so it + comes before the include of <sysdep.h>. + (THREAD_SELF_SYSINFO): New macro. + (THREAD_SYSINFO): Likewise. + (INIT_SYSINFO): New macro. + (TLS_INIT_TP): Call INIT_SYSINFO. + + * sysdeps/ia64/tcb-offsets.sym: Add SYSINFO_OFFSET. + + * sysdeps/pthread/createthread.c (create_thread): Use + THREAD_SELF_SYSINFO and THREAD_SYSINFO instead of open code. + * allocatestack.c (allocate_stack): Use THREAD_SYSINFO and + THREAD_SELF_SYSINFO instead of open code. + * sysdeps/i386/tls.h (THREAD_SELF_SYSINFO): New macro. + (THREAD_SYSINFO): Likewise. + + * sysdeps/unix/sysv/linux/ia64/dl-sysdep.h: New file. + + * sysdeps/unix/sysv/linux/ia64/pt-vfork.S: Work around gas problem. + +2003-12-06 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/ia64/pt-initfini.c: Use .init_array + instead of .init. Patch by David Mosberger. + +2003-11-30 Thorsten Kukuk <kukuk@suse.de> + + * sysdeps/pthread/configure.in: Remove broken declaration in C + cleanup handling check. + +2003-11-30 Andreas Jaeger <aj@suse.de> + + * Makefile (CFLAGS-pt-initfini.s): Add $(fno_unit_at_a_time). + * sysdeps/unix/sysv/linux/x86_64/Makefile (CFLAGS-pt-initfini.s): + Likewise. + +2003-11-27 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/internaltypes.h (ATTR_FLAG_OLDATTR): Define. + * pthread_attr_destroy.c: Include shlib-compat.h. + (__pthread_attr_destroy): Return immediately if ATTR_FLAG_OLDATTR + is set in iattr->flags. + * pthread_attr_init.c (__pthread_attr_init_2_0): Set ATTR_FLAG_OLDATTR. + +2003-11-21 Jakub Jelinek <jakub@redhat.com> + + * Makefile (distribute): Add tst-cleanup4aux.c. + + * tst-cond12.c (prepare): Add prototype. Move after test-skeleton.c + include. + +2003-11-21 Ulrich Drepper <drepper@redhat.com> + + * tst-cond12.c (do_test): If USE_COND_SIGNAL is defined, use + pthread_cond_signal. + + * sysdeps/pthread/pthread_cond_wait.c (__pthread_cond_wait): Don't + store mutex address if the current value is ~0l. + * sysdeps/pthread/pthread_cond_timedwait.c + (__pthread_cond_timedwait): Likewise. + * sysdeps/pthread/pthread_cond_broadcast.c + (__pthread_cond_broadcast): Don't use requeue for pshared + condvars. + + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S + (__pthread_cond_wait): Don't store mutex address if the current + value is ~0l. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S + (__pthread_cond_timedwait): Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S + (__pthread_cond_broadcast): Don't use requeue for pshared + condvars. + + * pthread_cond_init.c (__pthread_cond_init): Initialize __mutex + element with ~0l for pshared condvars, with NULL otherwise. + + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S + (__pthread_cond_wait): Don't store mutex address if the current + value is ~0l. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S + (__pthread_cond_timedwait): Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S + (__pthread_cond_broadcast): Don't use requeue for pshared + condvars. + + * Makefile: Add rules to build and run tst-cond12 and tst-cond13. + * tst-cond12.c: New file. + * tst-cond13.c: New file. + +2003-11-17 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/configure.in: Make missing forced unwind support + fatal. + +2003-11-11 Ulrich Drepper <drepper@redhat.com> + + * pthreadP.h: Don't declare __pthread_unwind as weak inside libpthread. + +2003-11-06 Ulrich Drepper <drepper@redhat.com> + + * Makefile: Add magic to clean up correctly. + +2003-11-05 Jakub Jelinek <jakub@redhat.com> + + * unwind.c (FRAME_LEFT): Define. + (unwind_stop): Handle old style cleanups here. + (__pthread_unwind): Handle old style cleanups only if + !HAVE_FORCED_UNWIND. + * Makefile (tests): Add tst-cleanup4 and tst-cleanupx4. + (CFLAGS-tst-cleanupx4.c): Add -fexceptions. + ($(objpfx)tst-cleanup4): Depend on $(objpfx)tst-cleanup4aux.o. + ($(objpfx)tst-cleanupx4): Likewise. + * tst-cleanup4.c: New test. + * tst-cleanup4aux.c: New. + * tst-cleanupx4.c: New test. + +2003-11-04 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/bits/stdio-lock.h: Use lll_*lock instead of + lll_mutex_*lock macros to skip atomic operations on some archs. + +2003-11-03 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/tst-timer.c (main): Initialize + sigev2.sigev_value as well. + +2003-10-15 Roland McGrath <roland@redhat.com> + + * sysdeps/pthread/configure.in: Barf if visibility attribute support + is missing. + * sysdeps/pthread/configure: Regenerated. + +2003-10-09 Kaz Kojima <kkojima@rr.iij4u.or.jp> + + * sysdeps/unix/sysv/linux/sh/lowlevellock.h: Completely revamp the + locking macros. No distinction between normal and mutex locking + anymore. + * sysdeps/unix/sysv/linux/sh/lowlevellock.S: Rewrite mutex locking. + Merge bits from lowlevelmutex.S we still need. + * sysdeps/unix/sysv/linux/sh/libc-lowlevelmutex.S: Remove. + * sysdeps/unix/sysv/linux/sh/lowlevelmutex.S: Likewise. + * sysdeps/unix/sysv/linux/sh/not-cancel.h: New file. + * sysdeps/unix/sysv/linux/sh/pthread_barrier_wait.S: Adjust for + new mutex implementation. + * sysdeps/unix/sysv/linux/sh/pthread_cond_broadcast.S: Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_cond_signal.S: Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_cond_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_cond_wait.S: Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_rdlock.S: Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedrdlock.S: Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedwrlock.S: Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_unlock.S: Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_wrlock.S: Likewise. + * sysdeps/unix/sysv/linux/sh/sysdep-cancel.h (PSEUDO): Also defined + symbol for entry point to avoid cancellation. + +2003-10-07 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h: Backout 2003-10-02 + changes. + (SAVE_OLDTYPE_0): Fix a typo. + +2003-10-03 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/pthread_once.S (__pthread_once): + Check __sigsetjmp return value. Reported by Daniel Jacobowitz. + +2003-10-02 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h (DOCARGS_1): Use + correct offset. + +2003-10-02 Jakub Jelinek <jakub@redhat.com> + + * Makefile (tests): Add tst-cancel19. + * tst-cancel19.c: New test. + +2003-10-02 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h: Fix saving and + restoring of the old cancellation type. + +2003-09-30 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/pthread/malloc-machine.h: Remove misleading comment. + +2003-09-27 Wolfram Gloger <wg@malloc.de> + + * sysdeps/pthread/malloc-machine.h: New file + +2003-09-24 Roland McGrath <roland@redhat.com> + + * allocatestack.c (__make_stacks_executable): Don't ignore return + value from _dl_make_stack_executable. + +2003-09-24 Ulrich Drepper <drepper@redhat.com> + + * allocatestack.c (__make_stacks_executable): Also change + permission of the currently unused stacks. + + * allocatestack.c (change_stack_perm): Split out from + __make_stacks_executable. + (allocate_stack): If the required permission changed between the time + we started preparing the stack and queueing it, change the permission. + (__make_stacks_executable): Call change_stack_perm. + + * Makefile: Build tst-execstack-mod locally. + * tst-execstack-mod.c: New file. + +2003-09-23 Jakub Jelinek <jakub@redhat.com> + + * Makefile (tests): Only add tst-execstack if have-z-execstack is yes. + +2003-09-23 Roland McGrath <roland@redhat.com> + + * tst-execstack.c: New file. + * Makefile (tests): Add it. + ($(objpfx)tst-execstack, $(objpfx)tst-execstack.out): New targets. + (LDFLAGS-tst-execstack): New variable. + + * allocatestack.c (allocate_stack): Use GL(dl_stack_flags) to decide + whether to use PROT_EXEC for stack mmap. + (__make_stacks_executable): New function. + * pthreadP.h: Declare it. + * init.c (__pthread_initialize_minimal_internal): Set + GL(dl_make_stack_executable_hook) to that. + +2003-09-22 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h: Adjust for latest + recommendation from AMD re avoidance of lock prefix. + +2003-09-22 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/lowlevellock.c (__lll_timedlock_wait): Use + lll_futex_timed_wait instead of lll_futex_wait. + * sysdeps/unix/sysv/linux/s390/lowlevellock.c: Removed. + * sysdeps/unix/sysv/linux/s390/lowlevelmutex.c: Removed. + * sysdeps/unix/sysv/linux/s390/libc-lowlevellock.c: Removed. + * sysdeps/unix/sysv/linux/s390/libc-lowlevelmutex.c: Removed. + * sysdeps/unix/sysv/linux/s390/sem_trywait.c: Removed. + * sysdeps/unix/sysv/linux/s390/sem_wait.c: Removed. + * sysdeps/unix/sysv/linux/s390/sem_post.c: Removed. + * sysdeps/unix/sysv/linux/s390/sem_timedwait.c: Removed. + * sysdeps/unix/sysv/linux/s390/lowlevellock.h: Include atomic.h. + Completely revamp the locking macros. No distinction between + normal and mutex locking anymore. + * sysdeps/unix/sysv/linux/sparc/lowlevellock.h: Likewise. + * sysdeps/unix/sysv/linux/ia64/lowlevellock.h (__lll_lock_wait, + __lll_lock_timedwait): Fix prototypes. + * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h (__lll_lock_wait, + __lll_lock_timedwait): Likewise. + (lll_mutex_lock, lll_mutex_cond_lock): Use _val instead of _bool + macros, add __builtin_expect. + (lll_mutex_timedlock): Likewise. Fix return value. + * sysdeps/unix/sysv/linux/i386/i486/libc-lowlevelmutex.S: Removed. + * sysdeps/unix/sysv/linux/i386/i586/libc-lowlevelmutex.S: Removed. + * sysdeps/unix/sysv/linux/i386/i586/lowlevelmutex.S: Removed. + * sysdeps/unix/sysv/linux/i386/i686/libc-lowlevelmutex.S: Removed. + * sysdeps/unix/sysv/linux/i386/i686/lowlevelmutex.S: Removed. + * sysdeps/unix/sysv/linux/x86_64/libc-lowlevelmutex.S: Removed. + * sysdeps/unix/sysv/linux/lowlevelmutex.c: Removed. + * sysdeps/unix/sysv/linux/libc-lowlevelmutex.c: Removed. + +2003-09-22 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S + (__lll_mutex_lock_wait): Minor optimization to avoid one atomic + operation if possible. + + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h: Don't play tricks + like jumping over the lock prefix. + +2003-09-21 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/lowlevellock.h: Completely revamp the + locking macros. No distinction between normal and mutex locking + anymore. + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h: Likewise. + * sysdeps/unix/sysv/linux/ia64/lowlevellock.h: Likewise. + * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S: Rewrite mutex + locking. Merge bits from lowlevelmutex.S we still need. + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.S: Likewise. + * sysdeps/unix/sysv/linux/lowlevellock.c: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/lowlevelmutex.S: Removed. + * sysdeps/unix/sysv/linux/x86_64/lowlevelmutex.S: Removed. + * Makefile (routines): Remove libc-lowlevelmutex. + (libpthread-rountines): Remove lowlevelmutex. + * sysdeps/unix/sysv/linux/i386/i486/pthread_barrier_wait.S: Adjust + for new mutex implementation. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_rdlock.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedrdlock.S: + Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedwrlock.S: + Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_unlock.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_wrlock.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_barrier_wait.S: Likewise + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_rdlock.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedrdlock.S: + Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedwrlock.S: + Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_unlock.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_wrlock.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_signal.S: Likewise. + Don't use requeue. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_signal.S: Likewise. + * sysdeps/pthread/pthread_cond_signal.c: Don't use requeue. + +2003-09-20 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/lowlevellock.h: Don't match memory + in parameters of asm with output parameters. + + * pthread_mutex_unlock.c (__pthread_mutex_unlock_usercnt): Change + type of DECR parameter to int. + * pthreadP.h: Adjust prototype of __pthread_mutex_unlock_usercnt. + +2003-09-18 Jakub Jelinek <jakub@redhat.com> + + * tst-attr3.c (tf, do_test): Print stack start/end/size and + guardsize for each thread. + +2003-09-17 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/pthread/pthread.h (pthread_getattr_np): Clarify usage. + * sysdeps/unix/sysv/linux/pthread_attr_setaffinity.c + (pthread_attr_setaffinity_np): Handle cpuset == NULL. + + * sysdeps/unix/sysv/linux/pthread_attr_getaffinity.c + (pthread_attr_getaffinity_np): Don't segfault if iattr->cpuset is + NULL. + * pthread_getattr_np.c: Set cpuset using pthread_getaffinity_np. + * pthreadP.h (pthread_getaffinity_np): Add hidden_proto. + * sysdeps/unix/sysv/linux/pthread_getaffinity.c + (pthread_getaffinity_np): Add hidden_def. + + * Makefile (tests): Add tst-attr3. + * tst-attr3.c: New test. + + * sysdeps/i386/Makefile (CFLAGS-tst-align.c): Remove. + +2003-09-15 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/i386/Makefile (CFLAGS-pthread_create.c, + CFLAGS-tst-align.c): Add -mpreferred-stack-boundary=4. + +2003-09-17 Jakub Jelinek <jakub@redhat.com> + + * Makefile (CFLAGS-tst-align.c): Add $(stack-align-test-flags). + * tst-align.c: Include tst-stack-align.h. + (tf, do_test): Use TEST_STACK_ALIGN macro. + +2003-09-17 Ulrich Drepper <drepper@redhat.com> + + * pthread_attr_init.c (__pthread_attr_init_2_0): Remove unused + variable. + +2003-09-16 Ulrich Drepper <drepper@redhat.com> + + * pthread_getattr_np.c (pthread_getattr_np): Correctly fill in the + stack-related values for the initial thread. + +2003-09-15 Jakub Jelinek <jakub@redhat.com> + + * Makefile (CFLAGS-pthread_once.c): Add $(uses-callbacks). + +2003-09-11 Ulrich Drepper <drepper@redhat.com> + + * pthread_mutex_lock.c: Minor code rearrangements. + +2003-09-05 Roland McGrath <roland@redhat.com> + + * pthread_create.c (__pthread_pthread_sizeof_descr): Removed. + Instead, include ../nptl_db/db_info.c to do its magic. + * pthread_key_create.c (__pthread_pthread_keys_max): Removed. + (__pthread_pthread_key_2ndlevel_size): Likewise. + * sysdeps/alpha/tls.h (DB_THREAD_SELF): New macro. + * sysdeps/i386/tls.h (DB_THREAD_SELF): New macro. + * sysdeps/ia64/tls.h (DB_THREAD_SELF): New macro. + * sysdeps/powerpc/tls.h (DB_THREAD_SELF): New macro. + * sysdeps/s390/tls.h (DB_THREAD_SELF): New macro. + * sysdeps/sh/tls.h (DB_THREAD_SELF): New macro. + * sysdeps/sparc/tls.h (DB_THREAD_SELF): New macro. + * sysdeps/x86_64/tls.h (DB_THREAD_SELF): New macro. + * sysdeps/alpha/td_ta_map_lwp2thr.c: File removed. + * sysdeps/generic/td_ta_map_lwp2thr.c: File removed. + * sysdeps/i386/td_ta_map_lwp2thr.c: File removed. + * sysdeps/ia64/td_ta_map_lwp2thr.c: File removed. + * sysdeps/powerpc/td_ta_map_lwp2thr.c: File removed. + * sysdeps/s390/td_ta_map_lwp2thr.c: File removed. + * sysdeps/sh/td_ta_map_lwp2thr.c: File removed. + * sysdeps/sparc/td_ta_map_lwp2thr.c: File removed. + * sysdeps/x86_64/td_ta_map_lwp2thr.c: File removed. + +2003-09-08 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: Change type + of pthread_t to be compatible with LT. + * sysdeps/unix/sysv/linux/sparc/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h: Likewise. + +2003-09-04 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/not-cancel.h (fcntl_not_cancel): Define. + +2003-09-04 Jakub Jelinek <jakub@redhat.com> + + * unwind-forcedunwind.c: Move to... + * sysdeps/pthread/unwind-forcedunwind.c: ...here. + (pthread_cancel_init): Use ARCH_CANCEL_INIT if defined. + * sysdeps/pthread/jmpbuf-unwind.h: New file. + * sysdeps/unix/sysv/linux/ia64/unwind-forcedunwind.c: New file. + * sysdeps/unix/sysv/linux/ia64/jmpbuf-unwind.h: New file. + * unwind.c: Include jmpbuf-unwind.h. + (unwind_stop): Use _JMPBUF_CFA_UNWINDS macro. + +2003-09-02 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/ia64/bits/local_lim.h: New file. + * sysdeps/unix/sysv/linux/ia64/Versions (libpthread): Export + pthread_attr_setstack and pthread_attr_setstacksize @@GLIBC_2.3.3. + * sysdeps/unix/sysv/linux/alpha/bits/local_lim.h: New file. + * sysdeps/unix/sysv/linux/alpha/Versions: New file. + * sysdeps/unix/sysv/linux/sparc/bits/local_lim.h: New file. + * sysdeps/unix/sysv/linux/sparc/Versions: New file. + * pthread_attr_setstack.c (__old_pthread_attr_setstack): New function. + (pthread_attr_setstack): If PTHREAD_STACK_MIN != 16384, export + as @@GLIBC_2.3.2 and also export compatibility @GLIBC_2.2. + * pthread_attr_setstacksize.c (__old_pthread_attr_setstacksize): New + function. + (pthread_attr_setstacksize): If PTHREAD_STACK_MIN != 16384, export + as @@GLIBC_2.3.2 and also export compatibility @GLIBC_2.1. + * Makefile (tests): Add tst-stack2. + * tst-stack2.c: New test. + * tst-stack1.c: Include limits.h and sys/param.h. + (do_test): Set size to MAX (4 * getpagesize (), PTHREAD_STACK_MIN). + + * pthread_condattr_setpshared.c: Include errno.h. + (pthread_condattr_setpshared): Return EINVAL if pshared + is neither PTHREAD_PROCESS_PRIVATE nor PTHREAD_PROCESS_SHARED. + + * sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h (PSEUDO): Also + defined symbol for entry point to avoid cancellation. + * sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h (PSEUDO): + Likewise. + * sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h (PSEUDO): + Likewise. + * sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h (PSEUDO): + Likewise. + * sysdeps/unix/sysv/linux/sparc/sparc32/sysdep-cancel.h (PSEUDO): + Likewise. + * sysdeps/unix/sysv/linux/sparc/sparc64/sysdep-cancel.h (PSEUDO): + Likewise. + * sysdeps/unix/sysv/linux/i386/not-cancel.h (__open_nocancel, + __close_nocancel, __read_nocancel, __write_nocancel, + __waitpid_nocancel): Add attribute_hidden. If not in libc.so, + libpthread.so or librt.so, define to corresponding function + without _nocancel suffix. + * sysdeps/unix/sysv/linux/s390/not-cancel.h: New file. + * sysdeps/unix/sysv/linux/powerpc/not-cancel.h: New file. + * sysdeps/unix/sysv/linux/sparc/not-cancel.h: New file. + + * sysdeps/unix/sysv/linux/x86_64/not-cancel.h: Fix a typo. + +2003-09-02 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/not-cancel.h: New file. + * sysdeps/unix/sysv/linux/x86_64/not-cancel.h: New file. + + * sysdeps/unix/sysv/linux/i386/lowlevellock.h: Make sure the code + in subsections has a symbol associated with it. + + * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h (PSEUDO): Also + defined symbol for entry point to avoid cancellation. + * sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h (PSEUDO): Likewise. + +2003-09-01 Jakub Jelinek <jakub@redhat.com> + + * Makefile (tests): Add tst-tls5. + (module-names): Add tst-tls5mod{,a,b,c,d,e,f}. + ($(objpfx)tst-tls5mod{,a,b,c,d,e,f}.so-no-z-defs): Set to yes. + ($(objpfx)tst-tls5): New. + ($(objpfx)tst-tls6.out): Likewise. + (tests): Depend on $(objpfx)tst-tls6.out. + * tst-tls3.c: Include stdint.h and pthreaddef.h. + (do_test): Check pthread_self () return value alignment. + * tst-tls3mod.c: Include stdint.h and pthreaddef.h. + (tf): Check pthread_self () return value alignment. + * tst-tls5.c: New test. + * tst-tls5.h: New. + * tst-tls5mod.c: New. + * tst-tls5moda.c: New. + * tst-tls5modb.c: New. + * tst-tls5modc.c: New. + * tst-tls5modd.c: New. + * tst-tls5mode.c: New. + * tst-tls5modf.c: New. + * tst-tls6.sh: New test. + + * sysdeps/pthread/pthread-functions.h (struct pthread_functions): Add + ptr___pthread_cond_timedwait and ptr___pthread_cond_timedwait_2_0. + * init.c (pthread_functions): Initialize them. + * forward.c (pthread_cond_timedwait@GLIBC_2.0, + pthread_cond_timedwait@@GLIBC_2.3.2): New forwards. + * Versions (libc): Export pthread_cond_timedwait@GLIBC_2.0, + pthread_cond_timedwait@@GLIBC_2.3.2. + +2003-09-01 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/alpha/timer_create.c: New file. + * sysdeps/unix/sysv/linux/alpha/timer_delete.c: New file. + * sysdeps/unix/sysv/linux/alpha/timer_getoverr.c: New file. + * sysdeps/unix/sysv/linux/alpha/timer_gettime.c: New file. + * sysdeps/unix/sysv/linux/alpha/timer_settime.c: New file. + * sysdeps/unix/sysv/linux/alpha/Versions: New file. + + * sysdeps/unix/sysv/linux/alpha/aio_cancel.c: New file. + + * sysdeps/unix/sysv/linux/ia64/bits/posix_opt.h: Define + _POSIX_THREAD_PRIORITY_SCHEDULING. + * sysdeps/unix/sysv/linux/x86_64/bits/posix_opt.h: Likewise. + +2003-08-31 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/bits/stdio-lock.h (_IO_acquire_lock): Avoid + nested function, use static inline function from libio.h. + Code by Richard Henderson. + + * sysdeps/pthread/bits/libc-lock.h: Mark pthread_setcancelstate as + weak. + +2003-08-30 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/sparc/sparc64/Versions: New file. + * sysdeps/unix/sysv/linux/sparc/sparc64/timer_create.c: New file. + * sysdeps/unix/sysv/linux/sparc/sparc64/timer_delete.c: New file. + * sysdeps/unix/sysv/linux/sparc/sparc64/timer_getoverr.c: New file. + * sysdeps/unix/sysv/linux/sparc/sparc64/timer_gettime.c: New file. + * sysdeps/unix/sysv/linux/sparc/sparc64/timer_settime.c: New file. + * sysdeps/unix/sysv/linux/sparc/sparc64/sysdep-cancel.h: New file. + * sysdeps/unix/sysv/linux/sparc/sparc32/sysdep-cancel.h: New file. + * sysdeps/unix/sysv/linux/sparc/bits/pthreadtypes.h: New file. + * sysdeps/unix/sysv/linux/sparc/bits/semaphore.h: New file. + * sysdeps/unix/sysv/linux/sparc/lowlevellock.h: New file. + * sysdeps/unix/sysv/linux/sparc/pthread_once.c: New file. + * sysdeps/unix/sysv/linux/sparc/pt-vfork.S: New file. + * sysdeps/unix/sysv/linux/sparc/fork.c: New file. + * sysdeps/unix/sysv/linux/sparc/aio_cancel.c: New file. + * sysdeps/sparc/sparc32/sparcv9/pthread_spin_lock.c: New file. + * sysdeps/sparc/sparc32/sparcv9/pthread_spin_trylock.c: New file. + * sysdeps/sparc/sparc32/sparcv9/pthread_spin_unlock.c: New file. + * sysdeps/sparc/sparc32/pthread_spin_lock.c: New file. + * sysdeps/sparc/sparc32/pthread_spin_trylock.c: New file. + * sysdeps/sparc/sparc32/pthreaddef.h: New file. + * sysdeps/sparc/sparc64/pthread_spin_lock.c: New file. + * sysdeps/sparc/sparc64/pthread_spin_trylock.c: New file. + * sysdeps/sparc/sparc64/pthread_spin_unlock.c: New file. + * sysdeps/sparc/sparc64/pthreaddef.h: New file. + * sysdeps/sparc/tls.h: New file. + * sysdeps/sparc/tcb-offsets.sym: New file. + * sysdeps/sparc/Makefile: New file. + * sysdeps/sparc/td_ta_map_lwp2thr.c: New file. + * init.c [__sparc__] (__NR_set_tid_address): Define. + +2003-08-29 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/pthread/bits/stdio-lock.h (_IO_acquire_lock, + _IO_release_lock): Define. + +2003-08-29 Jakub Jelinek <jakuB@redhat.com> + + * tst-cancel4.c (tf_sigwait, tf_sigwaitinfo, tf_sigtimedwait): Add + sigemptyset before sigaddset. Reported by jreiser@BitWagon.com. + +2003-08-27 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/pthread.h (pthread_exit): Remove __THROW. + (__pthread_cleanup_class): Add missing return types of member + functions. + +2003-08-26 Steven Munroe <sjmunroe@us.ibm.com> + + * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h + (lll_mutex_unlock_force): Add memory barrier between store and futex + syscall. + +2003-08-25 Ulrich Drepper <drepper@redhat.com> + + * tst-cancel4.c (do_test): Also unlink tempfname and remove + tempmsg in first loop. + +2003-08-18 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/bits/posix_opt.h: Define + _POSIX_THREAD_PRIORITY_SCHEDULING. + * sysdeps/unix/sysv/linux/i386/bits/posix_opt.h: Likewise. + +2003-08-07 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/pthread/bits/libc-lock.h [_LIBC && SHARED] + (__rtld_lock_default_lock_recursive, + __rtld_lock_default_unlock_recursive): Define. + [_LIBC && SHARED] (__rtld_lock_lock_recursive, + __rtld_lock_unlock_recursive): Define using + GL(_dl_rtld_*lock_recursive). + * init.c (__pthread_initialize_minimal_internal): Initialize + _dl_rtld_lock_recursive and _dl_rtld_unlock_recursive. + Lock GL(_dl_load_lock) the same number of times as + GL(_dl_load_lock) using non-mt implementation was nested. + + * pthreadP.h (__pthread_cleanup_upto): Add hidden_proto. + * pt-longjmp.c (__pthread_cleanup_upto): Add hidden_def. + +2003-08-06 Jakub Jelinek <jakub@redhat.com> + + * tst-cancel17.c (do_test): Make len2 maximum of page size and + PIPE_BUF. + +2003-08-07 Jakub Jelinek <jakub@redhat.com> + + * pthread_create.c (__pthread_create_2_0): Clear new_attr.cpuset. + +2003-08-03 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/pthread/createthread.c (do_clone): Move error handling + to first syscall error check. Move syscall error check for tkill + into __ASSUME_CLONE_STOPPED #ifdef. + +2003-08-02 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/createthread.c (do_clone): If __ASSUME_CLONE_STOPPED + is not defined, do explicit synchronization. + (create_thread): Do not lock pd->lock here. If __ASSUME_CLONE_STOPPED + is not defined also unlock pd->lock for non-debugging case in case + it is necessary. + * pthread_create.c (start_thread): Always get and release pd->lock + if __ASSUME_CLONE_STOPPED is not defined. + (start_thread_debug): Removed. Adjust users. + * allocatestack.c (allocate_stack): Always initialize lock if + __ASSUME_CLONE_STOPPED is not defined. + * Makefile (tests): Add tst-sched1. + * tst-sched1.c: New file. + + * sysdeps/pthread/createthread.c (do_clone): Only use + sched_setschduler and pass correct parameters. + +2003-07-31 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/pthread/pthread.h (pthread_attr_setstackaddr, + pthread_attr_setstacksize): Change PTHREAD_STACK_SIZE to + PTHREAD_STACK_MIN in comments. + +2003-07-31 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/pthread/pthread_cond_timedwait.c (__pthread_cond_timedwait): + Shut up warnings if INTERNAL_SYSCALL_ERROR_P does not use its first + argument. + * sysdeps/unix/sysv/linux/timer_create.c (timer_create): Likewise. + * pthread_condattr_setclock.c (pthread_condattr_setclock): Likewise. + * sysdeps/unix/sysv/linux/s390/jmp-unwind.c: Include pthreaddef.h. + (__pthread_cleanup_upto): Fix prototype. + (_longjmp_unwind): Adjust caller. + * sysdeps/unix/sysv/linux/s390/lowlevellock.h (__lll_mutex_timedlock): + Change second argument to const struct pointer. + * tst-sem8.c (main): Remove unused s2 and s3 variables. + * tst-sem9.c (main): Likewise. + * unwind.c: Include string.h for strlen prototype. + +2003-07-31 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S + (__pthread_cond_timedwait): Don't use cmov unless HAVE_CMOV is defined. + * sysdeps/unix/sysv/linux/i386/i686/pthread_cond_timedwait.S: + Define HAVE_CMOV. + Patch by Nicholas Miell <nmiell@attbi.com>. + +2003-07-30 Jakub Jelinek <jakub@redhat.com> + + * init.c (__pthread_initialize_minimal_internal): Initialize + GL(dl_init_static_tls). + * pthreadP.h (__pthread_init_static_tls): New prototype. + * allocatestack.c (init_one_static_tls, __pthread_init_static_tls): + New functions. + * Makefile (tests): Add tst-tls4. + (modules-names): Add tst-tls4moda and tst-tls4modb. + ($(objpfx)tst-tls4): Link against libdl and libpthread. + ($(objpfx)tst-tls4.out): Depend on tst-tls4moda.so and + tst-tls4modb.so. + * tst-tls4.c: New file. + * tst-tls4moda.c: New file. + * tst-tls4modb.c: New file. + +2003-06-19 Daniel Jacobowitz <drow@mvista.com> + + * sysdeps/pthread/timer_create.c (timer_create): Call timer_delref + before __timer_dealloc. + * sysdeps/pthread/timer_routines.c (__timer_thread_find_matching): + Don't call list_unlink. + +2003-07-29 Roland McGrath <roland@redhat.com> + + * Makefile [$(build-shared) = yes] (tests): Depend on $(test-modules). + +2003-07-25 Jakub Jelinek <jakub@redhat.com> + + * tst-cancel17.c (do_test): Check if aio_cancel failed. + Don't reuse struct aiocb A if it failed. + Write fpathconf (fds[1], _PC_PIPE_BUF) + 2 bytes using aio_write, + not just one byte, as that does not block. + +2003-07-22 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/pthread/unwind-resume.c: New file. + * sysdeps/pthread/Makefile (routines, shared-only-routines): Add + unwind-resume in csu subdir. + (CFLAGS-unwind-resume.c, CFLAGS-rt-unwind-resume.c): Compile with + exceptions. + (librt-sysdep_routines, librt-shared-only-routines): Add + rt-unwind-resume. + * sysdeps/pthread/rt-unwind-resume.c: New file. + * unwind-forcedunwind.c: New file. + * Makefile (libpthread-routines): Add unwind-forcedunwind. + (libpthread-shared-only-routines): Likewise. + (CFLAGS-unwind-forcedunwind.c): Compile with exceptions. + * pthreadP.h (pthread_cancel_init): New prototype. + * pthread_cancel.c (pthread_cancel): Call pthread_cancel_init. + + * sysdeps/pthread/createthread.c (do_thread, create_thread): Make + attr argument const struct pthread_attr *. + + * res.c (__res_state): Return __resp. + * descr.h: Include resolv.h. + (struct pthread): Add res field. + * pthread_create.c: Include resolv.h. + (start_thread): Initialize __resp. + * Makefile (tests): Add tst-_res1. + (module-names): Add tst-_res1mod1, tst-_res1mod2. + ($(objpfx)tst-_res1mod2.so): Depend on $(objpfx)tst-_res1mod1.so. + ($(objpfx)tst-_res1): Depend on $(objpfx)tst-_res1mod2.so and + libpthread. + * tst-_res1.c: New file. + * tst-_res1mod1.c: New file. + * tst-_res1mod2.c: New file. + +2003-07-21 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/createthread.c: Don't define CLONE_STOPPED. + + * Makefile: Define various *-no-z-defs variables for test DSOs + which has undefined symbols. + +2003-07-21 Steven Munroe <sjmunroe@us.ibm.com> + + * sysdeps/unix/sysv/linux/powerpc/pthread_once.c (__pthread_once): + Retry if the stwcx fails to store once_control. + +2003-07-20 Ulrich Drepper <drepper@redhat.com> + + * Makefile (libpthread-routines): Add pthread_attr_getaffinity and + pthread_attr_setaffinity. + * Versions [libpthread] (GLIBC_2.3.3): Likewise. + * sysdeps/unix/sysv/linux/pthread_attr_getaffinity.c: New file. + * sysdeps/unix/sysv/linux/pthread_attr_setaffinity.c: New file. + * pthread_attr_destroy.c: Free cpuset element if allocated. + * pthread_create.c: Pass iattr as additional parameter to + create_thread. + * sysdeps/pthread/createthread.c: If attribute is provided and + a new thread is created with affinity set or scheduling parameters, + start thread with CLONE_STOPPED. + * sysdeps/pthread/pthread.h: Declare pthread_attr_getaffinity and + pthread_attr_setaffinity. + * sysdeps/unix/sysv/linux/internaltypes.h (struct pthread_attr): Add + cpuset element. + +2003-07-15 Ulrich Drepper <drepper@redhat.com> + + * tst-tcancel-wrappers.sh: lseek and llseek are not cancelation points. + +2003-07-14 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/configure.in: Require CFI directives also for + ppc and s390. + +2003-07-15 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h (PSEUDO): + Add cfi directives. + +2003-07-12 Kaz Kojima <kkojima@rr.iij4u.or.jp> + + * sysdeps/sh/tcb-offsets.sym: Add RESULT, TID, CANCELHANDLING and + CLEANUP_JMP_BUF. + * sysdeps/unix/sysv/linux/sh/pthread_cond_wait.S: Use more + registers as variables. Call __pthread_mutex_unlock_usercnt. + * sysdeps/unix/sysv/linux/sh/pthread_cond_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_rdlock.S: Store TID + not self pointer in __writer. Compare with TID to determine + deadlocks. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_wrlock.S: Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedrdlock.S: + Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedwrlock.S: + Likewise. + * sysdeps/unix/sysv/linux/sh/sem_wait.S: Add cancellation support. + * sysdeps/unix/sysv/linux/sh/sem_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/sh/sysdep-cancel.h: Define all the nice + macros also when compiling librt. + +2003-07-11 Jakub Jelinek <jakub@redhat.com> + + * Makefile (CFLAGS-pthread_once.c): Add -fexceptions + -fasynchronous-unwind-tables. + * sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h + (PSEUDO): Add cfi directives. + * sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h (PSEUDO): + Likewise. + * sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h (PSEUDO): + Likewise. + +2003-07-08 Jakub Jelinek <jakub@redhat.com> + + * pthreadP.h (__pthread_unwind_next, __pthread_register_cancel, + __pthread_unregister_cancel): Add prototypes and hidden_proto. + * unwind.c (__pthread_unwind_next): Add hidden_def. + * cleanup.c (__pthread_register_cancel, __pthread_unregister_cancel): + Likewise. + * sysdeps/unix/sysv/linux/i386/i486/sem_wait.S (__new_sem_wait): + Use HIDDEN_JUMPTARGET to jump to __pthread_unwind. + * sysdeps/unix/sysv/linux/i386/i486/sem_timedwait.S (sem_timedwait): + Likewise. + * sysdeps/unix/sysv/linux/x86_64/sem_wait.S (sem_wait): Likewise. + * sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S (sem_timedwait): + Likewise. + * sysdeps/unix/sysv/linux/i386/pthread_once.S (__pthread_once): Use + HIDDEN_JUMPTARGET to call __pthread_register_cancel, + __pthread_unregister_cancel and __pthread_unwind_next. + +2003-07-04 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/ia64/sysdep-cancel.h (PSEUDO): Use + different symbol for the cancellation syscall wrapper and + non-cancellation syscall wrapper. + (PSEUDO_END): Define. + +2003-07-05 Richard Henderson <rth@redhat.com> + + * sysdeps/alpha/elf/pt-initfini.c: Avoid .ent/.end. + * sysdeps/unix/sysv/linux/alpha/lowlevellock.h (lll_futex_wait, + lll_futex_timed_wait, lll_futex_wake, lll_futex_requeue): On success + return actual return value from the syscall, not 0. + +2003-07-07 Ulrich Drepper <drepper@redhat.com> + + * descr.h (struct pthread): Add pid field. + * allocatestack.c (allocate_stack): Initialize pid field in descriptor. + (__reclaim_stacks): Likewise. + * init.c (sigcancel_handler): If __ASSUME_CORRECT_SI_PID is defined + also check for PID of the signal source. + (__pthread_initialize_minimal_internal): Also initialize pid field + of initial thread's descriptor. + * pthread_cancel.c: Use tgkill instead of tkill if possible. + * sysdeps/unix/sysv/linux/fork.c: Likewise. + * sysdeps/unix/sysv/linux/pt-raise.c: Likewise. + * sysdeps/unix/sysv/linux/pthread_kill.c: Likewise. + * sysdeps/unix/sysv/linux/raise.c: Likewise. + +2003-07-05 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/bits/libc-lock.h (__libc_cleanup_push): Renamed. + Fix use of parameter. + (__libc_cleanup_pop): Likewise. + +2003-07-04 Ulrich Drepper <drepper@redhat.com> + + * init.c (sigcancel_handler): Change parameters to match handler + for SA_SIGACTION. Check signal number and code to recognize + invalid invocations. + +2003-07-03 Roland McGrath <roland@redhat.com> + + * sysdeps/ia64/td_ta_map_lwp2thr.c (td_ta_map_lwp2thr): + Apply sizeof (struct pthread) bias to r13 value. + +2003-07-03 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/configure.in: Require CFI directives. + + * sysdeps/pthread/librt-cancellation.c (__pthread_unwind): Remove + definition. + * pthreadP.h (__pthread_unwind): Add hidden_proto if used in + libpthread compilation. + * unwind.c (__pthread_unwind): Add hidden_def. + * Versions (libpthread) [GLIBC_PRIVATE]: Add __pthread_unwind. + +2003-07-01 Ulrich Drepper <drepper@redhat.com> + + * libc-cancellation.c (__libc_cleanup_routine): Define. + * sysdeps/pthread/bits/libc-lock.h (__pthread_cleanup_push): Define. + (__pthread_cleanup_pop): Define. + +2003-07-01 Richard Henderson <rth@redhat.com> + + * sysdeps/alpha/elf/pt-initfini.c: New file. + * sysdeps/alpha/pthread_spin_lock.S: New file. + * sysdeps/alpha/pthread_spin_trylock.S: New file. + * sysdeps/alpha/pthreaddef.h: New file. + * sysdeps/alpha/td_ta_map_lwp2thr.c: New file. + * sysdeps/alpha/tls.h: New file. + * sysdeps/unix/sysv/linux/alpha/Makefile: New file. + * sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h: New file. + * sysdeps/unix/sysv/linux/alpha/bits/semaphore.h: New file. + * sysdeps/unix/sysv/linux/alpha/createthread.c: New file. + * sysdeps/unix/sysv/linux/alpha/fork.c: New file. + * sysdeps/unix/sysv/linux/alpha/lowlevellock.h: New file. + * sysdeps/unix/sysv/linux/alpha/pt-vfork.S: New file. + * sysdeps/unix/sysv/linux/alpha/pthread_once.c: New file. + * sysdeps/unix/sysv/linux/alpha/sem_post.c: New file. + * sysdeps/unix/sysv/linux/alpha/sysdep-cancel.h: New file. + +2003-07-01 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/x86_64/pthread_once.S: Add correct + cleanup support and unwind info. + +2003-06-30 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/pthread_once.S (__pthread_once): + Use correct cleanup handler registration. Add unwind info. + * sysdeps/unix/sysv/linux/unwindbuf.sym: New file. + * sysdeps/unix/sysv/linux/Makefile: Add rule to build unwindbuf.h. + * tst-once3.c: Add cleanup handler and check it is called. + * tst-once4.c: Likewise. + * tst-oncex3.c: New file. + * tst-oncex4.c: New file. + * Makefile: Add rules to build and run tst-oncex3 and tst-oncex4. + +2003-06-29 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/configure.in: Check for C cleanup handling in gcc. + +2003-06-27 Ulrich Drepper <drepper@redhat.com> + + * tst-cancel4.c (tf_msgrcv): Use IPC_PRIVATE in msgget call. + (tf_msgsnd): Likewise. + + * tst-cancel4.c (tf_msgrcv): Strengthen test against valid + premature returns a bit more. + +2003-06-26 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/librt-cancellation.c: Move __pthread_unwind + definition to the front. + + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Rename + the cleanup functions to make the names unique. Fix dwarf opcode + un unwind table. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Rename cleanup + functions to make the names unique. Fix CFA offset for two blocks. + +2003-06-25 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/pthread.h (class __pthread_cleanup_class): Add + missing closing braces. + Patch by Christophe Saout <christophe@saout.de>. + +2003-06-24 Roland McGrath <roland@redhat.com> + + * pthread_mutex_trylock.c (__pthread_mutex_trylock): Typo fix. + +2003-06-24 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/ia64/bits/posix_opt.h: New file. + * sysdeps/unix/sysv/linux/x86_64/bits/posix_opt.h: New file. + + * pthreadP.h: Declare __find_thread_by_id. + * allocatestack.c [HP_TIMING_AVAIL]: Define __find_thread_by_id. + * pthread_clock_gettime.c: Allow using other thread's clock. + * pthread_clock_settime.c: Likewise. + * sysdeps/pthread/pthread_getcpuclockid.c: Likewise. + * Makefile: Add rules to build and run tst-clock2. + * tst-clock2.c: New file. + +2003-06-23 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Rewrite + to use exception-based cleanup handler. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Likewise. + + * tst-cond8.c (ch): Announce that we are done. + + * pthreadP.h (__pthread_mutex_cond_lock): Mark with internal_function. + + * tst-cancel17.c (tf): Retry aio_suspend in case of EINTR. + Also test aio_suspend with timeout value. + +2003-06-22 Ulrich Drepper <drepper@redhat.com> + + * pthreadP.h: Mark __pthread_mutex_unlock_usercnt also hidden. + * pthread_mutex_unlock.c (__pthread_mutex_unlock_usercnt): Add + attribute_hidden. + + * pthreadP.h (__pthread_mutex_init_internal): Mark hidden. + (__pthread_mutex_lock_internal): Likewise. + (__pthread_mutex_unlock_internal): Likewise. + (__pthread_mutex_unlock_usercnt): Declare. + * pthread_mutex_destroy.c: Always fail if used in any way. + * pthread_mutex_init.c: Update comment. + * pthread_mutex_lock.c: If NO_INCR is not defined adjust __nusers. + * pthread_mutex_timedlock.c: Adjust __nusers. + * pthread_mutex_trylock.c: Adjust __nusers. + * pthread_mutex_unlock.c: Old code is in __pthread_mutex_unlock_usercnt + and public interfaces are wrapper with pass additional parameter. + __pthread_mutex_unlock_usercnt does not adjust __nusers if second + parameter zero. + * tst-mutex8.c: New file. + * Makefile (tests): Add tst-mutex8. + * sysdeps/pthread/pthread_cond_timedwait.c: Call + __pthread_mutex_unlock_usercnt. + * sysdeps/pthread/pthread_cond_wait.c: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S: Likewise. + * sysdeps/unix/sysv/linux/pthread_mutex_cond_lock.c: Define NO_INCR. + * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h (pthread_mutex_t): + Add __nusers. + * sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: Likewise. + + * pthread_mutex_lock.c: Don't store THREAD_ID in __owner, use TID. + * pthread_mutex_timedlock.c: Likewise. + * pthread_mutex_trylock.c: Adjust __nusers. + * pthread_mutex_unlock.c: Compare with TID not THREAD_ID. + * tst-mutex9.c: New file. + * Makefile (tests): Add tst-mutex9. + * sysdeps/i386/tls.h: Remove THREAD_ID definition. + * sysdeps/ia64/tls.h: Likewise. + * sysdeps/powerpc/tls.h: Likewise. + * sysdeps/s390/tls.h: Likewise. + * sysdeps/sh/tls.h: Likewise. + * sysdeps/x86_64/tls.h: Likewise. + * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h (pthread_mutex_t): + Change type of __owner. + * sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: Likewise. + +2003-06-19 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/ia64/sem_post.c: Move to... + * sysdeps/unix/sysv/linux/sem_post.c: ...here. + + * sysdeps/unix/sysv/linux/sem_post.c: Move to... + * sysdeps/unix/sysv/linux/powerpc/sem_post.c: ... here. Pass nr + 1 + instead of nr to lll_futex_wake. Only set errno and return -1 + if err < 0. + + * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h (lll_futex_wait, + lll_futex_timed_wait, lll_futex_wake, lll_futex_requeue): On success + return actual return value from the syscall, not 0. + +2003-06-18 Ulrich Drepper <drepper@redhat.com> + + * tst-cancel4.c (tf_msgsnd): Don't always use 100 as the type, + find a random value. + (tf_msgrcv): Likewise. Also don't report msgrcv returns if + errno==EIDRM. + + * sysdeps/unix/sysv/linux/timer_settime.c: Add prototype for + compat_timer_settime. + * sysdeps/unix/sysv/linux/timer_gettime.c: Add prototype for + compat_timer_gettime. + * sysdeps/unix/sysv/linux/timer_getoverr.c: Add prototype for + compat_timer_getoverrun. + * sysdeps/unix/sysv/linux/timer_delete.c: Add prototype for + compat_timer_delete. + + * pthread_mutex_destroy.c (__pthread_mutex_destroy): For + error-checking mutex detect busy mutexes. + +2003-06-17 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h (lll_mutex_lock): + Add ax to clobber list. + (lll_mutex_cond_lock): Likewise. + (lll_mutex_unlock): Likewise. + (lll_lock): Likewise. + (lll_unlock): Likewise. + + * Makefile: Add rules to build and run tst-cancel18 and tst-cancelx18. + * tst-cancel18.c: New file. + * tst-cancelx18.c: New file. + + * tst-cancel4.c: Test connect, creat, msgrcv, msgsnd, sendmsg, sendto, + and tcdrain. + + * Makefile: Add rules to build and run tst-cancel17 and tst-cancel17x. + * tst-cancel17.c: New file. + * tst-cancelx17.c: New file. + + * sysdeps/unix/sysv/linux/sigtimedwait.c: New file. + * sysdeps/unix/sysv/linux/sigwait.c: New file. + * sysdeps/unix/sysv/linux/sigwaitinfo.c: New file. + + * tst-cancel4.c: Test open, close, pread, pwrite, fsync, and msync. + +2003-06-16 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/pthread/createthread.c (create_thread): Set + header.multiple_threads unconditionally. + * allocatestack.c (allocate_stack): Likewise. + * descr.h (struct pthread): Add header.multiple_threads + unconditionally. + * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h (CENABLE, CDISABLE): + Define for librt. #error if neither libpthread, libc nor librt. + * sysdeps/unix/sysv/linux/ia64/sysdep-cancel.h (CENABLE, CDISABLE): + Likewise. + * sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h (CENABLE, + CDISABLE): Likewise. + * sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h (CENABLE, + CDISABLE): Likewise. + * sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h (CENABLE, + CDISABLE): Likewise. + * sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h (CENABLE, + CDISABLE): Likewise. Access header.multiple_threads outside of + libc and libpthread. + * sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h (CENABLE, CDISABLE): + Likewise. + * sysdeps/x86_64/tls.h (tcbhead_t): Add multiple_threads. + * sysdeps/x86_64/tcb-offsets.sym (MULTIPLE_THREADS_OFFSET): Define. + +2003-06-17 Ulrich Drepper <drepper@redhat.com> + + * tst-cancel4.c: Add tests for the socket and signal functions, pause. + Also test early cancellation before the thread reaches the cancellation + point. + + * Makefile: Compile forward.c with exceptions. + + * sysdeps/unix/sysv/linux/sleep.c: New file. + +2003-06-16 Ulrich Drepper <drepper@redhat.com> + + * Makefile: Add CFLAGS definition to compile function wrappers + duplicated from libc with exceptions. + * tst-cancel4.c: Also check cancellation handlers. + + * Makefile: Add rules to build and run tst-cancel16 and + tst-cancelx16. Add missing CFLAGS definitions. + * tst-cancel16.c: New file. + * tst-cancelx16.c: New file. + +2003-06-15 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/dl-sysdep.h + (DL_SYSINFO_IMPLEMENTATION): Use CFI opcodes. + * sysdeps/unix/sysv/linux/i386/i686/dl-sysdep.h + (DL_SYSINFO_IMPLEMENTATION): Likewise. + + * pthreadP.h (LIBC_CANCEL_ASYNC): Also define for librt. + (LIBC_CANCEL_RESET): Likewise. + Declare __librt_enable_asynccancel and __librt_disable_asynccancel. + * sysdeps/pthread/Makefile (librt-sysdep_routines): Add + librt-cancellation. + (CFLAGS-libcrt-cancellation.c): Define. + * sysdeps/pthread/librt-cancellation.c: New file. + * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h: Define all the nice + macros also when compiling librt. + * sysdeps/unix/sysv/linux/ia64/sysdep-cancel.h: Likewise. + * sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h: Likewise. + * sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h: Likewise. + * sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h: Likewise. + * sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h: Likewise. + * sysdeps/unix/sysv/linux/sh/sysdep-cancel.h: Likewise. + * sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h: Likewise. + + * sysdeps/unix/sysv/linux/timer_create.c: Add prototype for + compat_timer_create. + +2003-06-14 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/posix-timer.h (timespec_compare): Always inline. + + * sysdeps/unix/sysv/linux/fork.h: Add libc_hidden_proto for + __register_atfork. + * sysdeps/unix/sysv/linux/register-atfork.c (__register_atfork): + Add libc_hidden_def. + +2003-06-13 Roland McGrath <roland@redhat.com> + + * sysdeps/x86_64/td_ta_map_lwp2thr.c (td_ta_map_lwp2thr): Pass FS + constant from <sys/reg.h> to ps_get_thread_area, not register contents. + +2003-06-11 Ulrich Drepper <drepper@redhat.com> + + * allocatestack.c (queue_stack): Always inline. + * ptreadhP.h (__do_cancel): Likewise. + +2003-06-10 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/s390/sem_timedwait.c (sem_timedwait): Fix + a typo. + +2003-06-10 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_signal.S + (__pthread_cond_signal): Remove incorrect second addition for + cond_lock!=0. + +2003-06-09 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_signal.S + (__pthread_cond_signal): Use correct futex pointer in + __lll_mutex_lock_wait call. + + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_signal.S + (__pthread_cond_signal): Some more tweaks to handle cond_lock!=0. + +2003-06-08 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/s390/sem_wait.c (__new_sem_wait): Make + cancelable. + * sysdeps/unix/sysv/linux/s390/sem_timedwait.c (sem_timedwait): + Likewise. + + * sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h: Remove + hand-written CFI generation code. Since ENTRY/END also initiated + CFI frames this caused two CFI sets to be generated. + +2003-06-07 Ulrich Drepper <drepper@redhat.com> + + * cleanup_routine.c: New file. + * Versions (libpthread) [GLIBC_2.3.3]: Add __pthread_cleanup_routine. + * sysdeps/pthread/pthread.h: Add support for fully exception-based + cleanup handling. + * Makefile (libpthread-routines): Add cleanup_routine. + Add more CFLAGS variables to compile with exceptions. Add comments + why which file needs unwind tables. + (tests) [have-forced-unwind==yes]: Add tst-cancelx* and tst-cleanupx* + tests. + * tst-cancelx1.c: New file. + * tst-cancelx2.c: New file. + * tst-cancelx3.c: New file. + * tst-cancelx4.c: New file. + * tst-cancelx5.c: New file. + * tst-cancelx6.c: New file. + * tst-cancelx7.c: New file. + * tst-cancelx8.c: New file. + * tst-cancelx9.c: New file. + * tst-cancelx10.c: New file. + * tst-cancelx11.c: New file. + * tst-cancelx12.c: New file. + * tst-cancelx13.c: New file. + * tst-cancelx14.c: New file. + * tst-cancelx15.c: New file. + * tst-cleanupx0.c: New file. + * tst-cleanupx0.expect: New file. + * tst-cleanupx1.c: New file. + * tst-cleanupx2.c: New file. + * tst-cleanupx3.c: New file. + + * tst-cleanup0.c: Make standard compliant. + * tst-cleanup1.c: Likewise. + + * sysdeps/unix/sysv/linux/sem_timedwait.c: Add cancellation support. + * sysdeps/unix/sysv/linux/sem_wait.c: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/sem_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/sem_wait.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/sem_wait.S: Likewise. + * sysdeps/i386/tcb-offsets.sym: Add RESULT, CANCELHANDLING, and + CLEANUP_JMP_BUF. + * sysdeps/x86_64/tcb-offsets.sym: Likewise. + * tst-cancel12.c: New file. + * tst-cancel13.c: New file. + * tst-cancel14.c: New file. + * tst-cancel15.c: New file. + * Makefile (tests): Add tst-cancel12, tst-cancel13, tst-cancel14, + and tst-cancel15. + + * tst-cancel1.c: Add some comments. + + * sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S: Compute relative + timeout correctly. + +2003-06-06 Ulrich Drepper <drepper@redhat.com> + + * Makefile (CFLAGS-pthread_cancel.c): Define. + +2003-06-05 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h (pthread_rwlock_t): + Change type of __writer element to int. + * sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: Likewise. + * sysdeps/i386/tcb-offsets.sym: Replace SELF entry with TID entry. + * sysdeps/x86_64/tcb-offsets.sym: Likewise. + * pthread_rwlock_trywrlock.c: Store TID not self pointer in __writer. + Compare with TID to determine deadlocks. + * sysdeps/pthread/pthread_rwlock_rdlock.c: Likewise. + * sysdeps/pthread/pthread_rwlock_timedrdlock.c: Likewise. + * sysdeps/pthread/pthread_rwlock_timedwrlock.: Likewise. + * sysdeps/pthread/pthread_rwlock_wrlock.c: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_rdlock.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedrdlock.S: + Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedwrlock.S: + Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_wrlock.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_rdlock.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedrdlock.S: + Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedwrlock.S: + Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_wrlock.S: Likewise. + * Makefile (tests): Add tst-rwlock12. + * tst-rwlock12.c: New file. + +2003-06-05 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/lowlevellock.c (__lll_lock_wait, + __lll_timedlock_wait, lll_unlock_wake_cb, __lll_timedwait_tid): + Remove bogus hidden_proto. + * sysdeps/unix/sysv/linux/s390/libc-lowlevellock.c (___lll_lock): + Likewise. + * sysdeps/unix/sysv/linux/s390/lowlevellock.c (___lll_lock, + lll_unlock_wake_cb, ___lll_timedwait_tid): Likewise. + * sysdeps/unix/sysv/linux/s390/lowlevelmutex.c (___lll_mutex_lock, + ___lll_mutex_timedlock): Likewise. + +2003-06-04 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_signal.S + (__pthread_cond_signal): Add some code to eventually handle + cond_lock!=0. + +2003-06-01 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add tst-exec4. + (tst-exec4-ARGS): Define. + * tst-exec4.c: New file. + +2003-05-31 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/lowlevellock.c (__lll_timedlock_wait): + Also fail if tv_nsec < 0. + (__lll_timedwait_tid): Likewise. + * sysdeps/unix/sysv/linux/sem_timedwait.c (sem_timedwait): Likewise. + * sysdeps/unix/sysv/linux/i386/lowlevellock.h (lll_timedwait_tid): + Likewise. + * sysdeps/unix/sysv/linux/s390/lowlevellock.c (___lll_timedwait_tid): + Likewise. + * sysdeps/unix/sysv/linux/s390/lowlevelmutex.c (__lll_mutex_timedlock): + Likewise. + * sysdeps/unix/sysv/linux/s390/sem_timedwait.c (sem_timedwait): + Likewise. + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h (lll_timedwait_tid): + Likewise. + * sysdeps/unix/sysv/linux/sh/lowlevellock.h (lll_timedwait_tid): + Likewise. + + * Makefile (tests): Add tst-sem8 and tst-sem9. + * tst-sem8.c: New file. + * tst-sem9.c: New file. + * sem_open.c: Fix creation of in_use record if the file exists but + no internal record. + + * posix-timer.h: Remove old, unused timer_id2ptr and timer_ptr2id + definitions. + + * sysdeps/pthread/timer_create.c (timer_create): In case + evp==NULL, assign timer ID to sival_ptr. + + * descr.h (struct pthread_unwind_buf): Change type of prev element to + struct pthread_unwind_buf *. + (struct pthread): Likewise for cleanup_jmp_buf element. + + * cleanup.c (__pthread_register_cancel): Add cast to avoid warning. + * cleanup_defer.c (__pthread_register_cancel_defer): Likewise. + * unwind.c (__pthread_unwind_next): Likewise. + +2003-05-30 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/ia64/lowlevellock.h + (lll_futex_timed_wait): Use int for futex value parameter. + (lll_futex_wake): Likewise. + (lll_futex_requeue): Likewise. + + * sysdeps/unix/sysv/linux/lowlevellock.c (__lll_lock_wait): + Replace one memory operation with one register operation. + + * tst-join4.c (do_test): Fix error message. + + * tst-rwlock6.c (do_test): Use correct format specifier. + + * sysdeps/unix/sysv/linux/i386/i486/lowlevelmutex.S + (__lll_mutex_lock_wait): Replace one memory operation with one + register operation. + * sysdeps/unix/sysv/linux/x86_64/lowlevelmutex.S + (__lll_mutex_lock_wait): Likewise. + + * sysdeps/unix/sysv/linux/ia64/lowlevellock.h + (__lll_mutex_cond_lock): Add one to value parameter of + __lll_lock_wait to reflect reality in the futex syscall. + * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h + (lll_mutex_cond_lock): Likewise. + +2003-05-30 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/s390/lowlevellock.h (__lll_mutex_cond_lock): + New function. + (lll_mutex_cond_lock): Define. + +2003-05-29 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add tst-signal6. + * tst-signal6.c: New file. + + * sysdeps/unix/sysv/linux/s390/lowlevellock.h + (__lll_mutex_unlock_force): New function + (lll_mutex_unlock_force): Use __lll_mutex_unlock_force. + + * sysdeps/unix/sysv/linux/ia64/lowlevellock.h + (__lll_mutex_unlock_force): New function. + (lll_mutex_unlock_force): Use __lll_mutex_unlock_force. + + * tst-rwlock7.c (do_test): Use correct format specifier. + + * sysdeps/unix/sysv/linux/ia64/lowlevellock.h (lll_futex_requeue): + Find break parameter in correct asm argument. + +2003-05-27 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/ia64/lowlevellock.h (lll_futex_clobbers): + Remove out4. + (lll_futex_requeue): Fix __o3 constraint, return negative errno if + error occured. + * sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h (pthread_cond_t): + Add __mutex. + * sysdeps/unix/sysv/linux/s390/lowlevellock.h (FUTEX_REQUEUE, + lll_futex_requeue, lll_mutex_unlock_force): Define. + +2003-05-30 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h + (pthread_cond_t): Add __mutex. + * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h (FUTEX_REQUEUE, + lll_futex_requeue, lll_mutex_unlock_force): Define. + +2003-05-28 Kaz Kojima <kkojima@rr.iij4u.or.jp> + + * sysdeps/sh/tcb-offsets.sym: Define MUTEX_FUTEX. + * sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h (pthread_cond_t): + Add __mutex field. + * sysdeps/unix/sysv/linux/sh/lowlevellock.h (SYSCALL_WITH_INST_PAD): + Define. + (lll_futex_wait, lll_futex_wake): Define. + * sysdeps/unix/sysv/linux/sh/sh4/lowlevellock.h: New file. + * sysdeps/unix/sysv/linux/sh/pthread_cond_broadcast.S: Try using + FUTEX_REQUEUE instead of FUTEX_WAIT. + * sysdeps/unix/sysv/linux/sh/pthread_cond_signal.S: Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_cond_timedwait.S: Remember + mutex which was used in condvar structure. Call + __pthread_mutex_cond_lock instead of __pthread_mutex_lock_internal. + * sysdeps/unix/sysv/linux/sh/pthread_cond_wait.S: Likewise. + + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_rdlock.S: Don't + include tcb-offsets.h. Read wakeup value in locked region. + Use the value of gbr register as THREAD_ID. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_wrlock.S: Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedrdlock.S: Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedwrlock.S: Likewise. + + * sysdeps/unix/sysv/linux/sh/sem_trywait.S: Remove futex related + macros. + +2003-05-28 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/pthread_cond_broadcast.c + (__pthread_cond_broadcast): Fix typo: MAX_INT -> INT_MAX. + +2003-05-26 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S: Fix + typo in register name. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_signal.S: Use parameters + correctly. Actually use requeue. Little optimization. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: Store + mutex address early. Handle cancellation state as 32-bit value. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S: Likewise. + Remove unnecessary label. + +2003-05-25 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/pthread_cond_broadcast.c: Try using FUTEX_REQUEUE + instead of FUTEX_WAIT. + * sysdeps/pthread/pthread_cond_signal.c: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_signal.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_signal.S: Likewise. + * sysdeps/pthread/pthread_cond_timedwait.c: Remember mutex which was + used in condvar structure. Call __pthread_mutex_cond_lock instead + of __pthread_mutex_lock_internal. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: Likewise. + * sysdeps/pthread/pthread_cond_wait.c: Likewise. + (__condvar_cleanup): Always call __pthread_mutex_cond_lock. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S: Likewise. + * sysdeps/unix/sysv/linux/Makefile (libpthread-sysdep_routines): + Add pthread_mutex_cond_lock. + * sysdeps/unix/sysv/linux/lowlevelcond.sym: Add dep_mutex. + * sysdeps/unix/sysv/linux/pthread_cond_mutex_lock.c: New file. + * sysdeps/unix/sysv/linux/i386/lowlevellock.h: Define + lll_mutex_cond_lock. + * sysdeps/unix/sysv/linux/ia64/lowlevellock.h: Likewise. + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h: Likewise. + * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h (pthread_cond_t): + Add __mutex field. + * sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: Likewise. + + * sysdeps/i386/tcb-offsets.sym: Define MUTEX_FUTEX. + * sysdeps/x86_64/tcb-offsets.sym: Likewise. + + * pthreadP.h: Declare __pthread_mutex_cond_lock. + * pthread_mutex_lock.c: Define LLL_MUTEX_LOCK if not already defined. + Use it instead of lll_mutex_lock. If __pthread_mutex_lock is a + macro don't define aliases. + + * cancellation.c: Remove __pthread_enable_asynccancel_2. + * pthreadP.h: Remove declaration of __pthread_enable_asynccancel_2. + * sysdeps/pthread/pthread_cond_timedwait.c: Use + __pthread_enable_asynccancel instead of __pthread_enable_asynccancel_2. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: Likewise. + * sysdeps/pthread/pthread_cond_wait.c: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S: Likewise. + +2003-05-17 Ulrich Drepper <drepper@redhat.com> + + * sem_open.c: Fix one endless loop. Implement correct semantics + wrt opening the same semaphore more then once. + * sem_close.c: Adjust for sem_open change. + * semaphoreP.h: Include <semaphore.h>. Define struct inuse_sem. + Declare __sem_mappings, __sem_mappings_lock, __sem_search. + * Makefile (tests): Add tst-sem7. + * tst-sem7.c: New file. + +2003-05-16 Roland McGrath <roland@redhat.com> + + * sysdeps/unix/sysv/linux/register-atfork.c (libc_freeres_fn): Fix + uninitialized variable braino. + +2003-05-16 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/timer_gettime.c (timer_gettime): Correct + test for syscall availability. + + * sysdeps/unix/sysv/linux/timer_settime.c (timer_settime): Set + __no_posix_timers to -1 if the syscalls don't exist. + + * pthread_join.c (pthread_join): Set tid field of the joined + thread to -1. This isn't necessary but helps to recognize some + error conditions with almost no cost. + + * allocatestack.c (FREE_P): Also negative values indicate an + unused stack. + + * unwind.c: Include <unistd.h>. + +2003-05-14 Ulrich Drepper <drepper@redhat.com> + + * Makefile ($(objpfx)$(multidir)): Add rule to create the directory. + +2003-05-14 Jakub Jelinek <jakub@redhat.com> + + * Makefile (crti-objs, crtn-objs): New variables. + (omit-deps, extra-objs): Add crtn. + ($(objpfx)libpthread.so): Depend on both crti and crtn + and links to them in multidir. + ($(objpfx)crtn.S, $(objpfx)crtn.o): New rules. + +2003-05-12 Steven Munroe <sjmunroe@us.ibm.com> + + * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h + (lll_mutex_unlock): Use atomic_exchange_rel. + +2003-05-11 Ulrich Drepper <drepper@redhat.com> + + * cond-perf.c (cons): Add missing locking around setting of alldone. + +2003-05-10 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/i486/sem_trywait.S: Remove futex + related macros. + * sysdeps/unix/sysv/linux/x86_64/sem_trywait.S: Likewise. + +2003-05-09 Ulrich Drepper <drepper@redhat.com> + + * tst-sem6.c: New file. + * Makefile (tests): Add tst-sem6. + + * sysdeps/unix/sysv/linux/ia64/lowlevellock.h (___lll_mutex_unlock): + Use atomic_exchange_rel instead of atomic_exchange. + * sysdeps/unix/sysv/linux/lowlevellock.c (lll_unlock_wake_cb): + Likewise. + + * sysdeps/unix/sysv/linux/i386/lowlevellock.h: Improve quality of + code for lll_futex_wait and lll_futex_wake in static apps. Use + vsyscall is possible. + + * sysdeps/unix/sysv/linux/pthread_getaffinity.c: New file. + * sysdeps/unix/sysv/linux/pthread_setaffinity.c: New file. + * sysdeps/pthread/pthread.h: Declare pthread_getaffinity_np and + pthread_setaffinity_np. + * Versions [libpthread] (GLIBC_2.3.3): Add pthread_getaffinity_np + and pthread_setaffinity_np. + * Makefile (libpthread-routines): Add pthread_getaffinity and + pthread_setaffinity. + + * allocatestack.c (allocate_stack): If ARCH_RETRY_MMAP is defined, + use it in case mmap to allocate the stack fails. + * sysdeps/unix/sysv/linux/x86_64/Makefile: Don't define + ARCH_MAP_FLAGS here. + * sysdeps/x86_64/pthreaddef.h: Define ARCH_MAP_FLAGS and + ARCH_RETRY_MMAP. + +2003-05-08 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/fork.c: Complete rewrite of the atfork + handler implementation. It is now lockless in fork(). + * sysdeps/unix/sysv/linux/register-atfork.c: Likewise. + * sysdeps/unix/sysv/linux/unregister-atfork.c: Likewise. + * sysdeps/unix/sysv/linux/fork.h: Don't include <link.h>. Don't + declare the __fork_*_lists. + (struct fork_handler): Include pointers to all three functions. + Add next, refcntr and need_signal elements. + (__fork_handlers): New declaration. + (__register_atfork_malloc): Remove declaration. + (HAVE_register_atfork_malloc): Remove definition. + * sysdeps/unix/sysv/linux/libc_pthread_init.c: Remove + __pthread_child_handler variable. + (__libc_pthread_init): Use __register_atfork instead of explicitly + adding to the list. + * sysdeps/unix/sysv/linux/i386/lowlevellock.h: Define lll_futex_wait + and lll_futex_wake. + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h: Likewise. + + * unwind.c (unwind_cleanup): Print error message and then abort. This + function must never be reached. + + * cond-perf.c: New file. + +2003-05-05 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/i386/tls.h (TLS_INIT_TP): Include \n in error message. + +2003-05-04 Roland McGrath <roland@redhat.com> + + * Makefile ($(objpfx)../libc.so): New target. + +2003-05-02 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h + (pthread_condattr_t): Size is only an int, don't use long for + alignment. + (pthread_mutexattr_t): Likewise. + * sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h: Likewise. + +2003-05-01 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/i386/tls.h: Define THREAD_ID. + * sysdeps/ia64/tls.h: Likewise. + * sysdeps/powerpc/tls.h: Likewise. + * sysdeps/s390/tls.h: Likewise. + * sysdeps/sh/tls.h: Likewise. + * sysdeps/x86_64/tls.h: Likewise. + * pthread_mutex_lock.c: Use THREAD_ID instead of THREAD_SELF to + record ownership. + * pthread_mutex_timedlock.c: Likewise. + * pthread_mutex_trylock.c: Likewise. + * pthread_mutex_unlock.c: Likewise. + * pthread_rwlock_trywrlock.c: Likewise. + * sysdeps/pthread/pthread_rwlocklock_rdlock.c: Likewise. + * sysdeps/pthread/pthread_rwlock_timedrdlock.c: Likewise. + * sysdeps/pthread/pthread_rwlock_timedwrlock.c: Likewise. + * sysdeps/pthread/pthread_rwlock_wrlock.c: Likewise. + + * sysdeps/pthread/createthread.c (create_thread): Use CLONE_SYSVSEM + flag. + +2003-04-29 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h + (__SIZEOF_PTHREAD_COND_T): Define to 48. + (pthread_rwlock_t): Add 16 bytes of pad instead of 8 before __flags. + * sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h (pthread_cond_t): + Make __align long long instead of long. + (pthread_rwlock_t): Formatting. + * sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h + (pthread_rwlock_t): Formatting. + * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h + (pthread_cond_t): Make __align long long instead of long. + (pthread_rwlock_t): Move __flags field to the same position as in + linuxthreads. + +2003-04-30 Ulrich Drepper <drepper@redhat.com> + + * tst-rwlock6.c (do_test): Use correct printf format specifiers. + * tst-rwlock7.c (do_test): Likewise. + +2003-04-26 Roland McGrath <roland@redhat.com> + + * Makefile ($(test-modules)): Depend on $(common-objpfx)shlib.lds. + +2003-04-22 Jakub Jelinek <jakub@redhat.com> + + * allocatestack.c (TLS_TPADJ): Add TLS_PRE_TCB_SIZE instead of + sizeof (struct pthread). + (allocate_stack): Subtract TLS_PRE_TCB_SIZE bytes instead of + 1 struct pthread. + * sysdeps/powerpc/tls.h (TLS_INIT_TCB_SIZE, TLS_TCB_SIZE): Define + to 0. + (TLS_INIT_TCB_ALIGN, TLS_TCB_ALIGN): Define to alignment of + struct pthread. + (TLS_PRE_TCB_SIZE): Increase to cover tcbhead_t preceeded by pad + to 32-bit bytes. + (INSTALL_DTV, GET_DTV, THREAD_DTV): tcbhead_t is immediately before + tcbp. + (TLS_INIT_TP, THREAD_SELF, INIT_THREAD_SELF): Don't add TLS_TCB_SIZE + unneccessarily. + (NO_TLS_OFFSET): Define. + * sysdeps/unix/sysv/linux/powerpc/createthread.c (TLS_VALUE): Don't + add TLS_TCB_SIZE unnecessarily. + +2003-04-22 Roland McGrath <roland@redhat.com> + + * Makeconfig (shared-thread-library): Reverse link order to work + around linker bug. + +2003-04-22 Ulrich Drepper <drepper@redhat.com> + + * semaphore.h: Fix typo in comment. + +2003-04-21 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/sigfillset.c: New file. + + * init.c (__pthread_initialize_minimal): Don't block SIGTIMER. + * pthreadP.h: Make SIGTIMER and SIGCANCEL the same. + * sysdeps/pthread/pthread_sigmask.c: Remove handling of SIGTIMER. + * sysdeps/pthread/sigaction.c: Likewise. + * sysdeps/pthread/sigprocmask.c: New file. + * sysdeps/unix/sysv/linux/allocrtsig.c (current_rtmin): Define as + __SIGRTMIN+1. + * sysdeps/unix/sysv/linux/timer_routines.c (timer_helper_thread): + Block SIGTIMER. Also handle SI_TKILL events and terminate thread + in this case. + +2003-04-19 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/dl-sysdep.h + (DL_SYSINFO_IMPLEMENTATION): Add .eh_frame information. + + * sysdeps/unix/sysv/linux/unregister-atfork.c + (__unregister_atfork): Don't free memory not allocated dynamically. + + * semaphore.h: Remove __THROW marker from cancellation points. + * nptl/sysdeps/pthread/pthread.h: Likewise. + +2003-04-18 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/pthread.h: Don't mark pthread_testcancel, + pthread_cancel, pthread_setcancelstate, and pthread_setcanceltype with + __THROW. + +2003-04-16 Jakub Jelinek <jakub@redhat.com> + + * tst-cancel4.c (do_test): Use %zd instead of %d when printing cnt. + +2003-04-15 Roland McGrath <roland@redhat.com> + + * forward.c (__pthread_unwind): Tweak to avoid warning. + +2003-04-15 Ulrich Drepper <drepper@redhat.com> + + * pthreadP.h: Move THREAD_ATOMIC_* replacements to the top. + +2003-04-14 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S: Don't + overflow CFA advance instructions. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: Likewise. + +2003-04-14 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/i386/tls.h: Rename LOCK to LOCK_PREFIX. + * sysdeps/i386/pthread_spin_lock.c: Likewise. + * sysdeps/x86_64/tls.h: Likewise. Define LOCK_PREFIX if not already + defined. + + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Use + DW_CFA_advance_loc2 for .Laddl-.Lsubl. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Use + DW_CFA_advance_loc for .Laddl-.Lsubl. + +2003-04-13 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h: Don't use + position-independent unwind data for static libraries. + Add missing unwind info. Add comments. + + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S: Add unwind info. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Likewise. + +2003-04-12 Ulrich Drepper <drepper@redhat.com> + + * Makefile: Make sure all cancellation points are compiled with + exception and asynchronous unwind tables. + + * sysdeps/x86_64/tls.h (THREAD_SETMEM): Word around compiler bug + which mishandles loading of global object addresses in PIC. + (THREAD_SETMEM_NC): Likewise. + +2003-04-11 Ulrich Drepper <drepper@redhat.com> + + * pthread.h: Define new data structure for cleanup buffer. Declare + new cleanup handler interfaces. + * descr.h: Include <unwind.h> if necessary. Define pthread_unwind_buf. + (struct pthread): Add cleanup_jmp_buf pointer. Define + HAVE_CLEANUP_JMP_BUF and not HAVE_CANCELBUF. + * pthreadP.h: Declare __pthread_unwind. Define __do_cancel to use + it. Declare old cleanup handler installation functions. + * cleanup.c: Rewrite. Install handler for unwind-based cleanup + handling. + * cleanup_defer.c: Likewise. + * cleanup_compat.c: New file. Old cleanup code. + * cleanup_def_compat.c: New file. Old cleanup code. + * pthread_create.c (start_thread): Initialize cleanup_jmp_buf element + if own thread descriptor. + * unwind.c: New file. + * forward.c: Add __pthread_unwind. + * init.c (pthread_functions): Add __pthread_unwind. + * sysdeps/pthread/pthread-functions.s (struct pthread_functions): + Add ptr___pthread_unwind. + * Versions [GLIBC_2.3.3] (libpthread): Export new cleanup handling + and unwind function. + * Makefile (libpthread-routines): Add cleanup_compat, + cleanup_def_compat, and unwind. Define CFLAGS to enable unwind + table generation if necessary. + * version.c: Record whether unwind support is compiled in. + * sysdeps/pthread/configure.in: Add checks for unwind unterfaces. + * sysdeps/pthread/bits/libc-lock.h: Add prototypes of the old cleanup + handler interfaces. + * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h: Add quite a bit of + complication to generate unwind information for syscall wrappers. + * sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h: Likewise. + * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h: Define + __cleanup_fct_attribute. + + * Makefile: Add rules to build and run tst-cleanup0. + * tst-cleanup0.c: New file. + * tst-cleanup0.expect: New file. + + * pthread_create.c (deallocate_tsd): Don't take parameter. Adjust + caller. Optimize to avoid often unecessary local variable. + +2003-04-11 Roland McGrath <roland@redhat.com> + + * Makefile ($(objpfx)multidir.mk): New target, generated makefile that + sets variable `multidir'; include that. + (generated): Add it. + ($(objpfx)$(multidir)/crti.o): New target. + [$(multidir) != .] (generated-dirs, extra-objs, omit-deps): Add it. + +2003-04-11 Ulrich Drepper <drepper@redhat.com> + + * tst-attr2.c (do_test): Add cast to avoid warning. + * tst-mutex4.c (do_test): Likewise. + +2003-04-10 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/fork.c (__libc_fork): Reset CPU clocks + in child. + +2003-04-09 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add tst-detach1. + * tst-detach1.c: New file. + +2003-04-08 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/pthread.h: Remove duplicate + pthread_cleanup_{push,pop} definitions. + + * tst-barrier2.c: Eliminate warnings. + * tst-cancel4.c: Likewise. + * tst-cond4.c: Likewise. + * tst-cond6.c: Likewise. + * tst-detach1.c: Likewise. + * tst-rwlock4.c: Likewise. + * tst-rwlock6.c: Likewise. + * tst-rwlock7.c: Likewise. + * tst-sem3.c: Likewise. + * tst-spin2.c: Likewise. + * tst-umask1.c: Likewise. + +2003-04-07 Ulrich Drepper <drepper@redhat.com> + + * pthread_detach.c (pthread_detach): Fix test for invalid TID. + +2003-04-06 Ulrich Drepper <drepper@redhat.com> + + * descr.h (struct pthread): Move cancelhandling member to the front. + +2003-04-05 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/register-atfork.c: Define malloc_prepare, + malloc_parent, and malloc_child statically. + (__register_atfork_malloc): New function. + (free_mem): Don't free any of the malloc_* variables on the list. + * sysdeps/unix/sysv/linux/fork.h: Declare __register_atfork_malloc. + Define HAVE_register_atfork_malloc. + +2003-04-04 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/createthread.c (create_thread): Add some more + comments explaining when to set multiple_threads and when not. + + * pthreadP.h: Define THREAD_ATOMIC_CMPXCHG_VAL and + THREAD_ATOMIC_BIT_SET if not already defined. + * sysdeps/i386/tls.h: Define THREAD_ATOMIC_CMPXCHG_VAL and + THREAD_ATOMIC_BIT_SET: + * sysdeps/x86_64/tls.h: Likewise. + * cleanup_defer.c (_pthread_cleanup_push_defer): Rewrite to use + THREAD_ATOMIC_CMPXCHG_VAL. + (_pthread_cleanup_pop_restore): Likewise. + * cancellation.c (__pthread_enable_asynccancel): Likewise. + (__pthread_enable_asynccancel_2): Likewise. + (__pthread_disable_asynccancel): Likewise. + * libc-cancellation.c (__libc_enable_asynccancel): Likewise. + (__libc_disable_asynccancel): Likewise. + * init.c (sigcancel_handler): Likewise. + * pthread_setcancelstate.c (__pthread_setcancelstate): Likewise. + * pthread_setcanceltype.c (__pthread_setcanceltype): Likewise. + +2003-04-03 Ulrich Drepper <drepper@redhat.com> + + * init.c (sigcancel_handler): Don't set EXITING_BIT here. + * libc-cancellation.c (__libc_enable_asynccancel): Likewise. + * pthreadP.h (__do_cancel): Set EXITING_BIT here. + * Makefile (tests): Add tst-cancel11. + * tst-cancel11.c: New file. + +2003-04-01 Ulrich Drepper <drepper@redhat.com> + + * pthread_create.c (deallocate_tsd): Clear/free memory after the last + round, not the first. Use specific_used flag instead of local + found_nonzero variable. Use THREAD_[SG]ETMEM where possible. + (__free_tcb): Don't call deallocate_tsd here. + (start_thread): Call deallocate_tsd here. + * pthread_setspecific.c: Set specific_used flag really only when + needed. + * Makefile (tests): Add tst-tsd3.c and tst-tsd4. + * tst-tsd3.c: New file. + * tst-tsd4.c: New file. + +2003-03-31 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/ia64/lowlevellock.h (__lll_mutex_lock): + Use atomic_exchange_and_add instead of __lll_add. + (__lll_mutex_timedlock): Likewise. + Patch by Ian Wienand. + +2003-03-24 Steven Munroe <sjmunroe@us.ibm.com> + + * sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h + (SINGLE_THREAD_P): Fix typo. + * tst-cancel-wrappers.sh: Handle '.'ed symbols. + +2003-03-31 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add tst-align. + * tst-align.c: New file. + * sysdeps/i386/Makefile: Define CFLAGS-tst-align. + + * sysdeps/i386/tls.h (CALL_THREAD_FCT): Align stack of called + function correctly. + + * tst-tsd2.c: Add casts to avoid warnings. + +2003-03-30 Ulrich Drepper <drepper@redhat.com> + + * descr.h (struct pthread): Move most often used elements to the front. + +2003-03-29 Ulrich Drepper <drepper@redhat.com> + + * Makefile (libpthread-routines): Add pthread_atfork. + (libpthread-static-only-routines): Add pthread_atfork. + +2003-03-28 Kaz Kojima <kkojima@rr.iij4u.or.jp> + + * sysdeps/sh/tls.h: Include nptl/descr.h after the definition + of TLS_DTV_AT_TP. + (INSTALL_DTV): Add parens. + (THREAD_GETMEM, THREAD_GETMEM_NC, THREAD_SETMEM, THREAD_SETMEM_NC): + Use passed descr instead of THREAD_SELF. + * sysdeps/unix/sysv/linux/sh/lowlevelmutex.S + (__lll_mutex_timedlock_wait): Correct expected value after + spurious wakeup. + * sysdeps/unix/sysv/linux/sh/pthread_cond_broadcast.S: + Release lock before waking up the waiters. + * sysdeps/unix/sysv/linux/sh/pthread_cond_wait.S: Correct exit + criteria. Reorderstruct passed to cleanup handler. Fix + handling of cancellation and failung pthread_mutex_unlock call. + Use __pthread_enable_asynccancel_2 instead of + __pthread_enable_asynccancel. + * sysdeps/unix/sysv/linux/sh/pthread_cond_timedwait.S: Likewise. + Return result of lock re-get if it fails. + * sysdeps/unix/sysv/linux/sh/pthread_once.S: Fix wrong argument + for __pthread_cleanup_push. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_rdlock.S: Fix + completely broken rwlock implementation. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_wrlock.S: Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedrdlock.S: Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedwrlock.S: Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_unlock.S: Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_wrlock.S: Likewise. + * sysdeps/unix/sysv/linux/sh/sem_post.S: Fix error value. Use + versioned_symbol macro. + * sysdeps/unix/sysv/linux/sh/sem_trywait.S: Use versioned_symbol macro. + * sysdeps/unix/sysv/linux/sh/sem_wait.S: Likewise. + +2003-03-27 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/kernel-posix-timers.h: Don't declare + __timer_helper_thread. Declare __start_helper_thread, __helper_once, + and __helper_tid. + (struct timer): Remove th and bar field. + * sysdeps/unix/sysv/linux/timer_create.c (timer_create): Remove + debugging code. Create only one helper thread. + * sysdeps/unix/sysv/linux/timer_delete.c (timer_delete): Don't kill + helper thread. + * sysdeps/unix/sysv/linux/timer_routines.c (timer_helper_thread): + Renamed. Define statically. Use thread info from siginfo. + (__helper_once): New variable. + (__helper_tid): New variable. + (__reset_helper_control): New function. + (__start_helper_thread): New function. + + * pthread_create.c (start_thread): Don't use setjmp inside + __builtin_expect to work around gcc bug. + + * sysdeps/unix/sysv/linux/timer_delete.c (timer_delete): Even if + timer_delete syscall fails, but not with ENOSYS, set + __no_posix_timers. + + * sysdeps/unix/sysv/linux/timer_settime.c [!__ASSUME_POSIX_TIMERS] + (timer_settime): Fix typo. + * sysdeps/unix/sysv/linux/timer_getoverr.c + [!__ASSUME_POSIX_TIMERS] (timer_getoverrun): Likewise. + +2003-03-27 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Fix + offset of cleanupbuf.__prev. + +2003-03-26 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/timer_getoverr.c: Fix typo in name + of included file. + +2003-03-26 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/timer_create.c (timer_create): If EVP == + NULL provide default definition to syscall. + +2003-03-25 Roland McGrath <roland@redhat.com> + + * sysdeps/pthread/posix-timer.h (TIMER_MAX): Define if not defined. + (timer_id2ptr): Fix typo. + +2003-03-25 Ulrich Drepper <drepper@redhat.com> + + * pthreadP.h: Define SIGCANCEL and SIGTIMER. + * sysdeps/i386/pthreaddef.h: Remove SIGCANCEL definition. + * sysdeps/ia64/pthreaddef.h: Likewise. + * sysdeps/powerpc/pthreaddef.h: Likewise. + * sysdeps/s390/pthreaddef.h: Likewise. + * sysdeps/sh/pthreaddef.h: Likewise. + * sysdeps/x86_64/pthreaddef.h: Likewise. + * init.c (__pthread_initialize_minimal): Block SIGTIMER. + * sysdeps/pthread/sigaction.c: Also prevent SIGTIMER handler from + being changed. + * sysdeps/pthread/pthread_sigmask.c (pthread_sigmask): Make sure + SIGTIMER is not unblocked. + * sysdeps/unix/sysv/linux/allocrtsig.c (current_rtmin): One more + RT signal taken. + * sysdeps/unix/sysv/linux/pthread_kill.c: Do not allow SIGTIMER to + be send. + * sysdeps/pthread/posix-timer.h (timer_id2ptr, timer_ptr2id): Just + pass pointer through as ID. + * sysdeps/unix/sysv/linux/bits/local_lim.h (TIMER_MAX): Removed. + * sysdeps/unix/sysv/linux/kernel-posix-timers.h: New file. + * sysdeps/unix/sysv/linux/timer_create.c: New file. + * sysdeps/unix/sysv/linux/timer_delete.c: New file. + * sysdeps/unix/sysv/linux/timer_getoverr.c: New file. + * sysdeps/unix/sysv/linux/timer_gettime.c: New file. + * sysdeps/unix/sysv/linux/timer_routines.c: New file. + * sysdeps/unix/sysv/linux/timer_settime.c: New file. + * sysdeps/unix/sysv/linux/ia64/Versions: New file. + * sysdeps/unix/sysv/linux/ia64/timer_create.c: New file. + * sysdeps/unix/sysv/linux/ia64/timer_delete.c: New file. + * sysdeps/unix/sysv/linux/ia64/timer_getoverr.c: New file. + * sysdeps/unix/sysv/linux/ia64/timer_gettime.c: New file. + * sysdeps/unix/sysv/linux/ia64/timer_settime.c: New file. + * sysdeps/unix/sysv/linux/powerpc/powerpc64/Versions: New file. + * sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_create.c: New file. + * sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_delete.c: New file. + * sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_getoverr.c: New file. + * sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_gettime.c: New file. + * sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_settime.c: New file. + * sysdeps/unix/sysv/linux/s390/s390-64/Versions: New file. + * sysdeps/unix/sysv/linux/s390/s390-64/timer_create.c: New file. + * sysdeps/unix/sysv/linux/s390/s390-64/timer_delete.c: New file. + * sysdeps/unix/sysv/linux/s390/s390-64/timer_getoverr.c: New file. + * sysdeps/unix/sysv/linux/s390/s390-64/timer_gettime.c: New file. + * sysdeps/unix/sysv/linux/s390/s390-64/timer_settime.c: New file. + * sysdeps/unix/sysv/linux/x86_64/Versions: New file. + * sysdeps/unix/sysv/linux/x86_64/compat-timer.h: New file. + * sysdeps/unix/sysv/linux/x86_64/timer_create.c: New file. + * sysdeps/unix/sysv/linux/x86_64/timer_delete.c: New file. + * sysdeps/unix/sysv/linux/x86_64/timer_getoverr.c: New file. + * sysdeps/unix/sysv/linux/x86_64/timer_gettime.c: New file. + * sysdeps/unix/sysv/linux/x86_64/timer_settime.c: New file. + + * pthreadP.h: Remove FRAME_LEFT definition. + * cleanup.c (_pthread_cleanup_push): Don't check for reference to + already left frame. Programs which have this problem are not POSIX + compliant. + * cleanup_defer.c (_pthread_cleanup_push_defer): Likewise. + +2003-03-24 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/tst-timer.c: Check return values of the + functions we test. + +2003-03-23 Roland McGrath <roland@redhat.com> + + * tst-tls3.c (do_test) [! HAVE___THREAD]: Don't test anything. + * tst-tls3mod.c: Likewise. + * tst-tls1.c: Likewise. + * tst-tls2.c: Likewise. + + * tst-mutex5.c (do_test): Unlock before destroy, otherwise we invoke + undefined behavior. + + * tst-join5.c (tf1, tf2): Add a cast. + + * Makeconfig (includes): Append -I$(..)nptl to this variable. + + * tst-barrier2.c (do_test) [! _POSIX_THREAD_PROCESS_SHARED]: + Don't test anything. + * tst-cond4.c: Likewise. + * tst-cond6.c: Likewise. + * tst-flock2.c: Likewise. + * tst-mutex4.c: Likewise. + * tst-rwlock4.c: Likewise. + * tst-signal1.c: Likewise. + * tst-spin2.c: Likewise. + * tst-cond11.c [! _POSIX_CLOCK_SELECTION]: Likewise. + + * tst-mutex4.c: Use test-skeleton.c. + * tst-spin2.c: Likewise. + * tst-sysconf.c: Likewise. + * tst-barrier2.c: Likewise. + * tst-cond4.c: Likewise. + * tst-cond6.c: Likewise. + * tst-rwlock4.c: Likewise. + * tst-unload.c: Likewise. + * tst-flock2.c (do_test): Use return instead of exit. + +2003-03-22 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/fork.c (__fork): Add libc_hidden_def. + +2003-03-21 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/ia64/lowlevellock.h + (__lll_mutex_trylock): Use atomic_compare_and_exchange_val_acq + instead of __lll_compare_and_swap. + * sysdeps/unix/sysv/linux/ia64/pthread_once.c (__pthread_once): + Likewise. + Removed definition if __lll_compare_and_swap. + + * cancellation.c: Adjust for new form of compare&exchange macros. + * cleanup_defer.c: Likewise. + * init.c: Likewise. + * libc-cancellation.c: Likewise. + * old_pthread_cond_broadcast.c: Likewise. + * old_pthread_cond_signal.c: Likewise. + * old_pthread_cond_timedwait.c: Likewise. + * old_pthread_cond_wait.c: Likewise. + * pthread_cancel.c: Likewise. + * pthread_create.c: Likewise. + * pthread_detach.c: Likewise. + * pthread_join.c: Likewise. + * pthread_key_delete.c: Likewise. + * pthread_setcancelstate.c: Likewise. + * pthread_setcanceltype.c: Likewise. + * pthread_timedjoin.c: Likewise. + * pthread_tryjoin.c: Likewise. + * sysdeps/pthread/createthread.c: Likewise. + +2003-03-20 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/ia64/lowlevellock.h: Include <atomic.h>. + Remove __lll_add, __lll_dec_if_positive, and __lll_test_and_set + definitions. Replace uses with calls to atomic_* functions. + * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h: Likewise. + * sysdeps/unix/sysv/linux/lowlevellock.c: Replace __lll_add and + __lll_test_and_set calls with atomic_exchange_and_add and + atomic_exchange calls respectively. + * sysdeps/unix/sysv/linux/sem_post.c: Likewise. + * sysdeps/unix/sysv/linux/sem_timedwait.c: Likewise. + * sysdeps/unix/sysv/linux/sem_trywait.c: Likewise. + * sysdeps/unix/sysv/linux/sem_wait.c: Likewise. + * sysdeps/unix/sysv/linux/ia64/pthread_once.c: Likewise. + * sysdeps/unix/sysv/linux/ia64/sem_port.c: Likewise. + * sysdeps/unix/sysv/linux/powerpc/pthread_once.c: Likewise. + + * allocatestack.c (allocate_stack): Assume atomic_exchange_and_add + returns the old value. + +2003-03-20 Martin Schwidefsky <sky@mschwid3.boeblingen.de.ibm.com> + + * sysdeps/s390/pthread_spin_lock.c (pthread_spin_lock): Use type + int for variable OLDVAL and correct inline assembler contraint. + * sysdeps/s390/pthread_spin_trylock.c (pthread_spin_trylock): Use + type int for variable OLD. + + * sysdeps/s390/tls.h (TLS_MULTIPLE_THREADS_IN_TCB): Define it + only for s390-32. + * sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h + (SINGLE_THREAD_P): Use global variable __local_multiple_threads + instead of multiple_threads field in the TCB. + +2003-03-19 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/i386/i686/bits/atomic.h: Removed. + * sysdeps/i386/i586/bits/atomic.h: Removed. + * sysdeps/i386/i486/bits/atomic.h: Removed. Moved to glibc. + * sysdeps/x86_64/bits/atomic.h: Removed. Moved to glibc. + * sysdeps/s390/bits/atomic.h: Removed. Moved to glibc. + * sysdeps/sh/bits/atomic.h: Removed. Moved to glibc. + * sysdeps/ia64/bits/atomic.h: Removed. Moved to glibc. + * sysdeps/powerpc/bits/atomic.h: Removed. Moved to glibc. + * atomic.h: Removed. Moved to glibc. + + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: Add + support for clock selection. + + * sysdeps/pthread/pthread_cond_broadcast.c: Release lock before + signalling waiters. + +2003-03-18 Roland McGrath <roland@redhat.com> + + * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h (__lll_test_and_set): + Add __lll_rel_instr first. Add memory clobber. + (lll_mutex_unlock): Use __lll_test_and_set. + From Paul Mackerras <paulus@samba.org>. + + * sysdeps/powerpc/tls.h (TLS_MULTIPLE_THREADS_IN_TCB): Define + unconditionally. + * sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h + (SINGLE_THREAD_P): Add `header.' prefix. + From Paul Mackerras <paulus@samba.org>. + + * Versions (libpthread: GLIBC_2.3.2): Move pthread_tryjoin_np and + pthread_timedjoin_np to ... + (libpthread: GLIBC_2.3.3): ... here. + (libpthread: GLIBC_2.2): Move pthread_barrierattr_getpshared there too. + + * sysdeps/pthread/pthread_cond_timedwait.c (__pthread_cond_timedwait): + Avoid shadowing VAL variable. + + * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h (__lll_test_and_set): + New macro. + +2003-03-18 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add tst-cond11. + * tst-cond11.c: New file. + + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Reorder + struct passed to cleanup handler to eliminate one more + instruction. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Likewise. + + * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h + (pthrad_cond_t): Replace __unused field with __clock. + + * sysdeps/pthread/pthread_cond_wait.c: Release condvar lock before + waken all waiters in cleanup handler. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Likewise. + + * pthread_condattr_getclock.c: New file. + * pthread_condattr_setclock.c: New file. + * sysdeps/pthread/pthread.h: Declare these new functions. + * Versions [GLIBC_2.3.3] (libpthread): Add the new functions. + * Makefile (libpthread-routines): Add the new functions. + * sysdeps/unix/sysv/linux/internaltypes.h (struct pthread_condattr): + Renamed field to value. Document use of the bits. + * pthread_condattr_getpshared.c: Adjust for struct pthread_condattr + change. + * pthread_condattr_setpshared.c: Likewise. + * pthread_cond_init.c (__pthread_cond_init): Initialized __clock field. + * sysdeps/unix/sysv/linux/lowlevelcond.sym: Add cond_clock symbol. + * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h (pthread_cond_t): + Add __clock field. + * sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: + Implement clock selection. + * sysdeps/pthread/pthread_cond_timedwait.c: Likewise. + * pthread-errnos.sym: Add ENOSYS. + * sysdeps/unix/sysv/linux/bits/posix_opt.h: Define + _POSIX_CLOCK_SELECTION. + * sysdeps/unix/sysv/linux/i386/bits/posix_opt.h: Likewise. + + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: Remove + invalid .size directive. + +2003-03-17 Roland McGrath <roland@redhat.com> + + * sysdeps/unix/sysv/linux/lowlevellock.c (__lll_lock_wait): + Formatting tweaks. + +2003-03-17 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/ia64/pthread_once.c: Use __builtin_expect. + Use __lll_add instead of spelling it out. Use protected symbol names. + * sysdeps/unix/sysv/linux/ia64/sem_post.c: Use __builtin_expect. + Use __lll_add. + * sysdeps/unix/sysv/linux/ia64/lowlevellock.h (__lll_compare_and_swap): + Renamed from lll_compare_and_swap. Use new name where necessary. + (__lll_add): Defined. + (__lll_dec_if_positive): Defined. + (__lll_test_and_set): Defined. + * sysdeps/ia64/pthread_spin_init.c: Removed. + * sysdeps/unix/sysv/linux/ia64/lowlevelmutex.c: Removed. + * sysdeps/unix/sysv/linux/ia64/sem_trywait.c: Removed. + * sysdeps/unix/sysv/linux/ia64/sem_wait.c: Removed. + * sysdeps/unix/sysv/linux/ia64/lowlevellock.c: Removed. + * sysdeps/unix/sysv/linux/ia64/libc-lowlevellock.c: Removed. + * sysdeps/unix/sysv/linux/ia64/libc-lowlevelmutex.c: Removed. + * sysdeps/unix/sysv/linux/ia64/sem_timedwait.c: Removed. + * sysdeps/ia64/bits/atomic.h: Add __builtin_expect where appropriate. + * sysdeps/ia64/pthread_spin_unlock.c (pthread_spin_unlock): Use + __sync_lock_release_si. + Patch by Jakub Jelinek. + + * sysdeps/unix/sysv/linux/lowlevellock.c (__lll_timedlock_wait): + Fix timeout handling. + (__lll_timedwait_tid): Likewise. + (lll_unlock_wake_cb): Wake up other waiters if necessary. + Patch by Jakub Jelinek. + + * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h: Pretty printing. + +2003-03-17 Roland McGrath <roland@redhat.com> + + PowerPC port contributed by Paul Mackerras <paulus@samba.org>. + * sysdeps/pthread/pthread_spin_init.c: New file. + * sysdeps/pthread/pthread_spin_unlock.c: New file. + * sysdeps/powerpc/Makefile: New file. + * sysdeps/powerpc/pthread_spin_lock.c: New file. + * sysdeps/powerpc/pthread_spin_trylock.c: New file. + * sysdeps/powerpc/pthreaddef.h: New file. + * sysdeps/powerpc/tcb-offsets.sym: New file. + * sysdeps/powerpc/td_ta_map_lwp2thr.c: New file. + * sysdeps/powerpc/tls.h: New file. + * sysdeps/powerpc/bits/atomic.h: New file. + * sysdeps/unix/sysv/linux/libc-lowlevelmutex.c: New file. + * sysdeps/unix/sysv/linux/libc-lowlevellock.c: New file. + * sysdeps/unix/sysv/linux/lowlevellock.c: New file. + + * sysdeps/unix/sysv/linux/lowlevelmutex.c: New file. + * sysdeps/unix/sysv/linux/sem_post.c: New file. + * sysdeps/unix/sysv/linux/sem_timedwait.c: New file. + * sysdeps/unix/sysv/linux/sem_trywait.c: New file. + * sysdeps/unix/sysv/linux/sem_wait.c: New file. + * sysdeps/unix/sysv/linux/powerpc/Makefile: New file. + * sysdeps/unix/sysv/linux/powerpc/createthread.c: New file. + * sysdeps/unix/sysv/linux/powerpc/fork.c: New file. + * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h: New file. + * sysdeps/unix/sysv/linux/powerpc/pt-vfork.S: New file. + * sysdeps/unix/sysv/linux/powerpc/pthread_once.c: New file. + * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h: New file. + * sysdeps/unix/sysv/linux/powerpc/bits/semaphore.h: New file. + * sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h: New file. + * sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h: New file. + + * sysdeps/unix/sysv/linux/ia64/lowlevellock.c: Use __gettimeofday, + not gettimeofday. + * sysdeps/unix/sysv/linux/ia64/lowlevelmutex.c: Likewise. + * sysdeps/unix/sysv/linux/ia64/sem_timedwait.c: Likewise. + * sysdeps/unix/sysv/linux/s390/lowlevellock.c: Likewise. + * sysdeps/unix/sysv/linux/s390/lowlevelmutex.c: Likewise. + * sysdeps/unix/sysv/linux/s390/sem_timedwait.c: Likewise. + +2003-03-17 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/pthread_cond_wait.c: Correct exit criteria. + * sysdeps/pthread/pthread_cond_timedwait.c: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Likewise. + Patch by Ewald Snel <ewald@rambo.its.tudelft.nl>. + +2003-03-16 Roland McGrath <roland@redhat.com> + + * tst-fork4.c: Include <string.h>. + * tst-signal2.c: Likewise. + * tst-mutex5.c (do_test): exit -> return. + * tst-mutex2.c: Include <stdlib.h>. + +2003-03-16 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/i486/lowlevelmutex.S + (__lll_mutex_timedlock_wait): Correct expected value after + spurious wakeup. Otherwise we would never wait again. + + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h: Work around red + zone versus inline asm stupidity. Use correct instructions. + + * tst-rwlock6.c: Add some more status output. + +2003-03-15 Roland McGrath <roland@redhat.com> + + * sysdeps/pthread/configure.in: New file. + * sysdeps/pthread/configure: New file (generated). + +2003-03-15 Ulrich Drepper <drepper@redhat.com> + + * allocatestack.c (allocate_stack): Store the exact stack size of + user allocated stacks. + +2003-03-15 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h + (SINGLE_THREAD): Use `header' prefix instead of `header.data'. + * sysdeps/sh/tcb-offsets.sym (MULTIPLE_THREADS_OFFSET): Likewise. + * sysdeps/sh/tls.h (TLS_MULTIPLE_THREADS_IN_TCB): Define. + * sysdeps/unix/sysv/linux/ia64/sysdep-cancel.h (SINGLE_THREAD_P): + Use `header.' prefix. + * sysdeps/ia64/tcb-offsets.sym (MULTIPLE_THREADS_OFFSET): Likewise. + +2003-03-15 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/x86_64/pthreaddef.h (CURRENT_STACK_FRAME): Don't use + __builtin_frame_address, use stack pointer. + + * sysdeps/unix/sysv/linux/jmp-unwind.c: Use CURRENT_STACK_FRAME + instead of __builtin_frame_pointer. + +2003-03-14 Ulrich Drepper <drepper@redhat.com> + + * tst-basic1.c (do_test): Add cast to avoid warning. + * tst-basic2.c (do_test): Likewise. + + * sysdeps/unix/sysv/linux/x86_64/pthread_once.S: Use correct + amount of stack correction. + + * tst-fork4.c: Use test-skeleton.c. + +2003-03-14 Roland McGrath <roland@redhat.com> + + * init.c: Fix typo "#eli" for "#else". + +2003-03-14 Steven Munroe <sjmunroe@us.ibm.com> + + * allocatestack.c (__stack_user): Use hidden_data_def. + * pthread_create.c (__pthread_keys): Likewise. + + * init.c [__powerpc__] (__NR_set_tid_address): Define it. + +2003-03-14 Roland McGrath <roland@redhat.com> + + * tst-fork4.c: New file. + * Makefile (tests): Add it. + + * descr.h (struct pthread): Move the union out of [!TLS_DTV_AT_TP], so + we always define the padding space. + [!TLS_DTV_AT_TP]: Give tcbhead_t field a name, `header', since GCC + stopped supporting its own extensions fully. + [TLS_MULTIPLE_THREADS_IN_TCB]: Put `multiple_threads' inside a wrapper + struct also called `header', so `header.multiple_threads' is the field + name to use on all machines. + * allocatestack.c (allocate_stack): Use `header.' prefix. + * sysdeps/pthread/createthread.c (create_thread): Likewise. + * pthread_create.c (__pthread_create_2_1): Likewise. + * sysdeps/i386/tls.h (INSTALL_NEW_DTV, THREAD_DTV): Likewise. + (THREAD_SELF): Likewise. + * sysdeps/x86_64/tls.h: Likewise. + * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h + (SINGLE_THREAD_P): Likewise. + * sysdeps/unix/sysv/linux/sh/sysdep-cancel.h + (SINGLE_THREAD_P): Likewise. + * sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h + (SINGLE_THREAD_P): Likewise. + + * sysdeps/s390/td_ta_map_lwp2thr.c (td_ta_map_lwp2thr): Use REGS[18] + value directly. + +2003-03-14 Ulrich Drepper <drepper@redhat.com> + + * pthread_create.c (start_thread): Use CALL_THREAD_FCT if defined. + * sysdeps/i386/tls.h: Define CALL_THREAD_FCT. + + * pthread_create.c (start_thread): setjmp is expected to return 0. + + * sysdeps/x86_64/tls.h (THREAD_GETMEM): Mark asms volatile. + (THREAD_GETMEM_NC): Likewise. + +2003-03-13 Ulrich Drepper <drepper@redhat.com> + + * allocatestack.c (allocate_stack): If MULTI_PAGE_ALIASING is defined + and the size of the stack which must be allocated is a multiple, + allocate one more page. + * sysdeps/i386/i686/Makefile: Don't define COLORING_INCREMENT, but + MULTI_PAGE_ALIASING. + +2003-03-13 Roland McGrath <roland@redhat.com> + + * pthread_create.c (start_thread): Set EXITING_BIT after the + event-reporting (and destructors), not before. + +2003-03-13 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/ia64/lowlevellock.h (lll_futex_timed_wait, + lll_futex_wake): Declare register variables as long int instead of + unsigned long int. Patch by Ian Wienand <ianw@gelato.unsw.edu.au>. + Make syscall arguments clobbered by the syscall. + (lll_futex_wait): Define using lll_futex_timed_wait. + + * sysdeps/ia64/td_ta_map_lwp2thr.c (td_ta_map_lwp2thr): Cast regs[13] + to void *. + + * sysdeps/unix/sysv/linux/fork.c (__libc_fork): Only declare and set + PPID if [! NDEBUG]. + + * allocatestack.c (nptl_ncreated): Only declare if + COLORING_INCREMENT != 0. + + * pthreadP.h (__pthread_enable_asynccancel_2): New prototype. + (__libc_enable_asynccancel_2): Remove prototype. + + * sysdeps/unix/sysv/linux/ia64/fork.c (ARCH_FORK): Swap ptid and + ctid to match kernel. + +2003-03-12 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/Makefile (sysdep_routines): Add + libc_multiple_threads. + * sysdeps/unix/sysv/linux/libc_pthread_init.c: Move definition of + __libc_multiple_threads to... + * sysdeps/unix/sysv/linux/libc_multiple_threads.c: ...here. New file. + + * sysdeps/unix/sysv/linux/x86_64/sem_post.S: Remove unnecessary + versioning. + * sysdeps/unix/sysv/linux/x86_64/sem_trywait.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/sem_wait.S: Likewise. + + * sysdeps/unix/sysv/linux/x86_64/pthread_once.S + (__pthread_once_internal): Define. + + * sysdeps/unix/sysv/linux/i386/i486/sem_post.S: Use shlib-compat.h + macros instead of .symver directly. + * sysdeps/unix/sysv/linux/i386/i486/sem_trywait.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/sem_wait.S: Likewise. + + * sysdeps/x86_64/tls.h [__ASSEMBLER__]: Include tcb-offsets.h. + * sysdeps/x86_64/tcb-offsets.sym: New file. + * sysdeps/x86_64/Makefile: New file. + + * sysdeps/i386/tcb-offsets.sym: Add SELF. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_rdlock.S: Use SELF + to access own pthread_t in TCB. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedrdlock.S: + Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedwrlock.S: + Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_wrlock.S: Likewise. + +2003-03-12 Roland McGrath <roland@redhat.com> + + * pthread-errnos.sym: New file. + * Makefile (gen-as-const-headers): New variable, list that file. + * sysdeps/unix/sysv/linux/i386/i486/sem_wait.S: Include generated + header <pthread-errnos.h> instead of defining errno values here. + * sysdeps/unix/sysv/linux/i386/i486/sem_trywait.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/sem_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/sem_post.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_wrlock.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedwrlock.S: + Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedrdlock.S: + Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_rdlock.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/lowlevelmutex.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/sem_wait.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/sem_trywait.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/sem_post.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/lowlevelmutex.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.S: Likewise. + * sysdeps/unix/sysv/linux/sh/sem_trywait.S: Likewise. + * sysdeps/unix/sysv/linux/sh/sem_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/sh/sem_post.S: Likewise. + * sysdeps/unix/sysv/linux/sh/sem_wait.S: Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_wrlock.S: Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedwrlock.S: Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedrdlock.S: Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_cond_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_rdlock.S: Likewise. + * sysdeps/unix/sysv/linux/sh/lowlevellock.S: Likewise. + * sysdeps/unix/sysv/linux/sh/lowlevelmutex.S: Likewise. + * sysdeps/i386/i486/pthread_spin_trylock.S: Likewise. + * sysdeps/x86_64/pthread_spin_trylock.S: Likewise. + * sysdeps/sh/pthread_spin_trylock.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_rdlock.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_wrlock.S: Likewise. + + * sysdeps/unix/sysv/linux/fork.c: Add an assert to check that + CLONE_CHILD_SETTID worked. + +2003-03-12 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedrdlock.S: New + file. + * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedwrlock.S: New + file. + + * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h + (pthread_cond_t): Add padding. + + * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_rdlock.S: New file. + * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_wrlock.S: New file. + * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_unlock.S: New file. + + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedwrlock.S + (__pthread_rwlock_timedwrlock): Add missing opcode suffix. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedrdlock.S + (__pthread_rwlock_timedrdlock): Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_wrlock.S + (__pthread_rwlock_wrlock): Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_rdlock.S + (__pthread_rwlock_rdlock): Likewise. + + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: New file. + + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Return + result of lock re-get if it fails. + +2003-03-11 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.S: Fix asm syntax. + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h: Likewise. + * sysdeps/unix/sysv/linux/x86_64/lowlevelmutex.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_signal.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_once.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/sem_post.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/sem_trywait.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/sem_wait.S: Likewise. + + * sysdeps/x86_64/tls.h (THREAD_SELF, THREAD_GETMEM, THREAD_GETMEM_NC, + THREAD_SETMEM, THREAD_SETMEM_NC): Correct asm syntax. + + * allocatestack.c [! TLS_MULTIPLE_THREADS_IN_TCB] (allocate_stack): + Initialize *__libc_multiple_threads_ptr not __libc_multiple_threads. + * sysdeps/pthread/createthread.c [! TLS_MULTIPLE_THREADS_IN_TCB] + (create_thread): Likewise. + Define __pthread_multiple_threads and __libc_multiple_threads_ptr. + * init.c (__pthread_initialize_minimal_internal): Initialize + __libc_multiple_threads_ptr if necessary. + * pthreadP.h: Adjust prototype for __libc_pthread_init. Declare + __pthread_multiple_threads and __libc_multiple_threads_ptr. + * sysdeps/unix/sysv/linux/libc_pthread_init.c: Define + __libc_multiple_threads. + (__libc_pthread_init): Return pointer to __libc_pthread_init if + necessary. + + * sysdeps/i386/tls.h (THREAD_SETMEM): Fix one-byte variant. + (THREAD_SETMEM_NC): Likewise. + + * sysdeps/x86_64/pthread_spin_trylock.c: Removed. + * sysdeps/x86_64/pthread_spin_trylock.S: New file. + * sysdeps/x86_64/pthread_spin_unlock.c: Removed. + * sysdeps/x86_64/pthread_spin_unlock.S: New file. + + * sysdeps/i386/i486/pthread_spin_trylock.S (pthread_spin_trylock): + Eliminate one entire instruction. + + * cancellation.c (__pthread_enable_asynccancel_2): New function. + * pthreadP.h: Declare __pthread_enable_asynccancel_2. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S + (__pthread_cond_timedwait): Use __pthread_enable_asynccancel_2 + instead of __pthread_enable_asynccancel. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S + (__pthread_cond_wait): Likewise. + * sysdeps/pthread/pthread_cond_timedwait.c + (__pthread_cond_timedwait): Likewise. + * sysdeps/pthread/pthread_cond_wait.c (__pthread_cond_wait): Likewise. + + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S + (__condvar_cleanup): Wake up all waiters in case we got signaled + after being woken up but before disabling asynchronous + cancellation. + * sysdeps/pthread/pthread_cond_wait.c (__condvar_cleanup): Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S + (__condvar_cleanup): Likewise. + + * init.c (__NR_set_tid_address): If already defined, don't redefine. + Make it an error if architecture has no #if case. Add x86-64. + + * sysdeps/unix/sysv/linux/x86_64/Makefile: Add flags for + pt-initfini.s generation. + + * sysdeps/x86_64/tls.h: Include <asm/prctl.h>. + (TLS_INIT_TP): Fix typo. + +2003-03-11 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/ia64/bits/atomic.h (atomic_exchange_and_add): Swap 2nd and + 3rd argument of __arch_compare_and_exchange_{32,64}_val_acq. + + * sysdeps/unix/sysv/linux/ia64/sem_post.c: Include semaphore.h. + * sysdeps/unix/sysv/linux/ia64/sem_timedwait.c: Likewise. + * sysdeps/unix/sysv/linux/ia64/sem_trywait.c: Likewise. + * sysdeps/unix/sysv/linux/ia64/sem_wait.c: Likewise. + * sysdeps/unix/sysv/linux/s390/sem_post.c: Likewise. + * sysdeps/unix/sysv/linux/s390/sem_timedwait.c: Likewise. + * sysdeps/unix/sysv/linux/s390/sem_trywait.c: Likewise. + * sysdeps/unix/sysv/linux/s390/sem_wait.c: Likewise. + +2003-03-11 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/pthread_cond_timedwait.c + (__pthread_cond_timedwait): Return the result of the final + locking. If it succeeds, the regular function return value. + + * sysdeps/pthread/pthread_cond_wait.c (__pthread_cond_wait): + Return result of the final locking. + * version.c (__nptl_main): Work around problems with the strange + INTERNAL_SYSCALL macro on ppc32. + * init.c (__pthread_initialize_minimal_internal): Unblock + SIGCANCEL in case the parent blocked it. + Reported by Paul Mackerras <paulus@samba.org>. + + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S: New file. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_signal.S: New file. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S: New file. + +2003-03-11 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/pthread/pthread_cond_timedwait.c + (__pthread_cond_timedwait): Unlock and fail if + __pthread_mutex_unlock_internal failed. + + * sysdeps/pthread/createthread.c (ARCH_CLONE): Define if not defined. + (create_thread): Only assert PD->tcb != NULL under [TLS_TCB_AT_TP]. + Use ARCH_CLONE. + * allocatestack.c (ALLOCATE_STACK_PARMS): New macro. + [NEED_SEPARATE_REGISTER_STACK] (STACK_VARIABLES, + STACK_VARIABLES_ARGS, STACK_VARIABLES_PARMS, ALLOCATE_STACK_PARMS, + ALLOCATE_STACK): New macros. + (TLS_TPADJ): New macro. + (get_cached_stack, queue_stack, __deallocate_stack): Use TLS_TPADJ. + (allocate_stack): Handle TLS_DTV_AT_TP and + NEED_SEPARATE_REGISTER_STACK. Use TLS_TPADJ. + * pthread_create.c (__pthread_create_2_1) [! TLS_TCB_AT_TP]: + Don't set PD->self. + * init.c [__ia64__] (__NR_set_tid_address): Define. + + * sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h: New file. + * sysdeps/unix/sysv/linux/ia64/bits/semaphore.h: New file. + * sysdeps/unix/sysv/linux/ia64/fork.c: New file. + * sysdeps/unix/sysv/linux/ia64/createthread.c: New file. + * sysdeps/unix/sysv/linux/ia64/libc-lowlevellock.c: New file. + * sysdeps/unix/sysv/linux/ia64/libc-lowlevelmutex.c: New file. + * sysdeps/unix/sysv/linux/ia64/lowlevellock.c: New file. + * sysdeps/unix/sysv/linux/ia64/lowlevellock.h: New file. + * sysdeps/unix/sysv/linux/ia64/lowlevelmutex.c: New file. + * sysdeps/unix/sysv/linux/ia64/pt-initfini.c: New file. + * sysdeps/unix/sysv/linux/ia64/pt-vfork.S: New file. + * sysdeps/unix/sysv/linux/ia64/pthread_once.c: New file. + * sysdeps/unix/sysv/linux/ia64/sem_post.c: New file. + * sysdeps/unix/sysv/linux/ia64/sem_timedwait.c: New file. + * sysdeps/unix/sysv/linux/ia64/sem_trywait.c: New file. + * sysdeps/unix/sysv/linux/ia64/sem_wait.c: New file. + * sysdeps/unix/sysv/linux/ia64/sysdep-cancel.h: New file. + * sysdeps/ia64/bits/atomic.h: New file. + * sysdeps/ia64/Makefile: New file. + * sysdeps/ia64/pthread_spin_init.c: New file. + * sysdeps/ia64/pthread_spin_lock.c: New file. + * sysdeps/ia64/pthread_spin_trylock.c: New file. + * sysdeps/ia64/pthread_spin_unlock.c: New file. + * sysdeps/ia64/pthreaddef.h: New file. + * sysdeps/ia64/tcb-offsets.sym: New file. + * sysdeps/ia64/td_ta_map_lwp2thr.c: New file. + * sysdeps/ia64/tls.h: New file. + + * sysdeps/s390/pthreaddef.h (__exit_thread_inline): Pass 1 argument + to syscall instead of no arguments. + +2003-03-10 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/x86_64/sem_post.S: New file. + * sysdeps/unix/sysv/linux/x86_64/sem_trywait.S: New file. + * sysdeps/unix/sysv/linux/x86_64/sem_wait.S: New file. + * sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S: New file. + + * sysdeps/unix/sysv/linux/i386/i486/sem_post.S: Fix error value in + unused code. + + * sysdeps/unix/sysv/linux/x86_64/pthread_barrier_wait.S: New file + + * sysdeps/unix/sysv/linux/Makefile (gen-as-const-headers): Add + lowlevelbarrier.sym. + * sysdeps/unix/sysv/linux/lowlevelbarrier.sym: New file. + * sysdeps/unix/sysv/linux/i386/i486/pthread_barrier_wait.S: + Include lowlevelbarrier.h and don't define offsets locally. + * sysdeps/unix/sysv/linux/sh/pthread_barrier_wait.S: Likewise. + + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h + (__lll_mutex_lock_wait): Reverse order of first two parameters. + (__lll_mutex_timedlock_wait): Likewise. + (lll_mutex_lock): Adjust asm for that. + (lll_mutex_timedlock): Likewise. Mark cx, cc, r10 as clobbered. + (lll_lock): Adjust asm for operand order change. + * sysdeps/unix/sysv/linux/x86_64/lowlevelmutex.S: New file. + * sysdeps/unix/sysv/linux/x86_64/libc-lowlevelmutex.S: New file. + + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h (__lll_lock_wait): + Reverse order of parameters. + (__lll_timedwait_tid): Remove regparms attribute. + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.S: New file. + * sysdeps/unix/sysv/linux/x86_64/libc-lowlevellock.S: New file. + + * sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S + (__lll_timedwait_tid): Remove one unnecessary instruction. + + * sysdeps/unix/sysv/linux/sh/lowlevelmutex.S: Define + __lll_mutex_timedlock_wait only for NOT_IN_libc. + * sysdeps/unix/sysv/linux/sh/libc-lowlevelmutex.S: Include + lowlevelmutex.S. + + * sysdeps/unix/sysv/linux/sh/lowlevellock.S: Define + lll_unlock_wake_cb, __lll_wait_tid, and __lll_timedwait_tid only + for NOT_IN_libc. + * sysdeps/unix/sysv/linux/sh/libc-lowlevellock.S: Include + lowlevellock.S. + + * sysdeps/unix/sysv/linux/i386/i486/lowlevelmutex.S: Don't define + LOCK is already defined. Don't define __lll_mutex_timedlock_wait + for libc.so. + * sysdeps/unix/sysv/linux/i386/i486/libc-lowlevelmutex.S: Only + define LOCK here (if UP is not defined). The actual code is in + lowlevelmutex.S. + + * sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S: Don't define + LOCK is already defined. Don't define lll_unlock_wake_cb and + __lll_timedwait_tid for libc.so. + * sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S: Only + define LOCK here (if UP is not defined). The actual code is in + lowlevellock.S. + + * sysdeps/unix/sysv/linux/i386/lowlevelsem.h: Not needed anymore. + * sysdeps/unix/sysv/linux/s390/lowlevelsem.h: Likewise. + * sysdeps/unix/sysv/linux/s390/sem_post.c: Include lowlevellock.h + instead of lowlevelsem.h. + * sysdeps/unix/sysv/linux/s390/sem_timedwait.c: Likewise. + * sysdeps/unix/sysv/linux/s390/sem_trywait.c: Likewise. + * sysdeps/unix/sysv/linux/s390/sem_wait.c: Likewise. + + * sysdeps/unix/sysv/linux/Makefile (gen-as-const-headers): Add + lowlevelrwlock.sym. + * sysdeps/unix/sysv/linux/lowlevelrwlock.sym: New file. + * sysdeps/unix/sysv/linux/i386/lowlevelrwlock.h: Removed. + * sysdeps/unix/sysv/linux/sh/lowlevelrwlock.h: Removed. + + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h (lll_trylock): Fix + register loading. + * sysdeps/unix/sysv/linux/i386/lowlevellock.h (lll_trylock): Undo + last changed. D'oh. + + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h: New file. + + * sysdeps/unix/sysv/linux/i386/lowlevellock.h: Remove declaration + of __libc_locking_needed. + (lll_trylock): Initialize %eax to zero. + + * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: Update + pthread_cond_t definition. + +2003-03-10 Roland McGrath <roland@redhat.com> + + * sysdeps/unix/sysv/linux/lowlevelcond.sym: New file. + * sysdeps/unix/sysv/linux/Makefile (gen-as-const-headers): Add it. + * sysdeps/unix/sysv/linux/sh/lowlevelcond.h: File removed. + * sysdeps/unix/sysv/linux/i386/lowlevelcond.h: Likewise. + * sysdeps/unix/sysv/linux/x86_64/lowlevelcond.h: Likewise. + + * allocatestack.c (allocate_stack) [!TLS_MULTIPLE_THREADS_IN_TCB]: + Instead of setting PD->multiple_threads, set globals + __pthread_multiple_threads and __libc_multiple_threads. + * sysdeps/pthread/createthread.c (create_thread): Likewise. + * sysdeps/i386/tls.h (TLS_MULTIPLE_THREADS_IN_TCB): Define it. + * sysdeps/s390/tls.h (TLS_MULTIPLE_THREADS_IN_TCB): Likewise. + + * descr.h (struct pthread): Conditionalize first member on + [!TLS_DTV_AT_TP]. Replace the `header' member with an anonymous union + containing an anonymous tcbhead_t. Move `list' member out. + [TLS_MULTIPLE_THREADS_IN_TCB]: Define a `multiple_threads' member. + * allocatestack.c: Remove use of `header.data.' prefix. + * pthread_create.c: Likewise. + * init.c (__pthread_initialize_minimal_internal): Likewise. + * sysdeps/pthread/createthread.c (create_thread): Likewise. + * sysdeps/i386/tls.h (INSTALL_DTV): Add parens. + (THREAD_SELF, THREAD_DTV, INSTALL_NEW_DTV): No `header.data.' prefix. + * sysdeps/x86_64/tls.h: Likewise. + * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h + (SINGLE_THREAD_P): Likewise. + * sysdeps/unix/sysv/linux/sh/sysdep-cancel.h + (SINGLE_THREAD_P): Likewise. + * sysdeps/i386/tls.h (tcbhead_t): Remove `list' member. + * sysdeps/s390/tls.h (tcbhead_t): Likewise. + +2003-03-09 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/x86_64/lowlevelcond.h: New file. + + * sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h: New file. + * sysdeps/unix/sysv/linux/x86_64/fork.c: New file. + + * sysdeps/unix/sysv/linux/x86_64/pthread_once.S: Fix many + leftovers from the ia32 code. + + * sysdeps/unix/sysv/linux/i386/pthread_once.S: Remove unneccessary + memory load. + (clear_once_control): Don't load %esi. + + * sysdeps/x86_64/tls.h: Remove all traces of segment descriptor + handling. + + * sysdeps/unix/sysv/linux/x86_64/fork.c: New file. + + * sysdeps/unix/sysv/linux/s390/createthread.c: Moved to... + * sysdeps/unix/sysv/linux/createthread.c: ...here. + + * Makefile (tests): Add tst-cond10. + * tst-cond10.c: New file. + +2003-03-08 Ulrich Drepper <drepper@redhat.com> + + * tst-tls2.c (do_test): Add TEMP_FAILURE_RETRY around sem_wait call. + * tst-signal3.c (do_test): Likewise. + * tst-sem5.c (do_test): Likewise. + * tst-kill6.c (do_test): Likewise. + * tst-tls3.c (do_test): Likewise. Include <errno.h>. + + * sysdeps/unix/sysv/linux/i386/lowlevellock.h: Use add/sub instead + of inc/dec. + * sysdeps/unix/sysv/linux/i386/lowlevelsem.h: Likewise. + * sysdeps/unix/sysv/linux/i386/pthread_once.S: Likewise + * sysdeps/unix/sysv/linux/i386/i486/sem_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/sem_post.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_wrlock.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_unlock.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedwrlock.S: + Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedrdlock.S: + Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_rdlock.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_signal.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_barrier_wait.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/lowlevelmutex.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S: Likewise. + + * allocatestack.c (allocate_stack): If mprotect() fails free the + TLS memory. + +2003-03-07 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/i386/i486/bits/atomic.h: Fix a few unused definitions. + + * sysdeps/unix/sysv/linux/i386/lowlevellock.h: Remove all trace of + lll_wake_tid. This was used only to work around kernel limits in + the early days. + * sysdeps/unix/sysv/linux/s390/lowlevellock.h: Likewise. + * sysdeps/unix/sysv/linux/sh/libc-lowlevellock.S: Likewise. + * sysdeps/unix/sysv/linux/sh/lowlevellock.S: Likewise. + * sysdeps/unix/sysv/linux/sh/lowlevellock.h: Likewise. + + * init.c (__static_tls_align_m1): Renamed from __static_tls_align. + (__pthread_initialize_minimal_internal): Change initialization of + __static_tls_align_m1 appropriately. + * pthreadP.h (__static_tls_align_m1): Renamed from + __static_tls_align. + * allocatestack.c (allocate_stack): Use __static_tls_align_m1 + instead of __static_tls_align-1. + +2003-03-04 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/x86_64/Makefile: New file. + + * pthread_create.c: Define __pthread_keys using nocommon + attribute, not by placing it explicitly in bss. + Remove DEFINE_DEALLOC definition. Not needed anymore. + + * allocatestack.c: Define ARCH_MAP_FLAGS if not already defined. + Use it in mmap call to allocate stacks. + + * sysdeps/pthread/createthread.c (create_thread): Fix comment. + + * pthread_create.c (start_thread): Use THREAD_SETMEM to store + result of the thread function. + +2003-03-03 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/s390/dl-sysdep.h: Removed. The generic + version is just fine. + + * sysdeps/unix/sysv/linux/libc_pthread_init.c + (__pthread_child_handler): Renamed from pthread_child_handler, + exported, and marked hidden. Change all users. + * sysdeps/unix/sysv/linux/register-atfork.c (free_mem): Do not + free __pthread_child_handler from child list. + +2003-03-03 Martin Schwidefsky <schwidefsky@de.ibm.com> + + * atomic.h (atomic_exchange_and_add): Return newval, not oldval. + + * sysdeps/pthread/pthread_cond_timedwait.c (__pthread_cond_timedwait): + Fix handling of cancellation and failing pthread_mutex_unlock call. + * sysdeps/pthread/pthread_cond_wait.c (__condvar_cleanup): Likewise. + (__pthread_cond_wait): Likewise. + + * sysdeps/pthread/pthread_rwlock_timedrdlock.c + (pthread_rwlock_timedrdlock): Fix clobber of result variable by + lll_futex_timed_wait call. + * sysdeps/pthread/pthread_rwlock_timedwrlock.c + (pthread_rwlock_timedwrlock): Likewise. + + * sysdeps/unix/sysv/linux/s390/libc-lowlevellock.c (___lll_lock): + Don't define lll_unlock_wake_cb and ___lll_timedwait_tid in libc.so. + * sysdeps/unix/sysv/linux/s390/lowlevellock.c: Remove XXX comments. + + * sysdeps/unix/sysv/linux/s390/sem_post.c (__new_sem_post): Fix + check of lll_futex_wake return value. + +2003-03-03 Roland McGrath <roland@redhat.com> + + * forward.c: Fix typo in __pthread_attr_init_2_0 compat_symbol decl. + + * sysdeps/pthread/pthread-functions.h (struct pthread_functions): + Argument to ptr___pthread_cleanup_upto is __jmp_buf, not jmp_buf. + * sysdeps/unix/sysv/linux/jmp-unwind.c: Likewise. + +2003-03-02 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/timer_create.c (timer_create): Return correct + error for CPU clocks. + + * sysdeps/unix/sysv/linux/bits/posix_opt.h: Define + _POSIX_MONOTONIC_CLOCK. + * sysdeps/unix/sysv/linux/i386/bits/posix_opt.h: Likewise. + + * tst-cancel4.c (tf_sleep): Lower sleep time a bit to not upset + recent kernels. + +2003-03-01 Ulrich Drepper <drepper@redhat.com> + + * descr.h (struct pthread): Move cleanup field to the front. + +2003-03-01 Roland McGrath <roland@redhat.com> + + * sem_open.c (sem_open): Braino fix. + +2003-03-01 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/i386/tcb-offsets.sym: Add CLEANUP and CLEANUP_PREV. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Inline + __pthread_cleanup_pop functionality. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Likewise. + + * descr.h (struct pthread): Move tid field to the front now that + it is often used. + + * sysdeps/unix/sysv/linux/i386/i486/libc-lowlevelmutex.S + (__lll_mutex_timedlock_wait): Remove. + (__lll_mutex_unlock_wake): Don't save, load, and restore %esi. + * sysdeps/unix/sysv/linux/i386/i486/lowlevelmutex.S + (__lll_mutex_unlock_wake): Don't save, load, and restore %esi. + * sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S + (lll_unlock_wake_cb): Don't save and restore %esi. + (__lll_unlock_wake): Add alignment. Don't save, load, and restore + %esi. + (__lll_timedwait_tid): Add alignment. + * sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S + (__lll_unlock_wake): Add alignment. Don't save, load, and restore + %esi. + (__lll_timedwait_tid): Removed. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S + (__pthread_cond_broadcast): Don't save, load, and restore %esi. + * sysdeps/unix/sysv/linux/i386/i486/pthread_barrier_wait.S + (pthread_barrier_wait): Don't save, load, and restore %esi for + last thread. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_signal.S + (__pthread_cond_signal): Don't save, load, and restore %esi. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_unlock.S + (__pthread_rwlock_unlock): Don't save, load, and restore %esi. + * sysdeps/unix/sysv/linux/i386/i486/sem_post.S (__new_sem_post): + Don't save, load, and restore %esi. + +2003-02-27 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S: + Release lock before waking up the waiters. + + * tst-exit1.c (do_test): Don't start more than one thread in parallel. + + * tst-rwlock9.c (writer_thread): Correct adding TIMEOUT. + (reader_thread): Likewise. + + * sysdeps/pthread/pthread_rwlock_unlock.c + (__pthread_rwlock_unlock): Release internal lock early. Don't try + to wake up readers if there are none. + + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_unlock.S: + Release internal lock before wake threads. + +2003-02-26 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add tst-rwlock10 and tst-rwlock11. + * tst-rwlock8.c: Initialize lock with INIT. Allow INIT to be + predefined. + * tst-rwlock9.c: Likewise. + * tst-rwlock10.c: New file. + * tst-rwlock11.c: New file. + + * Makefile (tests): Add tst-dlsym1. + * tst-dlsym1.c: New file. + + * init.c (__pthread_initialize_minimal_internal): Set + GL(dl_error_catch_tsd) to __libc_dl_error_tsd. + * Versions (libc:GLIBC_PRIVATE): Export __libc_dl_error_tsd. + +2003-02-24 Ulrich Drepper <drepper@redhat.com> + + * sem_open.c (sem_open): Fix handling of O_CREAT without O_EXCL. + + * tst-cond2.c: Fix sychronization with child. + + * tst-rwlock8.c (reader_thread): Remove unused variable. + + * Makefile: Add rules to build and run tst-tls3. + * tst-tls3.c: New file. + * tst-tls3mod.c: New file. + + * Makefile (tests): Add tst-rwlock8 and tst-rwlock9. + * tst-rwlock8.c: New file. + * tst-rwlock9.c: New file. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_rdlock.S: Fix + complete broken rwlock implementation. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedrdlock.S: + Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedwrlock.S: + Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_unlock.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_wrlock.S: Likewise. + * sysdeps/pthread/pthread_rwlock_rdlock.c: Likewise. + * sysdeps/pthread/pthread_rwlock_timedrdlock.c: Likewise. + * sysdeps/pthread/pthread_rwlock_timedwrlock.c: Likewise. + * sysdeps/pthread/pthread_rwlock_unlock.c: Likewise. + * sysdeps/pthread/pthread_rwlock_wrlock.c: Likewise. + +2003-02-23 Roland McGrath <roland@redhat.com> + + * Makefile (nptl-version): Change regexp so case sensitivity is ok. + +2003-02-23 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add tst-context1. + * tst-context1.c: New file. + + * Makefile (tests): Add tst-tls1 and tst-tls2. + * tst-tls1.c: New file. + * tst-tls2.c: New file. + + * libc-cancellation.c (__libc_enable_asynccancel): Correct test + for failed cmpxchg. + + * pthread_create.c (start_thread): Set EXITING_BIT early. + + * sysdeps/i386/tls.h (THREAD_GETMEM): Mark asm as volatile. + (THREAD_GETMEM_NC): Likewise. + +2003-02-22 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/i486/pthread_barrier_wait.S: Shave + off 3 more bytes by using offset-less instructions when possible. + + * Makefile: Add dependency for $(objpfx)version.d. + + * eintr.c (eintr_source): Add unnecessary return but the compiler + insists. + + * tst-kill3.c: Include <unistd.h>. + +2003-02-21 Roland McGrath <roland@redhat.com> + + * pthread_create.c (start_thread): Call __libc_thread_freeres. + +2003-02-21 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add tst-eintr1. + (distribute): Add eintr.c. + * tst-eintr1.c: New file. + * eintr.c: New file. + + * pthread_cancel.c (pthread_cancel): Use tkill directly. + + * sysdeps/unix/sysv/linux/pthread_kill.c (__pthread_kill): + Disallow sending SIGCANCEL. + + * Makefile (tests): Remove tst-basic7. Add tst-kill1, tst-kill2, + tst-kill3, tst-kill4, tst-kill5, tst-kill6. + * tst-kill1.c: New file. + * tst-kill2.c: New file. + * tst-kill3.c: New file. + * tst-kill5.c: New file. + * tst-kill6.c: New file. + * tst-basic7.c: Renamed to... + * tst-kill4.c: ...this. + +2003-02-21 Roland McGrath <roland@redhat.com> + + * Makefile (install-lib-ldscripts): New variable. + +2003-02-21 Ulrich Drepper <drepper@redhat.com> + + * pthreadP.h: Define INVALID_TD_P and INVALID_NOT_TERMINATED_TD_P. + * pthread_cancel.c: Use INVALID_TD_P. + * pthread_detach.c: Likewise. + * pthread_getschedparam.c: Likewise. + * pthread_setschedparam.c: Likewise. + * sysdeps/pthread/pthread_getcpuclockid.c: Likewise. + * sysdeps/unix/sysv/linux/pthread_kill.c: Likewise. + * pthread_join.c: Use INVALID_NOT_TERMINATED_TD_P. + * pthread_timedjoin.c: Likewise. + + * tst-basic7.c: Include <signal.h>. + + * pthread_join.c (pthread_join): Limited checking for invalid + descriptors. + * pthread_timedjoin.c (pthread_timedjoin_np): Likewise. + +2003-02-20 Ulrich Drepper <drepper@redhat.com> + + * pthread_create.c (deallocate_tsd): Reset found_nonzero at the + beginning of the loop. Clear the entire first block of TSD. + * Makefile (tests): Add tst-key4. + * tst-key4.c: New file. + +2003-02-18 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add tst-basic7. + * tst-basic7.c: New file. + + * pthread_create.c (deallocate_tsd): Mark as internal_function. + Add some more __builtin_expect. + + * pthreadP.h: Define dummy version of DEBUGGING_P. + +2003-02-17 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/bits/posix_opt.h: Remnove + _POSIX_THREAD_PRIORITY_SCHEDULING. + * sysdeps/unix/sysv/linux/i386/bits/posix_opt.h: Remove + _XOPEN_REALTIME_THREADS. + * sysdeps/unix/sysv/linux/bits/posix_opt.h: Likewise. + + * sysdeps/unix/sysv/linux/pthread_kill.c (__pthread_kill): The + kernel returns EINVAL for PID <= 0, work around it. + + * Makefile (tests): Add tst-signal5. + * tst-signal5.c: New file. + + * sysdeps/unix/sysv/linux/bits/local_lim.h: Define TTY_NAME_MAX + and LOGIN_NAME_MAX. + + * tst-cancel1.c (tf): Block all signals. + + * Makefile (tests): Add tst-basic6. + * tst-basic6.c: New file. + + * tst-basic1.c: Add test for process ID. + + * Makefile (tests): Add tst-cancel10. + * tst-cancel10.c: New file. + + * Makefile (tests): Add tst-signal4. + * tst-signal4.c: New file. + + * sysdeps/pthread/pthread_sigmask.c (pthread_sigmask): Use + __sigismember instead of sigismember. Add __builtin_expect. + +2003-02-16 Ulrich Drepper <drepper@redhat.com> + + * tst-attr1.c (do_test): Add tests for pthread_setcanceltype, + pthread_setcancelstate, and pthread_rwlock_setpshared. + + * tst-cancel7.c (do_test): Make sure the pid file exists before + canceling the thread. + + * tst-rwlock6.c: More pthread_rwlock_timedwrlock and + pthread_rwlock_timedrdlock tests. + * tst-rwlock7.c: More pthread_rwlock_timedwrlock tests. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedrdlock.S: + Check for invalid tv_nsec field. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedwrlock.S: + Likewise. + + * pthread_mutex_trylock.c (__pthread_mutex_trylock): Protect + recursive mutex of overflow. + + * tst-attr1.c (do_test): Add test for pthread_mutexattr_setpshared. + + * libc-cancellation.c (__libc_enable_asynccancel): Rewrite to avoid + going into an endless loop. + * Makefile (tests): Add tst-cancel9. + * tst-cancel9.c: New file. + + * pthread_cancel.c (pthread_cancel): Use the result of __pthread_kill. + +2003-02-15 Ulrich Drepper <drepper@redhat.com> + + * tst-mutex5.c (do_test): Add more timedlock tests. + + * tst-mutex2.c: Tests of trylock and unlock with ERROR mutexes. + * tst-mutex3.c (do_test): Add tests for trylock with RECURSIVE mutexes. + + * sysdeps/unix/sysv/linux/pthread_kill.c (__pthread_kill): Don't + use INLINE_SYSCALL. Error number is returned, not -1. + + * pthreadP.h: Mark declarations of __find_in_stack_list, __free_tcb, + and __deallocate_stack with internal_function. + * pthread_create.c: Adjust definitions appropriately. + * allocatestack.c: Likewise. + + * pthread_join.c: Add one more __builtin_expect. + * pthread_timedjoin.c: Likewise. + + * pthread_getspecific.c (__pthread_getspecific): Clear data->data + not data of sequence number does not match. + Add one __builtin_expect. + + * Makefile (tests): Add tst-clock1. + * tst-clock1.c: New file. + + * pthread_setconcurrency.c (pthread_setconcurrency): Fail for + negative arguments. + * Makefile (tests): Add tst-basic5. + * tst-basic5.c: New file. + +2003-02-14 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add tst-basic4. + * tst-basic4.c: New file. + + * pthreadP.h: Add declaraction for __nptl_nthreads. + * pthread_create.c: Define __nptl_nthreads + (start_thread): Increment __nptl_nthreads at beginning. Decrement + after thread is done. If then zero, call exit(0). + * sysdeps/pthread/pthread-functions.h (struct pthread_functions): + Add ptr_nthreads. Define HAVE_PTR_NTHREADS. + * init.c (pthread_functions): Initialize ptr_nthreads. + * allocatestack.c (nptl_nthreads): Remove definition and all uses. + (__reclaim_stacks): Decrement __nptl_nthreads. + * sysdeps/pthread/Makefile [$(subdir)==csu] (CFLAGS-libc-start.c): + Define. + * Makefile (tests): Add tst-basic3. + * tst-basic3.c: New file. + + * descr.h: Define CANCELING_BIT and CANCELING_BITMASK. Introduce + after CANCELTYPE_BIT, move the other bits up. Update CANCEL_RESTMASK. + * init.c (sigcancel_handler): Also set CANCELING_BITMASK bit in newval. + * pthread_cancel.c (pthread_cancel): Likewise. Also set CANCELING_BIT + if asynchronous canceling is enabled. + * pthread_join.c (pthread_join): When recognizing circular joins, + take into account the other thread might be already canceled. + * Makefile (tests): Add tst-join5. + * tst-join5.c: New file. + + * Makefile (tests): Add tst-join4. + * tst-join4.c: New file. + +2003-02-13 Ulrich Drepper <drepper@redhat.com> + + * tst-cond4.c (main): Add test of pthread_attr_getpshared. + +2003-02-13 Martin Schwidefsky <schwidefsky@de.ibm.com> + + * sysdeps/s390/tls.h (THREAD_GETMEM, THREAD_GETMEM_NC, THREAD_SETMEM, + THREAD_SETMEM_NC): Use passed descr instead of THREAD_SELF. + * sysdeps/unix/sysv/linux/s390/jmp-unwind.c (_longjmp_unwind): Avoid + warning. + * sysdeps/unix/sysv/linux/s390/lowlevellock.c: Include <sys/time.h> + to avoid warning. + * sysdeps/unix/sysv/linux/s390/sem_post.c (__new_sem_post): Return + error if lll_futex_wake failed. + +2003-02-13 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Fix + handling of cancellation and failung pthread_mutex_unlock call. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Likewise. + * Makefile (tests): Add tst-cond8 and tst-cond9. + * tst-cond8.c: New file. + * tst-cond9.c: New file. + + * tst-cond7.c (do_test): Unlock the mutex before canceling the thread. + + * sysdeps/pthread/pthread.h: Add missing initializers. Protect + non-standard initializers with __USE_GNU. + + * Makefile (tests): Add tst-cleanup3. + * tst-cleanup3.c: New file. + +2003-02-12 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add tst-attr1 and tst-attr2. + * tst-attr1.c: New file. + * tst-attr2.c: New file. + + * Makefile: Add rules to build and run tst-atfork2 test. + * tst-atfork2.c: New file. + * tst-atfork2mod.c: New file. + + * sysdeps/unix/sysv/linux/unregister-atfork.c + (__unregister_atfork): Free the memory allocated for the handlers + after removing them from the lists. + + * sysdeps/unix/sysv/linux/register-atfork.c: Define memeory + cleanup function. + + * tst-atfork1.c (do_test): Wait for the child we forked. + Report error in child. + + * sysdeps/unix/sysv/linux/fork.c (__libc_fork): Fix comment. + + * sysdeps/pthread/Makefile: Define CFLAGS-confstr.c. + +2003-02-10 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add tst-cancel8. + * tst-cancel8.c: New file. + + * sysdeps/unix/sysv/linux/i386/pthread_once.S (clear_once_control): Fix + clearing of control variable. + * Makefile (tests): Add tst-once3 and tst-once4. + * tst-once3.c: New file. + * tst-once4.c: New file. + +2003-02-08 kaz Kojima <kkojima@rr.iij4u.or.jp> + + * sysdeps/sh/Makefile: New file. + * sysdeps/sh/bits/atomic.h: New file. + * sysdeps/sh/pthread_spin_init.c: New file. + * sysdeps/sh/pthread_spin_lock.c: New file. + * sysdeps/sh/pthread_spin_trylock.S: New file. + * sysdeps/sh/pthread_spin_unlock.S: New file. + * sysdeps/sh/pthreaddef.h: New file. + * sysdeps/sh/tcb-offsets.sym: New file. + * sysdeps/sh/td_ta_map_lwp2thr.c: New file. + * sysdeps/sh/tls.h: New file. + * sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h: New file. + * sysdeps/unix/sysv/linux/sh/bits/semaphore.h: New file. + * sysdeps/unix/sysv/linux/sh/createthread.c: New file. + * sysdeps/unix/sysv/linux/sh/fork.c: New file. + * sysdeps/unix/sysv/linux/sh/libc-lowlevellock.S: New file. + * sysdeps/unix/sysv/linux/sh/libc-lowlevelmutex.S: New file. + * sysdeps/unix/sysv/linux/sh/lowlevel-atomic.h: New file. + * sysdeps/unix/sysv/linux/sh/lowlevelcond.h: New file. + * sysdeps/unix/sysv/linux/sh/lowlevellock.S: New file. + * sysdeps/unix/sysv/linux/sh/lowlevellock.h: New file. + * sysdeps/unix/sysv/linux/sh/lowlevelmutex.S: New file. + * sysdeps/unix/sysv/linux/sh/lowlevelrwlock.h: New file. + * sysdeps/unix/sysv/linux/sh/pt-initfini.c: New file. + * sysdeps/unix/sysv/linux/sh/pt-vfork.S: New file. + * sysdeps/unix/sysv/linux/sh/pthread_barrier_wait.S: New file. + * sysdeps/unix/sysv/linux/sh/pthread_cond_broadcast.S: New file. + * sysdeps/unix/sysv/linux/sh/pthread_cond_signal.S: New file. + * sysdeps/unix/sysv/linux/sh/pthread_cond_timedwait.S: New file. + * sysdeps/unix/sysv/linux/sh/pthread_cond_wait.S: New file. + * sysdeps/unix/sysv/linux/sh/pthread_once.S: New file. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_rdlock.S: New file. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedrdlock.S: New file. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedwrlock.S: New file. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_unlock.S: New file. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_wrlock.S: New file. + * sysdeps/unix/sysv/linux/sh/sem_post.S: New file. + * sysdeps/unix/sysv/linux/sh/sem_timedwait.S: New file. + * sysdeps/unix/sysv/linux/sh/sem_trywait.S: New file. + * sysdeps/unix/sysv/linux/sh/sem_wait.S: New file. + * sysdeps/unix/sysv/linux/sh/sysdep-cancel.h: New file. + +2003-02-08 Ulrich Drepper <drepper@redhat.com> + + * tst-cond2.c: Rearrange code to not rely on behavior undefined + according to POSIX. + + * tst-basic2.c (do_test): Lock mutex before creating the thread. + +2003-02-07 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/x86_64/tls.h: Remove unnecessary macros, left over from x86. + (TLS_GET_FS): New #define. + (TLS_SET_FS): New #define. + Correct value of __NR_set_thread_area. + + * sysdeps/x86_64/td_ta_map_lwp2thr.c: New file. + +2003-02-06 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add tst-popen1. + * tst-popen1.c: New file. + + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Remove wrong + but inactive generalization. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_signal.S: Likewise. + Minor optimization, remove one instruction. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S: Likewise. + +2003-02-04 Martin Schwidefsky <schwidefsky@de.ibm.com> + + * sysdeps/unix/sysv/linux/s390/fork.c: Correct order of parameters. + +2003-01-31 Martin Schwidefsky <schwidefsky@de.ibm.com> + + * init.c (__NR_set_tid_address): Add #ifdef for s390. + * sysdeps/pthread/pthread_barrier_wait.c: New file. + * sysdeps/pthread/pthread_cond_broadcast.c: New file. + * sysdeps/pthread/pthread_cond_signal.c: New file. + * sysdeps/pthread/pthread_cond_timedwait.c: New file. + * sysdeps/pthread/pthread_cond_wait.c: New file. + * sysdeps/pthread/pthread_rwlock_rdlock.c: New file. + * sysdeps/pthread/pthread_rwlock_timedrdlock.c: New file. + * sysdeps/pthread/pthread_rwlock_timedwrlock.c: New file. + * sysdeps/pthread/pthread_rwlock_unlock.c: New file. + * sysdeps/pthread/pthread_rwlock_wrlock.c: New file. + * sysdeps/s390/Makefile: New file. + * sysdeps/s390/bits/atomic.h: New file. + * sysdeps/s390/pthread_spin_init.c: New file. + * sysdeps/s390/pthread_spin_lock.c: New file. + * sysdeps/s390/pthread_spin_trylock.c: New file. + * sysdeps/s390/pthread_spin_unlock.c: New file. + * sysdeps/s390/pthreaddef.h: New file. + * sysdeps/s390/tcb-offsets.sym: New file. + * sysdeps/s390/td_ta_map_lwp2thr.c: New file. + * sysdeps/s390/tls.h: New file. + * sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h: New file. + * sysdeps/unix/sysv/linux/s390/bits/semaphore.h: New file. + * sysdeps/unix/sysv/linux/s390/createthread.c: New file. + * sysdeps/unix/sysv/linux/s390/dl-sysdep.h: New file. + * sysdeps/unix/sysv/linux/s390/fork.c: New file. + * sysdeps/unix/sysv/linux/s390/jmp-unwind.c: New file. + * sysdeps/unix/sysv/linux/s390/libc-lowlevellock.c: New file. + * sysdeps/unix/sysv/linux/s390/libc-lowlevelmutex.c: New file. + * sysdeps/unix/sysv/linux/s390/lowlevellock.c: New file. + * sysdeps/unix/sysv/linux/s390/lowlevellock.h: New file. + * sysdeps/unix/sysv/linux/s390/lowlevelmutex.c: New file. + * sysdeps/unix/sysv/linux/s390/lowlevelsem.h: New file. + * sysdeps/unix/sysv/linux/s390/pthread_once.c: New file. + * sysdeps/unix/sysv/linux/s390/s390-32/pt-initfini.c: New file. + * sysdeps/unix/sysv/linux/s390/s390-32/pt-vfork.S: New file. + * sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h: New file. + * sysdeps/unix/sysv/linux/s390/s390-64/pt-initfini.c: New file. + * sysdeps/unix/sysv/linux/s390/s390-64/pt-vfork.S: New file. + * sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h: New file. + * sysdeps/unix/sysv/linux/s390/sem_post.c: New file. + * sysdeps/unix/sysv/linux/s390/sem_timedwait.c: New file. + * sysdeps/unix/sysv/linux/s390/libc-lowlevellock.c: New file. + * sysdeps/unix/sysv/linux/s390/sem_wait.c: New file. + +2003-02-04 Ulrich Drepper <drepper@redhat.com> + + * atomic.h: Add a couple more default implementations. + (atomic_compare_and_exchange_acq): Use + __arch_compare_and_exchange_32_acq in return value definition. It + always exists. + (atomic_bit_set): Renamed from atomic_set_bit. + Add missing atomic_ prefixes. + + * sysdeps/pthread/bits/libc-lock.h (__libc_once): In case no + thread library is available, use correct value to mark initialized + once variable. + +2003-02-03 Ulrich Drepper <drepper@redhat.com> + + * allocatestack.c (allocate_stack): Use __getpagesize instead of + __sysconf to determine pagesize. + + * pthread_create.c: Include <atomic.h>. + * allocatestack.c (allocate_stack): Implement coloring of the + allocated stack memory. Rename pagesize to pagesize_m1. It's the + size minus one. Adjust users. + * sysdeps/i386/i686/Makefile: New file. + +2003-02-02 Ulrich Drepper <drepper@redhat.com> + + * allocatestack.c: Improve comment throughout the file. + + * sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S + (__lll_lock_wait): Add branch prediction. + * sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S + (__lll_lock_wait): Likewise. + (lll_unlock_wake_cb): Removed. + +2003-01-31 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/bits/posix_opt.h: Remove + _POSIX_THREAD_PRIORITY_SCHEDULING. + +2003-01-30 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/pthread/pthread-functions.h (struct pthread_functions): + Fix return type of ptr___pthread_getspecific. + +2003-01-29 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add tst-umask1. + (tst-umask1-ARGS): Define. + * tst-umask1.c: New file. + +2003-01-28 Ulrich Drepper <drepper@redhat.com> + + * Makefile (libpthread-routines): Remove lowlevelrwlock. Add + pthread_rwlock_rdlock, pthread_rwlock_timedrdlock, + pthread_rwlock_wrlock, pthread_rwlock_timedwrlock, and + pthread_rwlock_unlock. + * sysdeps/unix/sysv/linux/i386/i486/lowlevelrwlock.S: Removed + * sysdeps/unix/sysv/linux/i386/i586/lowlevelrwlock.S: Removed + * sysdeps/unix/sysv/linux/i386/i686/lowlevelrwlock.S: Removed + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_rdlock.S: New file. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedrdlock.S: + New file. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_wrlock.S: New file. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedwrlock.S: + New file. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_unlock.S: New file. + * sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_rdlock.S: New file. + * sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_timedrdlock.S: + New file. + * sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_wrlock.S: New file. + * sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_timedwrlock.S: + New file. + * sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_unlock.S: New file. + * sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_rdlock.S: New file. + * sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_timedrdlock.S: + New file. + * sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_wrlock.S: New file. + * sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_timedwrlock.S: + New file. + * sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_unlock.S: New file. + + * Makefile (libpthread-routines): Remove lowlevelcond and + lowlevelsem. Add sem_wait, sem_trywait, sem_timedwait, sem_post, + pthread_cond_wait, pthread_cond_timedwait, pthread_cond_signal, + and pthread_cond_broadcast. + * sysdeps/unix/sysv/linux/i386/i486/lowlevelsem.S: Removed + * sysdeps/unix/sysv/linux/i386/i486/lowlevelcond.S: Removed + * sysdeps/unix/sysv/linux/i386/i586/lowlevelsem.S: Removed + * sysdeps/unix/sysv/linux/i386/i586/lowlevelcond.S: Removed + * sysdeps/unix/sysv/linux/i386/i686/lowlevelsem.S: Removed + * sysdeps/unix/sysv/linux/i386/i686/lowlevelcond.S: Removed + * sysdeps/unix/sysv/linux/i386/i486/sem_wait.S: New file. + * sysdeps/unix/sysv/linux/i386/i486/sem_trywait.S: New file. + * sysdeps/unix/sysv/linux/i386/i486/sem_timedwait.S: New file. + * sysdeps/unix/sysv/linux/i386/i486/sem_post.S: New file. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: New file. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: New file. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_signal.S: New file. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S: New file. + * sysdeps/unix/sysv/linux/i386/i586/sem_wait.S: New file. + * sysdeps/unix/sysv/linux/i386/i586/sem_trywait.S: New file. + * sysdeps/unix/sysv/linux/i386/i586/sem_timedwait.S: New file. + * sysdeps/unix/sysv/linux/i386/i586/sem_post.S: New file. + * sysdeps/unix/sysv/linux/i386/i586/pthread_cond_wait.S: New file. + * sysdeps/unix/sysv/linux/i386/i586/pthread_cond_timedwait.S: New file. + * sysdeps/unix/sysv/linux/i386/i586/pthread_cond_signal.S: New file. + * sysdeps/unix/sysv/linux/i386/i586/pthread_cond_broadcast.S: New file. + * sysdeps/unix/sysv/linux/i386/i686/sem_wait.S: New file. + * sysdeps/unix/sysv/linux/i386/i686/sem_trywait.S: New file. + * sysdeps/unix/sysv/linux/i386/i686/sem_timedwait.S: New file. + * sysdeps/unix/sysv/linux/i386/i686/sem_post.S: New file. + * sysdeps/unix/sysv/linux/i386/i686/pthread_cond_wait.S: New file. + * sysdeps/unix/sysv/linux/i386/i686/pthread_cond_timedwait.S: New file. + * sysdeps/unix/sysv/linux/i386/i686/pthread_cond_signal.S: New file. + * sysdeps/unix/sysv/linux/i386/i686/pthread_cond_broadcast.S: New file. + * sysdeps/unix/sysv/linux/i386/lowlevelcond.h: New file. + + * sysdeps/unix/sysv/linux/i386/createthread.c: Define + PREPARE_CREATE and TLS_VALUE with x86-specific bits. All the rest + of the code is moved to ... + * sysdeps/pthread/createthread.c: ...here. New file. + +2003-01-27 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/i486/lowlevelsem.S + (__new_sem_post): Clear %eax before returning. + Reported by MAEDA Naoaki <maeda.naoaki@jp.fujitsu.com>. + + * Makefile (tests): Add tst-cleanup2. + * tst-cleanup2.c: New file. + + * sysdeps/pthread/bits/libc-lock.h (__libc_cleanup_region_start): + Interpret first parameter correctly. + +2003-01-17 Ulrich Drepper <drepper@redhat.com> + + * Makefile (headers): Add bits/semaphore.h. + +2003-01-16 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/i386/tls.h (INIT_SYSINFO): Initialize _head->sysinfo even + if not SHARED. + +2003-01-14 Ulrich Drepper <drepper@redhat.com> + + * sem_open.c (sem_open): Return SEM_FAILED if existing semaphore + must be used and mapping failed. + Reported by Luke Elliott <luke.elliott@activfinancial.com>. + + * Makefile (CFLAGS-pthread_self.os): Define this, not + CFLAGS-pthread_self.c. + +2003-01-13 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S: Don't export + lll_unlock_wake_cb. + + * Makefile (libpthread-routines): Add version. Add rules to build + version.os and banner.h. + * version.c: New file. + +2003-01-13 Jakub Jelinek <jakub@redhat.com> + + * pthread_mutex_lock.c (__pthread_mutex_lock_internal): Make + the alias unconditional. + * pthread_mutex_unlock.c (__pthread_mutex_unlock_internal): Likewise. + +2003-01-13 Ulrich Drepper <drepper@redhat.com> + + * Makefile (CFLAGS-pthread_self.c): New definition. + +2003-01-06 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/pthread/pthread_sigmask.c (pthread_sigmask): Add + INTERNAL_SYSCALL_DECL, add err argument to INTERNAL_SYSCALL* macros. + * sysdeps/unix/sysv/linux/raise.c (raise): Likewise. + * init.c (__pthread_initialize_minimal_internal): Likewise. + +2003-01-07 Jakub Jelinek <jakub@redhat.com> + + * pthreadP.h (__pthread_cond_timedwait): Add prototype. + + * sysdeps/unix/sysv/linux/i386/dl-sysdep.h + (RTLD_CORRECT_DYNAMIC_WEAK): Remove. + (DL_SYSINFO_IMPLEMENTATION): Change into .text section and back. + * sysdeps/unix/sysv/linux/i386/i686/dl-sysdep.h + (RTLD_CORRECT_DYNAMIC_WEAK): Remove. + (DL_SYSINFO_IMPLEMENTATION): Change into .text section and back. + +2003-01-06 Jakub Jelinek <jakub@redhat.com> + + * pthreadP.h (LIBC_CANCEL_HANDLED): Define. + * pt-system.c (LIBC_CANCEL_HANDLED): Add. + * tst-cancel-wrappers.sh: Remove all exceptions. + +2003-01-05 Ulrich Drepper <drepper@redhat.com> + + * tst-cancel-wrappers.sh: Invoke gawk not awk since we use GNU awk + features. Reported by Marijn Ros <marijn@mad.scientist.com>. + + * sysdeps/unix/sysv/linux/jmp-unwind.c: Include <pthread-functions.h>. + Use __libc_pthread_functions array if SHARED. + + * pthreadP.h: Move pthread_cond_2_0_t definition to... + * sysdeps/unix/sysv/linux/internaltypes.h: ...here. + + * sysdeps/pthread/bits/libc-lock.h (__libc_ptf_call): New #define. + (__libc_rwlock_rdlock, __libc_rwlock_wrlock, __libc_rwlock_unlock, + __libc_key_create, __libc_getspecific, __libc_setspecific): Use + __libc_ptf_call instead of __libc_maybe_call. + (PTF): New #define. + (__libc_cleanup_region_start): Wrap function name with PTF call. + (__libc_cleanup_region_end): Likewise. + (__libc_cleanup_end): Likewise. + + * pthread_getspecific.c: Add __pthread_getspecific_internal alias. + * pthread_setspecific.c: Add __pthread_setspecific_internal alias. + * pthread_key_create.c: Add __pthread_key_create_internal alias. + * pthreadP.h: Add prototypes. + + * sysdeps/unix/sysv/linux/i386/i486/lowlevelrwlock.S: Add + __pthread_rwlock_rdlock, __pthread_rwlock_wrlock, and + __pthread_rwlock_unlock aliases. + * pthreadP.h: Add prototypes for new aliases. + + * pthreadP.h (struct pthead_functions): Moved to... + * sysdeps/pthread/pthread-functions.h: ...here. New file. + * init.c (pthread_functions): Add initializers for new elements. + + * cleanup_defer.c: Add __pthread_cleanup_push_defer and + __pthread_cleanup_pop_restore aliases. + * pthreadP.h: Add prototypes. + + * cleanup.c: Rename _GI_pthread_cleanup_push to __pthread_cleanup_push + and _GI_pthread_cleanup_pop to __pthread_cleanup_pop. + * sysdeps/unix/sysv/linux/i386/i486/lowlevelcond.S: Adjust caller. + * sysdeps/unix/sysv/linux/i386/pthread_once.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_once.S: Likewise. + * pthreadP.h: Adjust prototypes and callers. + +2003-01-04 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add tst-cancel7. + (tst-cancel7-ARGS): New variable. + * tst-cancel7.c: New file. + + * old_pthread_cond_broadcast.c: Optimize initialization a bit to work + around gcc defficiencies. + * old_pthread_cond_signal.c: Likewise. + * old_pthread_cond_timedwait.c: Likewise. + * old_pthread_cond_wait.c: Likewise. + + * pthreadP.h (pthread_cond_2_0_t): Remove unneeded lock element. + +2003-01-03 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add tst-cond7. + * tst-cond7.c: New file. + + * sysdeps/unix/sysv/linux/i386/i486/lowlevelcond.S + (condvar_cleanup): Get condvar address from the right place. + + * atomic.h: Correct definitions of atomic_full_barrier, + atomic_read_barrier, atomic_write_barrier. + + * old_pthread_cond_broadcast.c: Make memory allocate and initialization + race-free. + * old_pthread_cond_signal.c: Likewise. + * old_pthread_cond_timedwait.c: Likewise. + * old_pthread_cond_wait.c: Likewise. + +2003-01-03 Jakub Jelinek <jakub@redhat.com> + + * Makefile ($(objpfx)libpthread.so): Depend on ld.so. + +2003-01-03 Ulrich Drepper <drepper@redhat.com> + + * pthreadP.h (pthread_cond_2_0_t): New type. + (struct pthread_functions): Use new type for 2.0 condvar callbacks. + Use new type for the 2.0 condvar function prototypes. + * forward.c: Use pthread_cond_2_0_t for 2.0 condvar functions. + * old_pthread_cond_init.c: Use pthread_cond_2_0_t for condvar + parameter. + * old_pthread_cond_destroy.c: Likewise. + * old_pthread_cond_broadcast.c: Likewise. Lock appropriately. + * old_pthread_cond_signal.c: Likewise. + * old_pthread_cond_timedwait.c: Likewise. + * old_pthread_cond_wait.c: Likewise. + + * sysdeps/unix/sysv/linux/i386/i486/lowlevelcond.S + (__pthread_cond_wait): Don't save cancellation mode and seq value + in same location. + + * herrno.c (__h_errno_location): Don't define as weak. + +2003-01-02 Jakub Jelinek <jakub@redhat.com> + + * Versions [libc] (GLIBC_2.3.2): Export pthread_cond_broadcast, + pthread_cond_destroy, pthread_cond_init, pthread_cond_signal + and pthread_cond_wait. + * old_pthread_cond_broadcast.c (__old_pthread_cond_broadcast): + Renamed to... + (__pthread_cond_broadcast_2_0): ... this. + * old_pthread_cond_destroy.c (__old_pthread_cond_destroy): + Renamed to... + (__pthread_cond_destroy_2_0): ... this. + * old_pthread_cond_init.c (__old_pthread_cond_init): + Renamed to... + (__pthread_cond_init_2_0): ... this. + * old_pthread_cond_signal.c (__old_pthread_cond_signal): + Renamed to... + (__pthread_cond_signal_2_0): ... this. + * old_pthread_cond_wait.c (__old_pthread_cond_wait): + Renamed to... + (__pthread_cond_wait_2_0): ... this. + * pthread_cond_destroy.c: Include shlib-compat.h. + (pthread_cond_destroy): Change strong_alias into versioned_symbol. + * pthread_cond_init.c: Include shlib-compat.h. + (pthread_cond_init): Change strong_alias into versioned_symbol. + * pthreadP.h (struct pthread_functions): Rename ptr_pthread_cond_* + fields to ptr___pthread_cond_* and add ptr___pthread_cond_*_2_0 + fields. + (__pthread_cond_broadcast_2_0, __pthread_cond_destroy_2_0, + __pthread_cond_init_2_0, __pthread_cond_signal_2_0, + __pthread_cond_wait_2_0): New prototypes. + (__old_pthread_cond_broadcast, __old_pthread_cond_destroy, + __old_pthread_cond_init, __old_pthread_cond_signal, + __old_pthread_cond_wait): Removed. + * init.c: Include shlib-compat.h. + (pthread_functions): Guard ptr___pthread_attr_init_2_0 + initialization with SHLIB_COMPAT (GLIBC_2_0, GLIBC_2_1). + Rename ptr_pthread_cond_* to ptr___pthread_cond_*, initialize + ptr___pthread_cond_*_2_0 fields. + * forward.c: Export both pthread_cond_*@@GLIBC_2.3.2 and + pthread_cond_*@GLIBC_2.0 compatibility symbols. + + * sysdeps/pthread/sigaction.c (SIGCANCEL): Only define if + LIBC_SIGACTION was not yet defined. + [!defined LIBC_SIGACTION]: Define LIBC_SIGACTION, #include self. + [!defined LIBC_SIGACTION] (__sigaction): New function and + libc_hidden_weak. + [!defined LIBC_SIGACTION] (sigaction): New weak_alias. + [defined LIBC_SIGACTION]: #include_next <sigaction.c>. + +2003-01-02 Jakub Jelinek <jakub@redhat.com> + + * Makefile (CFLAGS-pthread_atfork.c): Add -DNOT_IN_libc. + +2003-01-02 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h (pthread_cond_t): + New, larger type definition. + * sysdeps/unix/sysv/linux/i386/i486/lowlevelcond.S: New condvar + implementation. + * Versions [libpthread]: Add definitions for new pthread_cond_* + interfaces for version GLIBC_2.3.2. + * pthread_cond_init.c: Update initialization for new type definition. + * Makefile (libpthread-routines): Remove pthread_cond_wait, + pthread_cond_timedwait, pthread_cond_signal, and + pthread_cond_broadcast. Add old_pthread_cond_init, + old_pthread_cond_destroy, old_pthread_cond_wait, + old_pthread_cond_timedwait, old_pthread_cond_signal, and + old_pthread_cond_broadcast. + * old_pthread_cond_broadcast.c: New file. + * old_pthread_cond_destroy.c: New file. + * old_pthread_cond_init.c: New file. + * old_pthread_cond_signal.c: New file. + * old_pthread_cond_timedwait.c: New file. + * old_pthread_cond_wait.c: New file. + * pthreadP.h: Add prototypes for the compatibility interfaces. + + * pthread_cond_destroy.c: Don't include <errno.h>. + +2003-01-01 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/i486/lowlevelrwlock.S: Avoid + unnecessary zero offset when addressing MUTEX. + +2002-12-31 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/fork.h: Add libc_hidden_proto for + __register_atfork. + * sysdeps/unix/sysv/linux/register-atfork.c: Add libc_hidden_def + for __register_atfork. + +2002-12-31 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h: Use __ASSEMBLER__ + instead of ASSEMBLER test macro. + + * sysdeps/unix/sysv/linux/allocrtsig.c (__libc_current_sigrtmin, + __libc_current_sigrtmax): Add libc_hidden_def. + + * sysdeps/pthread/list.h: Remove assert.h include. + +2002-12-31 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/pt-initfini.c (call_initialize_minimal): Use + __pthread_initialize_minimal_internal not + __pthread_initialize_minimal. + +2002-12-30 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/pt-initfini.c (call_initialize_minimal): Mark + __pthread_initialize_minimal as hidden. + + * init.c (__pthread_initialize_minimal_internal): Don't mark as + constructor. + +2002-12-31 Jakub Jelinek <jakub@redhat.com> + + * Makefile ($(inst_libdir)/libpthread.so): Depend on + $(common-objpfx)format.lds, include that into the output script. + Fix comment. + (extra-B-pthread.so): Change linuxthreads/ into nptl/. + +2002-12-28 Andreas Jaeger <aj@suse.de> + + * sysdeps/unix/sysv/linux/xstatconv.c (xstat_conv): Adjust for + nsec resolution changes. + (xstat64_conv): Likewise. + (xstat32_conv): Likewise. + * sysdeps/unix/sysv/linux/kernel_stat.h: Add nsec resolution for + struct kernel_stat. + * sysdeps/unix/sysv/linux/bits/stat.h: Add nsec resolution for + structs stat and stat64. + * time/time.h (__timespec_defined): Define for __USE_MISC. + * io/sys/stat.h [__USE_MISC]: Define __need_timespec for struct stat. + +2002-12-30 Jakub Jelinek <jakub@redhat.com> + + * forward.c (FORWARD2): Renamed from FORWARD3. Remove unused export + argument. + (pthread_attr_init_2_0, pthread_attr_init_2_1): Use FORWARD macro. + (pthread_exit): Use strong_alias to avoid warnings. + * pthreadP.h (struct pthread_functions): Rename ptr_pthread_exit + and ptr_pthread_attr_init_2_* to ptr___pthread_exit and + ptr___pthread_attr_init_2_*. + * init.c (pthread_functions): Adjust. + +2002-12-29 Ulrich Drepper <drepper@redhat.com> + + * forward.c: Make all functions available by default again. It + caused too much trouble. + + * pt-siglongjmp.c: Removed. + +2002-12-28 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/i386/tls.h: Include tcb-offsets.h in assembler. + (SYSINFO_OFFSET, MULTIPLE_THREADS_OFFSET): Remove. + * sysdeps/i386/Makefile: New file. + * sysdeps/i386/tcb-offsets.sym: New file. + * sysdeps/pthread/tcb-offsets.h: New file. + * sysdeps/unix/sysv/linux/libc_pthread_init.c (__libc_pthread_init): + Remove MULTIPLE_THREADS_OFFSET and SYSINFO_OFFSET checks. + + * sysdeps/unix/sysv/linux/Versions [libc] (GLIBC_PRIVATE): Move + __register_atfork... + (GLIBC_2.3.2): ...here. + +2002-12-28 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/pthread.h: Mark pthread_attr_getstackaddr and + pthread_attr_setstackaddr with __attribute_deprecated__. + +2002-12-27 Jakub Jelinek <jakub@redhat.com> + + * pt-system.c (system): Remove cancellation handling. + * tst-cancel-wrappers.sh: Allow pt-system.o* to not use the + cancellation routines. + +2002-12-28 Ulrich Drepper <drepper@redhat.com> + + * descr.h: Include <dl-sysdep.h>. + (struct pthread): Move header.data.list to the back of the struct. + * sysdeps/i386/tls.h (tcbhead_t): Move list to the back of the struct. + (MULTIPLE_THREADS_OFFSET): Adjust offset. + (SYSINFO_OFFSEET): Likewise. + +2002-12-27 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/i386/i686/dl-sysdep.h (USE_DL_SYSINFO): + Define. + (DL_SYSINFO_DEFAULT): Cast to uintptr_t to avoid warnings. + * sysdeps/unix/sysv/linux/i386/dl-sysdep.h (NEED_DL_SYSINFO, + DL_SYSINFO_DEFAULT, DL_SYSINFO_IMPLEMENTATION): Define. + (USE_DL_SYSINFO): Undef. + +2002-12-22 Jakub Jelinek <jakub@redhat.com> + + * Makefile (tests-reverse): Use $(objpfx)../libc.so instead of + $(common-objpfx)libc.so. + * tst-cancel4.c (tf_write, tf_writev): Increase buf sizes so that + it is bigger than pipe buffer size even on arches with bigger + page size. + (tf_usleep): Cast usleep argument to useconds_t to avoid warnings. + +2002-12-25 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/i486/lowlevelsem.S: Implement + correct errno access for case that USE___THREAD is not defined. + +2002-12-24 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/dl-sysdep.h: Add missing #endif. + Patch by Marijn Ros <marijn@mad.scientist.com>. + +2002-12-22 Roland McGrath <roland@redhat.com> + + * Makefile (omit-deps): Add $(unix-syscalls:%=ptw-%). + +2002-12-20 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/bits/stdio-lock.h (_IO_lock_inexpensive): Define. + +2002-12-19 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/dl-sysdep.h: Don't define + NEED_DL_SYSINFO since no processor < i686 had the sysenter opcode. + * sysdeps/unix/sysv/linux/i386/i686/dl-sysdep.h: New file. + + * sysdeps/unix/sysv/linux/i386/pthread_once.S: Use ENTER_KERNEL instead + of int $0x80. + * sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/libc-lowlevelmutex.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/lowlevelcond.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/lowlevelmutex.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/lowlevelrwlock.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/lowlevelsem.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_barrier_wait.S: Likewise. + + * sysdeps/unix/sysv/linux/i386/lowlevellock.h: Add support for using + sysenter. + * sysdeps/unix/sysv/linux/i386/lowlevelsem.h: Likewise. + + * sysdeps/i386/tls.h: Unconditionally include <dl-sysdep.h>. + + * allocatestack.c (allocate_stack) [NEED_DL_SYSINFO]: Set sysinfo + in new TCB. + * sysdeps/unix/sysv/linux/i386/createthread.c (create_thread): Check + that sysinfo is properly initialized. + * sysdeps/unix/sysv/linux/i386/dl-sysdep.h: Define RTLD_PRIVATE_ERRNO + to 1 only for ld.so. + + * sysdeps/unix/sysv/linux/i386/dl-sysdep.h: Define + RTLD_CORRECT_DYNAMIC_WEAK. + +2002-12-19 Jakub Jelinek <jakub@redhat.com> + + * forward.c (pthread_attr_init_2_0, pthread_attr_init_2_1): + Use return 0 as 6th argument to FORWARD4. + * pthread_equal.c: Include pthreadP.h instead of pthread.h. + +2002-12-18 Ulrich Drepper <drepper@redhat.com> + + * descr.h (struct pthread) [NEED_DL_SYSINFO]: Add sysinfo member. + * sysdeps/i386/tls.h (tcbhead_t): Add sysinfo member. + Define SYSINFO_OFFSEET if NEED_DL_SYSINFO is defined. + (INIT_SYSINFO): New #define. + (TLS_TP_INIT): Use INIT_SYSINFO. + * sysdeps/unix/sysv/linux/libc_pthread_init.c (__libc_pthread_init): + At test to make sure SYSINFO_OFFSET value is correct. + * sysdeps/unix/sysv/linux/i386/dl-sysdep.h: New file. + +2002-12-18 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/pthread/flockfile.c (flockfile): Change into weak alias. + * sysdeps/unix/sysv/linux/raise.c (gsignal): Add weak alias to raise. + * Versions [libc: GLIBC_2.0]: Add pthread_attr_init. + [libpthread: GLIBC_2.1]: Remove __pthread_rwlock_init, + __pthread_rwlock_destroy, __pthread_rwlock_rdlock, + __pthread_rwlock_wrlock, __pthread_rwlock_unlock, + __pthread_rwlock_tryrdlock and __pthread_rwlock_trywrlock. + +2002-12-18 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h: Use ENTER_KERNEL + macro instead of using int $0x80 directly. + + * sysdeps/pthread/bits/stdio-lock.h: New file. + * sysdeps/unix/sysv/linux/i386/i486/libc-lowlevelmutex.S: New file. + * sysdeps/unix/sysv/linux/i386/i586/libc-lowlevelmutex.S: New file. + * sysdeps/unix/sysv/linux/i386/i686/libc-lowlevelmutex.S: New file. + * Makefile (routines): Add libc-lowlevelmutex. + + * sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S: Remove + __i686.get_pc_thunk.dx. + +2002-12-17 Jakub Jelinek <jakub@redhat.com> + + * Makefile (libpthread-shared-only-routines): Add pt-allocrtsig. + (tests): Depend on $(objpfx)tst-cancel-wrappers.out. + ($(objpfx)tst-cancel-wrappers.out): New rule. + * tst-cancel-wrappers.sh: New test. + * tst-locale1.c: Include signal.h. + (uselocale): Test static linking of __libc_current_sigrt*. + +2002-12-17 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add tst-cancel6. + * tst-cancel6.c: New file + +2002-12-17 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h (SINGLE_THREAD_P): + Define meaningfully for assembler as well. + * pthreadP.h (struct pthread_functions): Remove + ptr_pthread_attr_init field. Add ptr_pthread_attr_init_2_0 + and ptr_pthread_attr_init_2_1 fields. + * init.c (pthread_functions): Initialize ptr_pthread_attr_init_2_0 + and ptr_pthread_attr_init_2_1 instead of ptr_pthread_attr_init. + * forward.c (FORWARD4): Renamed from FORWARD3. Add export argument. + (FORWARD3): Define using FORWARD4. + (pthread_attr_init): Provide both @GLIBC_2.0 and @@GLIBC_2.1 + versions. + * pt-system.c: Remove duplicate stdlib.h include. + +2002-12-16 Ulrich Drepper <drepper@redhat.com> + + * sem_init.c: Define sem_init@GLIBC_2.0. + * sem_destroy.c: Define sem_destroy@GLIBC_2.0. + * sem_getvalue.c: Define sem_getvalue@GLIBC_2.0. + + * flockfile.c: Moved to... + * sysdeps/pthread/flockfile.c: ...here. New file. + * funlockfile.c: Moved to... + * sysdeps/pthread/funlockfile.c: ...here. New file. + * ftrylockfile.c: Moved to... + * sysdeps/pthread/ftrylockfile.c: ...here. New file. + +2002-12-16 Jakub Jelinek <jakub@redhat.com> + + * libc-cancellation.c: Guard both function with + #if !defined NOT_IN_libc. + * Makefile (libpthread-routines): Use ptw-, not pt- prefix for the + automatically provided pthread wrappers. + * pthreadP.h (LIBC_CANCEL_ASYNC, LIBC_CANCEL_RESET): Define to + CANCEL_* if IS_IN_libpthread and to dummy versions if not in libc + nor in libpthread. + * pt-open.c: Removed. + * pt-fcntl.c: Removed. + * pt-fsync.c: Removed. + * pt-lseek.c: Removed. + * pt-msgrcv.c: Removed. + * pt-msgsnd.c: Removed. + * pt-msync.c: Removed. + * pt-nanosleep.c: Removed. + * pt-open64.c: Removed. + * pt-pause.c: Removed. + * pt-pread.c: Removed. + * pt-pread64.c: Removed. + * pt-pwrite.c: Removed. + * pt-pwrite64.c: Removed. + * pt-read.c: Removed. + * pt-recv.c: Removed. + * pt-recvfrom.c: Removed. + * pt-recvmsg.c: Removed. + * pt-send.c: Removed. + * pt-sendto.c: Removed. + * pt-sigtimedwait.c: Removed. + * pt-sigwait.c: Removed. + * pt-wait.c: Removed. + * pt-waitpid.c: Removed. + * pt-write.c: Removed. + * pt-accept.c: Removed. + * pt-close.c: Removed. + * pt-connect.c: Removed. + * pt-lseek64.c: Removed. + * pt-sendmsg.c: Removed. + * pt-tcdrain.c: Removed. + +2002-12-15 Ulrich Drepper <drepper@redhat.com> + + * init.c (__pthread_initialize_minimal_internal): Renamed from + __pthread_initialize_minimal. Make old name an alias. This + converts a normal relocation into a relative relocation. + + * pt-fcntl.c (__fcntl): Use fcntl64 syscall, not fcntl. + + * Versions [libpthread: GLIBC_2.3.2]: Remove creat, poll, pselect, + readv, select, sigpause, sigsuspend, sigwaitinfo, waitid, writev. + * Makefile (libpthread-routines): Remove pt-creat, pt-poll, + pt-pselect, pt-readv, pt-select, pt-sigpause, pt-sigsuspend, + pt-sigwaitinfo, pt-waitid, and pt-writev. + * pt-creat.c: Removed. + * pt-poll.c: Removed. + * pt-pselect.c: Removed. + * pt-readv.c: Removed. + * pt-select.c: Removed. + * pt-sigpause.c: Removed. + * pt-sigsuspend.c: Removed. + * pt-sigwaitinfo.c: Removed. + * pt-waitid.c: Removed. + * pt-writev.c: Removed. + + * init.c (pthread_functions): New variable. + (__pthread_initialize_minimal): Pass pointer to pthread_functions + (or NULL) to __libc_pthread_init. + * forward.c: Rewrite to use __libc:pthread_functions array to get + function addresses. + * sysdeps/unix/sysv/linux/fork.h: Remove __libc_pthread_init + prototype. + * sysdeps/unix/sysv/linux/libc_pthread_init.c (__libc_pthread_init): + Take new parameter. Copy content of variable pointed to by it + to __libc_pthread_init. + + * pthreadP.h (struct pthread_functions): New type. + (__libc_pthread_init): Declare. + + * pthread_attr_destroy.c: Add namespace protected alias. + * pthread_attr_getdetachstate.c: Likewise. + * pthread_attr_getinheritsched.c: Likewise. + * pthread_attr_getschedparam.c: Likewise. + * pthread_attr_getschedpolicy.c: Likewise. + * pthread_attr_getscope.c: Likewise. + * pthread_attr_setdetachstate.c: Likewise. + * pthread_attr_setinheritsched.c: Likewise. + * pthread_attr_setschedparam.c: Likewise. + * pthread_attr_setschedpolicy.c: Likewise. + * pthread_attr_setscope.c: Likewise. + * pthread_cond_broadcast.c: Likewise. + * pthread_cond_destroy.c: Likewise. + * pthread_cond_init.c: Likewise. + * pthread_cond_signal.c: Likewise. + * pthread_cond_wait.c: Likewise. + * pthread_condattr_destroy.c: Likewise. + * pthread_condattr_init.c: Likewise. + * pthread_equal.c: Likewise. + * pthread_exit.c: Likewise. + * pthread_getschedparam.c: Likewise. + * pthread_self.c: Likewise. + * pthread_setcancelstate.c: Likewise. + * pthread_setschedparam.c: Likewise. + * pthread_mutex_destroy.c: Likewise. + * pthread_mutex_init.c: Likewise. + * pthreadP.h: Add prototypes for the aliases. + + * sysdeps/unix/sysv/linux/i386/createthread.c (create_thread): Set + multiple_threads member in correct TCB to 1. + + * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h: Define + SINGLE_THREAD_P. If in libc or libpthread examine multiple_thread + member of thread decriptor, otherwise return unconditionally 1. + +2002-12-14 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/pt-socket.S: Changes folded into the + regular Linux version. Remove file. + * sysdeps/unix/sysv/linux/connect.S: Likewise. Remove file. + * sysdeps/unix/sysv/linux/llseek.c: Likewise. Remove file. + * sysdeps/unix/sysv/linux/msgrcv.c: Likewise. Remove file. + * sysdeps/unix/sysv/linux/msgsnd.c: Likewise. Remove file. + * sysdeps/unix/sysv/linux/open64.c: Likewise. Remove file. + * sysdeps/unix/sysv/linux/poll.c: Likewise. Remove file. + * sysdeps/unix/sysv/linux/pread.c: Likewise. Remove file. + * sysdeps/unix/sysv/linux/pread64.c: Likewise. Remove file. + * sysdeps/unix/sysv/linux/pselect.c: Likewise. Remove file. + * sysdeps/unix/sysv/linux/pwrite.c: Likewise. Remove file. + * sysdeps/unix/sysv/linux/pwrite64.c: Likewise. Remove file. + * sysdeps/unix/sysv/linux/readv.c: Likewise. Remove file. + * sysdeps/unix/sysv/linux/recv.S: Likewise. Remove file. + * sysdeps/unix/sysv/linux/recvfrom.S: Likewise. Remove file. + * sysdeps/unix/sysv/linux/recvmsg.S: Likewise. Remove file. + * sysdeps/unix/sysv/linux/send.S: Likewise. Remove file. + * sysdeps/unix/sysv/linux/sendmsg.S: Likewise. Remove file. + * sysdeps/unix/sysv/linux/sendto.S: Likewise. Remove file. + * sysdeps/unix/sysv/linux/sigpause.c: Likewise. Remove file. + * sysdeps/unix/sysv/linux/sigsuspend.c: Likewise. Remove file. + * sysdeps/unix/sysv/linux/sigtimedwait.c: Likewise. Remove file. + * sysdeps/unix/sysv/linux/sigwait.c: Likewise. Remove file. + * sysdeps/unix/sysv/linux/sigwaitinfo.c: Likewise. Remove file. + * sysdeps/unix/sysv/linux/system.c: Likewise. Remove file. + * sysdeps/unix/sysv/linux/tcdrain.c: Likewise. Remove file. + * sysdeps/unix/sysv/linux/wait.c: Likewise. Remove file. + * sysdeps/unix/sysv/linux/waitid.c: Likewise. Remove file. + * sysdeps/unix/sysv/linux/waitpid.c: Likewise. Remove file. + * sysdeps/unix/sysv/linux/writev.c: Likewise. Remove file. + * sysdeps/unix/sysv/linux/i386/fcntl.c: Likewise. Remove file. + +2002-12-14 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h: New file. + * sysdeps/unix/sysv/linux/open.c: Removed. + * sysdeps/unix/sysv/linux/fsync.c: Removed. + * sysdeps/unix/sysv/linux/lseek.c: Removed. + * sysdeps/unix/sysv/linux/msync.c: Removed. + * sysdeps/unix/sysv/linux/read.c: Removed. + * sysdeps/unix/sysv/linux/close.c: Removed. + * sysdeps/unix/sysv/linux/creat.c: Removed. + * sysdeps/unix/sysv/linux/nanosleep.c: Removed. + * sysdeps/unix/sysv/linux/pause.c: Removed. + * sysdeps/unix/sysv/linux/select.c: Removed. + * sysdeps/unix/sysv/linux/write.c: Removed. + +2002-12-14 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/pt-socket.S: Check multiple_threads + element in TCB to see whether locking is needed. + + * sysdeps/unix/sysv/linux/libc_pthread_init.c: Check that + MULTIPLE_THREADS_OFFSET value is correct. + + * sysdeps/unix/sysv/linux/close.c: New file. + * sysdeps/unix/sysv/linux/connect.S: New file. + * sysdeps/unix/sysv/linux/creat.c: New file. + * sysdeps/unix/sysv/linux/fsync.c: New file. + * sysdeps/unix/sysv/linux/llseek.c: New file. + * sysdeps/unix/sysv/linux/lseek.c: New file. + * sysdeps/unix/sysv/linux/msgrcv.c: New file. + * sysdeps/unix/sysv/linux/msgsnd.c: New file. + * sysdeps/unix/sysv/linux/msync.c: New file. + * sysdeps/unix/sysv/linux/nanosleep.c: New file. + * sysdeps/unix/sysv/linux/open.c: New file. + * sysdeps/unix/sysv/linux/open64.c: New file. + * sysdeps/unix/sysv/linux/pause.c: New file. + * sysdeps/unix/sysv/linux/poll.c: New file. + * sysdeps/unix/sysv/linux/pread.c: New file. + * sysdeps/unix/sysv/linux/pread64.c: New file. + * sysdeps/unix/sysv/linux/pselect.c: New file. + * sysdeps/unix/sysv/linux/pwrite.c: New file. + * sysdeps/unix/sysv/linux/pwrite64.c: New file. + * sysdeps/unix/sysv/linux/readv.c: New file. + * sysdeps/unix/sysv/linux/recv.S: New file. + * sysdeps/unix/sysv/linux/recvfrom.S: New file. + * sysdeps/unix/sysv/linux/recvmsg.S: New file. + * sysdeps/unix/sysv/linux/select.c: New file. + * sysdeps/unix/sysv/linux/send.S: New file. + * sysdeps/unix/sysv/linux/sendmsg.S: New file. + * sysdeps/unix/sysv/linux/sendto.S: New file. + * sysdeps/unix/sysv/linux/sigpause.c: New file. + * sysdeps/unix/sysv/linux/sigsuspend.c: New file. + * sysdeps/unix/sysv/linux/sigtimedwait.c: New file. + * sysdeps/unix/sysv/linux/sigwait.c: New file. + * sysdeps/unix/sysv/linux/sigwaitinfo.c: New file. + * sysdeps/unix/sysv/linux/system.c: New file. + * sysdeps/unix/sysv/linux/tcdrain.c: New file. + * sysdeps/unix/sysv/linux/wait.c: New file. + * sysdeps/unix/sysv/linux/waitid.c: New file. + * sysdeps/unix/sysv/linux/waitpid.c: New file. + * sysdeps/unix/sysv/linux/writev.c: New file. + * sysdeps/unix/sysv/linux/i386/fcntl.c: New file. + + * pt-readv.c: Fix comment. + +2002-12-14 Jakub Jelinek <jakub@redhat.com> + + * tst-cleanup1.c: Include stdlib.h. + + * tst-cancel5.c: New test. + * Makefile (tests): Add tst-cancel5. + (tst-cancel5): Link against libc.so libpthread.so in that order. + +2002-12-13 Ulrich Drepper <drepper@redhat.com> + + * forward.c (test_loaded): Prevent recursive calls. + + * Makefile (routines): Add libc-cancellation. + * libc-cancellation.c: New file. + * descr.h (struct pthread): Add multiple_threads field. + * allocatestack.c (allocate_stack): Initialize multiple_header field of + new thread descriptor to 1. + * sysdeps/unix/sysv/linux/i386/createthread.c (create_thread): + Initialize multiple_thread field after successful thread creation. + * cancellation.c (__do_cancel): Move to pthreadP.h. + (__pthread_enable_asynccancel): Remove parameter from __do_cancel call. + (__pthread_disable_asynccancel): Add internal_function attribute. + * init.c (sigcancel_handler): Remove parameter from __do_cancel call. + * pthread_setcancelstate.c: Likewise. + * pthread_setcanceltype.c: Likewise. + * pthread_exit.c: Likewise. + * pthreadP.h (CANCELLATION_P): Likewise. + (__do_cancel): Define as static inline. + (LIBC_CANCEL_ASYNC, LIBC_CANCEL_RESET): New #defines. + (__libc_enable_asynccancel, __libc_disable_asynccancel): New + declarations. + * sysdeps/i386/tls.h (tcbhead_t): Add list and multiple_threads + fields. Define MULTIPLE_THREADS_OFFSET. + * sysdeps/pthread/bits/libc-lock.h: Remove __libc_locking_needed + declaration. + * sysdeps/unix/sysv/linux/accept.S: New file. + * sysdeps/unix/sysv/linux/read.c: New file. + * sysdeps/unix/sysv/linux/write.c: New file. + * sysdeps/unix/sysv/linux/i386/pt-socket.S: New file. + * sysdeps/unix/sysv/linux/libc_pthread_init.c: Remove definition and + initialization of __libc_locking_needed. + * sysdeps/unix/sysv/linux/i386/lowlevellock.h: Don't use + __libc_locking_needed, use multiple_threads field in TCB. + * sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S: Likewise. + +2002-12-12 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/i686/libc-lowlevellock.S: Use i486 + version. + * sysdeps/unix/sysv/linux/i386/i586/libc-lowlevellock.S: Likewise. + + * sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S: Correct + access to __libc_locking_needed for PIC. + +2002-12-12 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/pthread/bits/libc-lock.h (__libc_locking_needed): Only + declare for libc.so. + (__libc_lock_init, __libc_lock_init_recursive): Change into comma + expression. + (__libc_lock_lock): Put into statement expression. + (__libc_lock_unlock): Remove trailing semicolon. + * sysdeps/unix/sysv/linux/fork.h (__libc_pthread_init): Fix typo. + +2002-12-12 Roland McGrath <roland@redhat.com> + + * sysdeps/unix/sysv/linux/i386/lowlevellock.h: Use asm operand with + "m" constraint to refer to __libc_locking_needed. Declare it here. + +2002-12-12 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/fork-gen.c: Renamed to... + * sysdeps/unix/sysv/linux/libc_pthread_init.c: ...this. + Initialize __libc_locking_needed. + * init.c (__pthread_initialize_minimal): Call __libc_pthread_init + instead of __register_pthread_fork_handler. + * sysdeps/pthread/bits/libc-lock.h: Declare __libc_locking_needed. + * sysdeps/unix/sysv/linux/Makefile (sysdep_routimes): Replace + fork-gen with libc_pthread_init. + * sysdeps/unix/sysv/linux/Versions: Use __libc_pthread_init instead + of __register_pthread_fork_handler. + * sysdeps/unix/sysv/linux/fork.h: Declare __libc_pthread_init instead + of __register_pthread_fork_handler. + * sysdeps/unix/sysv/linux/i386/lowlevellock.h: Use + __libc_locking_needed to determine whether lock prefix can be avoided. + * sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S: Likewise. + +2002-12-11 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add tst-cleanup1. + * tst-cleanup1.c: New file. + * cancellation.c (__cleanup_thread): Removed. + (__do_cancel): Remove call to __cleanup_thread. + * pthreadP.h: Remove __cleanup_thread prorotype. + + * sysdeps/pthread/bits/libc-lock.h (__libc_cleanup_region_start): + Remember function and argument even if cancellation handler + function is not available. + (__libc_cleanup_region_end): Execute registered function directly if + pthread functions are not available. + (__libc_cleanup_end): Likewise. + + * init.c (__pthread_initialize_minimal): Fix initialization in + static lib by preventing gcc from being too clever. + +2002-12-10 Ulrich Drepper <drepper@redhat.com> + + * init.c (__pthread_initialize_minimal): Remove unneccesary + sigaddset call. + + * Makefile (tests): We can run tst-locale2 now. + +2002-12-09 Ulrich Drepper <drepper@redhat.com> + + * Versions: Remove duplicated sigwait entry. + +2002-12-08 Ulrich Drepper <drepper@redhat.com> + + * pthreadP.h: Enable pthread_cleanup_{push,pop} optimizations only + inside libpthread. + + * pt-fcntl.c (__fcntl): Initialize oldtype to avoid warning. + + * pthreadP.h: Declare __pthread_enable_asynccancel and + __pthread_disable_asynccancel. + (CANCEL_ASYNC): Use __pthread_enable_asynccancel. + (CANCEL_RESET): Use __pthread_disable_asynccancel. + * cancellation.c (__pthread_enable_asynccancel): New function. + (__pthread_disable_asynccancel): New function. + * pt-accept.c: Adjust for CANCEL_ASYNC and CANCEL_RESET change. + * pt-close.c: Likewise. + * pt-connect.c: Likewise. + * pt-creat.c: Likewise. + * pt-fcntl.c: Likewise. + * pt-fsync.c: Likewise. + * pt-lseek.c: Likewise. + * pt-lseek64.c: Likewise. + * pt-msgrcv.c: Likewise. + * pt-msgsnd.c: Likewise. + * pt-msync.c: Likewise. + * pt-nanosleep.c: Likewise. + * pt-open.c: Likewise. + * pt-open64.c: Likewise. + * pt-pause.c: Likewise. + * pt-poll.c: Likewise. + * pt-pread.c: Likewise. + * pt-pread64.c: Likewise. + * pt-pselect.c: Likewise. + * pt-pwrite.c: Likewise. + * pt-pwrite64.c: Likewise. + * pt-read.c: Likewise. + * pt-readv.c: Likewise. + * pt-recv.c: Likewise. + * pt-recvfrom.c: Likewise. + * pt-recvmsg.c: Likewise. + * pt-select.c: Likewise. + * pt-send.c: Likewise. + * pt-sendmsg.c: Likewise. + * pt-sendto.c: Likewise. + * pt-sigpause.c: Likewise. + * pt-sigsuspend.c: Likewise. + * pt-sigtimedwait.c: Likewise. + * pt-sigwait.c: Likewise. + * pt-sigwaitinfo.c: Likewise. + * pt-system.c: Likewise. + * pt-tcdrain.c: Likewise. + * pt-wait.c: Likewise. + * pt-waitid.c: Likewise. + * pt-waitpid.c: Likewise. + * pt-write.c: Likewise. + * pt-writev.c: Likewise. + * pthread_join.c: Likewise. + * pthread_timedjoin.c: Likewise. + + * pt-sigpause.c (sigsuspend): Call __sigsuspend. + (__xpg_sigpause): New function. + * Versions (libpthread:GLIBC_2.3.2): Add __xpg_sigpause. + +2002-12-07 Ulrich Drepper <drepper@redhat.com> + + * Makefile (CFLAGS-ftrylockfile.c): Add -D_IO_MTSAFE_IO. + + * cleanup.c: Move declarations of _GI_pthread_cleanup_push and + _GI_pthread_cleanup_pop to pthreadP.h. + + * ftrylockfile.c: Use _IO_lock_trylock instead of + pthread_mutex_trylock. + + * pthreadP.h (CANCEL_ASYNC): Use __pthread_setcanceltype. + (CANCEL_RESET): Likewise. + (__pthread_setcanceltype_): Declare. + (__pthread_mutex_lock_internal): Declare. + (__pthread_mutex_unlock_internal): Declare. + (__pthread_once_internal): Declare. + (pthread_cleanup_push): Redefine using _GI_pthread_cleanup_push. + (pthread_cleanup_pop): Redefine using _GI_pthread_cleanup_pop. + + * pthread_cond_timedwait.c: Use INTUSE is calls to pthread_mutex_lock + and pthread_mutex_unlock. + * pthread_cond_wait.c: Likewise. + * pthread_mutex_lock.c: Use INTDEF to define alias if needed. + * pthread_mutex_unlock.c: Likewise. + + * pthread_setcanceltype.c: Add additional alias + __pthread_setcanceltype. + + * sem_unlink.c (sem_unlink): Use __pthread_once with INTDEF. + * sem_open.c (sem_open): Likewise. + Use __libc_open, __libc_write, and __libc_close instead of + open, write, and close respectively. + + * sysdeps/pthread/bits/libc-lock.h (__libc_lock_trylock_internal): + Rewrite as statement expression since it must return a value. + + * pthread_cancel.c: Use __pthread_kill instead of pthread_kill. + * sysdeps/unix/sysv/linux/pthread_kill.c: Define additional alias + __pthread_kill. + + * sysdeps/unix/sysv/linux/i386/pthread_once.S: Define additional + alias __pthread_once_internal. + + * sysdeps/unix/sysv/linux/raise.c: Use libc_hidden_def for raise. + +2002-12-06 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add tst-stdio1 and tst-stdio2. + * tst-stdio1.c: New file. + * tst-stdio2.c: New file. + + * init.c (__pthread_initialize_minimal): Correct INIT_LIST_HEAD use. + + * Makefile (tests): Comment out tst-locale2 for now. + (CFLAGS-flockfile.c, CFLAGS-funlockfile.c): Define to -D_IO_MTSAFE_IO. + + * sysdeps/unix/sysv/linux/Makefile: Define CFLAGS-fork.c to + -D_IO_MTSAFE_IO. + * sysdeps/unix/sysv/linux/fork.c: Include <bits/stdio-lock.h>. + Use _IO_lock_init instead of explicit assignment. + + * sysdeps/pthread/bits/libc-lock.h: Define __rtld_lock_* macros. + Define __libc_lock_* and __libc_lock_recursive macros with + lowlevellock macros, not pthread mutexes. + + * flockfile.c: Include <bits/stdio-lock.h>. Use _IO_lock_lock instead + of pthread_mutex_lock. + * funlockfile.c: Include <bits/stdio-lock.h>. Use _IO_lock_unlock + instead of pthread_mutex_unlock. + +2002-12-06 Roland McGrath <roland@redhat.com> + + * allocatestack.c (__stack_user): Use uninitialized defn. + * init.c (__pthread_initialize_minimal): Initialize it here. + +2002-12-05 Roland McGrath <roland@redhat.com> + + * sysdeps/i386/tls.h (TLS_INIT_TP): Make it return zero or an error + string. + * sysdeps/x86_64/tls.h (TLS_INIT_TP): Likewise. + + * sysdeps/unix/sysv/linux/i386/createthread.c (create_thread): Add + missing & here too. + +2002-12-05 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/Makefile (sysdep_routines): Remove + lowlevellock. + * sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S: New file. + * sysdeps/unix/sysv/linux/i386/i586/libc-lowlevellock.S: New file. + * sysdeps/unix/sysv/linux/i386/i686/libc-lowlevellock.S: New file. + * sysdeps/pthread/bits/libc-lock.h: Use lowlevellock implementation + for __libc_lock_* macros. + * Makefile (routines): Add libc-lowlevellock. + +2002-10-09 Roland McGrath <roland@redhat.com> + + * sysdeps/pthread/bits/libc-lock.h (__libc_maybe_call): New macro. + Under [__PIC__], call the function via the pointer fetched for + comparison rather than a call by name that uses the PLT. + (__libc_lock_init, __libc_rwlock_init, __libc_lock_fini) + (__libc_rwlock_fini, __libc_lock_lock, __libc_rwlock_rdlock) + (__libc_rwlock_wrlock, __libc_lock_trylock, __libc_rwlock_tryrdlock) + (__libc_rwlock_trywrlock, __libc_lock_unlock, __libc_rwlock_unlock) + (__libc_key_create, __libc_getspecific, __libc_setspecific): Use it. + +2002-12-04 Roland McGrath <roland@redhat.com> + + * forward.c (pthread_self): Use FORWARD3 macro to correct return type. + + * sysdeps/i386/td_ta_map_lwp2thr.c: Moved from ../nptl_db. + * sysdeps/generic/td_ta_map_lwp2thr.c: New file. + + * pthread_create.c (start_thread): Add missing & on __nptl_last_event. + +2002-12-04 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h: Make pthread_t + a completely opaque, non-integer type. + * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: Likewise. + +2002-12-05 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/i386/tls.h: Include stdlib.h. + * sysdeps/x86_64/tls.h: Likewise. + +2002-12-04 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add tst-locale2. + (tests-static): Likewise. + * tst-locale2.c: New file. + + * sysdeps/unix/sysv/linux/i386/lowlevellock.h: Mark asms as + volatile and add memory clobbers to lock operations. + +2002-12-03 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/i386/i686/bits/atomic.h: Use i486 version. + * sysdeps/i386/i486/bits/atomic.h: New file. + * sysdeps/i386/i586/bits/atomic.h: New file. + * sysdeps/i386/i686/pthread_spin_trylock.S: Define HAVE_CMOV and + include i486 version. + * sysdeps/i386/i486/pthread_spin_trylock.S: New file. + * sysdeps/i386/i586/pthread_spin_trylock.S: New file. + Patch by Marijn Ros <marijn@mad.scientist.com>. + + * allocatestack.c (get_cached_stack): Don't crash if we first + found a stack with a larger size then needed. + Reported by Hui Huang <hui.huang@sun.com>. + + * Makefile (tests): Add tst-sysconf. + * tst-sysconf.c: New file. + + * sysdeps/unix/sysv/linux/bits/local_lim.h: Undefine + PTHREAD_THREADS_MAX. + +2002-12-02 Roland McGrath <roland@redhat.com> + + * pthreadP.h (__stack_user, __nptl_create_event, __nptl_death_event): + Declare using hidden_proto instead of attribute_hidden, so there are + non-.hidden static symbols for gdb to find. + (__pthread_keys): Likewise. + * events.c (__nptl_create_event, __nptl_death_event): Add hidden_def. + * allocatestack.c (__stack_user): Likewise. + * pthread_create.c (__pthread_keys): Likewise. + (__nptl_threads_events, __nptl_last_event): Make these static instead + of hidden. + * pthread_key_create.c (__pthread_pthread_keys_max, + __pthread_pthread_key_2ndlevel_size): Renamed from __linuxthreads_*. + +2002-12-02 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add tst-locale1. If buid-static is yes link + statically. + * tst-locale1.c: New file. + + * pthread_cond_timedwait.c: Include <stdlib.h>. + + * Makefile (tests): Add tst-fork2 and tst-fork3. + * tst-fork2.c: New file. + * tst-fork3.c: New file. + +2002-11-28 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/bits/posix_opt.h: New file. + + * sysdeps/unix/sysv/linux/bits/posix_opt.h: Define macros which + require it to 200112L. + + * sysdeps/unix/sysv/linux/i386/i486/lowlevelrwlock.S: Use cmov + instruction only if HAVE_CMOV is defined. + * sysdeps/unix/sysv/linux/i386/i686/lowlevelrwlock.S: Define HAVE_CMOV. + + * sysdeps/unix/sysv/linux/x86_64/bits/semaphore.h: New file. + + * sysdeps/unix/sysv/linux/x86_64/pthread_once.S: New file. + + * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: New file. + + * sysdeps/unix/sysv/linux/x86_64/pt-vfork.S: New file. + +2002-11-27 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/x86_64/bits/atomic.h: New file. + + * sysdeps/i386/i686/bits/atomic.h: Fix asm syntax for 8- and + 16-bit operations. + + * sysdeps/unix/sysv/linux/raise.c (raise): Use INTERNAL_SYSCALL if + possible since gettid cannot fail. + + * sysdeps/x86_64/pthreaddef.h: New file. + + * sysdeps/i386/pthreaddef.h (gettid): Removed. + + * sysdeps/x86_64/pthread_spin_init.c: New file. + * sysdeps/x86_64/pthread_spin_lock.c: New file. + * sysdeps/x86_64/pthread_spin_trylock.c: New file. + * sysdeps/x86_64/pthread_spin_unlock.c: New file. + + * sysdeps/i386/i686/pthread_spin_trylock.S (pthread_spin_trylock): + Add missing lock prefix. Minute optimization. + + * tst-spin2.c (main): Also check successful trylock call. + + * sysdeps/pthread/pthread_sigmask.c (pthread_sigmask): Use correct + syscall. Fix typo in case INTERNAL_SYSCALL is not used. + + * sysdeps/i386/pthread_spin_destroy.c: Moved to... + * sysdeps/pthread/pthread_spin_destroy.c: ...here. New file. + + * sysdeps/i386/pthread_sigmask.c: Removed. Use the generic code. + * sysdeps/pthread/pthread_sigmask.c (pthread_sigmask): Return correct + value in case of an error. Add support for INTERNAL_SYSCALL. + + * sysdeps/i386/pthread_sigmask.c (pthread_sigmask): Return correct + value in case of an error. + + * sysdeps/x86_64/tls.h: New file. + +2002-11-26 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/i386/tls.h (THREAD_GETMEM_NC): Change interface. It now + takes the array member name and the index as parameters. + (THREAD_SETMEM_NC): Likewise. + * pthread_getspecific.c: Use new THREAD_GETMEM_NC interface. + * pthread_setspecific.c: Use new THREAD_GETMEM_NC and THREAD_SETMEM_NC + interfaces. + + * sysdeps/i386/tls.h (THREAD_SETMEM): Use size of member element + to decide which code to use. + (THREAD_SETMEM_NC): Likewise. + + * allocatestack.c (queue_stack): Don't remove stack from list here. + Do it in the caller. Correct condition to prematurely terminate + loop to free stacks. + (__deallocate_stack): Remove stack from list here. + +2002-11-26 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add tst-stack1. + * tst-stack1.c: New file. + + * allocatestack.c (allocate_stack): Initialize the TCB on a user + provided stack. + + * pthread_attr_getstack.c: Return bottom of the thread area. + +2002-11-25 Ulrich Drepper <drepper@redhat.com> + + * Makefile (libpthread-routines): Add pt-allocrtsig and + pthread_kill_other_threads. + * pt-allocrtsig.c: New file. + * pthread_kill_other_threads.c: New file. + * sysdeps/unix/sysv/linux/allocrtsig.c: Add additional aliases for + all three functions. + * sysdeps/unix/sysv/linux/Makefile (sysdep_routines): Remove + allocrtsig. + * sysdeps/unix/sysv/linux/Versions (libc:GLIBC_PRIVATE): Export + __libc_current_sigrtmin_private, __libc_current_sigrtmax_private, + and __libc_allocate_rtsig_private. + * Versions (libpthread): Export pthread_kill_other_threads_np, + __libc_current_sigrtmin, and __libc_current_sigrtmax. + +2002-11-24 Ulrich Drepper <drepper@redhat.com> + + * allocatestack.c (allocate_stack): stackaddr in attribute points to + the end of the stack. Adjust computations. + When mprotect call fails dequeue stack and free it. + * pthread_attr_setstack.c: Store top of the stack in stackaddr + attribute. + * pthread_getattr_np.c: Likewise. + + * descr.h (IS_DETACHED): Add some more parenthesis to prevent + surprises. + +2002-11-23 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/pthread.h (pthread_self): __THROW must come before + attribute definitions. Patch by Luca Barbieri <ldb@ldb.ods.org>. + +2002-11-22 Ulrich Drepper <drepper@redhat.com> + + * pthread_getspecific.c: Optimize access to first 2nd-level array. + * pthread_setspecific.c: Likewise. + +2002-11-21 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/createthread.c: Remove CLONE_ flags + definitions. Get them from the official place. + * sysdeps/unix/sysv/linux/i386/fork.c: Likewise. + + * sysdeps/unix/sysv/linux/i386/createthread.c: Update CLONE_* flags. + Use new CLONE_ flags in clone() calls. + + * sysdeps/unix/sysv/linux/fork.c: Use ARCH_FORK to actually fork. + * sysdeps/unix/sysv/linux/i386/fork.c: New file. + + * Versions: Add pthread_* functions for libc. + * forward.c: New file. + + * sysdeps/pthread/Makefile (libpthread-sysdeps_routines): Add + errno-loc. + * herrno.c: New file. + * res.c: New file. + + * Makefile (libpthread-routines): Remove sem_post, sem_wait, + sem_trywait, and sem_timedwait. Add herrno and res. + * sem_init.c: Don't initialize lock and waiters members. + * sem_open.c: Likewise. + * sem_post.c: Removed. + * sem_wait.c: Removed. + * sem_trywait.c: Removed. + * sem_timedwait.c: Removed. + * sysdeps/unix/sysv/linux/i386/i486/lowlevelsem.S: Complete rewrite. + Includes full implementations of sem_post, sem_wait, sem_trywait, + and sem_timedwait. + * sysdeps/unix/sysv/linux/i386/lowlevelsem.h (lll_sem_post): Adjust + for new implementation. + * sysdeps/unix/sysv/linux/internaltypes.h (struct sem): Remove lock + and waiters fields. + + * tst-sem3.c: Improve error message. + * tst-signal3.c: Likewise. + + * init.c (__pthread_initialize_minimal): Use set_tid_address syscall + to tell the kernel about the termination futex and to initialize tid + member. Don't initialize main_thread. + * descr.h (struct pthread): Remove main_thread member. + * cancelllation.c (__do_cancel): Remove code handling main thread. + The main thread is not special anymore. + + * allocatestack.c (__reclaim_stacks): Mark stacks as unused. Add + size of the stacks to stack_cache_actsize. + + * pt-readv.c: Add missing "defined". + * pt-sigwait.c: Likewise. + * pt-writev.c: Likewise. + +2002-11-09 Ulrich Drepper <drepper@redhat.com> + + * Versions: Export __connect from libpthread. + Patch by Luca Barbieri <ldb@ldb.ods.org>. + + * Makefile (libpthread-routines): Add pt-raise. + * sysdeps/unix/sysv/linux/raise.c: New file. + * sysdeps/unix/sysv/linux/pt-raise.c: New file. + * sysdeps/generic/pt-raise.c: New file. + + * pthread_cond_init.c: Initialize all data elements of the condvar + structure. Patch by Luca Barbieri <ldb@ldb.ods.org>. + + * pthread_attr_init.c: Actually implement 2.0 compatibility version. + * pthread_create.c: Likewise. + + * Makefile (tests): Add tst-key1, tst-key2, tst-key3. + * tst-key1.c: New file. + * tst-key2.c: New file. + * tst-key3.c: New file. + + * Versions: Export pthread_detach for version GLIBC_2.0. + Reported by Saurabh Desai <sdesai@austin.ibm.com>. + +2002-11-08 Ulrich Drepper <drepper@redhat.com> + + * pthread_key_create.c: Terminate search after an unused key was found. + Patch by Luca Barbieri <ldb@ldb.ods.org>. + + * sysdeps/unix/sysv/linux/i386/pthread_once.S: Return zero. + Patch by Luca Barbieri <ldb@ldb.ods.org>. + +2002-10-10 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/i486/lowlevelsem.S: Use slow generic + dynamic lookup for errno in PIC. + + * allocatestack.c (get_cached_stack): Rearrange code slightly to + release the stack lock as soon as possible. + Call _dl_allocate_tls_init for TCB from the cache to re-initialize + the static TLS block. + (allocate_stack): Call _dl_allocate_tls_init for user-provided stack. + + * cancellation.c: Renamed from cancelation.c. + * Makefile: Adjust accordingly. + * pthreadP.h (CANCELLATION_P): Renamed from CANCELATION_P. + * cleanup_defer.c: Use CANCELLATION_P. + * pthread_testcancel.c: Likewise. + * descr.h: Fix spelling in comments. + * init.c: Likewise. + * pthread_getattr_np.c: Likewise. + * pthread_getschedparam.c: Likewise. + * pthread_setschedparam.c: Likewise. + * Versions: Likewise. + + * pt-pselect.c: New file. + * Makefile (libpthread-routines): Add pt-pselect. + * Versions: Add pselect. + + * tst-cancel4.c: New file. + * Makefile (tests): Add tst-cancel4. + +2002-10-09 Ulrich Drepper <drepper@redhat.com> + + * pthread_mutex_lock.c: Always record lock ownership. + * pthread_mutex_timedlock.c: Likewise. + * pthread_mutex_trylock.c: Likewise. + + * pt-readv.c: New file. + * pt-writev.c: New file. + * pt-creat.c: New file. + * pt-msgrcv.c: New file. + * pt-msgsnd.c: New file. + * pt-poll.c: New file. + * pt-select.c: New file. + * pt-sigpause.c: New file. + * pt-sigsuspend.c: New file. + * pt-sigwait.c: New file. + * pt-sigwaitinfo.c: New file. + * pt-waitid.c: New file. + * Makefile (libpthread-routines): Add pt-readv, pt-writev, pt-creat, + pt-msgrcv, pt-msgsnd, pt-poll, pt-select, pt-sigpause, pt-sigsuspend, + pt-sigwait, pt-sigwaitinfo, and pt-waitid. + * Versions: Add all the new functions. + + * tst-exit1.c: New file. + * Makefile (tests): Add tst-exit1. + + * sem_timedwait.c: Minor optimization for more optimal fastpath. + +2002-10-08 Ulrich Drepper <drepper@redhat.com> + + * pt-fcntl.c: Only enable asynchronous cancellation for F_SETLKW. + + * pthread_join.c: Enable asynchronous cancellation around lll_wait_tid + call. pthread_join is an official cancellation point. + * pthread_timedjoin.c: Likewise. + + * pthread_cond_wait.c: Revert order in which internal lock are dropped + and the condvar's mutex are retrieved. + * pthread_cond_timedwait.c: Likewise. + Reported by dice@saros.East.Sun.COM. + +2002-10-07 Ulrich Drepper <drepper@redhat.com> + + * pthreadP.h: Cut out all type definitions and move them... + * sysdeps/unix/sysv/linux/internaltypes.h: ...here. New file. + * pthreadP.h: Include <internaltypes.h>. + + * sysdeps/unix/sysv/linux/i386/lowlevelsem.h (lll_sem_post): Little + performance tweaks. + + * sem_trywait.c: Shuffle #includes around to get right order. + * sem_timedwait.c: Likewise. + * sem_post.c: Likewise. + * sem_wait.c: Likewise. + + * nptl 0.3 released. + + * Makefile (tests): Add tst-signal3. + * tst-signal3.c: New file. + +2002-10-05 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/lowlevelsem.h: Tell the compiler that + the asms modify the sem object. + (__lll_sem_timedwait): Now takes struct sem* as first parameter. + + * sysdeps/unix/sysv/linux/i386/bits/semaphore.h (sem_t): Don't expose + the actual members. + * pthreadP.h (struct sem): New type. Actual semaphore type. + * semaphoreP.h: Include pthreadP.h. + * sem_getvalue.c: Adjust to sem_t change. + * sem_init.c: Likewise. + * sem_open.c: Likewise. + * sem_post.c: Likewise. + * sem_timedwait.c: Likewise. + * sem_trywait.c: Likewise. + * sem_wait.c: Likewise. + +2002-10-04 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add tst-basic2, tst-exec1, tst-exec3, tst-exec3. + * tst-basic2.c: New file. + * tst-exec1.c: New file. + * tst-exec2.c: New file. + * tst-exec3.c: New file. + + * tst-fork1.c: Remove extra */. + + * nptl 0.2 released. The API for IA-32 is complete. diff --git a/libpthread/nptl/Makefile b/libpthread/nptl/Makefile new file mode 100644 index 000000000..f9100219a --- /dev/null +++ b/libpthread/nptl/Makefile @@ -0,0 +1,13 @@ +# Makefile for uClibc +# +# Copyright (C) 2000-2005 Erik Andersen <andersen@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +top_srcdir=../../ +top_builddir=../../ +include $(top_builddir)Rules.mak +all: libs +include Makefile.in +include $(top_srcdir)Makerules diff --git a/libpthread/nptl/Makefile.in b/libpthread/nptl/Makefile.in new file mode 100644 index 000000000..9b4ba512b --- /dev/null +++ b/libpthread/nptl/Makefile.in @@ -0,0 +1,334 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2005-2006 Steven J. Hill <sjhill@realitydiluted.com> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +subdirs += libpthread/nptl/sysdeps/$(TARGET_ARCH) \ + libpthread/nptl/sysdeps/unix/sysv/linux \ + libpthread/nptl/sysdeps/pthread + +libpthread-routines = init vars events version \ + pthread_create pthread_exit pthread_detach \ + pthread_join pthread_tryjoin pthread_timedjoin \ + pthread_self pthread_equal pthread_yield \ + pthread_getconcurrency pthread_setconcurrency \ + pthread_getschedparam pthread_setschedparam \ + pthread_setschedprio \ + pthread_attr_init pthread_attr_destroy \ + pthread_attr_getdetachstate pthread_attr_setdetachstate \ + pthread_attr_getguardsize pthread_attr_setguardsize \ + pthread_attr_getschedparam pthread_attr_setschedparam \ + pthread_attr_getschedpolicy pthread_attr_setschedpolicy \ + pthread_attr_getinheritsched \ + pthread_attr_setinheritsched \ + pthread_attr_getscope pthread_attr_setscope \ + pthread_attr_getstackaddr pthread_attr_setstackaddr \ + pthread_attr_getstacksize pthread_attr_setstacksize \ + pthread_attr_getstack pthread_attr_setstack \ + pthread_getattr_np \ + pthread_mutex_init pthread_mutex_destroy \ + pthread_mutex_lock pthread_mutex_trylock \ + pthread_mutex_timedlock pthread_mutex_unlock \ + pthread_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 \ + pthread_condattr_init pthread_condattr_destroy \ + pthread_condattr_getpshared pthread_condattr_setpshared \ + pthread_condattr_getclock pthread_condattr_setclock \ + pthread_spin_init pthread_spin_destroy \ + pthread_spin_lock pthread_spin_trylock \ + pthread_spin_unlock \ + pthread_barrier_init pthread_barrier_destroy \ + pthread_barrier_wait \ + pthread_barrierattr_init pthread_barrierattr_destroy \ + pthread_barrierattr_getpshared \ + pthread_barrierattr_setpshared \ + pthread_key_create pthread_key_delete \ + pthread_getspecific pthread_setspecific \ + pthread_sigmask pthread_kill \ + pthread_cancel pthread_testcancel \ + pthread_setcancelstate pthread_setcanceltype \ + pthread_once \ + pthread_atfork \ + pthread_getcpuclockid \ + pthread_clock_gettime pthread_clock_settime \ + sem_init sem_destroy \ + sem_open sem_close sem_unlink \ + sem_getvalue \ + sem_wait sem_trywait sem_timedwait sem_post \ + cleanup cleanup_defer cleanup_compat \ + cleanup_defer_compat unwind \ + pt-longjmp pt-cleanup\ + cancellation \ + lowlevellock \ + pt-vfork \ + ptw-write ptw-read ptw-close ptw-fcntl ptw-accept \ + ptw-connect ptw-recv ptw-recvfrom ptw-recvmsg ptw-send \ + ptw-sendmsg ptw-sendto ptw-fsync ptw-lseek ptw-llseek \ + ptw-msync ptw-nanosleep ptw-open ptw-open64 ptw-pause \ + ptw-pread ptw-pread64 ptw-pwrite ptw-pwrite64 \ + ptw-tcdrain ptw-wait ptw-waitpid ptw-msgrcv ptw-msgsnd \ + ptw-sigwait \ + pt-raise pt-system \ + flockfile ftrylockfile funlockfile \ + sigaction \ + herrno res \ + pthread_kill_other_threads \ + pthread_getaffinity pthread_setaffinity \ + pthread_attr_getaffinity pthread_attr_setaffinity \ + cleanup_routine unwind-forcedunwind + +libpthread-shared-only-routines = version pt-allocrtsig unwind-forcedunwind + +CFLAGS-pthread_atfork.c = -DNOT_IN_libc + +# Since cancellation handling is in large parts handled using exceptions +# we have to compile some files with exception handling enabled, some +# even with asynchronous unwind tables. + +# init.c contains sigcancel_handler(). +CFLAGS-init.c = -fexceptions -fasynchronous-unwind-tables +# The unwind code itself, +CFLAGS-unwind.c = -fexceptions +CFLAGS-unwind-forcedunwind.c = -fexceptions -fasynchronous-unwind-tables + +# The following three functions must be async-cancel safe. +CFLAGS-pthread_cancel.c = -fexceptions -fasynchronous-unwind-tables +CFLAGS-pthread_setcancelstate.c = -fexceptions -fasynchronous-unwind-tables +CFLAGS-pthread_setcanceltype.c = -fexceptions -fasynchronous-unwind-tables + +# These are internal functions which similar functionality as setcancelstate +# and setcanceltype. +CFLAGS-cancellation.c = -fasynchronous-unwind-tables +CFLAGS-libc-cancellation.c = -fasynchronous-unwind-tables + +# Calling pthread_exit() must cause the registered cancel handlers to +# be executed. Therefore exceptions have to be thrown through this +# function. +CFLAGS-pthread_exit.c = -fexceptions + +# Among others, __pthread_unwind is forwarded. This function must handle +# exceptions. +CFLAGS-forward.c = -fexceptions + +# The following are cancellation points. Some of the functions can +# block and therefore temporarily enable asynchronous cancellation. +# Those must be compiled asynchronous unwind tables. +CFLAGS-pthread_testcancel.c = -fexceptions +CFLAGS-pthread_join.c = -fexceptions -fasynchronous-unwind-tables +CFLAGS-pthread_timedjoin.c = -fexceptions -fasynchronous-unwind-tables +CFLAGS-pthread_once.c = $(uses-callbacks) -fexceptions \ + -fasynchronous-unwind-tables +CFLAGS-pthread_cond_wait.c = -fexceptions -fasynchronous-unwind-tables +CFLAGS-pthread_cond_timedwait.c = -fexceptions -fasynchronous-unwind-tables +CFLAGS-sem_wait.c = -fexceptions -fasynchronous-unwind-tables +CFLAGS-sem_timedwait.c = -fexceptions -fasynchronous-unwind-tables + +# These are the function wrappers we have to duplicate here. +CFLAGS-fcntl.c = -fexceptions -fasynchronous-unwind-tables +CFLAGS-lockf.c = -fexceptions +CFLAGS-pread.c = -fexceptions -fasynchronous-unwind-tables +CFLAGS-pread64.c = -fexceptions -fasynchronous-unwind-tables +CFLAGS-pwrite.c = -fexceptions -fasynchronous-unwind-tables +CFLAGS-pwrite64.c = -fexceptions -fasynchronous-unwind-tables +CFLAGS-wait.c = -fexceptions -fasynchronous-unwind-tables +CFLAGS-waitpid.c = -fexceptions -fasynchronous-unwind-tables +CFLAGS-sigwait.c = -fexceptions -fasynchronous-unwind-tables +CFLAGS-msgrcv.c = -fexceptions -fasynchronous-unwind-tables +CFLAGS-msgsnd.c = -fexceptions -fasynchronous-unwind-tables +CFLAGS-tcdrain.c = -fexceptions -fasynchronous-unwind-tables + +CFLAGS-pt-system.c = -fexceptions -I./libc/stdlib + +# +# The rest of this file is uClibc specific. +# +CFLAGS-pthread_barrier_init.c = -D_GNU_SOURCE +CFLAGS-pthread_barrier_destroy.c = -D_GNU_SOURCE +CFLAGS-pthread_barrierattr_init.c = -D_GNU_SOURCE +CFLAGS-pthread_barrierattr_destroy.c = -D_GNU_SOURCE +CFLAGS-pthread_barrierattr_getpshared.c = -D_GNU_SOURCE +CFLAGS-pthread_barrierattr_setpshared.c = -D_GNU_SOURCE +CFLAGS-sem_open.c = -D_GNU_SOURCE + +CFLAGS-nptl = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 $(SSP_ALL_CFLAGS) + +CFLAGS-OMIT-alloca_cutoff.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +CFLAGS-OMIT-forward.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +CFLAGS-OMIT-libc-lowlevelock.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +CFLAGS-OMIT-libc-cancellation.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 + +libpthread-os-routines = pthread_yield +libpthread-misc-routines = pthread_rwlock_rdlock pthread_rwlock_timedrdlock \ + pthread_rwlock_wrlock pthread_rwlock_timedwrlock \ + pthread_rwlock_unlock pthread_cond_wait \ + pthread_cond_timedwait pthread_cond_signal \ + pthread_cond_broadcast pthread_spin_init \ + pthread_spin_destroy pthread_spin_lock \ + pthread_spin_trylock pthread_spin_unlock \ + pthread_barrier_wait pthread_sigmask \ + pthread_kill pthread_once \ + pthread_getcpuclockid sem_wait \ + sem_trywait sem_timedwait \ + sem_post pt-longjmp \ + lowlevellock pt-vfork \ + ptw-close ptw-read ptw-write \ + ptw-fcntl ptw-accept ptw-connect \ + ptw-recv ptw-recvfrom ptw-recvmsg \ + ptw-send ptw-sendmsg ptw-sendto \ + ptw-fsync ptw-lseek ptw-llseek \ + ptw-msync ptw-nanosleep ptw-open \ + ptw-open64 ptw-pause ptw-pread \ + ptw-pread64 ptw-pwrite ptw-pwrite64 \ + ptw-tcdrain ptw-wait ptw-waitpid \ + ptw-msgrcv ptw-msgsnd ptw-sigwait \ + pt-raise flockfile ftrylockfile \ + funlockfile sigaction \ + pthread_getaffinity \ + pthread_setaffinity \ + pthread_attr_getaffinity \ + pthread_attr_setaffinity \ + unwind-forcedunwind + +ifeq ($(PTHREADS_DEBUG_SUPPORT),y) +LDFLAGS-libpthread.so := $(LDFLAGS_NOSTRIP) -Wl,-z,defs +else +LDFLAGS-libpthread.so := $(LDFLAGS) +endif + +LDFLAGS-libpthread.so += $(top_builddir)lib/ld-uClibc-$(VERSION).so $(top_builddir)lib/libdl-$(VERSION).so + +LIBS-libpthread.so := $(LIBS) + +ifneq ($(UCLIBC_CTOR_DTOR),y) +START_FILE-libpthread.so := $(top_builddir)/libpthread/nptl/sysdeps/pthread/crti.o $(SHARED_START_FILES) +END_FILE-libpthread.so := $(SHARED_END_FILES) $(top_builddir)/libpthread/nptl/sysdeps/pthread/crtn.o +endif + +libpthread_FULL_NAME := libpthread-$(VERSION).so + +PTHREAD_DIR := $(top_srcdir)libpthread/nptl +PTHREAD_OUT := $(top_builddir)libpthread/nptl + +libpthread_static_SRC := pthread_atfork + +libpthread_a_SRC = $(patsubst %, $(PTHREAD_DIR)/%.c, \ + $(filter-out $(libpthread-os-routines) \ + $(libpthread-misc-routines) \ + $(libpthread-shared-only-routines), \ + $(libpthread-routines))) +libpthread_so_SRC = $(patsubst %, $(PTHREAD_DIR)/%.c, \ + $(filter-out $(libpthread-os-routines) \ + $(libpthread-misc-routines), $(libpthread-routines))) + +libc-static-y += $(patsubst %.c, $(PTHREAD_OUT)/%.o, alloca_cutoff.c \ + libc-cancellation.c) +libc-shared-y += $(patsubst %.c, $(PTHREAD_OUT)/%.oS, forward.c \ + libc-cancellation.c) +libpthread-nonshared-y += $(patsubst %,$(PTHREAD_OUT)/%.oS,$(libpthread_static_SRC)) + +ifeq ($(DOPIC),y) +libpthread-a-y := $(patsubst $(PTHREAD_DIR)/%.c,$(PTHREAD_OUT)/%.os,$(libpthread_a_SRC)) +else +libpthread-a-y := $(patsubst $(PTHREAD_DIR)/%.c,$(PTHREAD_OUT)/%.o,$(libpthread_a_SRC)) +endif + +libpthread-so-y := $(patsubst $(PTHREAD_DIR)/%.c,$(PTHREAD_OUT)/%.oS,$(libpthread_so_SRC)) +libpthread-static-y += $(patsubst $(PTHREAD_DIR)/%.c,$(PTHREAD_OUT)/%.o,$(libpthread_a_SRC) $(libpthread_static_SRC)) + +objclean-y += libpthread_clean +headers_clean-y += nptl_headers_clean + +-include $(PTHREAD_DIR)/sysdeps/generic/Makefile.in +-include $(PTHREAD_DIR)/sysdeps/pthread/Makefile.in +-include $(PTHREAD_DIR)/sysdeps/$(TARGET_ARCH)/Makefile.arch +-include $(PTHREAD_DIR)/sysdeps/unix/sysv/linux/Makefile.in +-include $(PTHREAD_DIR)/sysdeps/unix/sysv/linux/$(TARGET_ARCH)/Makefile.arch + +pthread_pregen := nptl_headers nptl_arch_headers nptl_linux_headers + +lib-a-$(UCLIBC_HAS_THREADS) += $(top_builddir)lib/libpthread.a +lib-so-$(UCLIBC_HAS_THREADS) += $(top_builddir)lib/libpthread.so + +$(top_builddir)lib/libpthread.so: $(PTHREAD_OUT)/libpthread_so.a $(libc) $(top_builddir)lib/libpthread_nonshared.a + $(call link.so,$(libpthread_FULL_NAME),$(MAJOR_VERSION)) + $(Q)$(RM) $@ + $(Q)cp $(top_srcdir)extra/scripts/format.lds $@ + $(Q)echo "GROUP ( $(notdir $@).$(MAJOR_VERSION) libpthread_nonshared.a )" >> $@ + +$(PTHREAD_OUT)/libpthread_so.a: $(libpthread-so-y) + $(Q)$(RM) $@ +ifeq ($(PTHREADS_DEBUG_SUPPORT),y) + $(do_strip:-x=-X --strip-debug) +else + $(do_strip) +endif + $(do_ar) + +$(top_builddir)lib/libpthread.a: $(libpthread-a-y) + $(Q)$(INSTALL) -d $(dir $@) + $(Q)$(RM) $@ + $(do_strip) + $(do_ar) + +# +# Create 'pthread-errnos.h' header file. +# +CFLAGS-pthread-errnos.c = -S + +$(PTHREAD_OUT)/pthread-errnos.c: $(PTHREAD_DIR)/pthread-errnos.sym + $(do_awk) $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@ + +$(PTHREAD_OUT)/pthread-errnos.s: $(PTHREAD_OUT)/pthread-errnos.c + $(compile.c) + +$(PTHREAD_OUT)/pthread-errnos.h: $(PTHREAD_OUT)/pthread-errnos.s + $(do_sed) -n "s/^.*@@@name@@@\([^@]*\)@@@value@@@[^0-9Xxa-fA-F-]*\([0-9Xxa-fA-F-][0-9Xxa-fA-F-]*\).*@@@end@@@.*$\/#define \1 \2/p" $< > $@ + + +headers-$(UCLIBC_HAS_THREADS_NATIVE) += $(nptl_headers_bootstrap) + +$(top_builddir)include/pthread.h: + $(do_ln) ../$(PTDIR)/sysdeps/pthread/$(@F) $(top_builddir)$@ +$(top_builddir)include/semaphore.h: + $(do_ln) ../$(PTDIR)/$(@F) $(top_builddir)$@ +$(top_builddir)include/bits/semaphore.h: | include/bits + $(do_ln) ../../$(PTDIR)/sysdeps/unix/sysv/linux/$(TARGET_ARCH)/bits/$(@F) $(top_builddir)$@ +$(top_builddir)include/bits/pthreadtypes.h: | include/bits + $(do_ln) ../../$(PTDIR)/sysdeps/unix/sysv/linux/$(TARGET_ARCH)/bits/$(@F) $(top_builddir)$@ +$(top_builddir)include/bits/libc-lock.h: | include/bits + $(do_ln) ../../$(PTDIR)/sysdeps/pthread/bits/$(@F) $(top_builddir)$@ +$(top_builddir)include/bits/stdio-lock.h: | include/bits + $(do_ln) ../../$(PTDIR)/sysdeps/pthread/bits/$(@F) $(top_builddir)$@ + +nptl_headers_bootstrap:= $(top_builddir)include/pthread.h \ + $(top_builddir)include/semaphore.h \ + $(top_builddir)include/bits/semaphore.h \ + $(top_builddir)include/bits/pthreadtypes.h \ + $(top_builddir)include/bits/libc-lock.h \ + $(top_builddir)include/bits/stdio-lock.h + +nptl_headers: $(PTHREAD_OUT)/pthread-errnos.h + +nptl_headers_clean: + $(do_rm) $(nptl_headers_bootstrap) \ + $(addprefix $(PTHREAD_OUT)/pthread-errnos., c h s) + +libpthread_clean: + $(do_rm) $(addprefix $(PTHREAD_OUT)/*., o os oS a) diff --git a/libpthread/nptl/README.NPTL b/libpthread/nptl/README.NPTL new file mode 100644 index 000000000..7e50984cb --- /dev/null +++ b/libpthread/nptl/README.NPTL @@ -0,0 +1,307 @@ +The base NPTL code for uClibc is from the glibc project located at +<http://sourceware.org/glibc/>. The starting version was the HEAD of +the glibc CVS repository dated 2005-05-06. Important changes from +glibc will continue to be brought in as necessary until the version +for uClibc is standing on its own. All of the files were originally +brought over verbatim with no modifications. Obviously, these will +undergo any necessary changes needed for integration into uClibc. +Additionally (or subtractingly), the files and directories below +were removed and not imported. + +-- Steven J. Hill <sjhill@realitydiluted.com> on 2005-05-06 + + +nptl/Makeconfig +nptl/configure +nptl/shlib-versions +nptl/sysdeps/generic +nptl/sysdeps/ia64 +nptl/sysdeps/pthread/Makefile +nptl/sysdeps/pthread/Subdirs +nptl/sysdeps/pthread/allocalim.h +nptl/sysdeps/pthread/configure +nptl/sysdeps/pthread/configure.in +nptl/sysdeps/pthread/createthread.c +nptl/sysdeps/pthread/flockfile.c +nptl/sysdeps/pthread/ftrylockfile.c +nptl/sysdeps/pthread/funlockfile.c +nptl/sysdeps/pthread/librt-cancellation.c +nptl/sysdeps/pthread/list.h +nptl/sysdeps/pthread/malloc-machine.h +nptl/sysdeps/pthread/posix-timer.h +nptl/sysdeps/pthread/pt-initfini.c +nptl/sysdeps/pthread/pt-longjmp.c +nptl/sysdeps/pthread/pthread-functions.h +nptl/sysdeps/pthread/pthread.h +nptl/sysdeps/pthread/pthread_barrier_wait.c +nptl/sysdeps/pthread/pthread_cond_broadcast.c +nptl/sysdeps/pthread/pthread_cond_signal.c +nptl/sysdeps/pthread/pthread_cond_timedwait.c +nptl/sysdeps/pthread/pthread_cond_wait.c +nptl/sysdeps/pthread/pthread_getcpuclockid.c +nptl/sysdeps/pthread/pthread_once.c +nptl/sysdeps/pthread/pthread_rwlock_rdlock.c +nptl/sysdeps/pthread/pthread_rwlock_timedrdlock.c +nptl/sysdeps/pthread/pthread_rwlock_timedwrlock.c +nptl/sysdeps/pthread/pthread_rwlock_unlock.c +nptl/sysdeps/pthread/pthread_rwlock_wrlock.c +nptl/sysdeps/pthread/pthread_sigmask.c +nptl/sysdeps/pthread/pthread_spin_destroy.c +nptl/sysdeps/pthread/pthread_spin_init.c +nptl/sysdeps/pthread/pthread_spin_unlock.c +nptl/sysdeps/pthread/rt-unwind-resume.c +nptl/sysdeps/pthread/setxid.h +nptl/sysdeps/pthread/sigaction.c +nptl/sysdeps/pthread/sigfillset.c +nptl/sysdeps/pthread/sigprocmask.c +nptl/sysdeps/pthread/tcb-offsets.h +nptl/sysdeps/pthread/timer_create.c +nptl/sysdeps/pthread/timer_delete.c +nptl/sysdeps/pthread/timer_getoverr.c +nptl/sysdeps/pthread/timer_gettime.c +nptl/sysdeps/pthread/timer_routines.c +nptl/sysdeps/pthread/timer_settime.c +nptl/sysdeps/pthread/tst-mqueue8x.c +nptl/sysdeps/pthread/tst-timer.c +nptl/sysdeps/pthread/unwind-forcedunwind.c +nptl/sysdeps/pthread/unwind-resume.c +nptl/sysdeps/s390 +nptl/sysdeps/unix +nptl/tst-_res1.c +nptl/tst-_res1mod1.c +nptl/tst-_res1mod2.c +nptl/tst-align.c +nptl/tst-align2.c +nptl/tst-atfork1.c +nptl/tst-atfork2.c +nptl/tst-atfork2mod.c +nptl/tst-attr1.c +nptl/tst-attr2.c +nptl/tst-attr3.c +nptl/tst-backtrace1.c +nptl/tst-barrier1.c +nptl/tst-barrier2.c +nptl/tst-barrier3.c +nptl/tst-barrier4.c +nptl/tst-basic1.c +nptl/tst-basic2.c +nptl/tst-basic3.c +nptl/tst-basic4.c +nptl/tst-basic5.c +nptl/tst-basic6.c +nptl/tst-cancel-wrappers.sh +nptl/tst-cancel1.c +nptl/tst-cancel10.c +nptl/tst-cancel11.c +nptl/tst-cancel12.c +nptl/tst-cancel13.c +nptl/tst-cancel14.c +nptl/tst-cancel15.c +nptl/tst-cancel16.c +nptl/tst-cancel17.c +nptl/tst-cancel18.c +nptl/tst-cancel19.c +nptl/tst-cancel2.c +nptl/tst-cancel20.c +nptl/tst-cancel21.c +nptl/tst-cancel22.c +nptl/tst-cancel23.c +nptl/tst-cancel3.c +nptl/tst-cancel4.c +nptl/tst-cancel5.c +nptl/tst-cancel6.c +nptl/tst-cancel7.c +nptl/tst-cancel8.c +nptl/tst-cancel9.c +nptl/tst-cancelx1.c +nptl/tst-cancelx10.c +nptl/tst-cancelx11.c +nptl/tst-cancelx12.c +nptl/tst-cancelx13.c +nptl/tst-cancelx14.c +nptl/tst-cancelx15.c +nptl/tst-cancelx16.c +nptl/tst-cancelx17.c +nptl/tst-cancelx18.c +nptl/tst-cancelx2.c +nptl/tst-cancelx20.c +nptl/tst-cancelx21.c +nptl/tst-cancelx3.c +nptl/tst-cancelx4.c +nptl/tst-cancelx5.c +nptl/tst-cancelx6.c +nptl/tst-cancelx7.c +nptl/tst-cancelx8.c +nptl/tst-cancelx9.c +nptl/tst-cleanup0.c +nptl/tst-cleanup0.expect +nptl/tst-cleanup1.c +nptl/tst-cleanup2.c +nptl/tst-cleanup3.c +nptl/tst-cleanup4.c +nptl/tst-cleanup4aux.c +nptl/tst-cleanupx0.c +nptl/tst-cleanupx0.expect +nptl/tst-cleanupx1.c +nptl/tst-cleanupx2.c +nptl/tst-cleanupx3.c +nptl/tst-cleanupx4.c +nptl/tst-clock1.c +nptl/tst-clock2.c +nptl/tst-cond1.c +nptl/tst-cond10.c +nptl/tst-cond11.c +nptl/tst-cond12.c +nptl/tst-cond13.c +nptl/tst-cond14.c +nptl/tst-cond15.c +nptl/tst-cond16.c +nptl/tst-cond17.c +nptl/tst-cond18.c +nptl/tst-cond19.c +nptl/tst-cond2.c +nptl/tst-cond20.c +nptl/tst-cond21.c +nptl/tst-cond3.c +nptl/tst-cond4.c +nptl/tst-cond5.c +nptl/tst-cond6.c +nptl/tst-cond7.c +nptl/tst-cond8.c +nptl/tst-cond9.c +nptl/tst-context1.c +nptl/tst-detach1.c +nptl/tst-dlsym1.c +nptl/tst-eintr1.c +nptl/tst-eintr2.c +nptl/tst-eintr3.c +nptl/tst-eintr4.c +nptl/tst-eintr5.c +nptl/tst-exec1.c +nptl/tst-exec2.c +nptl/tst-exec3.c +nptl/tst-exec4.c +nptl/tst-execstack-mod.c +nptl/tst-execstack.c +nptl/tst-exit1.c +nptl/tst-exit2.c +nptl/tst-exit3.c +nptl/tst-fini1.c +nptl/tst-fini1mod.c +nptl/tst-flock1.c +nptl/tst-flock2.c +nptl/tst-fork1.c +nptl/tst-fork2.c +nptl/tst-fork3.c +nptl/tst-fork4.c +nptl/tst-getpid1.c +nptl/tst-getpid2.c +nptl/tst-join1.c +nptl/tst-join2.c +nptl/tst-join3.c +nptl/tst-join4.c +nptl/tst-join5.c +nptl/tst-key1.c +nptl/tst-key2.c +nptl/tst-key3.c +nptl/tst-key4.c +nptl/tst-kill1.c +nptl/tst-kill2.c +nptl/tst-kill3.c +nptl/tst-kill4.c +nptl/tst-kill5.c +nptl/tst-kill6.c +nptl/tst-locale1.c +nptl/tst-locale2.c +nptl/tst-mutex1.c +nptl/tst-mutex2.c +nptl/tst-mutex3.c +nptl/tst-mutex4.c +nptl/tst-mutex5.c +nptl/tst-mutex5a.c +nptl/tst-mutex6.c +nptl/tst-mutex7.c +nptl/tst-mutex7a.c +nptl/tst-mutex8.c +nptl/tst-mutex9.c +nptl/tst-oddstacklimit.c +nptl/tst-once1.c +nptl/tst-once2.c +nptl/tst-once3.c +nptl/tst-once4.c +nptl/tst-oncex3.c +nptl/tst-oncex4.c +nptl/tst-popen1.c +nptl/tst-raise1.c +nptl/tst-rwlock1.c +nptl/tst-rwlock10.c +nptl/tst-rwlock11.c +nptl/tst-rwlock12.c +nptl/tst-rwlock13.c +nptl/tst-rwlock14.c +nptl/tst-rwlock2.c +nptl/tst-rwlock3.c +nptl/tst-rwlock4.c +nptl/tst-rwlock5.c +nptl/tst-rwlock6.c +nptl/tst-rwlock7.c +nptl/tst-rwlock8.c +nptl/tst-rwlock9.c +nptl/tst-sched1.c +nptl/tst-sem1.c +nptl/tst-sem2.c +nptl/tst-sem3.c +nptl/tst-sem4.c +nptl/tst-sem5.c +nptl/tst-sem6.c +nptl/tst-sem7.c +nptl/tst-sem8.c +nptl/tst-sem9.c +nptl/tst-setuid1-static.c +nptl/tst-setuid1.c +nptl/tst-signal1.c +nptl/tst-signal2.c +nptl/tst-signal3.c +nptl/tst-signal4.c +nptl/tst-signal5.c +nptl/tst-signal6.c +nptl/tst-spin1.c +nptl/tst-spin2.c +nptl/tst-spin3.c +nptl/tst-stack1.c +nptl/tst-stack2.c +nptl/tst-stack3.c +nptl/tst-stdio1.c +nptl/tst-stdio2.c +nptl/tst-sysconf.c +nptl/tst-tls1.c +nptl/tst-tls2.c +nptl/tst-tls3.c +nptl/tst-tls3mod.c +nptl/tst-tls4.c +nptl/tst-tls4moda.c +nptl/tst-tls4modb.c +nptl/tst-tls5.c +nptl/tst-tls5.h +nptl/tst-tls5mod.c +nptl/tst-tls5moda.c +nptl/tst-tls5modb.c +nptl/tst-tls5modc.c +nptl/tst-tls5modd.c +nptl/tst-tls5mode.c +nptl/tst-tls5modf.c +nptl/tst-tls6.sh +nptl/tst-tsd1.c +nptl/tst-tsd2.c +nptl/tst-tsd3.c +nptl/tst-tsd4.c +nptl/tst-tsd5.c +nptl/tst-umask1.c +nptl/tst-unload.c +nptl/tst-vfork1.c +nptl/tst-vfork1x.c +nptl/tst-vfork2.c +nptl/tst-vfork2x.c +nptl/version.c +nptl_db/ChangeLog +nptl_db/shlib-versions diff --git a/libpthread/nptl/alloca_cutoff.c b/libpthread/nptl/alloca_cutoff.c new file mode 100644 index 000000000..ba26ceba3 --- /dev/null +++ b/libpthread/nptl/alloca_cutoff.c @@ -0,0 +1,36 @@ +/* Determine whether block of given size can be allocated on the stack or not. + Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <alloca.h> +#include <stdlib.h> +#include <sys/param.h> +#include <pthreadP.h> + + +int +__libc_alloca_cutoff (size_t size) +{ + return size <= (MIN (__MAX_ALLOCA_CUTOFF, + THREAD_GETMEM (THREAD_SELF, stackblock_size) / 4 + /* The main thread, before the thread library is + initialized, has zero in the stackblock_size + element. Since it is the main thread we can + assume the maximum available stack space. */ + ?: __MAX_ALLOCA_CUTOFF * 4)); +} diff --git a/libpthread/nptl/allocatestack.c b/libpthread/nptl/allocatestack.c new file mode 100644 index 000000000..dab9f08ed --- /dev/null +++ b/libpthread/nptl/allocatestack.c @@ -0,0 +1,925 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include <errno.h> +#include <signal.h> +#include <stdint.h> +#include <string.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/param.h> +#include <tls.h> +#include <lowlevellock.h> +#include <link.h> + +#define __getpagesize getpagesize + +#ifndef NEED_SEPARATE_REGISTER_STACK + +/* Most architectures have exactly one stack pointer. Some have more. */ +# define STACK_VARIABLES void *stackaddr = 0 + +/* 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 = 0; size_t stacksize + +/* How to pass the values to the 'create_thread' function. */ +# define STACK_VARIABLES_ARGS stackaddr, stacksize + +/* How to declare function which gets there parameters. */ +# define STACK_VARIABLES_PARMS void *stackaddr, size_t stacksize + +/* How to declare allocate_stack. */ +# define ALLOCATE_STACK_PARMS void **stack, size_t *stacksize + +/* This is how the function is called. We do it this way to allow + other variants of the function to have more parameters. */ +# define ALLOCATE_STACK(attr, pd) \ + allocate_stack (attr, pd, &stackaddr, &stacksize) + +#endif + + +/* Default alignment of stack. */ +#ifndef STACK_ALIGN +# define STACK_ALIGN __alignof__ (long double) +#endif + +/* Default value for minimal stack size after allocating thread + descriptor and guard. */ +#ifndef MINIMAL_REST_STACK +# define MINIMAL_REST_STACK 4096 +#endif + + +/* Let the architecture add some flags to the mmap() call used to + allocate stacks. */ +#ifndef ARCH_MAP_FLAGS +# define ARCH_MAP_FLAGS 0 +#endif + +/* This yields the pointer that TLS support code calls the thread pointer. */ +#if defined(TLS_TCB_AT_TP) +# define TLS_TPADJ(pd) (pd) +#elif defined(TLS_DTV_AT_TP) +# define TLS_TPADJ(pd) ((struct pthread *)((char *) (pd) + TLS_PRE_TCB_SIZE)) +#endif + +/* Cache handling for not-yet free stacks. */ + +/* Maximum size in kB of cache. */ +static size_t stack_cache_maxsize = 40 * 1024 * 1024; /* 40MiBi by default. */ +static size_t stack_cache_actsize; + +/* Mutex protecting this variable. */ +static lll_lock_t stack_cache_lock = LLL_LOCK_INITIALIZER; + +/* List of queued stack frames. */ +static LIST_HEAD (stack_cache); + +/* List of the stacks in use. */ +static LIST_HEAD (stack_used); + +/* List of the threads with user provided stacks in use. No need to + initialize this, since it's done in __pthread_initialize_minimal. */ +list_t __stack_user __attribute__ ((nocommon)); +hidden_def (__stack_user) + +#if COLORING_INCREMENT != 0 +/* Number of threads created. */ +static unsigned int nptl_ncreated; +#endif + + +/* Check whether the stack is still used or not. */ +#define FREE_P(descr) ((descr)->tid <= 0) + + +/* We create a double linked list of all cache entries. Double linked + because this allows removing entries from the end. */ + + +/* Get a stack frame from the cache. We have to match by size since + some blocks might be too small or far too large. */ +static struct pthread * +get_cached_stack (size_t *sizep, void **memp) +{ + size_t size = *sizep; + struct pthread *result = NULL; + list_t *entry; + + lll_lock (stack_cache_lock); + + /* Search the cache for a matching entry. We search for the + smallest stack which has at least the required size. Note that + in normal situations the size of all allocated stacks is the + same. As the very least there are only a few different sizes. + Therefore this loop will exit early most of the time with an + exact match. */ + list_for_each (entry, &stack_cache) + { + struct pthread *curr; + + curr = list_entry (entry, struct pthread, list); + if (FREE_P (curr) && curr->stackblock_size >= size) + { + if (curr->stackblock_size == size) + { + result = curr; + break; + } + + if (result == NULL + || result->stackblock_size > curr->stackblock_size) + result = curr; + } + } + + if (__builtin_expect (result == NULL, 0) + /* Make sure the size difference is not too excessive. In that + case we do not use the block. */ + || __builtin_expect (result->stackblock_size > 4 * size, 0)) + { + /* Release the lock. */ + lll_unlock (stack_cache_lock); + + return NULL; + } + + /* Dequeue the entry. */ + list_del (&result->list); + + /* And add to the list of stacks in use. */ + list_add (&result->list, &stack_used); + + /* And decrease the cache size. */ + stack_cache_actsize -= result->stackblock_size; + + /* Release the lock early. */ + lll_unlock (stack_cache_lock); + + /* Report size and location of the stack to the caller. */ + *sizep = result->stackblock_size; + *memp = result->stackblock; + + /* Cancellation handling is back to the default. */ + result->cancelhandling = 0; + result->cleanup = NULL; + + /* No pending event. */ + result->nextevent = NULL; + + /* Clear the DTV. */ + dtv_t *dtv = GET_DTV (TLS_TPADJ (result)); + memset (dtv, '\0', (dtv[-1].counter + 1) * sizeof (dtv_t)); + + /* Re-initialize the TLS. */ + _dl_allocate_tls_init (TLS_TPADJ (result)); + + return result; +} + + +/* Add a stack frame which is not used anymore to the stack. Must be + called with the cache lock held. */ +static inline void +__attribute ((always_inline)) +queue_stack (struct pthread *stack) +{ + /* We unconditionally add the stack to the list. The memory may + still be in use but it will not be reused until the kernel marks + the stack as not used anymore. */ + list_add (&stack->list, &stack_cache); + + stack_cache_actsize += stack->stackblock_size; + if (__builtin_expect (stack_cache_actsize > stack_cache_maxsize, 0)) + { + /* We reduce the size of the cache. Remove the last entries + until the size is below the limit. */ + list_t *entry; + list_t *prev; + + /* Search from the end of the list. */ + list_for_each_prev_safe (entry, prev, &stack_cache) + { + struct pthread *curr; + + curr = list_entry (entry, struct pthread, list); + if (FREE_P (curr)) + { + /* Unlink the block. */ + list_del (entry); + + /* Account for the freed memory. */ + stack_cache_actsize -= curr->stackblock_size; + + /* Free the memory associated with the ELF TLS. */ + _dl_deallocate_tls (TLS_TPADJ (curr), false); + + /* Remove this block. This should never fail. If it + does something is really wrong. */ + if (munmap (curr->stackblock, curr->stackblock_size) != 0) + abort (); + + /* Maybe we have freed enough. */ + if (stack_cache_actsize <= stack_cache_maxsize) + break; + } + } + } +} + + +static int +internal_function +change_stack_perm (struct pthread *pd +#ifdef NEED_SEPARATE_REGISTER_STACK + , size_t pagemask +#endif + ) +{ +#ifdef NEED_SEPARATE_REGISTER_STACK + void *stack = (pd->stackblock + + (((((pd->stackblock_size - pd->guardsize) / 2) + & pagemask) + pd->guardsize) & pagemask)); + size_t len = pd->stackblock + pd->stackblock_size - stack; +#else + void *stack = pd->stackblock + pd->guardsize; + size_t len = pd->stackblock_size - pd->guardsize; +#endif + if (mprotect (stack, len, PROT_READ | PROT_WRITE | PROT_EXEC) != 0) + return errno; + + return 0; +} + + +static int +allocate_stack (const struct pthread_attr *attr, struct pthread **pdp, + ALLOCATE_STACK_PARMS) +{ + struct pthread *pd; + size_t size; + size_t pagesize_m1 = __getpagesize () - 1; + void *stacktop; + + assert (attr != NULL); + assert (powerof2 (pagesize_m1 + 1)); + assert (TCB_ALIGNMENT >= STACK_ALIGN); + + /* Get the stack size from the attribute if it is set. Otherwise we + use the default we determined at start time. */ + size = attr->stacksize ?: __default_stacksize; + + /* Get memory for the stack. */ + if (__builtin_expect (attr->flags & ATTR_FLAG_STACKADDR, 0)) + { + uintptr_t adj; + + /* If the user also specified the size of the stack make sure it + is large enough. */ + if (attr->stacksize != 0 + && attr->stacksize < (__static_tls_size + MINIMAL_REST_STACK)) + return EINVAL; + + /* Adjust stack size for alignment of the TLS block. */ +#if defined(TLS_TCB_AT_TP) + adj = ((uintptr_t) attr->stackaddr - TLS_TCB_SIZE) + & __static_tls_align_m1; + assert (size > adj + TLS_TCB_SIZE); +#elif defined(TLS_DTV_AT_TP) + adj = ((uintptr_t) attr->stackaddr - __static_tls_size) + & __static_tls_align_m1; + assert (size > adj); +#endif + + /* The user provided some memory. Let's hope it matches the + size... We do not allocate guard pages if the user provided + the stack. It is the user's responsibility to do this if it + is wanted. */ +#if defined(TLS_TCB_AT_TP) + pd = (struct pthread *) ((uintptr_t) attr->stackaddr + - TLS_TCB_SIZE - adj); +#elif defined(TLS_DTV_AT_TP) + pd = (struct pthread *) (((uintptr_t) attr->stackaddr + - __static_tls_size - adj) + - TLS_PRE_TCB_SIZE); +#endif + + /* The user provided stack memory needs to be cleared. */ + memset (pd, '\0', sizeof (struct pthread)); + + /* The first TSD block is included in the TCB. */ + pd->specific[0] = pd->specific_1stblock; + + /* Remember the stack-related values. */ + pd->stackblock = (char *) attr->stackaddr - size; + pd->stackblock_size = size; + + /* This is a user-provided stack. It will not be queued in the + stack cache nor will the memory (except the TLS memory) be freed. */ + pd->user_stack = true; + + /* This is at least the second thread. */ + pd->header.multiple_threads = 1; +#ifndef TLS_MULTIPLE_THREADS_IN_TCB + __pthread_multiple_threads = *__libc_multiple_threads_ptr = 1; +#endif + +#ifdef NEED_DL_SYSINFO + /* Copy the sysinfo value from the parent. */ + THREAD_SYSINFO(pd) = THREAD_SELF_SYSINFO; +#endif + + /* The process ID is also the same as that of the caller. */ + pd->pid = THREAD_GETMEM (THREAD_SELF, pid); + + /* Allocate the DTV for this thread. */ + if (_dl_allocate_tls (TLS_TPADJ (pd)) == NULL) + { + /* Something went wrong. */ + assert (errno == ENOMEM); + return EAGAIN; + } + + + /* Prepare to modify global data. */ + lll_lock (stack_cache_lock); + + /* And add to the list of stacks in use. */ + list_add (&pd->list, &__stack_user); + + lll_unlock (stack_cache_lock); + } + else + { + /* Allocate some anonymous memory. If possible use the cache. */ + size_t guardsize; + size_t reqsize; + void *mem = 0; + const int prot = (PROT_READ | PROT_WRITE); + +#if COLORING_INCREMENT != 0 + /* Add one more page for stack coloring. Don't do it for stacks + with 16 times pagesize or larger. This might just cause + unnecessary misalignment. */ + if (size <= 16 * pagesize_m1) + size += pagesize_m1 + 1; +#endif + + /* Adjust the stack size for alignment. */ + size &= ~__static_tls_align_m1; + assert (size != 0); + + /* Make sure the size of the stack is enough for the guard and + eventually the thread descriptor. */ + guardsize = (attr->guardsize + pagesize_m1) & ~pagesize_m1; + if (__builtin_expect (size < (guardsize + __static_tls_size + + MINIMAL_REST_STACK + pagesize_m1 + 1), + 0)) + /* The stack is too small (or the guard too large). */ + return EINVAL; + + /* Try to get a stack from the cache. */ + reqsize = size; + pd = get_cached_stack (&size, &mem); + if (pd == NULL) + { + /* To avoid aliasing effects on a larger scale than pages we + adjust the allocated stack size if necessary. This way + allocations directly following each other will not have + aliasing problems. */ +#if MULTI_PAGE_ALIASING != 0 + if ((size % MULTI_PAGE_ALIASING) == 0) + size += pagesize_m1 + 1; +#endif + + mem = mmap (NULL, size, prot, + MAP_PRIVATE | MAP_ANONYMOUS | ARCH_MAP_FLAGS, -1, 0); + + if (__builtin_expect (mem == MAP_FAILED, 0)) + { +#ifdef ARCH_RETRY_MMAP + mem = ARCH_RETRY_MMAP (size); + if (__builtin_expect (mem == MAP_FAILED, 0)) +#endif + return errno; + } + + /* SIZE is guaranteed to be greater than zero. + So we can never get a null pointer back from mmap. */ + assert (mem != NULL); + +#if COLORING_INCREMENT != 0 + /* Atomically increment NCREATED. */ + unsigned int ncreated = atomic_increment_val (&nptl_ncreated); + + /* We chose the offset for coloring by incrementing it for + every new thread by a fixed amount. The offset used + module the page size. Even if coloring would be better + relative to higher alignment values it makes no sense to + do it since the mmap() interface does not allow us to + specify any alignment for the returned memory block. */ + size_t coloring = (ncreated * COLORING_INCREMENT) & pagesize_m1; + + /* Make sure the coloring offsets does not disturb the alignment + of the TCB and static TLS block. */ + if (__builtin_expect ((coloring & __static_tls_align_m1) != 0, 0)) + coloring = (((coloring + __static_tls_align_m1) + & ~(__static_tls_align_m1)) + & ~pagesize_m1); +#else + /* Unless specified we do not make any adjustments. */ +# define coloring 0 +#endif + + /* Place the thread descriptor at the end of the stack. */ +#if defined(TLS_TCB_AT_TP) + pd = (struct pthread *) ((char *) mem + size - coloring) - 1; +#elif defined(TLS_DTV_AT_TP) + pd = (struct pthread *) ((((uintptr_t) mem + size - coloring + - __static_tls_size) + & ~__static_tls_align_m1) + - TLS_PRE_TCB_SIZE); +#endif + + /* Remember the stack-related values. */ + pd->stackblock = mem; + pd->stackblock_size = size; + + /* We allocated the first block thread-specific data array. + This address will not change for the lifetime of this + descriptor. */ + pd->specific[0] = pd->specific_1stblock; + + /* This is at least the second thread. */ + pd->header.multiple_threads = 1; +#ifndef TLS_MULTIPLE_THREADS_IN_TCB + __pthread_multiple_threads = *__libc_multiple_threads_ptr = 1; +#endif + +#ifdef NEED_DL_SYSINFO + /* Copy the sysinfo value from the parent. */ + THREAD_SYSINFO(pd) = THREAD_SELF_SYSINFO; +#endif + + /* The process ID is also the same as that of the caller. */ + pd->pid = THREAD_GETMEM (THREAD_SELF, pid); + + /* Allocate the DTV for this thread. */ + if (_dl_allocate_tls (TLS_TPADJ (pd)) == NULL) + { + /* Something went wrong. */ + assert (errno == ENOMEM); + + /* Free the stack memory we just allocated. */ + (void) munmap (mem, size); + + return EAGAIN; + } + + + /* Prepare to modify global data. */ + lll_lock (stack_cache_lock); + + /* And add to the list of stacks in use. */ + list_add (&pd->list, &stack_used); + + lll_unlock (stack_cache_lock); + + + /* Note that all of the stack and the thread descriptor is + zeroed. This means we do not have to initialize fields + with initial value zero. This is specifically true for + the 'tid' field which is always set back to zero once the + stack is not used anymore and for the 'guardsize' field + which will be read next. */ + } + + /* Create or resize the guard area if necessary. */ + if (__builtin_expect (guardsize > pd->guardsize, 0)) + { +#ifdef NEED_SEPARATE_REGISTER_STACK + char *guard = mem + (((size - guardsize) / 2) & ~pagesize_m1); +#else + char *guard = mem; +#endif + if (mprotect (guard, guardsize, PROT_NONE) != 0) + { + int err; + mprot_error: + err = errno; + + lll_lock (stack_cache_lock); + + /* Remove the thread from the list. */ + list_del (&pd->list); + + lll_unlock (stack_cache_lock); + + /* Get rid of the TLS block we allocated. */ + _dl_deallocate_tls (TLS_TPADJ (pd), false); + + /* Free the stack memory regardless of whether the size + of the cache is over the limit or not. If this piece + of memory caused problems we better do not use it + anymore. Uh, and we ignore possible errors. There + is nothing we could do. */ + (void) munmap (mem, size); + + return err; + } + + pd->guardsize = guardsize; + } + else if (__builtin_expect (pd->guardsize - guardsize > size - reqsize, + 0)) + { + /* The old guard area is too large. */ + +#ifdef NEED_SEPARATE_REGISTER_STACK + char *guard = mem + (((size - guardsize) / 2) & ~pagesize_m1); + char *oldguard = mem + (((size - pd->guardsize) / 2) & ~pagesize_m1); + + if (oldguard < guard + && mprotect (oldguard, guard - oldguard, prot) != 0) + goto mprot_error; + + if (mprotect (guard + guardsize, + oldguard + pd->guardsize - guard - guardsize, + prot) != 0) + goto mprot_error; +#else + if (mprotect ((char *) mem + guardsize, pd->guardsize - guardsize, + prot) != 0) + goto mprot_error; +#endif + + pd->guardsize = guardsize; + } + /* The pthread_getattr_np() calls need to get passed the size + requested in the attribute, regardless of how large the + actually used guardsize is. */ + pd->reported_guardsize = guardsize; + } + + /* Initialize the lock. We have to do this unconditionally since the + stillborn thread could be canceled while the lock is taken. */ + pd->lock = LLL_LOCK_INITIALIZER; + + /* We place the thread descriptor at the end of the stack. */ + *pdp = pd; + +#if defined(TLS_TCB_AT_TP) + /* The stack begins before the TCB and the static TLS block. */ + stacktop = ((char *) (pd + 1) - __static_tls_size); +#elif defined(TLS_DTV_AT_TP) + stacktop = (char *) (pd - 1); +#endif + +#ifdef NEED_SEPARATE_REGISTER_STACK + *stack = pd->stackblock; + *stacksize = stacktop - *stack; +#else + *stack = stacktop; +#endif + + return 0; +} + + +void +internal_function +__deallocate_stack (struct pthread *pd) +{ + lll_lock (stack_cache_lock); + + /* Remove the thread from the list of threads with user defined + stacks. */ + list_del (&pd->list); + + /* Not much to do. Just free the mmap()ed memory. Note that we do + not reset the 'used' flag in the 'tid' field. This is done by + the kernel. If no thread has been created yet this field is + still zero. */ + if (__builtin_expect (! pd->user_stack, 1)) + (void) queue_stack (pd); + else + /* Free the memory associated with the ELF TLS. */ + _dl_deallocate_tls (TLS_TPADJ (pd), false); + + lll_unlock (stack_cache_lock); +} + + +int +internal_function +__make_stacks_executable (void **stack_endp) +{ + /* First the main thread's stack. */ + int err = EPERM; + if (err != 0) + return err; + +#ifdef NEED_SEPARATE_REGISTER_STACK + const size_t pagemask = ~(__getpagesize () - 1); +#endif + + lll_lock (stack_cache_lock); + + list_t *runp; + list_for_each (runp, &stack_used) + { + err = change_stack_perm (list_entry (runp, struct pthread, list) +#ifdef NEED_SEPARATE_REGISTER_STACK + , pagemask +#endif + ); + if (err != 0) + break; + } + + /* Also change the permission for the currently unused stacks. This + might be wasted time but better spend it here than adding a check + in the fast path. */ + if (err == 0) + list_for_each (runp, &stack_cache) + { + err = change_stack_perm (list_entry (runp, struct pthread, list) +#ifdef NEED_SEPARATE_REGISTER_STACK + , pagemask +#endif + ); + if (err != 0) + break; + } + + lll_unlock (stack_cache_lock); + + return err; +} + + +/* In case of a fork() call the memory allocation in the child will be + the same but only one thread is running. All stacks except that of + the one running thread are not used anymore. We have to recycle + them. */ +void +__reclaim_stacks (void) +{ + struct pthread *self = (struct pthread *) THREAD_SELF; + + /* No locking necessary. The caller is the only stack in use. */ + + /* Mark all stacks except the still running one as free. */ + list_t *runp; + list_for_each (runp, &stack_used) + { + struct pthread *curp; + + curp = list_entry (runp, struct pthread, list); + if (curp != self) + { + /* This marks the stack as free. */ + curp->tid = 0; + + /* The PID field must be initialized for the new process. */ + curp->pid = self->pid; + + /* Account for the size of the stack. */ + stack_cache_actsize += curp->stackblock_size; + } + } + + /* Add the stack of all running threads to the cache. */ + list_splice (&stack_used, &stack_cache); + + /* Remove the entry for the current thread to from the cache list + and add it to the list of running threads. Which of the two + lists is decided by the user_stack flag. */ + list_del (&self->list); + + /* Re-initialize the lists for all the threads. */ + INIT_LIST_HEAD (&stack_used); + INIT_LIST_HEAD (&__stack_user); + + if (__builtin_expect (THREAD_GETMEM (self, user_stack), 0)) + list_add (&self->list, &__stack_user); + else + list_add (&self->list, &stack_used); + + /* There is one thread running. */ + __nptl_nthreads = 1; + + /* Initialize the lock. */ + stack_cache_lock = LLL_LOCK_INITIALIZER; +} + + +#if HP_TIMING_AVAIL +# undef __find_thread_by_id +/* Find a thread given the thread ID. */ +attribute_hidden +struct pthread * +__find_thread_by_id (pid_t tid) +{ + struct pthread *result = NULL; + + lll_lock (stack_cache_lock); + + /* Iterate over the list with system-allocated threads first. */ + list_t *runp; + list_for_each (runp, &stack_used) + { + struct pthread *curp; + + curp = list_entry (runp, struct pthread, list); + + if (curp->tid == tid) + { + result = curp; + goto out; + } + } + + /* Now the list with threads using user-allocated stacks. */ + list_for_each (runp, &__stack_user) + { + struct pthread *curp; + + curp = list_entry (runp, struct pthread, list); + + if (curp->tid == tid) + { + result = curp; + goto out; + } + } + + out: + lll_unlock (stack_cache_lock); + + return result; +} +#endif + +int +attribute_hidden +__nptl_setxid (struct xid_command *cmdp) +{ + int result; + lll_lock (stack_cache_lock); + + __xidcmd = cmdp; + cmdp->cntr = 0; + + INTERNAL_SYSCALL_DECL (err); + + struct pthread *self = THREAD_SELF; + + /* Iterate over the list with system-allocated threads first. */ + list_t *runp; + list_for_each (runp, &stack_used) + { + struct pthread *t = list_entry (runp, struct pthread, list); + if (t != self) + { + int val; +#if __ASSUME_TGKILL + val = INTERNAL_SYSCALL (tgkill, err, 3, + THREAD_GETMEM (THREAD_SELF, pid), + t->tid, SIGSETXID); +#else +# ifdef __NR_tgkill + val = INTERNAL_SYSCALL (tgkill, err, 3, + THREAD_GETMEM (THREAD_SELF, pid), + t->tid, SIGSETXID); + if (INTERNAL_SYSCALL_ERROR_P (val, err) + && INTERNAL_SYSCALL_ERRNO (val, err) == ENOSYS) +# endif + val = INTERNAL_SYSCALL (tkill, err, 2, t->tid, SIGSETXID); +#endif + + if (!INTERNAL_SYSCALL_ERROR_P (val, err)) + atomic_increment (&cmdp->cntr); + } + } + + /* Now the list with threads using user-allocated stacks. */ + list_for_each (runp, &__stack_user) + { + struct pthread *t = list_entry (runp, struct pthread, list); + if (t != self) + { + int val; +#if __ASSUME_TGKILL + val = INTERNAL_SYSCALL (tgkill, err, 3, + THREAD_GETMEM (THREAD_SELF, pid), + t->tid, SIGSETXID); +#else +# ifdef __NR_tgkill + val = INTERNAL_SYSCALL (tgkill, err, 3, + THREAD_GETMEM (THREAD_SELF, pid), + t->tid, SIGSETXID); + if (INTERNAL_SYSCALL_ERROR_P (val, err) + && INTERNAL_SYSCALL_ERRNO (val, err) == ENOSYS) +# endif + val = INTERNAL_SYSCALL (tkill, err, 2, t->tid, SIGSETXID); +#endif + + if (!INTERNAL_SYSCALL_ERROR_P (val, err)) + atomic_increment (&cmdp->cntr); + } + } + + int cur = cmdp->cntr; + while (cur != 0) + { + lll_futex_wait (&cmdp->cntr, cur); + cur = cmdp->cntr; + } + + /* This must be last, otherwise the current thread might not have + permissions to send SIGSETXID syscall to the other threads. */ + result = INTERNAL_SYSCALL_NCS (cmdp->syscall_no, err, 3, + cmdp->id[0], cmdp->id[1], cmdp->id[2]); + if (INTERNAL_SYSCALL_ERROR_P (result, err)) + { + __set_errno (INTERNAL_SYSCALL_ERRNO (result, err)); + result = -1; + } + + lll_unlock (stack_cache_lock); + return result; +} + +static inline void __attribute__((always_inline)) +init_one_static_tls (struct pthread *curp, struct link_map *map) +{ + dtv_t *dtv = GET_DTV (TLS_TPADJ (curp)); +# if defined(TLS_TCB_AT_TP) + void *dest = (char *) curp - map->l_tls_offset; +# elif defined(TLS_DTV_AT_TP) + void *dest = (char *) curp + map->l_tls_offset + TLS_PRE_TCB_SIZE; +# else +# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined" +# endif + + /* Fill in the DTV slot so that a later LD/GD access will find it. */ + dtv[map->l_tls_modid].pointer.val = dest; + dtv[map->l_tls_modid].pointer.is_static = true; + + /* Initialize the memory. */ + memset (mempcpy (dest, map->l_tls_initimage, map->l_tls_initimage_size), + '\0', map->l_tls_blocksize - map->l_tls_initimage_size); +} + +void +attribute_hidden +__pthread_init_static_tls (struct link_map *map) +{ + lll_lock (stack_cache_lock); + + /* Iterate over the list with system-allocated threads first. */ + list_t *runp; + list_for_each (runp, &stack_used) + init_one_static_tls (list_entry (runp, struct pthread, list), map); + + /* Now the list with threads using user-allocated stacks. */ + list_for_each (runp, &__stack_user) + init_one_static_tls (list_entry (runp, struct pthread, list), map); + + lll_unlock (stack_cache_lock); +} diff --git a/libpthread/nptl/banner.h b/libpthread/nptl/banner.h new file mode 100644 index 000000000..9982f4287 --- /dev/null +++ b/libpthread/nptl/banner.h @@ -0,0 +1 @@ +"Native POSIX Threads Library by Ulrich Drepper et al, uClibc port by Steven Hill\n" diff --git a/libpthread/nptl/cancellation.c b/libpthread/nptl/cancellation.c new file mode 100644 index 000000000..1d28d383f --- /dev/null +++ b/libpthread/nptl/cancellation.c @@ -0,0 +1,90 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <setjmp.h> +#include <stdlib.h> +#include "pthreadP.h" + + +/* The next two functions are similar to pthread_setcanceltype() but + more specialized for the use in the cancelable functions like write(). + They do not need to check parameters etc. */ +int +attribute_hidden +__pthread_enable_asynccancel (void) +{ + struct pthread *self = THREAD_SELF; + int oldval = THREAD_GETMEM (self, cancelhandling); + + while (1) + { + int newval = oldval | CANCELTYPE_BITMASK; + + if (newval == oldval) + break; + + int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, newval, + oldval); + if (__builtin_expect (curval == oldval, 1)) + { + if (CANCEL_ENABLED_AND_CANCELED_AND_ASYNCHRONOUS (newval)) + { + THREAD_SETMEM (self, result, PTHREAD_CANCELED); + __do_cancel (); + } + + break; + } + + /* Prepare the next round. */ + oldval = curval; + } + + return oldval; +} + + +void +internal_function attribute_hidden +__pthread_disable_asynccancel (int oldtype) +{ + /* If asynchronous cancellation was enabled before we do not have + anything to do. */ + if (oldtype & CANCELTYPE_BITMASK) + return; + + struct pthread *self = THREAD_SELF; + int oldval = THREAD_GETMEM (self, cancelhandling); + + while (1) + { + int newval = oldval & ~CANCELTYPE_BITMASK; + + if (newval == oldval) + break; + + int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, newval, + oldval); + if (__builtin_expect (curval == oldval, 1)) + break; + + /* Prepare the next round. */ + oldval = curval; + } +} diff --git a/libpthread/nptl/cleanup.c b/libpthread/nptl/cleanup.c new file mode 100644 index 000000000..af828c49f --- /dev/null +++ b/libpthread/nptl/cleanup.c @@ -0,0 +1,49 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <stdlib.h> +#include "pthreadP.h" + + +void +__cleanup_fct_attribute +__pthread_register_cancel (__pthread_unwind_buf_t *buf) +{ + struct pthread_unwind_buf *ibuf = (struct pthread_unwind_buf *) buf; + struct pthread *self = THREAD_SELF; + + /* Store old info. */ + ibuf->priv.data.prev = THREAD_GETMEM (self, cleanup_jmp_buf); + ibuf->priv.data.cleanup = THREAD_GETMEM (self, cleanup); + + /* Store the new cleanup handler info. */ + THREAD_SETMEM (self, cleanup_jmp_buf, (struct pthread_unwind_buf *) buf); +} +hidden_def (__pthread_register_cancel) + + +void +__cleanup_fct_attribute +__pthread_unregister_cancel (__pthread_unwind_buf_t *buf) +{ + struct pthread_unwind_buf *ibuf = (struct pthread_unwind_buf *) buf; + + THREAD_SETMEM (THREAD_SELF, cleanup_jmp_buf, ibuf->priv.data.prev); +} +hidden_def (__pthread_unregister_cancel) diff --git a/libpthread/nptl/cleanup_compat.c b/libpthread/nptl/cleanup_compat.c new file mode 100644 index 000000000..77d714f7f --- /dev/null +++ b/libpthread/nptl/cleanup_compat.c @@ -0,0 +1,55 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <stdlib.h> +#include "pthreadP.h" + + +void +_pthread_cleanup_push ( + struct _pthread_cleanup_buffer *buffer, + void (*routine) (void *), + void *arg) +{ + struct pthread *self = THREAD_SELF; + + buffer->__routine = routine; + buffer->__arg = arg; + buffer->__prev = THREAD_GETMEM (self, cleanup); + + THREAD_SETMEM (self, cleanup, buffer); +} +strong_alias (_pthread_cleanup_push, __pthread_cleanup_push) + + +void +_pthread_cleanup_pop ( + struct _pthread_cleanup_buffer *buffer, + int execute) +{ + struct pthread *self __attribute ((unused)) = THREAD_SELF; + + THREAD_SETMEM (self, cleanup, buffer->__prev); + + /* If necessary call the cleanup routine after we removed the + current cleanup block from the list. */ + if (execute) + buffer->__routine (buffer->__arg); +} +strong_alias (_pthread_cleanup_pop, __pthread_cleanup_pop) diff --git a/libpthread/nptl/cleanup_defer.c b/libpthread/nptl/cleanup_defer.c new file mode 100644 index 000000000..498d9557d --- /dev/null +++ b/libpthread/nptl/cleanup_defer.c @@ -0,0 +1,92 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <stdlib.h> +#include "pthreadP.h" + + +void +__cleanup_fct_attribute +__pthread_register_cancel_defer (__pthread_unwind_buf_t *buf) +{ + struct pthread_unwind_buf *ibuf = (struct pthread_unwind_buf *) buf; + struct pthread *self = THREAD_SELF; + + /* Store old info. */ + ibuf->priv.data.prev = THREAD_GETMEM (self, cleanup_jmp_buf); + ibuf->priv.data.cleanup = THREAD_GETMEM (self, cleanup); + + int cancelhandling = THREAD_GETMEM (self, cancelhandling); + + /* Disable asynchronous cancellation for now. */ + if (__builtin_expect (cancelhandling & CANCELTYPE_BITMASK, 0)) + while (1) + { + int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, + cancelhandling + & ~CANCELTYPE_BITMASK, + cancelhandling); + if (__builtin_expect (curval == cancelhandling, 1)) + /* Successfully replaced the value. */ + break; + + /* Prepare for the next round. */ + cancelhandling = curval; + } + + ibuf->priv.data.canceltype = (cancelhandling & CANCELTYPE_BITMASK + ? PTHREAD_CANCEL_ASYNCHRONOUS + : PTHREAD_CANCEL_DEFERRED); + + /* Store the new cleanup handler info. */ + THREAD_SETMEM (self, cleanup_jmp_buf, (struct pthread_unwind_buf *) buf); +} + + +void +__cleanup_fct_attribute +__pthread_unregister_cancel_restore (__pthread_unwind_buf_t *buf) +{ + struct pthread *self = THREAD_SELF; + struct pthread_unwind_buf *ibuf = (struct pthread_unwind_buf *) buf; + + THREAD_SETMEM (self, cleanup_jmp_buf, ibuf->priv.data.prev); + + int cancelhandling; + if (ibuf->priv.data.canceltype != PTHREAD_CANCEL_DEFERRED + && ((cancelhandling = THREAD_GETMEM (self, cancelhandling)) + & CANCELTYPE_BITMASK) == 0) + { + while (1) + { + int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, + cancelhandling + | CANCELTYPE_BITMASK, + cancelhandling); + if (__builtin_expect (curval == cancelhandling, 1)) + /* Successfully replaced the value. */ + break; + + /* Prepare for the next round. */ + cancelhandling = curval; + } + + CANCELLATION_P (self); + } +} diff --git a/libpthread/nptl/cleanup_defer_compat.c b/libpthread/nptl/cleanup_defer_compat.c new file mode 100644 index 000000000..8fd9b5415 --- /dev/null +++ b/libpthread/nptl/cleanup_defer_compat.c @@ -0,0 +1,98 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" + + +void +_pthread_cleanup_push_defer ( + struct _pthread_cleanup_buffer *buffer, + void (*routine) (void *), + void *arg) +{ + struct pthread *self = THREAD_SELF; + + buffer->__routine = routine; + buffer->__arg = arg; + buffer->__prev = THREAD_GETMEM (self, cleanup); + + int cancelhandling = THREAD_GETMEM (self, cancelhandling); + + /* Disable asynchronous cancellation for now. */ + if (__builtin_expect (cancelhandling & CANCELTYPE_BITMASK, 0)) + while (1) + { + int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, + cancelhandling + & ~CANCELTYPE_BITMASK, + cancelhandling); + if (__builtin_expect (curval == cancelhandling, 1)) + /* Successfully replaced the value. */ + break; + + /* Prepare for the next round. */ + cancelhandling = curval; + } + + buffer->__canceltype = (cancelhandling & CANCELTYPE_BITMASK + ? PTHREAD_CANCEL_ASYNCHRONOUS + : PTHREAD_CANCEL_DEFERRED); + + THREAD_SETMEM (self, cleanup, buffer); +} +strong_alias (_pthread_cleanup_push_defer, __pthread_cleanup_push_defer) + + +void +_pthread_cleanup_pop_restore ( + struct _pthread_cleanup_buffer *buffer, + int execute) +{ + struct pthread *self = THREAD_SELF; + + THREAD_SETMEM (self, cleanup, buffer->__prev); + + int cancelhandling; + if (__builtin_expect (buffer->__canceltype != PTHREAD_CANCEL_DEFERRED, 0) + && ((cancelhandling = THREAD_GETMEM (self, cancelhandling)) + & CANCELTYPE_BITMASK) == 0) + { + while (1) + { + int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, + cancelhandling + | CANCELTYPE_BITMASK, + cancelhandling); + if (__builtin_expect (curval == cancelhandling, 1)) + /* Successfully replaced the value. */ + break; + + /* Prepare for the next round. */ + cancelhandling = curval; + } + + CANCELLATION_P (self); + } + + /* If necessary call the cleanup routine after we removed the + current cleanup block from the list. */ + if (execute) + buffer->__routine (buffer->__arg); +} +strong_alias (_pthread_cleanup_pop_restore, __pthread_cleanup_pop_restore) diff --git a/libpthread/nptl/cleanup_routine.c b/libpthread/nptl/cleanup_routine.c new file mode 100644 index 000000000..cbf231834 --- /dev/null +++ b/libpthread/nptl/cleanup_routine.c @@ -0,0 +1,28 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> + + +void +__pthread_cleanup_routine (struct __pthread_cleanup_frame *f) +{ + if (f->__do_it) + f->__cancel_routine (f->__cancel_arg); +} diff --git a/libpthread/nptl/descr.h b/libpthread/nptl/descr.h new file mode 100644 index 000000000..1a8d91be8 --- /dev/null +++ b/libpthread/nptl/descr.h @@ -0,0 +1,271 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _DESCR_H +#define _DESCR_H 1 + +#include <limits.h> +#include <sched.h> +#include <setjmp.h> +#include <stdbool.h> +#include <sys/types.h> +#include <hp-timing.h> +#include <list.h> +#include <lowlevellock.h> +#include <pthreaddef.h> +#include "../nptl_db/thread_db.h" +#include <tls.h> +#ifdef HAVE_FORCED_UNWIND +# include <unwind.h> +#endif +#define __need_res_state +#include <resolv.h> + +#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; +}; + + +/* Thread descriptor data structure. */ +struct pthread +{ + union + { +#if !defined(TLS_DTV_AT_TP) + /* This overlaps the TCB as used for TLS without threads (see tls.h). */ + tcbhead_t header; +#else + struct + { + int multiple_threads; + } 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[16]; + }; + + /* This descriptor's link on the `stack_used' or `__stack_user' list. */ + list_t list; + + /* Thread ID - which is also a 'is this thread descriptor (and + therefore stack) used' flag. */ + pid_t tid; + + /* Process ID - thread group ID in kernel speak. */ + pid_t pid; + + /* List of 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 + /* Bit set if asynchronous cancellation mode is selected. */ +#define CANCELTYPE_BIT 1 +#define CANCELTYPE_BITMASK 0x02 + /* Bit set if canceling has been initiated. */ +#define CANCELING_BIT 2 +#define CANCELING_BITMASK 0x04 + /* Bit set if canceled. */ +#define CANCELED_BIT 3 +#define CANCELED_BITMASK 0x08 + /* Bit set if thread is exiting. */ +#define EXITING_BIT 4 +#define EXITING_BITMASK 0x10 + /* Bit set if thread terminated and TCB is freed. */ +#define TERMINATED_BIT 5 +#define TERMINATED_BITMASK 0x20 + /* Bit set if thread is supposed to change XID. */ +#define SETXID_BIT 6 +#define SETXID_BITMASK 0x40 + /* 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)) + + /* 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]; + + /* Flag which is set when specific data is set. */ + bool specific_used; + + /* Two-level array for the thread-specific data. */ + struct pthread_key_data *specific[PTHREAD_KEY_1STLEVEL_SIZE]; + + /* 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; + + /* Lock to synchronize access to the descriptor. */ + lll_lock_t lock; + + /* Lock for synchronizing setxid calls. */ + lll_lock_t 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)) + + /* Flags. Including those copied from the thread attribute. */ + int flags; + + /* The result of the thread function. */ + void *result; + + /* Scheduling parameters for the new thread. */ + struct sched_param schedparam; + int schedpolicy; + + /* Start position of the code to be executed and the argument passed + to the function. */ + void *(*start_routine) (void *); + void *arg; + + /* Debug state. */ + td_eventbuf_t eventbuf; + /* Next descriptor with a pending event. */ + struct pthread *nextevent; + +#ifdef HAVE_FORCED_UNWIND + /* Machine-specific unwind info. */ + struct _Unwind_Exception exc; +#endif + + /* If nonzero pointer to area allocated for the stack and its + size. */ + void *stackblock; + size_t stackblock_size; + /* Size of the included guard area. */ + size_t guardsize; + /* This is what the user specified and what we will report. */ + size_t reported_guardsize; + + /* Resolver state. */ + struct __res_state res; + + /* This member must be last. */ + char end_padding[]; + +#define PTHREAD_STRUCT_END_PADDING \ + (sizeof (struct pthread) - offsetof (struct pthread, end_padding)) +} __attribute ((aligned (TCB_ALIGNMENT))); + + +#endif /* descr.h */ diff --git a/libpthread/nptl/eintr.c b/libpthread/nptl/eintr.c new file mode 100644 index 000000000..933c5d81b --- /dev/null +++ b/libpthread/nptl/eintr.c @@ -0,0 +1,89 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <signal.h> +#include <unistd.h> + + +static int the_sig; + + +static void +eintr_handler (int sig) +{ + if (sig != the_sig) + { + write (STDOUT_FILENO, "eintr_handler: signal number wrong\n", 35); + _exit (1); + } + write (STDOUT_FILENO, ".", 1); +} + + +static void * +eintr_source (void *arg) +{ + struct timespec ts = { .tv_sec = 0, .tv_nsec = 500000 }; + + if (arg == NULL) + { + sigset_t ss; + sigemptyset (&ss); + sigaddset (&ss, the_sig); + pthread_sigmask (SIG_BLOCK, &ss, NULL); + } + + while (1) + { + if (arg != NULL) + pthread_kill (*(pthread_t *) arg, the_sig); + else + kill (getpid (), the_sig); + + nanosleep (&ts, NULL); + } + + /* NOTREACHED */ + return NULL; +} + + +static void +setup_eintr (int sig, pthread_t *thp) +{ + struct sigaction sa; + sigemptyset (&sa.sa_mask); + sa.sa_flags = 0; + sa.sa_handler = eintr_handler; + if (sigaction (sig, &sa, NULL) != 0) + { + puts ("setup_eintr: sigaction failed"); + exit (1); + } + the_sig = sig; + + /* Create the thread which will fire off the signals. */ + pthread_t th; + if (pthread_create (&th, NULL, eintr_source, thp) != 0) + { + puts ("setup_eintr: pthread_create failed"); + exit (1); + } +} diff --git a/libpthread/nptl/events.c b/libpthread/nptl/events.c new file mode 100644 index 000000000..df97e54f6 --- /dev/null +++ b/libpthread/nptl/events.c @@ -0,0 +1,34 @@ +/* Event functions used while debugging. + Copyright (C) 1999, 2000, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* The functions contained here do nothing, they just return. */ + +#include "pthreadP.h" + +void +__nptl_create_event (void) +{ +} +hidden_def (__nptl_create_event) + +void +__nptl_death_event (void) +{ +} +hidden_def (__nptl_death_event) diff --git a/libpthread/nptl/forward.c b/libpthread/nptl/forward.c new file mode 100644 index 000000000..5b71f8e67 --- /dev/null +++ b/libpthread/nptl/forward.c @@ -0,0 +1,172 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <dlfcn.h> +#include <pthreadP.h> +#include <signal.h> +#include <stdlib.h> +#include <atomic.h> +#include <sysdep.h> + + +/* Pointers to the libc functions. */ +struct pthread_functions __libc_pthread_functions attribute_hidden; + + +#define FORWARD2(name, rettype, decl, params, defaction) \ +rettype \ +name decl \ +{ \ + if (__libc_pthread_functions.ptr_##name == NULL) \ + defaction; \ + \ + return __libc_pthread_functions.ptr_##name params; \ +} + +#define FORWARD(name, decl, params, defretval) \ + FORWARD2 (name, int, decl, params, return defretval) + + +FORWARD (pthread_attr_destroy, (pthread_attr_t *attr), (attr), 0) + +FORWARD (__pthread_attr_init_2_1, (pthread_attr_t *attr), (attr), 0) +weak_alias(__pthread_attr_init_2_1, pthread_attr_init) + +FORWARD (pthread_attr_getdetachstate, + (const pthread_attr_t *attr, int *detachstate), (attr, detachstate), + 0) +FORWARD (pthread_attr_setdetachstate, (pthread_attr_t *attr, int detachstate), + (attr, detachstate), 0) + +FORWARD (pthread_attr_getinheritsched, + (const pthread_attr_t *attr, int *inherit), (attr, inherit), 0) +FORWARD (pthread_attr_setinheritsched, (pthread_attr_t *attr, int inherit), + (attr, inherit), 0) + +FORWARD (pthread_attr_getschedparam, + (const pthread_attr_t *attr, struct sched_param *param), + (attr, param), 0) +FORWARD (pthread_attr_setschedparam, + (pthread_attr_t *attr, const struct sched_param *param), + (attr, param), 0) + +FORWARD (pthread_attr_getschedpolicy, + (const pthread_attr_t *attr, int *policy), (attr, policy), 0) +FORWARD (pthread_attr_setschedpolicy, (pthread_attr_t *attr, int policy), + (attr, policy), 0) + +FORWARD (pthread_attr_getscope, + (const pthread_attr_t *attr, int *scope), (attr, scope), 0) +FORWARD (pthread_attr_setscope, (pthread_attr_t *attr, int scope), + (attr, scope), 0) + + +FORWARD (pthread_condattr_destroy, (pthread_condattr_t *attr), (attr), 0) +FORWARD (pthread_condattr_init, (pthread_condattr_t *attr), (attr), 0) + +FORWARD (__pthread_cond_broadcast, (pthread_cond_t *cond), (cond), 0) +weak_alias(__pthread_cond_broadcast, pthread_cond_broadcast) + +FORWARD (__pthread_cond_destroy, (pthread_cond_t *cond), (cond), 0) +weak_alias(__pthread_cond_destroy, pthread_cond_destroy) + +FORWARD (__pthread_cond_init, + (pthread_cond_t *cond, const pthread_condattr_t *cond_attr), + (cond, cond_attr), 0) +weak_alias(__pthread_cond_init, pthread_cond_init) + +FORWARD (__pthread_cond_signal, (pthread_cond_t *cond), (cond), 0) +weak_alias(__pthread_cond_signal, pthread_cond_signal) + +FORWARD (__pthread_cond_wait, (pthread_cond_t *cond, pthread_mutex_t *mutex), + (cond, mutex), 0) +weak_alias(__pthread_cond_wait, pthread_cond_wait) + +FORWARD (__pthread_cond_timedwait, + (pthread_cond_t *cond, pthread_mutex_t *mutex, + const struct timespec *abstime), (cond, mutex, abstime), 0) +weak_alias(__pthread_cond_timedwait, pthread_cond_timedwait) + + +FORWARD (pthread_equal, (pthread_t thread1, pthread_t thread2), + (thread1, thread2), 1) + + +/* Use an alias to avoid warning, as pthread_exit is declared noreturn. */ +FORWARD2 (__pthread_exit, void, (void *retval), (retval), exit (EXIT_SUCCESS)) +strong_alias (__pthread_exit, pthread_exit); + + +FORWARD (pthread_getschedparam, + (pthread_t target_thread, int *policy, struct sched_param *param), + (target_thread, policy, param), 0) +FORWARD (pthread_setschedparam, + (pthread_t target_thread, int policy, + const struct sched_param *param), (target_thread, policy, param), 0) + + +FORWARD (pthread_mutex_destroy, (pthread_mutex_t *mutex), (mutex), 0) + +libc_hidden_proto(pthread_mutex_init) +FORWARD (pthread_mutex_init, + (pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr), + (mutex, mutexattr), 0) +strong_alias(pthread_mutex_init, __pthread_mutex_init) +libc_hidden_def(pthread_mutex_init) + +libc_hidden_proto(pthread_mutex_trylock) +FORWARD (pthread_mutex_trylock, (pthread_mutex_t *mutex), (mutex), 0) +strong_alias(pthread_mutex_trylock, __pthread_mutex_trylock) +libc_hidden_def(pthread_mutex_trylock) + +libc_hidden_proto(pthread_mutex_lock) +FORWARD (pthread_mutex_lock, (pthread_mutex_t *mutex), (mutex), 0) +strong_alias(pthread_mutex_lock, __pthread_mutex_lock) +libc_hidden_def(pthread_mutex_lock) + +libc_hidden_proto(pthread_mutex_unlock) +FORWARD (pthread_mutex_unlock, (pthread_mutex_t *mutex), (mutex), 0) +strong_alias(pthread_mutex_unlock, __pthread_mutex_unlock) +libc_hidden_def(pthread_mutex_unlock) + +FORWARD (pthread_mutexattr_init, (pthread_mutexattr_t *attr), (attr), 0) + +FORWARD (pthread_mutexattr_destroy, (pthread_mutexattr_t *attr), (attr), 0) + +FORWARD (pthread_mutexattr_settype, (pthread_mutexattr_t *attr, int kind), + (attr, kind), 0) + + +FORWARD2 (pthread_self, pthread_t, (void), (), return 0) + + +FORWARD (pthread_setcancelstate, (int state, int *oldstate), (state, oldstate), + 0) + +FORWARD (pthread_setcanceltype, (int type, int *oldtype), (type, oldtype), 0) + +#define return /* value is void */ +FORWARD2(__pthread_unwind, + void attribute_hidden __attribute ((noreturn)) __cleanup_fct_attribute, + (__pthread_unwind_buf_t *buf), (buf), { + /* We cannot call abort() here. */ + INTERNAL_SYSCALL_DECL (err); + INTERNAL_SYSCALL (kill, err, 1, SIGKILL); + }) +#undef return diff --git a/libpthread/nptl/herrno.c b/libpthread/nptl/herrno.c new file mode 100644 index 000000000..6e8339d43 --- /dev/null +++ b/libpthread/nptl/herrno.c @@ -0,0 +1,35 @@ +/* Copyright (C) 1996,97,98,2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <features.h> +#include <netdb.h> +#undef h_errno + +#include <tls.h> + +/* We need to have the error status variable of the resolver + accessible in the libc. */ +extern __thread int h_errno; + + +/* When threaded, h_errno may be a per-thread variable. */ +int * +__h_errno_location (void) +{ + return &h_errno; +} diff --git a/libpthread/nptl/init.c b/libpthread/nptl/init.c new file mode 100644 index 000000000..0c55bbb8f --- /dev/null +++ b/libpthread/nptl/init.c @@ -0,0 +1,329 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include <limits.h> +#include <signal.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/param.h> +#include <sys/resource.h> +#include <pthreadP.h> +#include <atomic.h> +#include <ldsodefs.h> +#include <tls.h> +#include <fork.h> +#include <smp.h> +#include <lowlevellock.h> +#include <version.h> + + +#ifndef __NR_set_tid_address +/* XXX For the time being... Once we can rely on the kernel headers + having the definition remove these lines. */ +#if defined __s390__ +# define __NR_set_tid_address 252 +#elif defined __ia64__ +# define __NR_set_tid_address 1233 +#elif defined __i386__ +# define __NR_set_tid_address 258 +#elif defined __x86_64__ +# define __NR_set_tid_address 218 +#elif defined __powerpc__ +# define __NR_set_tid_address 232 +#elif defined __sparc__ +# define __NR_set_tid_address 166 +#else +# error "define __NR_set_tid_address" +#endif +#endif + + +/* Size and alignment of static TLS block. */ +size_t __static_tls_size; +size_t __static_tls_align_m1; + +/* Version of the library, used in libthread_db to detect mismatches. */ +static const char nptl_version[] __attribute_used__ = VERSION; + + +#if defined USE_TLS && !defined SHARED +extern void __libc_setup_tls (size_t tcbsize, size_t tcbalign); +#endif + +int +__libc_sigaction (int sig, const struct sigaction *act, struct sigaction *oact); + + +#ifdef SHARED +static const struct pthread_functions pthread_functions = + { + .ptr_pthread_attr_destroy = __pthread_attr_destroy, + .ptr___pthread_attr_init_2_1 = __pthread_attr_init_2_1, + .ptr_pthread_attr_getdetachstate = __pthread_attr_getdetachstate, + .ptr_pthread_attr_setdetachstate = __pthread_attr_setdetachstate, + .ptr_pthread_attr_getinheritsched = __pthread_attr_getinheritsched, + .ptr_pthread_attr_setinheritsched = __pthread_attr_setinheritsched, + .ptr_pthread_attr_getschedparam = __pthread_attr_getschedparam, + .ptr_pthread_attr_setschedparam = __pthread_attr_setschedparam, + .ptr_pthread_attr_getschedpolicy = __pthread_attr_getschedpolicy, + .ptr_pthread_attr_setschedpolicy = __pthread_attr_setschedpolicy, + .ptr_pthread_attr_getscope = __pthread_attr_getscope, + .ptr_pthread_attr_setscope = __pthread_attr_setscope, + .ptr_pthread_condattr_destroy = __pthread_condattr_destroy, + .ptr_pthread_condattr_init = __pthread_condattr_init, + .ptr___pthread_cond_broadcast = __pthread_cond_broadcast, + .ptr___pthread_cond_destroy = __pthread_cond_destroy, + .ptr___pthread_cond_init = __pthread_cond_init, + .ptr___pthread_cond_signal = __pthread_cond_signal, + .ptr___pthread_cond_wait = __pthread_cond_wait, + .ptr___pthread_cond_timedwait = __pthread_cond_timedwait, + .ptr_pthread_equal = __pthread_equal, + .ptr___pthread_exit = __pthread_exit, + .ptr_pthread_getschedparam = __pthread_getschedparam, + .ptr_pthread_setschedparam = __pthread_setschedparam, + .ptr_pthread_mutex_destroy = __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_internal, + .ptr___pthread_rwlock_rdlock = __pthread_rwlock_rdlock_internal, + .ptr___pthread_rwlock_wrlock = __pthread_rwlock_wrlock_internal, + .ptr___pthread_rwlock_unlock = __pthread_rwlock_unlock_internal, + .ptr___pthread_key_create = __pthread_key_create_internal, + .ptr___pthread_getspecific = __pthread_getspecific_internal, + .ptr___pthread_setspecific = __pthread_setspecific_internal, + .ptr__pthread_cleanup_push_defer = __pthread_cleanup_push_defer, + .ptr__pthread_cleanup_pop_restore = __pthread_cleanup_pop_restore, + .ptr_nthreads = &__nptl_nthreads, + .ptr___pthread_unwind = &__pthread_unwind, + .ptr__nptl_deallocate_tsd = __nptl_deallocate_tsd, + .ptr__nptl_setxid = __nptl_setxid + }; +# define ptr_pthread_functions &pthread_functions +#else +# define ptr_pthread_functions NULL +#endif + + +/* For asynchronous cancellation we use a signal. This is the handler. */ +static void +sigcancel_handler (int sig, siginfo_t *si, void *ctx) +{ + /* Safety check. It would be possible to call this function for + other signals and send a signal from another process. This is not + correct and might even be a security problem. Try to catch as + many incorrect invocations as possible. */ + if (sig != SIGCANCEL +#ifdef __ASSUME_CORRECT_SI_PID + /* Kernels before 2.5.75 stored the thread ID and not the process + ID in si_pid so we skip this test. */ + || si->si_pid != THREAD_GETMEM (THREAD_SELF, pid) +#endif + || si->si_code != SI_TKILL) + return; + + struct pthread *self = THREAD_SELF; + + int oldval = THREAD_GETMEM (self, cancelhandling); + while (1) + { + /* We are canceled now. When canceled by another thread this flag + is already set but if the signal is directly send (internally or + from another process) is has to be done here. */ + int newval = oldval | CANCELING_BITMASK | CANCELED_BITMASK; + + if (oldval == newval || (oldval & EXITING_BITMASK) != 0) + /* Already canceled or exiting. */ + break; + + int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, newval, + oldval); + if (curval == oldval) + { + /* Set the return value. */ + THREAD_SETMEM (self, result, PTHREAD_CANCELED); + + /* Make sure asynchronous cancellation is still enabled. */ + if ((newval & CANCELTYPE_BITMASK) != 0) + /* Run the registered destructors and terminate the thread. */ + __do_cancel (); + + break; + } + + oldval = curval; + } +} + + +struct xid_command *__xidcmd attribute_hidden; + +/* For asynchronous cancellation we use a signal. This is the handler. */ +static void +sighandler_setxid (int sig, siginfo_t *si, void *ctx) +{ + /* Safety check. It would be possible to call this function for + other signals and send a signal from another process. This is not + correct and might even be a security problem. Try to catch as + many incorrect invocations as possible. */ + if (sig != SIGSETXID +#ifdef __ASSUME_CORRECT_SI_PID + /* Kernels before 2.5.75 stored the thread ID and not the process + ID in si_pid so we skip this test. */ + || si->si_pid != THREAD_GETMEM (THREAD_SELF, pid) +#endif + || si->si_code != SI_TKILL) + return; + + INTERNAL_SYSCALL_DECL (err); + INTERNAL_SYSCALL_NCS (__xidcmd->syscall_no, err, 3, __xidcmd->id[0], + __xidcmd->id[1], __xidcmd->id[2]); + + if (atomic_decrement_val (&__xidcmd->cntr) == 0) + lll_futex_wake (&__xidcmd->cntr, 1); +} + + +/* When using __thread for this, we do it in libc so as not + to give libpthread its own TLS segment just for this. */ +extern void **__libc_dl_error_tsd (void) __attribute__ ((const)); + + +void +__pthread_initialize_minimal_internal (void) +{ +#ifndef SHARED + /* Unlike in the dynamically linked case the dynamic linker has not + taken care of initializing the TLS data structures. */ + __libc_setup_tls (TLS_TCB_SIZE, TLS_TCB_ALIGN); + + /* We must prevent gcc from being clever and move any of the + following code ahead of the __libc_setup_tls call. This function + will initialize the thread register which is subsequently + used. */ + __asm __volatile (""); +#endif + + /* Minimal initialization of the thread descriptor. */ + struct pthread *pd = THREAD_SELF; + INTERNAL_SYSCALL_DECL (err); + pd->pid = pd->tid = INTERNAL_SYSCALL (set_tid_address, err, 1, &pd->tid); + THREAD_SETMEM (pd, specific[0], &pd->specific_1stblock[0]); + THREAD_SETMEM (pd, user_stack, true); + if (LLL_LOCK_INITIALIZER != 0) + THREAD_SETMEM (pd, lock, LLL_LOCK_INITIALIZER); +#if HP_TIMING_AVAIL + THREAD_SETMEM (pd, cpuclock_offset, GL(dl_cpuclock_offset)); +#endif + + /* Set initial thread's stack block from 0 up to __libc_stack_end. + It will be bigger than it actually is, but for unwind.c/pt-longjmp.c + purposes this is good enough. */ + THREAD_SETMEM (pd, stackblock_size, (size_t) __libc_stack_end); + + /* Initialize the list of all running threads with the main thread. */ + INIT_LIST_HEAD (&__stack_user); + list_add (&pd->list, &__stack_user); + + + /* Install the cancellation signal handler. If for some reason we + cannot install the handler we do not abort. Maybe we should, but + it is only asynchronous cancellation which is affected. */ + struct sigaction sa; + sa.sa_sigaction = sigcancel_handler; + sa.sa_flags = SA_SIGINFO; + __sigemptyset (&sa.sa_mask); + + (void) __libc_sigaction (SIGCANCEL, &sa, NULL); + + /* Install the handle to change the threads' uid/gid. */ + sa.sa_sigaction = sighandler_setxid; + sa.sa_flags = SA_SIGINFO | SA_RESTART; + + (void) __libc_sigaction (SIGSETXID, &sa, NULL); + + /* The parent process might have left the signals blocked. Just in + case, unblock it. We reuse the signal mask in the sigaction + structure. It is already cleared. */ + __sigaddset (&sa.sa_mask, SIGCANCEL); + __sigaddset (&sa.sa_mask, SIGSETXID); + (void) INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_UNBLOCK, &sa.sa_mask, + NULL, _NSIG / 8); + + /* Get the size of the static and alignment requirements for the TLS + block. */ + size_t static_tls_align; + _dl_get_tls_static_info (&__static_tls_size, &static_tls_align); + + /* Make sure the size takes all the alignments into account. */ + if (STACK_ALIGN > static_tls_align) + static_tls_align = STACK_ALIGN; + __static_tls_align_m1 = static_tls_align - 1; + + __static_tls_size = roundup (__static_tls_size, static_tls_align); + + /* Determine the default allowed stack size. This is the size used + in case the user does not specify one. */ + struct rlimit limit; + if (getrlimit (RLIMIT_STACK, &limit) != 0 + || limit.rlim_cur == RLIM_INFINITY) + /* The system limit is not usable. Use an architecture-specific + default. */ + limit.rlim_cur = ARCH_STACK_DEFAULT_SIZE; + else if (limit.rlim_cur < PTHREAD_STACK_MIN) + /* The system limit is unusably small. + Use the minimal size acceptable. */ + limit.rlim_cur = PTHREAD_STACK_MIN; + + /* Make sure it meets the minimum size that allocate_stack + (allocatestack.c) will demand, which depends on the page size. */ + const uintptr_t pagesz = sysconf (_SC_PAGESIZE); + const size_t minstack = pagesz + __static_tls_size + MINIMAL_REST_STACK; + if (limit.rlim_cur < minstack) + limit.rlim_cur = minstack; + + /* Round the resource limit up to page size. */ + limit.rlim_cur = (limit.rlim_cur + pagesz - 1) & -pagesz; + __default_stacksize = limit.rlim_cur; + +#ifdef SHARED + /* Transfer the old value from the dynamic linker's internal location. */ + *__libc_dl_error_tsd () = *(*GL(dl_error_catch_tsd)) (); + GL(dl_error_catch_tsd) = &__libc_dl_error_tsd; +#endif + + GL(dl_init_static_tls) = &__pthread_init_static_tls; + + /* Register the fork generation counter with the libc. */ +#ifndef TLS_MULTIPLE_THREADS_IN_TCB + __libc_multiple_threads_ptr = +#endif + __libc_pthread_init (&__fork_generation, __reclaim_stacks, + ptr_pthread_functions); + + /* Determine whether the machine is SMP or not. */ + __is_smp = is_smp_system (); +} +strong_alias (__pthread_initialize_minimal_internal, + __pthread_initialize_minimal) diff --git a/libpthread/nptl/libc-cancellation.c b/libpthread/nptl/libc-cancellation.c new file mode 100644 index 000000000..c9237e095 --- /dev/null +++ b/libpthread/nptl/libc-cancellation.c @@ -0,0 +1,116 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <setjmp.h> +#include <stdlib.h> +#include "pthreadP.h" +#include "atomic.h" +#include <bits/libc-lock.h> + + +#ifndef NOT_IN_libc + +/* 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 +__libc_enable_asynccancel (void) +{ + struct pthread *self = THREAD_SELF; + int oldval = THREAD_GETMEM (self, cancelhandling); + + while (1) + { + int newval = oldval | CANCELTYPE_BITMASK; + + if (__builtin_expect ((oldval & CANCELED_BITMASK) != 0, 0)) + { + /* If we are already exiting or if PTHREAD_CANCEL_DISABLED, + stop right here. */ + if ((oldval & (EXITING_BITMASK | CANCELSTATE_BITMASK)) != 0) + break; + + int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, + newval, oldval); + if (__builtin_expect (curval != oldval, 0)) + { + /* Somebody else modified the word, try again. */ + oldval = curval; + continue; + } + + THREAD_SETMEM (self, result, PTHREAD_CANCELED); + + __do_cancel (); + + /* NOTREACHED */ + } + + int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, newval, + oldval); + if (__builtin_expect (curval == oldval, 1)) + break; + + /* Prepare the next round. */ + oldval = curval; + } + + return oldval; +} + + +void +internal_function attribute_hidden +__libc_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 oldval = THREAD_GETMEM (self, cancelhandling); + + while (1) + { + int newval = oldval & ~CANCELTYPE_BITMASK; + + if (newval == oldval) + break; + + int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, newval, + oldval); + if (__builtin_expect (curval == oldval, 1)) + break; + + /* Prepare the next round. */ + oldval = curval; + } +} + + +void +__libc_cleanup_routine (struct __pthread_cleanup_frame *f) +{ + if (f->__do_it) + f->__cancel_routine (f->__cancel_arg); +} + +#endif diff --git a/libpthread/nptl/linux_fsinfo.h b/libpthread/nptl/linux_fsinfo.h new file mode 100644 index 000000000..13c385626 --- /dev/null +++ b/libpthread/nptl/linux_fsinfo.h @@ -0,0 +1,153 @@ +/* Constants from kernel header for various FSes. + Copyright (C) 1998,1999,2000,2001,2002,2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _LINUX_FSINFO_H +#define _LINUX_FSINFO_H 1 + +/* These definitions come from the kernel headers. But we cannot + include the headers here because of type clashes. If new + filesystem types will become available we have to add the + appropriate definitions here.*/ + +/* Constants that identify the `adfs' filesystem. */ +#define ADFS_SUPER_MAGIC 0xadf5 + +/* Constants that identify the `affs' filesystem. */ +#define AFFS_SUPER_MAGIC 0xadff + +/* Constants that identify the `autofs' filesystem. */ +#define AUTOFS_SUPER_MAGIC 0x187 + +/* Constants that identify the `bfs' filesystem. */ +#define BFS_MAGIC 0x1BADFACE + +/* Constants that identify the `coda' filesystem. */ +#define CODA_SUPER_MAGIC 0x73757245 + +/* Constants that identify the `coherent' filesystem. */ +#define COH_SUPER_MAGIC 0x012ff7b7 + +/* Constant that identifies the `ramfs' filesystem. */ +#define CRAMFS_MAGIC 0x28cd3d45 + +/* Constant that identifies the `devfs' filesystem. */ +#define DEVFS_SUPER_MAGIC 0x1373 + +/* Constant that identifies the `devpts' filesystem. */ +#define DEVPTS_SUPER_MAGIC 0x1cd1 + +/* Constant that identifies the `efs' filesystem. */ +#define EFS_SUPER_MAGIC 0x414A53 +#define EFS_MAGIC 0x072959 + +/* Constant that identifies the `ext2' and `ext3' filesystems. */ +#define EXT2_SUPER_MAGIC 0xef53 + +/* Constant that identifies the `hpfs' filesystem. */ +#define HPFS_SUPER_MAGIC 0xf995e849 + +/* Constant that identifies the `iso9660' filesystem. */ +#define ISOFS_SUPER_MAGIC 0x9660 + +/* Constant that identifies the `jffs' filesystem. */ +#define JFFS_SUPER_MAGIC 0x07c0 + +/* Constant that identifies the `jffs2' filesystem. */ +#define JFFS2_SUPER_MAGIC 0x72b6 + +/* Constant that identifies the `jfs' filesystem. */ +#define JFS_SUPER_MAGIC 0x3153464a + +/* Constants that identify the `minix2' filesystem. */ +#define MINIX2_SUPER_MAGIC 0x2468 +#define MINIX2_SUPER_MAGIC2 0x2478 + +/* Constants that identify the `minix' filesystem. */ +#define MINIX_SUPER_MAGIC 0x137f +#define MINIX_SUPER_MAGIC2 0x138F + +/* Constants that identify the `msdos' filesystem. */ +#define MSDOS_SUPER_MAGIC 0x4d44 + +/* Constants that identify the `ncp' filesystem. */ +#define NCP_SUPER_MAGIC 0x564c + +/* Constants that identify the `nfs' filesystem. */ +#define NFS_SUPER_MAGIC 0x6969 + +/* Constants that identify the `ntfs' filesystem. */ +#define NTFS_SUPER_MAGIC 0x5346544e + +/* Constants that identify the `proc' filesystem. */ +#define PROC_SUPER_MAGIC 0x9fa0 + +/* Constant that identifies the `usbdevfs' filesystem. */ +#define USBDEVFS_SUPER_MAGIC 0x9fa2 + +/* Constants that identify the `qnx4' filesystem. */ +#define QNX4_SUPER_MAGIC 0x002f + +/* Constants that identify the `reiser' filesystem. */ +#define REISERFS_SUPER_MAGIC 0x52654973 + +/* Constant that identifies the `romfs' filesystem. */ +#define ROMFS_SUPER_MAGIC 0x7275 + +/* Constants that identify the `smb' filesystem. */ +#define SMB_SUPER_MAGIC 0x517b + +/* Constants that identify the `sysV' filesystem. */ +#define SYSV2_SUPER_MAGIC 0x012ff7b6 +#define SYSV4_SUPER_MAGIC 0x012ff7b5 + +/* Constants that identify the `udf' filesystem. */ +#define UDF_SUPER_MAGIC 0x15013346 + +/* Constants that identify the `ufs' filesystem. */ +#define UFS_MAGIC 0x00011954 +#define UFS_CIGAM 0x54190100 /* byteswapped MAGIC */ + +/* Constants that identify the `xenix' filesystem. */ +#define XENIX_SUPER_MAGIC 0x012ff7b4 + +/* Constant that identifies the `shm' filesystem. */ +#define SHMFS_SUPER_MAGIC 0x01021994 + +/* Constants that identify the `xfs' filesystem. */ +#define XFS_SUPER_MAGIC 0x58465342 + +/* Constants that identify the `vxfs' filesystem. */ +#define VXFS_SUPER_MAGIC 0xa501fcf5 + +/* Maximum link counts. */ +#define COH_LINK_MAX 10000 +#define EXT2_LINK_MAX 32000 +#define MINIX2_LINK_MAX 65530 +#define MINIX_LINK_MAX 250 +#define REISERFS_LINK_MAX 64535 +#define SYSV_LINK_MAX 126 /* 127? 251? */ +#define UFS_LINK_MAX EXT2_LINK_MAX +#define XENIX_LINK_MAX 126 /* ?? */ +#define XFS_LINK_MAX 2147483647 + +/* The Linux kernel header mentioned this as a kind of generic value. */ +#define LINUX_LINK_MAX 127 + + +#endif /* linux_fsinfo.h */ diff --git a/libpthread/nptl/pt-cleanup.c b/libpthread/nptl/pt-cleanup.c new file mode 100644 index 000000000..f5fdedeb6 --- /dev/null +++ b/libpthread/nptl/pt-cleanup.c @@ -0,0 +1,63 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <setjmp.h> +#include <stdlib.h> +#include "pthreadP.h" +#include "jmpbuf-unwind.h" + +void +__pthread_cleanup_upto (__jmp_buf target, char *targetframe) +{ + struct pthread *self = THREAD_SELF; + struct _pthread_cleanup_buffer *cbuf; + + /* Adjust all pointers used in comparisons, so that top of thread's + stack is at the top of address space. Without that, things break + if stack is allocated above the main stack. */ + uintptr_t adj = (uintptr_t) self->stackblock + self->stackblock_size; + uintptr_t targetframe_adj = (uintptr_t) targetframe - adj; + + for (cbuf = THREAD_GETMEM (self, cleanup); + cbuf != NULL && _JMPBUF_UNWINDS_ADJ (target, cbuf, adj); + cbuf = cbuf->__prev) + { +#if _STACK_GROWS_DOWN + if ((uintptr_t) cbuf - adj <= targetframe_adj) + { + cbuf = NULL; + break; + } +#elif _STACK_GROWS_UP + if ((uintptr_t) cbuf - adj >= targetframe_adj) + { + cbuf = NULL; + break; + } +#else +# error "Define either _STACK_GROWS_DOWN or _STACK_GROWS_UP" +#endif + + /* Call the cleanup code. */ + cbuf->__routine (cbuf->__arg); + } + + THREAD_SETMEM (self, cleanup, cbuf); +} +hidden_def (__pthread_cleanup_upto) diff --git a/libpthread/nptl/pt-system.c b/libpthread/nptl/pt-system.c new file mode 100644 index 000000000..09a08ec24 --- /dev/null +++ b/libpthread/nptl/pt-system.c @@ -0,0 +1,36 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <stdlib.h> +#include <sysdep.h> +#include "pthreadP.h" + + +extern __typeof(system) __libc_system; +#include <system.c> + +int +system (const char *line) +{ + return __libc_system (line); +} + +/* __libc_system in libc.so handles cancellation. */ +LIBC_CANCEL_HANDLED (); diff --git a/libpthread/nptl/pthread-errnos.sym b/libpthread/nptl/pthread-errnos.sym new file mode 100644 index 000000000..2bb4d0d3c --- /dev/null +++ b/libpthread/nptl/pthread-errnos.sym @@ -0,0 +1,12 @@ +#include <errno.h> + +-- These errno codes are used by some assembly code. + +EAGAIN EAGAIN +EBUSY EBUSY +EDEADLK EDEADLK +EINTR EINTR +EINVAL EINVAL +ENOSYS ENOSYS +ETIMEDOUT ETIMEDOUT +EWOULDBLOCK EWOULDBLOCK diff --git a/libpthread/nptl/pthreadP.h b/libpthread/nptl/pthreadP.h new file mode 100644 index 000000000..149c505c3 --- /dev/null +++ b/libpthread/nptl/pthreadP.h @@ -0,0 +1,463 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _PTHREADP_H +#define _PTHREADP_H 1 + +#include <pthread.h> +#include <setjmp.h> +#include <stdbool.h> +#include <sys/syscall.h> +#include "descr.h" +#include <tls.h> +#include <lowlevellock.h> +#include <bits/stackinfo.h> +#include <internaltypes.h> +#include <pthread-functions.h> +#include <atomic.h> + + +/* 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 + + +/* Internal variables. */ + + +/* Default stack size. */ +extern size_t __default_stacksize attribute_hidden; + +/* Size and alignment of static TLS block. */ +extern size_t __static_tls_size attribute_hidden; +extern size_t __static_tls_align_m1 attribute_hidden; + +/* Flag whether the machine is SMP or not. */ +extern int __is_smp attribute_hidden; + +/* Thread descriptor handling. */ +extern list_t __stack_user; +hidden_proto (__stack_user) + +/* Attribute handling. */ +extern struct pthread_attr *__attr_list attribute_hidden; +extern lll_lock_t __attr_list_lock attribute_hidden; + +/* First available RT signal. */ +extern int __current_sigrtmin attribute_hidden; +/* Last available RT signal. */ +extern int __current_sigrtmax attribute_hidden; + +/* Concurrency handling. */ +extern int __concurrency_level attribute_hidden; + +/* Thread-local data key handling. */ +extern struct pthread_key_struct __pthread_keys[PTHREAD_KEYS_MAX]; +hidden_proto (__pthread_keys) + +/* Number of threads running. */ +extern unsigned int __nptl_nthreads attribute_hidden; + +/* The library can run in debugging mode where it performs a lot more + tests. */ +extern int __pthread_debug attribute_hidden; +/** For now disable debugging support. */ +#if 0 +# define DEBUGGING_P __builtin_expect (__pthread_debug, 0) +# define INVALID_TD_P(pd) (DEBUGGING_P && __find_in_stack_list (pd) == NULL) +# define INVALID_NOT_TERMINATED_TD_P(pd) INVALID_TD_P (pd) +#else +# define DEBUGGING_P 0 +/* Simplified test. This will not catch all invalid descriptors but + is better than nothing. And if the test triggers the thread + descriptor is guaranteed to be invalid. */ +# define INVALID_TD_P(pd) __builtin_expect ((pd)->tid <= 0, 0) +# define INVALID_NOT_TERMINATED_TD_P(pd) __builtin_expect ((pd)->tid < 0, 0) +#endif + + +/* Cancellation test. */ +#define CANCELLATION_P(self) \ + do { \ + int _cancelhandling = THREAD_GETMEM (self, cancelhandling); \ + if (CANCEL_ENABLED_AND_CANCELED (_cancelhandling)) \ + { \ + THREAD_SETMEM (self, result, PTHREAD_CANCELED); \ + __do_cancel (); \ + } \ + } while (0) + + +extern void __pthread_unwind (__pthread_unwind_buf_t *__buf) + __cleanup_fct_attribute __attribute ((__noreturn__)) +#if !defined SHARED && !defined IS_IN_libpthread + weak_function +#endif + ; +extern void __pthread_unwind_next (__pthread_unwind_buf_t *__buf) + __cleanup_fct_attribute __attribute ((__noreturn__)) +#ifndef SHARED + weak_function +#endif + ; +extern void __pthread_register_cancel (__pthread_unwind_buf_t *__buf) + __cleanup_fct_attribute; +extern void __pthread_unregister_cancel (__pthread_unwind_buf_t *__buf) + __cleanup_fct_attribute; +#if defined NOT_IN_libc && defined IS_IN_libpthread +hidden_proto (__pthread_unwind) +hidden_proto (__pthread_unwind_next) +hidden_proto (__pthread_register_cancel) +hidden_proto (__pthread_unregister_cancel) +# ifdef SHARED +extern void attribute_hidden pthread_cancel_init (void); +# endif +#endif + + +/* Called when a thread reacts on a cancellation request. */ +static inline void +__attribute ((noreturn, always_inline)) +__do_cancel (void) +{ + struct pthread *self = THREAD_SELF; + + /* Make sure we get no more cancellations. */ + THREAD_ATOMIC_BIT_SET (self, cancelhandling, EXITING_BIT); + + __pthread_unwind ((__pthread_unwind_buf_t *) + THREAD_GETMEM (self, cleanup_jmp_buf)); +} + + +/* Set cancellation mode to asynchronous. */ +#define CANCEL_ASYNC() \ + __pthread_enable_asynccancel () +/* Reset to previous cancellation mode. */ +#define CANCEL_RESET(oldtype) \ + __pthread_disable_asynccancel (oldtype) + +#if !defined NOT_IN_libc +/* Same as CANCEL_ASYNC, but for use in libc.so. */ +# define LIBC_CANCEL_ASYNC() \ + __libc_enable_asynccancel () +/* Same as CANCEL_RESET, but for use in libc.so. */ +# define LIBC_CANCEL_RESET(oldtype) \ + __libc_disable_asynccancel (oldtype) +# define LIBC_CANCEL_HANDLED() \ + __asm (".globl " __USER_LABEL_PREFIX__ "__libc_enable_asynccancel"); \ + __asm (".globl " __USER_LABEL_PREFIX__ "__libc_disable_asynccancel") +#elif defined NOT_IN_libc && defined IS_IN_libpthread +# define LIBC_CANCEL_ASYNC() CANCEL_ASYNC () +# define LIBC_CANCEL_RESET(val) CANCEL_RESET (val) +# define LIBC_CANCEL_HANDLED() \ + __asm (".globl " __USER_LABEL_PREFIX__ "__pthread_enable_asynccancel"); \ + __asm (".globl " __USER_LABEL_PREFIX__ "__pthread_disable_asynccancel") +#elif defined NOT_IN_libc && defined IS_IN_librt +# define LIBC_CANCEL_ASYNC() \ + __librt_enable_asynccancel () +# define LIBC_CANCEL_RESET(val) \ + __librt_disable_asynccancel (val) +# define LIBC_CANCEL_HANDLED() \ + __asm (".globl " __USER_LABEL_PREFIX__ "__librt_enable_asynccancel"); \ + __asm (".globl " __USER_LABEL_PREFIX__ "__librt_disable_asynccancel") +#else +# define LIBC_CANCEL_ASYNC() 0 /* Just a dummy value. */ +# define LIBC_CANCEL_RESET(val) ((void)(val)) /* Nothing, but evaluate it. */ +# define LIBC_CANCEL_HANDLED() /* Nothing. */ +#endif + +/* The signal used for asynchronous cancelation. */ +#define SIGCANCEL __SIGRTMIN + + +/* Signal needed for the kernel-supported POSIX timer implementation. + We can reuse the cancellation signal since we can distinguish + cancellation from timer expirations. */ +#define SIGTIMER SIGCANCEL + + +/* Signal used to implement the setuid et.al. functions. */ +#define SIGSETXID (__SIGRTMIN + 1) + +/* Used to communicate with signal handler. */ +extern struct xid_command *__xidcmd attribute_hidden; + + +/* Internal prototypes. */ + +/* Thread list handling. */ +extern struct pthread *__find_in_stack_list (struct pthread *pd) + attribute_hidden internal_function; + +/* Deallocate a thread's stack after optionally making sure the thread + descriptor is still valid. */ +extern void __free_tcb (struct pthread *pd) attribute_hidden internal_function; + +/* Free allocated stack. */ +extern void __deallocate_stack (struct pthread *pd) + attribute_hidden internal_function; + +/* Mark all the stacks except for the current one as available. This + function also re-initializes the lock for the stack cache. */ +extern void __reclaim_stacks (void) attribute_hidden; + +/* Make all threads's stacks executable. */ +extern int __make_stacks_executable (void **stack_endp) + internal_function attribute_hidden; + +/* longjmp handling. */ +extern void __pthread_cleanup_upto (__jmp_buf target, char *targetframe); +#if defined NOT_IN_libc && defined IS_IN_libpthread +hidden_proto (__pthread_cleanup_upto) +#endif + + +/* Functions with versioned interfaces. */ +extern int __pthread_create_2_1 (pthread_t *newthread, + const pthread_attr_t *attr, + void *(*start_routine) (void *), void *arg); +extern int __pthread_create_2_0 (pthread_t *newthread, + const pthread_attr_t *attr, + void *(*start_routine) (void *), void *arg); +extern int __pthread_attr_init_2_1 (pthread_attr_t *attr); +extern int __pthread_attr_init_2_0 (pthread_attr_t *attr); + + +/* Event handlers for libthread_db interface. */ +extern void __nptl_create_event (void); +extern void __nptl_death_event (void); +hidden_proto (__nptl_create_event) +hidden_proto (__nptl_death_event) + +/* Register the generation counter in the libpthread with the libc. */ +#ifdef TLS_MULTIPLE_THREADS_IN_TCB +extern void __libc_pthread_init (unsigned long int *ptr, + void (*reclaim) (void), + const struct pthread_functions *functions); +#else +extern int *__libc_pthread_init (unsigned long int *ptr, + void (*reclaim) (void), + const struct pthread_functions *functions); + +/* Variable set to a nonzero value if more than one thread runs or ran. */ +extern int __pthread_multiple_threads attribute_hidden; +/* Pointer to the corresponding variable in libc. */ +extern int *__libc_multiple_threads_ptr attribute_hidden; +#endif + +/* Find a thread given its TID. */ +extern struct pthread *__find_thread_by_id (pid_t tid) attribute_hidden +#ifdef SHARED +; +#else +weak_function; +#define __find_thread_by_id(tid) \ + (__find_thread_by_id ? (__find_thread_by_id) (tid) : (struct pthread *) NULL) +#endif + +extern void __pthread_init_static_tls (struct link_map *) attribute_hidden; + + +/* Namespace save aliases. */ +extern int __pthread_getschedparam (pthread_t thread_id, int *policy, + struct sched_param *param); +extern int __pthread_setschedparam (pthread_t thread_id, int policy, + const struct sched_param *param); +extern int __pthread_setcancelstate (int state, int *oldstate); +extern int __pthread_mutex_init (pthread_mutex_t *__mutex, + __const pthread_mutexattr_t *__mutexattr); +extern int __pthread_mutex_init_internal (pthread_mutex_t *__mutex, + __const pthread_mutexattr_t *__mutexattr) + attribute_hidden; +extern int __pthread_mutex_destroy (pthread_mutex_t *__mutex); +extern int __pthread_mutex_destroy_internal (pthread_mutex_t *__mutex) + attribute_hidden; +extern int __pthread_mutex_trylock (pthread_mutex_t *_mutex); +extern int __pthread_mutex_lock (pthread_mutex_t *__mutex); +extern int __pthread_mutex_lock_internal (pthread_mutex_t *__mutex) + attribute_hidden; +extern int __pthread_mutex_cond_lock (pthread_mutex_t *__mutex); +extern int __pthread_mutex_unlock (pthread_mutex_t *__mutex); +extern int __pthread_mutex_unlock_internal (pthread_mutex_t *__mutex) + attribute_hidden; +extern int __pthread_mutex_unlock_usercnt (pthread_mutex_t *__mutex, + int __decr) + attribute_hidden internal_function; +extern int __pthread_mutexattr_init (pthread_mutexattr_t *attr); +extern int __pthread_mutexattr_destroy (pthread_mutexattr_t *attr); +extern int __pthread_mutexattr_settype (pthread_mutexattr_t *attr, int kind); +extern int __pthread_attr_destroy (pthread_attr_t *attr); +extern int __pthread_attr_getdetachstate (const pthread_attr_t *attr, + int *detachstate); +extern int __pthread_attr_setdetachstate (pthread_attr_t *attr, + int detachstate); +extern int __pthread_attr_getinheritsched (const pthread_attr_t *attr, + int *inherit); +extern int __pthread_attr_setinheritsched (pthread_attr_t *attr, int inherit); +extern int __pthread_attr_getschedparam (const pthread_attr_t *attr, + struct sched_param *param); +extern int __pthread_attr_setschedparam (pthread_attr_t *attr, + const struct sched_param *param); +extern int __pthread_attr_getschedpolicy (const pthread_attr_t *attr, + int *policy); +extern int __pthread_attr_setschedpolicy (pthread_attr_t *attr, int policy); +extern int __pthread_attr_getscope (const pthread_attr_t *attr, int *scope); +extern int __pthread_attr_setscope (pthread_attr_t *attr, int scope); +extern int __pthread_attr_getstackaddr (__const pthread_attr_t *__restrict + __attr, void **__restrict __stackaddr); +extern int __pthread_attr_setstackaddr (pthread_attr_t *__attr, + void *__stackaddr); +extern int __pthread_attr_getstacksize (__const pthread_attr_t *__restrict + __attr, + size_t *__restrict __stacksize); +extern int __pthread_attr_setstacksize (pthread_attr_t *__attr, + size_t __stacksize); +extern int __pthread_attr_getstack (__const pthread_attr_t *__restrict __attr, + void **__restrict __stackaddr, + size_t *__restrict __stacksize); +extern int __pthread_attr_setstack (pthread_attr_t *__attr, void *__stackaddr, + size_t __stacksize); +extern int __pthread_rwlock_init (pthread_rwlock_t *__restrict __rwlock, + __const pthread_rwlockattr_t *__restrict + __attr); +extern int __pthread_rwlock_destroy (pthread_rwlock_t *__rwlock); +extern int __pthread_rwlock_rdlock (pthread_rwlock_t *__rwlock); +extern int __pthread_rwlock_rdlock_internal (pthread_rwlock_t *__rwlock); +extern int __pthread_rwlock_tryrdlock (pthread_rwlock_t *__rwlock); +extern int __pthread_rwlock_wrlock (pthread_rwlock_t *__rwlock); +extern int __pthread_rwlock_wrlock_internal (pthread_rwlock_t *__rwlock); +extern int __pthread_rwlock_trywrlock (pthread_rwlock_t *__rwlock); +extern int __pthread_rwlock_unlock (pthread_rwlock_t *__rwlock); +extern int __pthread_rwlock_unlock_internal (pthread_rwlock_t *__rwlock); +extern int __pthread_cond_broadcast (pthread_cond_t *cond); +extern int __pthread_cond_destroy (pthread_cond_t *cond); +extern int __pthread_cond_init (pthread_cond_t *cond, + const pthread_condattr_t *cond_attr); +extern int __pthread_cond_signal (pthread_cond_t *cond); +extern int __pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex); +extern int __pthread_cond_timedwait (pthread_cond_t *cond, + pthread_mutex_t *mutex, + const struct timespec *abstime); +extern int __pthread_condattr_destroy (pthread_condattr_t *attr); +extern int __pthread_condattr_init (pthread_condattr_t *attr); +extern int __pthread_key_create (pthread_key_t *key, void (*destr) (void *)); +extern int __pthread_key_create_internal (pthread_key_t *key, + void (*destr) (void *)); +extern void *__pthread_getspecific (pthread_key_t key); +extern void *__pthread_getspecific_internal (pthread_key_t key); +extern int __pthread_setspecific (pthread_key_t key, const void *value); +extern int __pthread_setspecific_internal (pthread_key_t key, + const void *value); +extern int __pthread_once (pthread_once_t *once_control, + void (*init_routine) (void)); +extern int __pthread_once_internal (pthread_once_t *once_control, + void (*init_routine) (void)); +extern int __pthread_atfork (void (*prepare) (void), void (*parent) (void), + void (*child) (void)); +extern pthread_t __pthread_self (void); +extern int __pthread_equal (pthread_t thread1, pthread_t thread2); +extern int __pthread_kill (pthread_t threadid, int signo); +extern void __pthread_exit (void *value); +extern int __pthread_setcanceltype (int type, int *oldtype); +extern int __pthread_enable_asynccancel (void) attribute_hidden; +extern void __pthread_disable_asynccancel (int oldtype) + internal_function attribute_hidden; + +extern int __pthread_cond_broadcast_2_0 (pthread_cond_2_0_t *cond); +extern int __pthread_cond_destroy_2_0 (pthread_cond_2_0_t *cond); +extern int __pthread_cond_init_2_0 (pthread_cond_2_0_t *cond, + const pthread_condattr_t *cond_attr); +extern int __pthread_cond_signal_2_0 (pthread_cond_2_0_t *cond); +extern int __pthread_cond_timedwait_2_0 (pthread_cond_2_0_t *cond, + pthread_mutex_t *mutex, + const struct timespec *abstime); +extern int __pthread_cond_wait_2_0 (pthread_cond_2_0_t *cond, + pthread_mutex_t *mutex); + +extern int __pthread_getaffinity_np (pthread_t th, size_t cpusetsize, + cpu_set_t *cpuset); + +/* The two functions are in libc.so and not exported. */ +extern int __libc_enable_asynccancel (void) attribute_hidden; +extern void __libc_disable_asynccancel (int oldtype) + internal_function attribute_hidden; + + +/* The two functions are in librt.so and not exported. */ +extern int __librt_enable_asynccancel (void) attribute_hidden; +extern void __librt_disable_asynccancel (int oldtype) + internal_function attribute_hidden; + +#ifdef IS_IN_libpthread +/* Special versions which use non-exported functions. */ +extern void __pthread_cleanup_push (struct _pthread_cleanup_buffer *buffer, + void (*routine) (void *), void *arg) + attribute_hidden; +# undef pthread_cleanup_push +# define pthread_cleanup_push(routine,arg) \ + { struct _pthread_cleanup_buffer _buffer; \ + __pthread_cleanup_push (&_buffer, (routine), (arg)); + +extern void __pthread_cleanup_pop (struct _pthread_cleanup_buffer *buffer, + int execute) attribute_hidden; +# undef pthread_cleanup_pop +# define pthread_cleanup_pop(execute) \ + __pthread_cleanup_pop (&_buffer, (execute)); } +#endif + +extern void __pthread_cleanup_push_defer (struct _pthread_cleanup_buffer *buffer, + void (*routine) (void *), void *arg); +extern void __pthread_cleanup_pop_restore (struct _pthread_cleanup_buffer *buffer, + int execute); + +/* Old cleanup interfaces, still used in libc.so. */ +extern void _pthread_cleanup_push (struct _pthread_cleanup_buffer *buffer, + void (*routine) (void *), void *arg); +extern void _pthread_cleanup_pop (struct _pthread_cleanup_buffer *buffer, + int execute); +extern void _pthread_cleanup_push_defer (struct _pthread_cleanup_buffer *buffer, + void (*routine) (void *), void *arg); +extern void _pthread_cleanup_pop_restore (struct _pthread_cleanup_buffer *buffer, + int execute); + +extern void __nptl_deallocate_tsd (void) attribute_hidden; + +extern int __nptl_setxid (struct xid_command *cmdp) attribute_hidden; + +#ifdef SHARED +# define PTHREAD_STATIC_FN_REQUIRE(name) +#else +# define PTHREAD_STATIC_FN_REQUIRE(name) __asm (".globl " #name); +#endif + +#endif /* pthreadP.h */ diff --git a/libpthread/nptl/pthread_atfork.c b/libpthread/nptl/pthread_atfork.c new file mode 100644 index 000000000..5e9b35284 --- /dev/null +++ b/libpthread/nptl/pthread_atfork.c @@ -0,0 +1,55 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + In addition to the permissions in the GNU Lesser General Public + License, the Free Software Foundation gives you unlimited + permission to link the compiled version of this file with other + programs, and to distribute those programs without any restriction + coming from the use of this file. (The GNU Lesser General Public + License restrictions do apply in other respects; for example, they + cover modification of the file, and distribution when not linked + into another program.) + + Note that people who make modified versions of this file are not + obligated to grant this special exception for their modified + versions; it is their choice whether to do so. The GNU Lesser + General Public License gives permission to release a modified + version without this exception; this exception also makes it + possible to release a modified version which carries forward this + exception. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" +#include <fork.h> + +/* This is defined by newer gcc version unique for each module. */ +extern void *__dso_handle __attribute__ ((__weak__)); + + +/* Hide the symbol so that no definition but the one locally in the + executable or DSO is used. */ +int +__pthread_atfork ( + void (*prepare) (void), + void (*parent) (void), + void (*child) (void)) +{ + return __register_atfork (prepare, parent, child, + &__dso_handle == NULL ? NULL : __dso_handle); +} +strong_alias(__pthread_atfork, pthread_atfork) diff --git a/libpthread/nptl/pthread_attr_destroy.c b/libpthread/nptl/pthread_attr_destroy.c new file mode 100644 index 000000000..f9e446a5c --- /dev/null +++ b/libpthread/nptl/pthread_attr_destroy.c @@ -0,0 +1,39 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include <errno.h> +#include <string.h> +#include <unistd.h> +#include "pthreadP.h" + +int +__pthread_attr_destroy (pthread_attr_t *attr) +{ + struct pthread_attr *iattr; + + assert (sizeof (*attr) >= sizeof (struct pthread_attr)); + iattr = (struct pthread_attr *) attr; + + /* The affinity CPU set might be allocated dynamically. */ + free (iattr->cpuset); + + return 0; +} +strong_alias (__pthread_attr_destroy, pthread_attr_destroy) diff --git a/libpthread/nptl/pthread_attr_getdetachstate.c b/libpthread/nptl/pthread_attr_getdetachstate.c new file mode 100644 index 000000000..db0720e7a --- /dev/null +++ b/libpthread/nptl/pthread_attr_getdetachstate.c @@ -0,0 +1,37 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include "pthreadP.h" + + +int +__pthread_attr_getdetachstate (const pthread_attr_t *attr, int *detachstate) +{ + struct pthread_attr *iattr; + + assert (sizeof (*attr) >= sizeof (struct pthread_attr)); + iattr = (struct pthread_attr *) attr; + + *detachstate = (iattr->flags & ATTR_FLAG_DETACHSTATE + ? PTHREAD_CREATE_DETACHED : PTHREAD_CREATE_JOINABLE); + + return 0; +} +strong_alias (__pthread_attr_getdetachstate, pthread_attr_getdetachstate) diff --git a/libpthread/nptl/pthread_attr_getguardsize.c b/libpthread/nptl/pthread_attr_getguardsize.c new file mode 100644 index 000000000..6fc3e6af1 --- /dev/null +++ b/libpthread/nptl/pthread_attr_getguardsize.c @@ -0,0 +1,35 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include "pthreadP.h" + + +int +pthread_attr_getguardsize (const pthread_attr_t *attr, size_t *guardsize) +{ + struct pthread_attr *iattr; + + assert (sizeof (*attr) >= sizeof (struct pthread_attr)); + iattr = (struct pthread_attr *) attr; + + *guardsize = iattr->guardsize; + + return 0; +} diff --git a/libpthread/nptl/pthread_attr_getinheritsched.c b/libpthread/nptl/pthread_attr_getinheritsched.c new file mode 100644 index 000000000..3ff304094 --- /dev/null +++ b/libpthread/nptl/pthread_attr_getinheritsched.c @@ -0,0 +1,40 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include "pthreadP.h" + + +int +__pthread_attr_getinheritsched ( + const pthread_attr_t *attr, + int *inherit) +{ + struct pthread_attr *iattr; + + assert (sizeof (*attr) >= sizeof (struct pthread_attr)); + iattr = (struct pthread_attr *) attr; + + /* Store the current values. */ + *inherit = (iattr->flags & ATTR_FLAG_NOTINHERITSCHED + ? PTHREAD_EXPLICIT_SCHED : PTHREAD_INHERIT_SCHED); + + return 0; +} +strong_alias (__pthread_attr_getinheritsched, pthread_attr_getinheritsched) diff --git a/libpthread/nptl/pthread_attr_getschedparam.c b/libpthread/nptl/pthread_attr_getschedparam.c new file mode 100644 index 000000000..82b237198 --- /dev/null +++ b/libpthread/nptl/pthread_attr_getschedparam.c @@ -0,0 +1,40 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include <string.h> +#include "pthreadP.h" + + +int +__pthread_attr_getschedparam ( + const pthread_attr_t *attr, + struct sched_param *param) +{ + struct pthread_attr *iattr; + + assert (sizeof (*attr) >= sizeof (struct pthread_attr)); + iattr = (struct pthread_attr *) attr; + + /* Copy the current values. */ + memcpy (param, &iattr->schedparam, sizeof (struct sched_param)); + + return 0; +} +strong_alias (__pthread_attr_getschedparam, pthread_attr_getschedparam) diff --git a/libpthread/nptl/pthread_attr_getschedpolicy.c b/libpthread/nptl/pthread_attr_getschedpolicy.c new file mode 100644 index 000000000..7b8f1deb6 --- /dev/null +++ b/libpthread/nptl/pthread_attr_getschedpolicy.c @@ -0,0 +1,39 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include "pthreadP.h" + + +int +__pthread_attr_getschedpolicy ( + const pthread_attr_t *attr, + int *policy) +{ + struct pthread_attr *iattr; + + assert (sizeof (*attr) >= sizeof (struct pthread_attr)); + iattr = (struct pthread_attr *) attr; + + /* Store the current values. */ + *policy = iattr->schedpolicy; + + return 0; +} +strong_alias (__pthread_attr_getschedpolicy, pthread_attr_getschedpolicy) diff --git a/libpthread/nptl/pthread_attr_getscope.c b/libpthread/nptl/pthread_attr_getscope.c new file mode 100644 index 000000000..9b05ffaea --- /dev/null +++ b/libpthread/nptl/pthread_attr_getscope.c @@ -0,0 +1,40 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include "pthreadP.h" + + +int +__pthread_attr_getscope ( + const pthread_attr_t *attr, + int *scope) +{ + struct pthread_attr *iattr; + + assert (sizeof (*attr) >= sizeof (struct pthread_attr)); + iattr = (struct pthread_attr *) attr; + + /* Store the current values. */ + *scope = (iattr->flags & ATTR_FLAG_SCOPEPROCESS + ? PTHREAD_SCOPE_PROCESS : PTHREAD_SCOPE_SYSTEM); + + return 0; +} +strong_alias (__pthread_attr_getscope, pthread_attr_getscope) diff --git a/libpthread/nptl/pthread_attr_getstack.c b/libpthread/nptl/pthread_attr_getstack.c new file mode 100644 index 000000000..cb745368f --- /dev/null +++ b/libpthread/nptl/pthread_attr_getstack.c @@ -0,0 +1,41 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include "pthreadP.h" + + +int +__pthread_attr_getstack ( + const pthread_attr_t *attr, + void **stackaddr, + size_t *stacksize) +{ + struct pthread_attr *iattr; + + assert (sizeof (*attr) >= sizeof (struct pthread_attr)); + iattr = (struct pthread_attr *) attr; + + /* Store the result. */ + *stackaddr = (char *) iattr->stackaddr - iattr->stacksize; + *stacksize = iattr->stacksize; + + return 0; +} +strong_alias (__pthread_attr_getstack, pthread_attr_getstack) diff --git a/libpthread/nptl/pthread_attr_getstackaddr.c b/libpthread/nptl/pthread_attr_getstackaddr.c new file mode 100644 index 000000000..305910c16 --- /dev/null +++ b/libpthread/nptl/pthread_attr_getstackaddr.c @@ -0,0 +1,45 @@ +/* Copyright (C) 2002, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include <errno.h> +#include "pthreadP.h" + + +int +__pthread_attr_getstackaddr ( + const pthread_attr_t *attr, + void **stackaddr) +{ + struct pthread_attr *iattr; + + assert (sizeof (*attr) >= sizeof (struct pthread_attr)); + iattr = (struct pthread_attr *) attr; + + /* Some code assumes this function to work even if no stack address + has been set. Let them figure it out for themselves what the + value means. Simply store the result. */ + *stackaddr = iattr->stackaddr; + + return 0; +} +strong_alias (__pthread_attr_getstackaddr, pthread_attr_getstackaddr) + +link_warning (pthread_attr_getstackaddr, + "the use of `pthread_attr_getstackaddr' is deprecated, use `pthread_attr_getstack'") diff --git a/libpthread/nptl/pthread_attr_getstacksize.c b/libpthread/nptl/pthread_attr_getstacksize.c new file mode 100644 index 000000000..ec20f6b96 --- /dev/null +++ b/libpthread/nptl/pthread_attr_getstacksize.c @@ -0,0 +1,40 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include "pthreadP.h" + + +int +__pthread_attr_getstacksize ( + const pthread_attr_t *attr, + size_t *stacksize) +{ + struct pthread_attr *iattr; + + assert (sizeof (*attr) >= sizeof (struct pthread_attr)); + iattr = (struct pthread_attr *) attr; + + /* If the user has not set a stack size we return what the system + will use as the default. */ + *stacksize = iattr->stacksize ?: __default_stacksize; + + return 0; +} +strong_alias (__pthread_attr_getstacksize, pthread_attr_getstacksize) diff --git a/libpthread/nptl/pthread_attr_init.c b/libpthread/nptl/pthread_attr_init.c new file mode 100644 index 000000000..161282c67 --- /dev/null +++ b/libpthread/nptl/pthread_attr_init.c @@ -0,0 +1,49 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include <errno.h> +#include <string.h> +#include <unistd.h> +#include "pthreadP.h" + + +struct pthread_attr *__attr_list; +lll_lock_t __attr_list_lock = LLL_LOCK_INITIALIZER; + + +int +__pthread_attr_init_2_1 (pthread_attr_t *attr) +{ + struct pthread_attr *iattr; + + /* Many elements are initialized to zero so let us do it all at + once. This also takes care of clearing the bytes which are not + internally used. */ + memset (attr, '\0', __SIZEOF_PTHREAD_ATTR_T); + + assert (sizeof (*attr) >= sizeof (struct pthread_attr)); + iattr = (struct pthread_attr *) attr; + + /* Default guard size specified by the standard. */ + iattr->guardsize = getpagesize (); + + return 0; +} +weak_alias(__pthread_attr_init_2_1, pthread_attr_init) diff --git a/libpthread/nptl/pthread_attr_setdetachstate.c b/libpthread/nptl/pthread_attr_setdetachstate.c new file mode 100644 index 000000000..b6d9bb52e --- /dev/null +++ b/libpthread/nptl/pthread_attr_setdetachstate.c @@ -0,0 +1,46 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include <errno.h> +#include "pthreadP.h" + + +int +__pthread_attr_setdetachstate (pthread_attr_t *attr, int detachstate) +{ + struct pthread_attr *iattr; + + assert (sizeof (*attr) >= sizeof (struct pthread_attr)); + iattr = (struct pthread_attr *) attr; + + /* Catch invalid values. */ + if (detachstate != PTHREAD_CREATE_DETACHED + && __builtin_expect (detachstate != PTHREAD_CREATE_JOINABLE, 0)) + return EINVAL; + + /* Set the flag. It is nonzero if threads are created detached. */ + if (detachstate == PTHREAD_CREATE_DETACHED) + iattr->flags |= ATTR_FLAG_DETACHSTATE; + else + iattr->flags &= ~ATTR_FLAG_DETACHSTATE; + + return 0; +} +strong_alias (__pthread_attr_setdetachstate, pthread_attr_setdetachstate) diff --git a/libpthread/nptl/pthread_attr_setguardsize.c b/libpthread/nptl/pthread_attr_setguardsize.c new file mode 100644 index 000000000..a424312f2 --- /dev/null +++ b/libpthread/nptl/pthread_attr_setguardsize.c @@ -0,0 +1,38 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include "pthreadP.h" + + +int +pthread_attr_setguardsize (pthread_attr_t* attr, size_t guardsize) +{ + struct pthread_attr *iattr; + + assert (sizeof (*attr) >= sizeof (struct pthread_attr)); + iattr = (struct pthread_attr *) attr; + + /* Note that we don't round the value here. The standard requires + that subsequent pthread_attr_getguardsize calls return the value + set by the user. */ + iattr->guardsize = guardsize; + + return 0; +} diff --git a/libpthread/nptl/pthread_attr_setinheritsched.c b/libpthread/nptl/pthread_attr_setinheritsched.c new file mode 100644 index 000000000..9d0234aaa --- /dev/null +++ b/libpthread/nptl/pthread_attr_setinheritsched.c @@ -0,0 +1,47 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include <errno.h> +#include "pthreadP.h" + + +int +__pthread_attr_setinheritsched ( + pthread_attr_t *attr, + int inherit) +{ + struct pthread_attr *iattr; + + assert (sizeof (*attr) >= sizeof (struct pthread_attr)); + iattr = (struct pthread_attr *) attr; + + /* Catch invalid values. */ + if (inherit != PTHREAD_INHERIT_SCHED && inherit != PTHREAD_EXPLICIT_SCHED) + return EINVAL; + + /* Store the new values. */ + if (inherit != PTHREAD_INHERIT_SCHED) + iattr->flags |= ATTR_FLAG_NOTINHERITSCHED; + else + iattr->flags &= ~ATTR_FLAG_NOTINHERITSCHED; + + return 0; +} +strong_alias (__pthread_attr_setinheritsched, pthread_attr_setinheritsched) diff --git a/libpthread/nptl/pthread_attr_setschedparam.c b/libpthread/nptl/pthread_attr_setschedparam.c new file mode 100644 index 000000000..137fbe78c --- /dev/null +++ b/libpthread/nptl/pthread_attr_setschedparam.c @@ -0,0 +1,42 @@ +/* Copyright (C) 2002, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include <errno.h> +#include <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; + + /* Copy the new values. */ + memcpy (&iattr->schedparam, param, sizeof (struct sched_param)); + + /* Remember we set the value. */ + iattr->flags |= ATTR_FLAG_SCHED_SET; + + return 0; +} +strong_alias (__pthread_attr_setschedparam, pthread_attr_setschedparam) diff --git a/libpthread/nptl/pthread_attr_setschedpolicy.c b/libpthread/nptl/pthread_attr_setschedpolicy.c new file mode 100644 index 000000000..1d87b53c0 --- /dev/null +++ b/libpthread/nptl/pthread_attr_setschedpolicy.c @@ -0,0 +1,47 @@ +/* Copyright (C) 2002, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include <errno.h> +#include "pthreadP.h" + + +int +__pthread_attr_setschedpolicy ( + pthread_attr_t *attr, + int policy) +{ + struct pthread_attr *iattr; + + assert (sizeof (*attr) >= sizeof (struct pthread_attr)); + iattr = (struct pthread_attr *) attr; + + /* Catch invalid values. */ + if (policy != SCHED_OTHER && policy != SCHED_FIFO && policy != SCHED_RR) + return EINVAL; + + /* Store the new values. */ + iattr->schedpolicy = policy; + + /* Remember we set the value. */ + iattr->flags |= ATTR_FLAG_POLICY_SET; + + return 0; +} +strong_alias (__pthread_attr_setschedpolicy, pthread_attr_setschedpolicy) diff --git a/libpthread/nptl/pthread_attr_setscope.c b/libpthread/nptl/pthread_attr_setscope.c new file mode 100644 index 000000000..cc4e46708 --- /dev/null +++ b/libpthread/nptl/pthread_attr_setscope.c @@ -0,0 +1,51 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include <errno.h> +#include "pthreadP.h" + + +int +__pthread_attr_setscope ( + pthread_attr_t *attr, + int scope) +{ + struct pthread_attr *iattr; + + assert (sizeof (*attr) >= sizeof (struct pthread_attr)); + iattr = (struct pthread_attr *) attr; + + /* Catch invalid values. */ + switch (scope) + { + case PTHREAD_SCOPE_SYSTEM: + iattr->flags &= ~ATTR_FLAG_SCOPEPROCESS; + break; + + case PTHREAD_SCOPE_PROCESS: + return ENOTSUP; + + default: + return EINVAL; + } + + return 0; +} +strong_alias (__pthread_attr_setscope, pthread_attr_setscope) diff --git a/libpthread/nptl/pthread_attr_setstack.c b/libpthread/nptl/pthread_attr_setstack.c new file mode 100644 index 000000000..80780a042 --- /dev/null +++ b/libpthread/nptl/pthread_attr_setstack.c @@ -0,0 +1,56 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include <errno.h> +#include <limits.h> +#include "pthreadP.h" + + +int +__pthread_attr_setstack ( + pthread_attr_t *attr, + void *stackaddr, + size_t stacksize) +{ + struct pthread_attr *iattr; + + assert (sizeof (*attr) >= sizeof (struct pthread_attr)); + iattr = (struct pthread_attr *) attr; + + /* Catch invalid sizes. */ + if (stacksize < PTHREAD_STACK_MIN) + return EINVAL; + +#ifdef EXTRA_PARAM_CHECKS + EXTRA_PARAM_CHECKS; +#endif + + iattr->stacksize = stacksize; + iattr->stackaddr = (char *) stackaddr + stacksize; + iattr->flags |= ATTR_FLAG_STACKADDR; + + return 0; +} + +#if PTHREAD_STACK_MIN == 16384 +strong_alias(__pthread_attr_setstack, pthread_attr_setstack) +#else +weak_alias(__pthread_attr_setstack, pthread_attr_setstack) +#endif diff --git a/libpthread/nptl/pthread_attr_setstackaddr.c b/libpthread/nptl/pthread_attr_setstackaddr.c new file mode 100644 index 000000000..ead54baf0 --- /dev/null +++ b/libpthread/nptl/pthread_attr_setstackaddr.c @@ -0,0 +1,47 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include <errno.h> +#include "pthreadP.h" + + +int +__pthread_attr_setstackaddr ( + pthread_attr_t *attr, + void *stackaddr) +{ + struct pthread_attr *iattr; + +#ifdef EXTRA_PARAM_CHECKS + EXTRA_PARAM_CHECKS; +#endif + + assert (sizeof (*attr) >= sizeof (struct pthread_attr)); + iattr = (struct pthread_attr *) attr; + + iattr->stackaddr = stackaddr; + iattr->flags |= ATTR_FLAG_STACKADDR; + + return 0; +} +strong_alias (__pthread_attr_setstackaddr, pthread_attr_setstackaddr) + +link_warning (pthread_attr_setstackaddr, + "the use of `pthread_attr_setstackaddr' is deprecated, use `pthread_attr_setstack'") diff --git a/libpthread/nptl/pthread_attr_setstacksize.c b/libpthread/nptl/pthread_attr_setstacksize.c new file mode 100644 index 000000000..24e5b0a72 --- /dev/null +++ b/libpthread/nptl/pthread_attr_setstacksize.c @@ -0,0 +1,49 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include <errno.h> +#include <limits.h> +#include "pthreadP.h" + + +int +__pthread_attr_setstacksize ( + pthread_attr_t *attr, + size_t stacksize) +{ + struct pthread_attr *iattr; + + assert (sizeof (*attr) >= sizeof (struct pthread_attr)); + iattr = (struct pthread_attr *) attr; + + /* Catch invalid sizes. */ + if (stacksize < PTHREAD_STACK_MIN) + return EINVAL; + + iattr->stacksize = stacksize; + + return 0; +} + +#if PTHREAD_STACK_MIN == 16384 +strong_alias(__pthread_attr_setstacksize, pthread_attr_setstacksize) +#else +weak_alias(__pthread_attr_setstacksize, pthread_attr_setstacksize) +#endif diff --git a/libpthread/nptl/pthread_barrier_destroy.c b/libpthread/nptl/pthread_barrier_destroy.c new file mode 100644 index 000000000..628c1c378 --- /dev/null +++ b/libpthread/nptl/pthread_barrier_destroy.c @@ -0,0 +1,43 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include "pthreadP.h" +#include <lowlevellock.h> + + +int +pthread_barrier_destroy (pthread_barrier_t *barrier) +{ + struct pthread_barrier *ibarrier; + int result = EBUSY; + + ibarrier = (struct pthread_barrier *) barrier; + + lll_lock (ibarrier->lock); + + if (__builtin_expect (ibarrier->left == ibarrier->init_count, 1)) + /* The barrier is not used anymore. */ + result = 0; + else + /* Still used, return with an error. */ + lll_unlock (ibarrier->lock); + + return result; +} diff --git a/libpthread/nptl/pthread_barrier_init.c b/libpthread/nptl/pthread_barrier_init.c new file mode 100644 index 000000000..98a7ecc3f --- /dev/null +++ b/libpthread/nptl/pthread_barrier_init.c @@ -0,0 +1,57 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include "pthreadP.h" +#include <lowlevellock.h> + + +int +pthread_barrier_init ( + pthread_barrier_t *barrier, + const pthread_barrierattr_t *attr, + unsigned int count) +{ + struct pthread_barrier *ibarrier; + + if (__builtin_expect (count == 0, 0)) + return EINVAL; + + if (attr != NULL) + { + struct pthread_barrierattr *iattr; + + iattr = (struct pthread_barrierattr *) attr; + + if (iattr->pshared != PTHREAD_PROCESS_PRIVATE + && __builtin_expect (iattr->pshared != PTHREAD_PROCESS_SHARED, 0)) + /* Invalid attribute. */ + return EINVAL; + } + + ibarrier = (struct pthread_barrier *) barrier; + + /* Initialize the individual fields. */ + ibarrier->lock = LLL_LOCK_INITIALIZER; + ibarrier->left = count; + ibarrier->init_count = count; + ibarrier->curr_event = 0; + + return 0; +} diff --git a/libpthread/nptl/pthread_barrierattr_destroy.c b/libpthread/nptl/pthread_barrierattr_destroy.c new file mode 100644 index 000000000..5cdcb76fb --- /dev/null +++ b/libpthread/nptl/pthread_barrierattr_destroy.c @@ -0,0 +1,29 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" + + +int +pthread_barrierattr_destroy (pthread_barrierattr_t *attr) +{ + /* Nothing to do. */ + + return 0; +} diff --git a/libpthread/nptl/pthread_barrierattr_getpshared.c b/libpthread/nptl/pthread_barrierattr_getpshared.c new file mode 100644 index 000000000..ee96c0224 --- /dev/null +++ b/libpthread/nptl/pthread_barrierattr_getpshared.c @@ -0,0 +1,31 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" + + +int +pthread_barrierattr_getpshared ( + const pthread_barrierattr_t *attr, + int *pshared) +{ + *pshared = ((const struct pthread_barrierattr *) attr)->pshared; + + return 0; +} diff --git a/libpthread/nptl/pthread_barrierattr_init.c b/libpthread/nptl/pthread_barrierattr_init.c new file mode 100644 index 000000000..17391f91c --- /dev/null +++ b/libpthread/nptl/pthread_barrierattr_init.c @@ -0,0 +1,29 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" + + +int +pthread_barrierattr_init (pthread_barrierattr_t *attr) +{ + ((struct pthread_barrierattr *) attr)->pshared = PTHREAD_PROCESS_PRIVATE; + + return 0; +} diff --git a/libpthread/nptl/pthread_barrierattr_setpshared.c b/libpthread/nptl/pthread_barrierattr_setpshared.c new file mode 100644 index 000000000..fbf6fcb21 --- /dev/null +++ b/libpthread/nptl/pthread_barrierattr_setpshared.c @@ -0,0 +1,40 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include "pthreadP.h" + + +int +pthread_barrierattr_setpshared ( + pthread_barrierattr_t *attr, + int pshared) +{ + struct pthread_barrierattr *iattr; + + if (pshared != PTHREAD_PROCESS_PRIVATE + && __builtin_expect (pshared != PTHREAD_PROCESS_SHARED, 0)) + return EINVAL; + + iattr = (struct pthread_barrierattr *) attr; + + iattr->pshared = pshared; + + return 0; +} diff --git a/libpthread/nptl/pthread_cancel.c b/libpthread/nptl/pthread_cancel.c new file mode 100644 index 000000000..31885234e --- /dev/null +++ b/libpthread/nptl/pthread_cancel.c @@ -0,0 +1,103 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <signal.h> +#include "pthreadP.h" +#include "atomic.h" +#include <sysdep.h> +#include <bits/kernel-features.h> + + +int +pthread_cancel (pthread_t th) +{ + volatile struct pthread *pd = (volatile struct pthread *) th; + + /* Make sure the descriptor is valid. */ + if (INVALID_TD_P (pd)) + /* Not a valid thread handle. */ + return ESRCH; + +#ifdef SHARED + pthread_cancel_init (); +#endif + int result = 0; + int oldval; + int newval; + do + { + oldval = pd->cancelhandling; + newval = oldval | CANCELING_BITMASK | CANCELED_BITMASK; + + /* Avoid doing unnecessary work. The atomic operation can + potentially be expensive if the bug has to be locked and + remote cache lines have to be invalidated. */ + if (oldval == newval) + break; + + /* If the cancellation is handled asynchronously just send a + signal. We avoid this if possible since it's more + expensive. */ + if (CANCEL_ENABLED_AND_CANCELED_AND_ASYNCHRONOUS (newval)) + { + /* Mark the cancellation as "in progress". */ + atomic_bit_set (&pd->cancelhandling, CANCELING_BIT); + + /* The cancellation handler will take care of marking the + thread as canceled. */ + INTERNAL_SYSCALL_DECL (err); + + /* One comment: The PID field in the TCB can temporarily be + changed (in fork). But this must not affect this code + here. Since this function would have to be called while + the thread is executing fork, it would have to happen in + a signal handler. But this is no allowed, pthread_cancel + is not guaranteed to be async-safe. */ + int val; +#if __ASSUME_TGKILL + val = INTERNAL_SYSCALL (tgkill, err, 3, + THREAD_GETMEM (THREAD_SELF, pid), pd->tid, + SIGCANCEL); +#else +# ifdef __NR_tgkill + val = INTERNAL_SYSCALL (tgkill, err, 3, + THREAD_GETMEM (THREAD_SELF, pid), pd->tid, + SIGCANCEL); + if (INTERNAL_SYSCALL_ERROR_P (val, err) + && INTERNAL_SYSCALL_ERRNO (val, err) == ENOSYS) +# endif + val = INTERNAL_SYSCALL (tkill, err, 2, pd->tid, SIGCANCEL); +#endif + + if (INTERNAL_SYSCALL_ERROR_P (val, err)) + result = INTERNAL_SYSCALL_ERRNO (val, err); + + break; + } + } + /* Mark the thread as canceled. This has to be done + atomically since other bits could be modified as well. */ + while (atomic_compare_and_exchange_bool_acq (&pd->cancelhandling, newval, + oldval)); + + return result; +} + +PTHREAD_STATIC_FN_REQUIRE (pthread_create) diff --git a/libpthread/nptl/pthread_clock_gettime.c b/libpthread/nptl/pthread_clock_gettime.c new file mode 100644 index 000000000..a71174c9c --- /dev/null +++ b/libpthread/nptl/pthread_clock_gettime.c @@ -0,0 +1,69 @@ +/* Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <errno.h> +#include <stdlib.h> +#include <time.h> +#include <libc-internal.h> +#include "pthreadP.h" + + +#if HP_TIMING_AVAIL +int +__pthread_clock_gettime (clockid_t clock_id, hp_timing_t freq, + struct timespec *tp) +{ + hp_timing_t tsc; + + /* Get the current counter. */ + HP_TIMING_NOW (tsc); + + /* This is the ID of the thread we are looking for. */ + pid_t tid = ((unsigned int) clock_id) >> CLOCK_IDFIELD_SIZE; + + /* Compute the offset since the start time of the process. */ + if (tid == 0 || tid == THREAD_GETMEM (THREAD_SELF, tid)) + /* Our own clock. */ + tsc -= THREAD_GETMEM (THREAD_SELF, cpuclock_offset); + else + { + /* This is more complicated. We have to locate the thread based + on the ID. This means walking the list of existing + threads. */ + struct pthread *thread = __find_thread_by_id (tid); + if (thread == NULL) + { + __set_errno (EINVAL); + return -1; + } + + /* There is a race here. The thread might terminate and the stack + become unusable. But this is the user's problem. */ + tsc -= thread->cpuclock_offset; + } + + /* Compute the seconds. */ + tp->tv_sec = tsc / freq; + + /* And the nanoseconds. This computation should be stable until + we get machines with about 16GHz frequency. */ + tp->tv_nsec = ((tsc % freq) * 1000000000ull) / freq; + + return 0; +} +#endif diff --git a/libpthread/nptl/pthread_clock_settime.c b/libpthread/nptl/pthread_clock_settime.c new file mode 100644 index 000000000..61002a8f7 --- /dev/null +++ b/libpthread/nptl/pthread_clock_settime.c @@ -0,0 +1,56 @@ +/* Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <errno.h> +#include <stdlib.h> +#include <time.h> +#include <libc-internal.h> +#include "pthreadP.h" + + +#if HP_TIMING_AVAIL +int +__pthread_clock_settime (clockid_t clock_id, hp_timing_t offset) +{ + /* This is the ID of the thread we are looking for. */ + pid_t tid = ((unsigned int) clock_id) >> CLOCK_IDFIELD_SIZE; + + /* Compute the offset since the start time of the process. */ + if (tid == 0 || tid == THREAD_GETMEM (THREAD_SELF, tid)) + /* Our own clock. */ + THREAD_SETMEM (THREAD_SELF, cpuclock_offset, offset); + else + { + /* This is more complicated. We have to locate the thread based + on the ID. This means walking the list of existing + threads. */ + struct pthread *thread = __find_thread_by_id (tid); + if (thread == NULL) + { + __set_errno (EINVAL); + return -1; + } + + /* There is a race here. The thread might terminate and the stack + become unusable. But this is the user's problem. */ + thread->cpuclock_offset = offset; + } + + return 0; +} +#endif diff --git a/libpthread/nptl/pthread_cond_destroy.c b/libpthread/nptl/pthread_cond_destroy.c new file mode 100644 index 000000000..ebc6d78fc --- /dev/null +++ b/libpthread/nptl/pthread_cond_destroy.c @@ -0,0 +1,58 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include "pthreadP.h" + + +int +__pthread_cond_destroy (pthread_cond_t *cond) +{ + /* Make sure we are alone. */ + lll_mutex_lock (cond->__data.__lock); + + 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_mutex_unlock (cond->__data.__lock); + 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; + while (nwaiters >= (1 << COND_CLOCK_BITS)) + { + lll_mutex_unlock (cond->__data.__lock); + + lll_futex_wait (&cond->__data.__nwaiters, nwaiters); + + lll_mutex_lock (cond->__data.__lock); + + nwaiters = cond->__data.__nwaiters; + } + + return 0; +} +weak_alias(__pthread_cond_destroy, pthread_cond_destroy) diff --git a/libpthread/nptl/pthread_cond_init.c b/libpthread/nptl/pthread_cond_init.c new file mode 100644 index 000000000..bf2ab31e6 --- /dev/null +++ b/libpthread/nptl/pthread_cond_init.c @@ -0,0 +1,44 @@ +/* Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" + + +int +__pthread_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_MUTEX_LOCK_INITIALIZER; + cond->__data.__futex = 0; + cond->__data.__nwaiters = (icond_attr != NULL + && ((icond_attr->value & (COND_CLOCK_BITS << 1)) + >> 1)); + cond->__data.__total_seq = 0; + cond->__data.__wakeup_seq = 0; + cond->__data.__woken_seq = 0; + cond->__data.__mutex = (icond_attr == NULL || (icond_attr->value & 1) == 0 + ? NULL : (void *) ~0l); + cond->__data.__broadcast_seq = 0; + + return 0; +} +weak_alias(__pthread_cond_init, pthread_cond_init) diff --git a/libpthread/nptl/pthread_condattr_destroy.c b/libpthread/nptl/pthread_condattr_destroy.c new file mode 100644 index 000000000..bdb644152 --- /dev/null +++ b/libpthread/nptl/pthread_condattr_destroy.c @@ -0,0 +1,29 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" + + +int +__pthread_condattr_destroy (pthread_condattr_t *attr) +{ + /* Nothing to be done. */ + return 0; +} +strong_alias (__pthread_condattr_destroy, pthread_condattr_destroy) diff --git a/libpthread/nptl/pthread_condattr_getclock.c b/libpthread/nptl/pthread_condattr_getclock.c new file mode 100644 index 000000000..056515b1c --- /dev/null +++ b/libpthread/nptl/pthread_condattr_getclock.c @@ -0,0 +1,31 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "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_CLOCK_BITS) - 1)); + return 0; +} diff --git a/libpthread/nptl/pthread_condattr_getpshared.c b/libpthread/nptl/pthread_condattr_getpshared.c new file mode 100644 index 000000000..a558fdb8e --- /dev/null +++ b/libpthread/nptl/pthread_condattr_getpshared.c @@ -0,0 +1,31 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" + + +int +pthread_condattr_getpshared ( + const pthread_condattr_t *attr, + int *pshared) +{ + *pshared = ((const struct pthread_condattr *) attr)->value & 1; + + return 0; +} diff --git a/libpthread/nptl/pthread_condattr_init.c b/libpthread/nptl/pthread_condattr_init.c new file mode 100644 index 000000000..d22ca1e1d --- /dev/null +++ b/libpthread/nptl/pthread_condattr_init.c @@ -0,0 +1,31 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <string.h> +#include "pthreadP.h" + + +int +__pthread_condattr_init (pthread_condattr_t *attr) +{ + memset (attr, '\0', sizeof (*attr)); + + return 0; +} +strong_alias (__pthread_condattr_init, pthread_condattr_init) diff --git a/libpthread/nptl/pthread_condattr_setclock.c b/libpthread/nptl/pthread_condattr_setclock.c new file mode 100644 index 000000000..32b60cfac --- /dev/null +++ b/libpthread/nptl/pthread_condattr_setclock.c @@ -0,0 +1,72 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include <errno.h> +#include <stdbool.h> +#include <time.h> +#include <sysdep.h> +#include "pthreadP.h" +#include <bits/kernel-features.h> + + +int +pthread_condattr_setclock ( + pthread_condattr_t *attr, + clockid_t clock_id) +{ + /* Only a few clocks are allowed. CLOCK_REALTIME is always allowed. + CLOCK_MONOTONIC only if the kernel has the necessary support. */ + if (clock_id == CLOCK_MONOTONIC) + { +#ifndef __ASSUME_POSIX_TIMERS +# ifdef __NR_clock_getres + /* Check whether the clock is available. */ + static int avail; + + if (avail == 0) + { + struct timespec ts; + + INTERNAL_SYSCALL_DECL (err); + int val; + val = INTERNAL_SYSCALL (clock_getres, err, 2, CLOCK_MONOTONIC, &ts); + avail = INTERNAL_SYSCALL_ERROR_P (val, err) ? -1 : 1; + } + + if (avail < 0) +# endif + /* Not available. */ + return EINVAL; +#endif + } + else if (clock_id != CLOCK_REALTIME) + /* If more clocks are allowed some day the storing of the clock ID + in the pthread_cond_t structure needs to be adjusted. */ + return EINVAL; + + /* Make sure the value fits in the bits we reserved. */ + assert (clock_id < (1 << COND_CLOCK_BITS)); + + int *valuep = &((struct pthread_condattr *) attr)->value; + + *valuep = (*valuep & ~(1 << (COND_CLOCK_BITS + 1)) & ~1) | (clock_id << 1); + + return 0; +} diff --git a/libpthread/nptl/pthread_condattr_setpshared.c b/libpthread/nptl/pthread_condattr_setpshared.c new file mode 100644 index 000000000..f3d39aa2b --- /dev/null +++ b/libpthread/nptl/pthread_condattr_setpshared.c @@ -0,0 +1,37 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthreadP.h> + +int +pthread_condattr_setpshared ( + pthread_condattr_t *attr, + int pshared) +{ + if (pshared != PTHREAD_PROCESS_PRIVATE + && __builtin_expect (pshared != PTHREAD_PROCESS_SHARED, 0)) + return EINVAL; + + int *valuep = &((struct pthread_condattr *) attr)->value; + + *valuep = (*valuep & ~1) | (pshared != PTHREAD_PROCESS_PRIVATE); + + return 0; +} diff --git a/libpthread/nptl/pthread_create.c b/libpthread/nptl/pthread_create.c new file mode 100644 index 000000000..903e28dc6 --- /dev/null +++ b/libpthread/nptl/pthread_create.c @@ -0,0 +1,483 @@ +/* Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> +#include "pthreadP.h" +#include <hp-timing.h> +#include <ldsodefs.h> +#include <atomic.h> +#include <libc-internal.h> +#include <resolv.h> + + +/* Local function to start thread and handle cleanup. */ +static int start_thread (void *arg); + + +/* Nozero if debugging mode is enabled. */ +int __pthread_debug; + +/* Globally enabled events. */ +static td_thr_events_t __nptl_threads_events; + +/* Pointer to descriptor with the last event. */ +static struct pthread *__nptl_last_event; + +/* Number of threads running. */ +unsigned int __nptl_nthreads = 1; + + +/* Code to allocate and deallocate a stack. */ +#include "allocatestack.c" + +/* Code to create the thread. */ +#include "createthread.c" + + +struct pthread * +internal_function +__find_in_stack_list (struct pthread *pd) +{ + list_t *entry; + struct pthread *result = NULL; + + lll_lock (stack_cache_lock); + + list_for_each (entry, &stack_used) + { + struct pthread *curp; + + curp = list_entry (entry, struct pthread, list); + if (curp == pd) + { + result = curp; + break; + } + } + + if (result == NULL) + list_for_each (entry, &__stack_user) + { + struct pthread *curp; + + curp = list_entry (entry, struct pthread, list); + if (curp == pd) + { + result = curp; + break; + } + } + + lll_unlock (stack_cache_lock); + + return result; +} + + +/* Deallocate POSIX thread-local-storage. */ +void +attribute_hidden +__nptl_deallocate_tsd (void) +{ + struct pthread *self = THREAD_SELF; + + /* Maybe no data was ever allocated. This happens often so we have + a flag for this. */ + if (THREAD_GETMEM (self, specific_used)) + { + size_t round; + size_t cnt; + + round = 0; + do + { + size_t idx; + + /* So far no new nonzero data entry. */ + THREAD_SETMEM (self, specific_used, false); + + for (cnt = idx = 0; cnt < PTHREAD_KEY_1STLEVEL_SIZE; ++cnt) + { + struct pthread_key_data *level2; + + level2 = THREAD_GETMEM_NC (self, specific, cnt); + + if (level2 != NULL) + { + size_t inner; + + for (inner = 0; inner < PTHREAD_KEY_2NDLEVEL_SIZE; + ++inner, ++idx) + { + void *data = level2[inner].data; + + if (data != NULL) + { + /* Always clear the data. */ + level2[inner].data = NULL; + + /* Make sure the data corresponds to a valid + key. This test fails if the key was + deallocated and also if it was + re-allocated. It is the user's + responsibility to free the memory in this + case. */ + if (level2[inner].seq + == __pthread_keys[idx].seq + /* It is not necessary to register a destructor + function. */ + && __pthread_keys[idx].destr != NULL) + /* Call the user-provided destructor. */ + __pthread_keys[idx].destr (data); + } + } + } + else + idx += PTHREAD_KEY_1STLEVEL_SIZE; + } + + if (THREAD_GETMEM (self, specific_used) == 0) + /* No data has been modified. */ + goto just_free; + } + /* We only repeat the process a fixed number of times. */ + while (__builtin_expect (++round < PTHREAD_DESTRUCTOR_ITERATIONS, 0)); + + /* Just clear the memory of the first block for reuse. */ + memset (&THREAD_SELF->specific_1stblock, '\0', + sizeof (self->specific_1stblock)); + + just_free: + /* Free the memory for the other blocks. */ + for (cnt = 1; cnt < PTHREAD_KEY_1STLEVEL_SIZE; ++cnt) + { + struct pthread_key_data *level2; + + level2 = THREAD_GETMEM_NC (self, specific, cnt); + if (level2 != NULL) + { + /* The first block is allocated as part of the thread + descriptor. */ + free (level2); + THREAD_SETMEM_NC (self, specific, cnt, NULL); + } + } + + THREAD_SETMEM (self, specific_used, false); + } +} + + +/* Deallocate a thread's stack after optionally making sure the thread + descriptor is still valid. */ +void +internal_function +__free_tcb (struct pthread *pd) +{ + /* The thread is exiting now. */ + if (__builtin_expect (atomic_bit_test_set (&pd->cancelhandling, + TERMINATED_BIT) == 0, 1)) + { + /* Remove the descriptor from the list. */ + if (DEBUGGING_P && __find_in_stack_list (pd) == NULL) + /* Something is really wrong. The descriptor for a still + running thread is gone. */ + abort (); + + /* Queue the stack memory block for reuse and exit the process. The + kernel will signal via writing to the address returned by + QUEUE-STACK when the stack is available. */ + __deallocate_stack (pd); + } +} + + +static int +start_thread (void *arg) +{ + struct pthread *pd = (struct pthread *) arg; + +#if HP_TIMING_AVAIL + /* Remember the time when the thread was started. */ + hp_timing_t now; + HP_TIMING_NOW (now); + THREAD_SETMEM (pd, cpuclock_offset, now); +#endif + + /* Initialize resolver state pointer. */ + __resp = &pd->res; + + /* This is where the try/finally block should be created. For + compilers without that support we do use setjmp. */ + struct pthread_unwind_buf unwind_buf; + + /* No previous handlers. */ + unwind_buf.priv.data.prev = NULL; + unwind_buf.priv.data.cleanup = NULL; + + int not_first_call; + not_first_call = setjmp ((struct __jmp_buf_tag *) unwind_buf.cancel_jmp_buf); + if (__builtin_expect (! not_first_call, 1)) + { + /* Store the new cleanup handler info. */ + THREAD_SETMEM (pd, cleanup_jmp_buf, &unwind_buf); + + if (__builtin_expect (pd->stopped_start, 0)) + { + int oldtype = CANCEL_ASYNC (); + + /* Get the lock the parent locked to force synchronization. */ + lll_lock (pd->lock); + /* And give it up right away. */ + lll_unlock (pd->lock); + + CANCEL_RESET (oldtype); + } + + /* Run the code the user provided. */ +#ifdef CALL_THREAD_FCT + THREAD_SETMEM (pd, result, CALL_THREAD_FCT (pd)); +#else + THREAD_SETMEM (pd, result, pd->start_routine (pd->arg)); +#endif + } + + /* Run the destructor for the thread-local data. */ + __nptl_deallocate_tsd (); + + /* If this is the last thread we terminate the process now. We + do not notify the debugger, it might just irritate it if there + is no thread left. */ + if (__builtin_expect (atomic_decrement_and_test (&__nptl_nthreads), 0)) + /* This was the last thread. */ + exit (0); + + /* Report the death of the thread if this is wanted. */ + if (__builtin_expect (pd->report_events, 0)) + { + /* See whether TD_DEATH is in any of the mask. */ + const int idx = __td_eventword (TD_DEATH); + const uint32_t mask = __td_eventmask (TD_DEATH); + + if ((mask & (__nptl_threads_events.event_bits[idx] + | pd->eventbuf.eventmask.event_bits[idx])) != 0) + { + /* Yep, we have to signal the death. Add the descriptor to + the list but only if it is not already on it. */ + if (pd->nextevent == NULL) + { + pd->eventbuf.eventnum = TD_DEATH; + pd->eventbuf.eventdata = pd; + + do + pd->nextevent = __nptl_last_event; + while (atomic_compare_and_exchange_bool_acq (&__nptl_last_event, + pd, pd->nextevent)); + } + + /* Now call the function to signal the event. */ + __nptl_death_event (); + } + } + + /* The thread is exiting now. Don't set this bit until after we've hit + the event-reporting breakpoint, so that td_thr_get_info on us while at + the breakpoint reports TD_THR_RUN state rather than TD_THR_ZOMBIE. */ + atomic_bit_set (&pd->cancelhandling, EXITING_BIT); + + /* If the thread is detached free the TCB. */ + if (IS_DETACHED (pd)) + /* Free the TCB. */ + __free_tcb (pd); + + /* We cannot call '_exit' here. '_exit' will terminate the process. + + The 'exit' implementation in the kernel will signal when the + process is really dead since 'clone' got passed the CLONE_CLEARTID + flag. The 'tid' field in the TCB will be set to zero. + + The exit code is zero since in case all threads exit by calling + 'pthread_exit' the exit status must be 0 (zero). */ + __exit_thread_inline (0); + + /* NOTREACHED */ + return 0; +} + + +/* Default thread attributes for the case when the user does not + provide any. */ +static const struct pthread_attr default_attr = + { + /* Just some value > 0 which gets rounded to the nearest page size. */ + .guardsize = 1, + }; + + +int +__pthread_create_2_1 ( + pthread_t *newthread, + const pthread_attr_t *attr, + void *(*start_routine) (void *), + void *arg) +{ + STACK_VARIABLES; + + const struct pthread_attr *iattr = (struct pthread_attr *) attr; + if (iattr == NULL) + /* Is this the best idea? On NUMA machines this could mean + accessing far-away memory. */ + iattr = &default_attr; + + struct pthread *pd = 0; + int err = ALLOCATE_STACK (iattr, &pd); + if (__builtin_expect (err != 0, 0)) + /* Something went wrong. Maybe a parameter of the attributes is + invalid or we could not allocate memory. */ + return err; + + + /* Initialize the TCB. All initializations with zero should be + performed in 'get_cached_stack'. This way we avoid doing this if + the stack freshly allocated with 'mmap'. */ + +#ifdef TLS_TCB_AT_TP + /* Reference to the TCB itself. */ + pd->header.self = pd; + + /* Self-reference for TLS. */ + pd->header.tcb = pd; +#endif + + /* Store the address of the start routine and the parameter. Since + we do not start the function directly the stillborn thread will + get the information from its thread descriptor. */ + pd->start_routine = start_routine; + pd->arg = arg; + + /* Copy the thread attribute flags. */ + struct pthread *self = THREAD_SELF; + pd->flags = ((iattr->flags & ~(ATTR_FLAG_SCHED_SET | ATTR_FLAG_POLICY_SET)) + | (self->flags & (ATTR_FLAG_SCHED_SET | ATTR_FLAG_POLICY_SET))); + + /* Initialize the field for the ID of the thread which is waiting + for us. This is a self-reference in case the thread is created + detached. */ + pd->joinid = iattr->flags & ATTR_FLAG_DETACHSTATE ? pd : NULL; + + /* The debug events are inherited from the parent. */ + pd->eventbuf = self->eventbuf; + + + /* Copy the parent's scheduling parameters. The flags will say what + is valid and what is not. */ + pd->schedpolicy = self->schedpolicy; + pd->schedparam = self->schedparam; + + /* Copy the stack guard canary. */ +#ifdef THREAD_COPY_STACK_GUARD + THREAD_COPY_STACK_GUARD (pd); +#endif + + /* Determine scheduling parameters for the thread. */ + if (attr != NULL + && __builtin_expect ((iattr->flags & ATTR_FLAG_NOTINHERITSCHED) != 0, 0) + && (iattr->flags & (ATTR_FLAG_SCHED_SET | ATTR_FLAG_POLICY_SET)) != 0) + { + INTERNAL_SYSCALL_DECL (scerr); + + /* Use the scheduling parameters the user provided. */ + if (iattr->flags & ATTR_FLAG_POLICY_SET) + pd->schedpolicy = iattr->schedpolicy; + else if ((pd->flags & ATTR_FLAG_POLICY_SET) == 0) + { + pd->schedpolicy = INTERNAL_SYSCALL (sched_getscheduler, scerr, 1, 0); + pd->flags |= ATTR_FLAG_POLICY_SET; + } + + if (iattr->flags & ATTR_FLAG_SCHED_SET) + memcpy (&pd->schedparam, &iattr->schedparam, + sizeof (struct sched_param)); + else if ((pd->flags & ATTR_FLAG_SCHED_SET) == 0) + { + INTERNAL_SYSCALL (sched_getparam, scerr, 2, 0, &pd->schedparam); + pd->flags |= ATTR_FLAG_SCHED_SET; + } + + /* Check for valid priorities. */ + int minprio = INTERNAL_SYSCALL (sched_get_priority_min, scerr, 1, + iattr->schedpolicy); + int maxprio = INTERNAL_SYSCALL (sched_get_priority_max, scerr, 1, + iattr->schedpolicy); + if (pd->schedparam.sched_priority < minprio + || pd->schedparam.sched_priority > maxprio) + { + err = EINVAL; + goto errout; + } + } + + /* Pass the descriptor to the caller. */ + *newthread = (pthread_t) pd; + + /* Remember whether the thread is detached or not. In case of an + error we have to free the stacks of non-detached stillborn + threads. */ + bool is_detached = IS_DETACHED (pd); + + /* Start the thread. */ + err = create_thread (pd, iattr, STACK_VARIABLES_ARGS); + if (err != 0) + { + /* Something went wrong. Free the resources. */ + if (!is_detached) + { + errout: + __deallocate_stack (pd); + } + return err; + } + + return 0; +} +weak_alias(__pthread_create_2_1, pthread_create) + +/* Information for libthread_db. */ + +#include "../nptl_db/db_info.c" + +/* If pthread_create is present, libgcc_eh.a and libsupc++.a expects some other POSIX thread + functions to be present as well. */ +PTHREAD_STATIC_FN_REQUIRE (pthread_mutex_lock) +PTHREAD_STATIC_FN_REQUIRE (pthread_mutex_unlock) + +PTHREAD_STATIC_FN_REQUIRE (pthread_once) +PTHREAD_STATIC_FN_REQUIRE (pthread_cancel) + +PTHREAD_STATIC_FN_REQUIRE (pthread_key_create) +PTHREAD_STATIC_FN_REQUIRE (pthread_setspecific) +PTHREAD_STATIC_FN_REQUIRE (pthread_getspecific) + +/* UCLIBC_MUTEX_xxx macros expects to have these as well */ +PTHREAD_STATIC_FN_REQUIRE (pthread_mutex_init) +PTHREAD_STATIC_FN_REQUIRE (_pthread_cleanup_push_defer) +PTHREAD_STATIC_FN_REQUIRE (_pthread_cleanup_pop_restore) diff --git a/libpthread/nptl/pthread_detach.c b/libpthread/nptl/pthread_detach.c new file mode 100644 index 000000000..054d7793a --- /dev/null +++ b/libpthread/nptl/pthread_detach.c @@ -0,0 +1,56 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include "pthreadP.h" +#include <atomic.h> + + +int +pthread_detach (pthread_t th) +{ + struct pthread *pd = (struct pthread *) th; + + /* Make sure the descriptor is valid. */ + if (INVALID_NOT_TERMINATED_TD_P (pd)) + /* Not a valid thread handle. */ + return ESRCH; + + int result = 0; + + /* Mark the thread as detached. */ + if (atomic_compare_and_exchange_bool_acq (&pd->joinid, pd, NULL)) + { + /* There are two possibilities here. First, the thread might + already be detached. In this case we return EINVAL. + Otherwise there might already be a waiter. The standard does + not mention what happens in this case. */ + if (IS_DETACHED (pd)) + result = EINVAL; + } + else + /* Check whether the thread terminated meanwhile. In this case we + will just free the TCB. */ + if ((pd->cancelhandling & EXITING_BITMASK) != 0) + /* Note that the code in __free_tcb makes sure each thread + control block is freed only once. */ + __free_tcb (pd); + + return result; +} diff --git a/libpthread/nptl/pthread_equal.c b/libpthread/nptl/pthread_equal.c new file mode 100644 index 000000000..8587e0f52 --- /dev/null +++ b/libpthread/nptl/pthread_equal.c @@ -0,0 +1,28 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" + + +int +__pthread_equal (pthread_t thread1, pthread_t thread2) +{ + return thread1 == thread2; +} +strong_alias (__pthread_equal, pthread_equal) diff --git a/libpthread/nptl/pthread_exit.c b/libpthread/nptl/pthread_exit.c new file mode 100644 index 000000000..a8c92fd29 --- /dev/null +++ b/libpthread/nptl/pthread_exit.c @@ -0,0 +1,31 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <stdlib.h> +#include "pthreadP.h" + + +void +__pthread_exit (void* value) +{ + THREAD_SETMEM (THREAD_SELF, result, value); + + __do_cancel (); +} +strong_alias (__pthread_exit, pthread_exit) diff --git a/libpthread/nptl/pthread_getattr_np.c b/libpthread/nptl/pthread_getattr_np.c new file mode 100644 index 000000000..00b9ba357 --- /dev/null +++ b/libpthread/nptl/pthread_getattr_np.c @@ -0,0 +1,171 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include <errno.h> +#include <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); + + /* The thread library is responsible for keeping the values in the + thread desriptor up-to-date in case the user changes them. */ + memcpy (&iattr->schedparam, &thread->schedparam, + sizeof (struct sched_param)); + iattr->schedpolicy = thread->schedpolicy; + + /* Clear the flags work. */ + iattr->flags = thread->flags; + + /* The thread might be detached by now. */ + if (IS_DETACHED (thread)) + iattr->flags |= ATTR_FLAG_DETACHSTATE; + + /* This is the guardsize after adjusting it. */ + iattr->guardsize = thread->reported_guardsize; + + /* The sizes are subject to alignment. */ + if (__builtin_expect (thread->stackblock != NULL, 1)) + { + iattr->stacksize = thread->stackblock_size; + iattr->stackaddr = (char *) thread->stackblock + iattr->stacksize; + } + else + { + /* No stack information available. This must be for the initial + thread. Get the info in some magical way. */ + assert (abs (thread->pid) == thread->tid); + + /* Stack size limit. */ + struct rlimit rl; + + /* The safest way to get the top of the stack is to read + /proc/self/maps and locate the line into which + __libc_stack_end falls. */ + FILE *fp = fopen ("/proc/self/maps", "rc"); + if (fp == NULL) + ret = errno; + /* We need the limit of the stack in any case. */ + else if (getrlimit (RLIMIT_STACK, &rl) != 0) + ret = errno; + else + { + /* We need no locking. */ + __fsetlocking (fp, FSETLOCKING_BYCALLER); + + /* Until we found an entry (which should always be the case) + mark the result as a failure. */ + ret = ENOENT; + + char *line = NULL; + size_t linelen = 0; + uintptr_t last_to = 0; + + while (! feof_unlocked (fp)) + { + if (getdelim (&line, &linelen, '\n', fp) <= 0) + break; + + uintptr_t from; + uintptr_t to; + if (sscanf (line, "%" SCNxPTR "-%" SCNxPTR, &from, &to) != 2) + continue; + if (from <= (uintptr_t) __libc_stack_end + && (uintptr_t) __libc_stack_end < to) + { + /* Found the entry. Now we have the info we need. */ + iattr->stacksize = rl.rlim_cur; + iattr->stackaddr = (void *) to; + + /* The limit might be too high. */ + if ((size_t) iattr->stacksize + > (size_t) iattr->stackaddr - last_to) + iattr->stacksize = (size_t) iattr->stackaddr - last_to; + + /* We succeed and no need to look further. */ + ret = 0; + break; + } + last_to = to; + } + + fclose (fp); + free (line); + } + } + + iattr->flags |= ATTR_FLAG_STACKADDR; + + if (ret == 0) + { + size_t size = 16; + cpu_set_t *cpuset = NULL; + + do + { + size <<= 1; + + void *newp = realloc (cpuset, size); + if (newp == NULL) + { + ret = ENOMEM; + break; + } + cpuset = (cpu_set_t *) newp; + + ret = __pthread_getaffinity_np (thread_id, size, cpuset); + } + /* Pick some ridiculous upper limit. Is 8 million CPUs enough? */ + while (ret == EINVAL && size < 1024 * 1024); + + if (ret == 0) + { + iattr->cpuset = cpuset; + iattr->cpusetsize = size; + } + else + { + free (cpuset); + if (ret == ENOSYS) + /* There is no such functionality. */ + ret = 0; + } + } + + lll_unlock (thread->lock); + + return ret; +} diff --git a/libpthread/nptl/pthread_getconcurrency.c b/libpthread/nptl/pthread_getconcurrency.c new file mode 100644 index 000000000..52c0c7cbe --- /dev/null +++ b/libpthread/nptl/pthread_getconcurrency.c @@ -0,0 +1,27 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" + + +int +pthread_getconcurrency (void) +{ + return __concurrency_level; +} diff --git a/libpthread/nptl/pthread_getschedparam.c b/libpthread/nptl/pthread_getschedparam.c new file mode 100644 index 000000000..2dd33acc0 --- /dev/null +++ b/libpthread/nptl/pthread_getschedparam.c @@ -0,0 +1,75 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <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); + + /* 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); + + return result; +} +strong_alias (__pthread_getschedparam, pthread_getschedparam) diff --git a/libpthread/nptl/pthread_getspecific.c b/libpthread/nptl/pthread_getspecific.c new file mode 100644 index 000000000..62c48fe8e --- /dev/null +++ b/libpthread/nptl/pthread_getspecific.c @@ -0,0 +1,68 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <stdlib.h> +#include "pthreadP.h" + + +void * +__pthread_getspecific (pthread_key_t key) +{ + struct pthread_key_data *data; + + /* Special case access to the first 2nd-level block. This is the + usual case. */ + if (__builtin_expect (key < PTHREAD_KEY_2NDLEVEL_SIZE, 1)) + data = &THREAD_SELF->specific_1stblock[key]; + else + { + /* Verify the key is sane. */ + if (key >= PTHREAD_KEYS_MAX) + /* Not valid. */ + return NULL; + + unsigned int idx1st = key / PTHREAD_KEY_2NDLEVEL_SIZE; + unsigned int idx2nd = key % PTHREAD_KEY_2NDLEVEL_SIZE; + + /* If the sequence number doesn't match or the key cannot be defined + for this thread since the second level array is not allocated + return NULL, too. */ + struct pthread_key_data *level2 = THREAD_GETMEM_NC (THREAD_SELF, + specific, idx1st); + if (level2 == NULL) + /* Not allocated, therefore no data. */ + return NULL; + + /* There is data. */ + data = &level2[idx2nd]; + } + + void *result = data->data; + if (result != NULL) + { + uintptr_t seq = data->seq; + + if (__builtin_expect (seq != __pthread_keys[key].seq, 0)) + result = data->data = NULL; + } + + return result; +} +strong_alias (__pthread_getspecific, pthread_getspecific) +strong_alias (__pthread_getspecific, __pthread_getspecific_internal) diff --git a/libpthread/nptl/pthread_join.c b/libpthread/nptl/pthread_join.c new file mode 100644 index 000000000..977dbcff4 --- /dev/null +++ b/libpthread/nptl/pthread_join.c @@ -0,0 +1,106 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <stdlib.h> + +#include "atomic.h" +#include "pthreadP.h" + + +static void +cleanup (void *arg) +{ + *(void **) arg = NULL; +} + + +int +pthread_join (pthread_t threadid, void **thread_return) +{ + struct pthread *self; + 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; + + self = THREAD_SELF; + if (pd == self + || (self->joinid == pd + && (pd->cancelhandling + & (CANCELING_BITMASK | CANCELED_BITMASK | EXITING_BITMASK + | TERMINATED_BITMASK)) == 0)) + /* 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. */ + lll_wait_tid (pd->tid); + + + /* Restore cancellation mode. */ + CANCEL_RESET (oldtype); + + /* Remove the handler. */ + pthread_cleanup_pop (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); + + return 0; +} diff --git a/libpthread/nptl/pthread_key_create.c b/libpthread/nptl/pthread_key_create.c new file mode 100644 index 000000000..88d160e18 --- /dev/null +++ b/libpthread/nptl/pthread_key_create.c @@ -0,0 +1,63 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include "pthreadP.h" + + +/* Internal mutex for __pthread_keys table handling. */ +lll_lock_t __pthread_keys_lock = LLL_LOCK_INITIALIZER; + +int +__pthread_key_create ( + pthread_key_t *key, + void (*destr) (void *)) +{ + int result = EAGAIN; + size_t cnt; + + lll_lock (__pthread_keys_lock); + + /* Find a slot in __pthread_kyes which is unused. */ + for (cnt = 0; cnt < PTHREAD_KEYS_MAX; ++cnt) + if (KEY_UNUSED (__pthread_keys[cnt].seq) + && KEY_USABLE (__pthread_keys[cnt].seq)) + { + /* We found an unused slot. */ + ++__pthread_keys[cnt].seq; + + /* Remember the destructor. */ + __pthread_keys[cnt].destr = destr; + + /* Return the key to the caller. */ + *key = cnt; + + /* The call succeeded. */ + result = 0; + + /* We found a key and can stop now. */ + break; + } + + lll_unlock (__pthread_keys_lock); + + return result; +} +strong_alias (__pthread_key_create, pthread_key_create) +strong_alias (__pthread_key_create, __pthread_key_create_internal) diff --git a/libpthread/nptl/pthread_key_delete.c b/libpthread/nptl/pthread_key_delete.c new file mode 100644 index 000000000..cb408f095 --- /dev/null +++ b/libpthread/nptl/pthread_key_delete.c @@ -0,0 +1,42 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include "pthreadP.h" +#include <atomic.h> + + +int +pthread_key_delete (pthread_key_t key) +{ + int result = EINVAL; + + if (__builtin_expect (key < PTHREAD_KEYS_MAX, 1)) + { + unsigned int seq = __pthread_keys[key].seq; + + if (__builtin_expect (! KEY_UNUSED (seq), 1) + && ! atomic_compare_and_exchange_bool_acq (&__pthread_keys[key].seq, + seq + 1, seq)) + /* We deleted a valid key. */ + result = 0; + } + + return result; +} diff --git a/libpthread/nptl/pthread_kill_other_threads.c b/libpthread/nptl/pthread_kill_other_threads.c new file mode 100644 index 000000000..09401aab5 --- /dev/null +++ b/libpthread/nptl/pthread_kill_other_threads.c @@ -0,0 +1,32 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifdef SHARED +/* This function does not serve a useful purpose in the thread library + implementation anymore. It used to be necessary when then kernel + could not shut down "processes" but this is not the case anymore. + + We could theoretically provide an equivalent implementation but + this is not necessary since the kernel already does a much better + job than we ever could. */ +void +__pthread_kill_other_threads_np (void) +{ +} +#endif diff --git a/libpthread/nptl/pthread_mutex_destroy.c b/libpthread/nptl/pthread_mutex_destroy.c new file mode 100644 index 000000000..05bd96a3c --- /dev/null +++ b/libpthread/nptl/pthread_mutex_destroy.c @@ -0,0 +1,32 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include "pthreadP.h" + + +int +__pthread_mutex_destroy (pthread_mutex_t *mutex) +{ + if (mutex->__data.__nusers != 0) + return EBUSY; + + return 0; +} +strong_alias (__pthread_mutex_destroy, pthread_mutex_destroy) diff --git a/libpthread/nptl/pthread_mutex_init.c b/libpthread/nptl/pthread_mutex_init.c new file mode 100644 index 000000000..2349497fe --- /dev/null +++ b/libpthread/nptl/pthread_mutex_init.c @@ -0,0 +1,57 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include <string.h> +#include "pthreadP.h" + + +static const struct pthread_mutexattr default_attr = + { + /* Default is a normal mutex, not shared between processes. */ + .mutexkind = PTHREAD_MUTEX_NORMAL + }; + + +int +__pthread_mutex_init ( + pthread_mutex_t *mutex, + const pthread_mutexattr_t *mutexattr) +{ + const struct pthread_mutexattr *imutexattr; + + assert (sizeof (pthread_mutex_t) <= __SIZEOF_PTHREAD_MUTEX_T); + + imutexattr = (const struct pthread_mutexattr *) mutexattr ?: &default_attr; + + /* Clear the whole variable. */ + memset (mutex, '\0', __SIZEOF_PTHREAD_MUTEX_T); + + /* Copy the values from the attribute. */ + mutex->__data.__kind = imutexattr->mutexkind & ~0x80000000; + + /* Default values: mutex not used yet. */ + // mutex->__count = 0; already done by memset + // mutex->__owner = 0; already done by memset + // mutex->__nusers = 0; already done by memset + // mutex->__spins = 0; already done by memset + + return 0; +} +strong_alias (__pthread_mutex_init, pthread_mutex_init) diff --git a/libpthread/nptl/pthread_mutex_lock.c b/libpthread/nptl/pthread_mutex_lock.c new file mode 100644 index 000000000..faa5391dd --- /dev/null +++ b/libpthread/nptl/pthread_mutex_lock.c @@ -0,0 +1,118 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include <errno.h> +#include "pthreadP.h" +#include <lowlevellock.h> + + +#ifndef LLL_MUTEX_LOCK +# define LLL_MUTEX_LOCK(mutex) lll_mutex_lock (mutex) +# define LLL_MUTEX_TRYLOCK(mutex) lll_mutex_trylock (mutex) +#endif + + +int +__pthread_mutex_lock (pthread_mutex_t *mutex) +{ + assert (sizeof (mutex->__size) >= sizeof (mutex->__data)); + + pid_t id = THREAD_GETMEM (THREAD_SELF, tid); + + switch (__builtin_expect (mutex->__data.__kind, PTHREAD_MUTEX_TIMED_NP)) + { + /* Recursive mutex. */ + case PTHREAD_MUTEX_RECURSIVE_NP: + /* Check whether we already hold the mutex. */ + if (mutex->__data.__owner == id) + { + /* Just bump the counter. */ + if (__builtin_expect (mutex->__data.__count + 1 == 0, 0)) + /* Overflow of the counter. */ + return EAGAIN; + + ++mutex->__data.__count; + + return 0; + } + + /* We have to get the mutex. */ + LLL_MUTEX_LOCK (mutex->__data.__lock); + + mutex->__data.__count = 1; + break; + + /* Error checking mutex. */ + case PTHREAD_MUTEX_ERRORCHECK_NP: + /* Check whether we already hold the mutex. */ + if (mutex->__data.__owner == id) + return EDEADLK; + + /* FALLTHROUGH */ + + default: + /* Correct code cannot set any other type. */ + case PTHREAD_MUTEX_TIMED_NP: + simple: + /* Normal mutex. */ + LLL_MUTEX_LOCK (mutex->__data.__lock); + break; + + case PTHREAD_MUTEX_ADAPTIVE_NP: + if (! __is_smp) + goto simple; + + if (LLL_MUTEX_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) + { + LLL_MUTEX_LOCK (mutex->__data.__lock); + break; + } + +#ifdef BUSY_WAIT_NOP + BUSY_WAIT_NOP; +#endif + } + while (LLL_MUTEX_TRYLOCK (mutex->__data.__lock) != 0); + + mutex->__data.__spins += (cnt - mutex->__data.__spins) / 8; + } + break; + } + + /* Record the ownership. */ + assert (mutex->__data.__owner == 0); + mutex->__data.__owner = id; +#ifndef NO_INCR + ++mutex->__data.__nusers; +#endif + + return 0; +} +#ifndef __pthread_mutex_lock +strong_alias (__pthread_mutex_lock, pthread_mutex_lock) +strong_alias (__pthread_mutex_lock, __pthread_mutex_lock_internal) +#endif diff --git a/libpthread/nptl/pthread_mutex_timedlock.c b/libpthread/nptl/pthread_mutex_timedlock.c new file mode 100644 index 000000000..6f3df6ff0 --- /dev/null +++ b/libpthread/nptl/pthread_mutex_timedlock.c @@ -0,0 +1,118 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include "pthreadP.h" +#include <lowlevellock.h> + + +int +pthread_mutex_timedlock ( + pthread_mutex_t *mutex, + const struct timespec *abstime) +{ + pid_t id = THREAD_GETMEM (THREAD_SELF, tid); + int result = 0; + + /* We must not check ABSTIME here. If the thread does not block + abstime must not be checked for a valid value. */ + + switch (mutex->__data.__kind) + { + /* Recursive mutex. */ + case PTHREAD_MUTEX_RECURSIVE_NP: + /* Check whether we already hold the mutex. */ + if (mutex->__data.__owner == id) + { + /* Just bump the counter. */ + if (__builtin_expect (mutex->__data.__count + 1 == 0, 0)) + /* Overflow of the counter. */ + return EAGAIN; + + ++mutex->__data.__count; + + goto out; + } + else + { + /* We have to get the mutex. */ + result = lll_mutex_timedlock (mutex->__data.__lock, abstime); + + if (result != 0) + goto out; + + /* Only locked once so far. */ + mutex->__data.__count = 1; + } + break; + + /* Error checking mutex. */ + case PTHREAD_MUTEX_ERRORCHECK_NP: + /* Check whether we already hold the mutex. */ + if (mutex->__data.__owner == id) + return EDEADLK; + + /* FALLTHROUGH */ + + default: + /* Correct code cannot set any other type. */ + case PTHREAD_MUTEX_TIMED_NP: + simple: + /* Normal mutex. */ + result = lll_mutex_timedlock (mutex->__data.__lock, abstime); + break; + + case PTHREAD_MUTEX_ADAPTIVE_NP: + if (! __is_smp) + goto simple; + + if (lll_mutex_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_mutex_timedlock (mutex->__data.__lock, abstime); + break; + } + +#ifdef BUSY_WAIT_NOP + BUSY_WAIT_NOP; +#endif + } + while (lll_mutex_trylock (mutex->__data.__lock) != 0); + + mutex->__data.__spins += (cnt - mutex->__data.__spins) / 8; + } + break; + } + + if (result == 0) + { + /* Record the ownership. */ + mutex->__data.__owner = id; + ++mutex->__data.__nusers; + } + + out: + return result; +} diff --git a/libpthread/nptl/pthread_mutex_trylock.c b/libpthread/nptl/pthread_mutex_trylock.c new file mode 100644 index 000000000..2eb88db53 --- /dev/null +++ b/libpthread/nptl/pthread_mutex_trylock.c @@ -0,0 +1,76 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include "pthreadP.h" +#include <lowlevellock.h> + + +int +__pthread_mutex_trylock (pthread_mutex_t *mutex) +{ + pid_t id; + + switch (__builtin_expect (mutex->__data.__kind, PTHREAD_MUTEX_TIMED_NP)) + { + /* Recursive mutex. */ + case PTHREAD_MUTEX_RECURSIVE_NP: + id = THREAD_GETMEM (THREAD_SELF, tid); + /* Check whether we already hold the mutex. */ + if (mutex->__data.__owner == id) + { + /* Just bump the counter. */ + if (__builtin_expect (mutex->__data.__count + 1 == 0, 0)) + /* Overflow of the counter. */ + return EAGAIN; + + ++mutex->__data.__count; + return 0; + } + + if (lll_mutex_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: + /* Error checking mutex. We do not check for deadlocks. */ + default: + /* Correct code cannot set any other type. */ + case PTHREAD_MUTEX_TIMED_NP: + case PTHREAD_MUTEX_ADAPTIVE_NP: + /* Normal mutex. */ + if (lll_mutex_trylock (mutex->__data.__lock) == 0) + { + /* Record the ownership. */ + mutex->__data.__owner = THREAD_GETMEM (THREAD_SELF, tid); + ++mutex->__data.__nusers; + + return 0; + } + } + + return EBUSY; +} +strong_alias (__pthread_mutex_trylock, pthread_mutex_trylock) diff --git a/libpthread/nptl/pthread_mutex_unlock.c b/libpthread/nptl/pthread_mutex_unlock.c new file mode 100644 index 000000000..0cb6df36c --- /dev/null +++ b/libpthread/nptl/pthread_mutex_unlock.c @@ -0,0 +1,77 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include "pthreadP.h" +#include <lowlevellock.h> + + +int +internal_function attribute_hidden +__pthread_mutex_unlock_usercnt ( + pthread_mutex_t *mutex, + int decr) +{ + switch (__builtin_expect (mutex->__data.__kind, PTHREAD_MUTEX_TIMED_NP)) + { + case PTHREAD_MUTEX_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; + break; + + case PTHREAD_MUTEX_ERRORCHECK_NP: + /* Error checking mutex. */ + if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid) + || ! lll_mutex_islocked (mutex->__data.__lock)) + return EPERM; + break; + + default: + /* Correct code cannot set any other type. */ + case PTHREAD_MUTEX_TIMED_NP: + case PTHREAD_MUTEX_ADAPTIVE_NP: + /* Normal mutex. Nothing special to do. */ + break; + } + + /* Always reset the owner field. */ + mutex->__data.__owner = 0; + if (decr) + /* One less user. */ + --mutex->__data.__nusers; + + /* Unlock. */ + lll_mutex_unlock (mutex->__data.__lock); + + return 0; +} + + +int +__pthread_mutex_unlock (pthread_mutex_t *mutex) +{ + return __pthread_mutex_unlock_usercnt (mutex, 1); +} +strong_alias (__pthread_mutex_unlock, pthread_mutex_unlock) +strong_alias (__pthread_mutex_unlock, __pthread_mutex_unlock_internal) diff --git a/libpthread/nptl/pthread_mutexattr_destroy.c b/libpthread/nptl/pthread_mutexattr_destroy.c new file mode 100644 index 000000000..adf2884bf --- /dev/null +++ b/libpthread/nptl/pthread_mutexattr_destroy.c @@ -0,0 +1,28 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthreadP.h> + + +int +__pthread_mutexattr_destroy (pthread_mutexattr_t *attr) +{ + return 0; +} +strong_alias (__pthread_mutexattr_destroy, pthread_mutexattr_destroy) diff --git a/libpthread/nptl/pthread_mutexattr_getpshared.c b/libpthread/nptl/pthread_mutexattr_getpshared.c new file mode 100644 index 000000000..12de51662 --- /dev/null +++ b/libpthread/nptl/pthread_mutexattr_getpshared.c @@ -0,0 +1,38 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthreadP.h> + + +int +pthread_mutexattr_getpshared ( + const pthread_mutexattr_t *attr, + int *pshared) +{ + const struct pthread_mutexattr *iattr; + + iattr = (const struct pthread_mutexattr *) attr; + + /* We use bit 31 to signal whether the mutex is going to be + process-shared or not. */ + *pshared = ((iattr->mutexkind & 0x80000000) != 0 + ? PTHREAD_PROCESS_SHARED : PTHREAD_PROCESS_PRIVATE); + + return 0; +} diff --git a/libpthread/nptl/pthread_mutexattr_gettype.c b/libpthread/nptl/pthread_mutexattr_gettype.c new file mode 100644 index 000000000..0f380a939 --- /dev/null +++ b/libpthread/nptl/pthread_mutexattr_gettype.c @@ -0,0 +1,38 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthreadP.h> + + +int +pthread_mutexattr_gettype ( + const pthread_mutexattr_t *attr, + int *kind) +{ + const struct pthread_mutexattr *iattr; + + iattr = (const struct pthread_mutexattr *) attr; + + /* We use bit 31 to signal whether the mutex is going to be + process-shared or not. */ + *kind = iattr->mutexkind & ~0x80000000; + + return 0; +} +weak_alias (pthread_mutexattr_gettype, pthread_mutexattr_getkind_np) diff --git a/libpthread/nptl/pthread_mutexattr_init.c b/libpthread/nptl/pthread_mutexattr_init.c new file mode 100644 index 000000000..ce8080d59 --- /dev/null +++ b/libpthread/nptl/pthread_mutexattr_init.c @@ -0,0 +1,37 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <string.h> +#include <pthreadP.h> + + +int +__pthread_mutexattr_init (pthread_mutexattr_t *attr) +{ + if (sizeof (struct pthread_mutexattr) != sizeof (pthread_mutexattr_t)) + memset (attr, '\0', sizeof (*attr)); + + /* We use bit 31 to signal whether the mutex is going to be + process-shared or not. By default it is zero, i.e., the mutex is + not process-shared. */ + ((struct pthread_mutexattr *) attr)->mutexkind = PTHREAD_MUTEX_NORMAL; + + return 0; +} +strong_alias (__pthread_mutexattr_init, pthread_mutexattr_init) diff --git a/libpthread/nptl/pthread_mutexattr_setpshared.c b/libpthread/nptl/pthread_mutexattr_setpshared.c new file mode 100644 index 000000000..74df1bfdd --- /dev/null +++ b/libpthread/nptl/pthread_mutexattr_setpshared.c @@ -0,0 +1,45 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthreadP.h> + + +int +pthread_mutexattr_setpshared ( + pthread_mutexattr_t *attr, + int pshared) +{ + struct pthread_mutexattr *iattr; + + if (pshared != PTHREAD_PROCESS_PRIVATE + && __builtin_expect (pshared != PTHREAD_PROCESS_SHARED, 0)) + return EINVAL; + + iattr = (struct pthread_mutexattr *) attr; + + /* We use bit 31 to signal whether the mutex is going to be + process-shared or not. */ + if (pshared == PTHREAD_PROCESS_PRIVATE) + iattr->mutexkind &= ~0x80000000; + else + iattr->mutexkind |= 0x80000000; + + return 0; +} diff --git a/libpthread/nptl/pthread_mutexattr_settype.c b/libpthread/nptl/pthread_mutexattr_settype.c new file mode 100644 index 000000000..aaeec8120 --- /dev/null +++ b/libpthread/nptl/pthread_mutexattr_settype.c @@ -0,0 +1,43 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthreadP.h> + + +int +__pthread_mutexattr_settype ( + pthread_mutexattr_t *attr, + int kind) +{ + struct pthread_mutexattr *iattr; + + if (kind < PTHREAD_MUTEX_NORMAL || kind > PTHREAD_MUTEX_ADAPTIVE_NP) + return EINVAL; + + iattr = (struct pthread_mutexattr *) attr; + + /* We use bit 31 to signal whether the mutex is going to be + process-shared or not. */ + iattr->mutexkind = (iattr->mutexkind & 0x80000000) | kind; + + return 0; +} +weak_alias (__pthread_mutexattr_settype, pthread_mutexattr_setkind_np) +strong_alias (__pthread_mutexattr_settype, pthread_mutexattr_settype) diff --git a/libpthread/nptl/pthread_rwlock_destroy.c b/libpthread/nptl/pthread_rwlock_destroy.c new file mode 100644 index 000000000..d38202b43 --- /dev/null +++ b/libpthread/nptl/pthread_rwlock_destroy.c @@ -0,0 +1,29 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" + + +int +__pthread_rwlock_destroy (pthread_rwlock_t *rwlock) +{ + /* Nothing to be done. For now. */ + return 0; +} +strong_alias (__pthread_rwlock_destroy, pthread_rwlock_destroy) diff --git a/libpthread/nptl/pthread_rwlock_init.c b/libpthread/nptl/pthread_rwlock_init.c new file mode 100644 index 000000000..8055960e0 --- /dev/null +++ b/libpthread/nptl/pthread_rwlock_init.c @@ -0,0 +1,51 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" + + +static const struct pthread_rwlockattr default_attr = + { + .lockkind = PTHREAD_RWLOCK_DEFAULT_NP, + .pshared = PTHREAD_PROCESS_PRIVATE + }; + + +int +__pthread_rwlock_init ( + pthread_rwlock_t *rwlock, + const pthread_rwlockattr_t *attr) +{ + const struct pthread_rwlockattr *iattr; + + iattr = ((const struct pthread_rwlockattr *) attr) ?: &default_attr; + + rwlock->__data.__lock = 0; + rwlock->__data.__flags + = iattr->lockkind == PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP; + rwlock->__data.__nr_readers = 0; + rwlock->__data.__writer = 0; + rwlock->__data.__readers_wakeup = 0; + rwlock->__data.__writer_wakeup = 0; + rwlock->__data.__nr_readers_queued = 0; + rwlock->__data.__nr_writers_queued = 0; + + return 0; +} +strong_alias (__pthread_rwlock_init, pthread_rwlock_init) diff --git a/libpthread/nptl/pthread_rwlock_tryrdlock.c b/libpthread/nptl/pthread_rwlock_tryrdlock.c new file mode 100644 index 000000000..0a9c815e0 --- /dev/null +++ b/libpthread/nptl/pthread_rwlock_tryrdlock.c @@ -0,0 +1,49 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include "pthreadP.h" +#include <lowlevellock.h> + + +int +__pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock) +{ + int result = EBUSY; + + lll_mutex_lock (rwlock->__data.__lock); + + if (rwlock->__data.__writer == 0 + && (rwlock->__data.__nr_writers_queued == 0 + || rwlock->__data.__flags == 0)) + { + if (__builtin_expect (++rwlock->__data.__nr_readers == 0, 0)) + { + --rwlock->__data.__nr_readers; + result = EAGAIN; + } + else + result = 0; + } + + lll_mutex_unlock (rwlock->__data.__lock); + + return result; +} +strong_alias (__pthread_rwlock_tryrdlock, pthread_rwlock_tryrdlock) diff --git a/libpthread/nptl/pthread_rwlock_trywrlock.c b/libpthread/nptl/pthread_rwlock_trywrlock.c new file mode 100644 index 000000000..47150c154 --- /dev/null +++ b/libpthread/nptl/pthread_rwlock_trywrlock.c @@ -0,0 +1,42 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include "pthreadP.h" +#include <lowlevellock.h> + + +int +__pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock) +{ + int result = EBUSY; + + lll_mutex_lock (rwlock->__data.__lock); + + if (rwlock->__data.__writer == 0 && rwlock->__data.__nr_readers == 0) + { + rwlock->__data.__writer = THREAD_GETMEM (THREAD_SELF, tid); + result = 0; + } + + lll_mutex_unlock (rwlock->__data.__lock); + + return result; +} +strong_alias (__pthread_rwlock_trywrlock, pthread_rwlock_trywrlock) diff --git a/libpthread/nptl/pthread_rwlockattr_destroy.c b/libpthread/nptl/pthread_rwlockattr_destroy.c new file mode 100644 index 000000000..db1870413 --- /dev/null +++ b/libpthread/nptl/pthread_rwlockattr_destroy.c @@ -0,0 +1,29 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" + + +int +pthread_rwlockattr_destroy (pthread_rwlockattr_t *attr) +{ + /* Nothing to do. For now. */ + + return 0; +} diff --git a/libpthread/nptl/pthread_rwlockattr_getkind_np.c b/libpthread/nptl/pthread_rwlockattr_getkind_np.c new file mode 100644 index 000000000..b15275c4d --- /dev/null +++ b/libpthread/nptl/pthread_rwlockattr_getkind_np.c @@ -0,0 +1,31 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" + + +int +pthread_rwlockattr_getkind_np ( + const pthread_rwlockattr_t *attr, + int *pref) +{ + *pref = ((const struct pthread_rwlockattr *) attr)->lockkind; + + return 0; +} diff --git a/libpthread/nptl/pthread_rwlockattr_getpshared.c b/libpthread/nptl/pthread_rwlockattr_getpshared.c new file mode 100644 index 000000000..2e0437c78 --- /dev/null +++ b/libpthread/nptl/pthread_rwlockattr_getpshared.c @@ -0,0 +1,31 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" + + +int +pthread_rwlockattr_getpshared ( + const pthread_rwlockattr_t *attr, + int *pshared) +{ + *pshared = ((const struct pthread_rwlockattr *) attr)->pshared; + + return 0; +} diff --git a/libpthread/nptl/pthread_rwlockattr_init.c b/libpthread/nptl/pthread_rwlockattr_init.c new file mode 100644 index 000000000..b33ae5bff --- /dev/null +++ b/libpthread/nptl/pthread_rwlockattr_init.c @@ -0,0 +1,34 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" + + +int +pthread_rwlockattr_init (pthread_rwlockattr_t *attr) +{ + struct pthread_rwlockattr *iattr; + + iattr = (struct pthread_rwlockattr *) attr; + + iattr->lockkind = PTHREAD_RWLOCK_DEFAULT_NP; + iattr->pshared = PTHREAD_PROCESS_PRIVATE; + + return 0; +} diff --git a/libpthread/nptl/pthread_rwlockattr_setkind_np.c b/libpthread/nptl/pthread_rwlockattr_setkind_np.c new file mode 100644 index 000000000..186bf737b --- /dev/null +++ b/libpthread/nptl/pthread_rwlockattr_setkind_np.c @@ -0,0 +1,41 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include "pthreadP.h" + + +int +pthread_rwlockattr_setkind_np ( + pthread_rwlockattr_t *attr, + int pref) +{ + struct pthread_rwlockattr *iattr; + + if (pref != PTHREAD_RWLOCK_PREFER_READER_NP + && pref != PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP + && __builtin_expect (pref != PTHREAD_RWLOCK_PREFER_WRITER_NP, 0)) + return EINVAL; + + iattr = (struct pthread_rwlockattr *) attr; + + iattr->lockkind = pref; + + return 0; +} diff --git a/libpthread/nptl/pthread_rwlockattr_setpshared.c b/libpthread/nptl/pthread_rwlockattr_setpshared.c new file mode 100644 index 000000000..a30de0eeb --- /dev/null +++ b/libpthread/nptl/pthread_rwlockattr_setpshared.c @@ -0,0 +1,40 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include "pthreadP.h" + + +int +pthread_rwlockattr_setpshared ( + pthread_rwlockattr_t *attr, + int pshared) +{ + struct pthread_rwlockattr *iattr; + + if (pshared != PTHREAD_PROCESS_SHARED + && __builtin_expect (pshared != PTHREAD_PROCESS_PRIVATE, 0)) + return EINVAL; + + iattr = (struct pthread_rwlockattr *) attr; + + iattr->pshared = pshared; + + return 0; +} diff --git a/libpthread/nptl/pthread_self.c b/libpthread/nptl/pthread_self.c new file mode 100644 index 000000000..f0e3b3f98 --- /dev/null +++ b/libpthread/nptl/pthread_self.c @@ -0,0 +1,29 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" +#include <tls.h> + + +pthread_t +__pthread_self (void) +{ + return (pthread_t) THREAD_SELF; +} +strong_alias (__pthread_self, pthread_self) diff --git a/libpthread/nptl/pthread_setcancelstate.c b/libpthread/nptl/pthread_setcancelstate.c new file mode 100644 index 000000000..e53b52d67 --- /dev/null +++ b/libpthread/nptl/pthread_setcancelstate.c @@ -0,0 +1,73 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include "pthreadP.h" +#include <atomic.h> + + +int +__pthread_setcancelstate ( + int state, + int *oldstate) +{ + volatile struct pthread *self; + + if (state < PTHREAD_CANCEL_ENABLE || state > PTHREAD_CANCEL_DISABLE) + return EINVAL; + + self = THREAD_SELF; + + int oldval = THREAD_GETMEM (self, cancelhandling); + while (1) + { + int newval = (state == PTHREAD_CANCEL_DISABLE + ? oldval | CANCELSTATE_BITMASK + : oldval & ~CANCELSTATE_BITMASK); + + /* Store the old value. */ + if (oldstate != NULL) + *oldstate = ((oldval & CANCELSTATE_BITMASK) + ? PTHREAD_CANCEL_DISABLE : PTHREAD_CANCEL_ENABLE); + + /* Avoid doing unnecessary work. The atomic operation can + potentially be expensive if the memory has to be locked and + remote cache lines have to be invalidated. */ + if (oldval == newval) + break; + + /* Update the cancel handling word. This has to be done + atomically since other bits could be modified as well. */ + int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, newval, + oldval); + if (__builtin_expect (curval == oldval, 1)) + { + if (CANCEL_ENABLED_AND_CANCELED_AND_ASYNCHRONOUS (newval)) + __do_cancel (); + + break; + } + + /* Prepare for the next round. */ + oldval = curval; + } + + return 0; +} +strong_alias (__pthread_setcancelstate, pthread_setcancelstate) diff --git a/libpthread/nptl/pthread_setcanceltype.c b/libpthread/nptl/pthread_setcanceltype.c new file mode 100644 index 000000000..47c104b02 --- /dev/null +++ b/libpthread/nptl/pthread_setcanceltype.c @@ -0,0 +1,76 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include "pthreadP.h" +#include <atomic.h> + + +int +__pthread_setcanceltype ( + int type, + int *oldtype) +{ + volatile struct pthread *self; + + if (type < PTHREAD_CANCEL_DEFERRED || type > PTHREAD_CANCEL_ASYNCHRONOUS) + return EINVAL; + + self = THREAD_SELF; + + int oldval = THREAD_GETMEM (self, cancelhandling); + while (1) + { + int newval = (type == PTHREAD_CANCEL_ASYNCHRONOUS + ? oldval | CANCELTYPE_BITMASK + : oldval & ~CANCELTYPE_BITMASK); + + /* Store the old value. */ + if (oldtype != NULL) + *oldtype = ((oldval & CANCELTYPE_BITMASK) + ? PTHREAD_CANCEL_ASYNCHRONOUS : PTHREAD_CANCEL_DEFERRED); + + /* Avoid doing unnecessary work. The atomic operation can + potentially be expensive if the memory has to be locked and + remote cache lines have to be invalidated. */ + if (oldval == newval) + break; + + /* Update the cancel handling word. This has to be done + atomically since other bits could be modified as well. */ + int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, newval, + oldval); + if (__builtin_expect (curval == oldval, 1)) + { + if (CANCEL_ENABLED_AND_CANCELED_AND_ASYNCHRONOUS (newval)) + { + THREAD_SETMEM (self, result, PTHREAD_CANCELED); + __do_cancel (); + } + + break; + } + + /* Prepare for the next round. */ + oldval = curval; + } + + return 0; +} +strong_alias (__pthread_setcanceltype, pthread_setcanceltype) diff --git a/libpthread/nptl/pthread_setconcurrency.c b/libpthread/nptl/pthread_setconcurrency.c new file mode 100644 index 000000000..754fe3f25 --- /dev/null +++ b/libpthread/nptl/pthread_setconcurrency.c @@ -0,0 +1,40 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include "pthreadP.h" + + +/* Global definition. Needed in pthread_getconcurrency as well. */ +int __concurrency_level; + + +int +pthread_setconcurrency (int level) +{ + if (level < 0) + return EINVAL; + + __concurrency_level = level; + + /* XXX For ports which actually need to handle the concurrency level + some more code is probably needed here. */ + + return 0; +} diff --git a/libpthread/nptl/pthread_setegid.c b/libpthread/nptl/pthread_setegid.c new file mode 100644 index 000000000..9252dfac7 --- /dev/null +++ b/libpthread/nptl/pthread_setegid.c @@ -0,0 +1,3 @@ +#define SINGLE_THREAD +#define setegid pthread_setegid_np +#include <setegid.c> diff --git a/libpthread/nptl/pthread_seteuid.c b/libpthread/nptl/pthread_seteuid.c new file mode 100644 index 000000000..47bb69802 --- /dev/null +++ b/libpthread/nptl/pthread_seteuid.c @@ -0,0 +1,3 @@ +#define SINGLE_THREAD +#define seteuid pthread_seteuid_np +#include <seteuid.c> diff --git a/libpthread/nptl/pthread_setgid.c b/libpthread/nptl/pthread_setgid.c new file mode 100644 index 000000000..b06bffbf3 --- /dev/null +++ b/libpthread/nptl/pthread_setgid.c @@ -0,0 +1,3 @@ +#define SINGLE_THREAD +#define __setgid pthread_setgid_np +#include <setgid.c> diff --git a/libpthread/nptl/pthread_setregid.c b/libpthread/nptl/pthread_setregid.c new file mode 100644 index 000000000..7461d2b7f --- /dev/null +++ b/libpthread/nptl/pthread_setregid.c @@ -0,0 +1,3 @@ +#define SINGLE_THREAD +#define __setregid pthread_setregid_np +#include <setregid.c> diff --git a/libpthread/nptl/pthread_setresgid.c b/libpthread/nptl/pthread_setresgid.c new file mode 100644 index 000000000..369fae267 --- /dev/null +++ b/libpthread/nptl/pthread_setresgid.c @@ -0,0 +1,3 @@ +#define SINGLE_THREAD +#define __setresgid pthread_setresgid_np +#include <setresgid.c> diff --git a/libpthread/nptl/pthread_setresuid.c b/libpthread/nptl/pthread_setresuid.c new file mode 100644 index 000000000..ac57c0fa8 --- /dev/null +++ b/libpthread/nptl/pthread_setresuid.c @@ -0,0 +1,3 @@ +#define SINGLE_THREAD +#define __setresuid pthread_setresuid_np +#include <setresuid.c> diff --git a/libpthread/nptl/pthread_setreuid.c b/libpthread/nptl/pthread_setreuid.c new file mode 100644 index 000000000..aa804ab01 --- /dev/null +++ b/libpthread/nptl/pthread_setreuid.c @@ -0,0 +1,3 @@ +#define SINGLE_THREAD +#define __setreuid pthread_setreuid_np +#include <setreuid.c> diff --git a/libpthread/nptl/pthread_setschedparam.c b/libpthread/nptl/pthread_setschedparam.c new file mode 100644 index 000000000..55dfefc52 --- /dev/null +++ b/libpthread/nptl/pthread_setschedparam.c @@ -0,0 +1,61 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <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); + + /* 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, param, sizeof (struct sched_param)); + pd->flags |= ATTR_FLAG_SCHED_SET | ATTR_FLAG_POLICY_SET; + } + + lll_unlock (pd->lock); + + return result; +} +strong_alias (__pthread_setschedparam, pthread_setschedparam) diff --git a/libpthread/nptl/pthread_setschedprio.c b/libpthread/nptl/pthread_setschedprio.c new file mode 100644 index 000000000..d5e30e5cb --- /dev/null +++ b/libpthread/nptl/pthread_setschedprio.c @@ -0,0 +1,58 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <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); + + /* Try to set the scheduler information. */ + if (__builtin_expect (sched_setparam (pd->tid, ¶m) == -1, 0)) + result = errno; + else + { + /* We succeeded changing the kernel information. Reflect this + change in the thread descriptor. */ + memcpy (&pd->schedparam, ¶m, sizeof (struct sched_param)); + pd->flags |= ATTR_FLAG_SCHED_SET; + } + + lll_unlock (pd->lock); + + return result; +} diff --git a/libpthread/nptl/pthread_setspecific.c b/libpthread/nptl/pthread_setspecific.c new file mode 100644 index 000000000..8761eb99a --- /dev/null +++ b/libpthread/nptl/pthread_setspecific.c @@ -0,0 +1,96 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <stdlib.h> +#include "pthreadP.h" + + +int +__pthread_setspecific ( + pthread_key_t key, + const void *value) +{ + struct pthread *self; + unsigned int idx1st; + unsigned int idx2nd; + struct pthread_key_data *level2; + unsigned int seq; + + self = THREAD_SELF; + + /* Special case access to the first 2nd-level block. This is the + usual case. */ + if (__builtin_expect (key < PTHREAD_KEY_2NDLEVEL_SIZE, 1)) + { + /* Verify the key is sane. */ + if (KEY_UNUSED ((seq = __pthread_keys[key].seq))) + /* Not valid. */ + return EINVAL; + + level2 = &self->specific_1stblock[key]; + + /* Remember that we stored at least one set of data. */ + if (value != NULL) + THREAD_SETMEM (self, specific_used, true); + } + else + { + if (KEY_UNUSED ((seq = __pthread_keys[key].seq)) + || key >= PTHREAD_KEYS_MAX) + /* Not valid. */ + return EINVAL; + + idx1st = key / PTHREAD_KEY_2NDLEVEL_SIZE; + idx2nd = key % PTHREAD_KEY_2NDLEVEL_SIZE; + + /* This is the second level array. Allocate it if necessary. */ + level2 = THREAD_GETMEM_NC (self, specific, idx1st); + if (level2 == NULL) + { + if (value == NULL) + /* We don't have to do anything. The value would in any case + be NULL. We can save the memory allocation. */ + return 0; + + level2 + = (struct pthread_key_data *) calloc (PTHREAD_KEY_2NDLEVEL_SIZE, + sizeof (*level2)); + if (level2 == NULL) + return ENOMEM; + + THREAD_SETMEM_NC (self, specific, idx1st, level2); + } + + /* Pointer to the right array element. */ + level2 = &level2[idx2nd]; + + /* Remember that we stored at least one set of data. */ + THREAD_SETMEM (self, specific_used, true); + } + + /* Store the data and the sequence number so that we can recognize + stale data. */ + level2->seq = seq; + level2->data = (void *) value; + + return 0; +} +strong_alias (__pthread_setspecific, pthread_setspecific) +strong_alias (__pthread_setspecific, __pthread_setspecific_internal) diff --git a/libpthread/nptl/pthread_setuid.c b/libpthread/nptl/pthread_setuid.c new file mode 100644 index 000000000..ff949c850 --- /dev/null +++ b/libpthread/nptl/pthread_setuid.c @@ -0,0 +1,3 @@ +#define SINGLE_THREAD +#define __setuid pthread_setuid_np +#include <setuid.c> diff --git a/libpthread/nptl/pthread_testcancel.c b/libpthread/nptl/pthread_testcancel.c new file mode 100644 index 000000000..e9b17b493 --- /dev/null +++ b/libpthread/nptl/pthread_testcancel.c @@ -0,0 +1,28 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <stdlib.h> +#include "pthreadP.h" + + +void +pthread_testcancel (void) +{ + CANCELLATION_P (THREAD_SELF); +} diff --git a/libpthread/nptl/pthread_timedjoin.c b/libpthread/nptl/pthread_timedjoin.c new file mode 100644 index 000000000..ce2cf3f65 --- /dev/null +++ b/libpthread/nptl/pthread_timedjoin.c @@ -0,0 +1,107 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <stdlib.h> +#include "atomic.h" +#include "pthreadP.h" + + +static void +cleanup (void *arg) +{ + *(void **) arg = NULL; +} + + +int +pthread_timedjoin_np ( + pthread_t threadid, + void **thread_return, + const struct timespec *abstime) +{ + struct pthread *self; + struct pthread *pd = (struct pthread *) threadid; + int result; + + /* Make sure the descriptor is valid. */ + if (INVALID_NOT_TERMINATED_TD_P (pd)) + /* Not a valid thread handle. */ + return ESRCH; + + /* Is the thread joinable?. */ + if (IS_DETACHED (pd)) + /* We cannot wait for the thread. */ + return EINVAL; + + self = THREAD_SELF; + if (pd == self || self->joinid == pd) + /* This is a deadlock situation. The threads are waiting for each + other to finish. Note that this is a "may" error. To be 100% + sure we catch this error we would have to lock the data + structures but it is not necessary. In the unlikely case that + two threads are really caught in this situation they will + deadlock. It is the programmer's problem to figure this + out. */ + return EDEADLK; + + /* Wait for the thread to finish. If it is already locked something + is wrong. There can only be one waiter. */ + if (__builtin_expect (atomic_compare_and_exchange_bool_acq (&pd->joinid, + self, NULL), 0)) + /* There is already somebody waiting for the thread. */ + return EINVAL; + + + /* During the wait we change to asynchronous cancellation. If we + are cancelled the thread we are waiting for must be marked as + un-wait-ed for again. */ + pthread_cleanup_push (cleanup, &pd->joinid); + + /* Switch to asynchronous cancellation. */ + int oldtype = CANCEL_ASYNC (); + + + /* Wait for the child. */ + result = lll_timedwait_tid (pd->tid, abstime); + + + /* Restore cancellation mode. */ + CANCEL_RESET (oldtype); + + /* Remove the handler. */ + pthread_cleanup_pop (0); + + + /* We might have timed out. */ + if (result == 0) + { + /* Store the return value if the caller is interested. */ + if (thread_return != NULL) + *thread_return = pd->result; + + + /* Free the TCB. */ + __free_tcb (pd); + } + else + pd->joinid = NULL; + + return result; +} diff --git a/libpthread/nptl/pthread_tryjoin.c b/libpthread/nptl/pthread_tryjoin.c new file mode 100644 index 000000000..049cb5e0a --- /dev/null +++ b/libpthread/nptl/pthread_tryjoin.c @@ -0,0 +1,73 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <stdlib.h> + +#include "atomic.h" +#include "pthreadP.h" + + +int +pthread_tryjoin_np (pthread_t threadid, void **thread_return) +{ + struct pthread *self; + struct pthread *pd = (struct pthread *) threadid; + + /* Make sure the descriptor is valid. */ + if (DEBUGGING_P && __find_in_stack_list (pd) == NULL) + /* Not a valid thread handle. */ + return ESRCH; + + /* Is the thread joinable?. */ + if (IS_DETACHED (pd)) + /* We cannot wait for the thread. */ + return EINVAL; + + self = THREAD_SELF; + if (pd == self || self->joinid == pd) + /* This is a deadlock situation. The threads are waiting for each + other to finish. Note that this is a "may" error. To be 100% + sure we catch this error we would have to lock the data + structures but it is not necessary. In the unlikely case that + two threads are really caught in this situation they will + deadlock. It is the programmer's problem to figure this + out. */ + return EDEADLK; + + /* Return right away if the thread hasn't terminated yet. */ + if (pd->tid != 0) + return EBUSY; + + /* Wait for the thread to finish. If it is already locked something + is wrong. There can only be one waiter. */ + if (atomic_compare_and_exchange_bool_acq (&pd->joinid, self, NULL)) + /* There is already somebody waiting for the thread. */ + return EINVAL; + + /* Store the return value if the caller is interested. */ + if (thread_return != NULL) + *thread_return = pd->result; + + + /* Free the TCB. */ + __free_tcb (pd); + + return 0; +} diff --git a/libpthread/nptl/res.c b/libpthread/nptl/res.c new file mode 100644 index 000000000..37529899e --- /dev/null +++ b/libpthread/nptl/res.c @@ -0,0 +1,28 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <features.h> + +#include <tls.h> +#include <resolv.h> + +struct __res_state * +__res_state (void) +{ + return __resp; +} diff --git a/libpthread/nptl/sem_close.c b/libpthread/nptl/sem_close.c new file mode 100644 index 000000000..a2bcc7179 --- /dev/null +++ b/libpthread/nptl/sem_close.c @@ -0,0 +1,80 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <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); + + /* 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); + + return result; +} diff --git a/libpthread/nptl/sem_destroy.c b/libpthread/nptl/sem_destroy.c new file mode 100644 index 000000000..2e612c13d --- /dev/null +++ b/libpthread/nptl/sem_destroy.c @@ -0,0 +1,32 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <semaphore.h> +#include "semaphoreP.h" + + +int +__new_sem_destroy (sem_t *sem) +{ + /* XXX Check for valid parameter. */ + + /* Nothing to do. */ + return 0; +} +weak_alias(__new_sem_destroy, sem_destroy) diff --git a/libpthread/nptl/sem_getvalue.c b/libpthread/nptl/sem_getvalue.c new file mode 100644 index 000000000..5e6c8df42 --- /dev/null +++ b/libpthread/nptl/sem_getvalue.c @@ -0,0 +1,37 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <semaphore.h> +#include "semaphoreP.h" + + +int +__new_sem_getvalue ( + sem_t *sem, + int *sval) +{ + struct sem *isem = (struct sem *) sem; + + /* XXX Check for valid SEM parameter. */ + + *sval = isem->count; + + return 0; +} +weak_alias(__new_sem_getvalue, sem_getvalue) diff --git a/libpthread/nptl/sem_init.c b/libpthread/nptl/sem_init.c new file mode 100644 index 000000000..1439bd053 --- /dev/null +++ b/libpthread/nptl/sem_init.c @@ -0,0 +1,50 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <semaphore.h> +#include <lowlevellock.h> +#include "semaphoreP.h" + + +int +__new_sem_init ( + sem_t *sem, + int pshared, + unsigned int value) +{ + /* Parameter sanity check. */ + if (__builtin_expect (value > SEM_VALUE_MAX, 0)) + { + __set_errno (EINVAL); + return -1; + } + + /* Map to the internal type. */ + struct sem *isem = (struct sem *) sem; + + /* Use the value the user provided. */ + isem->count = value; + + /* We can completely ignore the PSHARED parameter since inter-process + use needs no special preparation. */ + + return 0; +} +weak_alias(__new_sem_init, sem_init) diff --git a/libpthread/nptl/sem_open.c b/libpthread/nptl/sem_open.c new file mode 100644 index 000000000..25389f0cd --- /dev/null +++ b/libpthread/nptl/sem_open.c @@ -0,0 +1,391 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <fcntl.h> +#include <mntent.h> +#include <paths.h> +#include <pthread.h> +#include <search.h> +#include <semaphore.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/statfs.h> +#include <linux_fsinfo.h> +#include "semaphoreP.h" +#include "../../libc/misc/internals/tempname.h" + + +/* Compatibility defines. */ +#define __endmntent endmntent +#define __fxstat64(vers, fd, buf) fstat64(fd, buf) +#define __getmntent_r getmntent_r +#define __setmntent setmntent +#define __statfs statfs +#define __libc_close close +#define __libc_open open +#define __libc_write write + +/* Information about the mount point. */ +struct mountpoint_info mountpoint attribute_hidden; + +/* This is the default mount point. */ +static const char defaultmount[] = "/dev/shm"; +/* This is the default directory. */ +static const char defaultdir[] = "/dev/shm/sem."; + +/* Protect the `mountpoint' variable above. */ +pthread_once_t __namedsem_once attribute_hidden = PTHREAD_ONCE_INIT; + + +/* Determine where the shmfs is mounted (if at all). */ +void +attribute_hidden +__where_is_shmfs (void) +{ + char buf[512]; + struct statfs f; + struct mntent resmem; + struct mntent *mp; + FILE *fp; + + /* The canonical place is /dev/shm. This is at least what the + documentation tells everybody to do. */ + if (__statfs (defaultmount, &f) == 0 && f.f_type == SHMFS_SUPER_MAGIC) + { + /* It is in the normal place. */ + mountpoint.dir = (char *) defaultdir; + mountpoint.dirlen = sizeof (defaultdir) - 1; + + return; + } + + /* OK, do it the hard way. Look through the /proc/mounts file and if + this does not exist through /etc/fstab to find the mount point. */ + fp = __setmntent ("/proc/mounts", "r"); + if (__builtin_expect (fp == NULL, 0)) + { + fp = __setmntent (_PATH_MNTTAB, "r"); + if (__builtin_expect (fp == NULL, 0)) + /* There is nothing we can do. Blind guesses are not helpful. */ + return; + } + + /* Now read the entries. */ + while ((mp = __getmntent_r (fp, &resmem, buf, sizeof buf)) != NULL) + /* The original name is "shm" but this got changed in early Linux + 2.4.x to "tmpfs". */ + if (strcmp (mp->mnt_type, "tmpfs") == 0 + || strcmp (mp->mnt_type, "shm") == 0) + { + /* Found it. There might be more than one place where the + filesystem is mounted but one is enough for us. */ + size_t namelen; + + /* First make sure this really is the correct entry. At least + some versions of the kernel give wrong information because + of the implicit mount of the shmfs for SysV IPC. */ + if (__statfs (mp->mnt_dir, &f) != 0 || f.f_type != SHMFS_SUPER_MAGIC) + continue; + + namelen = strlen (mp->mnt_dir); + + if (namelen == 0) + /* Hum, maybe some crippled entry. Keep on searching. */ + continue; + + mountpoint.dir = (char *) malloc (namelen + 4 + 2); + if (mountpoint.dir != NULL) + { + char *cp = mempcpy (mountpoint.dir, mp->mnt_dir, namelen); + if (cp[-1] != '/') + *cp++ = '/'; + cp = stpcpy (cp, "sem."); + mountpoint.dirlen = cp - mountpoint.dir; + } + + break; + } + + /* Close the stream. */ + __endmntent (fp); +} + + +/* Comparison function for search of existing mapping. */ +int +attribute_hidden +__sem_search (const void *a, const void *b) +{ + const struct inuse_sem *as = (const struct inuse_sem *) a; + const struct inuse_sem *bs = (const struct inuse_sem *) b; + + if (as->ino != bs->ino) + /* Cannot return the difference the type is larger than int. */ + return as->ino < bs->ino ? -1 : (as->ino == bs->ino ? 0 : 1); + + if (as->dev != bs->dev) + /* Cannot return the difference the type is larger than int. */ + return as->dev < bs->dev ? -1 : (as->dev == bs->dev ? 0 : 1); + + return strcmp (as->name, bs->name); +} + + +/* The search tree for existing mappings. */ +void *__sem_mappings attribute_hidden; + +/* Lock to protect the search tree. */ +lll_lock_t __sem_mappings_lock = LLL_LOCK_INITIALIZER; + + +/* Search for existing mapping and if possible add the one provided. */ +static sem_t * +check_add_mapping (const char *name, size_t namelen, int fd, sem_t *existing) +{ + sem_t *result = SEM_FAILED; + + /* Get the information about the file. */ +#ifdef __UCLIBC_HAS_LFS__ + struct stat64 st; + if (__fxstat64 (_STAT_VER, fd, &st) == 0) +#else + struct stat st; + if (fstat (fd, &st) == 0) +#endif + { + /* Get the lock. */ + lll_lock (__sem_mappings_lock); + + /* Search for an existing mapping given the information we have. */ + struct inuse_sem *fake; + fake = (struct inuse_sem *) alloca (sizeof (*fake) + namelen); + memcpy (fake->name, name, namelen); + fake->dev = st.st_dev; + fake->ino = st.st_ino; + + struct inuse_sem **foundp = tfind (fake, &__sem_mappings, __sem_search); + if (foundp != NULL) + { + /* There is already a mapping. Use it. */ + result = (*foundp)->sem; + ++(*foundp)->refcnt; + } + else + { + /* We haven't found a mapping. Install ione. */ + struct inuse_sem *newp; + + newp = (struct inuse_sem *) malloc (sizeof (*newp) + namelen); + if (newp != NULL) + { + /* If the caller hasn't provided any map it now. */ + if (existing == SEM_FAILED) + existing = (sem_t *) mmap (NULL, sizeof (sem_t), + PROT_READ | PROT_WRITE, MAP_SHARED, + fd, 0); + + newp->dev = st.st_dev; + newp->ino = st.st_ino; + newp->refcnt = 1; + newp->sem = existing; + memcpy (newp->name, name, namelen); + + /* Insert the new value. */ + if (existing != MAP_FAILED + && tsearch (newp, &__sem_mappings, __sem_search) != NULL) + /* Successful. */ + result = existing; + else + /* Something went wrong while inserting the new + value. We fail completely. */ + free (newp); + } + } + + /* Release the lock. */ + lll_unlock (__sem_mappings_lock); + } + + if (result != existing && existing != SEM_FAILED && existing != MAP_FAILED) + { + /* Do not disturb errno. */ + INTERNAL_SYSCALL_DECL (err); + INTERNAL_SYSCALL (munmap, err, 2, existing, sizeof (sem_t)); + } + + return result; +} + + +sem_t * +sem_open (const char *name, int oflag, ...) +{ + char *finalname; + sem_t *result = SEM_FAILED; + int fd; + + /* Determine where the shmfs is mounted. */ + __pthread_once (&__namedsem_once, __where_is_shmfs); + + /* If we don't know the mount points there is nothing we can do. Ever. */ + if (mountpoint.dir == NULL) + { + __set_errno (ENOSYS); + return SEM_FAILED; + } + + /* Construct the filename. */ + while (name[0] == '/') + ++name; + + if (name[0] == '\0') + { + /* The name "/" is not supported. */ + __set_errno (EINVAL); + return SEM_FAILED; + } + size_t namelen = strlen (name) + 1; + + /* Create the name of the final file. */ + finalname = (char *) alloca (mountpoint.dirlen + namelen); + mempcpy (mempcpy (finalname, mountpoint.dir, mountpoint.dirlen), + name, namelen); + + /* If the semaphore object has to exist simply open it. */ + if ((oflag & O_CREAT) == 0 || (oflag & O_EXCL) == 0) + { + try_again: + fd = __libc_open (finalname, + (oflag & ~(O_CREAT|O_ACCMODE)) | O_NOFOLLOW | O_RDWR); + + if (fd == -1) + { + /* If we are supposed to create the file try this next. */ + if ((oflag & O_CREAT) != 0 && errno == ENOENT) + goto try_create; + + /* Return. errno is already set. */ + } + else + /* Check whether we already have this semaphore mapped and + create one if necessary. */ + result = check_add_mapping (name, namelen, fd, SEM_FAILED); + } + else + { + /* We have to open a temporary file first since it must have the + correct form before we can start using it. */ + char *tmpfname; + mode_t mode; + unsigned int value; + va_list ap; + + try_create: + va_start (ap, oflag); + + mode = va_arg (ap, mode_t); + value = va_arg (ap, unsigned int); + + va_end (ap); + + if (value > SEM_VALUE_MAX) + { + __set_errno (EINVAL); + return SEM_FAILED; + } + + /* Create the initial file content. */ + sem_t initsem; + + struct sem *iinitsem = (struct sem *) &initsem; + iinitsem->count = value; + + /* Initialize the remaining bytes as well. */ + memset ((char *) &initsem + sizeof (struct sem), '\0', + sizeof (sem_t) - sizeof (struct sem)); + + tmpfname = (char *) alloca (mountpoint.dirlen + 6 + 1); + char *xxxxxx = mempcpy (tmpfname, mountpoint.dir, mountpoint.dirlen); + strcpy (xxxxxx, "XXXXXX"); + + fd = __gen_tempname (tmpfname, __GT_FILE, mode); + if (fd == -1) + return SEM_FAILED; + + if (TEMP_FAILURE_RETRY (__libc_write (fd, &initsem, sizeof (sem_t))) + == sizeof (sem_t) + /* Map the sem_t structure from the file. */ + && (result = (sem_t *) mmap (NULL, sizeof (sem_t), + PROT_READ | PROT_WRITE, MAP_SHARED, + fd, 0)) != MAP_FAILED) + { + /* Create the file. Don't overwrite an existing file. */ + if (link (tmpfname, finalname) != 0) + { + /* Undo the mapping. */ + (void) munmap (result, sizeof (sem_t)); + + /* Reinitialize 'result'. */ + result = SEM_FAILED; + + /* This failed. If O_EXCL is not set and the problem was + that the file exists, try again. */ + if ((oflag & O_EXCL) == 0 && errno == EEXIST) + { + /* Remove the file. */ + (void) unlink (tmpfname); + + /* Close the file. */ + (void) __libc_close (fd); + + goto try_again; + } + } + else + /* Insert the mapping into the search tree. This also + determines whether another thread sneaked by and already + added such a mapping despite the fact that we created it. */ + result = check_add_mapping (name, namelen, fd, result); + } + + /* Now remove the temporary name. This should never fail. If + it fails we leak a file name. Better fix the kernel. */ + (void) unlink (tmpfname); + } + + /* Map the mmap error to the error we need. */ + if (MAP_FAILED != (void *) SEM_FAILED && result == MAP_FAILED) + result = SEM_FAILED; + + /* We don't need the file descriptor anymore. */ + if (fd != -1) + { + /* Do not disturb errno. */ + INTERNAL_SYSCALL_DECL (err); + INTERNAL_SYSCALL (close, err, 1, fd); + } + + return result; +} diff --git a/libpthread/nptl/sem_unlink.c b/libpthread/nptl/sem_unlink.c new file mode 100644 index 000000000..e52a08d15 --- /dev/null +++ b/libpthread/nptl/sem_unlink.c @@ -0,0 +1,66 @@ +/* Copyright (C) 2002, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <semaphore.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "semaphoreP.h" + + +int +sem_unlink (const char *name) +{ + char *fname; + size_t namelen; + + /* Determine where the shmfs is mounted. */ + __pthread_once (&__namedsem_once, __where_is_shmfs); + + /* If we don't know the mount points there is nothing we can do. Ever. */ + if (mountpoint.dir == NULL) + { + __set_errno (ENOSYS); + return -1; + } + + /* Construct the filename. */ + while (name[0] == '/') + ++name; + + if (name[0] == '\0') + { + /* The name "/" is not supported. */ + __set_errno (ENOENT); + return -1; + } + namelen = strlen (name); + + /* Create the name of the file. */ + fname = (char *) alloca (mountpoint.dirlen + namelen + 1); + mempcpy (mempcpy (fname, mountpoint.dir, mountpoint.dirlen), + name, namelen + 1); + + /* Now try removing it. */ + int ret = unlink (fname); + if (ret < 0 && errno == EPERM) + __set_errno (EACCES); + return ret; +} diff --git a/libpthread/nptl/semaphore.h b/libpthread/nptl/semaphore.h new file mode 100644 index 000000000..4f13725b3 --- /dev/null +++ b/libpthread/nptl/semaphore.h @@ -0,0 +1,79 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _SEMAPHORE_H +#define _SEMAPHORE_H 1 + +#include <features.h> +#include <sys/types.h> +#ifdef __USE_XOPEN2K +# define __need_timespec +# include <time.h> +#endif + +/* Get the definition for sem_t. */ +#include <bits/semaphore.h> + + +__BEGIN_DECLS + +/* Initialize semaphore object SEM to VALUE. If PSHARED then share it + with other processes. */ +extern int sem_init (sem_t *__sem, int __pshared, unsigned int __value) + __THROW; +/* Free resources associated with semaphore object SEM. */ +extern int sem_destroy (sem_t *__sem) __THROW; + +/* Open a named semaphore NAME with open flags OFLAG. */ +extern sem_t *sem_open (__const char *__name, int __oflag, ...) __THROW; + +/* Close descriptor for named semaphore SEM. */ +extern int sem_close (sem_t *__sem) __THROW; + +/* Remove named semaphore NAME. */ +extern int sem_unlink (__const char *__name) __THROW; + +/* Wait for SEM being posted. + + This function is a cancellation point and therefore not marked with + __THROW. */ +extern int sem_wait (sem_t *__sem); + +#ifdef __USE_XOPEN2K +/* Similar to `sem_wait' but wait only until ABSTIME. + + This function is a cancellation point and therefore not marked with + __THROW. */ +extern int sem_timedwait (sem_t *__restrict __sem, + __const struct timespec *__restrict __abstime); +#endif + +/* Test whether SEM is posted. */ +extern int sem_trywait (sem_t *__sem) __THROW; + +/* Post SEM. */ +extern int sem_post (sem_t *__sem) __THROW; + +/* Get current value of SEM and store it in *SVAL. */ +extern int sem_getvalue (sem_t *__restrict __sem, int *__restrict __sval) + __THROW; + + +__END_DECLS + +#endif /* semaphore.h */ diff --git a/libpthread/nptl/semaphoreP.h b/libpthread/nptl/semaphoreP.h new file mode 100644 index 000000000..d14ea92c7 --- /dev/null +++ b/libpthread/nptl/semaphoreP.h @@ -0,0 +1,67 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <semaphore.h> +#include "pthreadP.h" + + +/* Mount point of the shared memory filesystem. */ +struct mountpoint_info +{ + char *dir; + size_t dirlen; +}; + +/* Keeping track of currently used mappings. */ +struct inuse_sem +{ + dev_t dev; + ino_t ino; + int refcnt; + sem_t *sem; + char name[0]; +}; + + +/* Variables used in multiple interfaces. */ +extern struct mountpoint_info mountpoint attribute_hidden; + +extern pthread_once_t __namedsem_once attribute_hidden; + +/* The search tree for existing mappings. */ +extern void *__sem_mappings attribute_hidden; + +/* Lock to protect the search tree. */ +extern lll_lock_t __sem_mappings_lock; + + +/* Initializer for mountpoint. */ +extern void __where_is_shmfs (void) attribute_hidden; + +/* Comparison function for search in tree with existing mappings. */ +extern int __sem_search (const void *a, const void *b) attribute_hidden; + + +/* Prototypes of functions with multiple interfaces. */ +extern int __new_sem_init (sem_t *sem, int pshared, unsigned int value); +extern int __new_sem_destroy (sem_t *sem); +extern int __new_sem_post (sem_t *sem); +extern int __new_sem_wait (sem_t *sem); +extern int __new_sem_trywait (sem_t *sem); +extern int __new_sem_getvalue (sem_t *sem, int *sval); diff --git a/libpthread/nptl/sysdeps/alpha/Makefile b/libpthread/nptl/sysdeps/alpha/Makefile new file mode 100644 index 000000000..88c106bbb --- /dev/null +++ b/libpthread/nptl/sysdeps/alpha/Makefile @@ -0,0 +1,21 @@ +# Copyright (C) 2003 Free Software Foundation, Inc. +# This file is part of the GNU C Library. +# +# The GNU C Library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# The GNU C Library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with the GNU C Library; if not, write to the Free +# Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +# 02111-1307 USA. + +ifeq ($(subdir),csu) +gen-as-const-headers += tcb-offsets.sym +endif diff --git a/libpthread/nptl/sysdeps/alpha/dl-tls.h b/libpthread/nptl/sysdeps/alpha/dl-tls.h new file mode 100644 index 000000000..f81f95d75 --- /dev/null +++ b/libpthread/nptl/sysdeps/alpha/dl-tls.h @@ -0,0 +1,29 @@ +/* Thread-local storage handling in the ELF dynamic linker. Alpha version. + Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + + +/* Type used for the representation of TLS information in the GOT. */ +typedef struct +{ + unsigned long int ti_module; + unsigned long int ti_offset; +} tls_index; + + +extern void *__tls_get_addr (tls_index *ti); diff --git a/libpthread/nptl/sysdeps/alpha/elf/pt-initfini.c b/libpthread/nptl/sysdeps/alpha/elf/pt-initfini.c new file mode 100644 index 000000000..ba2e419d6 --- /dev/null +++ b/libpthread/nptl/sysdeps/alpha/elf/pt-initfini.c @@ -0,0 +1,89 @@ +/* Special .init and .fini section support for Alpha. NPTL version. + Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* This file is compiled into assembly code which is then munged by a sed + script into two files: crti.s and crtn.s. + + * crti.s puts a function prologue at the beginning of the .init and .fini + sections and defines global symbols for those addresses, so they can be + called as functions. + + * crtn.s puts the corresponding function epilogues in the .init and .fini + sections. + + This differs from what would be generated by the generic code in that + we save and restore the GP within the function. In order for linker + relaxation to work, the value in the GP register on exit from a function + must be valid for the function entry point. Normally, a function is + contained within one object file and this is not an issue, provided + that the function reloads the gp after making any function calls. + However, _init and _fini are constructed from pieces of many object + files, all of which may have different GP values. So we must reload + the GP value from crti.o in crtn.o. */ + +__asm__ (" \n\ +#include \"defs.h\" \n\ + \n\ +/*@HEADER_ENDS*/ \n\ + \n\ +/*@_init_PROLOG_BEGINS*/ \n\ + .section .init, \"ax\", @progbits \n\ + .globl _init \n\ + .type _init,@function \n\ + .usepv _init,std \n\ +_init: \n\ + ldgp $29, 0($27) \n\ + subq $30, 16, $30 \n\ + stq $26, 0($30) \n\ + stq $29, 8($30) \n\ + bsr $26, __pthread_initialize_minimal_internal !samegp \n\ + .align 3 \n\ +/*@_init_PROLOG_ENDS*/ \n\ + \n\ +/*@_init_EPILOG_BEGINS*/ \n\ + .section .init, \"ax\", @progbits \n\ + ldq $26, 0($30) \n\ + ldq $29, 8($30) \n\ + addq $30, 16, $30 \n\ + ret \n\ +/*@_init_EPILOG_ENDS*/ \n\ + \n\ +/*@_fini_PROLOG_BEGINS*/ \n\ + .section .fini, \"ax\", @progbits \n\ + .globl _fini \n\ + .type _fini,@function \n\ + .usepv _fini,std \n\ +_fini: \n\ + ldgp $29, 0($27) \n\ + subq $30, 16, $30 \n\ + stq $26, 0($30) \n\ + stq $29, 8($30) \n\ + .align 3 \n\ +/*@_fini_PROLOG_ENDS*/ \n\ + \n\ +/*@_fini_EPILOG_BEGINS*/ \n\ + .section .fini, \"ax\", @progbits \n\ + ldq $26, 0($30) \n\ + ldq $29, 8($30) \n\ + addq $30, 16, $30 \n\ + ret \n\ +/*@_fini_EPILOG_ENDS*/ \n\ + \n\ +/*@TRAILER_BEGINS*/ \n\ +"); diff --git a/libpthread/nptl/sysdeps/alpha/jmpbuf-unwind.h b/libpthread/nptl/sysdeps/alpha/jmpbuf-unwind.h new file mode 100644 index 000000000..5cef8b1cf --- /dev/null +++ b/libpthread/nptl/sysdeps/alpha/jmpbuf-unwind.h @@ -0,0 +1,31 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <setjmp.h> +#include <stdint.h> +#include <unwind.h> + +#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \ + _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj) + +#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \ + ((uintptr_t) (_address) - (_adj) < (uintptr_t) (_jmpbuf)[JB_SP] - (_adj)) + +/* We use the normal lobngjmp for unwinding. */ +#define __libc_unwind_longjmp(buf, val) __libc_longjmp (buf, val) diff --git a/libpthread/nptl/sysdeps/alpha/libc-tls.c b/libpthread/nptl/sysdeps/alpha/libc-tls.c new file mode 100644 index 000000000..a3b68e928 --- /dev/null +++ b/libpthread/nptl/sysdeps/alpha/libc-tls.c @@ -0,0 +1,37 @@ +/* Thread-local storage handling in the ELF dynamic linker. Alpha version. + Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdeps/generic/libc-tls.c> +#include <dl-tls.h> + +#if USE_TLS + +/* On Alpha, linker optimizations are not required, so __tls_get_addr + can be called even in statically linked binaries. In this case module + must be always 1 and PT_TLS segment exist in the binary, otherwise it + would not link. */ + +void * +__tls_get_addr (tls_index *ti) +{ + dtv_t *dtv = THREAD_DTV (); + return (char *) dtv[1].pointer.val + ti->ti_offset; +} + +#endif diff --git a/libpthread/nptl/sysdeps/alpha/pthread_spin_lock.S b/libpthread/nptl/sysdeps/alpha/pthread_spin_lock.S new file mode 100644 index 000000000..ce6cd41a4 --- /dev/null +++ b/libpthread/nptl/sysdeps/alpha/pthread_spin_lock.S @@ -0,0 +1,45 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Richard Henderson <rth@twiddle.net>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + + + .text + .align 4 + + .globl pthread_spin_lock + .ent pthread_spin_lock +pthread_spin_lock: + .frame $sp, 0, $26, 0 + .prologue 0 + +0: ldl_l $1, 0($16) + lda $2, 1 + lda $0, 0 + bne $1, 1f + + stl_c $2, 0($16) + beq $2, 1f + mb + ret + +1: ldl $1, 0($16) + bne $1, 1b + unop + br 0b + + .end pthread_spin_lock diff --git a/libpthread/nptl/sysdeps/alpha/pthread_spin_trylock.S b/libpthread/nptl/sysdeps/alpha/pthread_spin_trylock.S new file mode 100644 index 000000000..0948da698 --- /dev/null +++ b/libpthread/nptl/sysdeps/alpha/pthread_spin_trylock.S @@ -0,0 +1,46 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Richard Henderson <rth@twiddle.net>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + + +#define _ERRNO_H 1 +#include <bits/errno.h> + + .text + .align 4 + + .globl pthread_spin_trylock + .ent pthread_spin_trylock +pthread_spin_trylock: + .frame $sp, 0, $26, 0 + .prologue 0 + +0: ldl_l $1, 0($16) + lda $2, 1 + lda $0, EBUSY + bne $1, 1f + + stl_c $2, 0($16) + beq $2, 2f + mb + lda $0, 0 + +1: ret +2: br 0b + + .end pthread_spin_trylock diff --git a/libpthread/nptl/sysdeps/alpha/pthreaddef.h b/libpthread/nptl/sysdeps/alpha/pthreaddef.h new file mode 100644 index 000000000..26c4daf7b --- /dev/null +++ b/libpthread/nptl/sysdeps/alpha/pthreaddef.h @@ -0,0 +1,38 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* Default stack size. */ +#define ARCH_STACK_DEFAULT_SIZE (4 * 1024 * 1024) + +/* Required stack pointer alignment at beginning. The ABI requires 16. */ +#define STACK_ALIGN 16 + +/* Minimal stack size after allocating thread descriptor and guard size. */ +#define MINIMAL_REST_STACK 4096 + +/* Alignment requirement for TCB. */ +#define TCB_ALIGNMENT 16 + +/* Location of current stack frame. */ +#define CURRENT_STACK_FRAME __builtin_frame_address (0) + +/* XXX Until we have a better place keep the definitions here. */ + +/* While there is no such syscall. */ +#define __exit_thread_inline(val) \ + INLINE_SYSCALL (exit, 1, (val)) diff --git a/libpthread/nptl/sysdeps/alpha/tcb-offsets.sym b/libpthread/nptl/sysdeps/alpha/tcb-offsets.sym new file mode 100644 index 000000000..c21a79104 --- /dev/null +++ b/libpthread/nptl/sysdeps/alpha/tcb-offsets.sym @@ -0,0 +1,14 @@ +#include <sysdep.h> +#include <tls.h> + +-- + +-- Abuse tls.h macros to derive offsets relative to the thread register. +-- # define __builtin_thread_pointer() ((void *) 0) +-- # define thread_offsetof(mem) ((void *) &THREAD_SELF->mem - (void *) 0) +-- Ho hum, this doesn't work in gcc4, so Know Things about THREAD_SELF +#define thread_offsetof(mem) (long)(offsetof(struct pthread, mem) - sizeof(struct pthread)) + +MULTIPLE_THREADS_OFFSET thread_offsetof (header.multiple_threads) +PID_OFFSET thread_offsetof (pid) +TID_OFFSET thread_offsetof (tid) diff --git a/libpthread/nptl/sysdeps/alpha/tls.h b/libpthread/nptl/sysdeps/alpha/tls.h new file mode 100644 index 000000000..99cd27a03 --- /dev/null +++ b/libpthread/nptl/sysdeps/alpha/tls.h @@ -0,0 +1,127 @@ +/* Definition for thread-local data handling. NPTL/Alpha version. + Copyright (C) 2003, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _TLS_H +#define _TLS_H 1 + +#ifndef __ASSEMBLER__ +# include <stdbool.h> +# include <stddef.h> +# include <stdint.h> + +/* Type for the dtv. */ +typedef union dtv +{ + size_t counter; + struct + { + void *val; + bool is_static; + } pointer; +} dtv_t; + +#else /* __ASSEMBLER__ */ +# include <tcb-offsets.h> +#endif /* __ASSEMBLER__ */ + + +/* We require TLS support in the tools. */ +#ifndef HAVE_TLS_SUPPORT +# error "TLS support is required." +#endif + +/* Signal that TLS support is available. */ +# define USE_TLS 1 + +#ifndef __ASSEMBLER__ + +/* Get system call information. */ +# include <sysdep.h> + +/* The TP points to the start of the thread blocks. */ +# define TLS_DTV_AT_TP 1 + +/* Get the thread descriptor definition. */ +# include <nptl/descr.h> + +typedef struct +{ + dtv_t *dtv; + void *private; +} tcbhead_t; + +/* This is the size of the initial TCB. */ +# define TLS_INIT_TCB_SIZE sizeof (tcbhead_t) + +/* Alignment requirements for the initial TCB. */ +# define TLS_INIT_TCB_ALIGN 16 + +/* This is the size of the TCB. */ +# define TLS_TCB_SIZE sizeof (tcbhead_t) + +/* This is the size we need before TCB. */ +# define TLS_PRE_TCB_SIZE sizeof (struct pthread) + +/* Alignment requirements for the TCB. */ +# define TLS_TCB_ALIGN 16 + +/* Install the dtv pointer. The pointer passed is to the element with + index -1 which contain the length. */ +# define INSTALL_DTV(tcbp, dtvp) \ + (((tcbhead_t *) (tcbp))->dtv = (dtvp) + 1) + +/* Install new dtv for current thread. */ +# define INSTALL_NEW_DTV(dtv) \ + (THREAD_DTV() = (dtv)) + +/* Return dtv of given thread descriptor. */ +# define GET_DTV(tcbp) \ + (((tcbhead_t *) (tcbp))->dtv) + +/* Code to initially initialize the thread pointer. This might need + special attention since 'errno' is not yet available and if the + operation can cause a failure 'errno' must not be touched. */ +# define TLS_INIT_TP(tcbp, secondcall) \ + (__builtin_set_thread_pointer ((void *)(tcbp)), NULL) + +/* Return the address of the dtv for the current thread. */ +# define THREAD_DTV() \ + (((tcbhead_t *) __builtin_thread_pointer ())->dtv) + +/* Return the thread descriptor for the current thread. */ +# define THREAD_SELF \ + ((struct pthread *)__builtin_thread_pointer () - 1) + +/* Magic for libthread_db to know how to do THREAD_SELF. */ +# define DB_THREAD_SELF \ + REGISTER (64, 64, 32 * 8, -sizeof (struct pthread)) + +/* Access to data in the thread descriptor is easy. */ +#define THREAD_GETMEM(descr, member) \ + descr->member +#define THREAD_GETMEM_NC(descr, member, idx) \ + descr->member[idx] +#define THREAD_SETMEM(descr, member, value) \ + descr->member = (value) +#define THREAD_SETMEM_NC(descr, member, idx, value) \ + descr->member[idx] = (value) + +#endif /* __ASSEMBLER__ */ + +#endif /* tls.h */ diff --git a/libpthread/nptl/sysdeps/arm/Makefile.arch b/libpthread/nptl/sysdeps/arm/Makefile.arch new file mode 100644 index 000000000..6d16ae3fd --- /dev/null +++ b/libpthread/nptl/sysdeps/arm/Makefile.arch @@ -0,0 +1,69 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2005 Steven J. Hill <sjhill@uclibc.org> +# Portions Copyright (C) 2006 CodeSourcery +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +libpthread_SSRC = pthread_spin_lock.S pthread_spin_trylock.S aeabi_read_tp.S \ + thumb_atomics.S +libpthread_CSRC = aeabi_unwind_cpp_pr1.c + +librt_SSRC = aeabi_read_tp.S thumb_atomics.S +librt_CSRC = aeabi_unwind_cpp_pr1.c + +libc_a_CSRC = + +CFLAGS-pt-raise.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 + +ASFLAGS-pthread_spin_lock.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +ASFLAGS-pthread_spin_trylock.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +ASFLAGS-aeabi_read_tp.S = -DNOT_IN_libc=1 + +CFLAGS-arm = $(SSP_ALL_CFLAGS) + +PTHREAD_ARCH_DIR := $(top_srcdir)libpthread/nptl/sysdeps/arm +PTHREAD_ARCH_OUT := $(top_builddir)libpthread/nptl/sysdeps/arm +PTHREAD_ARCH_OBJ := $(patsubst %.S,$(PTHREAD_ARCH_OUT)/%.o,$(libpthread_SSRC)) +PTHREAD_ARCH_OBJ += $(patsubst %.c,$(PTHREAD_ARCH_OUT)/%.o,$(libpthread_CSRC)) +LIBRT_ARCH_OBJ := $(patsubst %.S,$(PTHREAD_ARCH_OUT)/%.o,$(librt_SSRC)) +LIBRT_ARCH_OBJ += $(patsubst %.c,$(PTHREAD_ARCH_OUT)/%.o,$(librt_CSRC)) + + +ifeq ($(DOPIC),y) +libpthread-a-y += $(PTHREAD_ARCH_OBJ:.o=.os) +else +libpthread-a-y += $(PTHREAD_ARCH_OBJ) +endif +libpthread-so-y += $(PTHREAD_ARCH_OBJ:.o=.oS) + +librt-a-y += $(LIBRT_ARCH_OBJ) +librt-so-y += $(LIBRT_ARCH_OBJ:.o=.oS) + +libpthread-nomulti-y += $(PTHREAD_ARCH_OBJ) + +objclean-y += nptl_arch_objclean +headers_clean-y += nptl_arch_headers_clean + +# +# Create 'tcb-offsets.h' header file. +# +CFLAGS-tcb-offsets.c = -S + +$(PTHREAD_ARCH_OUT)/tcb-offsets.c: $(PTHREAD_ARCH_DIR)/tcb-offsets.sym + $(do_awk) $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@ + +$(PTHREAD_ARCH_OUT)/tcb-offsets.s: $(PTHREAD_ARCH_OUT)/tcb-offsets.c + $(compile.c) + +nptl_arch_headers: $(PTHREAD_ARCH_OUT)/tcb-offsets.s + $(do_sed) -n "s/^.*@@@name@@@\([^@]*\)@@@value@@@[^0-9Xxa-fA-F-]*\([0-9Xxa-fA-F-][0-9Xxa-fA-F-]*\).*@@@end@@@.*$\/#define \1 \2/p" $< > $(PTHREAD_ARCH_OUT)/tcb-offsets.h + +nptl_arch_headers_clean: + $(RM) $(PTHREAD_ARCH_OUT)/tcb-offsets.c \ + $(PTHREAD_ARCH_OUT)/tcb-offsets.s \ + $(PTHREAD_ARCH_OUT)/tcb-offsets.h + +nptl_arch_objclean: + $(RM) $(PTHREAD_ARCH_OUT)/*.{o,os,oS} diff --git a/libpthread/nptl/sysdeps/arm/aeabi_read_tp.S b/libpthread/nptl/sysdeps/arm/aeabi_read_tp.S new file mode 100644 index 000000000..af640d625 --- /dev/null +++ b/libpthread/nptl/sysdeps/arm/aeabi_read_tp.S @@ -0,0 +1 @@ +#include <../../../../ldso/ldso/arm/aeabi_read_tp.S> diff --git a/libpthread/nptl/sysdeps/arm/aeabi_unwind_cpp_pr1.c b/libpthread/nptl/sysdeps/arm/aeabi_unwind_cpp_pr1.c new file mode 100644 index 000000000..84683627b --- /dev/null +++ b/libpthread/nptl/sysdeps/arm/aeabi_unwind_cpp_pr1.c @@ -0,0 +1 @@ +#include <../../../../libc/sysdeps/linux/arm/aeabi_unwind_cpp_pr1.c> diff --git a/libpthread/nptl/sysdeps/arm/dl-tls.h b/libpthread/nptl/sysdeps/arm/dl-tls.h new file mode 100644 index 000000000..e0324a7b6 --- /dev/null +++ b/libpthread/nptl/sysdeps/arm/dl-tls.h @@ -0,0 +1,29 @@ +/* Thread-local storage handling in the ELF dynamic linker. ARM version. + Copyright (C) 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + + +/* Type used for the representation of TLS information in the GOT. */ +typedef struct +{ + unsigned long int ti_module; + unsigned long int ti_offset; +} tls_index; + + +extern void *__tls_get_addr (tls_index *ti); diff --git a/libpthread/nptl/sysdeps/arm/jmpbuf-unwind.h b/libpthread/nptl/sysdeps/arm/jmpbuf-unwind.h new file mode 100644 index 000000000..6e8f01d10 --- /dev/null +++ b/libpthread/nptl/sysdeps/arm/jmpbuf-unwind.h @@ -0,0 +1,36 @@ +/* Copyright (C) 2005,2006 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <setjmp.h> +#include <stdint.h> +#include <unwind.h> + +/* Test if longjmp to JMPBUF would unwind the frame + containing a local variable at ADDRESS. */ +#undef _JMPBUF_UNWINDS +#define _JMPBUF_UNWINDS(jmpbuf, address, demangle) \ + ((void *) (address) < (void *) demangle (jmpbuf[__JMP_BUF_SP])) + +#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \ + _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj) + +#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \ + ((uintptr_t) (_address) - (_adj) < (uintptr_t) (_jmpbuf)[__JMP_BUF_SP] - (_adj)) + +/* We use the normal longjmp for unwinding. */ +#define __libc_unwind_longjmp(buf, val) longjmp (buf, val) diff --git a/libpthread/nptl/sysdeps/arm/pthread_spin_lock.S b/libpthread/nptl/sysdeps/arm/pthread_spin_lock.S new file mode 100644 index 000000000..bd6adf794 --- /dev/null +++ b/libpthread/nptl/sysdeps/arm/pthread_spin_lock.S @@ -0,0 +1,31 @@ +/* Copyright (C) 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> + + .text + .align 4 + +ENTRY (pthread_spin_lock) + mov r1, #1 +1: swp r2, r1, [r0] + teq r2, #0 + bne 1b + mov r0, #0 + PSEUDO_RET_NOERRNO +END (pthread_spin_lock) diff --git a/libpthread/nptl/sysdeps/arm/pthread_spin_trylock.S b/libpthread/nptl/sysdeps/arm/pthread_spin_trylock.S new file mode 100644 index 000000000..85931507a --- /dev/null +++ b/libpthread/nptl/sysdeps/arm/pthread_spin_trylock.S @@ -0,0 +1,34 @@ +/* Copyright (C) 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#define _ERRNO_H 1 +#include <bits/errno.h> + +#include <sysdep.h> + + .text + .align 4 + +ENTRY (pthread_spin_trylock) + mov r1, #1 + swp r2, r1, [r0] + teq r2, #0 + moveq r0, #0 + movne r0, #EBUSY + PSEUDO_RET_NOERRNO +END (pthread_spin_trylock) diff --git a/libpthread/nptl/sysdeps/arm/pthreaddef.h b/libpthread/nptl/sysdeps/arm/pthreaddef.h new file mode 100644 index 000000000..783828a40 --- /dev/null +++ b/libpthread/nptl/sysdeps/arm/pthreaddef.h @@ -0,0 +1,39 @@ +/* Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* Default stack size. */ +#define ARCH_STACK_DEFAULT_SIZE (2 * 1024 * 1024) + +/* Required stack pointer alignment at beginning. SSE requires 16 + bytes. */ +#define STACK_ALIGN 16 + +/* Minimal stack size after allocating thread descriptor and guard size. */ +#define MINIMAL_REST_STACK 2048 + +/* Alignment requirement for TCB. */ +#define TCB_ALIGNMENT 16 + + +/* Location of current stack frame. */ +#define CURRENT_STACK_FRAME __builtin_frame_address (0) + + +/* XXX Until we have a better place keep the definitions here. */ +#define __exit_thread_inline(val) \ + INLINE_SYSCALL (exit, 1, (val)) diff --git a/libpthread/nptl/sysdeps/arm/sysdep.h b/libpthread/nptl/sysdeps/arm/sysdep.h new file mode 100644 index 000000000..19bd3c3f7 --- /dev/null +++ b/libpthread/nptl/sysdeps/arm/sysdep.h @@ -0,0 +1,91 @@ +/* Assembler macros for ARM. + Copyright (C) 1997, 1998, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdeps/generic/sysdep.h> + +#ifdef __ASSEMBLER__ + +/* Syntactic details of assembler. */ + +#define ALIGNARG(log2) log2 +/* For ELF we need the `.type' directive to make shared libs work right. */ +#define ASM_TYPE_DIRECTIVE(name,typearg) .type name,%##typearg; +#define ASM_SIZE_DIRECTIVE(name) .size name,.-name + +/* In ELF C symbols are asm symbols. */ +#undef NO_UNDERSCORES +#define NO_UNDERSCORES + +#define PLTJMP(_x) _x##(PLT) + +/* APCS-32 doesn't preserve the condition codes across function call. */ +#ifdef __APCS_32__ +#define LOADREGS(cond, base, reglist...)\ + ldm##cond base,reglist +#ifdef __USE_BX__ +#define RETINSTR(cond, reg) \ + bx##cond reg +#define DO_RET(_reg) \ + bx _reg +#else +#define RETINSTR(cond, reg) \ + mov##cond pc, reg +#define DO_RET(_reg) \ + mov pc, _reg +#endif +#else /* APCS-26 */ +#define LOADREGS(cond, base, reglist...)\ + ldm##cond base,reglist^ +#define RETINSTR(cond, reg) \ + mov##cond##s pc, reg +#define DO_RET(_reg) \ + movs pc, _reg +#endif + +/* Define an entry point visible from C. */ +#define ENTRY(name) \ + ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(name); \ + ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name),function) \ + .align ALIGNARG(4); \ + name##: \ + CALL_MCOUNT + +#undef END +#define END(name) \ + ASM_SIZE_DIRECTIVE(name) + +/* If compiled for profiling, call `mcount' at the start of each function. */ +#ifdef PROF +#define CALL_MCOUNT \ + str lr,[sp, #-4]! ; \ + bl PLTJMP(mcount) ; \ + ldr lr, [sp], #4 ; +#else +#define CALL_MCOUNT /* Do nothing. */ +#endif + +#ifdef NO_UNDERSCORES +/* Since C identifiers are not normally prefixed with an underscore + on this system, the asm identifier `syscall_error' intrudes on the + C name space. Make sure we use an innocuous name. */ +#define syscall_error __syscall_error +#define mcount _mcount +#endif + +#endif /* __ASSEMBLER__ */ diff --git a/libpthread/nptl/sysdeps/arm/tcb-offsets.sym b/libpthread/nptl/sysdeps/arm/tcb-offsets.sym new file mode 100644 index 000000000..92cc441d3 --- /dev/null +++ b/libpthread/nptl/sysdeps/arm/tcb-offsets.sym @@ -0,0 +1,11 @@ +#include <sysdep.h> +#include <tls.h> + +-- + +-- Derive offsets relative to the thread register. +#define thread_offsetof(mem) (long)(offsetof(struct pthread, mem) - sizeof(struct pthread)) + +MULTIPLE_THREADS_OFFSET thread_offsetof (header.multiple_threads) +PID_OFFSET thread_offsetof (pid) +TID_OFFSET thread_offsetof (tid) diff --git a/libpthread/nptl/sysdeps/arm/thumb_atomics.S b/libpthread/nptl/sysdeps/arm/thumb_atomics.S new file mode 100644 index 000000000..aaa7a3d8f --- /dev/null +++ b/libpthread/nptl/sysdeps/arm/thumb_atomics.S @@ -0,0 +1 @@ +#include <../../../../ldso/ldso/arm/thumb_atomics.S> diff --git a/libpthread/nptl/sysdeps/arm/tls.h b/libpthread/nptl/sysdeps/arm/tls.h new file mode 100644 index 000000000..b8efd59b3 --- /dev/null +++ b/libpthread/nptl/sysdeps/arm/tls.h @@ -0,0 +1,140 @@ +/* Definition for thread-local data handling. NPTL/ARM version. + Copyright (C) 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _TLS_H +#define _TLS_H 1 + +#ifndef __ASSEMBLER__ +#include <dl-sysdep.h> + +# include <stdbool.h> +# include <stddef.h> +# include <stdint.h> + +/* Type for the dtv. */ +typedef union dtv +{ + size_t counter; + struct + { + void *val; + bool is_static; + } pointer; +} dtv_t; + +#else /* __ASSEMBLER__ */ +# include <tcb-offsets.h> +#endif /* __ASSEMBLER__ */ + + +/* We require TLS support in the tools. */ +#define HAVE_TLS_SUPPORT 1 +#define HAVE_TLS_MODEL_ATTRIBUTE 1 +#define HAVE___THREAD 1 + +/* Signal that TLS support is available. */ +#define USE_TLS 1 + +/* Like all other modern NPTL ports, ARM uses forced unwinding. */ +#define HAVE_FORCED_UNWIND + +#ifndef __ASSEMBLER__ + +/* Get system call information. */ +# include <sysdep.h> + +/* The TP points to the start of the thread blocks. */ +# define TLS_DTV_AT_TP 1 + +/* Get the thread descriptor definition. */ +# include <../../descr.h> + +typedef struct +{ + dtv_t *dtv; + void *private; +} tcbhead_t; + +/* This is the size of the initial TCB. */ +# define TLS_INIT_TCB_SIZE sizeof (tcbhead_t) + +/* Alignment requirements for the initial TCB. */ +# define TLS_INIT_TCB_ALIGN 16 + +/* This is the size of the TCB. */ +# define TLS_TCB_SIZE sizeof (tcbhead_t) + +/* This is the size we need before TCB. */ +# define TLS_PRE_TCB_SIZE sizeof (struct pthread) + +/* Alignment requirements for the TCB. */ +# define TLS_TCB_ALIGN 16 + +/* Install the dtv pointer. The pointer passed is to the element with + index -1 which contain the length. */ +# define INSTALL_DTV(tcbp, dtvp) \ + (((tcbhead_t *) (tcbp))->dtv = (dtvp) + 1) + +/* Install new dtv for current thread. */ +# define INSTALL_NEW_DTV(dtv) \ + (THREAD_DTV() = (dtv)) + +/* Return dtv of given thread descriptor. */ +# define GET_DTV(tcbp) \ + (((tcbhead_t *) (tcbp))->dtv) + +/* Code to initially initialize the thread pointer. This might need + special attention since 'errno' is not yet available and if the + operation can cause a failure 'errno' must not be touched. */ +# define TLS_INIT_TP(tcbp, secondcall) \ + ({ INTERNAL_SYSCALL_DECL (err); \ + long result_var; \ + result_var = INTERNAL_SYSCALL_ARM (set_tls, err, 1, (tcbp)); \ + INTERNAL_SYSCALL_ERROR_P (result_var, err) \ + ? "unknown error" : NULL; }) + +/* Return the address of the dtv for the current thread. */ +# define THREAD_DTV() \ + (((tcbhead_t *) __builtin_thread_pointer ())->dtv) + +/* Return the thread descriptor for the current thread. */ +# define THREAD_SELF \ + ((struct pthread *)__builtin_thread_pointer () - 1) + +/* Magic for libthread_db to know how to do THREAD_SELF. */ +# define DB_THREAD_SELF \ + CONST_THREAD_AREA (32, sizeof (struct pthread)) + +/* Access to data in the thread descriptor is easy. */ +#define THREAD_GETMEM(descr, member) \ + descr->member +#define THREAD_GETMEM_NC(descr, member, idx) \ + descr->member[idx] +#define THREAD_SETMEM(descr, member, value) \ + descr->member = (value) +#define THREAD_SETMEM_NC(descr, member, idx, value) \ + descr->member[idx] = (value) + +/* Initializing the thread pointer will generate a SIGILL if the syscall + is not available. */ +#define TLS_INIT_TP_EXPENSIVE 1 + +#endif /* __ASSEMBLER__ */ + +#endif /* tls.h */ diff --git a/libpthread/nptl/sysdeps/generic/Makefile b/libpthread/nptl/sysdeps/generic/Makefile new file mode 100644 index 000000000..582661fde --- /dev/null +++ b/libpthread/nptl/sysdeps/generic/Makefile @@ -0,0 +1,13 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2006 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +top_srcdir=../../../../ +top_builddir=../../../../ +all: objs +include $(top_builddir)Rules.mak +include Makefile.in +include $(top_srcdir)Makerules diff --git a/libpthread/nptl/sysdeps/generic/Makefile.in b/libpthread/nptl/sysdeps/generic/Makefile.in new file mode 100644 index 000000000..1079a5fd9 --- /dev/null +++ b/libpthread/nptl/sysdeps/generic/Makefile.in @@ -0,0 +1,30 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2006 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +# +# NOTE: Alpha and MIPS have their own versions of 'libc-tls.c' in +# their architecture specific directory which will override +# the one here. +# +libc_a_CSRC = dl-tls.c libc-tls.c + + +CFLAGS-generic = $(SSP_ALL_CFLAGS) +#CFLAGS:=$(CFLAGS:-O1=-O2) + +PTHREAD_GENERIC_OUT:=$(top_builddir)libpthread/nptl/sysdeps/generic + +LIBC_GENERIC_OBJ:=$(patsubst %.c,$(PTHREAD_GENERIC_OUT)/%.o,$(libc_a_CSRC)) + +libc-static-y+=$(LIBC_GENERIC_OBJ) + +libc-nomulti-y+=$(LIBC_GENERIC_OBJ) + +objclean-y+=nptl_pthread_generic_clean + +nptl_pthread_generic_clean: + $(do_rm) $(addprefix $(PTHREAD_GENERIC_OUT)/*., o os oS) diff --git a/libpthread/nptl/sysdeps/generic/dl-tls.c b/libpthread/nptl/sysdeps/generic/dl-tls.c new file mode 100644 index 000000000..da6ebbddb --- /dev/null +++ b/libpthread/nptl/sysdeps/generic/dl-tls.c @@ -0,0 +1,895 @@ +/* Thread-local storage handling in the ELF dynamic linker. Generic version. + Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <libintl.h> +#include <signal.h> +#include <stdlib.h> +#include <sys/param.h> +#include <tls.h> +#include <dl-tls.h> +#include <ldsodefs.h> +#include <dl-elf.h> +#include <dl-hash.h> + +#include <assert.h> +#include <link.h> +#include <string.h> +#include <unistd.h> +#include <stdio.h> + +#define _dl_malloc malloc +#define _dl_memset memset +#define _dl_mempcpy mempcpy +#define _dl_dprintf fprintf +#define _dl_debug_file stderr +#define _dl_exit exit + +/* Amount of excess space to allocate in the static TLS area + to allow dynamic loading of modules defining IE-model TLS data. */ +# define TLS_STATIC_SURPLUS 64 + DL_NNS * 100 + +/* Value used for dtv entries for which the allocation is delayed. */ +# define TLS_DTV_UNALLOCATED ((void *) -1l) + + +/* Out-of-memory handler. */ +# ifdef SHARED +static void +__attribute__ ((__noreturn__)) +oom (void) +{ + do { + _dl_dprintf (_dl_debug_file, + "cannot allocate thread-local memory: ABORT\n"); + _dl_exit (127); + } while (1); +} +# endif + + +void *_dl_memalign(size_t alignment, size_t bytes) +{ + return _dl_malloc(bytes); +} + + +/* + * We are trying to perform a static TLS relocation in MAP, but it was + * dynamically loaded. This can only work if there is enough surplus in + * the static TLS area already allocated for each running thread. If this + * object's TLS segment is too big to fit, we fail. If it fits, + * we set MAP->l_tls_offset and return. + * This function intentionally does not return any value but signals error + * directly, as static TLS should be rare and code handling it should + * not be inlined as much as possible. + */ + + +void +internal_function __attribute_noinline__ +_dl_allocate_static_tls (struct link_map *map) +{ + /* If the alignment requirements are too high fail. */ + if (map->l_tls_align > _dl_tls_static_align) + { +fail: + _dl_dprintf(_dl_debug_file, "cannot allocate memory in static TLS block"); + _dl_exit(30); + } + +# if defined(TLS_TCB_AT_TP) + size_t freebytes; + size_t n; + size_t blsize; + + freebytes = _dl_tls_static_size - _dl_tls_static_used - TLS_TCB_SIZE; + + blsize = map->l_tls_blocksize + map->l_tls_firstbyte_offset; + if (freebytes < blsize) + goto fail; + + n = (freebytes - blsize) / map->l_tls_align; + + size_t offset = _dl_tls_static_used + (freebytes - n * map->l_tls_align + - map->l_tls_firstbyte_offset); + + map->l_tls_offset = _dl_tls_static_used = offset; +# elif defined(TLS_DTV_AT_TP) + size_t used; + size_t check; + + size_t offset = roundup (_dl_tls_static_used, map->l_tls_align); + used = offset + map->l_tls_blocksize; + check = used; + + /* dl_tls_static_used includes the TCB at the beginning. */ + if (check > _dl_tls_static_size) + goto fail; + + map->l_tls_offset = offset; + _dl_tls_static_used = used; +# else +# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined" +# endif + + /* + * If the object is not yet relocated we cannot initialize the + * static TLS region. Delay it. + */ + if (((struct elf_resolve *) map)->init_flag & RELOCS_DONE) + { +#ifdef SHARED + /* + * Update the slot information data for at least the generation of + * the DSO we are allocating data for. + */ + if (__builtin_expect (THREAD_DTV()[0].counter != _dl_tls_generation, 0)) + (void) _dl_update_slotinfo (map->l_tls_modid); +#endif + _dl_init_static_tls (map); + } + else + map->l_need_tls_init = 1; +} + +size_t +internal_function +_dl_next_tls_modid (void) +{ + size_t result; + + if (__builtin_expect (GL(dl_tls_dtv_gaps), false)) + { + size_t disp = 0; + struct dtv_slotinfo_list *runp = GL(dl_tls_dtv_slotinfo_list); + + /* Note that this branch will never be executed during program + start since there are no gaps at that time. Therefore it + does not matter that the dl_tls_dtv_slotinfo is not allocated + yet when the function is called for the first times. + + NB: the offset +1 is due to the fact that DTV[0] is used + for something else. */ + result = GL(dl_tls_static_nelem) + 1; + if (result <= GL(dl_tls_max_dtv_idx)) + do + { + while (result - disp < runp->len) + { + if (runp->slotinfo[result - disp].map == NULL) + break; + + ++result; + assert (result <= GL(dl_tls_max_dtv_idx) + 1); + } + + if (result - disp < runp->len) + break; + + disp += runp->len; + } + while ((runp = runp->next) != NULL); + + if (result > GL(dl_tls_max_dtv_idx)) + { + /* The new index must indeed be exactly one higher than the + previous high. */ + assert (result == GL(dl_tls_max_dtv_idx) + 1); + /* There is no gap anymore. */ + GL(dl_tls_dtv_gaps) = false; + + goto nogaps; + } + } + else + { + /* No gaps, allocate a new entry. */ + nogaps: + + result = ++GL(dl_tls_max_dtv_idx); + } + + return result; +} + + +# ifdef SHARED +void +internal_function +_dl_determine_tlsoffset (void) +{ + size_t max_align = TLS_TCB_ALIGN; + size_t freetop = 0; + size_t freebottom = 0; + + /* The first element of the dtv slot info list is allocated. */ + assert (GL(dl_tls_dtv_slotinfo_list) != NULL); + /* There is at this point only one element in the + dl_tls_dtv_slotinfo_list list. */ + assert (GL(dl_tls_dtv_slotinfo_list)->next == NULL); + + struct dtv_slotinfo *slotinfo = GL(dl_tls_dtv_slotinfo_list)->slotinfo; + + /* Determining the offset of the various parts of the static TLS + block has several dependencies. In addition we have to work + around bugs in some toolchains. + + Each TLS block from the objects available at link time has a size + and an alignment requirement. The GNU ld computes the alignment + requirements for the data at the positions *in the file*, though. + I.e, it is not simply possible to allocate a block with the size + of the TLS program header entry. The data is layed out assuming + that the first byte of the TLS block fulfills + + p_vaddr mod p_align == &TLS_BLOCK mod p_align + + This means we have to add artificial padding at the beginning of + the TLS block. These bytes are never used for the TLS data in + this module but the first byte allocated must be aligned + according to mod p_align == 0 so that the first byte of the TLS + block is aligned according to p_vaddr mod p_align. This is ugly + and the linker can help by computing the offsets in the TLS block + assuming the first byte of the TLS block is aligned according to + p_align. + + The extra space which might be allocated before the first byte of + the TLS block need not go unused. The code below tries to use + that memory for the next TLS block. This can work if the total + memory requirement for the next TLS block is smaller than the + gap. */ + +# if defined(TLS_TCB_AT_TP) + /* We simply start with zero. */ + size_t offset = 0; + + for (size_t cnt = 0; slotinfo[cnt].map != NULL; ++cnt) + { + assert (cnt < GL(dl_tls_dtv_slotinfo_list)->len); + + size_t firstbyte = (-slotinfo[cnt].map->l_tls_firstbyte_offset + & (slotinfo[cnt].map->l_tls_align - 1)); + size_t off; + max_align = MAX (max_align, slotinfo[cnt].map->l_tls_align); + + if (freebottom - freetop >= slotinfo[cnt].map->l_tls_blocksize) + { + off = roundup (freetop + slotinfo[cnt].map->l_tls_blocksize + - firstbyte, slotinfo[cnt].map->l_tls_align) + + firstbyte; + if (off <= freebottom) + { + freetop = off; + + /* XXX For some architectures we perhaps should store the + negative offset. */ + slotinfo[cnt].map->l_tls_offset = off; + continue; + } + } + + off = roundup (offset + slotinfo[cnt].map->l_tls_blocksize - firstbyte, + slotinfo[cnt].map->l_tls_align) + firstbyte; + if (off > offset + slotinfo[cnt].map->l_tls_blocksize + + (freebottom - freetop)) + { + freetop = offset; + freebottom = off - slotinfo[cnt].map->l_tls_blocksize; + } + offset = off; + + /* XXX For some architectures we perhaps should store the + negative offset. */ + slotinfo[cnt].map->l_tls_offset = off; + } + + GL(dl_tls_static_used) = offset; + GL(dl_tls_static_size) = (roundup (offset + TLS_STATIC_SURPLUS, max_align) + + TLS_TCB_SIZE); +# elif defined(TLS_DTV_AT_TP) + /* The TLS blocks start right after the TCB. */ + size_t offset = TLS_TCB_SIZE; + size_t cnt; + + for (cnt = 0; slotinfo[cnt].map != NULL; ++cnt) + { + assert (cnt < GL(dl_tls_dtv_slotinfo_list)->len); + + size_t firstbyte = (-slotinfo[cnt].map->l_tls_firstbyte_offset + & (slotinfo[cnt].map->l_tls_align - 1)); + size_t off; + max_align = MAX (max_align, slotinfo[cnt].map->l_tls_align); + + if (slotinfo[cnt].map->l_tls_blocksize <= freetop - freebottom) + { + off = roundup (freebottom, slotinfo[cnt].map->l_tls_align); + if (off - freebottom < firstbyte) + off += slotinfo[cnt].map->l_tls_align; + if (off + slotinfo[cnt].map->l_tls_blocksize - firstbyte <= freetop) + { + slotinfo[cnt].map->l_tls_offset = off - firstbyte; + freebottom = (off + slotinfo[cnt].map->l_tls_blocksize + - firstbyte); + continue; + } + } + + off = roundup (offset, slotinfo[cnt].map->l_tls_align); + if (off - offset < firstbyte) + off += slotinfo[cnt].map->l_tls_align; + + slotinfo[cnt].map->l_tls_offset = off - firstbyte; + if (off - firstbyte - offset > freetop - freebottom) + { + freebottom = offset; + freetop = off - firstbyte; + } + + offset = off + slotinfo[cnt].map->l_tls_blocksize - firstbyte; + } + + GL(dl_tls_static_used) = offset; + GL(dl_tls_static_size) = roundup (offset + TLS_STATIC_SURPLUS, + TLS_TCB_ALIGN); +# else +# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined" +# endif + + /* The alignment requirement for the static TLS block. */ + GL(dl_tls_static_align) = max_align; +} + + +/* This is called only when the data structure setup was skipped at startup, + when there was no need for it then. Now we have dynamically loaded + something needing TLS, or libpthread needs it. */ +int +internal_function +_dl_tls_setup (void) +{ + assert (GL(dl_tls_dtv_slotinfo_list) == NULL); + assert (GL(dl_tls_max_dtv_idx) == 0); + + const size_t nelem = 2 + TLS_SLOTINFO_SURPLUS; + + GL(dl_tls_dtv_slotinfo_list) + = calloc (1, (sizeof (struct dtv_slotinfo_list) + + nelem * sizeof (struct dtv_slotinfo))); + if (GL(dl_tls_dtv_slotinfo_list) == NULL) + return -1; + + GL(dl_tls_dtv_slotinfo_list)->len = nelem; + + /* Number of elements in the static TLS block. It can't be zero + because of various assumptions. The one element is null. */ + GL(dl_tls_static_nelem) = GL(dl_tls_max_dtv_idx) = 1; + + /* This initializes more variables for us. */ + _dl_determine_tlsoffset (); + + return 0; +} +# endif + +static void * +internal_function +allocate_dtv (void *result) +{ + dtv_t *dtv; + size_t dtv_length; + + /* We allocate a few more elements in the dtv than are needed for the + initial set of modules. This should avoid in most cases expansions + of the dtv. */ + dtv_length = GL(dl_tls_max_dtv_idx) + DTV_SURPLUS; + dtv = calloc (dtv_length + 2, sizeof (dtv_t)); + if (dtv != NULL) + { + /* This is the initial length of the dtv. */ + dtv[0].counter = dtv_length; + + /* The rest of the dtv (including the generation counter) is + Initialize with zero to indicate nothing there. */ + + /* Add the dtv to the thread data structures. */ + INSTALL_DTV (result, dtv); + } + else + result = NULL; + + return result; +} + + +/* Get size and alignment requirements of the static TLS block. */ +void +internal_function +_dl_get_tls_static_info (size_t *sizep, size_t *alignp) +{ + *sizep = GL(dl_tls_static_size); + *alignp = GL(dl_tls_static_align); +} + + +void * +internal_function +_dl_allocate_tls_storage (void) +{ + void *result; + size_t size = GL(dl_tls_static_size); + +# if defined(TLS_DTV_AT_TP) + /* Memory layout is: + [ TLS_PRE_TCB_SIZE ] [ TLS_TCB_SIZE ] [ TLS blocks ] + ^ This should be returned. */ + size += (TLS_PRE_TCB_SIZE + GL(dl_tls_static_align) - 1) + & ~(GL(dl_tls_static_align) - 1); +# endif + + /* Allocate a correctly aligned chunk of memory. */ + result = _dl_memalign (GL(dl_tls_static_align), size); + if (__builtin_expect (result != NULL, 1)) + { + /* Allocate the DTV. */ + void *allocated = result; + +# if defined(TLS_TCB_AT_TP) + /* The TCB follows the TLS blocks. */ + result = (char *) result + size - TLS_TCB_SIZE; + + /* Clear the TCB data structure. We can't ask the caller (i.e. + libpthread) to do it, because we will initialize the DTV et al. */ + _dl_memset (result, '\0', TLS_TCB_SIZE); +# elif defined(TLS_DTV_AT_TP) + result = (char *) result + size - GL(dl_tls_static_size); + + /* Clear the TCB data structure and TLS_PRE_TCB_SIZE bytes before it. + We can't ask the caller (i.e. libpthread) to do it, because we will + initialize the DTV et al. */ + _dl_memset ((char *) result - TLS_PRE_TCB_SIZE, '\0', + TLS_PRE_TCB_SIZE + TLS_TCB_SIZE); +# endif + + result = allocate_dtv (result); + if (result == NULL) + free (allocated); + } + + return result; +} + + +void * +internal_function +_dl_allocate_tls_init (void *result) +{ + if (result == NULL) + /* The memory allocation failed. */ + return NULL; + + dtv_t *dtv = GET_DTV (result); + struct dtv_slotinfo_list *listp; + size_t total = 0; + size_t maxgen = 0; + + /* We have to prepare the dtv for all currently loaded modules using + TLS. For those which are dynamically loaded we add the values + indicating deferred allocation. */ + listp = GL(dl_tls_dtv_slotinfo_list); + while (1) + { + size_t cnt; + + for (cnt = total == 0 ? 1 : 0; cnt < listp->len; ++cnt) + { + struct link_map *map; + void *dest; + + /* Check for the total number of used slots. */ + if (total + cnt > GL(dl_tls_max_dtv_idx)) + break; + + map = listp->slotinfo[cnt].map; + if (map == NULL) + /* Unused entry. */ + continue; + + /* Keep track of the maximum generation number. This might + not be the generation counter. */ + maxgen = MAX (maxgen, listp->slotinfo[cnt].gen); + + if (map->l_tls_offset == NO_TLS_OFFSET) + { + /* For dynamically loaded modules we simply store + the value indicating deferred allocation. */ + dtv[map->l_tls_modid].pointer.val = TLS_DTV_UNALLOCATED; + dtv[map->l_tls_modid].pointer.is_static = false; + continue; + } + + assert (map->l_tls_modid == cnt); + assert (map->l_tls_blocksize >= map->l_tls_initimage_size); +# if defined(TLS_TCB_AT_TP) + assert ((size_t) map->l_tls_offset >= map->l_tls_blocksize); + dest = (char *) result - map->l_tls_offset; +# elif defined(TLS_DTV_AT_TP) + dest = (char *) result + map->l_tls_offset; +# else +# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined" +# endif + + /* Copy the initialization image and clear the BSS part. */ + dtv[map->l_tls_modid].pointer.val = dest; + dtv[map->l_tls_modid].pointer.is_static = true; + _dl_memset (_dl_mempcpy (dest, map->l_tls_initimage, + map->l_tls_initimage_size), '\0', + map->l_tls_blocksize - map->l_tls_initimage_size); + } + + total += cnt; + if (total >= GL(dl_tls_max_dtv_idx)) + break; + + listp = listp->next; + assert (listp != NULL); + } + + /* The DTV version is up-to-date now. */ + dtv[0].counter = maxgen; + + return result; +} + +void * +internal_function +_dl_allocate_tls (void *mem) +{ + return _dl_allocate_tls_init (mem == NULL + ? _dl_allocate_tls_storage () + : allocate_dtv (mem)); +} + + +void +internal_function +_dl_deallocate_tls (void *tcb, bool dealloc_tcb) +{ + dtv_t *dtv = GET_DTV (tcb); + size_t cnt; + + /* We need to free the memory allocated for non-static TLS. */ + for (cnt = 0; cnt < dtv[-1].counter; ++cnt) + if (! dtv[1 + cnt].pointer.is_static + && dtv[1 + cnt].pointer.val != TLS_DTV_UNALLOCATED) + free (dtv[1 + cnt].pointer.val); + + /* The array starts with dtv[-1]. */ +#ifdef SHARED + if (dtv != GL(dl_initial_dtv)) +#endif + free (dtv - 1); + + if (dealloc_tcb) + { +# if defined(TLS_TCB_AT_TP) + /* The TCB follows the TLS blocks. Back up to free the whole block. */ + tcb -= GL(dl_tls_static_size) - TLS_TCB_SIZE; +# elif defined(TLS_DTV_AT_TP) + /* Back up the TLS_PRE_TCB_SIZE bytes. */ + tcb -= (TLS_PRE_TCB_SIZE + GL(dl_tls_static_align) - 1) + & ~(GL(dl_tls_static_align) - 1); +# endif + free (tcb); + } +} + + +# ifdef SHARED +/* The __tls_get_addr function has two basic forms which differ in the + arguments. The IA-64 form takes two parameters, the module ID and + offset. The form used, among others, on IA-32 takes a reference to + a special structure which contain the same information. The second + form seems to be more often used (in the moment) so we default to + it. Users of the IA-64 form have to provide adequate definitions + of the following macros. */ +# ifndef GET_ADDR_ARGS +# define GET_ADDR_ARGS tls_index *ti +# endif +# ifndef GET_ADDR_MODULE +# define GET_ADDR_MODULE ti->ti_module +# endif +# ifndef GET_ADDR_OFFSET +# define GET_ADDR_OFFSET ti->ti_offset +# endif + + +static void * +allocate_and_init (struct link_map *map) +{ + void *newp; + + newp = _dl_memalign (map->l_tls_align, map->l_tls_blocksize); + if (newp == NULL) + oom (); + + /* Initialize the memory. */ + _dl_memset (_dl_mempcpy (newp, map->l_tls_initimage, map->l_tls_initimage_size), + '\0', map->l_tls_blocksize - map->l_tls_initimage_size); + + return newp; +} + + +struct link_map * +_dl_update_slotinfo (unsigned long int req_modid) +{ + struct link_map *the_map = NULL; + dtv_t *dtv = THREAD_DTV (); + + /* The global dl_tls_dtv_slotinfo array contains for each module + index the generation counter current when the entry was created. + This array never shrinks so that all module indices which were + valid at some time can be used to access it. Before the first + use of a new module index in this function the array was extended + appropriately. Access also does not have to be guarded against + modifications of the array. It is assumed that pointer-size + values can be read atomically even in SMP environments. It is + possible that other threads at the same time dynamically load + code and therefore add to the slotinfo list. This is a problem + since we must not pick up any information about incomplete work. + The solution to this is to ignore all dtv slots which were + created after the one we are currently interested. We know that + dynamic loading for this module is completed and this is the last + load operation we know finished. */ + unsigned long int idx = req_modid; + struct dtv_slotinfo_list *listp = GL(dl_tls_dtv_slotinfo_list); + + while (idx >= listp->len) + { + idx -= listp->len; + listp = listp->next; + } + + if (dtv[0].counter < listp->slotinfo[idx].gen) + { + /* The generation counter for the slot is higher than what the + current dtv implements. We have to update the whole dtv but + only those entries with a generation counter <= the one for + the entry we need. */ + size_t new_gen = listp->slotinfo[idx].gen; + size_t total = 0; + + /* We have to look through the entire dtv slotinfo list. */ + listp = GL(dl_tls_dtv_slotinfo_list); + do + { + size_t cnt; + + for (cnt = total == 0 ? 1 : 0; cnt < listp->len; ++cnt) + { + size_t gen = listp->slotinfo[cnt].gen; + + if (gen > new_gen) + /* This is a slot for a generation younger than the + one we are handling now. It might be incompletely + set up so ignore it. */ + continue; + + /* If the entry is older than the current dtv layout we + know we don't have to handle it. */ + if (gen <= dtv[0].counter) + continue; + + /* If there is no map this means the entry is empty. */ + struct link_map *map = listp->slotinfo[cnt].map; + if (map == NULL) + { + /* If this modid was used at some point the memory + might still be allocated. */ + if (! dtv[total + cnt].pointer.is_static + && dtv[total + cnt].pointer.val != TLS_DTV_UNALLOCATED) + { + free (dtv[total + cnt].pointer.val); + dtv[total + cnt].pointer.val = TLS_DTV_UNALLOCATED; + } + + continue; + } + + /* Check whether the current dtv array is large enough. */ + size_t modid = map->l_tls_modid; + assert (total + cnt == modid); + if (dtv[-1].counter < modid) + { + /* Reallocate the dtv. */ + dtv_t *newp; + size_t newsize = GL(dl_tls_max_dtv_idx) + DTV_SURPLUS; + size_t oldsize = dtv[-1].counter; + + assert (map->l_tls_modid <= newsize); + + if (dtv == GL(dl_initial_dtv)) + { + /* This is the initial dtv that was allocated + during rtld startup using the dl-minimal.c + malloc instead of the real malloc. We can't + free it, we have to abandon the old storage. */ + + newp = malloc ((2 + newsize) * sizeof (dtv_t)); + if (newp == NULL) + oom (); + _dl_memcpy (newp, &dtv[-1], oldsize * sizeof (dtv_t)); + } + else + { + newp = realloc (&dtv[-1], + (2 + newsize) * sizeof (dtv_t)); + if (newp == NULL) + oom (); + } + + newp[0].counter = newsize; + + /* Clear the newly allocated part. */ + _dl_memset (newp + 2 + oldsize, '\0', + (newsize - oldsize) * sizeof (dtv_t)); + + /* Point dtv to the generation counter. */ + dtv = &newp[1]; + + /* Install this new dtv in the thread data + structures. */ + INSTALL_NEW_DTV (dtv); + } + + /* If there is currently memory allocate for this + dtv entry free it. */ + /* XXX Ideally we will at some point create a memory + pool. */ + if (! dtv[modid].pointer.is_static + && dtv[modid].pointer.val != TLS_DTV_UNALLOCATED) + /* Note that free is called for NULL is well. We + deallocate even if it is this dtv entry we are + supposed to load. The reason is that we call + memalign and not malloc. */ + free (dtv[modid].pointer.val); + + /* This module is loaded dynamically- We defer memory + allocation. */ + dtv[modid].pointer.is_static = false; + dtv[modid].pointer.val = TLS_DTV_UNALLOCATED; + + if (modid == req_modid) + the_map = map; + } + + total += listp->len; + } + while ((listp = listp->next) != NULL); + + /* This will be the new maximum generation counter. */ + dtv[0].counter = new_gen; + } + + return the_map; +} + + +/* The generic dynamic and local dynamic model cannot be used in + statically linked applications. */ +void * +__tls_get_addr (GET_ADDR_ARGS) +{ + dtv_t *dtv = THREAD_DTV (); + struct link_map *the_map = NULL; + void *p; + + if (__builtin_expect (dtv[0].counter != GL(dl_tls_generation), 0)) + the_map = _dl_update_slotinfo (GET_ADDR_MODULE); + + p = dtv[GET_ADDR_MODULE].pointer.val; + + if (__builtin_expect (p == TLS_DTV_UNALLOCATED, 0)) + { + /* The allocation was deferred. Do it now. */ + if (the_map == NULL) + { + /* Find the link map for this module. */ + size_t idx = GET_ADDR_MODULE; + struct dtv_slotinfo_list *listp = GL(dl_tls_dtv_slotinfo_list); + + while (idx >= listp->len) + { + idx -= listp->len; + listp = listp->next; + } + + the_map = listp->slotinfo[idx].map; + } + + p = dtv[GET_ADDR_MODULE].pointer.val = allocate_and_init (the_map); + dtv[GET_ADDR_MODULE].pointer.is_static = false; + } + + return (char *) p + GET_ADDR_OFFSET; +} +# endif + + + +void +_dl_add_to_slotinfo (struct link_map *l) +{ + /* Now that we know the object is loaded successfully add + modules containing TLS data to the dtv info table. We + might have to increase its size. */ + struct dtv_slotinfo_list *listp; + struct dtv_slotinfo_list *prevp; + size_t idx = l->l_tls_modid; + + /* Find the place in the dtv slotinfo list. */ + listp = GL(dl_tls_dtv_slotinfo_list); + prevp = NULL; /* Needed to shut up gcc. */ + do + { + /* Does it fit in the array of this list element? */ + if (idx < listp->len) + break; + idx -= listp->len; + prevp = listp; + listp = listp->next; + } + while (listp != NULL); + + if (listp == NULL) + { + /* When we come here it means we have to add a new element + to the slotinfo list. And the new module must be in + the first slot. */ + assert (idx == 0); + + listp = prevp->next = (struct dtv_slotinfo_list *) + malloc (sizeof (struct dtv_slotinfo_list) + + TLS_SLOTINFO_SURPLUS * sizeof (struct dtv_slotinfo)); + if (listp == NULL) + { + /* We ran out of memory. We will simply fail this + call but don't undo anything we did so far. The + application will crash or be terminated anyway very + soon. */ + + /* We have to do this since some entries in the dtv + slotinfo array might already point to this + generation. */ + ++GL(dl_tls_generation); + + _dl_dprintf (_dl_debug_file, + "cannot create TLS data structures: ABORT\n"); + _dl_exit (127); + } + + listp->len = TLS_SLOTINFO_SURPLUS; + listp->next = NULL; + _dl_memset (listp->slotinfo, '\0', + TLS_SLOTINFO_SURPLUS * sizeof (struct dtv_slotinfo)); + } + + /* Add the information into the slotinfo data structure. */ + listp->slotinfo[idx].map = l; + listp->slotinfo[idx].gen = GL(dl_tls_generation) + 1; +} diff --git a/libpthread/nptl/sysdeps/generic/dl-tls.h b/libpthread/nptl/sysdeps/generic/dl-tls.h new file mode 100644 index 000000000..7703a9752 --- /dev/null +++ b/libpthread/nptl/sysdeps/generic/dl-tls.h @@ -0,0 +1,2 @@ +/* There has to be an architecture specific version of this file. */ +#error "architecture-specific version of <dl-tls.h> missing" diff --git a/libpthread/nptl/sysdeps/generic/libc-tls.c b/libpthread/nptl/sysdeps/generic/libc-tls.c new file mode 100644 index 000000000..b78d96483 --- /dev/null +++ b/libpthread/nptl/sysdeps/generic/libc-tls.c @@ -0,0 +1,265 @@ +/* Initialization code for TLS in statically linked application. + Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <ldsodefs.h> +#include <tls.h> +#include <unistd.h> +#include <stdio.h> +#include <sys/param.h> +#include <elf.h> +#include <link.h> +#include <string.h> +#include <stdlib.h> + + +#ifdef SHARED + #error makefile bug, this file is for static only +#endif + +#if USE_TLS +extern ElfW(Phdr) *_dl_phdr; +extern size_t _dl_phnum; + + +static dtv_t static_dtv[2 + TLS_SLOTINFO_SURPLUS]; + + +static struct +{ + struct dtv_slotinfo_list si; + /* The dtv_slotinfo_list data structure does not include the actual + information since it is defined as an array of size zero. We define + here the necessary entries. Note that it is not important whether + there is padding or not since we will always access the information + through the 'si' element. */ + struct dtv_slotinfo info[2 + TLS_SLOTINFO_SURPLUS]; +} static_slotinfo; + +/* Fake link map for the application. */ +static struct link_map static_map; + + +/* Highest dtv index currently needed. */ +size_t _dl_tls_max_dtv_idx; +/* Flag signalling whether there are gaps in the module ID allocation. */ +bool _dl_tls_dtv_gaps; +/* Information about the dtv slots. */ +struct dtv_slotinfo_list *_dl_tls_dtv_slotinfo_list; +/* Number of modules in the static TLS block. */ +size_t _dl_tls_static_nelem; +/* Size of the static TLS block. */ +size_t _dl_tls_static_size; +/* Size actually allocated in the static TLS block. */ +size_t _dl_tls_static_used; +/* Alignment requirement of the static TLS block. */ +size_t _dl_tls_static_align; + +/* Generation counter for the dtv. */ +size_t _dl_tls_generation; + + +/* Additional definitions needed by TLS initialization. */ +#ifdef TLS_INIT_HELPER +TLS_INIT_HELPER +#endif + +static inline void +init_slotinfo (void) +{ + /* Create the slotinfo list. */ + static_slotinfo.si.len = (((char *) (&static_slotinfo + 1) + - (char *) &static_slotinfo.si.slotinfo[0]) + / sizeof static_slotinfo.si.slotinfo[0]); + // static_slotinfo.si.next = NULL; already zero + + /* The slotinfo list. Will be extended by the code doing dynamic + linking. */ + GL(dl_tls_max_dtv_idx) = 1; + GL(dl_tls_dtv_slotinfo_list) = &static_slotinfo.si; +} + +static inline void +init_static_tls (size_t memsz, size_t align) +{ + /* That is the size of the TLS memory for this object. The initialized + value of _dl_tls_static_size is provided by dl-open.c to request some + surplus that permits dynamic loading of modules with IE-model TLS. */ + GL(dl_tls_static_size) = roundup (memsz + GL(dl_tls_static_size), + TLS_TCB_ALIGN); + GL(dl_tls_static_used) = memsz; + /* The alignment requirement for the static TLS block. */ + GL(dl_tls_static_align) = align; + /* Number of elements in the static TLS block. */ + GL(dl_tls_static_nelem) = GL(dl_tls_max_dtv_idx); +} + +void +__libc_setup_tls (size_t tcbsize, size_t tcbalign) +{ + void *tlsblock; + size_t memsz = 0; + size_t filesz = 0; + void *initimage = NULL; + size_t align = 0; + size_t max_align = tcbalign; + size_t tcb_offset; + ElfW(Phdr) *phdr; + + /* Look through the TLS segment if there is any. */ + if (_dl_phdr != NULL) + for (phdr = _dl_phdr; phdr < &_dl_phdr[_dl_phnum]; ++phdr) + if (phdr->p_type == PT_TLS) + { + /* Remember the values we need. */ + memsz = phdr->p_memsz; + filesz = phdr->p_filesz; + initimage = (void *) phdr->p_vaddr; + align = phdr->p_align; + if (phdr->p_align > max_align) + max_align = phdr->p_align; + break; + } + + /* We have to set up the TCB block which also (possibly) contains + 'errno'. Therefore we avoid 'malloc' which might touch 'errno'. + Instead we use 'sbrk' which would only uses 'errno' if it fails. + In this case we are right away out of memory and the user gets + what she/he deserves. + + The initialized value of _dl_tls_static_size is provided by dl-open.c + to request some surplus that permits dynamic loading of modules with + IE-model TLS. */ +# if defined(TLS_TCB_AT_TP) + tcb_offset = roundup (memsz + GL(dl_tls_static_size), tcbalign); + tlsblock = sbrk (tcb_offset + tcbsize + max_align); +# elif defined(TLS_DTV_AT_TP) + tcb_offset = roundup (tcbsize, align ?: 1); + tlsblock = sbrk (tcb_offset + memsz + max_align + + TLS_PRE_TCB_SIZE + GL(dl_tls_static_size)); + tlsblock += TLS_PRE_TCB_SIZE; +# else + /* In case a model with a different layout for the TCB and DTV + is defined add another #elif here and in the following #ifs. */ +# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined" +# endif + + /* Align the TLS block. */ + tlsblock = (void *) (((uintptr_t) tlsblock + max_align - 1) + & ~(max_align - 1)); + + /* Initialize the dtv. [0] is the length, [1] the generation counter. */ + static_dtv[0].counter = (sizeof (static_dtv) / sizeof (static_dtv[0])) - 2; + // static_dtv[1].counter = 0; would be needed if not already done + + /* Initialize the TLS block. */ +# if defined(TLS_TCB_AT_TP) + static_dtv[2].pointer.val = ((char *) tlsblock + tcb_offset + - roundup (memsz, align ?: 1)); + static_map.l_tls_offset = roundup (memsz, align ?: 1); +# elif defined(TLS_DTV_AT_TP) + static_dtv[2].pointer.val = (char *) tlsblock + tcb_offset; + static_map.l_tls_offset = tcb_offset; +# else +# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined" +# endif + static_dtv[2].pointer.is_static = true; + /* sbrk gives us zero'd memory, so we don't need to clear the remainder. */ + memcpy (static_dtv[2].pointer.val, initimage, filesz); + + /* Install the pointer to the dtv. */ + + /* Initialize the thread pointer. */ +# if defined(TLS_TCB_AT_TP) + INSTALL_DTV ((char *) tlsblock + tcb_offset, static_dtv); + + const char *lossage = TLS_INIT_TP ((char *) tlsblock + tcb_offset, 0); +# elif defined(TLS_DTV_AT_TP) + INSTALL_DTV (tlsblock, static_dtv); + const char *lossage = (char *)TLS_INIT_TP (tlsblock, 0); +# else +# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined" +# endif + if (__builtin_expect (lossage != NULL, 0)) + abort(); + + /* We have to create a fake link map which normally would be created + by the dynamic linker. It just has to have enough information to + make the TLS routines happy. */ + static_map.l_tls_align = align; + static_map.l_tls_blocksize = memsz; + static_map.l_tls_initimage = initimage; + static_map.l_tls_initimage_size = filesz; + static_map.l_tls_modid = 1; + + init_slotinfo (); + // static_slotinfo.si.slotinfo[1].gen = 0; already zero + static_slotinfo.si.slotinfo[1].map = &static_map; + + memsz = roundup (memsz, align ?: 1); + +# if defined(TLS_TCB_AT_TP) + memsz += tcbsize; +# elif defined(TLS_DTV_AT_TP) + memsz += tcb_offset; +# endif + + init_static_tls (memsz, MAX (TLS_TCB_ALIGN, max_align)); +} + +/* This is called only when the data structure setup was skipped at startup, + when there was no need for it then. Now we have dynamically loaded + something needing TLS, or libpthread needs it. */ +int +internal_function +_dl_tls_setup (void) +{ + init_slotinfo (); + init_static_tls ( +# if defined(TLS_TCB_AT_TP) + TLS_TCB_SIZE, +# else + 0, +# endif + TLS_TCB_ALIGN); + return 0; +} + + +/* This is the minimal initialization function used when libpthread is + not used. */ +void +__attribute__ ((weak)) +__pthread_initialize_minimal (void) +{ + __libc_setup_tls (TLS_INIT_TCB_SIZE, TLS_INIT_TCB_ALIGN); +} + +#elif defined NONTLS_INIT_TP + +/* This is the minimal initialization function used when libpthread is + not used. */ +void +__attribute__ ((weak)) +__pthread_initialize_minimal (void) +{ + NONTLS_INIT_TP; +} + +#endif diff --git a/libpthread/nptl/sysdeps/generic/lowlevellock.h b/libpthread/nptl/sysdeps/generic/lowlevellock.h new file mode 100644 index 000000000..7f95daada --- /dev/null +++ b/libpthread/nptl/sysdeps/generic/lowlevellock.h @@ -0,0 +1,89 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <atomic.h> + + +/* Implement generic mutex. Basic futex syscall support is required: + + lll_futex_wait(futex, value) - call sys_futex with FUTEX_WAIT + and third parameter VALUE + + lll_futex_wake(futex, value) - call sys_futex with FUTEX_WAKE + and third parameter VALUE +*/ + + +/* 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); + } +} + + +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); +} + + +#define lll_mutex_lock(futex) __generic_mutex_lock (&(futex)) +#define lll_mutex_unlock(futex) __generic_mutex_unlock (&(futex)) diff --git a/libpthread/nptl/sysdeps/generic/sysdep.h b/libpthread/nptl/sysdeps/generic/sysdep.h new file mode 100644 index 000000000..9627b3e79 --- /dev/null +++ b/libpthread/nptl/sysdeps/generic/sysdep.h @@ -0,0 +1,137 @@ +/* Generic asm macros used on many machines. + Copyright (C) 1991,92,93,96,98,2002,2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef C_LABEL + +/* Define a macro we can use to construct the asm name for a C symbol. */ +#ifndef __UCLIBC_UNDERSCORES__ +#ifdef __STDC__ +#define C_LABEL(name) name##: +#else +#define C_LABEL(name) name/**/: +#endif +#else +#ifdef __STDC__ +#define C_LABEL(name) _##name##: +#else +#define C_LABEL(name) _/**/name/**/: +#endif +#endif + +#endif + +#ifdef __ASSEMBLER__ +/* Mark the end of function named SYM. This is used on some platforms + to generate correct debugging information. */ +#ifndef END +#define END(sym) +#endif + +#ifndef JUMPTARGET +#define JUMPTARGET(sym) sym +#endif + +/* Macros to generate eh_frame unwind information. */ +# ifdef HAVE_ASM_CFI_DIRECTIVES +# define cfi_startproc .cfi_startproc +# define cfi_endproc .cfi_endproc +# define cfi_def_cfa(reg, off) .cfi_def_cfa reg, off +# define cfi_def_cfa_register(reg) .cfi_def_cfa_register reg +# define cfi_def_cfa_offset(off) .cfi_def_cfa_offset off +# define cfi_adjust_cfa_offset(off) .cfi_adjust_cfa_offset off +# define cfi_offset(reg, off) .cfi_offset reg, off +# define cfi_rel_offset(reg, off) .cfi_rel_offset reg, off +# define cfi_register(r1, r2) .cfi_register r1, r2 +# define cfi_return_column(reg) .cfi_return_column reg +# define cfi_restore(reg) .cfi_restore reg +# define cfi_same_value(reg) .cfi_same_value reg +# define cfi_undefined(reg) .cfi_undefined reg +# define cfi_remember_state .cfi_remember_state +# define cfi_restore_state .cfi_restore_state +# define cfi_window_save .cfi_window_save +# else +# define cfi_startproc +# define cfi_endproc +# define cfi_def_cfa(reg, off) +# define cfi_def_cfa_register(reg) +# define cfi_def_cfa_offset(off) +# define cfi_adjust_cfa_offset(off) +# define cfi_offset(reg, off) +# define cfi_rel_offset(reg, off) +# define cfi_register(r1, r2) +# define cfi_return_column(reg) +# define cfi_restore(reg) +# define cfi_same_value(reg) +# define cfi_undefined(reg) +# define cfi_remember_state +# define cfi_restore_state +# define cfi_window_save +# endif + +#else /* ! ASSEMBLER */ +# ifdef HAVE_ASM_CFI_DIRECTIVES +# define CFI_STRINGIFY(Name) CFI_STRINGIFY2 (Name) +# define CFI_STRINGIFY2(Name) #Name +# define CFI_STARTPROC ".cfi_startproc" +# define CFI_ENDPROC ".cfi_endproc" +# define CFI_DEF_CFA(reg, off) \ + ".cfi_def_cfa " CFI_STRINGIFY(reg) "," CFI_STRINGIFY(off) +# define CFI_DEF_CFA_REGISTER(reg) \ + ".cfi_def_cfa_register " CFI_STRINGIFY(reg) +# define CFI_DEF_CFA_OFFSET(off) \ + ".cfi_def_cfa_offset " CFI_STRINGIFY(off) +# define CFI_ADJUST_CFA_OFFSET(off) \ + ".cfi_adjust_cfa_offset " CFI_STRINGIFY(off) +# define CFI_OFFSET(reg, off) \ + ".cfi_offset " CFI_STRINGIFY(reg) "," CFI_STRINGIFY(off) +# define CFI_REL_OFFSET(reg, off) \ + ".cfi_rel_offset " CFI_STRINGIFY(reg) "," CFI_STRINGIFY(off) +# define CFI_REGISTER(r1, r2) \ + ".cfi_register " CFI_STRINGIFY(r1) "," CFI_STRINGIFY(r2) +# define CFI_RETURN_COLUMN(reg) \ + ".cfi_return_column " CFI_STRINGIFY(reg) +# define CFI_RESTORE(reg) \ + ".cfi_restore " CFI_STRINGIFY(reg) +# define CFI_UNDEFINED(reg) \ + ".cfi_undefined " CFI_STRINGIFY(reg) +# define CFI_REMEMBER_STATE \ + ".cfi_remember_state" +# define CFI_RESTORE_STATE \ + ".cfi_restore_state" +# define CFI_WINDOW_SAVE \ + ".cfi_window_save" +# else +# define CFI_STARTPROC +# define CFI_ENDPROC +# define CFI_DEF_CFA(reg, off) +# define CFI_DEF_CFA_REGISTER(reg) +# define CFI_DEF_CFA_OFFSET(off) +# define CFI_ADJUST_CFA_OFFSET(off) +# define CFI_OFFSET(reg, off) +# define CFI_REL_OFFSET(reg, off) +# define CFI_REGISTER(r1, r2) +# define CFI_RETURN_COLUMN(reg) +# define CFI_RESTORE(reg) +# define CFI_UNDEFINED(reg) +# define CFI_REMEMBER_STATE +# define CFI_RESTORE_STATE +# define CFI_WINDOW_SAVE +# endif + +#endif /* __ASSEMBLER__ */ diff --git a/libpthread/nptl/sysdeps/i386/Makefile b/libpthread/nptl/sysdeps/i386/Makefile new file mode 100644 index 000000000..2f0d88f30 --- /dev/null +++ b/libpthread/nptl/sysdeps/i386/Makefile @@ -0,0 +1,27 @@ +# Copyright (C) 2002, 2003 Free Software Foundation, Inc. +# This file is part of the GNU C Library. + +# The GNU C Library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. + +# The GNU C Library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. + +# You should have received a copy of the GNU Lesser General Public +# License along with the GNU C Library; if not, write to the Free +# Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +# 02111-1307 USA. + +ifeq ($(subdir),csu) +gen-as-const-headers += tcb-offsets.sym +endif + +ifeq ($(subdir),nptl) +CFLAGS-pthread_create.c += -mpreferred-stack-boundary=4 +CFLAGS-tst-align.c += -mpreferred-stack-boundary=4 +CFLAGS-tst-align2.c += -mpreferred-stack-boundary=4 +endif diff --git a/libpthread/nptl/sysdeps/i386/Makefile.arch b/libpthread/nptl/sysdeps/i386/Makefile.arch new file mode 100644 index 000000000..2b9a2dc7c --- /dev/null +++ b/libpthread/nptl/sysdeps/i386/Makefile.arch @@ -0,0 +1,53 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2005 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +libpthread_CSRC = pthread_spin_lock.c +libpthread_SSRC = i486/pthread_spin_trylock.S + +CFLAGS-pthread_spin_lock.c += -D_GNU_SOURCE + +CFLAGS-i386 = $(SSP_ALL_CFLAGS) +#CFLAGS:=$(CFLAGS:-O1=-O2) + +PTHREAD_ARCH_DIR := $(top_srcdir)libpthread/nptl/sysdeps/i386/ +PTHREAD_ARCH_OUT := $(top_builddir)libpthread/nptl/sysdeps/i386/ +PTHREAD_ARCH_OBJ := $(patsubst %.S,$(PTHREAD_ARCH_OUT)/%.o,$(libpthread_SSRC)) +PTHREAD_ARCH_OBJ += $(patsubst %.c,$(PTHREAD_ARCH_OUT)/%.o,$(libpthread_CSRC)) + +ifeq ($(DOPIC),y) +libpthread-a-y += $(PTHREAD_ARCH_OBJ:.o=.os) +else +libpthread-a-y += $(PTHREAD_ARCH_OBJ) +endif +libpthread-so-y += $(PTHREAD_ARCH_OBJ:.o=.oS) + +libpthread-nomulti-y += $(PTHREAD_ARCH_OBJ) + +objclean-y += nptl_arch_clean +headers_clean-y += nptl_arch_headers_clean + +# +# Create 'tcb-offsets.h' header file. +# +CFLAGS-tcb-offsets.c = -S + +$(PTHREAD_ARCH_OUT)/tcb-offsets.c: $(PTHREAD_ARCH_DIR)/tcb-offsets.sym + $(do_awk) $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@ + +$(PTHREAD_ARCH_OUT)/tcb-offsets.s: $(PTHREAD_ARCH_OUT)/tcb-offsets.c + $(compile.c) + +$(PTHREAD_ARCH_OUT)/tcb-offsets.h: $(PTHREAD_ARCH_OUT)/tcb-offsets.s + @sed -n "s/^.*@@@name@@@\([^@]*\)@@@value@@@[^0-9Xxa-fA-F-]*\([0-9Xxa-fA-F-][0-9Xxa-fA-F-]*\).*@@@end@@@.*$\/#define \1 \2/p" $< > $@ + +nptl_arch_headers: $(PTHREAD_ARCH_OUT)/tcb-offsets.h + +nptl_arch_headers_clean: + $(do_rm) $(addprefix $(PTHREAD_ARCH_OUT)/tcb-offsets., c s h) + +nptl_arch_clean: + $(do_rm) $(addprefix $(PTHREAD_ARCH_OUT)/*., o os oS) diff --git a/libpthread/nptl/sysdeps/i386/dl-tls.h b/libpthread/nptl/sysdeps/i386/dl-tls.h new file mode 100644 index 000000000..a1707197c --- /dev/null +++ b/libpthread/nptl/sysdeps/i386/dl-tls.h @@ -0,0 +1,60 @@ +/* Thread-local storage handling in the ELF dynamic linker. i386 version. + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + + +/* Type used for the representation of TLS information in the GOT. */ +typedef struct +{ + unsigned long int ti_module; + unsigned long int ti_offset; +} tls_index; + + +#ifdef SHARED +/* This is the prototype for the GNU version. */ +extern void *___tls_get_addr (tls_index *ti) + __attribute__ ((__regparm__ (1))); +extern void *___tls_get_addr_internal (tls_index *ti) + __attribute__ ((__regparm__ (1))) attribute_hidden; + +# ifdef IS_IN_rtld +/* The special thing about the x86 TLS ABI is that we have two + variants of the __tls_get_addr function with different calling + conventions. The GNU version, which we are mostly concerned here, + takes the parameter in a register. The name is changed by adding + an additional underscore at the beginning. The Sun version uses + the normal calling convention. */ +void * +__tls_get_addr (tls_index *ti) +{ + return ___tls_get_addr_internal (ti); +} + + +/* Prepare using the definition of __tls_get_addr in the generic + version of this file. */ +# define __tls_get_addr __attribute__ ((__regparm__ (1))) ___tls_get_addr +strong_alias (___tls_get_addr, ___tls_get_addr_internal) +#else + +/* Users should get the better interface. */ +# define __tls_get_addr ___tls_get_addr + +# endif +#endif diff --git a/libpthread/nptl/sysdeps/i386/i486/pthread_spin_trylock.S b/libpthread/nptl/sysdeps/i386/i486/pthread_spin_trylock.S new file mode 100644 index 000000000..e30072c3d --- /dev/null +++ b/libpthread/nptl/sysdeps/i386/i486/pthread_spin_trylock.S @@ -0,0 +1,47 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread-errnos.h> + + +#ifdef UP +# define LOCK +#else +# define LOCK lock +#endif + + .globl pthread_spin_trylock + .type pthread_spin_trylock,@function + .align 16 +pthread_spin_trylock: + movl 4(%esp), %edx + movl $1, %eax + xorl %ecx, %ecx + LOCK + cmpxchgl %ecx, (%edx) + movl $EBUSY, %eax +#ifdef HAVE_CMOV + cmovel %ecx, %eax +#else + jne 0f + movl %ecx, %eax +0: +#endif + ret + .size pthread_spin_trylock,.-pthread_spin_trylock diff --git a/libpthread/nptl/sysdeps/i386/i586/pthread_spin_trylock.S b/libpthread/nptl/sysdeps/i386/i586/pthread_spin_trylock.S new file mode 100644 index 000000000..ffe3d456b --- /dev/null +++ b/libpthread/nptl/sysdeps/i386/i586/pthread_spin_trylock.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/pthread_spin_trylock.S" diff --git a/libpthread/nptl/sysdeps/i386/i686/Makefile b/libpthread/nptl/sysdeps/i386/i686/Makefile new file mode 100644 index 000000000..137c0a2f0 --- /dev/null +++ b/libpthread/nptl/sysdeps/i386/i686/Makefile @@ -0,0 +1,32 @@ +# Copyright (C) 2003 Free Software Foundation, Inc. +# This file is part of the GNU C Library. +# Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +# The GNU C Library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. + +# The GNU C Library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. + +# You should have received a copy of the GNU Lesser General Public +# License along with the GNU C Library; if not, write to the Free +# Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +# 02111-1307 USA. + +ifeq ($(subdir),nptl) +# It turns out that stack coloring is in general not good on P4s. Some +# applications will benefit. We will probably have a configuration option +# at some point. Enabling coloring can be done with +# +# -DCOLORING_INCREMENT=128 +# +# What is useful is to avoid the 64k aliasing problem which reliably +# happens if all stacks use sizes which are a multiple of 64k. Tell +# the stack allocator to disturb this by allocation one more page if +# necessary. +CFLAGS-pthread_create.c += -DMULTI_PAGE_ALIASING=65536 +endif diff --git a/libpthread/nptl/sysdeps/i386/i686/pthread_spin_trylock.S b/libpthread/nptl/sysdeps/i386/i686/pthread_spin_trylock.S new file mode 100644 index 000000000..a5d861f92 --- /dev/null +++ b/libpthread/nptl/sysdeps/i386/i686/pthread_spin_trylock.S @@ -0,0 +1,21 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#define HAVE_CMOV 1 +#include "../i486/pthread_spin_trylock.S" diff --git a/libpthread/nptl/sysdeps/i386/i686/tls.h b/libpthread/nptl/sysdeps/i386/i686/tls.h new file mode 100644 index 000000000..4025ed8d2 --- /dev/null +++ b/libpthread/nptl/sysdeps/i386/i686/tls.h @@ -0,0 +1,36 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _TLS_H + +/* Additional definitions for <tls.h> on i686 and up. */ + + +/* Macros to load from and store into segment registers. We can use + the 32-bit instructions. */ +#define TLS_GET_GS() \ + ({ int __seg; __asm ("movl %%gs, %0" : "=q" (__seg)); __seg; }) +#define TLS_SET_GS(val) \ + __asm ("movl %0, %%gs" :: "q" (val)) + + +/* Get the full set of definitions. */ +#include "../tls.h" + +#endif /* tls.h */ diff --git a/libpthread/nptl/sysdeps/i386/jmpbuf-unwind.h b/libpthread/nptl/sysdeps/i386/jmpbuf-unwind.h new file mode 100644 index 000000000..b9528f363 --- /dev/null +++ b/libpthread/nptl/sysdeps/i386/jmpbuf-unwind.h @@ -0,0 +1,32 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <setjmp.h> +#include <stdint.h> +#include <unwind.h> + +#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \ + _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj) + +#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \ + ((uintptr_t) (_address) - (_adj) < (uintptr_t) (_jmpbuf)[JB_SP] - (_adj)) + +/* We use the normal lobngjmp for unwinding. */ +extern __typeof(longjmp) __libc_longjmp attribute_noreturn; +#define __libc_unwind_longjmp(buf, val) __libc_longjmp (buf, val) diff --git a/libpthread/nptl/sysdeps/i386/pthread_spin_init.c b/libpthread/nptl/sysdeps/i386/pthread_spin_init.c new file mode 100644 index 000000000..0a47981aa --- /dev/null +++ b/libpthread/nptl/sysdeps/i386/pthread_spin_init.c @@ -0,0 +1,20 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* Not needed. pthread_spin_init is an alias for pthread_spin_unlock. */ diff --git a/libpthread/nptl/sysdeps/i386/pthread_spin_lock.c b/libpthread/nptl/sysdeps/i386/pthread_spin_lock.c new file mode 100644 index 000000000..a6b1cf403 --- /dev/null +++ b/libpthread/nptl/sysdeps/i386/pthread_spin_lock.c @@ -0,0 +1,48 @@ +/* Copyright (C) 2002,2003,2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" + +#ifndef LOCK_PREFIX +# ifdef UP +# define LOCK_PREFIX /* nothing */ +# else +# define LOCK_PREFIX "lock;" +# endif +#endif + + +int +pthread_spin_lock (pthread_spinlock_t *lock) +{ + __asm__ ("\n" + "1:\t" LOCK_PREFIX "decl %0\n\t" + "jne 2f\n\t" + ".subsection 1\n\t" + ".align 16\n" + "2:\trep; nop\n\t" + "cmpl $0, %0\n\t" + "jg 1b\n\t" + "jmp 2b\n\t" + ".previous" + : "=m" (*lock) + : "m" (*lock)); + + return 0; +} diff --git a/libpthread/nptl/sysdeps/i386/pthread_spin_unlock.S b/libpthread/nptl/sysdeps/i386/pthread_spin_unlock.S new file mode 100644 index 000000000..d94f1e7b8 --- /dev/null +++ b/libpthread/nptl/sysdeps/i386/pthread_spin_unlock.S @@ -0,0 +1,32 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + + .globl pthread_spin_unlock + .type pthread_spin_unlock,@function + .align 16 +pthread_spin_unlock: + movl 4(%esp), %eax + movl $1, (%eax) + xorl %eax, %eax + ret + .size pthread_spin_unlock,.-pthread_spin_unlock + + /* The implementation of pthread_spin_init is identical. */ + .globl pthread_spin_init +pthread_spin_init = pthread_spin_unlock diff --git a/libpthread/nptl/sysdeps/i386/pthreaddef.h b/libpthread/nptl/sysdeps/i386/pthreaddef.h new file mode 100644 index 000000000..81456a4fc --- /dev/null +++ b/libpthread/nptl/sysdeps/i386/pthreaddef.h @@ -0,0 +1,48 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* Default stack size. */ +#define ARCH_STACK_DEFAULT_SIZE (2 * 1024 * 1024) + +/* Required stack pointer alignment at beginning. SSE requires 16 + bytes. */ +#define STACK_ALIGN 16 + +/* Minimal stack size after allocating thread descriptor and guard size. */ +#define MINIMAL_REST_STACK 2048 + +/* Alignment requirement for TCB. */ +#define TCB_ALIGNMENT 16 + + +/* Location of current stack frame. */ +#define CURRENT_STACK_FRAME __builtin_frame_address (0) + + +/* XXX Until we have a better place keep the definitions here. */ + +/* While there is no such syscall. */ +#define __exit_thread_inline(val) \ + while (1) { \ + if (__builtin_constant_p (val) && (val) == 0) \ + __asm__ volatile ("xorl %%ebx, %%ebx; int $0x80" :: "a" (__NR_exit)); \ + else \ + __asm__ volatile ("movl %1, %%ebx; int $0x80" \ + :: "a" (__NR_exit), "r" (val)); \ + } diff --git a/libpthread/nptl/sysdeps/i386/sysdep.h b/libpthread/nptl/sysdeps/i386/sysdep.h new file mode 100644 index 000000000..e49d65759 --- /dev/null +++ b/libpthread/nptl/sysdeps/i386/sysdep.h @@ -0,0 +1,157 @@ +/* Assembler macros for i386. + Copyright (C) 1991-93,95,96,98,2002,2003,2005,2006 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdeps/generic/sysdep.h> + +#ifdef __ASSEMBLER__ + +/* Syntactic details of assembler. */ + +/* ELF uses byte-counts for .align, most others use log2 of count of bytes. */ +#define ALIGNARG(log2) 1<<log2 +/* For ELF we need the `.type' directive to make shared libs work right. */ +#define ASM_TYPE_DIRECTIVE(name,typearg) .type name,typearg; +#define ASM_SIZE_DIRECTIVE(name) .size name,.-name; + +/* In ELF C symbols are asm symbols. */ +#undef NO_UNDERSCORES +#define NO_UNDERSCORES + +/* Define an entry point visible from C. + + There is currently a bug in gdb which prevents us from specifying + incomplete stabs information. Fake some entries here which specify + the current source file. */ +#define ENTRY(name) \ + STABS_CURRENT_FILE1("") \ + STABS_CURRENT_FILE(name) \ + ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(name); \ + ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name),@function) \ + .align ALIGNARG(4); \ + STABS_FUN(name) \ + C_LABEL(name) \ + cfi_startproc; \ + CALL_MCOUNT + +#undef END +#define END(name) \ + cfi_endproc; \ + ASM_SIZE_DIRECTIVE(name) \ + STABS_FUN_END(name) + +#ifdef HAVE_CPP_ASM_DEBUGINFO +/* Disable that goop, because we just pass -g through to the assembler + and it generates proper line number information directly. */ +# define STABS_CURRENT_FILE1(name) +# define STABS_CURRENT_FILE(name) +# define STABS_FUN(name) +# define STABS_FUN_END(name) +#else +/* Remove the following two lines once the gdb bug is fixed. */ +#define STABS_CURRENT_FILE(name) \ + STABS_CURRENT_FILE1 (#name) +#define STABS_CURRENT_FILE1(name) \ + 1: .stabs name,100,0,0,1b; +/* Emit stabs definition lines. We use F(0,1) and define t(0,1) as `int', + the same way gcc does it. */ +#define STABS_FUN(name) STABS_FUN2(name, name##:F(0,1)) +#define STABS_FUN2(name, namestr) \ + .stabs "int:t(0,1)=r(0,1);-2147483648;2147483647;",128,0,0,0; \ + .stabs #namestr,36,0,0,name; +#define STABS_FUN_END(name) \ + 1: .stabs "",36,0,0,1b-name; +#endif + +/* If compiled for profiling, call `mcount' at the start of each function. */ +#ifdef PROF +/* The mcount code relies on a normal frame pointer being on the stack + to locate our caller, so push one just for its benefit. */ +#define CALL_MCOUNT \ + pushl %ebp; cfi_adjust_cfa_offset (4); movl %esp, %ebp; \ + cfi_def_cfa_register (ebp); call JUMPTARGET(mcount); \ + popl %ebp; cfi_def_cfa (esp, 4); +#else +#define CALL_MCOUNT /* Do nothing. */ +#endif + +#ifdef NO_UNDERSCORES +/* Since C identifiers are not normally prefixed with an underscore + on this system, the asm identifier `syscall_error' intrudes on the + C name space. Make sure we use an innocuous name. */ +#define syscall_error __syscall_error +#define mcount _mcount +#endif + +#define PSEUDO(name, syscall_name, args) \ + .globl syscall_error; \ +lose: SYSCALL_PIC_SETUP \ + jmp JUMPTARGET(syscall_error); \ + ENTRY (name) \ + DO_CALL (syscall_name, args); \ + jb lose + +#undef PSEUDO_END +#define PSEUDO_END(name) \ + END (name) + +#undef JUMPTARGET +#ifdef __PIC__ +#define JUMPTARGET(name) name##@PLT +#define SYSCALL_PIC_SETUP \ + pushl %ebx; \ + cfi_adjust_cfa_offset (4); \ + call 0f; \ +0: popl %ebx; \ + cfi_adjust_cfa_offset (-4); \ + addl $_GLOBAL_OFFSET_TABLE+[.-0b], %ebx; + + +# define SETUP_PIC_REG(reg) \ + .ifndef __x86.get_pc_thunk.reg; \ + .section .gnu.linkonce.t.__x86.get_pc_thunk.reg,"ax",@progbits; \ + .globl __x86.get_pc_thunk.reg; \ + .hidden __x86.get_pc_thunk.reg; \ + .type __x86.get_pc_thunk.reg,@function; \ +__x86.get_pc_thunk.reg: \ + movl (%esp), %e##reg; \ + ret; \ + .size __x86.get_pc_thunk.reg, . - __x86.get_pc_thunk.reg; \ + .previous; \ + .endif; \ + call __x86.get_pc_thunk.reg + +# define LOAD_PIC_REG(reg) \ + SETUP_PIC_REG(reg); addl $_GLOBAL_OFFSET_TABLE_, %e##reg + +#else +#define JUMPTARGET(name) name +#define SYSCALL_PIC_SETUP /* Nothing. */ +#endif + +/* Local label name for asm code. */ +#ifndef L +#ifdef HAVE_ELF +#define L(name) .L##name +#else +#define L(name) name +#endif +#endif + +#endif /* __ASSEMBLER__ */ diff --git a/libpthread/nptl/sysdeps/i386/tcb-offsets.sym b/libpthread/nptl/sysdeps/i386/tcb-offsets.sym new file mode 100644 index 000000000..4e0444ba3 --- /dev/null +++ b/libpthread/nptl/sysdeps/i386/tcb-offsets.sym @@ -0,0 +1,13 @@ +#include <sysdep.h> +#include <tls.h> + +RESULT offsetof (struct pthread, result) +TID offsetof (struct pthread, tid) +PID offsetof (struct pthread, pid) +CANCELHANDLING offsetof (struct pthread, cancelhandling) +CLEANUP_JMP_BUF offsetof (struct pthread, cleanup_jmp_buf) +MULTIPLE_THREADS_OFFSET offsetof (tcbhead_t, multiple_threads) +SYSINFO_OFFSET offsetof (tcbhead_t, sysinfo) +CLEANUP offsetof (struct pthread, cleanup) +CLEANUP_PREV offsetof (struct _pthread_cleanup_buffer, __prev) +MUTEX_FUTEX offsetof (pthread_mutex_t, __data.__lock) diff --git a/libpthread/nptl/sysdeps/i386/tls.h b/libpthread/nptl/sysdeps/i386/tls.h new file mode 100644 index 000000000..52bde9eec --- /dev/null +++ b/libpthread/nptl/sysdeps/i386/tls.h @@ -0,0 +1,429 @@ +/* Definition for thread-local data handling. nptl/i386 version. + Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _TLS_H +#define _TLS_H 1 + +#ifndef __ASSEMBLER__ +# include <stdbool.h> +# include <stddef.h> +# include <stdint.h> +# include <stdlib.h> +# include <list.h> + + +/* Type for the dtv. */ +typedef union dtv +{ + size_t counter; + struct + { + void *val; + bool is_static; + } pointer; +} dtv_t; + + +typedef struct +{ + void *tcb; /* Pointer to the TCB. Not necessarily the + thread descriptor used by libpthread. */ + dtv_t *dtv; + void *self; /* Pointer to the thread descriptor. */ + int multiple_threads; + uintptr_t sysinfo; + uintptr_t stack_guard; +} tcbhead_t; + +# define TLS_MULTIPLE_THREADS_IN_TCB 1 + +#else /* __ASSEMBLER__ */ +# include <tcb-offsets.h> +#endif + + +/* We require TLS support in the tools. */ +#define HAVE_TLS_SUPPORT +#define HAVE___THREAD 1 +#define HAVE_TLS_MODEL_ATTRIBUTE 1 + +/* Signal that TLS support is available. */ +#define USE_TLS 1 + +/* Alignment requirement for the stack. For IA-32 this is governed by + the SSE memory functions. */ +#define STACK_ALIGN 16 + +#ifndef __ASSEMBLER__ +/* Get system call information. */ +# include <sysdep.h> + +/* The old way: using LDT. */ + +/* Structure passed to `modify_ldt', 'set_thread_area', and 'clone' calls. */ +struct user_desc +{ + unsigned int entry_number; + unsigned long int base_addr; + unsigned int limit; + unsigned int seg_32bit:1; + unsigned int contents:2; + unsigned int read_exec_only:1; + unsigned int limit_in_pages:1; + unsigned int seg_not_present:1; + unsigned int useable:1; + unsigned int empty:25; +}; + +/* Initializing bit fields is slow. We speed it up by using a union. */ +union user_desc_init +{ + struct user_desc desc; + unsigned int vals[4]; +}; + + +/* 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) + +/* Get the thread descriptor definition. */ +#include <descr.h> + +/* The TCB can have any size and the memory following the address the + thread pointer points to is unspecified. Allocate the TCB there. */ +# define TLS_TCB_AT_TP 1 + + +/* Install the dtv pointer. The pointer passed is to the element with + index -1 which contain the length. */ +# define INSTALL_DTV(descr, dtvp) \ + ((tcbhead_t *) (descr))->dtv = (dtvp) + 1 + +/* Install new dtv for current thread. */ +# define INSTALL_NEW_DTV(dtvp) \ + ({ struct pthread *__pd; \ + THREAD_SETMEM (__pd, header.dtv, (dtvp)); }) + +/* Return dtv of given thread descriptor. */ +# define GET_DTV(descr) \ + (((tcbhead_t *) (descr))->dtv) + +#define THREAD_SELF_SYSINFO THREAD_GETMEM (THREAD_SELF, header.sysinfo) +#define THREAD_SYSINFO(pd) ((pd)->header.sysinfo) + +/* Macros to load from and store into segment registers. */ +# ifndef TLS_GET_GS +# define TLS_GET_GS() \ + ({ int __seg; __asm__ ("movw %%gs, %w0" : "=q" (__seg)); __seg & 0xffff; }) +# endif +# ifndef TLS_SET_GS +# define TLS_SET_GS(val) \ + __asm__ ("movw %w0, %%gs" :: "q" (val)) +# endif + + +# ifndef __NR_set_thread_area +# define __NR_set_thread_area 243 +# endif +# ifndef TLS_FLAG_WRITABLE +# define TLS_FLAG_WRITABLE 0x00000001 +# endif + +// XXX Enable for the real world. +#if 0 +# ifndef __ASSUME_SET_THREAD_AREA +# error "we need set_thread_area" +# endif +#endif + +# ifdef __PIC__ +# define TLS_EBX_ARG "r" +# define TLS_LOAD_EBX "xchgl %3, %%ebx\n\t" +# else +# define TLS_EBX_ARG "b" +# define TLS_LOAD_EBX +# endif + +#if defined NEED_DL_SYSINFO +# define INIT_SYSINFO \ + _head->sysinfo = GLRO(dl_sysinfo) +#else +# define INIT_SYSINFO +#endif + +#ifndef LOCK_PREFIX +# ifdef UP +# define LOCK_PREFIX /* nothing */ +# else +# define LOCK_PREFIX "lock;" +# endif +#endif + +/* Code to initially initialize the thread pointer. This might need + special attention since 'errno' is not yet available and if the + operation can cause a failure 'errno' must not be touched. */ +# define TLS_INIT_TP(thrdescr, secondcall) \ + ({ void *_thrdescr = (thrdescr); \ + tcbhead_t *_head = _thrdescr; \ + union user_desc_init _segdescr; \ + int _result; \ + \ + _head->tcb = _thrdescr; \ + /* For now the thread descriptor is at the same address. */ \ + _head->self = _thrdescr; \ + /* New syscall handling support. */ \ + INIT_SYSINFO; \ + \ + /* The 'entry_number' field. Let the kernel pick a value. */ \ + if (secondcall) \ + _segdescr.vals[0] = TLS_GET_GS () >> 3; \ + else \ + _segdescr.vals[0] = -1; \ + /* The 'base_addr' field. Pointer to the TCB. */ \ + _segdescr.vals[1] = (unsigned long int) _thrdescr; \ + /* The 'limit' field. We use 4GB which is 0xfffff pages. */ \ + _segdescr.vals[2] = 0xfffff; \ + /* Collapsed value of the bitfield: \ + .seg_32bit = 1 \ + .contents = 0 \ + .read_exec_only = 0 \ + .limit_in_pages = 1 \ + .seg_not_present = 0 \ + .useable = 1 */ \ + _segdescr.vals[3] = 0x51; \ + \ + /* Install the TLS. */ \ + __asm__ volatile (TLS_LOAD_EBX \ + "int $0x80\n\t" \ + TLS_LOAD_EBX \ + : "=a" (_result), "=m" (_segdescr.desc.entry_number) \ + : "0" (__NR_set_thread_area), \ + TLS_EBX_ARG (&_segdescr.desc), "m" (_segdescr.desc)); \ + \ + if (_result == 0) \ + /* We know the index in the GDT, now load the segment register. \ + The use of the GDT is described by the value 3 in the lower \ + three bits of the segment descriptor value. \ + \ + Note that we have to do this even if the numeric value of \ + the descriptor does not change. Loading the segment register \ + causes the segment information from the GDT to be loaded \ + which is necessary since we have changed it. */ \ + TLS_SET_GS (_segdescr.desc.entry_number * 8 + 3); \ + \ + _result == 0 ? NULL \ + : "set_thread_area failed when setting up thread-local storage\n"; }) + + +/* Return the address of the dtv for the current thread. */ +# define THREAD_DTV() \ + ({ struct pthread *__pd; \ + THREAD_GETMEM (__pd, header.dtv); }) + + +/* Return the thread descriptor for the current thread. + + The contained asm must *not* be marked volatile since otherwise + assignments like + pthread_descr self = thread_self(); + do not get optimized away. */ +# define THREAD_SELF \ + ({ struct pthread *__self; \ + __asm__ ("movl %%gs:%c1,%0" : "=r" (__self) \ + : "i" (offsetof (struct pthread, header.self))); \ + __self;}) + +/* Magic for libthread_db to know how to do THREAD_SELF. */ +# define DB_THREAD_SELF \ + REGISTER_THREAD_AREA (32, offsetof (struct user_regs_struct, xgs), 3) \ + REGISTER_THREAD_AREA (64, 26 * 8, 3) /* x86-64's user_regs_struct->gs */ + + +/* Read member of the thread descriptor directly. */ +# define THREAD_GETMEM(descr, member) \ + ({ __typeof (descr->member) __value; \ + if (sizeof (__value) == 1) \ + __asm__ volatile ("movb %%gs:%P2,%b0" \ + : "=q" (__value) \ + : "0" (0), "i" (offsetof (struct pthread, member))); \ + else if (sizeof (__value) == 4) \ + __asm__ volatile ("movl %%gs:%P1,%0" \ + : "=r" (__value) \ + : "i" (offsetof (struct pthread, member))); \ + else \ + { \ + if (sizeof (__value) != 8) \ + /* There should not be any value with a size other than 1, \ + 4 or 8. */ \ + abort (); \ + \ + __asm__ volatile ("movl %%gs:%P1,%%eax\n\t" \ + "movl %%gs:%P2,%%edx" \ + : "=A" (__value) \ + : "i" (offsetof (struct pthread, member)), \ + "i" (offsetof (struct pthread, member) + 4)); \ + } \ + __value; }) + + +/* Same as THREAD_GETMEM, but the member offset can be non-constant. */ +# define THREAD_GETMEM_NC(descr, member, idx) \ + ({ __typeof (descr->member[0]) __value; \ + if (sizeof (__value) == 1) \ + __asm__ volatile ("movb %%gs:%P2(%3),%b0" \ + : "=q" (__value) \ + : "0" (0), "i" (offsetof (struct pthread, member[0])), \ + "r" (idx)); \ + else if (sizeof (__value) == 4) \ + __asm__ volatile ("movl %%gs:%P1(,%2,4),%0" \ + : "=r" (__value) \ + : "i" (offsetof (struct pthread, member[0])), \ + "r" (idx)); \ + else \ + { \ + if (sizeof (__value) != 8) \ + /* There should not be any value with a size other than 1, \ + 4 or 8. */ \ + abort (); \ + \ + __asm__ volatile ("movl %%gs:%P1(,%2,8),%%eax\n\t" \ + "movl %%gs:4+%P1(,%2,8),%%edx" \ + : "=&A" (__value) \ + : "i" (offsetof (struct pthread, member[0])), \ + "r" (idx)); \ + } \ + __value; }) + + +/* Same as THREAD_SETMEM, but the member offset can be non-constant. */ +# define THREAD_SETMEM(descr, member, value) \ + ({ if (sizeof (descr->member) == 1) \ + __asm__ volatile ("movb %b0,%%gs:%P1" : \ + : "iq" (value), \ + "i" (offsetof (struct pthread, member))); \ + else if (sizeof (descr->member) == 4) \ + __asm__ volatile ("movl %0,%%gs:%P1" : \ + : "ir" (value), \ + "i" (offsetof (struct pthread, member))); \ + else \ + { \ + if (sizeof (descr->member) != 8) \ + /* There should not be any value with a size other than 1, \ + 4 or 8. */ \ + abort (); \ + \ + __asm__ volatile ("movl %%eax,%%gs:%P1\n\t" \ + "movl %%edx,%%gs:%P2" : \ + : "A" (value), \ + "i" (offsetof (struct pthread, member)), \ + "i" (offsetof (struct pthread, member) + 4)); \ + }}) + + +/* Set member of the thread descriptor directly. */ +# define THREAD_SETMEM_NC(descr, member, idx, value) \ + ({ if (sizeof (descr->member[0]) == 1) \ + __asm__ volatile ("movb %b0,%%gs:%P1(%2)" : \ + : "iq" (value), \ + "i" (offsetof (struct pthread, member)), \ + "r" (idx)); \ + else if (sizeof (descr->member[0]) == 4) \ + __asm__ volatile ("movl %0,%%gs:%P1(,%2,4)" : \ + : "ir" (value), \ + "i" (offsetof (struct pthread, member)), \ + "r" (idx)); \ + else \ + { \ + if (sizeof (descr->member[0]) != 8) \ + /* There should not be any value with a size other than 1, \ + 4 or 8. */ \ + abort (); \ + \ + __asm__ volatile ("movl %%eax,%%gs:%P1(,%2,8)\n\t" \ + "movl %%edx,%%gs:4+%P1(,%2,8)" : \ + : "A" (value), \ + "i" (offsetof (struct pthread, member)), \ + "r" (idx)); \ + }}) + + +/* Atomic compare and exchange on TLS, returning old value. */ +#define THREAD_ATOMIC_CMPXCHG_VAL(descr, member, newval, oldval) \ + ({ __typeof (descr->member) __ret; \ + __typeof (oldval) __old = (oldval); \ + if (sizeof (descr->member) == 4) \ + __asm__ volatile (LOCK_PREFIX "cmpxchgl %2, %%gs:%P3" \ + : "=a" (__ret) \ + : "0" (__old), "r" (newval), \ + "i" (offsetof (struct pthread, member))); \ + else \ + /* Not necessary for other sizes in the moment. */ \ + abort (); \ + __ret; }) + + +/* Atomic 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)) + + +#endif /* __ASSEMBLER__ */ + +#endif /* tls.h */ diff --git a/libpthread/nptl/sysdeps/mips/Makefile b/libpthread/nptl/sysdeps/mips/Makefile new file mode 100644 index 000000000..6371d2871 --- /dev/null +++ b/libpthread/nptl/sysdeps/mips/Makefile @@ -0,0 +1,13 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2005 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +top_srcdir=../../../../ +top_builddir=../../../../ +all: objs +include $(top_builddir)Rules.mak +include Makefile.arch +include $(top_srcdir)Makerules diff --git a/libpthread/nptl/sysdeps/mips/Makefile.arch b/libpthread/nptl/sysdeps/mips/Makefile.arch new file mode 100644 index 000000000..5d77b0074 --- /dev/null +++ b/libpthread/nptl/sysdeps/mips/Makefile.arch @@ -0,0 +1,65 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2005 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +libpthread_SSRC = pthread_spin_lock.S pthread_spin_trylock.S \ + nptl-sysdep.S + +libc_a_CSRC = libc-tls.c + +CFLAGS-pt-raise.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 + +ASFLAGS-pthread_spin_lock.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +ASFLAGS-pthread_spin_trylock.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +ASFLAGS-nptl-sysdep.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 \ + -I$(top_srcdir)libc/sysdeps/linux/mips + +CFLAGS-mips = $(SSP_ALL_CFLAGS) +#CFLAGS:=$(CFLAGS:-O1=-O2) + +PTHREAD_ARCH_DIR := $(top_srcdir)libpthread/nptl/sysdeps/mips +PTHREAD_ARCH_OUT := $(top_builddir)libpthread/nptl/sysdeps/mips +PTHREAD_ARCH_OBJ := $(patsubst %.S,$(PTHREAD_ARCH_OUT)/%.o,$(libpthread_SSRC)) + +ifeq ($(DOPIC),y) +libpthread-a-y += $(PTHREAD_ARCH_OBJ:.o=.os) +else +libpthread-a-y += $(PTHREAD_ARCH_OBJ) +endif +libpthread-so-y += $(PTHREAD_ARCH_OBJ:.o=.oS) + +libpthread-nomulti-y += $(PTHREAD_ARCH_OBJ) + +LIBC_ARCH_OBJ := $(patsubst %.c,$(PTHREAD_ARCH_OUT)/%.o,$(libc_a_CSRC)) + +libc-static-y += $(LIBC_ARCH_OBJ) + +libc-nomulti-y += $(LIBC_ARCH_OBJ) + +objclean-y += nptl_arch_objclean +headers_clean-y += nptl_arch_headers_clean + +# +# Create 'tcb-offsets.h' header file. +# +CFLAGS-tcb-offsets.c = -S + +$(PTHREAD_ARCH_OUT)/tcb-offsets.c: $(PTHREAD_ARCH_DIR)/tcb-offsets.sym + awk -f $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@ + +$(PTHREAD_ARCH_OUT)/tcb-offsets.s: $(PTHREAD_ARCH_OUT)/tcb-offsets.c + $(compile.c) + +nptl_arch_headers: $(PTHREAD_ARCH_OUT)/tcb-offsets.s + $(do_sed) -n "s/^.*@@@name@@@\([^@]*\)@@@value@@@[^0-9Xxa-fA-F-]*\([0-9Xxa-fA-F-][0-9Xxa-fA-F-]*\).*@@@end@@@.*$\/#define \1 \2/p" $< > $(PTHREAD_ARCH_OUT)/tcb-offsets.h + +nptl_arch_headers_clean: + $(RM) $(PTHREAD_ARCH_OUT)/tcb-offsets.c \ + $(PTHREAD_ARCH_OUT)/tcb-offsets.s \ + $(PTHREAD_ARCH_OUT)/tcb-offsets.h + +nptl_arch_objclean: + $(RM) $(PTHREAD_ARCH_OUT)/*.{o,os,oS} diff --git a/libpthread/nptl/sysdeps/mips/dl-tls.h b/libpthread/nptl/sysdeps/mips/dl-tls.h new file mode 100644 index 000000000..6d3ed6f5a --- /dev/null +++ b/libpthread/nptl/sysdeps/mips/dl-tls.h @@ -0,0 +1,46 @@ +/* Thread-local storage handling in the ELF dynamic linker. MIPS version. + Copyright (C) 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + + +/* Type used for the representation of TLS information in the GOT. */ +typedef struct +{ + unsigned long int ti_module; + unsigned long int ti_offset; +} tls_index; + +/* The thread pointer points 0x7000 past the first static TLS block. */ +#define TLS_TP_OFFSET 0x7000 + +/* Dynamic thread vector pointers point 0x8000 past the start of each + TLS block. */ +#define TLS_DTV_OFFSET 0x8000 + +/* Compute the value for a GOTTPREL reloc. */ +#define TLS_TPREL_VALUE(sym_map, sym) \ + ((sym_map)->l_tls_offset + (sym)->st_value - TLS_TP_OFFSET) + +/* Compute the value for a DTPREL reloc. */ +#define TLS_DTPREL_VALUE(sym) \ + ((sym)->st_value - TLS_DTV_OFFSET) + +extern void *__tls_get_addr (tls_index *ti); + +# define GET_ADDR_OFFSET (ti->ti_offset + TLS_DTV_OFFSET) +# define __TLS_GET_ADDR(__ti) (__tls_get_addr (__ti) - TLS_DTV_OFFSET) diff --git a/libpthread/nptl/sysdeps/mips/jmpbuf-unwind.h b/libpthread/nptl/sysdeps/mips/jmpbuf-unwind.h new file mode 100644 index 000000000..a9cfe43b3 --- /dev/null +++ b/libpthread/nptl/sysdeps/mips/jmpbuf-unwind.h @@ -0,0 +1,30 @@ +/* Copyright (C) 2003, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <setjmp.h> +#include <stdint.h> +#include <unwind.h> + +#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \ + _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj) + +#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \ + ((uintptr_t) (_address) - (_adj) < (uintptr_t) (_jmpbuf)[0].__sp - (_adj)) + +/* We use the normal longjmp for unwinding. */ +#define __libc_unwind_longjmp(buf, val) longjmp (buf, val) diff --git a/libpthread/nptl/sysdeps/mips/libc-tls.c b/libpthread/nptl/sysdeps/mips/libc-tls.c new file mode 100644 index 000000000..fdedc9f5a --- /dev/null +++ b/libpthread/nptl/sysdeps/mips/libc-tls.c @@ -0,0 +1,37 @@ +/* Thread-local storage handling in the ELF dynamic linker. MIPS version. + Copyright (C) 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <../generic/libc-tls.c> +#include <dl-tls.h> + +#if USE_TLS + +/* On MIPS, linker optimizations are not required, so __tls_get_addr + can be called even in statically linked binaries. In this case module + must be always 1 and PT_TLS segment exist in the binary, otherwise it + would not link. */ + +void * +__tls_get_addr (tls_index *ti) +{ + dtv_t *dtv = THREAD_DTV (); + return (char *) dtv[1].pointer.val + GET_ADDR_OFFSET; +} + +#endif diff --git a/libpthread/nptl/sysdeps/mips/nptl-sysdep.S b/libpthread/nptl/sysdeps/mips/nptl-sysdep.S new file mode 100644 index 000000000..7a4a8d311 --- /dev/null +++ b/libpthread/nptl/sysdeps/mips/nptl-sysdep.S @@ -0,0 +1,2 @@ +/* Pull in __syscall_error. */ +#include <syscall_error.S> diff --git a/libpthread/nptl/sysdeps/mips/pthread_spin_lock.S b/libpthread/nptl/sysdeps/mips/pthread_spin_lock.S new file mode 100644 index 000000000..e35c381ed --- /dev/null +++ b/libpthread/nptl/sysdeps/mips/pthread_spin_lock.S @@ -0,0 +1,38 @@ +/* Copyright (C) 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sys/asm.h> +#include <sysdep.h> +#include <sgidefs.h> + +ENTRY (pthread_spin_lock) + .set push +#if _MIPS_SIM == _ABIO32 + .set mips2 +#endif +1: ll a2, 0(a0) + li a1, 1 + bnez a2, 1b + sc a1, 0(a0) + beqz a1, 1b + MIPS_SYNC + .set pop + li v0, 0 + j ra + nop +END (pthread_spin_lock) diff --git a/libpthread/nptl/sysdeps/mips/pthread_spin_trylock.S b/libpthread/nptl/sysdeps/mips/pthread_spin_trylock.S new file mode 100644 index 000000000..b54732869 --- /dev/null +++ b/libpthread/nptl/sysdeps/mips/pthread_spin_trylock.S @@ -0,0 +1,43 @@ +/* Copyright (C) 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sys/asm.h> +#include <sysdep.h> +#define _ERRNO_H 1 +#include <bits/errno.h> +#include <sgidefs.h> + +ENTRY (pthread_spin_trylock) + .set push +#if _MIPS_SIM == _ABIO32 + .set mips2 +#endif + ll a2, 0(a0) + li a1, 1 + bnez a2, 1f + sc a1, 0(a0) + beqz a1, 1f + MIPS_SYNC + .set pop + li v0, 0 + j ra + nop +1: li v0, EBUSY + j ra + nop +END (pthread_spin_trylock) diff --git a/libpthread/nptl/sysdeps/mips/pthreaddef.h b/libpthread/nptl/sysdeps/mips/pthreaddef.h new file mode 100644 index 000000000..e72b4bc58 --- /dev/null +++ b/libpthread/nptl/sysdeps/mips/pthreaddef.h @@ -0,0 +1,39 @@ +/* Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* Default stack size. */ +#define ARCH_STACK_DEFAULT_SIZE (2 * 1024 * 1024) + +/* Required stack pointer alignment at beginning. */ +#define STACK_ALIGN 16 + +/* Minimal stack size after allocating thread descriptor and guard size. */ +#define MINIMAL_REST_STACK 2048 + +/* Alignment requirement for TCB. */ +#define TCB_ALIGNMENT 16 + + +/* Location of current stack frame. */ +#define CURRENT_STACK_FRAME __builtin_frame_address (0) + + +/* XXX Until we have a better place keep the definitions here. */ + +#define __exit_thread_inline(val) \ + INLINE_SYSCALL (exit, 1, (val)) diff --git a/libpthread/nptl/sysdeps/mips/regdef.h b/libpthread/nptl/sysdeps/mips/regdef.h new file mode 100644 index 000000000..a462d512a --- /dev/null +++ b/libpthread/nptl/sysdeps/mips/regdef.h @@ -0,0 +1,26 @@ +/* Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ralf Baechle <ralf@gnu.org>. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _REGDEF_H +#define _REGDEF_H + +#include <sys/regdef.h> +#include <sys/fpregdef.h> + +#endif /* _REGDEF_H */ diff --git a/libpthread/nptl/sysdeps/mips/sysdep.h b/libpthread/nptl/sysdeps/mips/sysdep.h new file mode 100644 index 000000000..69cecae70 --- /dev/null +++ b/libpthread/nptl/sysdeps/mips/sysdep.h @@ -0,0 +1,110 @@ +/* Copyright (C) 1992, 1995, 1997, 1999, 2000, 2002, 2003, 2004 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Brendan Kehoe (brendan@zen.org). + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sgidefs.h> +#include <sysdeps/generic/sysdep.h> + +#ifdef __ASSEMBLER__ + +#include <regdef.h> + +#define ENTRY(name) \ + .globl name; \ + .align 2; \ + .ent name,0; \ + name##: + +#undef END +#define END(function) \ + .end function; \ + .size function,.-function + +#define ret j ra ; nop + +#undef PSEUDO_END +#define PSEUDO_END(sym) .end sym; .size sym,.-sym + +#define PSEUDO_NOERRNO(name, syscall_name, args) \ + .align 2; \ + ENTRY(name) \ + .set noreorder; \ + li v0, SYS_ify(syscall_name); \ + syscall + +#undef PSEUDO_END_NOERRNO +#define PSEUDO_END_NOERRNO(sym) .end sym; .size sym,.-sym + +#define ret_NOERRNO ret + +#define PSEUDO_ERRVAL(name, syscall_name, args) \ + .align 2; \ + ENTRY(name) \ + .set noreorder; \ + li v0, SYS_ify(syscall_name); \ + syscall + +#undef PSEUDO_END_ERRVAL +#define PSEUDO_END_ERRVAL(sym) .end sym; .size sym,.-sym + +#define ret_ERRVAL ret + +#define r0 v0 +#define r1 v1 +/* The mips move insn is d,s. */ +#define MOVE(x,y) move y , x + +#if _MIPS_SIM == _ABIO32 +# define L(label) $L ## label +#else +# define L(label) .L ## label +#endif + +/* Note that while it's better structurally, going back to call __syscall_error + can make things confusing if you're debugging---it looks like it's jumping + backwards into the previous fn. */ +#ifdef __PIC__ +#define PSEUDO(name, syscall_name, args) \ + .align 2; \ + 99: la t9,__syscall_error; \ + jr t9; \ + ENTRY(name) \ + .set noreorder; \ + .cpload t9; \ + li v0, SYS_ify(syscall_name); \ + syscall; \ + .set reorder; \ + bne a3, zero, 99b; \ +L(syse1): +#else +#define PSEUDO(name, syscall_name, args) \ + .set noreorder; \ + .align 2; \ + 99: j __syscall_error; \ + nop; \ + ENTRY(name) \ + .set noreorder; \ + li v0, SYS_ify(syscall_name); \ + syscall; \ + .set reorder; \ + bne a3, zero, 99b; \ +L(syse1): +#endif + +#endif diff --git a/libpthread/nptl/sysdeps/mips/tcb-offsets.sym b/libpthread/nptl/sysdeps/mips/tcb-offsets.sym new file mode 100644 index 000000000..e0e71dc43 --- /dev/null +++ b/libpthread/nptl/sysdeps/mips/tcb-offsets.sym @@ -0,0 +1,11 @@ +#include <sysdep.h> +#include <tls.h> + +-- + +-- Abuse tls.h macros to derive offsets relative to the thread register. +#define thread_offsetof(mem) (long)(offsetof(struct pthread, mem) - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE) + +MULTIPLE_THREADS_OFFSET thread_offsetof (header.multiple_threads) +PID_OFFSET thread_offsetof (pid) +TID_OFFSET thread_offsetof (tid) diff --git a/libpthread/nptl/sysdeps/mips/tls.h b/libpthread/nptl/sysdeps/mips/tls.h new file mode 100644 index 000000000..0a83ac672 --- /dev/null +++ b/libpthread/nptl/sysdeps/mips/tls.h @@ -0,0 +1,159 @@ +/* Definition for thread-local data handling. NPTL/MIPS version. + Copyright (C) 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _TLS_H +#define _TLS_H 1 + +#ifndef __ASSEMBLER__ +# include <stdbool.h> +# include <stddef.h> +# include <stdint.h> + +/* Type for the dtv. */ +typedef union dtv +{ + size_t counter; + struct + { + void *val; + bool is_static; + } pointer; +} dtv_t; + +/* Note: rd must be $v1 to be ABI-conformant. */ +# define READ_THREAD_POINTER() \ + ({ void *__result; \ + __asm__ __volatile__ (".set\tpush\n\t.set\tmips32r2\n\t" \ + "rdhwr\t%0, $29\n\t.set\tpop" : "=v" (__result)); \ + __result; }) + +#else /* __ASSEMBLER__ */ +# include <tcb-offsets.h> + +# define READ_THREAD_POINTER(rd) \ + .set push; \ + .set mips32r2; \ + rdhwr rd, $29; \ + .set pop +#endif /* __ASSEMBLER__ */ + + +/* We require TLS support in the tools. */ +#define HAVE_TLS_SUPPORT 1 +#define HAVE_TLS_MODEL_ATTRIBUTE 1 +#define HAVE___THREAD 1 + +/* Signal that TLS support is available. */ +#define USE_TLS 1 + +#ifndef __ASSEMBLER__ + +/* Get system call information. */ +# include <sysdep.h> + +/* The TP points to the start of the thread blocks. */ +# define TLS_DTV_AT_TP 1 + +/* Get the thread descriptor definition. */ +#include <../../descr.h> + +typedef struct +{ + dtv_t *dtv; + void *private; +} tcbhead_t; + +/* This is the size of the initial TCB. Because our TCB is before the thread + pointer, we don't need this. */ +# define TLS_INIT_TCB_SIZE 0 + +/* Alignment requirements for the initial TCB. */ +# define TLS_INIT_TCB_ALIGN __alignof__ (struct pthread) + +/* This is the size of the TCB. Because our TCB is before the thread + pointer, we don't need this. */ +# define TLS_TCB_SIZE 0 + +/* Alignment requirements for the TCB. */ +# define TLS_TCB_ALIGN __alignof__ (struct pthread) + +/* This is the size we need before TCB - actually, it includes the TCB. */ +# define TLS_PRE_TCB_SIZE \ + (sizeof (struct pthread) \ + + ((sizeof (tcbhead_t) + TLS_TCB_ALIGN - 1) & ~(TLS_TCB_ALIGN - 1))) + +/* The thread pointer (in hardware register $29) points to the end of + the TCB + 0x7000, as for PowerPC. The pthread_descr structure is + immediately in front of the TCB. */ +# define TLS_TCB_OFFSET 0x7000 + +/* Install the dtv pointer. The pointer passed is to the element with + index -1 which contain the length. */ +# define INSTALL_DTV(tcbp, dtvp) \ + (((tcbhead_t *) (tcbp))[-1].dtv = (dtvp) + 1) + +/* Install new dtv for current thread. */ +# define INSTALL_NEW_DTV(dtv) \ + (THREAD_DTV() = (dtv)) + +/* Return dtv of given thread descriptor. */ +# define GET_DTV(tcbp) \ + (((tcbhead_t *) (tcbp))[-1].dtv) + +/* Code to initially initialize the thread pointer. This might need + special attention since 'errno' is not yet available and if the + operation can cause a failure 'errno' must not be touched. */ +# define TLS_INIT_TP(tcbp, secondcall) \ + ({ INTERNAL_SYSCALL_DECL (err); \ + long result_var; \ + result_var = INTERNAL_SYSCALL (set_thread_area, err, 1, \ + (char *) (tcbp) + TLS_TCB_OFFSET); \ + INTERNAL_SYSCALL_ERROR_P (result_var, err) \ + ? "unknown error" : NULL; }) + +/* Return the address of the dtv for the current thread. */ +# define THREAD_DTV() \ + (((tcbhead_t *) (READ_THREAD_POINTER () - TLS_TCB_OFFSET))[-1].dtv) + +/* Return the thread descriptor for the current thread. */ +# define THREAD_SELF \ + ((struct pthread *) (READ_THREAD_POINTER () \ + - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE)) + +/* Magic for libthread_db to know how to do THREAD_SELF. */ +# define DB_THREAD_SELF \ + CONST_THREAD_AREA (32, TLS_TCB_OFFSET + TLS_PRE_TCB_SIZE) + +/* Access to data in the thread descriptor is easy. */ +# define THREAD_GETMEM(descr, member) \ + descr->member +# define THREAD_GETMEM_NC(descr, member, idx) \ + descr->member[idx] +# define THREAD_SETMEM(descr, member, value) \ + descr->member = (value) +# define THREAD_SETMEM_NC(descr, member, idx, value) \ + descr->member[idx] = (value) + +/* l_tls_offset == 0 is perfectly valid on MIPS, so we have to use some + different value to mean unset l_tls_offset. */ +# define NO_TLS_OFFSET -1 + +#endif /* __ASSEMBLER__ */ + +#endif /* tls.h */ diff --git a/libpthread/nptl/sysdeps/powerpc/Makefile b/libpthread/nptl/sysdeps/powerpc/Makefile new file mode 100644 index 000000000..3af245600 --- /dev/null +++ b/libpthread/nptl/sysdeps/powerpc/Makefile @@ -0,0 +1,21 @@ +# Copyright (C) 2003 Free Software Foundation, Inc. +# This file is part of the GNU C Library. + +# The GNU C Library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. + +# The GNU C Library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. + +# You should have received a copy of the GNU Lesser General Public +# License along with the GNU C Library; if not, write to the Free +# Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +# 02111-1307 USA. + +ifeq ($(subdir),csu) +gen-as-const-headers += tcb-offsets.sym +endif diff --git a/libpthread/nptl/sysdeps/powerpc/dl-tls.h b/libpthread/nptl/sysdeps/powerpc/dl-tls.h new file mode 100644 index 000000000..957d4b4b9 --- /dev/null +++ b/libpthread/nptl/sysdeps/powerpc/dl-tls.h @@ -0,0 +1,49 @@ +/* Thread-local storage handling in the ELF dynamic linker. PowerPC version. + Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + + +/* Type used for the representation of TLS information in the TOC. */ +typedef struct +{ + unsigned long int ti_module; + unsigned long int ti_offset; +} tls_index; + +/* The thread pointer points 0x7000 past the first static TLS block. */ +#define TLS_TP_OFFSET 0x7000 + +/* Dynamic thread vector pointers point 0x8000 past the start of each + TLS block. */ +#define TLS_DTV_OFFSET 0x8000 + +/* Compute the value for a @tprel reloc. */ +#define TLS_TPREL_VALUE(sym_map, sym, reloc) \ + ((sym_map)->l_tls_offset + (sym)->st_value + (reloc)->r_addend \ + - TLS_TP_OFFSET) + +/* Compute the value for a @dtprel reloc. */ +#define TLS_DTPREL_VALUE(sym, reloc) \ + ((sym)->st_value + (reloc)->r_addend - TLS_DTV_OFFSET) + +#ifdef SHARED +extern void *__tls_get_addr (tls_index *ti); + +# define GET_ADDR_OFFSET (ti->ti_offset + TLS_DTV_OFFSET) +# define __TLS_GET_ADDR(__ti) (__tls_get_addr (__ti) - TLS_DTV_OFFSET) +#endif diff --git a/libpthread/nptl/sysdeps/powerpc/jmpbuf-unwind.h b/libpthread/nptl/sysdeps/powerpc/jmpbuf-unwind.h new file mode 100644 index 000000000..0b817160d --- /dev/null +++ b/libpthread/nptl/sysdeps/powerpc/jmpbuf-unwind.h @@ -0,0 +1,31 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <setjmp.h> +#include <stdint.h> +#include <unwind.h> + +#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \ + _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj) + +#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \ + ((uintptr_t) (_address) - (_adj) < (uintptr_t) (_jmpbuf)[JB_GPR1] - (_adj)) + +/* We use the normal lobngjmp for unwinding. */ +#define __libc_unwind_longjmp(buf, val) __libc_longjmp (buf, val) diff --git a/libpthread/nptl/sysdeps/powerpc/pthread_spin_lock.c b/libpthread/nptl/sysdeps/powerpc/pthread_spin_lock.c new file mode 100644 index 000000000..e2293fda1 --- /dev/null +++ b/libpthread/nptl/sysdeps/powerpc/pthread_spin_lock.c @@ -0,0 +1,45 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" + +int +pthread_spin_lock (lock) + pthread_spinlock_t *lock; +{ + unsigned int __tmp; + + asm volatile ( + "1: lwarx %0,0,%1\n" + " cmpwi 0,%0,0\n" + " bne- 2f\n" + " stwcx. %2,0,%1\n" + " bne- 2f\n" + " isync\n" + " .subsection 1\n" + "2: lwzx %0,0,%1\n" + " cmpwi 0,%0,0\n" + " bne 2b\n" + " b 1b\n" + " .previous" + : "=&r" (__tmp) + : "r" (lock), "r" (1) + : "cr0", "memory"); + return 0; +} diff --git a/libpthread/nptl/sysdeps/powerpc/pthread_spin_trylock.c b/libpthread/nptl/sysdeps/powerpc/pthread_spin_trylock.c new file mode 100644 index 000000000..d8e1dbcc8 --- /dev/null +++ b/libpthread/nptl/sysdeps/powerpc/pthread_spin_trylock.c @@ -0,0 +1,43 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include "pthreadP.h" + +int +pthread_spin_trylock (lock) + pthread_spinlock_t *lock; +{ + unsigned int old; + int err = EBUSY; + + asm ("1: lwarx %0,0,%2\n" + " cmpwi 0,%0,0\n" + " bne 2f\n" + " stwcx. %3,0,%2\n" + " bne- 1b\n" + " li %1,0\n" + " isync\n" + "2: " + : "=&r" (old), "=&r" (err) + : "r" (lock), "r" (1), "1" (err) + : "cr0", "memory"); + + return err; +} diff --git a/libpthread/nptl/sysdeps/powerpc/pthreaddef.h b/libpthread/nptl/sysdeps/powerpc/pthreaddef.h new file mode 100644 index 000000000..342c15c67 --- /dev/null +++ b/libpthread/nptl/sysdeps/powerpc/pthreaddef.h @@ -0,0 +1,41 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* Default stack size. */ +#define ARCH_STACK_DEFAULT_SIZE (4 * 1024 * 1024) + +/* Required stack pointer alignment at beginning. The ABI requires 16 + bytes (for both 32-bit and 64-bit PowerPC). */ +#define STACK_ALIGN 16 + +/* Minimal stack size after allocating thread descriptor and guard size. */ +#define MINIMAL_REST_STACK 4096 + +/* Alignment requirement for TCB. */ +#define TCB_ALIGNMENT 16 + + +/* Location of current stack frame. */ +#define CURRENT_STACK_FRAME __builtin_frame_address (0) + + +/* XXX Until we have a better place keep the definitions here. */ + +/* While there is no such syscall. */ +#define __exit_thread_inline(val) \ + INLINE_SYSCALL (exit, 1, (val)) diff --git a/libpthread/nptl/sysdeps/powerpc/tcb-offsets.sym b/libpthread/nptl/sysdeps/powerpc/tcb-offsets.sym new file mode 100644 index 000000000..3962edbd5 --- /dev/null +++ b/libpthread/nptl/sysdeps/powerpc/tcb-offsets.sym @@ -0,0 +1,16 @@ +#include <sysdep.h> +#include <tls.h> + +-- + +-- Abuse tls.h macros to derive offsets relative to the thread register. +# undef __thread_register +# define __thread_register ((void *) 0) +# define thread_offsetof(mem) ((ptrdiff_t) THREAD_SELF + offsetof (struct pthread, mem)) + + +#if TLS_MULTIPLE_THREADS_IN_TCB +MULTIPLE_THREADS_OFFSET thread_offsetof (header.multiple_threads) +#endif +PID thread_offsetof (pid) +TID thread_offsetof (tid) diff --git a/libpthread/nptl/sysdeps/powerpc/tls.h b/libpthread/nptl/sysdeps/powerpc/tls.h new file mode 100644 index 000000000..1157116a3 --- /dev/null +++ b/libpthread/nptl/sysdeps/powerpc/tls.h @@ -0,0 +1,173 @@ +/* Definition for thread-local data handling. NPTL/PowerPC version. + Copyright (C) 2003, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _TLS_H +#define _TLS_H 1 + +#ifndef __ASSEMBLER__ +# include <stdbool.h> +# include <stddef.h> +# include <stdint.h> + +/* Type for the dtv. */ +typedef union dtv +{ + size_t counter; + struct + { + void *val; + bool is_static; + } pointer; +} dtv_t; + +#else /* __ASSEMBLER__ */ +# include <tcb-offsets.h> +#endif /* __ASSEMBLER__ */ + + +/* We require TLS support in the tools. */ +#ifndef HAVE_TLS_SUPPORT +# error "TLS support is required." +#endif + +/* Signal that TLS support is available. */ +# define USE_TLS 1 + +#ifndef __ASSEMBLER__ + +/* Get system call information. */ +# include <sysdep.h> + +/* The TP points to the start of the thread blocks. */ +# define TLS_DTV_AT_TP 1 + +/* We use the multiple_threads field in the pthread struct */ +#define TLS_MULTIPLE_THREADS_IN_TCB 1 + +/* Get the thread descriptor definition. */ +# include <nptl/descr.h> + +/* The stack_guard is accessed directly by GCC -fstack-protector code, + so it is a part of public ABI. The dtv field is private. */ +typedef struct +{ + uintptr_t stack_guard; + dtv_t *dtv; +} tcbhead_t; + +/* This is the size of the initial TCB. */ +# define TLS_INIT_TCB_SIZE 0 + +/* Alignment requirements for the initial TCB. */ +# define TLS_INIT_TCB_ALIGN __alignof__ (struct pthread) + +/* This is the size of the TCB. */ +# define TLS_TCB_SIZE 0 + +/* Alignment requirements for the TCB. */ +# define TLS_TCB_ALIGN __alignof__ (struct pthread) + +/* This is the size we need before TCB. */ +# define TLS_PRE_TCB_SIZE \ + (sizeof (struct pthread) \ + + ((sizeof (tcbhead_t) + TLS_TCB_ALIGN - 1) & ~(TLS_TCB_ALIGN - 1))) + +# ifndef __powerpc64__ +/* Register r2 (tp) is reserved by the ABI as "thread pointer". */ +register void *__thread_register __asm__ ("r2"); +# define PT_THREAD_POINTER PT_R2 +# else +/* Register r13 (tp) is reserved by the ABI as "thread pointer". */ +register void *__thread_register __asm__ ("r13"); +# define PT_THREAD_POINTER PT_R13 +# endif + +/* The following assumes that TP (R2 or R13) points to the end of the + TCB + 0x7000 (per the ABI). This implies that TCB address is + TP - 0x7000. As we define TLS_DTV_AT_TP we can + assume that the pthread struct is allocated immediately ahead of the + TCB. This implies that the pthread_descr address is + TP - (TLS_PRE_TCB_SIZE + 0x7000). */ +# define TLS_TCB_OFFSET 0x7000 + +/* Install the dtv pointer. The pointer passed is to the element with + index -1 which contain the length. */ +# define INSTALL_DTV(tcbp, dtvp) \ + ((tcbhead_t *) (tcbp))[-1].dtv = dtvp + 1 + +/* Install new dtv for current thread. */ +# define INSTALL_NEW_DTV(dtv) (THREAD_DTV() = (dtv)) + +/* Return dtv of given thread descriptor. */ +# define GET_DTV(tcbp) (((tcbhead_t *) (tcbp))[-1].dtv) + +/* Code to initially initialize the thread pointer. This might need + special attention since 'errno' is not yet available and if the + operation can cause a failure 'errno' must not be touched. */ +# define TLS_INIT_TP(tcbp, secondcall) \ + (__thread_register = (void *) (tcbp) + TLS_TCB_OFFSET, NULL) + +/* Return the address of the dtv for the current thread. */ +# define THREAD_DTV() \ + (((tcbhead_t *) (__thread_register - TLS_TCB_OFFSET))[-1].dtv) + +/* Return the thread descriptor for the current thread. */ +# define THREAD_SELF \ + ((struct pthread *) (__thread_register \ + - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE)) + +/* Magic for libthread_db to know how to do THREAD_SELF. */ +# define DB_THREAD_SELF \ + REGISTER (32, 32, PT_THREAD_POINTER * 4, \ + - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE) \ + REGISTER (64, 64, PT_THREAD_POINTER * 8, \ + - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE) + +/* Read member of the thread descriptor directly. */ +# define THREAD_GETMEM(descr, member) ((void)(descr), (THREAD_SELF)->member) + +/* Same as THREAD_GETMEM, but the member offset can be non-constant. */ +# define THREAD_GETMEM_NC(descr, member, idx) \ + ((void)(descr), (THREAD_SELF)->member[idx]) + +/* Set member of the thread descriptor directly. */ +# define THREAD_SETMEM(descr, member, value) \ + ((void)(descr), (THREAD_SELF)->member = (value)) + +/* Same as THREAD_SETMEM, but the member offset can be non-constant. */ +# define THREAD_SETMEM_NC(descr, member, idx, value) \ + ((void)(descr), (THREAD_SELF)->member[idx] = (value)) + +/* Set the stack guard field in TCB head. */ +# define THREAD_SET_STACK_GUARD(value) \ + (((tcbhead_t *) ((char *) __thread_register \ + - TLS_TCB_OFFSET))[-1].stack_guard = (value)) +# define THREAD_COPY_STACK_GUARD(descr) \ + (((tcbhead_t *) ((char *) (descr) \ + + TLS_PRE_TCB_SIZE))[-1].stack_guard \ + = ((tcbhead_t *) ((char *) __thread_register \ + - TLS_TCB_OFFSET))[-1].stack_guard) + +/* l_tls_offset == 0 is perfectly valid on PPC, so we have to use some + different value to mean unset l_tls_offset. */ +# define NO_TLS_OFFSET -1 + +#endif /* __ASSEMBLER__ */ + +#endif /* tls.h */ diff --git a/libpthread/nptl/sysdeps/pthread/Makefile b/libpthread/nptl/sysdeps/pthread/Makefile new file mode 100644 index 000000000..a30ded527 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/Makefile @@ -0,0 +1,13 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2005 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +top_srcdir=../../../../ +top_builddir=../../../../ +all: objs +include $(top_builddir)Rules.mak +include Makefile.in +include $(top_srcdir)Makerules diff --git a/libpthread/nptl/sysdeps/pthread/Makefile.in b/libpthread/nptl/sysdeps/pthread/Makefile.in new file mode 100644 index 000000000..0d1097929 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/Makefile.in @@ -0,0 +1,153 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2005-2006 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +# +# NOTE: glibc puts flockfile.c, ftrylockfile.c, funlockfile.c, and +# pt-longjmp.c in libc and libpthread. For uClibc, they are +# in libc only. +# +libpthread_CSRC = pthread_barrier_wait.c pthread_cond_broadcast.c \ + pthread_cond_signal.c pthread_cond_timedwait.c \ + pthread_cond_wait.c pthread_rwlock_rdlock.c \ + pthread_rwlock_timedrdlock.c \ + pthread_rwlock_timedwrlock.c pthread_rwlock_unlock.c \ + pthread_rwlock_wrlock.c pthread_sigmask.c \ + pthread_spin_destroy.c pthread_spin_init.c \ + pthread_spin_unlock.c pt-sigfillset.c \ + pt-longjmp.c + + +ifeq ($(TARGET_ARCH),i386) +X86_PTHREAD_EXCLUDE_LIST = pthread_spin_unlock.c pthread_spin_init.c \ + pthread_barrier_wait.c pthread_cond_broadcast.c \ + pthread_cond_signal.c pthread_rwlock_timedrdlock.c \ + pthread_rwlock_timedwrlock.c pthread_rwlock_unlock.c pthread_rwlock_wrlock.c \ + pthread_rwlock_rdlock.c + +libpthread_CSRC := $(filter-out $(X86_PTHREAD_EXCLUDE_LIST),$(libpthread_CSRC)) +endif + +ifeq ($(TARGET_ARCH),sh) +SH_PTHREAD_EXCLUDE_LIST = pthread_spin_unlock.c pthread_spin_init.c \ + pthread_rwlock_wrlock.c pthread_rwlock_rdlock.c \ + pthread_rwlock_unlock.c pt-longjmp.c \ + pthread_barrier_wait.c pthread_cond_broadcast.c \ + pthread_cond_signal.c \ + pthread_rwlock_timedrdlock.c \ + pthread_rwlock_timedwrlock.c + +libpthread_CSRC := $(filter-out $(SH_PTHREAD_EXCLUDE_LIST),$(libpthread_CSRC)) +endif + +ifeq ($(TARGET_ARCH),x86_64) +X64_PTHREAD_EXCLUDE_LIST = pthread_spin_unlock.c pthread_spin_init.c \ + pthread_barrier_wait.c pthread_cond_broadcast.c \ + pthread_cond_signal.c pthread_rwlock_timedrdlock.c \ + pthread_rwlock_timedwrlock.c pthread_rwlock_unlock.c pthread_rwlock_wrlock.c \ + pthread_rwlock_rdlock.c pthread_cond_timedwait.c + +libpthread_CSRC := $(filter-out $(X64_PTHREAD_EXCLUDE_LIST),$(libpthread_CSRC)) +endif + + + +CFLAGS-pt-common = -DNOT_IN_libc=1 $(SSP_ALL_CFLAGS) + +CFLAGS-pthread_barrier_wait.c = -D_GNU_SOURCE $(CFLAGS-pt-common) \ + -DIS_IN_libpthread=1 +CFLAGS-pthread_cond_broadcast.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1 +CFLAGS-pthread_cond_signal.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1 +CFLAGS-pthread_cond_timedwait.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1 +CFLAGS-pthread_cond_wait.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1 +CFLAGS-pthread_rwlock_rdlock.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1 +CFLAGS-pthread_rwlock_timedrdlock.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1 +CFLAGS-pthread_rwlock_timedwrlock.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1 +CFLAGS-pthread_rwlock_unlock.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1 +CFLAGS-pthread_rwlock_wrlock.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1 +CFLAGS-pthread_sigmask.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1 +CFLAGS-pthread_spin_destroy.c = -D_GNU_SOURCE $(CFLAGS-pt-common) \ + -DIS_IN_libpthread=1 +CFLAGS-pthread_spin_init.c = -D_GNU_SOURCE $(CFLAGS-pt-common) \ + -DIS_IN_libpthread=1 +CFLAGS-pthread_spin_unlock.c = -D_GNU_SOURCE $(CFLAGS-pt-common) \ + -DIS_IN_libpthread=1 +CFLAGS-pt-sigaction.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1 \ + -I$(top_srcdir)libc/sysdeps/linux/$(TARGET_ARCH) \ + -I$(top_srcdir)libc/signal +CFLAGS-pt-sigfillset.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1 \ + -I$(top_srcdir)libc/signal +CFLAGS-pt-sigprocmask.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1 \ + -I$(top_srcdir)libc/sysdeps/linux/common +CFLAGS-unwind-forcedunwind.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1 -fexceptions -fasynchronous-unwind-tables +CFLAGS-librt-cancellation.c = -DIS_IN_librt=1 $(CFLAGS-pt-common) \ + -fexceptions -fasynchronous-unwind-tables +CFLAGS-rt-unwind-resume.c = -DIS_IN_librt=1 $(CFLAGS-pt-common) \ + -fexceptions -fasynchronous-unwind-tables + +#CFLAGS:=$(CFLAGS:-O1=-O2) + +pthread_DIR := $(top_srcdir)libpthread/nptl/sysdeps/pthread +pthread_OUT := $(top_builddir)libpthread/nptl/sysdeps/pthread + +pthread_SRC = $(patsubst %.c, $(pthread_DIR)/%.c, $(libpthread_CSRC)) +pthread_OBJ = $(patsubst %.c, $(pthread_OUT)/%.o, $(libpthread_CSRC)) + +ifeq ($(DOPIC),y) +libpthread-a-y += $(pthread_OBJ:.o=.os) +else +libpthread-a-y += $(pthread_OBJ) +endif +libpthread-so-y += $(pthread_OBJ:.o=.oS) +libpthread-so-y += $(pthread_OUT)/pt-sigaction.oS $(pthread_OUT)/pt-sigprocmask.oS \ + $(pthread_OUT)/unwind-forcedunwind.oS + +CFLAGS-sigaction.c = -I$(top_srcdir)libc/signal +libc-y += $(pthread_OUT)/sigaction.o + +librt-a-y += $(pthread_OUT)/librt-cancellation.o +librt-so-y += $(pthread_OUT)/librt-cancellation.oS \ + $(pthread_OUT)/rt-unwind-resume.oS + +ifeq ($(UCLIBC_CTOR_DTOR),y) +CFLAGS-pt-initfini.c = -S -g0 -fPIC -fno-inline-functions \ + $(call check_gcc,-fno-unit-at-a-time,) \ + -finhibit-size-directive \ + $(patsubst -f%,-fno-%,$(call check_gcc,-fexceptions,)) +ASFLAGS-crti.S = -g0 +ASFLAGS-crtn.S = -g0 + +$(pthread_OUT)/pt-initfini.s: $(pthread_DIR)/pt-initfini.c + $(compile.c) + sed -n -e '/@TESTS_BEGIN/,/@TESTS_END/p' $< | \ + awk -f $(pthread_DIR)/defs.awk > $(pthread_OUT)/defs.h + +$(pthread_OUT)/crti.S: $(pthread_OUT)/pt-initfini.s + sed -n -e '1,/@HEADER_ENDS/p' \ + -e '/@_.*_PROLOG_BEGINS/,/@_.*_PROLOG_ENDS/p' \ + -e '/@TRAILER_BEGINS/,$$p' $< > $@ + +$(pthread_OUT)/crtn.S: $(pthread_OUT)/pt-initfini.s + sed -n -e '1,/@HEADER_ENDS/p' \ + -e '/@_.*_EPILOG_BEGINS/,/@_.*_EPILOG_ENDS/p' \ + -e '/@TRAILER_BEGINS/,$$p' $< > $@ +endif + +$(pthread_DIR)/pt-sigaction.c: + $(LN) -s sigaction.c $@ + +$(pthread_DIR)/pt-sigfillset.c: + $(LN) -s sigfillset.c $@ + +$(pthread_DIR)/pt-sigprocmask.c: + $(LN) -s sigprocmask.c $@ + +objclean-y += nptl_pthread_clean + +nptl_pthread_clean: + $(do_rm) $(addprefix $(pthread_OUT)/*., o os oS s S) $(pthread_OUT)/defs.h \ + $(pthread_DIR)/pt-sigaction.c $(pthread_DIR)/pt-sigfillset.c \ + $(pthread_DIR)/pt-sigprocmask.c diff --git a/libpthread/nptl/sysdeps/pthread/allocalim.h b/libpthread/nptl/sysdeps/pthread/allocalim.h new file mode 100644 index 000000000..35224ec74 --- /dev/null +++ b/libpthread/nptl/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 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <alloca.h> +#include <limits.h> + + +extern inline int +__libc_use_alloca (size_t size) +{ + return (__builtin_expect (size <= PTHREAD_STACK_MIN / 4, 1) + || __libc_alloca_cutoff (size)); +} diff --git a/libpthread/nptl/sysdeps/pthread/bits/libc-lock.h b/libpthread/nptl/sysdeps/pthread/bits/libc-lock.h new file mode 100644 index 000000000..c59e3a0cc --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/bits/libc-lock.h @@ -0,0 +1,566 @@ +/* libc-internal interface for mutex locks. NPTL version. + Copyright (C) 1996-2001, 2002, 2003, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef _BITS_LIBC_LOCK_H +#define _BITS_LIBC_LOCK_H 1 + +#include <pthread.h> +#define __need_NULL +#include <stddef.h> + + +/* Fortunately Linux now has a mean to do locking which is realtime + safe without the aid of the thread library. We also need no fancy + options like error checking mutexes etc. We only need simple + locks, maybe recursive. This can be easily and cheaply implemented + using futexes. We will use them everywhere except in ld.so since + ld.so might be used on old kernels with a different libc.so. */ +#ifdef _LIBC +# include <lowlevellock.h> +# include <tls.h> +# include <pthread-functions.h> +#endif + +/* Mutex type. */ +#if defined _LIBC || defined _IO_MTSAFE_IO +# if (defined NOT_IN_libc && !defined IS_IN_libpthread) || !defined _LIBC +typedef pthread_mutex_t __libc_lock_t; +typedef struct { pthread_mutex_t mutex; } __libc_lock_recursive_t; +# else +typedef int __libc_lock_t; +typedef struct { int lock; int cnt; void *owner; } __libc_lock_recursive_t; +# endif +typedef struct { pthread_mutex_t mutex; } __rtld_lock_recursive_t; +# ifdef __USE_UNIX98 +typedef pthread_rwlock_t __libc_rwlock_t; +# else +typedef struct __libc_rwlock_opaque__ __libc_rwlock_t; +# endif +#else +typedef struct __libc_lock_opaque__ __libc_lock_t; +typedef struct __libc_lock_recursive_opaque__ __libc_lock_recursive_t; +typedef struct __libc_rwlock_opaque__ __libc_rwlock_t; +#endif + +/* Type for key to thread-specific data. */ +typedef pthread_key_t __libc_key_t; + +/* Define a lock variable NAME with storage class CLASS. The lock must be + initialized with __libc_lock_init before it can be used (or define it + with __libc_lock_define_initialized, below). Use `extern' for CLASS to + declare a lock defined in another module. In public structure + definitions you must use a pointer to the lock structure (i.e., NAME + begins with a `*'), because its storage size will not be known outside + of libc. */ +#define __libc_lock_define(CLASS,NAME) \ + CLASS __libc_lock_t NAME; +#define __libc_rwlock_define(CLASS,NAME) \ + CLASS __libc_rwlock_t NAME; +#define __libc_lock_define_recursive(CLASS,NAME) \ + CLASS __libc_lock_recursive_t NAME; +#define __rtld_lock_define_recursive(CLASS,NAME) \ + CLASS __rtld_lock_recursive_t NAME; + +/* Define an initialized lock variable NAME with storage class CLASS. + + For the C library we take a deeper look at the initializer. For + this implementation all fields are initialized to zero. Therefore + we don't initialize the variable which allows putting it into the + BSS section. (Except on PA-RISC and other odd architectures, where + initialized locks must be set to one due to the lack of normal + atomic operations.) */ + +#if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread) +# if LLL_LOCK_INITIALIZER == 0 +# define __libc_lock_define_initialized(CLASS,NAME) \ + CLASS __libc_lock_t NAME; +# else +# define __libc_lock_define_initialized(CLASS,NAME) \ + CLASS __libc_lock_t NAME = LLL_LOCK_INITIALIZER; +# endif +#else +# if __LT_SPINLOCK_INIT == 0 +# define __libc_lock_define_initialized(CLASS,NAME) \ + CLASS __libc_lock_t NAME; +# else +# define __libc_lock_define_initialized(CLASS,NAME) \ + CLASS __libc_lock_t NAME = PTHREAD_MUTEX_INITIALIZER; +# endif +#endif + +#define __libc_rwlock_define_initialized(CLASS,NAME) \ + CLASS __libc_rwlock_t NAME = PTHREAD_RWLOCK_INITIALIZER; + +/* Define an initialized recursive lock variable NAME with storage + class CLASS. */ +#if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread) +# if LLL_LOCK_INITIALIZER == 0 +# define __libc_lock_define_initialized_recursive(CLASS,NAME) \ + CLASS __libc_lock_recursive_t NAME; +# else +# define __libc_lock_define_initialized_recursive(CLASS,NAME) \ + CLASS __libc_lock_recursive_t NAME = _LIBC_LOCK_RECURSIVE_INITIALIZER; +# endif +# define _LIBC_LOCK_RECURSIVE_INITIALIZER \ + { LLL_LOCK_INITIALIZER, 0, NULL } +#else +# define __libc_lock_define_initialized_recursive(CLASS,NAME) \ + CLASS __libc_lock_recursive_t NAME = _LIBC_LOCK_RECURSIVE_INITIALIZER; +# define _LIBC_LOCK_RECURSIVE_INITIALIZER \ + {PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP} +#endif + +#define __rtld_lock_define_initialized_recursive(CLASS,NAME) \ + CLASS __rtld_lock_recursive_t NAME = _RTLD_LOCK_RECURSIVE_INITIALIZER; +#define _RTLD_LOCK_RECURSIVE_INITIALIZER \ + {PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP} + +#define __rtld_lock_initialize(NAME) \ + (void) ((NAME) = (__rtld_lock_recursive_t) _RTLD_LOCK_RECURSIVE_INITIALIZER) + +/* If we check for a weakly referenced symbol and then perform a + normal jump to it te code generated for some platforms in case of + PIC is unnecessarily slow. What would happen is that the function + is first referenced as data and then it is called indirectly + through the PLT. We can make this a direct jump. */ +#ifdef __PIC__ +# define __libc_maybe_call(FUNC, ARGS, ELSE) \ + (__extension__ ({ __typeof (FUNC) *_fn = (FUNC); \ + _fn != NULL ? (*_fn) ARGS : ELSE; })) +#else +# define __libc_maybe_call(FUNC, ARGS, ELSE) \ + (FUNC != NULL ? FUNC ARGS : ELSE) +#endif + +/* Call thread functions through the function pointer table. */ +#if defined SHARED && !defined NOT_IN_libc +# define PTF(NAME) __libc_pthread_functions.ptr_##NAME +# define __libc_ptf_call(FUNC, ARGS, ELSE) \ + (PTF(FUNC) != NULL ? PTF(FUNC) ARGS : ELSE) +#else +# define PTF(NAME) NAME +# define __libc_ptf_call(FUNC, ARGS, ELSE) \ + __libc_maybe_call (FUNC, ARGS, ELSE) +#endif + + +/* Initialize the named lock variable, leaving it in a consistent, unlocked + state. */ +#if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread) +# define __libc_lock_init(NAME) ((NAME) = LLL_LOCK_INITIALIZER, 0) +#else +# define __libc_lock_init(NAME) \ + __libc_maybe_call (__pthread_mutex_init, (&(NAME), NULL), 0) +#endif +#define __libc_rwlock_init(NAME) \ + __libc_maybe_call (__pthread_rwlock_init, (&(NAME), NULL), 0) + +/* Same as last but this time we initialize a recursive mutex. */ +#if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread) +# define __libc_lock_init_recursive(NAME) \ + ((NAME) = (__libc_lock_recursive_t) _LIBC_LOCK_RECURSIVE_INITIALIZER, 0) +#else +# define __libc_lock_init_recursive(NAME) \ + do { \ + if (__pthread_mutex_init != NULL) \ + { \ + pthread_mutexattr_t __attr; \ + __pthread_mutexattr_init (&__attr); \ + __pthread_mutexattr_settype (&__attr, PTHREAD_MUTEX_RECURSIVE_NP); \ + __pthread_mutex_init (&(NAME).mutex, &__attr); \ + __pthread_mutexattr_destroy (&__attr); \ + } \ + } while (0) +#endif + +#define __rtld_lock_init_recursive(NAME) \ + do { \ + if (__pthread_mutex_init != NULL) \ + { \ + pthread_mutexattr_t __attr; \ + __pthread_mutexattr_init (&__attr); \ + __pthread_mutexattr_settype (&__attr, PTHREAD_MUTEX_RECURSIVE_NP); \ + __pthread_mutex_init (&(NAME).mutex, &__attr); \ + __pthread_mutexattr_destroy (&__attr); \ + } \ + } while (0) + +/* Finalize the named lock variable, which must be locked. It cannot be + used again until __libc_lock_init is called again on it. This must be + called on a lock variable before the containing storage is reused. */ +#if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread) +# define __libc_lock_fini(NAME) ((void) 0) +#else +# define __libc_lock_fini(NAME) \ + __libc_maybe_call (__pthread_mutex_destroy, (&(NAME)), 0) +#endif +#define __libc_rwlock_fini(NAME) \ + __libc_maybe_call (__pthread_rwlock_destroy, (&(NAME)), 0) + +/* Finalize recursive named lock. */ +#if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread) +# define __libc_lock_fini_recursive(NAME) ((void) 0) +#else +# define __libc_lock_fini_recursive(NAME) \ + __libc_maybe_call (__pthread_mutex_destroy, (&(NAME)), 0) +#endif + +/* Lock the named lock variable. */ +#if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread) +# define __libc_lock_lock(NAME) \ + ({ lll_lock (NAME); 0; }) +#else +# define __libc_lock_lock(NAME) \ + __libc_maybe_call (__pthread_mutex_lock, (&(NAME)), 0) +#endif +#define __libc_rwlock_rdlock(NAME) \ + __libc_ptf_call (__pthread_rwlock_rdlock, (&(NAME)), 0) +#define __libc_rwlock_wrlock(NAME) \ + __libc_ptf_call (__pthread_rwlock_wrlock, (&(NAME)), 0) + +/* Lock the recursive named lock variable. */ +#if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread) +# define __libc_lock_lock_recursive(NAME) \ + do { \ + void *self = THREAD_SELF; \ + if ((NAME).owner != self) \ + { \ + lll_lock ((NAME).lock); \ + (NAME).owner = self; \ + } \ + ++(NAME).cnt; \ + } while (0) +#else +# define __libc_lock_lock_recursive(NAME) \ + __libc_maybe_call (__pthread_mutex_lock, (&(NAME).mutex), 0) +#endif + +/* Try to lock the named lock variable. */ +#if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread) +# define __libc_lock_trylock(NAME) \ + lll_trylock (NAME) +#else +# define __libc_lock_trylock(NAME) \ + __libc_maybe_call (__pthread_mutex_trylock, (&(NAME)), 0) +#endif +#define __libc_rwlock_tryrdlock(NAME) \ + __libc_maybe_call (__pthread_rwlock_tryrdlock, (&(NAME)), 0) +#define __libc_rwlock_trywrlock(NAME) \ + __libc_maybe_call (__pthread_rwlock_trywrlock, (&(NAME)), 0) + +/* Try to lock the recursive named lock variable. */ +#if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread) +# define __libc_lock_trylock_recursive(NAME) \ + ({ \ + int result = 0; \ + void *self = THREAD_SELF; \ + if ((NAME).owner != self) \ + { \ + if (lll_trylock ((NAME).lock) == 0) \ + { \ + (NAME).owner = self; \ + (NAME).cnt = 1; \ + } \ + else \ + result = EBUSY; \ + } \ + else \ + ++(NAME).cnt; \ + result; \ + }) +#else +# define __libc_lock_trylock_recursive(NAME) \ + __libc_maybe_call (__pthread_mutex_trylock, (&(NAME)), 0) +#endif + +#define __rtld_lock_trylock_recursive(NAME) \ + __libc_maybe_call (__pthread_mutex_trylock, (&(NAME).mutex), 0) + +/* Unlock the named lock variable. */ +#if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread) +# define __libc_lock_unlock(NAME) \ + lll_unlock (NAME) +#else +# define __libc_lock_unlock(NAME) \ + __libc_maybe_call (__pthread_mutex_unlock, (&(NAME)), 0) +#endif +#define __libc_rwlock_unlock(NAME) \ + __libc_ptf_call (__pthread_rwlock_unlock, (&(NAME)), 0) + +/* Unlock the recursive named lock variable. */ +#if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread) +/* We do no error checking here. */ +# define __libc_lock_unlock_recursive(NAME) \ + do { \ + if (--(NAME).cnt == 0) \ + { \ + (NAME).owner = NULL; \ + lll_unlock ((NAME).lock); \ + } \ + } while (0) +#else +# define __libc_lock_unlock_recursive(NAME) \ + __libc_maybe_call (__pthread_mutex_unlock, (&(NAME)), 0) +#endif + +#if defined _LIBC && defined SHARED +# define __rtld_lock_default_lock_recursive(lock) \ + ++((pthread_mutex_t *)(lock))->__data.__count; + +# define __rtld_lock_default_unlock_recursive(lock) \ + --((pthread_mutex_t *)(lock))->__data.__count; + +# define __rtld_lock_lock_recursive(NAME) \ + GL(dl_rtld_lock_recursive) (&(NAME).mutex) + +# define __rtld_lock_unlock_recursive(NAME) \ + GL(dl_rtld_unlock_recursive) (&(NAME).mutex) +#else +# define __rtld_lock_lock_recursive(NAME) \ + __libc_maybe_call (__pthread_mutex_lock, (&(NAME).mutex), 0) + +# define __rtld_lock_unlock_recursive(NAME) \ + __libc_maybe_call (__pthread_mutex_unlock, (&(NAME).mutex), 0) +#endif + +/* Define once control variable. */ +#if PTHREAD_ONCE_INIT == 0 +/* Special case for static variables where we can avoid the initialization + if it is zero. */ +# define __libc_once_define(CLASS, NAME) \ + CLASS pthread_once_t NAME +#else +# define __libc_once_define(CLASS, NAME) \ + CLASS pthread_once_t NAME = PTHREAD_ONCE_INIT +#endif + +/* Call handler iff the first call. */ +#define __libc_once(ONCE_CONTROL, INIT_FUNCTION) \ + do { \ + if (PTF(__pthread_once) != NULL) \ + PTF(__pthread_once) (&(ONCE_CONTROL), INIT_FUNCTION); \ + else if ((ONCE_CONTROL) == PTHREAD_ONCE_INIT) { \ + INIT_FUNCTION (); \ + (ONCE_CONTROL) |= 2; \ + } \ + } while (0) + + +/* Note that for I/O cleanup handling we are using the old-style + cancel handling. It does not have to be integrated with C++ snce + no C++ code is called in the middle. The old-style handling is + faster and the support is not going away. */ +extern void _pthread_cleanup_push (struct _pthread_cleanup_buffer *buffer, + void (*routine) (void *), void *arg); +extern void _pthread_cleanup_pop (struct _pthread_cleanup_buffer *buffer, + int execute); +extern void _pthread_cleanup_push_defer (struct _pthread_cleanup_buffer *buffer, + void (*routine) (void *), void *arg); +extern void _pthread_cleanup_pop_restore (struct _pthread_cleanup_buffer *buffer, + int execute); + +/* Start critical region with cleanup. */ +#define __libc_cleanup_region_start(DOIT, FCT, ARG) \ + { struct _pthread_cleanup_buffer _buffer; \ + int _avail; \ + if (DOIT) { \ + _avail = PTF(_pthread_cleanup_push_defer) != NULL; \ + if (_avail) { \ + PTF(_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) { \ + PTF(_pthread_cleanup_pop_restore) (&_buffer, DOIT); \ + } else if (DOIT) \ + _buffer.__routine (_buffer.__arg); \ + } + +/* Sometimes we have to exit the block in the middle. */ +#define __libc_cleanup_end(DOIT) \ + if (_avail) { \ + PTF(_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); + +__extern_inline void +__libc_cleanup_routine (struct __pthread_cleanup_frame *f) +{ + if (f->__do_it) + f->__cancel_routine (f->__cancel_arg); +} + +#define __libc_cleanup_push(fct, arg) \ + do { \ + struct __pthread_cleanup_frame __clframe \ + __attribute__ ((__cleanup__ (__libc_cleanup_routine))) \ + = { .__cancel_routine = (fct), .__cancel_arg = (arg), \ + .__do_it = 1 }; + +#define __libc_cleanup_pop(execute) \ + __clframe.__do_it = (execute); \ + } while (0) + + +/* Create thread-specific key. */ +#define __libc_key_create(KEY, DESTRUCTOR) \ + __libc_ptf_call (__pthread_key_create, (KEY, DESTRUCTOR), 1) + +/* Get thread-specific data. */ +#define __libc_getspecific(KEY) \ + __libc_ptf_call (__pthread_getspecific, (KEY), NULL) + +/* Set thread-specific data. */ +#define __libc_setspecific(KEY, VALUE) \ + __libc_ptf_call (__pthread_setspecific, (KEY, VALUE), 0) + + +/* Register handlers to execute before and after `fork'. Note that the + last parameter is NULL. The handlers registered by the libc are + never removed so this is OK. */ +#define __libc_atfork(PREPARE, PARENT, CHILD) \ + __register_atfork (PREPARE, PARENT, CHILD, NULL) +extern int __register_atfork (void (*__prepare) (void), + void (*__parent) (void), + void (*__child) (void), + void *__dso_handle); + +/* Functions that are used by this file and are internal to the GNU C + library. */ + +extern int __pthread_mutex_init (pthread_mutex_t *__mutex, + __const pthread_mutexattr_t *__mutex_attr); + +extern int __pthread_mutex_destroy (pthread_mutex_t *__mutex); + +extern int __pthread_mutex_trylock (pthread_mutex_t *__mutex); + +extern int __pthread_mutex_lock (pthread_mutex_t *__mutex); + +extern int __pthread_mutex_unlock (pthread_mutex_t *__mutex); + +extern int __pthread_mutexattr_init (pthread_mutexattr_t *__attr); + +extern int __pthread_mutexattr_destroy (pthread_mutexattr_t *__attr); + +extern int __pthread_mutexattr_settype (pthread_mutexattr_t *__attr, + int __kind); + +#ifdef __USE_UNIX98 +extern int __pthread_rwlock_init (pthread_rwlock_t *__rwlock, + __const pthread_rwlockattr_t *__attr); + +extern int __pthread_rwlock_destroy (pthread_rwlock_t *__rwlock); + +extern int __pthread_rwlock_rdlock (pthread_rwlock_t *__rwlock); + +extern int __pthread_rwlock_tryrdlock (pthread_rwlock_t *__rwlock); + +extern int __pthread_rwlock_wrlock (pthread_rwlock_t *__rwlock); + +extern int __pthread_rwlock_trywrlock (pthread_rwlock_t *__rwlock); + +extern int __pthread_rwlock_unlock (pthread_rwlock_t *__rwlock); +#endif + +extern int __pthread_key_create (pthread_key_t *__key, + void (*__destr_function) (void *)); + +extern int __pthread_setspecific (pthread_key_t __key, + __const void *__pointer); + +extern void *__pthread_getspecific (pthread_key_t __key); + +extern int __pthread_once (pthread_once_t *__once_control, + void (*__init_routine) (void)); + +extern int __pthread_atfork (void (*__prepare) (void), + void (*__parent) (void), + void (*__child) (void)); + + + +/* Make the pthread functions weak so that we can elide them from + single-threaded processes. */ +#ifndef __NO_WEAK_PTHREAD_ALIASES +# ifdef weak_extern +weak_extern (__pthread_mutex_init) +weak_extern (__pthread_mutex_destroy) +weak_extern (__pthread_mutex_lock) +weak_extern (__pthread_mutex_trylock) +weak_extern (__pthread_mutex_unlock) +weak_extern (__pthread_mutexattr_init) +weak_extern (__pthread_mutexattr_destroy) +weak_extern (__pthread_mutexattr_settype) +weak_extern (__pthread_rwlock_init) +weak_extern (__pthread_rwlock_destroy) +weak_extern (__pthread_rwlock_rdlock) +weak_extern (__pthread_rwlock_tryrdlock) +weak_extern (__pthread_rwlock_wrlock) +weak_extern (__pthread_rwlock_trywrlock) +weak_extern (__pthread_rwlock_unlock) +weak_extern (__pthread_key_create) +weak_extern (__pthread_setspecific) +weak_extern (__pthread_getspecific) +weak_extern (__pthread_once) +weak_extern (__pthread_atfork) +#ifdef SHARED +weak_extern (_pthread_cleanup_push_defer) +weak_extern (_pthread_cleanup_pop_restore) +#endif +weak_extern (pthread_setcancelstate) +# else +# pragma weak __pthread_mutex_init +# pragma weak __pthread_mutex_destroy +# pragma weak __pthread_mutex_lock +# pragma weak __pthread_mutex_trylock +# pragma weak __pthread_mutex_unlock +# pragma weak __pthread_mutexattr_init +# pragma weak __pthread_mutexattr_destroy +# pragma weak __pthread_mutexattr_settype +# pragma weak __pthread_rwlock_destroy +# pragma weak __pthread_rwlock_rdlock +# pragma weak __pthread_rwlock_tryrdlock +# pragma weak __pthread_rwlock_wrlock +# pragma weak __pthread_rwlock_trywrlock +# pragma weak __pthread_rwlock_unlock +# pragma weak __pthread_key_create +# pragma weak __pthread_setspecific +# pragma weak __pthread_getspecific +# pragma weak __pthread_once +# pragma weak __pthread_atfork +# pragma weak _pthread_cleanup_push_defer +# pragma weak _pthread_cleanup_pop_restore +# pragma weak pthread_setcancelstate +# endif +#endif + +#endif /* bits/libc-lock.h */ diff --git a/libpthread/nptl/sysdeps/pthread/bits/libc-tsd.h b/libpthread/nptl/sysdeps/pthread/bits/libc-tsd.h new file mode 100644 index 000000000..3f1676b3e --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/bits/libc-tsd.h @@ -0,0 +1,69 @@ +/* libc-internal interface for thread-specific data. Stub or TLS version. + Copyright (C) 1998,2001,02 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _GENERIC_BITS_LIBC_TSD_H +#define _GENERIC_BITS_LIBC_TSD_H 1 + +/* This file defines the following macros for accessing a small fixed + set of thread-specific `void *' data used only internally by libc. + + __libc_tsd_define(CLASS, KEY) -- Define or declare a `void *' datum + for KEY. CLASS can be `static' for + keys used in only one source file, + empty for global definitions, or + `extern' for global declarations. + __libc_tsd_address(KEY) -- Return the `void **' pointing to + the current thread's datum for KEY. + __libc_tsd_get(KEY) -- Return the `void *' datum for KEY. + __libc_tsd_set(KEY, VALUE) -- Set the datum for KEY to VALUE. + + The set of available KEY's will usually be provided as an enum, + and contains (at least): + _LIBC_TSD_KEY_MALLOC + _LIBC_TSD_KEY_DL_ERROR + _LIBC_TSD_KEY_RPC_VARS + All uses must be the literal _LIBC_TSD_* name in the __libc_tsd_* macros. + Some implementations may not provide any enum at all and instead + using string pasting in the macros. */ + +#include <tls.h> + +/* When full support for __thread variables is available, this interface is + just a trivial wrapper for it. Without TLS, this is the generic/stub + implementation for wholly single-threaded systems. + + We don't define an enum for the possible key values, because the KEYs + translate directly into variables by macro magic. */ + +#if USE___THREAD +# define __libc_tsd_define(CLASS, KEY) \ + CLASS __thread void *__libc_tsd_##KEY attribute_tls_model_ie; + +# define __libc_tsd_address(KEY) (&__libc_tsd_##KEY) +# define __libc_tsd_get(KEY) (__libc_tsd_##KEY) +# define __libc_tsd_set(KEY, VALUE) (__libc_tsd_##KEY = (VALUE)) +#else +# define __libc_tsd_define(CLASS, KEY) CLASS void *__libc_tsd_##KEY##_data; + +# define __libc_tsd_address(KEY) (&__libc_tsd_##KEY##_data) +# define __libc_tsd_get(KEY) (__libc_tsd_##KEY##_data) +# define __libc_tsd_set(KEY, VALUE) (__libc_tsd_##KEY##_data = (VALUE)) +#endif + +#endif /* bits/libc-tsd.h */ diff --git a/libpthread/nptl/sysdeps/pthread/bits/sigthread.h b/libpthread/nptl/sysdeps/pthread/bits/sigthread.h new file mode 100644 index 000000000..960bde18a --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/bits/sigthread.h @@ -0,0 +1,38 @@ +/* Signal handling function for threaded programs. + Copyright (C) 1998, 1999, 2000, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#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; + +#endif /* bits/sigthread.h */ diff --git a/libpthread/nptl/sysdeps/pthread/bits/stdio-lock.h b/libpthread/nptl/sysdeps/pthread/bits/stdio-lock.h new file mode 100644 index 000000000..cd64bc37e --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/bits/stdio-lock.h @@ -0,0 +1,105 @@ +/* Thread package specific definitions of stream lock type. NPTL version. + Copyright (C) 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _BITS_STDIO_LOCK_H +#define _BITS_STDIO_LOCK_H 1 + +#include <bits/libc-lock.h> +#include <lowlevellock.h> + + +/* The locking here is very inexpensive, even for inlining. */ +#define _IO_lock_inexpensive 1 + +typedef struct { int lock; int cnt; void *owner; } _IO_lock_t; + +#define _IO_lock_initializer { LLL_LOCK_INITIALIZER, 0, NULL } + +#define _IO_lock_init(_name) \ + ((_name) = (_IO_lock_t) _IO_lock_initializer , 0) + +#define _IO_lock_fini(_name) \ + ((void) 0) + +#define _IO_lock_lock(_name) \ + do { \ + void *__self = THREAD_SELF; \ + if ((_name).owner != __self) \ + { \ + lll_lock ((_name).lock); \ + (_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); \ + } \ + } while (0) + + + +#define _IO_cleanup_region_start(_fct, _fp) \ + __libc_cleanup_region_start (((_fp)->_flags & _IO_USER_LOCK) == 0, _fct, _fp) +#define _IO_cleanup_region_start_noarg(_fct) \ + __libc_cleanup_region_start (1, _fct, NULL) +#define _IO_cleanup_region_end(_doit) \ + __libc_cleanup_region_end (_doit) + +#if defined _LIBC && !defined NOT_IN_libc + +# ifdef __EXCEPTIONS +# define _IO_acquire_lock(_fp) \ + do { \ + _IO_FILE *_IO_acquire_lock_file \ + __attribute__((cleanup (_IO_acquire_lock_fct))) \ + = (_fp); \ + _IO_flockfile (_IO_acquire_lock_file); + +# else +# define _IO_acquire_lock(_fp) _IO_acquire_lock_needs_exceptions_enabled +# endif +# define _IO_release_lock(_fp) ; } while (0) + +#endif + +#endif /* bits/stdio-lock.h */ diff --git a/libpthread/nptl/sysdeps/pthread/createthread.c b/libpthread/nptl/sysdeps/pthread/createthread.c new file mode 100644 index 000000000..88ffe09d3 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/createthread.c @@ -0,0 +1,255 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sched.h> +#include <setjmp.h> +#include <signal.h> +#include <stdlib.h> +#include <atomic.h> +#include <ldsodefs.h> +#include <tls.h> + +#include <bits/kernel-features.h> + + +#define CLONE_SIGNAL (CLONE_SIGHAND | CLONE_THREAD) + +/* Unless otherwise specified, the thread "register" is going to be + initialized with a pointer to the TCB. */ +#ifndef TLS_VALUE +# define TLS_VALUE pd +#endif + +#ifndef ARCH_CLONE +# define ARCH_CLONE __clone +#endif + + +#ifndef TLS_MULTIPLE_THREADS_IN_TCB +/* Pointer to the corresponding variable in libc. */ +int *__libc_multiple_threads_ptr attribute_hidden; +#endif + + +static int +do_clone (struct pthread *pd, const struct pthread_attr *attr, + int clone_flags, int (*fct) (void *), STACK_VARIABLES_PARMS, + int stopped) +{ +#ifdef PREPARE_CREATE + PREPARE_CREATE; +#endif + + if (stopped) + /* We Make sure the thread does not run far by forcing it to get a + lock. We lock it here too so that the new thread cannot continue + until we tell it to. */ + lll_lock (pd->lock); + + /* One more thread. We cannot have the thread do this itself, since it + might exist but not have been scheduled yet by the time we've returned + and need to check the value to behave correctly. We must do it before + creating the thread, in case it does get scheduled first and then + might mistakenly think it was the only thread. In the failure case, + we momentarily store a false value; this doesn't matter because there + is no kosher thing a signal handler interrupting us right here can do + that cares whether the thread count is correct. */ + atomic_increment (&__nptl_nthreads); + + if (ARCH_CLONE (fct, STACK_VARIABLES_ARGS, clone_flags, + pd, &pd->tid, TLS_VALUE, &pd->tid) == -1) + { + atomic_decrement (&__nptl_nthreads); /* Oops, we lied for a second. */ + + /* Failed. If the thread is detached, remove the TCB here since + the caller cannot do this. The caller remembered the thread + as detached and cannot reverify that it is not since it must + not access the thread descriptor again. */ + if (IS_DETACHED (pd)) + __deallocate_stack (pd); + + return errno; + } + + /* Now we have the possibility to set scheduling parameters etc. */ + if (__builtin_expect (stopped != 0, 0)) + { + INTERNAL_SYSCALL_DECL (err); + int res = 0; + + /* Set the affinity mask if necessary. */ + if (attr->cpuset != NULL) + { + res = INTERNAL_SYSCALL (sched_setaffinity, err, 3, pd->tid, + sizeof (cpu_set_t), attr->cpuset); + + if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (res, err), 0)) + { + /* The operation failed. We have to kill the thread. First + send it the cancellation signal. */ + INTERNAL_SYSCALL_DECL (err2); + err_out: +#if __ASSUME_TGKILL + (void) INTERNAL_SYSCALL (tgkill, err2, 3, + THREAD_GETMEM (THREAD_SELF, pid), + pd->tid, SIGCANCEL); +#else + (void) INTERNAL_SYSCALL (tkill, err2, 2, pd->tid, SIGCANCEL); +#endif + + return (INTERNAL_SYSCALL_ERROR_P (res, err) + ? INTERNAL_SYSCALL_ERRNO (res, err) + : 0); + } + } + + /* Set the scheduling parameters. */ + if ((attr->flags & ATTR_FLAG_NOTINHERITSCHED) != 0) + { + res = INTERNAL_SYSCALL (sched_setscheduler, err, 3, pd->tid, + pd->schedpolicy, &pd->schedparam); + + if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (res, err), 0)) + goto err_out; + } + } + + /* We now have for sure more than one thread. The main thread might + not yet have the flag set. No need to set the global variable + again if this is what we use. */ + THREAD_SETMEM (THREAD_SELF, header.multiple_threads, 1); + + return 0; +} + + +static int +create_thread (struct pthread *pd, const struct pthread_attr *attr, + STACK_VARIABLES_PARMS) +{ +#ifdef TLS_TCB_AT_TP + assert (pd->header.tcb != NULL); +#endif + + /* We rely heavily on various flags the CLONE function understands: + + CLONE_VM, CLONE_FS, CLONE_FILES + These flags select semantics with shared address space and + file descriptors according to what POSIX requires. + + CLONE_SIGNAL + This flag selects the POSIX signal semantics. + + CLONE_SETTLS + The sixth parameter to CLONE determines the TLS area for the + new thread. + + CLONE_PARENT_SETTID + The kernels writes the thread ID of the newly created thread + into the location pointed to by the fifth parameters to CLONE. + + Note that it would be semantically equivalent to use + CLONE_CHILD_SETTID but it is be more expensive in the kernel. + + CLONE_CHILD_CLEARTID + The kernels clears the thread ID of a thread that has called + sys_exit() in the location pointed to by the seventh parameter + to CLONE. + + CLONE_DETACHED + No signal is generated if the thread exists and it is + automatically reaped. + + The termination signal is chosen to be zero which means no signal + is sent. */ + int clone_flags = (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGNAL + | CLONE_SETTLS | CLONE_PARENT_SETTID + | CLONE_CHILD_CLEARTID | CLONE_SYSVSEM +#if __ASSUME_NO_CLONE_DETACHED == 0 + | CLONE_DETACHED +#endif + | 0); + + if (__builtin_expect (THREAD_GETMEM (THREAD_SELF, report_events), 0)) + { + /* The parent thread is supposed to report events. Check whether + the TD_CREATE event is needed, too. */ + const int _idx = __td_eventword (TD_CREATE); + const uint32_t _mask = __td_eventmask (TD_CREATE); + + if ((_mask & (__nptl_threads_events.event_bits[_idx] + | pd->eventbuf.eventmask.event_bits[_idx])) != 0) + { + /* We always must have the thread start stopped. */ + pd->stopped_start = true; + + /* Create the thread. We always create the thread stopped + so that it does not get far before we tell the debugger. */ + int res = do_clone (pd, attr, clone_flags, start_thread, + STACK_VARIABLES_ARGS, 1); + if (res == 0) + { + /* Now fill in the information about the new thread in + the newly created thread's data structure. We cannot let + the new thread do this since we don't know whether it was + already scheduled when we send the event. */ + pd->eventbuf.eventnum = TD_CREATE; + pd->eventbuf.eventdata = pd; + + /* Enqueue the descriptor. */ + do + pd->nextevent = __nptl_last_event; + while (atomic_compare_and_exchange_bool_acq (&__nptl_last_event, + pd, pd->nextevent) + != 0); + + /* Now call the function which signals the event. */ + __nptl_create_event (); + + /* And finally restart the new thread. */ + lll_unlock (pd->lock); + } + + return res; + } + } + +#ifdef NEED_DL_SYSINFO + assert (THREAD_SELF_SYSINFO == THREAD_SYSINFO (pd)); +#endif + + /* Determine whether the newly created threads has to be started + stopped since we have to set the scheduling parameters or set the + affinity. */ + bool stopped = false; + if (attr != NULL && (attr->cpuset != NULL + || (attr->flags & ATTR_FLAG_NOTINHERITSCHED) != 0)) + stopped = true; + pd->stopped_start = stopped; + + /* Actually create the thread. */ + int res = do_clone (pd, attr, clone_flags, start_thread, + STACK_VARIABLES_ARGS, stopped); + + if (res == 0 && stopped) + /* And finally restart the new thread. */ + lll_unlock (pd->lock); + + return res; +} diff --git a/libpthread/nptl/sysdeps/pthread/defs.awk b/libpthread/nptl/sysdeps/pthread/defs.awk new file mode 100644 index 000000000..d41d57bd7 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/defs.awk @@ -0,0 +1,24 @@ +/^[ ]*\.endp/ { need_endp = 1 } +/^[ ]*\.end/ { need_end = 1 } +/^[ ]*\.align/ { if($2 > max) max = $2; } + +END { + if(need_endp) + { + print "#define END_INIT .endp _init"; + print "#define END_FINI .endp _fini"; + } else if(need_end) + { + print "#define END_INIT .end _init"; + print "#define END_FINI .end _fini"; + } + else + { + print "#define END_INIT"; + print "#define END_FINI"; + } + if(max) + print "#define ALIGN .align", max; + else + print "#define ALIGN"; +} diff --git a/libpthread/nptl/sysdeps/pthread/librt-cancellation.c b/libpthread/nptl/sysdeps/pthread/librt-cancellation.c new file mode 100644 index 000000000..753a2d831 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/librt-cancellation.c @@ -0,0 +1,108 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <setjmp.h> +#include <signal.h> +#include <stdlib.h> +#include "pthreadP.h" +#include "atomic.h" + + +#ifdef IS_IN_librt +/* 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 +__librt_enable_asynccancel (void) +{ + struct pthread *self = THREAD_SELF; + int oldval = THREAD_GETMEM (self, cancelhandling); + + while (1) + { + int newval = oldval | CANCELTYPE_BITMASK; + + if (__builtin_expect ((oldval & CANCELED_BITMASK) != 0, 0)) + { + /* If we are already exiting or if PTHREAD_CANCEL_DISABLED, + stop right here. */ + if ((oldval & (EXITING_BITMASK | CANCELSTATE_BITMASK)) != 0) + break; + + int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, + newval, oldval); + if (__builtin_expect (curval != oldval, 0)) + { + /* Somebody else modified the word, try again. */ + oldval = curval; + continue; + } + + THREAD_SETMEM (self, result, PTHREAD_CANCELED); + + __do_cancel (); + + /* NOTREACHED */ + } + + int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, newval, + oldval); + if (__builtin_expect (curval == oldval, 1)) + break; + + /* Prepare the next round. */ + oldval = curval; + } + + return oldval; +} + + +void +internal_function attribute_hidden +__librt_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 oldval = THREAD_GETMEM (self, cancelhandling); + + while (1) + { + int newval = oldval & ~CANCELTYPE_BITMASK; + + if (newval == oldval) + break; + + int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, newval, + oldval); + if (__builtin_expect (curval == oldval, 1)) + break; + + /* Prepare the next round. */ + oldval = curval; + } +} + + +#endif diff --git a/libpthread/nptl/sysdeps/pthread/list.h b/libpthread/nptl/sysdeps/pthread/list.h new file mode 100644 index 000000000..43186a2d5 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/list.h @@ -0,0 +1,114 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _LIST_H +#define _LIST_H 1 + +/* The definitions of this file are adopted from those which can be + found in the Linux kernel headers to enable people familiar with + the latter find their way in these sources as well. */ + + +/* Basic type for the double-link list. */ +typedef struct list_head +{ + struct list_head *next; + struct list_head *prev; +} list_t; + + +/* Define a variable with the head and tail of the list. */ +#define LIST_HEAD(name) \ + list_t name = { &(name), &(name) } + +/* Initialize a new list head. */ +#define INIT_LIST_HEAD(ptr) \ + (ptr)->next = (ptr)->prev = (ptr) + + +/* Add new element at the head of the list. */ +static inline void +list_add (list_t *newp, list_t *head) +{ + head->next->prev = newp; + newp->next = head->next; + newp->prev = head; + head->next = newp; +} + + +/* Add new element at the tail of the list. */ +static inline void +list_add_tail (list_t *newp, list_t *head) +{ + head->prev->next = newp; + newp->next = head; + newp->prev = head->prev; + head->prev = newp; +} + + +/* Remove element from list. */ +static inline void +list_del (list_t *elem) +{ + elem->next->prev = elem->prev; + elem->prev->next = elem->next; +} + + +/* Join two lists. */ +static inline void +list_splice (list_t *add, list_t *head) +{ + /* Do nothing if the list which gets added is empty. */ + if (add != add->next) + { + add->next->prev = head; + add->prev->next = head->next; + head->next->prev = add->prev; + head->next = add->next; + } +} + + +/* Get typed element from list at a given position. */ +#define list_entry(ptr, type, member) \ + ((type *) ((char *) (ptr) - (unsigned long) (&((type *) 0)->member))) + + + +/* Iterate forward over the elements of the list. */ +#define list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + + +/* Iterate forward over the elements of the list. */ +#define list_for_each_prev(pos, head) \ + for (pos = (head)->prev; pos != (head); pos = pos->prev) + + +/* Iterate backwards over the elements list. The list elements can be + removed from the list while doing this. */ +#define list_for_each_prev_safe(pos, p, head) \ + for (pos = (head)->prev, p = pos->prev; \ + pos != (head); \ + pos = p, p = pos->prev) + +#endif /* list.h */ diff --git a/libpthread/nptl/sysdeps/pthread/malloc-machine.h b/libpthread/nptl/sysdeps/pthread/malloc-machine.h new file mode 100644 index 000000000..efab230aa --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/malloc-machine.h @@ -0,0 +1,62 @@ +/* Basic platform-independent macro definitions for mutexes, + thread-specific data and parameters for malloc. + Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _MALLOC_MACHINE_H +#define _MALLOC_MACHINE_H + +#undef thread_atfork_static + +#include <atomic.h> +#include <bits/libc-lock.h> + +__libc_lock_define (typedef, mutex_t) + +#define mutex_init(m) __libc_lock_init (*(m)) +#define mutex_lock(m) __libc_lock_lock (*(m)) +#define mutex_trylock(m) __libc_lock_trylock (*(m)) +#define mutex_unlock(m) __libc_lock_unlock (*(m)) + +/* This is defined by newer gcc version unique for each module. */ +extern void *__dso_handle __attribute__ ((__weak__)); + +#include <fork.h> + +#ifdef SHARED +# define thread_atfork(prepare, parent, child) \ + __register_atfork (prepare, parent, child, __dso_handle) +#else +# define thread_atfork(prepare, parent, child) \ + __register_atfork (prepare, parent, child, \ + &__dso_handle == NULL ? NULL : __dso_handle) +#endif + +/* thread specific data for glibc */ + +#include <bits/libc-tsd.h> + +typedef int tsd_key_t[1]; /* no key data structure, libc magic does it */ +__libc_tsd_define (static, MALLOC) /* declaration/common definition */ +#define tsd_key_create(key, destr) ((void) (key)) +#define tsd_setspecific(key, data) __libc_tsd_set (MALLOC, (data)) +#define tsd_getspecific(key, vptr) ((vptr) = __libc_tsd_get (MALLOC)) + +#include <sysdeps/generic/malloc-machine.h> + +#endif /* !defined(_MALLOC_MACHINE_H) */ diff --git a/libpthread/nptl/sysdeps/pthread/posix-timer.h b/libpthread/nptl/sysdeps/pthread/posix-timer.h new file mode 100644 index 000000000..8b4cbc8cd --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/posix-timer.h @@ -0,0 +1,197 @@ +/* Definitions for POSIX timer implementation on top of NPTL. + Copyright (C) 2000, 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Kaz Kylheku <kaz@ashi.footprints.net>. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <limits.h> +#include <signal.h> + +/* Double linked list. */ +struct list_links +{ + struct list_links *next; + struct list_links *prev; +}; + + +/* Forward declaration. */ +struct timer_node; + + +/* Definitions for an internal thread of the POSIX timer implementation. */ +struct thread_node +{ + struct list_links links; + pthread_attr_t attr; + pthread_t id; + unsigned int exists; + struct list_links timer_queue; + pthread_cond_t cond; + struct timer_node *current_timer; + pthread_t captured; + clockid_t clock_id; +}; + + +/* Internal representation of a timer. */ +struct timer_node +{ + struct list_links links; + struct sigevent event; + clockid_t clock; + struct itimerspec value; + struct timespec expirytime; + pthread_attr_t attr; + unsigned int abstime; + unsigned int armed; + enum { + TIMER_FREE, TIMER_INUSE, TIMER_DELETED + } inuse; + struct thread_node *thread; + pid_t creator_pid; + int refcount; + int overrun_count; +}; + + +/* The limit is not published if we are compiled with kernel timer support. + But we still compiled in this implementation with its limit unless built + to require the kernel support. */ +#ifndef TIMER_MAX +# define TIMER_MAX 256 +#endif + +/* Static array with the structures for all the timers. */ +extern struct timer_node __timer_array[TIMER_MAX]; + +/* Global lock to protect operation on the lists. */ +extern pthread_mutex_t __timer_mutex; + +/* Variable to protext initialization. */ +extern pthread_once_t __timer_init_once_control; + +/* Nonzero if initialization of timer implementation failed. */ +extern int __timer_init_failed; + +/* Node for the thread used to deliver signals. */ +extern struct thread_node __timer_signal_thread_rclk; + + +/* Return pointer to timer structure corresponding to ID. */ +#define timer_id2ptr(timerid) ((struct timer_node *) timerid) +#define timer_ptr2id(timerid) ((void *) timerid) + +/* Check whether timer is valid; global mutex must be held. */ +static inline int +timer_valid (struct timer_node *timer) +{ + return timer && timer->inuse == TIMER_INUSE; +} + +/* Timer refcount functions; need global mutex. */ +extern void __timer_dealloc (struct timer_node *timer); + +static inline void +timer_addref (struct timer_node *timer) +{ + timer->refcount++; +} + +static inline void +timer_delref (struct timer_node *timer) +{ + if (--timer->refcount == 0) + __timer_dealloc (timer); +} + +/* Timespec helper routines. */ +static inline int +__attribute ((always_inline)) +timespec_compare (const struct timespec *left, const struct timespec *right) +{ + if (left->tv_sec < right->tv_sec) + return -1; + if (left->tv_sec > right->tv_sec) + return 1; + + if (left->tv_nsec < right->tv_nsec) + return -1; + if (left->tv_nsec > right->tv_nsec) + return 1; + + return 0; +} + +static inline void +timespec_add (struct timespec *sum, const struct timespec *left, + const struct timespec *right) +{ + sum->tv_sec = left->tv_sec + right->tv_sec; + sum->tv_nsec = left->tv_nsec + right->tv_nsec; + + if (sum->tv_nsec >= 1000000000) + { + ++sum->tv_sec; + sum->tv_nsec -= 1000000000; + } +} + +static inline void +timespec_sub (struct timespec *diff, const struct timespec *left, + const struct timespec *right) +{ + diff->tv_sec = left->tv_sec - right->tv_sec; + diff->tv_nsec = left->tv_nsec - right->tv_nsec; + + if (diff->tv_nsec < 0) + { + --diff->tv_sec; + diff->tv_nsec += 1000000000; + } +} + + +/* We need one of the list functions in the other modules. */ +static inline void +list_unlink_ip (struct list_links *list) +{ + struct list_links *lnext = list->next, *lprev = list->prev; + + lnext->prev = lprev; + lprev->next = lnext; + + /* The suffix ip means idempotent; list_unlink_ip can be called + * two or more times on the same node. + */ + + list->next = list; + list->prev = list; +} + + +/* Functions in the helper file. */ +extern void __timer_mutex_cancel_handler (void *arg); +extern void __timer_init_once (void); +extern struct timer_node *__timer_alloc (void); +extern int __timer_thread_start (struct thread_node *thread); +extern struct thread_node *__timer_thread_find_matching (const pthread_attr_t *desired_attr, clockid_t); +extern struct thread_node *__timer_thread_alloc (const pthread_attr_t *desired_attr, clockid_t); +extern void __timer_thread_dealloc (struct thread_node *thread); +extern int __timer_thread_queue_timer (struct thread_node *thread, + struct timer_node *insert); +extern void __timer_thread_wakeup (struct thread_node *thread); diff --git a/libpthread/nptl/sysdeps/pthread/pt-initfini.c b/libpthread/nptl/sysdeps/pthread/pt-initfini.c new file mode 100644 index 000000000..5955a7efc --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pt-initfini.c @@ -0,0 +1,125 @@ +/* Special .init and .fini section support. Linuxthread version. + Copyright (C) 1995,1996,1997,2000,2001,2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it + and/or modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + In addition to the permissions in the GNU Lesser General Public + License, the Free Software Foundation gives you unlimited + permission to link the compiled version of this file with other + programs, and to distribute those programs without any restriction + coming from the use of this file. (The Library General Public + License restrictions do apply in other respects; for example, they + cover modification of the file, and distribution when not linked + into another program.) + + The GNU C Library is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* This file is compiled into assembly code which is then munged by a sed + script into two files: crti.s and crtn.s. + + * crti.s puts a function prologue at the beginning of the + .init and .fini sections and defines global symbols for + those addresses, so they can be called as functions. + + * crtn.s puts the corresponding function epilogues + in the .init and .fini sections. */ + +#include <stdlib.h> + +/* We use embedded asm for .section unconditionally, as this makes it + easier to insert the necessary directives into crtn.S. */ +#define SECTION(x) __asm__ (".section " x ) + +/* Embed an #include to pull in the alignment and .end directives. */ +asm ("\n#include \"defs.h\""); + +/* The initial common code ends here. */ +asm ("\n/*@HEADER_ENDS*/"); + +/* To determine whether we need .end and .align: */ +asm ("\n/*@TESTS_BEGIN*/"); +extern void dummy (void (*foo) (void)); +void +dummy (void (*foo) (void)) +{ + if (foo) + (*foo) (); +} +asm ("\n/*@TESTS_END*/"); + +/* The beginning of _init: */ +asm ("\n/*@_init_PROLOG_BEGINS*/"); + +static void +call_initialize_minimal (void) +{ + extern void __pthread_initialize_minimal_internal (void) + __attribute ((visibility ("hidden"))); + + __pthread_initialize_minimal_internal (); +} + +SECTION (".init"); +extern void _init (void); +void +_init (void) +{ + /* The very first thing we must do is to set up the registers. */ + call_initialize_minimal (); + + asm ("ALIGN"); + asm("END_INIT"); + /* Now the epilog. */ + asm ("\n/*@_init_PROLOG_ENDS*/"); + asm ("\n/*@_init_EPILOG_BEGINS*/"); + SECTION(".init"); +} +asm ("END_INIT"); + +/* End of the _init epilog, beginning of the _fini prolog. */ +asm ("\n/*@_init_EPILOG_ENDS*/"); +asm ("\n/*@_fini_PROLOG_BEGINS*/"); + +SECTION (".fini"); +extern void _fini (void); +void +_fini (void) +{ + + /* End of the _fini prolog. */ + asm ("ALIGN"); + asm ("END_FINI"); + asm ("\n/*@_fini_PROLOG_ENDS*/"); + + { + /* Let GCC know that _fini is not a leaf function by having a dummy + function call here. We arrange for this call to be omitted from + either crt file. */ + extern void i_am_not_a_leaf (void); + i_am_not_a_leaf (); + } + + /* Beginning of the _fini epilog. */ + asm ("\n/*@_fini_EPILOG_BEGINS*/"); + SECTION (".fini"); +} +asm ("END_FINI"); + +/* End of the _fini epilog. Any further generated assembly (e.g. .ident) + is shared between both crt files. */ +asm ("\n/*@_fini_EPILOG_ENDS*/"); +asm ("\n/*@TRAILER_BEGINS*/"); + +/* End of file. */ diff --git a/libpthread/nptl/sysdeps/pthread/pt-longjmp.c b/libpthread/nptl/sysdeps/pthread/pt-longjmp.c new file mode 100644 index 000000000..b4106fdba --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pt-longjmp.c @@ -0,0 +1,31 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <setjmp.h> +#include <stdlib.h> +#include "pthreadP.h" + +extern void __libc_longjmp (sigjmp_buf env, int val) + __attribute__ ((noreturn)); +void +longjmp (jmp_buf env, int val) +{ + __libc_longjmp (env, val); +} +weak_alias (longjmp, siglongjmp) diff --git a/libpthread/nptl/sysdeps/pthread/pthread-functions.h b/libpthread/nptl/sysdeps/pthread/pthread-functions.h new file mode 100644 index 000000000..813d55621 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pthread-functions.h @@ -0,0 +1,107 @@ +/* Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _PTHREAD_FUNCTIONS_H +#define _PTHREAD_FUNCTIONS_H 1 + +#include <pthread.h> +#include <setjmp.h> +#include <internaltypes.h> + +struct xid_command; + +/* Data type shared with libc. The libc uses it to pass on calls to + the thread functions. */ +struct pthread_functions +{ + int (*ptr_pthread_attr_destroy) (pthread_attr_t *); + int (*ptr___pthread_attr_init_2_0) (pthread_attr_t *); + int (*ptr___pthread_attr_init_2_1) (pthread_attr_t *); + int (*ptr_pthread_attr_getdetachstate) (const pthread_attr_t *, int *); + int (*ptr_pthread_attr_setdetachstate) (pthread_attr_t *, int); + int (*ptr_pthread_attr_getinheritsched) (const pthread_attr_t *, int *); + int (*ptr_pthread_attr_setinheritsched) (pthread_attr_t *, int); + int (*ptr_pthread_attr_getschedparam) (const pthread_attr_t *, + struct sched_param *); + int (*ptr_pthread_attr_setschedparam) (pthread_attr_t *, + const struct sched_param *); + int (*ptr_pthread_attr_getschedpolicy) (const pthread_attr_t *, int *); + int (*ptr_pthread_attr_setschedpolicy) (pthread_attr_t *, int); + int (*ptr_pthread_attr_getscope) (const pthread_attr_t *, int *); + int (*ptr_pthread_attr_setscope) (pthread_attr_t *, int); + int (*ptr_pthread_condattr_destroy) (pthread_condattr_t *); + int (*ptr_pthread_condattr_init) (pthread_condattr_t *); + int (*ptr___pthread_cond_broadcast) (pthread_cond_t *); + int (*ptr___pthread_cond_destroy) (pthread_cond_t *); + int (*ptr___pthread_cond_init) (pthread_cond_t *, + const pthread_condattr_t *); + int (*ptr___pthread_cond_signal) (pthread_cond_t *); + int (*ptr___pthread_cond_wait) (pthread_cond_t *, pthread_mutex_t *); + int (*ptr___pthread_cond_timedwait) (pthread_cond_t *, pthread_mutex_t *, + const struct timespec *); + int (*ptr___pthread_cond_broadcast_2_0) (pthread_cond_2_0_t *); + int (*ptr___pthread_cond_destroy_2_0) (pthread_cond_2_0_t *); + int (*ptr___pthread_cond_init_2_0) (pthread_cond_2_0_t *, + const pthread_condattr_t *); + int (*ptr___pthread_cond_signal_2_0) (pthread_cond_2_0_t *); + int (*ptr___pthread_cond_wait_2_0) (pthread_cond_2_0_t *, pthread_mutex_t *); + int (*ptr___pthread_cond_timedwait_2_0) (pthread_cond_2_0_t *, + pthread_mutex_t *, + const struct timespec *); + int (*ptr_pthread_equal) (pthread_t, pthread_t); + void (*ptr___pthread_exit) (void *); + int (*ptr_pthread_getschedparam) (pthread_t, int *, struct sched_param *); + int (*ptr_pthread_setschedparam) (pthread_t, int, + const struct sched_param *); + int (*ptr_pthread_mutex_destroy) (pthread_mutex_t *); + int (*ptr_pthread_mutex_init) (pthread_mutex_t *, + const pthread_mutexattr_t *); + int (*ptr_pthread_mutex_trylock) (pthread_mutex_t *); + int (*ptr_pthread_mutex_lock) (pthread_mutex_t *); + int (*ptr_pthread_mutex_unlock) (pthread_mutex_t *); + int (*ptr_pthread_mutexattr_init) (pthread_mutexattr_t *attr); + int (*ptr_pthread_mutexattr_destroy) (pthread_mutexattr_t *attr); + int (*ptr_pthread_mutexattr_settype) (pthread_mutexattr_t *attr, int kind); + 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 *); +}; + +/* Variable in libc.so. */ +extern struct pthread_functions __libc_pthread_functions attribute_hidden; + +#endif /* pthread-functions.h */ diff --git a/libpthread/nptl/sysdeps/pthread/pthread.h b/libpthread/nptl/sysdeps/pthread/pthread.h new file mode 100644 index 000000000..c4bfc0e81 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pthread.h @@ -0,0 +1,976 @@ +/* Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _PTHREAD_H +#define _PTHREAD_H 1 + +#include <features.h> +#include <sched.h> +#include <time.h> + +#define __need_sigset_t +#include <signal.h> +#include <bits/pthreadtypes.h> +#include <bits/setjmp.h> +#include <bits/wordsize.h> +#if defined _LIBC && ( defined IS_IN_libc || defined NOT_IN_libc ) +#include <bits/uClibc_pthread.h> +#endif + + +/* Detach state. */ +enum +{ + PTHREAD_CREATE_JOINABLE, +#define PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_JOINABLE + PTHREAD_CREATE_DETACHED +#define PTHREAD_CREATE_DETACHED PTHREAD_CREATE_DETACHED +}; + + +/* Mutex types. */ +enum +{ + PTHREAD_MUTEX_TIMED_NP, + PTHREAD_MUTEX_RECURSIVE_NP, + PTHREAD_MUTEX_ERRORCHECK_NP, + PTHREAD_MUTEX_ADAPTIVE_NP +#ifdef __USE_UNIX98 + , + 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 +}; + +/* Mutex initializers. */ +#if __WORDSIZE == 64 +# define PTHREAD_MUTEX_INITIALIZER \ + { { 0, 0, 0, 0, 0, 0, { 0, 0 } } } +# ifdef __USE_GNU +# define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP \ + { { 0, 0, 0, 0, PTHREAD_MUTEX_RECURSIVE_NP, 0, { 0, 0 } } } +# define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP \ + { { 0, 0, 0, 0, PTHREAD_MUTEX_ERRORCHECK_NP, 0, { 0, 0 } } } +# define PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP \ + { { 0, 0, 0, 0, PTHREAD_MUTEX_ADAPTIVE_NP, 0, { 0, 0 } } } +# endif +#else +# define PTHREAD_MUTEX_INITIALIZER \ + { { 0, 0, 0, 0, 0, { 0 } } } +# ifdef __USE_GNU +# define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP \ + { { 0, 0, 0, PTHREAD_MUTEX_RECURSIVE_NP, 0, { 0 } } } +# define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP \ + { { 0, 0, 0, PTHREAD_MUTEX_ERRORCHECK_NP, 0, { 0 } } } +# define PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP \ + { { 0, 0, 0, PTHREAD_MUTEX_ADAPTIVE_NP, 0, { 0 } } } +# endif +#endif + +/* Read-write lock types. */ +#if defined __USE_UNIX98 || defined __USE_XOPEN2K +enum +{ + PTHREAD_RWLOCK_PREFER_READER_NP, + PTHREAD_RWLOCK_PREFER_WRITER_NP, + PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP, + PTHREAD_RWLOCK_DEFAULT_NP = PTHREAD_RWLOCK_PREFER_READER_NP +}; + +/* Read-write lock initializers. */ +# if __WORDSIZE == 64 +# define PTHREAD_RWLOCK_INITIALIZER \ + { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } +# else +# define PTHREAD_RWLOCK_INITIALIZER \ + { { 0, 0, 0, 0, 0, 0, 0, 0 } } +# endif +# ifdef __USE_GNU +# if __WORDSIZE == 64 +# define PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP \ + { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ + PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP } } +# else +# define PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP \ + { { 0, 0, 0, 0, 0, 0, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP, 0 } } +# endif +# endif +#endif /* Unix98 or XOpen2K */ + + +/* Scheduler inheritance. */ +enum +{ + PTHREAD_INHERIT_SCHED, +#define PTHREAD_INHERIT_SCHED PTHREAD_INHERIT_SCHED + PTHREAD_EXPLICIT_SCHED +#define PTHREAD_EXPLICIT_SCHED PTHREAD_EXPLICIT_SCHED +}; + + +/* Scope handling. */ +enum +{ + PTHREAD_SCOPE_SYSTEM, +#define PTHREAD_SCOPE_SYSTEM PTHREAD_SCOPE_SYSTEM + PTHREAD_SCOPE_PROCESS +#define PTHREAD_SCOPE_PROCESS PTHREAD_SCOPE_PROCESS +}; + + +/* Process shared or private flag. */ +enum +{ + PTHREAD_PROCESS_PRIVATE, +#define PTHREAD_PROCESS_PRIVATE PTHREAD_PROCESS_PRIVATE + PTHREAD_PROCESS_SHARED +#define PTHREAD_PROCESS_SHARED PTHREAD_PROCESS_SHARED +}; + + + +/* Conditional variable handling. */ +#define PTHREAD_COND_INITIALIZER { { 0, 0, 0, 0, 0, (void *) 0, 0, 0 } } + + +/* Cleanup buffers */ +struct _pthread_cleanup_buffer +{ + void (*__routine) (void *); /* Function to call. */ + void *__arg; /* Its argument. */ + int __canceltype; /* Saved cancellation type. */ + struct _pthread_cleanup_buffer *__prev; /* Chaining of cleanup functions. */ +}; + +/* Cancellation */ +enum +{ + PTHREAD_CANCEL_ENABLE, +#define PTHREAD_CANCEL_ENABLE PTHREAD_CANCEL_ENABLE + PTHREAD_CANCEL_DISABLE +#define PTHREAD_CANCEL_DISABLE PTHREAD_CANCEL_DISABLE +}; +enum +{ + PTHREAD_CANCEL_DEFERRED, +#define PTHREAD_CANCEL_DEFERRED PTHREAD_CANCEL_DEFERRED + PTHREAD_CANCEL_ASYNCHRONOUS +#define PTHREAD_CANCEL_ASYNCHRONOUS PTHREAD_CANCEL_ASYNCHRONOUS +}; +#define PTHREAD_CANCELED ((void *) -1) + + +/* Single execution handling. */ +#define PTHREAD_ONCE_INIT 0 + + +#ifdef __USE_XOPEN2K +/* Value returned by 'pthread_barrier_wait' for one of the threads after + the required number of threads have called this function. + -1 is distinct from 0 and all errno constants */ +# define PTHREAD_BARRIER_SERIAL_THREAD -1 +#endif + + +__BEGIN_DECLS + +/* Create a new thread, starting with execution of START-ROUTINE + getting passed ARG. Creation attributed come from ATTR. The new + handle is stored in *NEWTHREAD. */ +extern int pthread_create (pthread_t *__restrict __newthread, + __const pthread_attr_t *__restrict __attr, + void *(*__start_routine) (void *), + void *__restrict __arg) __THROW; + +/* Terminate calling thread. + + The registered cleanup handlers are called via exception handling + so we cannot mark this function with __THROW.*/ +extern void pthread_exit (void *__retval) __attribute__ ((__noreturn__)); + +/* Make calling thread wait for termination of the thread TH. The + exit status of the thread is stored in *THREAD_RETURN, if THREAD_RETURN + is not NULL. + + This function is a cancellation point and therefore not marked with + __THROW. */ +extern int pthread_join (pthread_t __th, void **__thread_return); + +#ifdef __USE_GNU +/* Check whether thread TH has terminated. If yes return the status of + the thread in *THREAD_RETURN, if THREAD_RETURN is not NULL. */ +extern int pthread_tryjoin_np (pthread_t __th, void **__thread_return) __THROW; + +/* Make calling thread wait for termination of the thread TH, but only + until TIMEOUT. The exit status of the thread is stored in + *THREAD_RETURN, if THREAD_RETURN is not NULL. + + This function is a cancellation point and therefore not marked with + __THROW. */ +extern int pthread_timedjoin_np (pthread_t __th, void **__thread_return, + __const struct timespec *__abstime); +#endif + +/* Indicate that the thread TH is never to be joined with PTHREAD_JOIN. + The resources of TH will therefore be freed immediately when it + terminates, instead of waiting for another thread to perform PTHREAD_JOIN + on it. */ +extern int pthread_detach (pthread_t __th) __THROW; + + +/* Obtain the identifier of the current thread. */ +extern pthread_t pthread_self (void) __THROW __attribute__ ((__const__)); + +/* Compare two thread identifiers. */ +extern int pthread_equal (pthread_t __thread1, pthread_t __thread2) __THROW; + + +/* Thread attribute handling. */ + +/* Initialize thread attribute *ATTR with default attributes + (detachstate is PTHREAD_JOINABLE, scheduling policy is SCHED_OTHER, + no user-provided stack). */ +extern int pthread_attr_init (pthread_attr_t *__attr) __THROW; + +/* Destroy thread attribute *ATTR. */ +extern int pthread_attr_destroy (pthread_attr_t *__attr) __THROW; + +/* Get detach state attribute. */ +extern int pthread_attr_getdetachstate (__const pthread_attr_t *__attr, + int *__detachstate) __THROW; + +/* Set detach state attribute. */ +extern int pthread_attr_setdetachstate (pthread_attr_t *__attr, + int __detachstate) __THROW; + + +/* 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; + +/* 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; + + +/* 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; + +/* 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; + +/* Return in *POLICY the scheduling policy of *ATTR. */ +extern int pthread_attr_getschedpolicy (__const pthread_attr_t *__restrict + __attr, int *__restrict __policy) + __THROW; + +/* Set scheduling policy in *ATTR according to POLICY. */ +extern int pthread_attr_setschedpolicy (pthread_attr_t *__attr, int __policy) + __THROW; + +/* Return in *INHERIT the scheduling inheritance mode of *ATTR. */ +extern int pthread_attr_getinheritsched (__const pthread_attr_t *__restrict + __attr, int *__restrict __inherit) + __THROW; + +/* Set scheduling inheritance mode in *ATTR according to INHERIT. */ +extern int pthread_attr_setinheritsched (pthread_attr_t *__attr, + int __inherit) __THROW; + + +/* Return in *SCOPE the scheduling contention scope of *ATTR. */ +extern int pthread_attr_getscope (__const pthread_attr_t *__restrict __attr, + int *__restrict __scope) __THROW; + +/* Set scheduling contention scope in *ATTR according to SCOPE. */ +extern int pthread_attr_setscope (pthread_attr_t *__attr, int __scope) + __THROW; + +/* Return the previously set address for the stack. */ +extern int pthread_attr_getstackaddr (__const pthread_attr_t *__restrict + __attr, void **__restrict __stackaddr) + __THROW __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 __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; + +/* 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; + +#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; + +/* 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; +#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; + +/* 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; + + +/* Initialize thread attribute *ATTR with attributes corresponding to the + already running thread TH. It shall be called on unitialized ATTR + and destroyed with pthread_attr_destroy when no longer needed. */ +extern int pthread_getattr_np (pthread_t __th, pthread_attr_t *__attr) __THROW; +#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; + +/* 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; + +/* Set the scheduling priority for TARGET_THREAD. */ +extern int pthread_setschedprio (pthread_t __target_thread, int __prio) + __THROW; + + +#ifdef __USE_UNIX98 +/* Determine level of concurrency. */ +extern int pthread_getconcurrency (void) __THROW; + +/* Set new concurrency level to LEVEL. */ +extern int pthread_setconcurrency (int __level) __THROW; +#endif + +#ifdef __USE_GNU +/* Yield the processor to another thread or process. + This function is similar to the POSIX `sched_yield' function but + might be differently implemented in the case of a m-on-n thread + implementation. */ +extern int pthread_yield (void) __THROW; + + +/* Limit specified thread TH to run only on the processors represented + in CPUSET. */ +extern int pthread_setaffinity_np (pthread_t __th, size_t __cpusetsize, + __const cpu_set_t *__cpuset) __THROW; + +/* 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; +#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)); + + +/* 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); + +__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 *) \ + __cancel_buf.__cancel_jmp_buf, 0); \ + if (__builtin_expect (not_first_call, 0)) \ + { \ + __cancel_routine (__cancel_arg); \ + __pthread_unwind_next (&__cancel_buf); \ + /* NOTREACHED */ \ + } \ + \ + __pthread_register_cancel (&__cancel_buf); \ + do { +extern void __pthread_register_cancel (__pthread_unwind_buf_t *__buf) + __cleanup_fct_attribute; + +/* Remove a cleanup handler installed by the matching pthread_cleanup_push. + If EXECUTE is non-zero, the handler function is called. */ +# define pthread_cleanup_pop(execute) \ + } 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 *) \ + __cancel_buf.__cancel_jmp_buf, 0); \ + if (__builtin_expect (not_first_call, 0)) \ + { \ + __cancel_routine (__cancel_arg); \ + __pthread_unwind_next (&__cancel_buf); \ + /* NOTREACHED */ \ + } \ + \ + __pthread_register_cancel_defer (&__cancel_buf); \ + do { +extern void __pthread_register_cancel_defer (__pthread_unwind_buf_t *__buf) + __cleanup_fct_attribute; + +/* Remove a cleanup handler as pthread_cleanup_pop does, but also + restores the cancellation type that was in effect when the matching + pthread_cleanup_push_defer was called. */ +# define pthread_cleanup_pop_restore_np(execute) \ + } while (0); \ + __pthread_unregister_cancel_restore (&__cancel_buf); \ + if (execute) \ + __cancel_routine (__cancel_arg); \ + } while (0) +extern void __pthread_unregister_cancel_restore (__pthread_unwind_buf_t *__buf) + __cleanup_fct_attribute; +# endif + +/* Internal interface to initiate cleanup. */ +extern void __pthread_unwind_next (__pthread_unwind_buf_t *__buf) + __cleanup_fct_attribute __attribute ((__noreturn__)) +# ifndef SHARED + __attribute ((__weak__)) +# endif + ; +#endif + +/* Function used in the macros. */ +struct __jmp_buf_tag; +extern int __sigsetjmp (struct __jmp_buf_tag *__env, int __savemask) __THROW; + + +/* Mutex handling. */ + +/* Initialize a mutex. */ +extern int pthread_mutex_init (pthread_mutex_t *__mutex, + __const pthread_mutexattr_t *__mutexattr) + __THROW; + +/* Destroy a mutex. */ +extern int pthread_mutex_destroy (pthread_mutex_t *__mutex) __THROW; + +/* Try locking a mutex. */ +extern int pthread_mutex_trylock (pthread_mutex_t *_mutex) __THROW; + +/* Lock a mutex. */ +extern int pthread_mutex_lock (pthread_mutex_t *__mutex) __THROW; + +#ifdef __USE_XOPEN2K +/* Wait until lock becomes available, or specified time passes. */ +extern int pthread_mutex_timedlock (pthread_mutex_t *__restrict __mutex, + __const struct timespec *__restrict + __abstime) __THROW; +#endif + +/* Unlock a mutex. */ +extern int pthread_mutex_unlock (pthread_mutex_t *__mutex) __THROW; + + +/* 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; + +/* Destroy mutex attribute object ATTR. */ +extern int pthread_mutexattr_destroy (pthread_mutexattr_t *__attr) __THROW; + +/* 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; + +/* Set the process-shared flag of the mutex attribute ATTR. */ +extern int pthread_mutexattr_setpshared (pthread_mutexattr_t *__attr, + int __pshared) __THROW; + +#ifdef __USE_UNIX98 +/* Return in *KIND the mutex kind attribute in *ATTR. */ +extern int pthread_mutexattr_gettype (__const pthread_mutexattr_t *__restrict + __attr, int *__restrict __kind) __THROW; + +/* 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; +#endif + + +#if defined __USE_UNIX98 || defined __USE_XOPEN2K +/* Functions for handling read-write locks. */ + +/* Initialize read-write lock RWLOCK using attributes ATTR, or use + the default values if later is NULL. */ +extern int pthread_rwlock_init (pthread_rwlock_t *__restrict __rwlock, + __const pthread_rwlockattr_t *__restrict + __attr) __THROW; + +/* Destroy read-write lock RWLOCK. */ +extern int pthread_rwlock_destroy (pthread_rwlock_t *__rwlock) __THROW; + +/* Acquire read lock for RWLOCK. */ +extern int pthread_rwlock_rdlock (pthread_rwlock_t *__rwlock) __THROW; + +/* Try to acquire read lock for RWLOCK. */ +extern int pthread_rwlock_tryrdlock (pthread_rwlock_t *__rwlock) __THROW; + +# ifdef __USE_XOPEN2K +/* Try to acquire read lock for RWLOCK or return after specfied time. */ +extern int pthread_rwlock_timedrdlock (pthread_rwlock_t *__restrict __rwlock, + __const struct timespec *__restrict + __abstime) __THROW; +# endif + +/* Acquire write lock for RWLOCK. */ +extern int pthread_rwlock_wrlock (pthread_rwlock_t *__rwlock) __THROW; + +/* Try to acquire write lock for RWLOCK. */ +extern int pthread_rwlock_trywrlock (pthread_rwlock_t *__rwlock) __THROW; + +# ifdef __USE_XOPEN2K +/* Try to acquire write lock for RWLOCK or return after specfied time. */ +extern int pthread_rwlock_timedwrlock (pthread_rwlock_t *__restrict __rwlock, + __const struct timespec *__restrict + __abstime) __THROW; +# endif + +/* Unlock RWLOCK. */ +extern int pthread_rwlock_unlock (pthread_rwlock_t *__rwlock) __THROW; + + +/* Functions for handling read-write lock attributes. */ + +/* Initialize attribute object ATTR with default values. */ +extern int pthread_rwlockattr_init (pthread_rwlockattr_t *__attr) __THROW; + +/* Destroy attribute object ATTR. */ +extern int pthread_rwlockattr_destroy (pthread_rwlockattr_t *__attr) __THROW; + +/* 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; + +/* Set process-shared attribute of ATTR to PSHARED. */ +extern int pthread_rwlockattr_setpshared (pthread_rwlockattr_t *__attr, + int __pshared) __THROW; + +/* Return current setting of reader/writer preference. */ +extern int pthread_rwlockattr_getkind_np (__const pthread_rwlockattr_t * + __restrict __attr, + int *__restrict __pref) __THROW; + +/* Set reader/write preference. */ +extern int pthread_rwlockattr_setkind_np (pthread_rwlockattr_t *__attr, + int __pref) __THROW; +#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; + +/* Destroy condition variable COND. */ +extern int pthread_cond_destroy (pthread_cond_t *__cond) __THROW; + +/* Wake up one thread waiting for condition variable COND. */ +extern int pthread_cond_signal (pthread_cond_t *__cond) __THROW; + +/* Wake up all threads waiting for condition variables COND. */ +extern int pthread_cond_broadcast (pthread_cond_t *__cond) __THROW; + +/* 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); + +/* 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); + +/* Functions for handling condition variable attributes. */ + +/* Initialize condition variable attribute ATTR. */ +extern int pthread_condattr_init (pthread_condattr_t *__attr) __THROW; + +/* Destroy condition variable attribute ATTR. */ +extern int pthread_condattr_destroy (pthread_condattr_t *__attr) __THROW; + +/* 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; + +/* Set the process-shared flag of the condition variable attribute ATTR. */ +extern int pthread_condattr_setpshared (pthread_condattr_t *__attr, + int __pshared) __THROW; + +#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; + +/* Set the clock selected for the conditon variable attribute ATTR. */ +extern int pthread_condattr_setclock (pthread_condattr_t *__attr, + __clockid_t __clock_id) __THROW; + +#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; + +/* Destroy the spinlock LOCK. */ +extern int pthread_spin_destroy (pthread_spinlock_t *__lock) __THROW; + +/* Wait until spinlock LOCK is retrieved. */ +extern int pthread_spin_lock (pthread_spinlock_t *__lock) __THROW; + +/* Try to lock spinlock LOCK. */ +extern int pthread_spin_trylock (pthread_spinlock_t *__lock) __THROW; + +/* Release spinlock LOCK. */ +extern int pthread_spin_unlock (pthread_spinlock_t *__lock) __THROW; + + +/* 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; + +/* Destroy a previously dynamically initialized barrier BARRIER. */ +extern int pthread_barrier_destroy (pthread_barrier_t *__barrier) __THROW; + +/* Wait on barrier BARRIER. */ +extern int pthread_barrier_wait (pthread_barrier_t *__barrier) __THROW; + + +/* Initialize barrier attribute ATTR. */ +extern int pthread_barrierattr_init (pthread_barrierattr_t *__attr) __THROW; + +/* Destroy previously dynamically initialized barrier attribute ATTR. */ +extern int pthread_barrierattr_destroy (pthread_barrierattr_t *__attr) __THROW; + +/* 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; + +/* Set the process-shared flag of the barrier attribute ATTR. */ +extern int pthread_barrierattr_setpshared (pthread_barrierattr_t *__attr, + int __pshared) __THROW; +#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; + +/* 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; +#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; + +__END_DECLS + +#endif /* pthread.h */ diff --git a/libpthread/nptl/sysdeps/pthread/pthread_barrier_wait.c b/libpthread/nptl/sysdeps/pthread/pthread_barrier_wait.c new file mode 100644 index 000000000..d21ed79b1 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pthread_barrier_wait.c @@ -0,0 +1,76 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <pthreadP.h> + + +/* Wait on barrier. */ +int +pthread_barrier_wait (pthread_barrier_t *barrier) +{ + struct pthread_barrier *ibarrier = (struct pthread_barrier *) barrier; + int result = 0; + + /* Make sure we are alone. */ + lll_lock (ibarrier->lock); + + /* 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); + + /* 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); + + /* Wait for the event counter of the barrier to change. */ + do + lll_futex_wait (&ibarrier->curr_event, event); + 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); + + return result; +} diff --git a/libpthread/nptl/sysdeps/pthread/pthread_cond_broadcast.c b/libpthread/nptl/sysdeps/pthread/pthread_cond_broadcast.c new file mode 100644 index 000000000..f6e83ed3f --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pthread_cond_broadcast.c @@ -0,0 +1,75 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <endian.h> +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <pthread.h> +#include <pthreadP.h> +#include <bits/kernel-features.h> + + +int +__pthread_cond_broadcast (pthread_cond_t *cond) +{ + /* Make sure we are alone. */ + lll_mutex_lock (cond->__data.__lock); + + /* 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_mutex_unlock (cond->__data.__lock); + + /* Do not use requeue for pshared condvars. */ + if (cond->__data.__mutex == (void *) ~0l) + goto wake_all; + + /* Wake everybody. */ + pthread_mutex_t *mut = (pthread_mutex_t *) cond->__data.__mutex; + /* 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), 0)) + { + /* The requeue functionality is not available. */ + wake_all: + lll_futex_wake (&cond->__data.__futex, INT_MAX); + } + + /* That's all. */ + return 0; + } + + /* We are done. */ + lll_mutex_unlock (cond->__data.__lock); + + return 0; +} +weak_alias(__pthread_cond_broadcast, pthread_cond_broadcast) diff --git a/libpthread/nptl/sysdeps/pthread/pthread_cond_signal.c b/libpthread/nptl/sysdeps/pthread/pthread_cond_signal.c new file mode 100644 index 000000000..5091bea87 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pthread_cond_signal.c @@ -0,0 +1,51 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <endian.h> +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <pthread.h> +#include <pthreadP.h> +#include <bits/kernel-features.h> + + +int +__pthread_cond_signal (pthread_cond_t *cond) +{ + /* Make sure we are alone. */ + lll_mutex_lock (cond->__data.__lock); + + /* Are there any waiters to be woken? */ + if (cond->__data.__total_seq > cond->__data.__wakeup_seq) + { + /* Yes. Mark one of them as woken. */ + ++cond->__data.__wakeup_seq; + ++cond->__data.__futex; + + /* Wake one. */ + lll_futex_wake (&cond->__data.__futex, 1); + } + + /* We are done. */ + lll_mutex_unlock (cond->__data.__lock); + + return 0; +} +weak_alias(__pthread_cond_signal, pthread_cond_signal) diff --git a/libpthread/nptl/sysdeps/pthread/pthread_cond_timedwait.c b/libpthread/nptl/sysdeps/pthread/pthread_cond_timedwait.c new file mode 100644 index 000000000..1f4136e70 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pthread_cond_timedwait.c @@ -0,0 +1,210 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <endian.h> +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <pthread.h> +#include <pthreadP.h> + + +/* 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; + + /* Make sure we are along. */ + lll_mutex_lock (cond->__data.__lock); + + /* Now we can release the mutex. */ + int err = __pthread_mutex_unlock_usercnt (mutex, 0); + if (err) + { + lll_mutex_unlock (cond->__data.__lock); + return err; + } + + /* We have one new user of the condvar. */ + ++cond->__data.__total_seq; + ++cond->__data.__futex; + cond->__data.__nwaiters += 1 << COND_CLOCK_BITS; + + /* Remember the mutex we are using here. If there is already a + different address store this is a bad user bug. Do not store + anything for pshared condvars. */ + if (cond->__data.__mutex != (void *) ~0l) + cond->__data.__mutex = mutex; + + /* Prepare structure passed to cancellation handler. */ + cbuffer.cond = cond; + cbuffer.mutex = mutex; + + /* Before we block we enable cancellation. Therefore we have to + install a cancellation handler. */ + __pthread_cleanup_push (&buffer, __condvar_cleanup, &cbuffer); + + /* The current values of the wakeup counter. The "woken" counter + must exceed this value. */ + unsigned long long int val; + unsigned long long int seq; + val = seq = cond->__data.__wakeup_seq; + /* Remember the broadcast counter. */ + cbuffer.bc_seq = cond->__data.__broadcast_seq; + + while (1) + { + struct timespec rt; + { +#ifdef __NR_clock_gettime + INTERNAL_SYSCALL_DECL (err); + int ret; + ret = INTERNAL_SYSCALL (clock_gettime, err, 2, + (cond->__data.__nwaiters + & ((1 << COND_CLOCK_BITS) - 1)), + &rt); +# ifndef __ASSUME_POSIX_TIMERS + if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (ret, err), 0)) + { + struct timeval tv; + (void) gettimeofday (&tv, NULL); + + /* Convert the absolute timeout value to a relative timeout. */ + rt.tv_sec = abstime->tv_sec - tv.tv_sec; + rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000; + } + else +# endif + { + /* Convert the absolute timeout value to a relative timeout. */ + rt.tv_sec = abstime->tv_sec - rt.tv_sec; + rt.tv_nsec = abstime->tv_nsec - rt.tv_nsec; + } +#else + /* Get the current time. So far we support only one clock. */ + struct timeval tv; + (void) gettimeofday (&tv, NULL); + + /* Convert the absolute timeout value to a relative timeout. */ + rt.tv_sec = abstime->tv_sec - tv.tv_sec; + rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000; +#endif + } + if (rt.tv_nsec < 0) + { + rt.tv_nsec += 1000000000; + --rt.tv_sec; + } + /* Did we already time out? */ + if (__builtin_expect (rt.tv_sec < 0, 0)) + { + if (cbuffer.bc_seq != cond->__data.__broadcast_seq) + goto bc_out; + + goto timeout; + } + + unsigned int futex_val = cond->__data.__futex; + + /* Prepare to wait. Release the condvar futex. */ + lll_mutex_unlock (cond->__data.__lock); + + /* Enable asynchronous cancellation. Required by the standard. */ + cbuffer.oldtype = __pthread_enable_asynccancel (); + + /* Wait until woken by signal or broadcast. */ + err = lll_futex_timed_wait (&cond->__data.__futex, + futex_val, &rt); + + /* Disable asynchronous cancellation. */ + __pthread_disable_asynccancel (cbuffer.oldtype); + + /* We are going to look at shared data again, so get the lock. */ + lll_mutex_lock(cond->__data.__lock); + + /* If a broadcast happened, we are done. */ + if (cbuffer.bc_seq != cond->__data.__broadcast_seq) + goto bc_out; + + /* Check whether we are eligible for wakeup. */ + val = cond->__data.__wakeup_seq; + if (val != seq && cond->__data.__woken_seq != val) + break; + + /* Not woken yet. Maybe the time expired? */ + if (__builtin_expect (err == -ETIMEDOUT, 0)) + { + timeout: + /* Yep. Adjust the counters. */ + ++cond->__data.__wakeup_seq; + ++cond->__data.__futex; + + /* The error value. */ + result = ETIMEDOUT; + break; + } + } + + /* Another thread woken up. */ + ++cond->__data.__woken_seq; + + bc_out: + + cond->__data.__nwaiters -= 1 << COND_CLOCK_BITS; + + /* 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_CLOCK_BITS)) + lll_futex_wake (&cond->__data.__nwaiters, 1); + + /* We are done with the condvar. */ + lll_mutex_unlock (cond->__data.__lock); + + /* The cancellation handling is back to normal, remove the handler. */ + __pthread_cleanup_pop (&buffer, 0); + + /* Get the mutex before returning. */ + err = __pthread_mutex_cond_lock (mutex); + + return err ?: result; +} +weak_alias(__pthread_cond_timedwait, pthread_cond_timedwait) diff --git a/libpthread/nptl/sysdeps/pthread/pthread_cond_wait.c b/libpthread/nptl/sysdeps/pthread/pthread_cond_wait.c new file mode 100644 index 000000000..79245b7c1 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pthread_cond_wait.c @@ -0,0 +1,181 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <endian.h> +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <pthread.h> +#include <pthreadP.h> + + +struct _condvar_cleanup_buffer +{ + int oldtype; + pthread_cond_t *cond; + pthread_mutex_t *mutex; + unsigned int bc_seq; +}; + + +void +__attribute__ ((visibility ("hidden"))) +__condvar_cleanup (void *arg) +{ + struct _condvar_cleanup_buffer *cbuffer = + (struct _condvar_cleanup_buffer *) arg; + unsigned int destroying; + + /* We are going to modify shared data. */ + lll_mutex_lock (cbuffer->cond->__data.__lock); + + if (cbuffer->bc_seq == cbuffer->cond->__data.__broadcast_seq) + { + /* This thread is not waiting anymore. Adjust the sequence counters + appropriately. */ + ++cbuffer->cond->__data.__wakeup_seq; + ++cbuffer->cond->__data.__woken_seq; + ++cbuffer->cond->__data.__futex; + } + + cbuffer->cond->__data.__nwaiters -= 1 << COND_CLOCK_BITS; + + /* 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_CLOCK_BITS)) + { + lll_futex_wake (&cbuffer->cond->__data.__nwaiters, 1); + destroying = 1; + } + + /* We are done. */ + lll_mutex_unlock (cbuffer->cond->__data.__lock); + + /* Wake everybody to make sure no condvar signal gets lost. */ + if (! destroying) + lll_futex_wake (&cbuffer->cond->__data.__futex, INT_MAX); + + /* Get the mutex before returning unless asynchronous cancellation + is in effect. */ + __pthread_mutex_cond_lock (cbuffer->mutex); +} + + +int +__pthread_cond_wait ( + pthread_cond_t *cond, + pthread_mutex_t *mutex) +{ + struct _pthread_cleanup_buffer buffer; + struct _condvar_cleanup_buffer cbuffer; + int err; + + /* Make sure we are along. */ + lll_mutex_lock (cond->__data.__lock); + + /* Now we can release the mutex. */ + err = __pthread_mutex_unlock_usercnt (mutex, 0); + if (__builtin_expect (err, 0)) + { + lll_mutex_unlock (cond->__data.__lock); + return err; + } + + /* We have one new user of the condvar. */ + ++cond->__data.__total_seq; + ++cond->__data.__futex; + cond->__data.__nwaiters += 1 << COND_CLOCK_BITS; + + /* 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_mutex_unlock (cond->__data.__lock); + + /* Enable asynchronous cancellation. Required by the standard. */ + cbuffer.oldtype = __pthread_enable_asynccancel (); + + /* Wait until woken by signal or broadcast. */ + lll_futex_wait (&cond->__data.__futex, futex_val); + + /* Disable asynchronous cancellation. */ + __pthread_disable_asynccancel (cbuffer.oldtype); + + /* We are going to look at shared data again, so get the lock. */ + lll_mutex_lock (cond->__data.__lock); + + /* 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_CLOCK_BITS; + + /* 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_CLOCK_BITS)) + lll_futex_wake (&cond->__data.__nwaiters, 1); + + /* We are done with the condvar. */ + lll_mutex_unlock (cond->__data.__lock); + + /* The cancellation handling is back to normal, remove the handler. */ + __pthread_cleanup_pop (&buffer, 0); + + /* Get the mutex before returning. */ + return __pthread_mutex_cond_lock (mutex); +} +weak_alias(__pthread_cond_wait, pthread_cond_wait) diff --git a/libpthread/nptl/sysdeps/pthread/pthread_once.c b/libpthread/nptl/sysdeps/pthread/pthread_once.c new file mode 100644 index 000000000..fc16bc535 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pthread_once.c @@ -0,0 +1,54 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" +#include <lowlevellock.h> + + + +static lll_lock_t once_lock = LLL_LOCK_INITIALIZER; + + +int +__pthread_once ( + pthread_once_t *once_control, + void (*init_routine) (void)) +{ + /* XXX Depending on whether the LOCK_IN_ONCE_T is defined use a + global lock variable or one which is part of the pthread_once_t + object. */ + if (*once_control == PTHREAD_ONCE_INIT) + { + lll_lock (once_lock); + + /* 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); + } + + return 0; +} +strong_alias (__pthread_once, pthread_once) diff --git a/libpthread/nptl/sysdeps/pthread/pthread_rwlock_rdlock.c b/libpthread/nptl/sysdeps/pthread/pthread_rwlock_rdlock.c new file mode 100644 index 000000000..2fdcc49f9 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pthread_rwlock_rdlock.c @@ -0,0 +1,94 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <pthread.h> +#include <pthreadP.h> + + +/* Acquire read lock for RWLOCK. */ +int +__pthread_rwlock_rdlock (pthread_rwlock_t *rwlock) +{ + int result = 0; + + /* Make sure we are along. */ + lll_mutex_lock (rwlock->__data.__lock); + + 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 + || rwlock->__data.__flags == 0)) + { + /* Increment the reader counter. Avoid overflow. */ + if (__builtin_expect (++rwlock->__data.__nr_readers == 0, 0)) + { + /* Overflow on number of readers. */ + --rwlock->__data.__nr_readers; + result = EAGAIN; + } + + break; + } + + /* Make sure we are not holding the rwlock as a writer. This is + a deadlock situation we recognize and report. */ + if (__builtin_expect (rwlock->__data.__writer + == THREAD_GETMEM (THREAD_SELF, tid), 0)) + { + result = EDEADLK; + break; + } + + /* Remember that we are a reader. */ + if (__builtin_expect (++rwlock->__data.__nr_readers_queued == 0, 0)) + { + /* Overflow on number of queued readers. */ + --rwlock->__data.__nr_readers_queued; + result = EAGAIN; + break; + } + + int waitval = rwlock->__data.__readers_wakeup; + + /* Free the lock. */ + lll_mutex_unlock (rwlock->__data.__lock); + + /* Wait for the writer to finish. */ + lll_futex_wait (&rwlock->__data.__readers_wakeup, waitval); + + /* Get the lock. */ + lll_mutex_lock (rwlock->__data.__lock); + + --rwlock->__data.__nr_readers_queued; + } + + /* We are done, free the lock. */ + lll_mutex_unlock (rwlock->__data.__lock); + + return result; +} + +weak_alias (__pthread_rwlock_rdlock, pthread_rwlock_rdlock) +strong_alias (__pthread_rwlock_rdlock, __pthread_rwlock_rdlock_internal) diff --git a/libpthread/nptl/sysdeps/pthread/pthread_rwlock_timedrdlock.c b/libpthread/nptl/sysdeps/pthread/pthread_rwlock_timedrdlock.c new file mode 100644 index 000000000..8503788c2 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pthread_rwlock_timedrdlock.c @@ -0,0 +1,137 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <pthread.h> +#include <pthreadP.h> + + +/* Try to acquire read lock for RWLOCK or return after specfied time. */ +int +pthread_rwlock_timedrdlock ( + pthread_rwlock_t *rwlock, + const struct timespec *abstime) +{ + int result = 0; + + /* Make sure we are along. */ + lll_mutex_lock(rwlock->__data.__lock); + + 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 + || rwlock->__data.__flags == 0)) + { + /* Increment the reader counter. Avoid overflow. */ + if (++rwlock->__data.__nr_readers == 0) + { + /* Overflow on number of readers. */ + --rwlock->__data.__nr_readers; + result = EAGAIN; + } + + break; + } + + /* Make sure we are not holding the rwlock as a writer. This is + a deadlock situation we recognize and report. */ + if (__builtin_expect (rwlock->__data.__writer + == THREAD_GETMEM (THREAD_SELF, tid), 0)) + { + result = EDEADLK; + break; + } + + /* Make sure the passed in timeout value is valid. Ideally this + test would be executed once. But since it must not be + performed if we would not block at all simply moving the test + to the front is no option. Replicating all the code is + costly while this test is not. */ + if (__builtin_expect (abstime->tv_nsec >= 1000000000 + || abstime->tv_nsec < 0, 0)) + { + result = EINVAL; + break; + } + + /* Get the current time. So far we support only one clock. */ + struct timeval tv; + (void) gettimeofday (&tv, NULL); + + /* Convert the absolute timeout value to a relative timeout. */ + struct timespec rt; + rt.tv_sec = abstime->tv_sec - tv.tv_sec; + rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000; + if (rt.tv_nsec < 0) + { + rt.tv_nsec += 1000000000; + --rt.tv_sec; + } + /* Did we already time out? */ + if (rt.tv_sec < 0) + { + /* Yep, return with an appropriate error. */ + result = ETIMEDOUT; + break; + } + + /* Remember that we are a reader. */ + if (++rwlock->__data.__nr_readers_queued == 0) + { + /* Overflow on number of queued readers. */ + --rwlock->__data.__nr_readers_queued; + result = EAGAIN; + break; + } + + int waitval = rwlock->__data.__readers_wakeup; + + /* Free the lock. */ + lll_mutex_unlock (rwlock->__data.__lock); + + /* Wait for the writer to finish. */ + err = lll_futex_timed_wait (&rwlock->__data.__readers_wakeup, + waitval, &rt); + + /* Get the lock. */ + lll_mutex_lock (rwlock->__data.__lock); + + --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_mutex_unlock (rwlock->__data.__lock); + + return result; +} diff --git a/libpthread/nptl/sysdeps/pthread/pthread_rwlock_timedwrlock.c b/libpthread/nptl/sysdeps/pthread/pthread_rwlock_timedwrlock.c new file mode 100644 index 000000000..d9caa85bb --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pthread_rwlock_timedwrlock.c @@ -0,0 +1,127 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <pthread.h> +#include <pthreadP.h> + + +/* Try to acquire write lock for RWLOCK or return after specfied time. */ +int +pthread_rwlock_timedwrlock ( + pthread_rwlock_t *rwlock, + const struct timespec *abstime) +{ + int result = 0; + + /* Make sure we are along. */ + lll_mutex_lock (rwlock->__data.__lock); + + while (1) + { + int err; + + /* Get the rwlock if there is no writer and no reader. */ + if (rwlock->__data.__writer == 0 && rwlock->__data.__nr_readers == 0) + { + /* Mark self as writer. */ + rwlock->__data.__writer = THREAD_GETMEM (THREAD_SELF, tid); + break; + } + + /* Make sure we are not holding the rwlock as a writer. This is + a deadlock situation we recognize and report. */ + if (__builtin_expect (rwlock->__data.__writer + == THREAD_GETMEM (THREAD_SELF, tid), 0)) + { + result = EDEADLK; + break; + } + + /* Make sure the passed in timeout value is valid. Ideally this + test would be executed once. But since it must not be + performed if we would not block at all simply moving the test + to the front is no option. Replicating all the code is + costly while this test is not. */ + if (__builtin_expect (abstime->tv_nsec >= 1000000000 + || abstime->tv_nsec < 0, 0)) + { + result = EINVAL; + break; + } + + /* Get the current time. So far we support only one clock. */ + struct timeval tv; + (void) gettimeofday (&tv, NULL); + + /* Convert the absolute timeout value to a relative timeout. */ + struct timespec rt; + rt.tv_sec = abstime->tv_sec - tv.tv_sec; + rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000; + if (rt.tv_nsec < 0) + { + rt.tv_nsec += 1000000000; + --rt.tv_sec; + } + /* Did we already time out? */ + if (rt.tv_sec < 0) + { + result = ETIMEDOUT; + break; + } + + /* Remember that we are a writer. */ + if (++rwlock->__data.__nr_writers_queued == 0) + { + /* Overflow on number of queued writers. */ + --rwlock->__data.__nr_writers_queued; + result = EAGAIN; + break; + } + + int waitval = rwlock->__data.__writer_wakeup; + + /* Free the lock. */ + lll_mutex_unlock (rwlock->__data.__lock); + + /* Wait for the writer or reader(s) to finish. */ + err = lll_futex_timed_wait (&rwlock->__data.__writer_wakeup, + waitval, &rt); + + /* Get the lock. */ + lll_mutex_lock (rwlock->__data.__lock); + + /* 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_mutex_unlock (rwlock->__data.__lock); + + return result; +} diff --git a/libpthread/nptl/sysdeps/pthread/pthread_rwlock_unlock.c b/libpthread/nptl/sysdeps/pthread/pthread_rwlock_unlock.c new file mode 100644 index 000000000..9cae8b6c2 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pthread_rwlock_unlock.c @@ -0,0 +1,57 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <pthread.h> +#include <pthreadP.h> + +/* Unlock RWLOCK. */ +int +__pthread_rwlock_unlock (pthread_rwlock_t *rwlock) +{ + lll_mutex_lock (rwlock->__data.__lock); + 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_mutex_unlock (rwlock->__data.__lock); + lll_futex_wake (&rwlock->__data.__writer_wakeup, 1); + return 0; + } + else if (rwlock->__data.__nr_readers_queued) + { + ++rwlock->__data.__readers_wakeup; + lll_mutex_unlock (rwlock->__data.__lock); + lll_futex_wake (&rwlock->__data.__readers_wakeup, INT_MAX); + return 0; + } + } + lll_mutex_unlock (rwlock->__data.__lock); + return 0; +} + +weak_alias (__pthread_rwlock_unlock, pthread_rwlock_unlock) +strong_alias (__pthread_rwlock_unlock, __pthread_rwlock_unlock_internal) diff --git a/libpthread/nptl/sysdeps/pthread/pthread_rwlock_wrlock.c b/libpthread/nptl/sysdeps/pthread/pthread_rwlock_wrlock.c new file mode 100644 index 000000000..1b9186fb8 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pthread_rwlock_wrlock.c @@ -0,0 +1,86 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <pthread.h> +#include <pthreadP.h> + + +/* Acquire write lock for RWLOCK. */ +int +__pthread_rwlock_wrlock (pthread_rwlock_t *rwlock) +{ + int result = 0; + + /* Make sure we are along. */ + lll_mutex_lock (rwlock->__data.__lock); + + while (1) + { + /* Get the rwlock if there is no writer and no reader. */ + if (rwlock->__data.__writer == 0 && rwlock->__data.__nr_readers == 0) + { + /* Mark self as writer. */ + rwlock->__data.__writer = THREAD_GETMEM (THREAD_SELF, tid); + break; + } + + /* Make sure we are not holding the rwlock as a writer. This is + a deadlock situation we recognize and report. */ + if (__builtin_expect (rwlock->__data.__writer + == THREAD_GETMEM (THREAD_SELF, tid), 0)) + { + result = EDEADLK; + break; + } + + /* Remember that we are a writer. */ + if (++rwlock->__data.__nr_writers_queued == 0) + { + /* Overflow on number of queued writers. */ + --rwlock->__data.__nr_writers_queued; + result = EAGAIN; + break; + } + + int waitval = rwlock->__data.__writer_wakeup; + + /* Free the lock. */ + lll_mutex_unlock (rwlock->__data.__lock); + + /* Wait for the writer or reader(s) to finish. */ + lll_futex_wait (&rwlock->__data.__writer_wakeup, waitval); + + /* Get the lock. */ + lll_mutex_lock (rwlock->__data.__lock); + + /* To start over again, remove the thread from the writer list. */ + --rwlock->__data.__nr_writers_queued; + } + + /* We are done, free the lock. */ + lll_mutex_unlock (rwlock->__data.__lock); + + return result; +} + +weak_alias (__pthread_rwlock_wrlock, pthread_rwlock_wrlock) +strong_alias (__pthread_rwlock_wrlock, __pthread_rwlock_wrlock_internal) diff --git a/libpthread/nptl/sysdeps/pthread/pthread_sigmask.c b/libpthread/nptl/sysdeps/pthread/pthread_sigmask.c new file mode 100644 index 000000000..6f66bbbff --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pthread_sigmask.c @@ -0,0 +1,58 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <signal.h> +#include <pthreadP.h> +#include <sysdep.h> + + +int +pthread_sigmask ( + int how, + const sigset_t *newmask, + sigset_t *oldmask) +{ + sigset_t local_newmask; + + /* The only thing we have to make sure here is that SIGCANCEL and + SIGSETXID is not blocked. */ + if (newmask != NULL + && (__builtin_expect (__sigismember (newmask, SIGCANCEL), 0) + || __builtin_expect (__sigismember (newmask, SIGSETXID), 0))) + { + local_newmask = *newmask; + __sigdelset (&local_newmask, SIGCANCEL); + __sigdelset (&local_newmask, SIGSETXID); + newmask = &local_newmask; + } + +#ifdef INTERNAL_SYSCALL + /* We know that realtime signals are available if NPTL is used. */ + INTERNAL_SYSCALL_DECL (err); + int result = INTERNAL_SYSCALL (rt_sigprocmask, err, 4, how, newmask, + oldmask, _NSIG / 8); + + return (INTERNAL_SYSCALL_ERROR_P (result, err) + ? INTERNAL_SYSCALL_ERRNO (result, err) + : 0); +#else + return sigprocmask (how, newmask, oldmask) == -1 ? errno : 0; +#endif +} diff --git a/libpthread/nptl/sysdeps/pthread/pthread_spin_destroy.c b/libpthread/nptl/sysdeps/pthread/pthread_spin_destroy.c new file mode 100644 index 000000000..62082f44e --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pthread_spin_destroy.c @@ -0,0 +1,28 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" + + +int +pthread_spin_destroy (pthread_spinlock_t *lock) +{ + /* Nothing to do. */ + return 0; +} diff --git a/libpthread/nptl/sysdeps/pthread/pthread_spin_init.c b/libpthread/nptl/sysdeps/pthread/pthread_spin_init.c new file mode 100644 index 000000000..c2275085e --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pthread_spin_init.c @@ -0,0 +1,28 @@ +/* pthread_spin_init -- initialize a spin lock. Generic version. + Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" + +int +pthread_spin_init (pthread_spinlock_t *lock, int pshared) +{ + *lock = 0; + return 0; +} diff --git a/libpthread/nptl/sysdeps/pthread/pthread_spin_unlock.c b/libpthread/nptl/sysdeps/pthread/pthread_spin_unlock.c new file mode 100644 index 000000000..f97cadfbd --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pthread_spin_unlock.c @@ -0,0 +1,30 @@ +/* pthread_spin_unlock -- unlock a spin lock. Generic version. + Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" +#include <atomic.h> + +int +pthread_spin_unlock (pthread_spinlock_t *lock) +{ + atomic_full_barrier (); + *lock = 0; + return 0; +} diff --git a/libpthread/nptl/sysdeps/pthread/rt-unwind-resume.c b/libpthread/nptl/sysdeps/pthread/rt-unwind-resume.c new file mode 100644 index 000000000..743e675d4 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/rt-unwind-resume.c @@ -0,0 +1 @@ +#include <unwind-resume.c> diff --git a/libpthread/nptl/sysdeps/pthread/setxid.h b/libpthread/nptl/sysdeps/pthread/setxid.h new file mode 100644 index 000000000..8ec382f40 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/setxid.h @@ -0,0 +1,64 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthreadP.h> +#include <sysdep.h> + +#define __SETXID_1(cmd, arg1) \ + cmd.id[0] = arg1 +#define __SETXID_2(cmd, arg1, arg2) \ + __SETXID_1 (cmd, arg1); cmd.id[1] = arg2 +#define __SETXID_3(cmd, arg1, arg2, arg3) \ + __SETXID_2 (cmd, arg1, arg2); cmd.id[2] = arg3 + +#ifdef SINGLE_THREAD +# define INLINE_SETXID_SYSCALL(name, nr, args...) \ + INLINE_SYSCALL (name, nr, args) +#elif defined SHARED +# define INLINE_SETXID_SYSCALL(name, nr, args...) \ + ({ \ + int __result; \ + if (__builtin_expect (__libc_pthread_functions.ptr__nptl_setxid \ + != NULL, 0)) \ + { \ + struct xid_command __cmd; \ + __cmd.syscall_no = __NR_##name; \ + __SETXID_##nr (__cmd, args); \ + __result = __libc_pthread_functions.ptr__nptl_setxid (&__cmd); \ + } \ + else \ + __result = INLINE_SYSCALL (name, nr, args); \ + __result; \ + }) +#else +# define INLINE_SETXID_SYSCALL(name, nr, args...) \ + ({ \ + extern __typeof (__nptl_setxid) __nptl_setxid __attribute__((weak));\ + int __result; \ + if (__builtin_expect (__nptl_setxid != NULL, 0)) \ + { \ + struct xid_command __cmd; \ + __cmd.syscall_no = __NR_##name; \ + __SETXID_##nr (__cmd, args); \ + __result =__nptl_setxid (&__cmd); \ + } \ + else \ + __result = INLINE_SYSCALL (name, nr, args); \ + __result; \ + }) +#endif diff --git a/libpthread/nptl/sysdeps/pthread/sigaction.c b/libpthread/nptl/sysdeps/pthread/sigaction.c new file mode 100644 index 000000000..54b5d2de4 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/sigaction.c @@ -0,0 +1,54 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* This is tricky. GCC doesn't like #include_next in the primary + source file and even if it did, the first #include_next is this + exact file anyway. */ +#ifndef LIBC_SIGACTION + +#include <pthreadP.h> + +/* We use the libc implementation but we tell it to not allow + SIGCANCEL or SIGTIMER to be handled. */ +# define LIBC_SIGACTION 1 + +# include <sigaction.c> + +int +sigaction (int sig, const struct sigaction *act, struct sigaction *oact); + +int +__sigaction (int sig, const struct sigaction *act, struct sigaction *oact) +{ + if (__builtin_expect (sig == SIGCANCEL || sig == SIGSETXID, 0)) + { + __set_errno (EINVAL); + return -1; + } + + return __libc_sigaction (sig, act, oact); +} +libc_hidden_proto(sigaction) +weak_alias (__sigaction, sigaction) +libc_hidden_weak(sigaction) +#else + +# include_next <sigaction.c> + +#endif /* LIBC_SIGACTION */ diff --git a/libpthread/nptl/sysdeps/pthread/sigfillset.c b/libpthread/nptl/sysdeps/pthread/sigfillset.c new file mode 100644 index 000000000..fbe458f55 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/sigfillset.c @@ -0,0 +1,21 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthreadP.h> + +#include <../../../../libc/signal/sigfillset.c> diff --git a/libpthread/nptl/sysdeps/pthread/sigprocmask.c b/libpthread/nptl/sysdeps/pthread/sigprocmask.c new file mode 100644 index 000000000..35aa843ba --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/sigprocmask.c @@ -0,0 +1,22 @@ +/* Copyright (C) 1997,1998,1999,2000,2001,2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthreadP.h> +#undef _LARGEFILE64_SOURCE + +#include <../../../../libc/sysdeps/linux/common/sigprocmask.c> diff --git a/libpthread/nptl/sysdeps/pthread/timer_create.c b/libpthread/nptl/sysdeps/pthread/timer_create.c new file mode 100644 index 000000000..ae82c5af0 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/timer_create.c @@ -0,0 +1,170 @@ +/* Copyright (C) 2000, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Kaz Kylheku <kaz@ashi.footprints.net>. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <errno.h> +#include <signal.h> +#include <pthread.h> +#include <time.h> +#include <unistd.h> + +#include "posix-timer.h" + + +/* Create new per-process timer using CLOCK. */ +int +timer_create ( + clockid_t clock_id, + struct sigevent *evp, + timer_t *timerid) +{ + int retval = -1; + struct timer_node *newtimer = NULL; + struct thread_node *thread = NULL; + + if (0 +#if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0 + || clock_id == CLOCK_PROCESS_CPUTIME_ID +#endif +#if defined _POSIX_THREAD_CPUTIME && _POSIX_THREAD_CPUTIME >= 0 + || clock_id == CLOCK_THREAD_CPUTIME_ID +#endif + ) + { + /* We don't allow timers for CPU clocks. At least not in the + moment. */ + __set_errno (ENOTSUP); + return -1; + } + + if (clock_id != CLOCK_REALTIME) + { + __set_errno (EINVAL); + return -1; + } + + pthread_once (&__timer_init_once_control, __timer_init_once); + + if (__timer_init_failed) + { + __set_errno (ENOMEM); + return -1; + } + + pthread_mutex_lock (&__timer_mutex); + + newtimer = __timer_alloc (); + if (__builtin_expect (newtimer == NULL, 0)) + { + __set_errno (EAGAIN); + goto unlock_bail; + } + + if (evp != NULL) + newtimer->event = *evp; + else + { + newtimer->event.sigev_notify = SIGEV_SIGNAL; + newtimer->event.sigev_signo = SIGALRM; + newtimer->event.sigev_value.sival_ptr = timer_ptr2id (newtimer); + newtimer->event.sigev_notify_function = 0; + } + + newtimer->event.sigev_notify_attributes = &newtimer->attr; + newtimer->creator_pid = getpid (); + + switch (__builtin_expect (newtimer->event.sigev_notify, SIGEV_SIGNAL)) + { + case SIGEV_NONE: + case SIGEV_SIGNAL: + /* We have a global thread for delivering timed signals. + If it is not running, try to start it up. */ + thread = &__timer_signal_thread_rclk; + if (! thread->exists) + { + if (__builtin_expect (__timer_thread_start (thread), + 1) < 0) + { + __set_errno (EAGAIN); + goto unlock_bail; + } + } + break; + + case SIGEV_THREAD: + /* Copy over thread attributes or set up default ones. */ + if (evp->sigev_notify_attributes) + newtimer->attr = *(pthread_attr_t *) evp->sigev_notify_attributes; + else + pthread_attr_init (&newtimer->attr); + + /* Ensure thread attributes call for deatched thread. */ + pthread_attr_setdetachstate (&newtimer->attr, PTHREAD_CREATE_DETACHED); + + /* Try to find existing thread having the right attributes. */ + thread = __timer_thread_find_matching (&newtimer->attr, clock_id); + + /* If no existing thread has these attributes, try to allocate one. */ + if (thread == NULL) + thread = __timer_thread_alloc (&newtimer->attr, clock_id); + + /* Out of luck; no threads are available. */ + if (__builtin_expect (thread == NULL, 0)) + { + __set_errno (EAGAIN); + goto unlock_bail; + } + + /* If the thread is not running already, try to start it. */ + if (! thread->exists + && __builtin_expect (! __timer_thread_start (thread), 0)) + { + __set_errno (EAGAIN); + goto unlock_bail; + } + break; + + default: + __set_errno (EINVAL); + goto unlock_bail; + } + + newtimer->clock = clock_id; + newtimer->abstime = 0; + newtimer->armed = 0; + newtimer->thread = thread; + + *timerid = timer_ptr2id (newtimer); + retval = 0; + + if (__builtin_expect (retval, 0) == -1) + { + unlock_bail: + if (thread != NULL) + __timer_thread_dealloc (thread); + if (newtimer != NULL) + { + timer_delref (newtimer); + __timer_dealloc (newtimer); + } + } + + pthread_mutex_unlock (&__timer_mutex); + + return retval; +} diff --git a/libpthread/nptl/sysdeps/pthread/timer_delete.c b/libpthread/nptl/sysdeps/pthread/timer_delete.c new file mode 100644 index 000000000..4c53112db --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/timer_delete.c @@ -0,0 +1,70 @@ +/* Copyright (C) 2000, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Kaz Kylheku <kaz@ashi.footprints.net>. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <assert.h> +#include <errno.h> +#include <pthread.h> +#include <time.h> + +#include "posix-timer.h" + + +/* Delete timer TIMERID. */ +int +timer_delete ( + timer_t timerid) +{ + struct timer_node *timer; + int retval = -1; + + pthread_mutex_lock (&__timer_mutex); + + timer = timer_id2ptr (timerid); + if (! timer_valid (timer)) + /* Invalid timer ID or the timer is not in use. */ + __set_errno (EINVAL); + else + { + if (timer->armed && timer->thread != NULL) + { + struct thread_node *thread = timer->thread; + assert (thread != NULL); + + /* If thread is cancelled while waiting for handler to terminate, + the mutex is unlocked and timer_delete is aborted. */ + pthread_cleanup_push (__timer_mutex_cancel_handler, &__timer_mutex); + + /* If timer is currently being serviced, wait for it to finish. */ + while (thread->current_timer == timer) + pthread_cond_wait (&thread->cond, &__timer_mutex); + + pthread_cleanup_pop (0); + } + + /* Remove timer from whatever queue it may be on and deallocate it. */ + timer->inuse = TIMER_DELETED; + list_unlink_ip (&timer->links); + timer_delref (timer); + retval = 0; + } + + pthread_mutex_unlock (&__timer_mutex); + + return retval; +} diff --git a/libpthread/nptl/sysdeps/pthread/timer_getoverr.c b/libpthread/nptl/sysdeps/pthread/timer_getoverr.c new file mode 100644 index 000000000..f3e22215b --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/timer_getoverr.c @@ -0,0 +1,45 @@ +/* Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Kaz Kylheku <kaz@ashi.footprints.net>. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <errno.h> +#include <pthread.h> +#include <time.h> + +#include "posix-timer.h" + + +/* Get expiration overrun for timer TIMERID. */ +int +timer_getoverrun (timerid) + timer_t timerid; +{ + struct timer_node *timer; + int retval = -1; + + pthread_mutex_lock (&__timer_mutex); + + if (! timer_valid (timer = timer_id2ptr (timerid))) + __set_errno (EINVAL); + else + retval = timer->overrun_count; + + pthread_mutex_unlock (&__timer_mutex); + + return retval; +} diff --git a/libpthread/nptl/sysdeps/pthread/timer_gettime.c b/libpthread/nptl/sysdeps/pthread/timer_gettime.c new file mode 100644 index 000000000..723a61632 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/timer_gettime.c @@ -0,0 +1,77 @@ +/* Copyright (C) 2000, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Kaz Kylheku <kaz@ashi.footprints.net>. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <errno.h> +#include <pthread.h> +#include <time.h> + +#include "posix-timer.h" + + +/* Get current value of timer TIMERID and store it in VLAUE. */ +int +timer_gettime (timerid, value) + timer_t timerid; + struct itimerspec *value; +{ + struct timer_node *timer; + struct timespec now, expiry; + int retval = -1, armed = 0, valid; + clock_t clock = 0; + + pthread_mutex_lock (&__timer_mutex); + + timer = timer_id2ptr (timerid); + valid = timer_valid (timer); + + if (valid) { + armed = timer->armed; + expiry = timer->expirytime; + clock = timer->clock; + value->it_interval = timer->value.it_interval; + } + + pthread_mutex_unlock (&__timer_mutex); + + if (valid) + { + if (armed) + { + clock_gettime (clock, &now); + if (timespec_compare (&now, &expiry) < 0) + timespec_sub (&value->it_value, &expiry, &now); + else + { + value->it_value.tv_sec = 0; + value->it_value.tv_nsec = 0; + } + } + else + { + value->it_value.tv_sec = 0; + value->it_value.tv_nsec = 0; + } + + retval = 0; + } + else + __set_errno (EINVAL); + + return retval; +} diff --git a/libpthread/nptl/sysdeps/pthread/timer_routines.c b/libpthread/nptl/sysdeps/pthread/timer_routines.c new file mode 100644 index 000000000..8d5b1d13a --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/timer_routines.c @@ -0,0 +1,578 @@ +/* Helper code for POSIX timer implementation on NPTL. + Copyright (C) 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Kaz Kylheku <kaz@ashi.footprints.net>. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <assert.h> +#include <errno.h> +#include <pthread.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <sysdep.h> +#include <time.h> +#include <unistd.h> +#include <sys/syscall.h> + +#include "posix-timer.h" +#include <pthreadP.h> + + +/* Number of threads used. */ +#define THREAD_MAXNODES 16 + +/* Array containing the descriptors for the used threads. */ +static struct thread_node thread_array[THREAD_MAXNODES]; + +/* Static array with the structures for all the timers. */ +struct timer_node __timer_array[TIMER_MAX]; + +/* Global lock to protect operation on the lists. */ +pthread_mutex_t __timer_mutex = PTHREAD_MUTEX_INITIALIZER; + +/* Variable to protext initialization. */ +pthread_once_t __timer_init_once_control = PTHREAD_ONCE_INIT; + +/* Nonzero if initialization of timer implementation failed. */ +int __timer_init_failed; + +/* Node for the thread used to deliver signals. */ +struct thread_node __timer_signal_thread_rclk; + +/* Lists to keep free and used timers and threads. */ +struct list_links timer_free_list; +struct list_links thread_free_list; +struct list_links thread_active_list; + + +#ifdef __NR_rt_sigqueueinfo +extern int __syscall_rt_sigqueueinfo (int, int, siginfo_t *); +#endif + + +/* List handling functions. */ +static inline void +list_init (struct list_links *list) +{ + list->next = list->prev = list; +} + +static inline void +list_append (struct list_links *list, struct list_links *newp) +{ + newp->prev = list->prev; + newp->next = list; + list->prev->next = newp; + list->prev = newp; +} + +static inline void +list_insbefore (struct list_links *list, struct list_links *newp) +{ + list_append (list, newp); +} + +/* + * Like list_unlink_ip, except that calling it on a node that + * is already unlinked is disastrous rather than a noop. + */ + +static inline void +list_unlink (struct list_links *list) +{ + struct list_links *lnext = list->next, *lprev = list->prev; + + lnext->prev = lprev; + lprev->next = lnext; +} + +static inline struct list_links * +list_first (struct list_links *list) +{ + return list->next; +} + +static inline struct list_links * +list_null (struct list_links *list) +{ + return list; +} + +static inline struct list_links * +list_next (struct list_links *list) +{ + return list->next; +} + +static inline int +list_isempty (struct list_links *list) +{ + return list->next == list; +} + + +/* Functions build on top of the list functions. */ +static inline struct thread_node * +thread_links2ptr (struct list_links *list) +{ + return (struct thread_node *) ((char *) list + - offsetof (struct thread_node, links)); +} + +static inline struct timer_node * +timer_links2ptr (struct list_links *list) +{ + return (struct timer_node *) ((char *) list + - offsetof (struct timer_node, links)); +} + + +/* Initialize a newly allocated thread structure. */ +static void +thread_init (struct thread_node *thread, const pthread_attr_t *attr, clockid_t clock_id) +{ + if (attr != NULL) + thread->attr = *attr; + else + { + pthread_attr_init (&thread->attr); + pthread_attr_setdetachstate (&thread->attr, PTHREAD_CREATE_DETACHED); + } + + thread->exists = 0; + list_init (&thread->timer_queue); + pthread_cond_init (&thread->cond, 0); + thread->current_timer = 0; + thread->captured = pthread_self (); + thread->clock_id = clock_id; +} + + +/* Initialize the global lists, and acquire global resources. Error + reporting is done by storing a non-zero value to the global variable + timer_init_failed. */ +static void +init_module (void) +{ + int i; + + list_init (&timer_free_list); + list_init (&thread_free_list); + list_init (&thread_active_list); + + for (i = 0; i < TIMER_MAX; ++i) + { + list_append (&timer_free_list, &__timer_array[i].links); + __timer_array[i].inuse = TIMER_FREE; + } + + for (i = 0; i < THREAD_MAXNODES; ++i) + list_append (&thread_free_list, &thread_array[i].links); + + thread_init (&__timer_signal_thread_rclk, 0, CLOCK_REALTIME); +} + + +/* This is a handler executed in a child process after a fork() + occurs. It reinitializes the module, resetting all of the data + structures to their initial state. The mutex is initialized in + case it was locked in the parent process. */ +static void +reinit_after_fork (void) +{ + init_module (); + pthread_mutex_init (&__timer_mutex, 0); +} + + +/* Called once form pthread_once in timer_init. This initializes the + module and ensures that reinit_after_fork will be executed in any + child process. */ +void +__timer_init_once (void) +{ + init_module (); + pthread_atfork (0, 0, reinit_after_fork); +} + + +/* Deinitialize a thread that is about to be deallocated. */ +static void +thread_deinit (struct thread_node *thread) +{ + assert (list_isempty (&thread->timer_queue)); + pthread_cond_destroy (&thread->cond); +} + + +/* Allocate a thread structure from the global free list. Global + mutex lock must be held by caller. The thread is moved to + the active list. */ +struct thread_node * +__timer_thread_alloc (const pthread_attr_t *desired_attr, clockid_t clock_id) +{ + struct list_links *node = list_first (&thread_free_list); + + if (node != list_null (&thread_free_list)) + { + struct thread_node *thread = thread_links2ptr (node); + list_unlink (node); + thread_init (thread, desired_attr, clock_id); + list_append (&thread_active_list, node); + return thread; + } + + return 0; +} + + +/* Return a thread structure to the global free list. Global lock + must be held by caller. */ +void +__timer_thread_dealloc (struct thread_node *thread) +{ + thread_deinit (thread); + list_unlink (&thread->links); + list_append (&thread_free_list, &thread->links); +} + + +/* Each of our threads which terminates executes this cleanup + handler. We never terminate threads ourselves; if a thread gets here + it means that the evil application has killed it. If the thread has + timers, these require servicing and so we must hire a replacement + thread right away. We must also unblock another thread that may + have been waiting for this thread to finish servicing a timer (see + timer_delete()). */ + +static void +thread_cleanup (void *val) +{ + if (val != NULL) + { + struct thread_node *thread = val; + + /* How did the signal thread get killed? */ + assert (thread != &__timer_signal_thread_rclk); + + pthread_mutex_lock (&__timer_mutex); + + thread->exists = 0; + + /* We are no longer processing a timer event. */ + thread->current_timer = 0; + + if (list_isempty (&thread->timer_queue)) + __timer_thread_dealloc (thread); + else + (void) __timer_thread_start (thread); + + pthread_mutex_unlock (&__timer_mutex); + + /* Unblock potentially blocked timer_delete(). */ + pthread_cond_broadcast (&thread->cond); + } +} + + +/* Handle a timer which is supposed to go off now. */ +static void +thread_expire_timer (struct thread_node *self, struct timer_node *timer) +{ + self->current_timer = timer; /* Lets timer_delete know timer is running. */ + + pthread_mutex_unlock (&__timer_mutex); + + switch (__builtin_expect (timer->event.sigev_notify, SIGEV_SIGNAL)) + { + case SIGEV_NONE: + break; + + case SIGEV_SIGNAL: +#ifdef __NR_rt_sigqueueinfo + { + siginfo_t info; + + /* First, clear the siginfo_t structure, so that we don't pass our + stack content to other tasks. */ + memset (&info, 0, sizeof (siginfo_t)); + /* We must pass the information about the data in a siginfo_t + value. */ + info.si_signo = timer->event.sigev_signo; + info.si_code = SI_TIMER; + info.si_pid = timer->creator_pid; + info.si_uid = getuid (); + info.si_value = timer->event.sigev_value; + + INLINE_SYSCALL (rt_sigqueueinfo, 3, info.si_pid, info.si_signo, &info); + } +#else + if (pthread_kill (self->captured, timer->event.sigev_signo) != 0) + { + if (pthread_kill (self->id, timer->event.sigev_signo) != 0) + abort (); + } +#endif + break; + + case SIGEV_THREAD: + timer->event.sigev_notify_function (timer->event.sigev_value); + break; + + default: + assert (! "unknown event"); + break; + } + + pthread_mutex_lock (&__timer_mutex); + + self->current_timer = 0; + + pthread_cond_broadcast (&self->cond); +} + + +/* Thread function; executed by each timer thread. The job of this + function is to wait on the thread's timer queue and expire the + timers in chronological order as close to their scheduled time as + possible. */ +static void +__attribute__ ((noreturn)) +thread_func (void *arg) +{ + struct thread_node *self = arg; + + /* Register cleanup handler, in case rogue application terminates + this thread. (This cannot happen to __timer_signal_thread, which + doesn't invoke application callbacks). */ + + pthread_cleanup_push (thread_cleanup, self); + + pthread_mutex_lock (&__timer_mutex); + + while (1) + { + struct list_links *first; + struct timer_node *timer = NULL; + + /* While the timer queue is not empty, inspect the first node. */ + first = list_first (&self->timer_queue); + if (first != list_null (&self->timer_queue)) + { + struct timespec now; + + timer = timer_links2ptr (first); + + /* This assumes that the elements of the list of one thread + are all for the same clock. */ + clock_gettime (timer->clock, &now); + + while (1) + { + /* If the timer is due or overdue, remove it from the queue. + If it's a periodic timer, re-compute its new time and + requeue it. Either way, perform the timer expiry. */ + if (timespec_compare (&now, &timer->expirytime) < 0) + break; + + list_unlink_ip (first); + + if (__builtin_expect (timer->value.it_interval.tv_sec, 0) != 0 + || timer->value.it_interval.tv_nsec != 0) + { + timer->overrun_count = 0; + timespec_add (&timer->expirytime, &timer->expirytime, + &timer->value.it_interval); + while (timespec_compare (&timer->expirytime, &now) < 0) + { + timespec_add (&timer->expirytime, &timer->expirytime, + &timer->value.it_interval); + if (timer->overrun_count < DELAYTIMER_MAX) + ++timer->overrun_count; + } + __timer_thread_queue_timer (self, timer); + } + + thread_expire_timer (self, timer); + + first = list_first (&self->timer_queue); + if (first == list_null (&self->timer_queue)) + break; + + timer = timer_links2ptr (first); + } + } + + /* If the queue is not empty, wait until the expiry time of the + first node. Otherwise wait indefinitely. Insertions at the + head of the queue must wake up the thread by broadcasting + this condition variable. */ + if (timer != NULL) + pthread_cond_timedwait (&self->cond, &__timer_mutex, + &timer->expirytime); + else + pthread_cond_wait (&self->cond, &__timer_mutex); + } + /* This macro will never be executed since the while loop loops + forever - but we have to add it for proper nesting. */ + pthread_cleanup_pop (1); +} + + +/* Enqueue a timer in wakeup order in the thread's timer queue. + Returns 1 if the timer was inserted at the head of the queue, + causing the queue's next wakeup time to change. */ + +int +__timer_thread_queue_timer (struct thread_node *thread, + struct timer_node *insert) +{ + struct list_links *iter; + int athead = 1; + + for (iter = list_first (&thread->timer_queue); + iter != list_null (&thread->timer_queue); + iter = list_next (iter)) + { + struct timer_node *timer = timer_links2ptr (iter); + + if (timespec_compare (&insert->expirytime, &timer->expirytime) < 0) + break; + athead = 0; + } + + list_insbefore (iter, &insert->links); + return athead; +} + + +/* Start a thread and associate it with the given thread node. Global + lock must be held by caller. */ +int +__timer_thread_start (struct thread_node *thread) +{ + int retval = 1; + + assert (!thread->exists); + thread->exists = 1; + + if (pthread_create (&thread->id, &thread->attr, + (void *(*) (void *)) thread_func, thread) != 0) + { + thread->exists = 0; + retval = -1; + } + + return retval; +} + + +void +__timer_thread_wakeup (struct thread_node *thread) +{ + pthread_cond_broadcast (&thread->cond); +} + + +/* Compare two pthread_attr_t thread attributes for exact equality. + Returns 1 if they are equal, otherwise zero if they are not equal + or contain illegal values. This version is NPTL-specific for + performance reason. One could use the access functions to get the + values of all the fields of the attribute structure. */ +static int +thread_attr_compare (const pthread_attr_t *left, const pthread_attr_t *right) +{ + struct pthread_attr *ileft = (struct pthread_attr *) left; + struct pthread_attr *iright = (struct pthread_attr *) right; + + return (ileft->flags == iright->flags + && ileft->schedpolicy == iright->schedpolicy + && (ileft->schedparam.sched_priority + == iright->schedparam.sched_priority) + && ileft->guardsize == iright->guardsize + && ileft->stackaddr == iright->stackaddr + && ileft->stacksize == iright->stacksize + && ((ileft->cpuset == NULL && iright->cpuset == NULL) + || (ileft->cpuset != NULL && iright->cpuset != NULL + && ileft->cpusetsize == iright->cpusetsize + && memcmp (ileft->cpuset, iright->cpuset, + ileft->cpusetsize) == 0))); +} + + +/* Search the list of active threads and find one which has matching + attributes. Global mutex lock must be held by caller. */ +struct thread_node * +__timer_thread_find_matching (const pthread_attr_t *desired_attr, + clockid_t desired_clock_id) +{ + struct list_links *iter = list_first (&thread_active_list); + + while (iter != list_null (&thread_active_list)) + { + struct thread_node *candidate = thread_links2ptr (iter); + + if (thread_attr_compare (desired_attr, &candidate->attr) + && desired_clock_id == candidate->clock_id) + return candidate; + + iter = list_next (iter); + } + + return NULL; +} + + +/* Grab a free timer structure from the global free list. The global + lock must be held by the caller. */ +struct timer_node * +__timer_alloc (void) +{ + struct list_links *node = list_first (&timer_free_list); + + if (node != list_null (&timer_free_list)) + { + struct timer_node *timer = timer_links2ptr (node); + list_unlink_ip (node); + timer->inuse = TIMER_INUSE; + timer->refcount = 1; + return timer; + } + + return NULL; +} + + +/* Return a timer structure to the global free list. The global lock + must be held by the caller. */ +void +__timer_dealloc (struct timer_node *timer) +{ + assert (timer->refcount == 0); + timer->thread = NULL; /* Break association between timer and thread. */ + timer->inuse = TIMER_FREE; + list_append (&timer_free_list, &timer->links); +} + + +/* Thread cancellation handler which unlocks a mutex. */ +void +__timer_mutex_cancel_handler (void *arg) +{ + pthread_mutex_unlock (arg); +} diff --git a/libpthread/nptl/sysdeps/pthread/timer_settime.c b/libpthread/nptl/sysdeps/pthread/timer_settime.c new file mode 100644 index 000000000..592b5271b --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/timer_settime.c @@ -0,0 +1,137 @@ +/* Copyright (C) 2000, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Kaz Kylheku <kaz@ashi.footprints.net>. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <errno.h> +#include <pthread.h> +#include <time.h> + +#include "posix-timer.h" + + +/* Set timer TIMERID to VALUE, returning old value in OVLAUE. */ +int +timer_settime (timerid, flags, value, ovalue) + timer_t timerid; + int flags; + const struct itimerspec *value; + struct itimerspec *ovalue; +{ + struct timer_node *timer; + struct thread_node *thread = NULL; + struct timespec now; + int have_now = 0, need_wakeup = 0; + int retval = -1; + + timer = timer_id2ptr (timerid); + if (timer == NULL) + { + __set_errno (EINVAL); + goto bail; + } + + if (value->it_interval.tv_nsec < 0 + || value->it_interval.tv_nsec >= 1000000000 + || value->it_value.tv_nsec < 0 + || value->it_value.tv_nsec >= 1000000000) + { + __set_errno (EINVAL); + goto bail; + } + + /* Will need to know current time since this is a relative timer; + might as well make the system call outside of the lock now! */ + + if ((flags & TIMER_ABSTIME) == 0) + { + clock_gettime (timer->clock, &now); + have_now = 1; + } + + pthread_mutex_lock (&__timer_mutex); + timer_addref (timer); + + /* One final check of timer validity; this one is possible only + until we have the mutex, because it accesses the inuse flag. */ + + if (! timer_valid(timer)) + { + __set_errno (EINVAL); + goto unlock_bail; + } + + if (ovalue != NULL) + { + ovalue->it_interval = timer->value.it_interval; + + if (timer->armed) + { + if (! have_now) + { + pthread_mutex_unlock (&__timer_mutex); + clock_gettime (timer->clock, &now); + have_now = 1; + pthread_mutex_lock (&__timer_mutex); + timer_addref (timer); + } + + timespec_sub (&ovalue->it_value, &timer->expirytime, &now); + } + else + { + ovalue->it_value.tv_sec = 0; + ovalue->it_value.tv_nsec = 0; + } + } + + timer->value = *value; + + list_unlink_ip (&timer->links); + timer->armed = 0; + + thread = timer->thread; + + /* A value of { 0, 0 } causes the timer to be stopped. */ + if (value->it_value.tv_sec != 0 + || __builtin_expect (value->it_value.tv_nsec != 0, 1)) + { + if ((flags & TIMER_ABSTIME) != 0) + /* The user specified the expiration time. */ + timer->expirytime = value->it_value; + else + timespec_add (&timer->expirytime, &now, &value->it_value); + + /* Only need to wake up the thread if timer is inserted + at the head of the queue. */ + if (thread != NULL) + need_wakeup = __timer_thread_queue_timer (thread, timer); + timer->armed = 1; + } + + retval = 0; + +unlock_bail: + timer_delref (timer); + pthread_mutex_unlock (&__timer_mutex); + +bail: + if (thread != NULL && need_wakeup) + __timer_thread_wakeup (thread); + + return retval; +} diff --git a/libpthread/nptl/sysdeps/pthread/unwind-forcedunwind.c b/libpthread/nptl/sysdeps/pthread/unwind-forcedunwind.c new file mode 100644 index 000000000..8b1f24407 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/unwind-forcedunwind.c @@ -0,0 +1,103 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <dlfcn.h> +#include <stdio.h> +#include <unwind.h> +#include <pthreadP.h> + +#define __libc_dlopen(x) dlopen(x, (RTLD_LOCAL | RTLD_LAZY)) +#define __libc_dlsym dlsym + +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 +pthread_cancel_init (void) +{ + void *resume, *personality, *forcedunwind, *getcfa; + void *handle; + + if (__builtin_expect (libgcc_s_getcfa != NULL, 1)) + return; + + handle = __libc_dlopen ("libgcc_s.so.1"); + + if (handle == NULL + || (resume = __libc_dlsym (handle, "_Unwind_Resume")) == NULL + || (personality = __libc_dlsym (handle, "__gcc_personality_v0")) == NULL + || (forcedunwind = __libc_dlsym (handle, "_Unwind_ForcedUnwind")) + == NULL + || (getcfa = __libc_dlsym (handle, "_Unwind_GetCFA")) == NULL +#ifdef ARCH_CANCEL_INIT + || ARCH_CANCEL_INIT (handle) +#endif + ) + { + printf("libgcc_s.so.1 must be installed for pthread_cancel to work\n"); + abort(); + } + + libgcc_s_resume = resume; + libgcc_s_personality = personality; + libgcc_s_forcedunwind = forcedunwind; + libgcc_s_getcfa = getcfa; +} + +void +_Unwind_Resume (struct _Unwind_Exception *exc) +{ + if (__builtin_expect (libgcc_s_resume == NULL, 0)) + pthread_cancel_init (); + libgcc_s_resume (exc); +} + +_Unwind_Reason_Code +__gcc_personality_v0 (int version, _Unwind_Action actions, + _Unwind_Exception_Class exception_class, + struct _Unwind_Exception *ue_header, + struct _Unwind_Context *context) +{ + if (__builtin_expect (libgcc_s_personality == NULL, 0)) + pthread_cancel_init (); + return libgcc_s_personality (version, actions, exception_class, + ue_header, context); +} + +_Unwind_Reason_Code +_Unwind_ForcedUnwind (struct _Unwind_Exception *exc, _Unwind_Stop_Fn stop, + void *stop_argument) +{ + if (__builtin_expect (libgcc_s_forcedunwind == NULL, 0)) + pthread_cancel_init (); + return libgcc_s_forcedunwind (exc, stop, stop_argument); +} + +_Unwind_Word +_Unwind_GetCFA (struct _Unwind_Context *context) +{ + if (__builtin_expect (libgcc_s_getcfa == NULL, 0)) + pthread_cancel_init (); + return libgcc_s_getcfa (context); +} diff --git a/libpthread/nptl/sysdeps/pthread/unwind-resume.c b/libpthread/nptl/sysdeps/pthread/unwind-resume.c new file mode 100644 index 000000000..018d2fd2f --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/unwind-resume.c @@ -0,0 +1,72 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <dlfcn.h> +#include <stdio.h> +#include <stdlib.h> +#include <unwind.h> + +static void (*libgcc_s_resume) (struct _Unwind_Exception *exc); +static _Unwind_Reason_Code (*libgcc_s_personality) + (int, _Unwind_Action, _Unwind_Exception_Class, struct _Unwind_Exception *, + struct _Unwind_Context *); + +extern +void abort(void); + +static void +init (void) +{ + void *resume = NULL; + void *personality = NULL; + void *handle; + resume = personality = NULL; /* make gcc silent */ + handle = dlopen ("libgcc_s.so.1", (RTLD_LOCAL | RTLD_LAZY)); + + if (handle == NULL + || (resume = dlsym (handle, "_Unwind_Resume")) == NULL + || (personality = dlsym (handle, "__gcc_personality_v0")) == NULL) + { + printf("libgcc_s.so.1 must be installed for pthread_cancel to work\n"); + abort(); + } + + libgcc_s_resume = resume; + libgcc_s_personality = personality; +} + +void +_Unwind_Resume (struct _Unwind_Exception *exc) +{ + if (__builtin_expect (libgcc_s_resume == NULL, 0)) + init (); + libgcc_s_resume (exc); +} + +_Unwind_Reason_Code +__gcc_personality_v0 (int version, _Unwind_Action actions, + _Unwind_Exception_Class exception_class, + struct _Unwind_Exception *ue_header, + struct _Unwind_Context *context) +{ + if (__builtin_expect (libgcc_s_personality == NULL, 0)) + init (); + return libgcc_s_personality (version, actions, exception_class, + ue_header, context); +} diff --git a/libpthread/nptl/sysdeps/sh/Makefile b/libpthread/nptl/sysdeps/sh/Makefile new file mode 100644 index 000000000..81bddf688 --- /dev/null +++ b/libpthread/nptl/sysdeps/sh/Makefile @@ -0,0 +1,3 @@ +ifeq ($(subdir),csu) +gen-as-const-headers += tcb-offsets.sym +endif diff --git a/libpthread/nptl/sysdeps/sh/Makefile.arch b/libpthread/nptl/sysdeps/sh/Makefile.arch new file mode 100644 index 000000000..83db10fbe --- /dev/null +++ b/libpthread/nptl/sysdeps/sh/Makefile.arch @@ -0,0 +1,56 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2005 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +libpthread_SSRC = pthread_spin_unlock.S pthread_spin_trylock.S +libpthread_CSRC = pthread_spin_lock.c pthread_spin_init.c + +ASFLAGS-pthread_spin_unlock.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +ASFLAGS-pthread_spin_trylock.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 + +CFLAGS-pthread_spin_lock.c += -D_GNU_SOURCE + +CFLAGS-sh = $(SSP_ALL_CFLAGS) +#CFLAGS:=$(CFLAGS:-O1=-O2) + +PTHREAD_ARCH_DIR := $(top_srcdir)libpthread/nptl/sysdeps/sh +PTHREAD_ARCH_OUT := $(top_builddir)libpthread/nptl/sysdeps/sh +PTHREAD_ARCH_OBJ := $(patsubst %.S,$(PTHREAD_ARCH_OUT)/%.o,$(libpthread_SSRC)) +PTHREAD_ARCH_OBJ += $(patsubst %.c,$(PTHREAD_ARCH_OUT)/%.o,$(libpthread_CSRC)) + +ifeq ($(DOPIC),y) +libpthread-a-y += $(PTHREAD_ARCH_OBJ:.o=.os) +else +libpthread-a-y += $(PTHREAD_ARCH_OBJ) +endif +libpthread-so-y += $(PTHREAD_ARCH_OBJ:.o=.oS) + +libpthread-nomulti-y += $(PTHREAD_ARCH_OBJ) + +objclean-y += nptl_arch_clean +headers_clean-y += nptl_arch_headers_clean + +# +# Create 'tcb-offsets.h' header file. +# +CFLAGS-tcb-offsets.c = -S + +$(PTHREAD_ARCH_OUT)/tcb-offsets.c: $(PTHREAD_ARCH_DIR)/tcb-offsets.sym + $(do_awk) $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@ + +$(PTHREAD_ARCH_OUT)/tcb-offsets.s: $(PTHREAD_ARCH_OUT)/tcb-offsets.c + $(compile.c) + +$(PTHREAD_ARCH_OUT)/tcb-offsets.h: $(PTHREAD_ARCH_OUT)/tcb-offsets.s + $(do_sed) -n "s/^.*@@@name@@@\([^@]*\)@@@value@@@[^0-9Xxa-fA-F-]*\([0-9Xxa-fA-F-][0-9Xxa-fA-F-]*\).*@@@end@@@.*$\/#define \1 \2/p" $< > $@ + +nptl_arch_headers: $(PTHREAD_ARCH_OUT)/tcb-offsets.h + +nptl_arch_headers_clean: + $(do_rm) $(addprefix $(PTHREAD_ARCH_OUT)/tcb-offsets., c s h) + +nptl_arch_clean: + $(do_rm) $(addprefix $(PTHREAD_ARCH_OUT)/*., o os oS) diff --git a/libpthread/nptl/sysdeps/sh/dl-tls.h b/libpthread/nptl/sysdeps/sh/dl-tls.h new file mode 100644 index 000000000..98e2f1904 --- /dev/null +++ b/libpthread/nptl/sysdeps/sh/dl-tls.h @@ -0,0 +1,29 @@ +/* Thread-local storage handling in the ELF dynamic linker. SH version. + Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + + +/* Type used for the representation of TLS information in the GOT. */ +typedef struct +{ + unsigned long int ti_module; + unsigned long int ti_offset; +} tls_index; + + +extern void *__tls_get_addr (tls_index *ti); diff --git a/libpthread/nptl/sysdeps/sh/jmpbuf-unwind.h b/libpthread/nptl/sysdeps/sh/jmpbuf-unwind.h new file mode 100644 index 000000000..41c3c3984 --- /dev/null +++ b/libpthread/nptl/sysdeps/sh/jmpbuf-unwind.h @@ -0,0 +1,33 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <setjmp.h> +#include <stdint.h> +#include <unwind.h> + +#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \ + _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj) + +#define _JMPBUF_UNWINDS_ADJ(jmpbuf, address, adj) \ + ((uintptr_t) (address) - (adj) < (uintptr_t) (jmpbuf)[0].__regs[7] - (adj)) + +extern __typeof(longjmp) __libc_longjmp attribute_noreturn; + +/* We use the normal lobngjmp for unwinding. */ +#define __libc_unwind_longjmp(buf, val) __libc_longjmp (buf, val) diff --git a/libpthread/nptl/sysdeps/sh/pthread_spin_init.c b/libpthread/nptl/sysdeps/sh/pthread_spin_init.c new file mode 100644 index 000000000..0a47981aa --- /dev/null +++ b/libpthread/nptl/sysdeps/sh/pthread_spin_init.c @@ -0,0 +1,20 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* Not needed. pthread_spin_init is an alias for pthread_spin_unlock. */ diff --git a/libpthread/nptl/sysdeps/sh/pthread_spin_lock.c b/libpthread/nptl/sysdeps/sh/pthread_spin_lock.c new file mode 100644 index 000000000..d158183f0 --- /dev/null +++ b/libpthread/nptl/sysdeps/sh/pthread_spin_lock.c @@ -0,0 +1,35 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" + +int +pthread_spin_lock (lock) + pthread_spinlock_t *lock; +{ + unsigned int val; + + do + __asm__ volatile ("tas.b @%1; movt %0" + : "=&r" (val) + : "r" (lock) + : "memory"); + while (val == 0); + + return 0; +} diff --git a/libpthread/nptl/sysdeps/sh/pthread_spin_trylock.S b/libpthread/nptl/sysdeps/sh/pthread_spin_trylock.S new file mode 100644 index 000000000..18112ba23 --- /dev/null +++ b/libpthread/nptl/sysdeps/sh/pthread_spin_trylock.S @@ -0,0 +1,32 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread-errnos.h> + + .globl pthread_spin_trylock + .type pthread_spin_trylock,@function + .align 5 +pthread_spin_trylock: + tas.b @r4 + bf/s 1f + mov #EBUSY, r0 + mov #0, r0 +1: + rts + nop + .size pthread_spin_trylock,.-pthread_spin_trylock diff --git a/libpthread/nptl/sysdeps/sh/pthread_spin_unlock.S b/libpthread/nptl/sysdeps/sh/pthread_spin_unlock.S new file mode 100644 index 000000000..c77acaffe --- /dev/null +++ b/libpthread/nptl/sysdeps/sh/pthread_spin_unlock.S @@ -0,0 +1,30 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + + .globl pthread_spin_unlock + .type pthread_spin_unlock,@function + .align 5 +pthread_spin_unlock: + mov #0,r0 + rts + mov.l r0,@r4 + .size pthread_spin_unlock,.-pthread_spin_unlock + + /* The implementation of pthread_spin_init is identical. */ + .globl pthread_spin_init +pthread_spin_init = pthread_spin_unlock diff --git a/libpthread/nptl/sysdeps/sh/pthreaddef.h b/libpthread/nptl/sysdeps/sh/pthreaddef.h new file mode 100644 index 000000000..c1902fb54 --- /dev/null +++ b/libpthread/nptl/sysdeps/sh/pthreaddef.h @@ -0,0 +1,49 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> + +/* Default stack size. */ +#define ARCH_STACK_DEFAULT_SIZE (2 * 1024 * 1024) + +/* Required stack pointer alignment at beginning. */ +#define STACK_ALIGN 8 + +/* Minimal stack size after allocating thread descriptor and guard size. */ +#define MINIMAL_REST_STACK 2048 + +/* Alignment requirement for TCB. */ +#define TCB_ALIGNMENT 8 + + +/* Location of current stack frame. */ +#define CURRENT_STACK_FRAME __builtin_frame_address (0) + + +/* XXX Until we have a better place keep the definitions here. */ + +/* While there is no such syscall. */ +#define __exit_thread_inline(val) \ + while (1) { \ + if (__builtin_constant_p (val) && (val) == 0) \ + __asm__ volatile ("mov #0,r4; mov %0,r3; trapa #0x11\n\t" SYSCALL_INST_PAD \ + :: "i" (__NR_exit)); \ + else \ + __asm__ volatile ("mov %1,r4; mov %0,r3; trapa #0x11\n\t" SYSCALL_INST_PAD \ + :: "i" (__NR_exit), "r" (val)); \ + } diff --git a/libpthread/nptl/sysdeps/sh/sysdep.h b/libpthread/nptl/sysdeps/sh/sysdep.h new file mode 100644 index 000000000..5b75198f9 --- /dev/null +++ b/libpthread/nptl/sysdeps/sh/sysdep.h @@ -0,0 +1,82 @@ +/* Assembler macros for SH. + Copyright (C) 1999, 2000, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdeps/generic/sysdep.h> + +#include <features.h> +#include <libc-internal.h> + +#ifdef __ASSEMBLER__ + +/* Syntactic details of assembler. */ + +#define ALIGNARG(log2) log2 +/* For ELF we need the `.type' directive to make shared libs work right. */ +#define ASM_TYPE_DIRECTIVE(name,typearg) .type name,@##typearg; +#define ASM_SIZE_DIRECTIVE(name) .size name,.-name + +#ifdef SHARED +#define PLTJMP(_x) _x##@PLT +#else +#define PLTJMP(_x) _x +#endif + +/* Define an entry point visible from C. */ +#define ENTRY(name) \ + ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(name); \ + ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name),function) \ + .align ALIGNARG(5); \ + C_LABEL(name) \ + cfi_startproc; \ + CALL_MCOUNT + +#undef END +#define END(name) \ + cfi_endproc; \ + ASM_SIZE_DIRECTIVE(C_SYMBOL_NAME(name)) + +/* If compiled for profiling, call `mcount' at the start of each function. */ +#ifdef PROF +#define CALL_MCOUNT \ + mov.l 1f,r1; \ + sts.l pr,@-r15; \ + cfi_adjust_cfa_offset (4); \ + cfi_rel_offset (pr, 0); \ + mova 2f,r0; \ + jmp @r1; \ + lds r0,pr; \ + .align 2; \ +1: .long mcount; \ +2: lds.l @r15+,pr; \ + cfi_adjust_cfa_offset (-4); \ + cfi_restore (pr) + +#else +#define CALL_MCOUNT /* Do nothing. */ +#endif + +#ifdef __UCLIBC_UNDERSCORES__ +/* Since C identifiers are not normally prefixed with an underscore + on this system, the asm identifier `syscall_error' intrudes on the + C name space. Make sure we use an innocuous name. */ +#define syscall_error __syscall_error +#define mcount _mcount +#endif + +#endif /* __ASSEMBLER__ */ diff --git a/libpthread/nptl/sysdeps/sh/tcb-offsets.sym b/libpthread/nptl/sysdeps/sh/tcb-offsets.sym new file mode 100644 index 000000000..539789a81 --- /dev/null +++ b/libpthread/nptl/sysdeps/sh/tcb-offsets.sym @@ -0,0 +1,11 @@ +#include <sysdep.h> +#include <tls.h> + +RESULT offsetof (struct pthread, result) +TID offsetof (struct pthread, tid) +PID offsetof (struct pthread, pid) +CANCELHANDLING offsetof (struct pthread, cancelhandling) +CLEANUP_JMP_BUF offsetof (struct pthread, cleanup_jmp_buf) +MULTIPLE_THREADS_OFFSET offsetof (struct pthread, header.multiple_threads) +TLS_PRE_TCB_SIZE sizeof (struct pthread) +MUTEX_FUTEX offsetof (pthread_mutex_t, __data.__lock) diff --git a/libpthread/nptl/sysdeps/sh/tls.h b/libpthread/nptl/sysdeps/sh/tls.h new file mode 100644 index 000000000..5e5ce12b0 --- /dev/null +++ b/libpthread/nptl/sysdeps/sh/tls.h @@ -0,0 +1,142 @@ +/* Definition for thread-local data handling. NPTL/SH version. + Copyright (C) 2003, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _TLS_H +#define _TLS_H + +#ifndef __ASSEMBLER__ +# include <stdbool.h> +# include <stddef.h> +# include <stdint.h> + +/* Type for the dtv. */ +typedef union dtv +{ + size_t counter; + struct + { + void *val; + bool is_static; + } pointer; +} dtv_t; + +typedef struct +{ + dtv_t *dtv; + void *private; +} tcbhead_t; + +# define TLS_MULTIPLE_THREADS_IN_TCB 1 + +#else /* __ASSEMBLER__ */ +# include <tcb-offsets.h> +#endif /* __ASSEMBLER__ */ + + +/* We require TLS support in the tools. */ +#define HAVE_TLS_SUPPORT +#define HAVE___THREAD 1 +#define HAVE_TLS_MODEL_ATTRIBUTE 1 +/* Signal that TLS support is available. */ +# define USE_TLS 1 + +#ifndef __ASSEMBLER__ + +/* Get system call information. */ +# include <sysdep.h> + +/* This is the size of the initial TCB. */ +# define TLS_INIT_TCB_SIZE sizeof (tcbhead_t) + +/* Alignment requirements for the initial TCB. */ +# define TLS_INIT_TCB_ALIGN __alignof__ (tcbhead_t) + +/* This is the size of the TCB. */ +# define TLS_TCB_SIZE sizeof (tcbhead_t) + +/* This is the size we need before TCB. */ +# define TLS_PRE_TCB_SIZE sizeof (struct pthread) + +/* Alignment requirements for the TCB. */ +# define TLS_TCB_ALIGN __alignof__ (struct pthread) + +/* The TLS blocks start right after the TCB. */ +# define TLS_DTV_AT_TP 1 + +/* Get the thread descriptor definition. */ +# include <descr.h> + +/* Install the dtv pointer. The pointer passed is to the element with + index -1 which contain the length. */ +# define INSTALL_DTV(tcbp, dtvp) \ + ((tcbhead_t *) (tcbp))->dtv = (dtvp) + 1 + +/* Install new dtv for current thread. */ +# define INSTALL_NEW_DTV(dtv) \ + ({ tcbhead_t *__tcbp; \ + __asm __volatile ("stc gbr,%0" : "=r" (__tcbp)); \ + __tcbp->dtv = (dtv);}) + +/* Return dtv of given thread descriptor. */ +# define GET_DTV(tcbp) \ + (((tcbhead_t *) (tcbp))->dtv) + +/* Code to initially initialize the thread pointer. This might need + special attention since 'errno' is not yet available and if the + operation can cause a failure 'errno' must not be touched. */ +# define TLS_INIT_TP(tcbp, secondcall) \ + ({ __asm __volatile ("ldc %0,gbr" : : "r" (tcbp)); 0; }) + +/* Return the address of the dtv for the current thread. */ +# define THREAD_DTV() \ + ({ tcbhead_t *__tcbp; \ + __asm __volatile ("stc gbr,%0" : "=r" (__tcbp)); \ + __tcbp->dtv;}) + +/* Return the thread descriptor for the current thread. + The contained asm must *not* be marked volatile since otherwise + assignments like + struct pthread *self = thread_self(); + do not get optimized away. */ +# define THREAD_SELF \ + ({ struct pthread *__thread_self; \ + __asm ("stc gbr,%0" : "=r" (__thread_self)); \ + __thread_self - 1;}) + +/* Magic for libthread_db to know how to do THREAD_SELF. */ +# define DB_THREAD_SELF \ + REGISTER (32, 32, REG_GBR * 4, -sizeof (struct pthread)) + +/* Read member of the thread descriptor directly. */ +# define THREAD_GETMEM(descr, member) (descr->member) + +/* Same as THREAD_GETMEM, but the member offset can be non-constant. */ +# define THREAD_GETMEM_NC(descr, member, idx) (descr->member[idx]) + +/* Set member of the thread descriptor directly. */ +# define THREAD_SETMEM(descr, member, value) \ + descr->member = (value) + +/* Same as THREAD_SETMEM, but the member offset can be non-constant. */ +# define THREAD_SETMEM_NC(descr, member, idx, value) \ + descr->member[idx] = (value) + +#endif /* __ASSEMBLER__ */ + +#endif /* tls.h */ diff --git a/libpthread/nptl/sysdeps/sparc/Makefile b/libpthread/nptl/sysdeps/sparc/Makefile new file mode 100644 index 000000000..81bddf688 --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/Makefile @@ -0,0 +1,3 @@ +ifeq ($(subdir),csu) +gen-as-const-headers += tcb-offsets.sym +endif diff --git a/libpthread/nptl/sysdeps/sparc/Makefile.arch b/libpthread/nptl/sysdeps/sparc/Makefile.arch new file mode 100644 index 000000000..b13eee9f6 --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/Makefile.arch @@ -0,0 +1,53 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2005 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +libpthread_CSRC = sparc32/pthread_spin_lock.c \ + sparc32/pthread_spin_trylock.c + +CFLAGS-pthread_spin_lock.c += -D_GNU_SOURCE + +CFLAGS-sparc = $(SSP_ALL_CFLAGS) +#CFLAGS:=$(CFLAGS:-O1=-O2) + +PTHREAD_ARCH_DIR := $(top_srcdir)libpthread/nptl/sysdeps/sparc/ +PTHREAD_ARCH_OUT := $(top_builddir)libpthread/nptl/sysdeps/sparc/ +PTHREAD_ARCH_OBJ := $(patsubst %.S,$(PTHREAD_ARCH_OUT)/%.o,$(libpthread_SSRC)) +PTHREAD_ARCH_OBJ += $(patsubst %.c,$(PTHREAD_ARCH_OUT)/%.o,$(libpthread_CSRC)) + +ifeq ($(DOPIC),y) +libpthread-a-y += $(PTHREAD_ARCH_OBJ:.o=.os) +else +libpthread-a-y += $(PTHREAD_ARCH_OBJ) +endif +libpthread-so-y += $(PTHREAD_ARCH_OBJ:.o=.oS) + +libpthread-nomulti-y += $(PTHREAD_ARCH_OBJ) + +objclean-y += nptl_arch_clean +headers_clean-y += nptl_arch_headers_clean + +# +# Create 'tcb-offsets.h' header file. +# +CFLAGS-tcb-offsets.c = -S + +$(PTHREAD_ARCH_OUT)/tcb-offsets.c: $(PTHREAD_ARCH_DIR)/tcb-offsets.sym + $(do_awk) $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@ + +$(PTHREAD_ARCH_OUT)/tcb-offsets.s: $(PTHREAD_ARCH_OUT)/tcb-offsets.c + $(compile.c) + +$(PTHREAD_ARCH_OUT)/tcb-offsets.h: $(PTHREAD_ARCH_OUT)/tcb-offsets.s + @sed -n "s/^.*@@@name@@@\([^@]*\)@@@value@@@[^0-9Xxa-fA-F-]*\([0-9Xxa-fA-F-][0-9Xxa-fA-F-]*\).*@@@end@@@.*$\/#define \1 \2/p" $< > $@ + +nptl_arch_headers: $(PTHREAD_ARCH_OUT)/tcb-offsets.h + +nptl_arch_headers_clean: + $(do_rm) $(addprefix $(PTHREAD_ARCH_OUT)/tcb-offsets., c s h) + +nptl_arch_clean: + $(do_rm) $(addprefix $(PTHREAD_ARCH_OUT)/*., o os oS) diff --git a/libpthread/nptl/sysdeps/sparc/dl-tls.h b/libpthread/nptl/sysdeps/sparc/dl-tls.h new file mode 100644 index 000000000..6edf8d525 --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/dl-tls.h @@ -0,0 +1,29 @@ +/* Thread-local storage handling in the ELF dynamic linker. SPARC version. + Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + + +/* Type used for the representation of TLS information in the GOT. */ +typedef struct +{ + unsigned long int ti_module; + unsigned long int ti_offset; +} tls_index; + + +extern void *__tls_get_addr (tls_index *ti); diff --git a/libpthread/nptl/sysdeps/sparc/jmpbuf-unwind.h b/libpthread/nptl/sysdeps/sparc/jmpbuf-unwind.h new file mode 100644 index 000000000..6cbb37baf --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/jmpbuf-unwind.h @@ -0,0 +1,5 @@ +#if defined(__arch64__) +#include "sparc64/jmpbuf-unwind.h" +#else +#include "sparc32/jmpbuf-unwind.h" +#endif diff --git a/libpthread/nptl/sysdeps/sparc/pthreaddef.h b/libpthread/nptl/sysdeps/sparc/pthreaddef.h new file mode 100644 index 000000000..d4695c47d --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/pthreaddef.h @@ -0,0 +1,5 @@ +#if defined(__arch64__) +#include "sparc64/pthreaddef.h" +#else +#include "sparc32/pthreaddef.h" +#endif diff --git a/libpthread/nptl/sysdeps/sparc/sparc32/jmpbuf-unwind.h b/libpthread/nptl/sysdeps/sparc/sparc32/jmpbuf-unwind.h new file mode 100644 index 000000000..71a358209 --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/sparc32/jmpbuf-unwind.h @@ -0,0 +1,32 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <setjmp.h> +#include <stdint.h> +#include <unwind.h> + +#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \ + _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj) + +#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \ + ((uintptr_t) (_address) - (_adj) < (uintptr_t) (_jmpbuf)[JB_SP] - (_adj)) + +/* We use the normal longjmp for unwinding. */ +extern __typeof(longjmp) __libc_longjmp attribute_noreturn; +#define __libc_unwind_longjmp(buf, val) __libc_longjmp (buf, val) diff --git a/libpthread/nptl/sysdeps/sparc/sparc32/pthread_spin_lock.c b/libpthread/nptl/sysdeps/sparc/sparc32/pthread_spin_lock.c new file mode 100644 index 000000000..d3c6e3049 --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/sparc32/pthread_spin_lock.c @@ -0,0 +1,40 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" + +int +pthread_spin_lock (pthread_spinlock_t *lock) +{ + __asm __volatile + ("1: ldstub [%0], %%g2\n" + " orcc %%g2, 0x0, %%g0\n" + " bne,a 2f\n" + " ldub [%0], %%g2\n" + ".subsection 2\n" + "2: orcc %%g2, 0x0, %%g0\n" + " bne,a 2b\n" + " ldub [%0], %%g2\n" + " b,a 1b\n" + ".previous" + : /* no outputs */ + : "r" (lock) + : "g2", "memory", "cc"); + return 0; +} diff --git a/libpthread/nptl/sysdeps/sparc/sparc32/pthread_spin_trylock.c b/libpthread/nptl/sysdeps/sparc/sparc32/pthread_spin_trylock.c new file mode 100644 index 000000000..bcc3158fd --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/sparc32/pthread_spin_trylock.c @@ -0,0 +1,29 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include "pthreadP.h" + +int +pthread_spin_trylock (pthread_spinlock_t *lock) +{ + int res; + __asm __volatile ("ldstub [%1], %0" : "=r" (res) : "r" (lock) : "memory"); + return res == 0 ? 0 : EBUSY; +} diff --git a/libpthread/nptl/sysdeps/sparc/sparc32/pthreaddef.h b/libpthread/nptl/sysdeps/sparc/sparc32/pthreaddef.h new file mode 100644 index 000000000..9908df9e9 --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/sparc32/pthreaddef.h @@ -0,0 +1,40 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* Default stack size. */ +#define ARCH_STACK_DEFAULT_SIZE (2 * 1024 * 1024) + +/* Required stack pointer alignment at beginning. */ +#define STACK_ALIGN 16 + +/* Minimal stack size after allocating thread descriptor and guard size. */ +#define MINIMAL_REST_STACK 2048 + +/* Alignment requirement for TCB. */ +#define TCB_ALIGNMENT 16 + + +/* Location of current stack frame. */ +#define CURRENT_STACK_FRAME (stack_pointer + (2 * 64)) +register char *stack_pointer __asm__("%sp"); + +/* XXX Until we have a better place keep the definitions here. */ + +/* While there is no such syscall. */ +#define __exit_thread_inline(val) \ + INLINE_SYSCALL (exit, 1, (val)) diff --git a/libpthread/nptl/sysdeps/sparc/sparc32/sparcv9/pthread_spin_lock.c b/libpthread/nptl/sysdeps/sparc/sparc32/sparcv9/pthread_spin_lock.c new file mode 100644 index 000000000..8880f535b --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/sparc32/sparcv9/pthread_spin_lock.c @@ -0,0 +1,39 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" + +int +pthread_spin_lock (pthread_spinlock_t *lock) +{ + __asm __volatile + ("1: ldstub [%0], %%g2\n" + " brnz,pn %%g2, 2f\n" + " membar #StoreLoad | #StoreStore\n" + ".subsection 2\n" + "2: ldub [%0], %%g2\n" + " brnz,pt %%g2, 2b\n" + " membar #LoadLoad\n" + " b,a,pt %%xcc, 1b\n" + ".previous" + : /* no outputs */ + : "r" (lock) + : "g2", "memory"); + return 0; +} diff --git a/libpthread/nptl/sysdeps/sparc/sparc32/sparcv9/pthread_spin_trylock.c b/libpthread/nptl/sysdeps/sparc/sparc32/sparcv9/pthread_spin_trylock.c new file mode 100644 index 000000000..3b20a2180 --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/sparc32/sparcv9/pthread_spin_trylock.c @@ -0,0 +1 @@ +#include <sparc64/pthread_spin_trylock.c> diff --git a/libpthread/nptl/sysdeps/sparc/sparc32/sparcv9/pthread_spin_unlock.c b/libpthread/nptl/sysdeps/sparc/sparc32/sparcv9/pthread_spin_unlock.c new file mode 100644 index 000000000..482cbe3d7 --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/sparc32/sparcv9/pthread_spin_unlock.c @@ -0,0 +1 @@ +#include <sparc64/pthread_spin_unlock.c> diff --git a/libpthread/nptl/sysdeps/sparc/sparc64/jmpbuf-unwind.h b/libpthread/nptl/sysdeps/sparc/sparc64/jmpbuf-unwind.h new file mode 100644 index 000000000..5cef8b1cf --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/sparc64/jmpbuf-unwind.h @@ -0,0 +1,31 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <setjmp.h> +#include <stdint.h> +#include <unwind.h> + +#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \ + _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj) + +#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \ + ((uintptr_t) (_address) - (_adj) < (uintptr_t) (_jmpbuf)[JB_SP] - (_adj)) + +/* We use the normal lobngjmp for unwinding. */ +#define __libc_unwind_longjmp(buf, val) __libc_longjmp (buf, val) diff --git a/libpthread/nptl/sysdeps/sparc/sparc64/pthread_spin_lock.c b/libpthread/nptl/sysdeps/sparc/sparc64/pthread_spin_lock.c new file mode 100644 index 000000000..77171d9b9 --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/sparc64/pthread_spin_lock.c @@ -0,0 +1,39 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" + +int +pthread_spin_lock (pthread_spinlock_t *lock) +{ + __asm __volatile + ("1: ldstub [%0], %%g5\n" + " brnz,pn %%g5, 2f\n" + " membar #StoreLoad | #StoreStore\n" + ".subsection 2\n" + "2: ldub [%0], %%g5\n" + " brnz,pt %%g5, 2b\n" + " membar #LoadLoad\n" + " b,a,pt %%xcc, 1b\n" + ".previous" + : /* no outputs */ + : "r" (lock) + : "g5", "memory"); + return 0; +} diff --git a/libpthread/nptl/sysdeps/sparc/sparc64/pthread_spin_trylock.c b/libpthread/nptl/sysdeps/sparc/sparc64/pthread_spin_trylock.c new file mode 100644 index 000000000..2bda809da --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/sparc64/pthread_spin_trylock.c @@ -0,0 +1,34 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include "pthreadP.h" + +int +pthread_spin_trylock (pthread_spinlock_t *lock) +{ + int res; + __asm __volatile + ("ldstub [%1], %0\n" + "membar #StoreLoad | #StoreStore" + : "=r" (res) + : "r" (lock) + : "memory"); + return res == 0 ? 0 : EBUSY; +} diff --git a/libpthread/nptl/sysdeps/sparc/sparc64/pthread_spin_unlock.c b/libpthread/nptl/sysdeps/sparc/sparc64/pthread_spin_unlock.c new file mode 100644 index 000000000..7037675a2 --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/sparc64/pthread_spin_unlock.c @@ -0,0 +1,30 @@ +/* pthread_spin_unlock -- unlock a spin lock. Generic version. + Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" +#include <atomic.h> + +int +pthread_spin_unlock (pthread_spinlock_t *lock) +{ + __asm __volatile ("membar #StoreStore | #LoadStore"); + *lock = 0; + return 0; +} diff --git a/libpthread/nptl/sysdeps/sparc/sparc64/pthreaddef.h b/libpthread/nptl/sysdeps/sparc/sparc64/pthreaddef.h new file mode 100644 index 000000000..ec7651211 --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/sparc64/pthreaddef.h @@ -0,0 +1,40 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* Default stack size. */ +#define ARCH_STACK_DEFAULT_SIZE (4 * 1024 * 1024) + +/* Required stack pointer alignment at beginning. */ +#define STACK_ALIGN 16 + +/* Minimal stack size after allocating thread descriptor and guard size. */ +#define MINIMAL_REST_STACK 4096 + +/* Alignment requirement for TCB. */ +#define TCB_ALIGNMENT 16 + + +/* Location of current stack frame. */ +#define CURRENT_STACK_FRAME (stack_pointer + (2 * 128)) +register char *stack_pointer __asm__("%sp"); + +/* XXX Until we have a better place keep the definitions here. */ + +/* While there is no such syscall. */ +#define __exit_thread_inline(val) \ + INLINE_SYSCALL (exit, 1, (val)) diff --git a/libpthread/nptl/sysdeps/sparc/tcb-offsets.sym b/libpthread/nptl/sysdeps/sparc/tcb-offsets.sym new file mode 100644 index 000000000..237f975b2 --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/tcb-offsets.sym @@ -0,0 +1,6 @@ +#include <sysdep.h> +#include <tls.h> + +MULTIPLE_THREADS_OFFSET offsetof (tcbhead_t, multiple_threads) +PID offsetof (struct pthread, pid) +TID offsetof (struct pthread, tid) diff --git a/libpthread/nptl/sysdeps/sparc/tls.h b/libpthread/nptl/sysdeps/sparc/tls.h new file mode 100644 index 000000000..e5d27fb57 --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/tls.h @@ -0,0 +1,139 @@ +/* Definitions for thread-local data handling. NPTL/sparc version. + Copyright (C) 2003, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _TLS_H +#define _TLS_H + +#ifndef __ASSEMBLER__ +# include <stdbool.h> +# include <stddef.h> +# include <stdint.h> +# include <stdlib.h> +# include <list.h> + +/* Type for the dtv. */ +typedef union dtv +{ + size_t counter; + struct + { + void *val; + bool is_static; + } pointer; +} dtv_t; + +typedef struct +{ + void *tcb; /* Pointer to the TCB. Not necessary the + thread descriptor used by libpthread. */ + dtv_t *dtv; + void *self; + int multiple_threads; + uintptr_t sysinfo; + uintptr_t stack_guard; +} tcbhead_t; + +#else /* __ASSEMBLER__ */ +# include <tcb-offsets.h> +#endif /* __ASSEMBLER__ */ + +/* We require TLS support in the tools. */ +#define HAVE_TLS_SUPPORT +#define HAVE___THREAD 1 +#define HAVE_TLS_MODEL_ATTRIBUTE 1 + +/* Signal that TLS support is available. */ +#define USE_TLS 1 + +#ifndef __ASSEMBLER__ +/* Get system call information. */ +# include <sysdep.h> + +register struct pthread *__thread_self __asm__("%g7"); + +/* This is the size of the initial TCB. Can't be just sizeof (tcbhead_t), + because NPTL getpid, __libc_alloca_cutoff etc. need (almost) the whole + struct pthread even when not linked with -lpthread. */ +# define TLS_INIT_TCB_SIZE sizeof (struct pthread) + +/* Alignment requirements for the initial TCB. */ +# define TLS_INIT_TCB_ALIGN __alignof__ (struct pthread) + +/* This is the size of the TCB. */ +# define TLS_TCB_SIZE sizeof (struct pthread) + +/* Alignment requirements for the TCB. */ +# define TLS_TCB_ALIGN __alignof__ (struct pthread) + +/* Get the thread descriptor definition. */ +# include <descr.h> + +/* The TCB can have any size and the memory following the address the + thread pointer points to is unspecified. Allocate the TCB there. */ +# define TLS_TCB_AT_TP 1 + +/* Install the dtv pointer. The pointer passed is to the element with + index -1 which contain the length. */ +# define INSTALL_DTV(descr, dtvp) \ + ((tcbhead_t *) (descr))->dtv = (dtvp) + 1 + +/* Install new dtv for current thread. */ +# define INSTALL_NEW_DTV(DTV) \ + (((tcbhead_t *) __thread_self)->dtv = (DTV)) + +/* Return dtv of given thread descriptor. */ +# define GET_DTV(descr) \ + (((tcbhead_t *) (descr))->dtv) + +/* Code to initially initialize the thread pointer. */ +# define TLS_INIT_TP(descr, secondcall) \ + (__thread_self = (__typeof (__thread_self)) (descr), NULL) + +/* Return the address of the dtv for the current thread. */ +# define THREAD_DTV() \ + (((tcbhead_t *) __thread_self)->dtv) + +/* Return the thread descriptor for the current thread. */ +#define THREAD_SELF __thread_self + +/* Magic for libthread_db to know how to do THREAD_SELF. */ +# define DB_THREAD_SELF_INCLUDE <sys/ucontext.h> +# define DB_THREAD_SELF \ + REGISTER (32, 32, REG_G7 * 4, 0) REGISTER (64, 64, REG_G7 * 8, 0) + +/* Access to data in the thread descriptor is easy. */ +#define THREAD_GETMEM(descr, member) \ + descr->member +#define THREAD_GETMEM_NC(descr, member, idx) \ + descr->member[idx] +#define THREAD_SETMEM(descr, member, value) \ + descr->member = (value) +#define THREAD_SETMEM_NC(descr, member, idx, value) \ + descr->member[idx] = (value) + +/* Set the stack guard field in TCB head. */ +#define THREAD_SET_STACK_GUARD(value) \ + THREAD_SETMEM (THREAD_SELF, header.stack_guard, value) +# define THREAD_COPY_STACK_GUARD(descr) \ + ((descr)->header.stack_guard \ + = THREAD_GETMEM (THREAD_SELF, header.stack_guard)) + +#endif /* !ASSEMBLER */ + +#endif /* tls.h */ diff --git a/libpthread/nptl/sysdeps/unix/sh/sysdep.h b/libpthread/nptl/sysdeps/unix/sh/sysdep.h new file mode 100644 index 000000000..bf1ac0fd4 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sh/sysdep.h @@ -0,0 +1,29 @@ +/* Copyright (C) 1999, 2000 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdeps/unix/sysdep.h> +#include <sysdeps/sh/sysdep.h> + +#ifdef __ASSEMBLER__ + +#define ret rts ; nop + +/* The sh move insn is s, d. */ +#define MOVE(x,y) mov x , y + +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysdep.h b/libpthread/nptl/sysdeps/unix/sysdep.h new file mode 100644 index 000000000..0e7c9da5a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysdep.h @@ -0,0 +1,63 @@ +/* Copyright (C) 1991, 92, 93, 96, 98, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdeps/generic/sysdep.h> + +#include <sys/syscall.h> +#define HAVE_SYSCALLS + +/* Note that using a `PASTE' macro loses. */ +#ifdef __STDC__ +#define SYSCALL__(name, args) PSEUDO (__##name, name, args) +#else +#define SYSCALL__(name, args) PSEUDO (__/**/name, name, args) +#endif +#define SYSCALL(name, args) PSEUDO (name, name, args) + +/* Machine-dependent sysdep.h files are expected to define the macro + PSEUDO (function_name, syscall_name) to emit assembly code to define the + C-callable function FUNCTION_NAME to do system call SYSCALL_NAME. + r0 and r1 are the system call outputs. MOVE(x, y) should be defined as + an instruction such that "MOVE(r1, r0)" works. ret should be defined + as the return instruction. */ + +#ifndef SYS_ify +#ifdef __STDC__ +#define SYS_ify(syscall_name) SYS_##syscall_name +#else +#define SYS_ify(syscall_name) SYS_/**/syscall_name +#endif +#endif + +/* Terminate a system call named SYM. This is used on some platforms + to generate correct debugging information. */ +#ifndef PSEUDO_END +#define PSEUDO_END(sym) +#endif +#ifndef PSEUDO_END_NOERRNO +#define PSEUDO_END_NOERRNO(sym) PSEUDO_END(sym) +#endif +#ifndef PSEUDO_END_ERRVAL +#define PSEUDO_END_ERRVAL(sym) PSEUDO_END(sym) +#endif + +/* Wrappers around system calls should normally inline the system call code. + But sometimes it is not possible or implemented and we use this code. */ +#ifndef INLINE_SYSCALL +#define INLINE_SYSCALL(name, nr, args...) __syscall_##name (args) +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/Makefile b/libpthread/nptl/sysdeps/unix/sysv/linux/Makefile new file mode 100644 index 000000000..34d647527 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/Makefile @@ -0,0 +1,13 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2005 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +top_srcdir=../../../../../../ +top_builddir=../../../../../../ +all: objs +include $(top_builddir)Rules.mak +include Makefile.in +include $(top_srcdir)Makerules diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/Makefile.in b/libpthread/nptl/sysdeps/unix/sysv/linux/Makefile.in new file mode 100644 index 000000000..6c491b6e5 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/Makefile.in @@ -0,0 +1,208 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2006 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +libpthread_CSRC = pthread_attr_getaffinity.c \ + pthread_attr_setaffinity.c pthread_getaffinity.c \ + pthread_getcpuclockid.c pthread_kill.c \ + pthread_mutex_cond_lock.c pthread_setaffinity.c \ + pthread_yield.c sem_post.c sem_timedwait.c \ + sem_trywait.c sem_wait.c pt-fork.c \ + sigtimedwait.c sigwaitinfo.c sigwait.c pt-sleep.c + +libpthread_SSRC = #ptw-close.S ptw-open.S ptw-waitid.S ptw-waidpid.S ptw-write.S + +libc_CSRC = libc_pthread_init.c libc_multiple_threads.c \ + register-atfork.c unregister-atfork.c getpid.c \ + raise.c sleep.c jmp-unwind.c + +# These provide both a cancellable and a not cancellable implementation +libc_SSRC = close.S open.S write.S read.S waitpid.S + +librt_CSRC := mq_notify.c timer_create.c timer_delete.c \ + timer_getoverr.c timer_gettime.c timer_routines.c \ + timer_settime.c + + +ifeq ($(TARGET_ARCH),alpha) +libpthread_CSRC += lowlevellock.c +libc_CSRC += libc-lowlevellock.c +librt_CSRC := mq_notify.c +endif + +ifeq ($(TARGET_ARCH),arm) +libc_SSRC := $(filter-out waitpid.S,$(libc_SSRC)) +endif + +ifeq ($(TARGET_ARCH),mips) +libpthread_CSRC += lowlevellock.c +libc_CSRC += libc-lowlevellock.c +endif + +ifeq ($(TARGET_ARCH),powerpc) +libpthread_CSRC += lowlevellock.c +libc_CSRC += libc-lowlevellock.c +librt_CSRC := mq_notify.c +endif + +ifeq ($(TARGET_ARCH),sparc) +libpthread_CSRC += __syscall_error.c +librt_CSRC += __syscall_error.c +endif + +ifeq ($(TARGET_ARCH),sh) +SH_PTHREAD_SPECIFIC := sem_post.c sem_wait.c sem_timedwait.c sem_trywait.c +libpthread_CSRC := $(filter-out $(SH_PTHREAD_SPECIFIC),$(libpthread_CSRC)) +endif + +ifeq ($(TARGET_ARCH),i386) +X86_PTHREAD_SPECIFIC := sem_post.c sem_wait.c sem_timedwait.c sem_trywait.c +libpthread_CSRC := $(filter-out $(X86_PTHREAD_SPECIFIC),$(libpthread_CSRC)) +endif + +ifeq ($(TARGET_ARCH),x86_64) +libc_SSRC := $(filter-out waitpid.S,$(libc_SSRC)) +X86_PTHREAD_SPECIFIC := sem_post.c sem_wait.c sem_timedwait.c sem_trywait.c +libpthread_CSRC := $(filter-out $(X86_PTHREAD_SPECIFIC),$(libpthread_CSRC)) +endif + +CFLAGS-pthread_getcpuclockid.c = -I$(top_srcdir)librt +CFLAGS-pt-pread_pwrite.c = -I$(top_srcdir)libc/sysdeps/linux/$(TARGET_ARCH) \ + -I$(top_srcdir)libc/sysdeps/linux/common +CFLAGS-mq_notify.c = -I$(top_srcdir)librt -DIS_IN_librt=1 +CFLAGS-timer_create.c = -I$(top_srcdir)librt -DIS_IN_librt=1 +CFLAGS-timer_delete.c = -I$(top_srcdir)librt -DIS_IN_librt=1 +CFLAGS-timer_getoverr.c = -I$(top_srcdir)librt -DIS_IN_librt=1 +CFLAGS-timer_gettime.c = -I$(top_srcdir)librt -DIS_IN_librt=1 +CFLAGS-timer_routines.c = -I$(top_srcdir)librt -DIS_IN_librt=1 +CFLAGS-timer_settime.c = -I$(top_srcdir)librt -DIS_IN_librt=1 + +CFLAGS-linux = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 $(SSP_ALL_CFLAGS) +#CFLAGS:=$(CFLAGS:-O1=-O2) + +CFLAGS-OMIT-libc_pthread_init.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +CFLAGS-OMIT-libc_multiple_threads.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +CFLAGS-OMIT-register-atfork.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +CFLAGS-OMIT-unregister-atfork.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +CFLAGS-OMIT-getpid.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +CFLAGS-OMIT-raise.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +CFLAGS-OMIT-sleep.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +CFLAGS-OMIT-libc-lowlevellock.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 + +CFLAGS-OMIT-close.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +CFLAGS-OMIT-open.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +CFLAGS-OMIT-read.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +CFLAGS-OMIT-write.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +CFLAGS-OMIT-waitpid.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 + +CFLAGS-OMIT-mq_notify.c = -DIS_IN_libpthread=1 +CFLAGS-OMIT-timer_create.c = -DIS_IN_libpthread=1 +CFLAGS-OMIT-timer_delete.c = -DIS_IN_libpthread=1 +CFLAGS-OMIT-timer_getoverr.c = -DIS_IN_libpthread=1 +CFLAGS-OMIT-timer_gettime.c = -DIS_IN_libpthread=1 +CFLAGS-OMIT-timer_routines.c = -DIS_IN_libpthread=1 +CFLAGS-OMIT-timer_settime.c = -DIS_IN_libpthread=1 + +PTHREAD_LINUX_DIR := $(top_srcdir)libpthread/nptl/sysdeps/unix/sysv/linux +PTHREAD_LINUX_OUT := $(top_builddir)libpthread/nptl/sysdeps/unix/sysv/linux + +PTHREAD_LINUX_OBJ := $(patsubst %.c,$(PTHREAD_LINUX_OUT)/%.o,$(libpthread_CSRC)) +PTHREAD_LINUX_OBJ += $(patsubst %.S,$(PTHREAD_LINUX_OUT)/%.o,$(libpthread_SSRC)) + +ifeq ($(DOPIC),y) +libpthread-a-y += $(PTHREAD_LINUX_OBJ:.o=.os) +else +libpthread-a-y += $(PTHREAD_LINUX_OBJ) +endif +libpthread-so-y += $(PTHREAD_LINUX_OBJ:.o=.oS) +libpthread-so-y += $(PTHREAD_LINUX_OUT)/pt-raise.oS +libpthread-nomulti-y += $(PTHREAD_LINUX_OBJ) + +ASFLAGS-open.S = -D_LIBC_REENTRANT +ASFLAGS-close.S = -D_LIBC_REENTRANT +ASFLAGS-read.S = -D_LIBC_REENTRANT +ASFLAGS-write.S = -D_LIBC_REENTRANT +ASFLAGS-waitpid.S = -D_LIBC_REENTRANT + +LIBC_LINUX_OBJ := $(patsubst %.c,$(PTHREAD_LINUX_OUT)/%.o,$(libc_CSRC)) +LIBC_LINUX_OBJ += $(patsubst %.S,$(PTHREAD_LINUX_OUT)/%.o,$(libc_SSRC)) + +libc-static-y += $(LIBC_LINUX_OBJ) +libc-shared-y += $(LIBC_LINUX_OBJ:.o=.oS) +libc-nomulti-y += $(LIBC_LINUX_OBJ) + +LIBRT_LINUX_OBJ := $(patsubst %.c,$(PTHREAD_LINUX_OUT)/%.o,$(librt_CSRC)) + +librt-a-y += $(LIBRT_LINUX_OBJ) +librt-so-y += $(LIBRT_LINUX_OBJ:.o=.oS) + +objclean-y += nptl_linux_clean +headers_clean-y += nptl_linux_headers_clean + +# +# Create header files. +# +CFLAGS-lowlevelbarrier.c = -S +CFLAGS-lowlevelcond.c = -S +CFLAGS-lowlevelrwlock.c = -S +CFLAGS-unwindbuf.c = -S + +$(PTHREAD_LINUX_OUT)/lowlevelbarrier.c: $(PTHREAD_LINUX_DIR)/lowlevelbarrier.sym + $(do_awk) $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@ + +$(PTHREAD_LINUX_OUT)/lowlevelcond.c: $(PTHREAD_LINUX_DIR)/lowlevelcond.sym + $(do_awk) $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@ + +$(PTHREAD_LINUX_OUT)/lowlevelrwlock.c: $(PTHREAD_LINUX_DIR)/lowlevelrwlock.sym + $(do_awk) $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@ + +$(PTHREAD_LINUX_OUT)/unwindbuf.c: $(PTHREAD_LINUX_DIR)/unwindbuf.sym + $(do_awk) $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@ + +$(PTHREAD_LINUX_OUT)/lowlevelbarrier.s: $(PTHREAD_LINUX_OUT)/lowlevelbarrier.c + $(compile.c) + +$(PTHREAD_LINUX_OUT)/lowlevelcond.s: $(PTHREAD_LINUX_OUT)/lowlevelcond.c + $(compile.c) + +$(PTHREAD_LINUX_OUT)/lowlevelrwlock.s: $(PTHREAD_LINUX_OUT)/lowlevelrwlock.c + $(compile.c) + +$(PTHREAD_LINUX_OUT)/unwindbuf.s: $(PTHREAD_LINUX_OUT)/unwindbuf.c + $(compile.c) + +$(PTHREAD_LINUX_OUT)/lowlevelbarrier.h: $(PTHREAD_LINUX_OUT)/lowlevelbarrier.s + $(do_sed) -n "s/^.*@@@name@@@\([^@]*\)@@@value@@@[^0-9Xxa-fA-F-]*\([0-9Xxa-fA-F-][0-9Xxa-fA-F-]*\).*@@@end@@@.*$\/#define \1 \2/p" $< > $@ + +$(PTHREAD_LINUX_OUT)/lowlevelcond.h: $(PTHREAD_LINUX_OUT)/lowlevelcond.s + $(do_sed) -n "s/^.*@@@name@@@\([^@]*\)@@@value@@@[^0-9Xxa-fA-F-]*\([0-9Xxa-fA-F-][0-9Xxa-fA-F-]*\).*@@@end@@@.*$\/#define \1 \2/p" $< > $@ + +$(PTHREAD_LINUX_OUT)/lowlevelrwlock.h: $(PTHREAD_LINUX_OUT)/lowlevelrwlock.s + $(do_sed) -n "s/^.*@@@name@@@\([^@]*\)@@@value@@@[^0-9Xxa-fA-F-]*\([0-9Xxa-fA-F-][0-9Xxa-fA-F-]*\).*@@@end@@@.*$\/#define \1 \2/p" $< > $@ + +$(PTHREAD_LINUX_OUT)/unwindbuf.h: $(PTHREAD_LINUX_OUT)/unwindbuf.s + $(do_sed) -n "s/^.*@@@name@@@\([^@]*\)@@@value@@@[^0-9Xxa-fA-F-]*\([0-9Xxa-fA-F-][0-9Xxa-fA-F-]*\).*@@@end@@@.*$\/#define \1 \2/p" $< > $@ + +nptl_linux_headers: $(PTHREAD_LINUX_OUT)/lowlevelbarrier.h \ + $(PTHREAD_LINUX_OUT)/lowlevelcond.h \ + $(PTHREAD_LINUX_OUT)/lowlevelrwlock.h \ + $(PTHREAD_LINUX_OUT)/unwindbuf.h + +HEADERS_BITS_PTHREAD := $(notdir $(wildcard $(PTHREAD_LINUX_DIR)/bits/*.h)) +ALL_HEADERS_BITS_PTHREAD := $(addprefix include/bits/,$(HEADERS_BITS_PTHREAD)) + +$(ALL_HEADERS_BITS_PTHREAD): + $(do_ln) ../../$(PTHREAD_LINUX_DIR)/bits/$(@F) $(top_builddir)$@ + +nptl_linux_headers_clean: + $(do_rm) $(addprefix $(PTHREAD_LINUX_OUT)/lowlevelbarrier., c h s) \ + $(addprefix $(PTHREAD_LINUX_OUT)/lowlevelcond., c h s) \ + $(addprefix $(PTHREAD_LINUX_OUT)/lowlevelrwlock., c h s) \ + $(addprefix $(PTHREAD_LINUX_OUT)/unwindbuf., c h s) + + +nptl_linux_clean: + $(do_rm) $(addprefix $(PTHREAD_LINUX_OUT)/*., o os oS) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/__syscall_error.c b/libpthread/nptl/sysdeps/unix/sysv/linux/__syscall_error.c new file mode 100644 index 000000000..5e109a83b --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/__syscall_error.c @@ -0,0 +1,18 @@ +/* Wrapper for setting errno. + * + * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org> + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +#include <errno.h> +#include <features.h> + +/* This routine is jumped to by all the syscall handlers, to stash + * an error number into errno. */ +int __syscall_error(int err_no) attribute_hidden; +int __syscall_error(int err_no) +{ + __set_errno(err_no); + return -1; +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/accept.S b/libpthread/nptl/sysdeps/unix/sysv/linux/accept.S new file mode 100644 index 000000000..529763d80 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/accept.S @@ -0,0 +1,12 @@ +#include <sysdep-cancel.h> +#ifndef __NR_accept +#error Missing definition of NR_accept needed for cancellation. +#endif +PSEUDO (__libc_accept, accept, 3) +ret +PSEUDO_END(__libc_accept) +libc_hidden_def (__libc_accept) +weak_alias (__libc_accept, __accept) +libc_hidden_weak (__accept) +weak_alias (__libc_accept, accept) +libc_hidden_weak (accept) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/Makefile b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/Makefile new file mode 100644 index 000000000..8c8084079 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/Makefile @@ -0,0 +1,2 @@ +# pull in __syscall_error routine, __sigprocmask, __syscall_rt_sigaction +libpthread-routines += ptw-sysdep ptw-sigprocmask ptw-rt_sigaction diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/Versions b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/Versions new file mode 100644 index 000000000..437c4da28 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/Versions @@ -0,0 +1,13 @@ +libpthread { + GLIBC_2.3.3 { + # Changed PTHREAD_STACK_MIN. + pthread_attr_setstack; pthread_attr_setstacksize; + } +} +librt { + GLIBC_2.3.3 { + # Changed timer_t. + timer_create; timer_delete; timer_getoverrun; timer_gettime; + timer_settime; + } +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/bits/local_lim.h b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/bits/local_lim.h new file mode 100644 index 000000000..e0718780c --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/bits/local_lim.h @@ -0,0 +1,89 @@ +/* Minimum guaranteed maximum values for system limits. Linux/Alpha version. + Copyright (C) 1993-1998,2000,2002,2003,2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* The kernel header pollutes the namespace with the NR_OPEN symbol + and defines LINK_MAX although filesystems have different maxima. A + similar thing is true for OPEN_MAX: the limit can be changed at + runtime and therefore the macro must not be defined. Remove this + after including the header if necessary. */ +#ifndef NR_OPEN +# define __undef_NR_OPEN +#endif +#ifndef LINK_MAX +# define __undef_LINK_MAX +#endif +#ifndef OPEN_MAX +# define __undef_OPEN_MAX +#endif + +/* The kernel sources contain a file with all the needed information. */ +#include <linux/limits.h> + +/* Have to remove NR_OPEN? */ +#ifdef __undef_NR_OPEN +# undef NR_OPEN +# undef __undef_NR_OPEN +#endif +/* Have to remove LINK_MAX? */ +#ifdef __undef_LINK_MAX +# undef LINK_MAX +# undef __undef_LINK_MAX +#endif +/* Have to remove OPEN_MAX? */ +#ifdef __undef_OPEN_MAX +# undef OPEN_MAX +# undef __undef_OPEN_MAX +#endif + +/* The number of data keys per process. */ +#define _POSIX_THREAD_KEYS_MAX 128 +/* This is the value this implementation supports. */ +#define PTHREAD_KEYS_MAX 1024 + +/* Controlling the iterations of destructors for thread-specific data. */ +#define _POSIX_THREAD_DESTRUCTOR_ITERATIONS 4 +/* Number of iterations this implementation does. */ +#define PTHREAD_DESTRUCTOR_ITERATIONS _POSIX_THREAD_DESTRUCTOR_ITERATIONS + +/* The number of threads per process. */ +#define _POSIX_THREAD_THREADS_MAX 64 +/* We have no predefined limit on the number of threads. */ +#undef PTHREAD_THREADS_MAX + +/* Maximum amount by which a process can descrease its asynchronous I/O + priority level. */ +#define AIO_PRIO_DELTA_MAX 20 + +/* Minimum size for a thread. We are free to choose a reasonable value. */ +#define PTHREAD_STACK_MIN 24576 + +/* Maximum number of timer expiration overruns. */ +#define DELAYTIMER_MAX 2147483647 + +/* Maximum tty name length. */ +#define TTY_NAME_MAX 32 + +/* Maximum login name length. This is arbitrary. */ +#define LOGIN_NAME_MAX 256 + +/* Maximum host name length. */ +#define HOST_NAME_MAX 64 + +/* Maximum message queue priority level. */ +#define MQ_PRIO_MAX 32768 diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h new file mode 100644 index 000000000..0f3bf838e --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h @@ -0,0 +1,168 @@ +/* Machine-specific pthread type layouts. Alpha version. + Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _BITS_PTHREADTYPES_H +#define _BITS_PTHREADTYPES_H 1 + +#define __SIZEOF_PTHREAD_ATTR_T 56 +#define __SIZEOF_PTHREAD_MUTEX_T 40 +#define __SIZEOF_PTHREAD_MUTEXATTR_T 4 +#define __SIZEOF_PTHREAD_COND_T 48 +#define __SIZEOF_PTHREAD_CONDATTR_T 4 +#define __SIZEOF_PTHREAD_RWLOCK_T 56 +#define __SIZEOF_PTHREAD_RWLOCKATTR_T 8 +#define __SIZEOF_PTHREAD_BARRIER_T 32 +#define __SIZEOF_PTHREAD_BARRIERATTR_T 4 + + +/* Thread identifiers. The structure of the attribute type is + deliberately not exposed. */ +typedef unsigned long int pthread_t; + + +typedef union +{ + char __size[__SIZEOF_PTHREAD_ATTR_T]; + long int __align; +} pthread_attr_t; + + +typedef struct __pthread_internal_list +{ + struct __pthread_internal_list *__prev; + struct __pthread_internal_list *__next; +} __pthread_list_t; + + +/* Data structures for mutex handling. The structure of the attribute + type is deliberately not exposed. */ +typedef union +{ + struct __pthread_mutex_s + { + int __lock; + unsigned int __count; + int __owner; + unsigned int __nusers; + /* KIND must stay at this position in the structure to maintain + binary compatibility. */ + int __kind; + int __spins; + __pthread_list_t __list; +#define __PTHREAD_MUTEX_HAVE_PREV 1 + } __data; + char __size[__SIZEOF_PTHREAD_MUTEX_T]; + long int __align; +} pthread_mutex_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_MUTEXATTR_T]; + int __align; +} pthread_mutexattr_t; + + +/* Data structure for conditional variable handling. The structure of + the attribute type is deliberately not exposed. */ +typedef union +{ + struct + { + int __lock; + unsigned int __futex; + __extension__ unsigned long long int __total_seq; + __extension__ unsigned long long int __wakeup_seq; + __extension__ unsigned long long int __woken_seq; + void *__mutex; + unsigned int __nwaiters; + unsigned int __broadcast_seq; + } __data; + char __size[__SIZEOF_PTHREAD_COND_T]; + __extension__ long long int __align; +} pthread_cond_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_CONDATTR_T]; + int __align; +} pthread_condattr_t; + + +/* Keys for thread-specific data */ +typedef unsigned int pthread_key_t; + + +/* Once-only execution */ +typedef int pthread_once_t; + + +#if defined __USE_UNIX98 || defined __USE_XOPEN2K +/* Data structure for read-write lock variable handling. The + structure of the attribute type is deliberately not exposed. */ +typedef union +{ + struct + { + int __lock; + unsigned int __nr_readers; + unsigned int __readers_wakeup; + unsigned int __writer_wakeup; + unsigned int __nr_readers_queued; + unsigned int __nr_writers_queued; + int __writer; + int __pad1; + unsigned long int __pad2; + unsigned long int __pad3; + /* FLAGS must stay at this position in the structure to maintain + binary compatibility. */ + unsigned int __flags; + } __data; + char __size[__SIZEOF_PTHREAD_RWLOCK_T]; + long int __align; +} pthread_rwlock_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_RWLOCKATTR_T]; + long int __align; +} pthread_rwlockattr_t; +#endif + + +#ifdef __USE_XOPEN2K +/* POSIX spinlock data type. */ +typedef volatile int pthread_spinlock_t; + +/* POSIX barriers data type. The structure of the type is + deliberately not exposed. */ +typedef union +{ + char __size[__SIZEOF_PTHREAD_BARRIER_T]; + long int __align; +} pthread_barrier_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_BARRIERATTR_T]; + int __align; +} pthread_barrierattr_t; +#endif + + +#endif /* bits/pthreadtypes.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/bits/semaphore.h b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/bits/semaphore.h new file mode 100644 index 000000000..6dadfda20 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/bits/semaphore.h @@ -0,0 +1,37 @@ +/* Machine-specific POSIX semaphore type layouts. Alpha version. + Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _SEMAPHORE_H +# error "Never use <bits/semaphore.h> directly; include <semaphore.h> instead." +#endif + +# define __SIZEOF_SEM_T 32 + +/* Value returned if `sem_open' failed. */ +#define SEM_FAILED ((sem_t *) 0) + +/* Maximum value the semaphore can have. */ +#define SEM_VALUE_MAX (2147483647) + + +typedef union +{ + char __size[__SIZEOF_SEM_T]; + long int __align; +} sem_t; diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/clone.S b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/clone.S new file mode 100644 index 000000000..eea1cbeed --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/clone.S @@ -0,0 +1,2 @@ +#define RESET_PID +#include <sysdeps/unix/sysv/linux/alpha/clone.S> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/createthread.c b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/createthread.c new file mode 100644 index 000000000..6a51e73da --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/createthread.c @@ -0,0 +1,23 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* Value passed to 'clone' for initialization of the thread register. */ +#define TLS_VALUE (pd + 1) + +/* Get the real implementation. */ +#include <nptl/sysdeps/pthread/createthread.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/fork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/fork.c new file mode 100644 index 000000000..ca85fc008 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/fork.c @@ -0,0 +1,30 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sched.h> +#include <signal.h> +#include <sysdep.h> +#include <tls.h> + + +#define ARCH_FORK() \ + INLINE_SYSCALL (clone, 5, \ + CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD, \ + NULL, NULL, &THREAD_SELF->tid, NULL) + +#include "../fork.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/lowlevellock.h b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/lowlevellock.h new file mode 100644 index 000000000..fd4a7ca4b --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/lowlevellock.h @@ -0,0 +1,217 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Libr \ary; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _LOWLEVELLOCK_H +#define _LOWLEVELLOCK_H 1 + +#include <time.h> +#include <sys/param.h> +#include <bits/pthreadtypes.h> +#include <atomic.h> +#include <sysdep.h> + + +#define __NR_futex 394 +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 +#define FUTEX_REQUEUE 3 +#define FUTEX_CMP_REQUEUE 4 + +/* Initializer for compatibility lock. */ +#define LLL_MUTEX_LOCK_INITIALIZER (0) + +#define lll_futex_wait(futexp, val) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + long int __ret; \ + __ret = INTERNAL_SYSCALL (futex, __err, 4, \ + (futexp), FUTEX_WAIT, (val), 0); \ + INTERNAL_SYSCALL_ERROR_P (__ret, __err)? -__ret : __ret; \ + }) + +#define lll_futex_timed_wait(futexp, val, timespec) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + long int __ret; \ + __ret = INTERNAL_SYSCALL (futex, __err, 4, \ + (futexp), FUTEX_WAIT, (val), (timespec)); \ + INTERNAL_SYSCALL_ERROR_P (__ret, __err)? -__ret : __ret; \ + }) + +#define lll_futex_wake(futexp, nr) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + long int __ret; \ + __ret = INTERNAL_SYSCALL (futex, __err, 4, \ + (futexp), FUTEX_WAKE, (nr), 0); \ + INTERNAL_SYSCALL_ERROR_P (__ret, __err)? -__ret : __ret; \ + }) + +/* Returns non-zero if error happened, zero if success. */ +#define lll_futex_requeue(futexp, nr_wake, nr_move, mutex, val) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + long int __ret; \ + __ret = INTERNAL_SYSCALL (futex, __err, 6, \ + (futexp), FUTEX_CMP_REQUEUE, (nr_wake), \ + (nr_move), (mutex), (val)); \ + INTERNAL_SYSCALL_ERROR_P (__ret, __err); \ + }) + + +static inline int __attribute__((always_inline)) +__lll_mutex_trylock(int *futex) +{ + return atomic_compare_and_exchange_val_acq (futex, 1, 0) != 0; +} +#define lll_mutex_trylock(lock) __lll_mutex_trylock (&(lock)) + + +static inline int __attribute__((always_inline)) +__lll_mutex_cond_trylock(int *futex) +{ + return atomic_compare_and_exchange_val_acq (futex, 2, 0) != 0; +} +#define lll_mutex_cond_trylock(lock) __lll_mutex_cond_trylock (&(lock)) + + +extern void __lll_lock_wait (int *futex) attribute_hidden; + +static inline void __attribute__((always_inline)) +__lll_mutex_lock(int *futex) +{ + if (atomic_compare_and_exchange_bool_acq (futex, 1, 0) != 0) + __lll_lock_wait (futex); +} +#define lll_mutex_lock(futex) __lll_mutex_lock (&(futex)) + + +static inline void __attribute__ ((always_inline)) +__lll_mutex_cond_lock (int *futex) +{ + if (atomic_compare_and_exchange_bool_acq (futex, 2, 0) != 0) + __lll_lock_wait (futex); +} +#define lll_mutex_cond_lock(futex) __lll_mutex_cond_lock (&(futex)) + + +extern int __lll_timedlock_wait (int *futex, const struct timespec *) + attribute_hidden; + +static inline int __attribute__ ((always_inline)) +__lll_mutex_timedlock (int *futex, const struct timespec *abstime) +{ + int result = 0; + if (atomic_compare_and_exchange_bool_acq (futex, 1, 0) != 0) + result = __lll_timedlock_wait (futex, abstime); + return result; +} +#define lll_mutex_timedlock(futex, abstime) \ + __lll_mutex_timedlock (&(futex), abstime) + + +static inline void __attribute__ ((always_inline)) +__lll_mutex_unlock (int *futex) +{ + int val = atomic_exchange_rel (futex, 0); + if (__builtin_expect (val > 1, 0)) + lll_futex_wake (futex, 1); +} +#define lll_mutex_unlock(futex) __lll_mutex_unlock(&(futex)) + + +static inline void __attribute__ ((always_inline)) +__lll_mutex_unlock_force (int *futex) +{ + (void) atomic_exchange_rel (futex, 0); + lll_futex_wake (futex, 1); +} +#define lll_mutex_unlock_force(futex) __lll_mutex_unlock_force(&(futex)) + + +#define lll_mutex_islocked(futex) \ + (futex != 0) + + +/* Our internal lock implementation is identical to the binary-compatible + mutex implementation. */ + +/* Type for lock object. */ +typedef int lll_lock_t; + +/* Initializers for lock. */ +#define LLL_LOCK_INITIALIZER (0) +#define LLL_LOCK_INITIALIZER_LOCKED (1) + +extern int lll_unlock_wake_cb (int *__futex) attribute_hidden; + +/* The states of a lock are: + 0 - untaken + 1 - taken by one user + >1 - taken by more users */ + +#define lll_trylock(lock) lll_mutex_trylock (lock) +#define lll_lock(lock) lll_mutex_lock (lock) +#define lll_unlock(lock) lll_mutex_unlock (lock) +#define lll_islocked(lock) lll_mutex_islocked (lock) + +/* The kernel notifies a process which uses CLONE_CLEARTID via futex + wakeup when the clone terminates. The memory location contains the + thread ID while the clone is running and is reset to zero + afterwards. */ +#define lll_wait_tid(tid) \ + do { \ + __typeof (tid) __tid; \ + while ((__tid = (tid)) != 0) \ + lll_futex_wait (&(tid), __tid); \ + } while (0) + +extern int __lll_timedwait_tid (int *, const struct timespec *) + attribute_hidden; + +#define lll_timedwait_tid(tid, abstime) \ + ({ \ + int __res = 0; \ + if ((tid) != 0) \ + __res = __lll_timedwait_tid (&(tid), (abstime)); \ + __res; \ + }) + + +/* Conditional variable handling. */ + +extern void __lll_cond_wait (pthread_cond_t *cond) + attribute_hidden; +extern int __lll_cond_timedwait (pthread_cond_t *cond, + const struct timespec *abstime) + attribute_hidden; +extern void __lll_cond_wake (pthread_cond_t *cond) + attribute_hidden; +extern void __lll_cond_broadcast (pthread_cond_t *cond) + attribute_hidden; + +#define lll_cond_wait(cond) \ + __lll_cond_wait (cond) +#define lll_cond_timedwait(cond, abstime) \ + __lll_cond_timedwait (cond, abstime) +#define lll_cond_wake(cond) \ + __lll_cond_wake (cond) +#define lll_cond_broadcast(cond) \ + __lll_cond_broadcast (cond) + +#endif /* lowlevellock.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/pt-vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/pt-vfork.S new file mode 100644 index 000000000..ec5d175be --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/pt-vfork.S @@ -0,0 +1,43 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <tcb-offsets.h> + +#undef PSEUDO_PREPARE_ARGS +#define PSEUDO_PREPARE_ARGS \ + /* Load the current cached pid value across the vfork. */ \ + rduniq; \ + ldl a2, PID_OFFSET(v0); \ + mov v0, a1; \ + /* Write back its negation, to indicate that the pid value is \ + uninitialized in the the child, and in the window between \ + here and the point at which we restore the value. */ \ + negl a2, t0; \ + stl t0, PID_OFFSET(v0); + +PSEUDO (__vfork, vfork, 0) + + /* If we're back in the parent, restore the saved pid. */ + beq v0, 1f + stl a2, PID_OFFSET(a1) +1: ret + +PSEUDO_END (__vfork) + +weak_alias (__vfork, vfork) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/pthread_once.c b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/pthread_once.c new file mode 100644 index 000000000..79a3c47ae --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/pthread_once.c @@ -0,0 +1,96 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" +#include <lowlevellock.h> + + +unsigned long int __fork_generation attribute_hidden; + +static void +clear_once_control (void *arg) +{ + pthread_once_t *once_control = (pthread_once_t *) arg; + + *once_control = 0; + lll_futex_wake (once_control, INT_MAX); +} + +int +__pthread_once (pthread_once_t *once_control, void (*init_routine) (void)) +{ + for (;;) + { + int oldval; + int newval; + int tmp; + + /* Pseudo code: + newval = __fork_generation | 1; + oldval = *once_control; + if ((oldval & 2) == 0) + *once_control = newval; + Do this atomically. + */ + newval = __fork_generation | 1; + __asm __volatile ( + "1: ldl_l %0, %2\n" + " and %0, 2, %1\n" + " bne %1, 2f\n" + " mov %3, %1\n" + " stl_c %1, %2\n" + " beq %1, 1b\n" + "2: mb" + : "=&r" (oldval), "=&r" (tmp), "=m" (*once_control) + : "r" (newval), "m" (*once_control)); + + /* Check if the initializer has already been done. */ + if ((oldval & 2) != 0) + return 0; + + /* Check if another thread already runs the initializer. */ + if ((oldval & 1) == 0) + break; + + /* Check whether the initializer execution was interrupted by a fork. */ + if (oldval != newval) + break; + + /* Same generation, some other thread was faster. Wait. */ + lll_futex_wait (once_control, oldval); + } + + /* This thread is the first here. Do the initialization. + Register a cleanup handler so that in case the thread gets + interrupted the initialization can be restarted. */ + pthread_cleanup_push (clear_once_control, once_control); + + init_routine (); + + pthread_cleanup_pop (0); + + /* Add one to *once_control to take the bottom 2 bits from 01 to 10. */ + atomic_increment (once_control); + + /* Wake up all other threads. */ + lll_futex_wake (once_control, INT_MAX); + + return 0; +} +weak_alias (__pthread_once, pthread_once) +strong_alias (__pthread_once, __pthread_once_internal) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/sem_post.c b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/sem_post.c new file mode 100644 index 000000000..27fd817e6 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/sem_post.c @@ -0,0 +1,5 @@ +/* ??? This is an ass-backwards way to do this. We should simply define + the acquire/release semantics of atomic_exchange_and_add. And even if + we don't do this, we should be using atomic_full_barrier or otherwise. */ +#define __lll_rel_instr "mb" +#include "../sem_post.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/sysdep-cancel.h new file mode 100644 index 000000000..49224079e --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/sysdep-cancel.h @@ -0,0 +1,169 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <tls.h> +#ifndef __ASSEMBLER__ +# include <nptl/pthreadP.h> +#endif + +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt + +# ifdef PROF +# define PSEUDO_PROF \ + .set noat; \ + lda AT, _mcount; \ + jsr AT, (AT), _mcount; \ + .set at +# else +# define PSEUDO_PROF +# endif + +/* ??? Assumes that nothing comes between PSEUDO and PSEUDO_END + besides "ret". */ + +# undef PSEUDO +# define PSEUDO(name, syscall_name, args) \ + .globl name; \ + .align 4; \ + .type name, @function; \ + .usepv name, std; \ + cfi_startproc; \ +__LABEL(name) \ + ldgp gp, 0(pv); \ + PSEUDO_PROF; \ + PSEUDO_PREPARE_ARGS \ + SINGLE_THREAD_P(t0); \ + bne t0, $pseudo_cancel; \ + lda v0, SYS_ify(syscall_name); \ + call_pal PAL_callsys; \ + bne a3, SYSCALL_ERROR_LABEL; \ +__LABEL($pseudo_ret) \ + .subsection 2; \ +__LABEL($pseudo_cancel) \ + subq sp, 64, sp; \ + cfi_def_cfa_offset(64); \ + stq ra, 0(sp); \ + cfi_offset(ra, -64); \ + SAVE_ARGS_##args; \ + CENABLE; \ + LOAD_ARGS_##args; \ + /* Save the CENABLE return value in RA. That register \ + is preserved across syscall and the real return \ + address is saved on the stack. */ \ + mov v0, ra; \ + lda v0, SYS_ify(syscall_name); \ + call_pal PAL_callsys; \ + stq v0, 8(sp); \ + mov ra, a0; \ + bne a3, $multi_error; \ + CDISABLE; \ + ldq ra, 0(sp); \ + ldq v0, 8(sp); \ + addq sp, 64, sp; \ + cfi_remember_state; \ + cfi_restore(ra); \ + cfi_def_cfa_offset(0); \ + ret; \ + cfi_restore_state; \ +__LABEL($multi_error) \ + CDISABLE; \ + ldq ra, 0(sp); \ + ldq v0, 8(sp); \ + addq sp, 64, sp; \ + cfi_restore(ra); \ + cfi_def_cfa_offset(0); \ +__LABEL($syscall_error) \ + SYSCALL_ERROR_HANDLER; \ + .previous + +# undef PSEUDO_END +# define PSEUDO_END(sym) \ + .subsection 2; \ + cfi_endproc; \ + .size sym, .-sym + +# define SAVE_ARGS_0 /* Nothing. */ +# define SAVE_ARGS_1 SAVE_ARGS_0; stq a0, 8(sp) +# define SAVE_ARGS_2 SAVE_ARGS_1; stq a1, 16(sp) +# define SAVE_ARGS_3 SAVE_ARGS_2; stq a2, 24(sp) +# define SAVE_ARGS_4 SAVE_ARGS_3; stq a3, 32(sp) +# define SAVE_ARGS_5 SAVE_ARGS_4; stq a4, 40(sp) +# define SAVE_ARGS_6 SAVE_ARGS_5; stq a5, 48(sp) + +# define LOAD_ARGS_0 /* Nothing. */ +# define LOAD_ARGS_1 LOAD_ARGS_0; ldq a0, 8(sp) +# define LOAD_ARGS_2 LOAD_ARGS_1; ldq a1, 16(sp) +# define LOAD_ARGS_3 LOAD_ARGS_2; ldq a2, 24(sp) +# define LOAD_ARGS_4 LOAD_ARGS_3; ldq a3, 32(sp) +# define LOAD_ARGS_5 LOAD_ARGS_4; ldq a4, 40(sp) +# define LOAD_ARGS_6 LOAD_ARGS_5; ldq a5, 48(sp) + +# ifdef IS_IN_libpthread +# define __local_enable_asynccancel __pthread_enable_asynccancel +# define __local_disable_asynccancel __pthread_disable_asynccancel +# define __local_multiple_threads __pthread_multiple_threads +# elif !defined NOT_IN_libc +# define __local_enable_asynccancel __libc_enable_asynccancel +# define __local_disable_asynccancel __libc_disable_asynccancel +# define __local_multiple_threads __libc_multiple_threads +# elif defined IS_IN_librt +# define __local_enable_asynccancel __librt_enable_asynccancel +# define __local_disable_asynccancel __librt_disable_asynccancel +# else +# error Unsupported library +# endif + +# ifdef __PIC__ +# define CENABLE bsr ra, __local_enable_asynccancel !samegp +# define CDISABLE bsr ra, __local_disable_asynccancel !samegp +# else +# define CENABLE jsr ra, __local_enable_asynccancel; ldgp ra, 0(gp) +# define CDISABLE jsr ra, __local_disable_asynccancel; ldgp ra, 0(gp) +# endif + +# if defined IS_IN_libpthread || !defined NOT_IN_libc +# ifndef __ASSEMBLER__ +extern int __local_multiple_threads attribute_hidden; +# define SINGLE_THREAD_P \ + __builtin_expect (__local_multiple_threads == 0, 1) +# elif defined(PIC) +# define SINGLE_THREAD_P(reg) ldl reg, __local_multiple_threads(gp) !gprel +# else +# define SINGLE_THREAD_P(reg) \ + ldah reg, __local_multiple_threads(gp) !gprelhigh; \ + ldl reg, __local_multiple_threads(reg) !gprellow +# endif +# else +# ifndef __ASSEMBLER__ +# define SINGLE_THREAD_P \ + __builtin_expect (THREAD_GETMEM (THREAD_SELF, \ + header.multiple_threads) == 0, 1) +# else +# define SINGLE_THREAD_P(reg) \ + call_pal PAL_rduniq; \ + ldl reg, MULTIPLE_THREADS_OFFSET($0) +# endif +# endif + +#else + +# define SINGLE_THREAD_P (1) +# define NO_CANCELLATION 1 + +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_create.c b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_create.c new file mode 100644 index 000000000..172223af3 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_create.c @@ -0,0 +1 @@ +#include "../x86_64/timer_create.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_delete.c b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_delete.c new file mode 100644 index 000000000..537516e0a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_delete.c @@ -0,0 +1 @@ +#include "../x86_64/timer_delete.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_getoverr.c b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_getoverr.c new file mode 100644 index 000000000..3f21a73c9 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_getoverr.c @@ -0,0 +1 @@ +#include "../x86_64/timer_getoverr.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_gettime.c b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_gettime.c new file mode 100644 index 000000000..a50143adc --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_gettime.c @@ -0,0 +1 @@ +#include "../x86_64/timer_gettime.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_settime.c b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_settime.c new file mode 100644 index 000000000..37baeffac --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_settime.c @@ -0,0 +1 @@ +#include "../x86_64/timer_settime.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/vfork.S new file mode 100644 index 000000000..f0c39982c --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/vfork.S @@ -0,0 +1,46 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <tcb-offsets.h> + +#undef PSEUDO_PREPARE_ARGS +#define PSEUDO_PREPARE_ARGS \ + /* Load the current cached pid value across the vfork. */ \ + rduniq; \ + ldl a2, PID_OFFSET(v0); \ + mov v0, a1; \ + /* If the cached value is initialized (nonzero), then write \ + back its negation, or INT_MIN, to indicate that the pid \ + value is uninitialized in the the child, and in the window \ + between here and the point at which we restore the value. */ \ + ldah t0, -0x8000; \ + negl a2, t1; \ + cmovne a2, t1, t0; \ + stl t0, PID_OFFSET(v0); + +PSEUDO (__vfork, vfork, 0) + + /* If we're back in the parent, restore the saved pid. */ + beq v0, 1f + stl a2, PID_OFFSET(a1) +1: ret + +PSEUDO_END (__vfork) +hidden_def (__vfork) +weak_alias (__vfork, vfork) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/Makefile b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/Makefile new file mode 100644 index 000000000..43a6fad84 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/Makefile @@ -0,0 +1,13 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2005 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +top_srcdir=../../../../../../../ +top_builddir=../../../../../../../ +all: objs +include $(top_builddir)Rules.mak +include Makefile.arch +include $(top_srcdir)Makerules diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/Makefile.arch b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/Makefile.arch new file mode 100644 index 000000000..2256d6b2e --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/Makefile.arch @@ -0,0 +1,56 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2006 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +libpthread_SSRC = pt-vfork.S +libpthread_CSRC = pthread_once.c lowlevellock.c \ + pt-__syscall_rt_sigaction.c pt-__syscall_error.c + +libc_a_CSRC = fork.c +libc_a_SSRC = clone.S vfork.S + +ifeq ($(UCLIBC_HAS_STDIO_FUTEXES),y) +CFLAGS-fork.c = -D__USE_STDIO_FUTEXES__ +endif +CFLAGS-pthread_once.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +CFLAGS-lowlevellock.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 + +ASFLAGS-pt-vfork.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 -marm +# We always compile it in arm mode because of SAVE_PID macro +# This macro should be alternatively implemented in THUMB +# assembly. +ASFLAGS-vfork.S = -marm + +CFLAGS += $(SSP_ALL_CFLAGS) +#CFLAGS:=$(CFLAGS:-O1=-O2) + +LINUX_ARCH_DIR:=$(top_srcdir)libpthread/nptl/sysdeps/unix/sysv/linux/arm +LINUX_ARCH_OUT:=$(top_builddir)libpthread/nptl/sysdeps/unix/sysv/linux/arm + +LINUX_ARCH_OBJ:=$(patsubst %.S,$(LINUX_ARCH_OUT)/%.o,$(libpthread_SSRC)) +LINUX_ARCH_OBJ+=$(patsubst %.c,$(LINUX_ARCH_OUT)/%.o,$(libpthread_CSRC)) + +ifeq ($(DOPIC),y) +libpthread-a-y += $(LINUX_ARCH_OBJ:.o=.os) +else +libpthread-a-y += $(LINUX_ARCH_OBJ) +endif +libpthread-so-y += $(LINUX_ARCH_OBJ:.o=.oS) + +libpthread-nomulti-y+=$(LINUX_ARCH_OBJ) + +LIBC_LINUX_ARCH_OBJ:=$(patsubst %.c,$(LINUX_ARCH_OUT)/%.o,$(libc_a_CSRC)) +LIBC_LINUX_ARCH_OBJ+=$(patsubst %.S,$(LINUX_ARCH_OUT)/%.o,$(libc_a_SSRC)) + +libc-static-y+=$(LIBC_LINUX_ARCH_OBJ) +libc-shared-y+=$(LIBC_LINUX_ARCH_OBJ:.o=.oS) + +libc-nomulti-y+=$(LIBC_LINUX_ARCH_OBJ) + +objclean-y+=pthread_linux_arch_objclean + +pthread_linux_arch_objclean: + $(RM) $(LINUX_ARCH_OUT)/*.{o,os,oS} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/bits/atomic.h b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/bits/atomic.h new file mode 100644 index 000000000..49a935a52 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/bits/atomic.h @@ -0,0 +1,136 @@ +/* Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <stdint.h> +#include <sysdep.h> + + +typedef int8_t atomic8_t; +typedef uint8_t uatomic8_t; +typedef int_fast8_t atomic_fast8_t; +typedef uint_fast8_t uatomic_fast8_t; + +typedef int32_t atomic32_t; +typedef uint32_t uatomic32_t; +typedef int_fast32_t atomic_fast32_t; +typedef uint_fast32_t uatomic_fast32_t; + +typedef intptr_t atomicptr_t; +typedef uintptr_t uatomicptr_t; +typedef intmax_t atomic_max_t; +typedef uintmax_t uatomic_max_t; + +void __arm_link_error (void); + +#ifdef __thumb__ + +/* Note that to allow efficient implementation the arguemtns are reversed + relative to atomic_exchange_acq. */ +int __thumb_swpb (int newvalue, void *mem) + attribute_hidden; +unsigned int __thumb_swp (unsigned int newvalue, void *mem) + attribute_hidden; +unsigned int __thumb_cmpxchg (unsigned int oldval, unsigned int newval, void *mem) + attribute_hidden; + +#define atomic_exchange_acq(mem, newvalue) \ + ({ __typeof (*mem) result; \ + if (sizeof (*mem) == 1) \ + result = __thumb_swpb (newvalue, mem); \ + else if (sizeof (*mem) == 4) \ + result = __thumb_swp (newvalue, mem); \ + else \ + { \ + result = 0; \ + abort (); \ + } \ + result; }) + +#define __arch_compare_and_exchange_val_8_acq(mem, newval, oldval) \ + ({ __arm_link_error (); oldval; }) + +#define __arch_compare_and_exchange_val_16_acq(mem, newval, oldval) \ + ({ __arm_link_error (); oldval; }) + +#define __arch_compare_and_exchange_val_32_acq(mem, newval, oldval) \ + ((__typeof (oldval)) __thumb_cmpxchg (oldval, newval, mem)) + +#define __arch_compare_and_exchange_val_64_acq(mem, newval, oldval) \ + ({ __arm_link_error (); oldval; }) + +#else +/* ARM mode. */ + +#define atomic_exchange_acq(mem, newvalue) \ + ({ __typeof (*mem) _xchg_result; \ + if (sizeof (*mem) == 1) \ + __asm__ __volatile__ ("swpb %0, %1, [%2]" \ + : "=&r,&r" (_xchg_result) \ + : "r,0" (newvalue), "r,r" (mem) : "memory"); \ + else if (sizeof (*mem) == 4) \ + __asm__ __volatile__ ("swp %0, %1, [%2]" \ + : "=&r,&r" (_xchg_result) \ + : "r,0" (newvalue), "r,r" (mem) : "memory"); \ + else \ + { \ + _xchg_result = 0; \ + abort (); \ + } \ + _xchg_result; }) + +/* Atomic compare and exchange. This sequence relies on the kernel to + provide a compare and exchange operation which is atomic on the + current architecture, either via cleverness on pre-ARMv6 or via + ldrex / strex on ARMv6. */ + +#define __arch_compare_and_exchange_val_8_acq(mem, newval, oldval) \ + ({ __arm_link_error (); oldval; }) + +#define __arch_compare_and_exchange_val_16_acq(mem, newval, oldval) \ + ({ __arm_link_error (); oldval; }) + +/* It doesn't matter what register is used for a_oldval2, but we must + specify one to work around GCC PR rtl-optimization/21223. Otherwise + it may cause a_oldval or a_tmp to be moved to a different register. */ + +#define __arch_compare_and_exchange_val_32_acq(mem, newval, oldval) \ + ({ register __typeof (oldval) a_oldval asm ("r0"); \ + register __typeof (oldval) a_newval asm ("r1") = (newval); \ + register __typeof (mem) a_ptr asm ("r2") = (mem); \ + register __typeof (oldval) a_tmp asm ("r3"); \ + register __typeof (oldval) a_oldval2 asm ("r4") = (oldval); \ + __asm__ __volatile__ \ + ("0:\tldr\t%1,[%3]\n\t" \ + "cmp\t%1, %4\n\t" \ + "bne\t1f\n\t" \ + "mov\t%0, %4\n\t" \ + "mov\t%1, #0xffff0fff\n\t" \ + "mov\tlr, pc\n\t" \ + "add\tpc, %1, #(0xffff0fc0 - 0xffff0fff)\n\t" \ + "bcc\t0b\n\t" \ + "mov\t%1, %4\n\t" \ + "1:" \ + : "=&r" (a_oldval), "=&r" (a_tmp) \ + : "r" (a_newval), "r" (a_ptr), "r" (a_oldval2) \ + : "ip", "lr", "cc", "memory"); \ + a_tmp; }) + +#define __arch_compare_and_exchange_val_64_acq(mem, newval, oldval) \ + ({ __arm_link_error (); oldval; }) + +#endif /* __thumb__ */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/bits/pthreadtypes.h b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/bits/pthreadtypes.h new file mode 100644 index 000000000..ea8d6a2f0 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/bits/pthreadtypes.h @@ -0,0 +1,167 @@ +/* Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _BITS_PTHREADTYPES_H +#define _BITS_PTHREADTYPES_H 1 + +#define __SIZEOF_PTHREAD_ATTR_T 36 +#define __SIZEOF_PTHREAD_MUTEX_T 24 +#define __SIZEOF_PTHREAD_MUTEXATTR_T 4 +#define __SIZEOF_PTHREAD_COND_T 48 +#define __SIZEOF_PTHREAD_COND_COMPAT_T 12 +#define __SIZEOF_PTHREAD_CONDATTR_T 4 +#define __SIZEOF_PTHREAD_RWLOCK_T 32 +#define __SIZEOF_PTHREAD_RWLOCKATTR_T 8 +#define __SIZEOF_PTHREAD_BARRIER_T 20 +#define __SIZEOF_PTHREAD_BARRIERATTR_T 4 + + +/* Thread identifiers. The structure of the attribute type is not + exposed on purpose. */ +typedef unsigned long int pthread_t; + + +typedef union +{ + char __size[__SIZEOF_PTHREAD_ATTR_T]; + long int __align; +} pthread_attr_t; + + +typedef struct __pthread_internal_slist +{ + struct __pthread_internal_slist *__next; +} __pthread_slist_t; + + +/* Data structures for mutex handling. The structure of the attribute + type is not exposed on purpose. */ +typedef union +{ + struct __pthread_mutex_s + { + int __lock; + unsigned int __count; + int __owner; + /* KIND must stay at this position in the structure to maintain + binary compatibility. */ + int __kind; + unsigned int __nusers; + __extension__ union + { + int __spins; + __pthread_slist_t __list; + }; + } __data; + char __size[__SIZEOF_PTHREAD_MUTEX_T]; + long int __align; +} pthread_mutex_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_MUTEXATTR_T]; + long int __align; +} pthread_mutexattr_t; + + +/* Data structure for conditional variable handling. The structure of + the attribute type is not exposed on purpose. */ +typedef union +{ + struct + { + int __lock; + unsigned int __futex; + __extension__ unsigned long long int __total_seq; + __extension__ unsigned long long int __wakeup_seq; + __extension__ unsigned long long int __woken_seq; + void *__mutex; + unsigned int __nwaiters; + unsigned int __broadcast_seq; + } __data; + char __size[__SIZEOF_PTHREAD_COND_T]; + __extension__ long long int __align; +} pthread_cond_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_CONDATTR_T]; + long int __align; +} pthread_condattr_t; + + +/* Keys for thread-specific data */ +typedef unsigned int pthread_key_t; + + +/* Once-only execution */ +typedef int pthread_once_t; + + +#if defined __USE_UNIX98 || defined __USE_XOPEN2K +/* Data structure for read-write lock variable handling. The + structure of the attribute type is not exposed on purpose. */ +typedef union +{ + struct + { + int __lock; + unsigned int __nr_readers; + unsigned int __readers_wakeup; + unsigned int __writer_wakeup; + unsigned int __nr_readers_queued; + unsigned int __nr_writers_queued; + /* FLAGS must stay at this position in the structure to maintain + binary compatibility. */ + unsigned int __flags; + int __writer; + } __data; + char __size[__SIZEOF_PTHREAD_RWLOCK_T]; + long int __align; +} pthread_rwlock_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_RWLOCKATTR_T]; + long int __align; +} pthread_rwlockattr_t; +#endif + + +#ifdef __USE_XOPEN2K +/* POSIX spinlock data type. */ +typedef volatile int pthread_spinlock_t; + + +/* POSIX barriers data type. The structure of the type is + deliberately not exposed. */ +typedef union +{ + char __size[__SIZEOF_PTHREAD_BARRIER_T]; + long int __align; +} pthread_barrier_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_BARRIERATTR_T]; + int __align; +} pthread_barrierattr_t; +#endif + + +#endif /* bits/pthreadtypes.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/bits/semaphore.h b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/bits/semaphore.h new file mode 100644 index 000000000..3fc647d31 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/bits/semaphore.h @@ -0,0 +1,38 @@ +/* Copyright (C) 2002, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _SEMAPHORE_H +# error "Never use <bits/semaphore.h> directly; include <semaphore.h> instead." +#endif + + +#define __SIZEOF_SEM_T 16 + + +/* Value returned if `sem_open' failed. */ +#define SEM_FAILED ((sem_t *) 0) + +/* Maximum value the semaphore can have. */ +#define SEM_VALUE_MAX ((int) ((~0u) >> 1)) + + +typedef union +{ + char __size[__SIZEOF_SEM_T]; + long int __align; +} sem_t; diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/clone.S b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/clone.S new file mode 100644 index 000000000..23227eb24 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/clone.S @@ -0,0 +1,3 @@ +#define RESET_PID +#include <tcb-offsets.h> +#include "../../../../../../../libc/sysdeps/linux/arm/clone.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/createthread.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/createthread.c new file mode 100644 index 000000000..2d4355980 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/createthread.c @@ -0,0 +1,23 @@ +/* Copyright (C) 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* Value passed to 'clone' for initialization of the thread register. */ +#define TLS_VALUE (pd + 1) + +/* Get the real implementation. */ +#include <sysdeps/pthread/createthread.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/fork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/fork.c new file mode 100644 index 000000000..1c8f4c43a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/fork.c @@ -0,0 +1,31 @@ +/* Copyright (C) 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Phil Blundell <pb@nexus.co.uk>, 2005 + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sched.h> +#include <signal.h> +#include <sysdep.h> +#include <tls.h> + + +#define ARCH_FORK() \ + INLINE_SYSCALL (clone, 5, \ + CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD, \ + NULL, NULL, NULL, &THREAD_SELF->tid) + +#include "../fork.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/lowlevellock.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/lowlevellock.c new file mode 100644 index 000000000..74be18855 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/lowlevellock.c @@ -0,0 +1,118 @@ +/* low level locking for pthread library. Generic futex-using version. + Copyright (C) 2003, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <sys/time.h> + +int +__lll_timedlock_wait (int *futex, const struct timespec *abstime) +{ + struct timespec rt; + + /* Reject invalid timeouts. */ + if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) + return EINVAL; + + /* Upgrade the lock. */ + if (atomic_exchange_acq (futex, 2) == 0) + return 0; + + do + { + struct timeval tv; + + /* Get the current time. */ + (void) gettimeofday (&tv, NULL); + + /* Compute relative timeout. */ + rt.tv_sec = abstime->tv_sec - tv.tv_sec; + rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000; + if (rt.tv_nsec < 0) + { + rt.tv_nsec += 1000000000; + --rt.tv_sec; + } + + /* Already timed out? */ + if (rt.tv_sec < 0) + return ETIMEDOUT; + + lll_futex_timed_wait (futex, 2, &rt); + } + while (atomic_exchange_acq (futex, 2) != 0); + + return 0; +} + + +/* These don't get included in libc.so */ +#ifdef IS_IN_libpthread +int +lll_unlock_wake_cb (int *futex) +{ + int val = atomic_exchange_rel (futex, 0); + + if (__builtin_expect (val > 1, 0)) + lll_futex_wake (futex, 1); + + return 0; +} + + +int +__lll_timedwait_tid (int *tidp, const struct timespec *abstime) +{ + int tid; + + if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) + return EINVAL; + + /* Repeat until thread terminated. */ + while ((tid = *tidp) != 0) + { + struct timeval tv; + struct timespec rt; + + /* Get the current time. */ + (void) gettimeofday (&tv, NULL); + + /* Compute relative timeout. */ + rt.tv_sec = abstime->tv_sec - tv.tv_sec; + rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000; + if (rt.tv_nsec < 0) + { + rt.tv_nsec += 1000000000; + --rt.tv_sec; + } + + /* Already timed out? */ + if (rt.tv_sec < 0) + return ETIMEDOUT; + + /* Wait until thread terminates. */ + if (lll_futex_timed_wait (tidp, tid, &rt) == -ETIMEDOUT) + return ETIMEDOUT; + } + + return 0; +} + +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/lowlevellock.h b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/lowlevellock.h new file mode 100644 index 000000000..79f3ddeca --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/lowlevellock.h @@ -0,0 +1,339 @@ +/* Copyright (C) 2005, 2006 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Libr \ary; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _LOWLEVELLOCK_H +#define _LOWLEVELLOCK_H 1 + +#include <time.h> +#include <sys/param.h> +#include <bits/pthreadtypes.h> +#include <atomic.h> +#include <sysdep.h> + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 +#define FUTEX_REQUEUE 3 +#define FUTEX_CMP_REQUEUE 4 +#define FUTEX_WAKE_OP 5 +#define FUTEX_OP_CLEAR_WAKE_IF_GT_ONE ((4 << 24) | 1) + +/* Initializer for compatibility lock. */ +#define LLL_MUTEX_LOCK_INITIALIZER (0) + +#define lll_futex_wait(futexp, val) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + long int __ret; \ + __ret = INTERNAL_SYSCALL (futex, __err, 4, \ + (futexp), FUTEX_WAIT, (val), 0); \ + __ret; \ + }) + +#define lll_futex_timed_wait(futexp, val, timespec) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + long int __ret; \ + __ret = INTERNAL_SYSCALL (futex, __err, 4, \ + (futexp), FUTEX_WAIT, (val), (timespec)); \ + __ret; \ + }) + +#define lll_futex_wake(futexp, nr) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + long int __ret; \ + __ret = INTERNAL_SYSCALL (futex, __err, 4, \ + (futexp), FUTEX_WAKE, (nr), 0); \ + __ret; \ + }) + +#define lll_robust_mutex_dead(futexv) \ + do \ + { \ + int *__futexp = &(futexv); \ + atomic_or (__futexp, FUTEX_OWNER_DIED); \ + lll_futex_wake (__futexp, 1); \ + } \ + while (0) + +/* Returns non-zero if error happened, zero if success. */ +#define lll_futex_requeue(futexp, nr_wake, nr_move, mutex, val) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + long int __ret; \ + __ret = INTERNAL_SYSCALL (futex, __err, 6, \ + (futexp), FUTEX_CMP_REQUEUE, (nr_wake), \ + (nr_move), (mutex), (val)); \ + __ret; \ + }) + + +/* Returns non-zero if error happened, zero if success. */ +#define lll_futex_wake_unlock(futexp, nr_wake, nr_wake2, futexp2) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + long int __ret; \ + __ret = INTERNAL_SYSCALL (futex, __err, 6, \ + (futexp), FUTEX_WAKE_OP, (nr_wake), \ + (nr_wake2), (futexp2), \ + FUTEX_OP_CLEAR_WAKE_IF_GT_ONE); \ + __ret; \ + }) + + +static inline int __attribute__((always_inline)) +__lll_mutex_trylock (int *futex) +{ + int flag = 1, old; +#ifdef __thumb__ + old = atomic_exchange_acq (futex, flag); + if (old < 1) + flag = 0; + else if (old > 1) + flag = atomic_exchange_acq (futex, old); +#else + __asm__ __volatile__ ( + "\tswp %[old], %[flag], [%[futex]] @ try to take the lock\n" + "\tcmp %[old], #1 @ check old lock value\n" + "\tmovlo %[flag], #0 @ if we got it, return 0\n" + "\tswphi %[flag], %[old], [%[futex]] @ if it was contested,\n" + " @ restore the contested flag,\n" + " @ and check whether that won." + : [futex] "+&r" (futex), [flag] "+&r" (flag), [old] "=&r" (old) + : : "memory" ); +#endif + + return flag; +} +#define lll_mutex_trylock(lock) __lll_mutex_trylock (&(lock)) + + +static inline int __attribute__((always_inline)) +__lll_mutex_cond_trylock (int *futex) +{ + int flag = 2, old; +#ifdef __thumb__ + old = atomic_exchange_acq (futex, flag); + if (old < 1) + flag = 0; + else if (old > 1) + flag = atomic_exchange_acq (futex, old); +#else + __asm__ __volatile__ ( + "\tswp %[old], %[flag], [%[futex]] @ try to take the lock\n" + "\tcmp %[old], #1 @ check old lock value\n" + "\tmovlo %[flag], #0 @ if we got it, return 0\n" + "\tswphi %[flag], %[old], [%[futex]] @ if it was contested,\n" + " @ restore the contested flag,\n" + " @ and check whether that won." + : [futex] "+&r" (futex), [flag] "+&r" (flag), [old] "=&r" (old) + : : "memory" ); +#endif + + return flag; +} +#define lll_mutex_cond_trylock(lock) __lll_mutex_cond_trylock (&(lock)) + + +static inline int __attribute__((always_inline)) +__lll_robust_mutex_trylock(int *futex, int id) +{ + return atomic_compare_and_exchange_val_acq (futex, id, 0) != 0; +} +#define lll_robust_mutex_trylock(lock, id) \ + __lll_robust_mutex_trylock (&(lock), id) + +extern int __lll_robust_lock_wait (int *futex) attribute_hidden; + +static inline void __attribute__((always_inline)) +__lll_mutex_lock (int *futex) +{ + int val = atomic_exchange_acq (futex, 1); + + if (__builtin_expect (val != 0, 0)) + { + while (atomic_exchange_acq (futex, 2) != 0) + lll_futex_wait (futex, 2); + } +} +#define lll_mutex_lock(futex) __lll_mutex_lock (&(futex)) + + +static inline int __attribute__ ((always_inline)) +__lll_robust_mutex_lock (int *futex, int id) +{ + int result = 0; + if (atomic_compare_and_exchange_bool_acq (futex, id, 0) != 0) + result = __lll_robust_lock_wait (futex); + return result; +} +#define lll_robust_mutex_lock(futex, id) \ + __lll_robust_mutex_lock (&(futex), id) + + +static inline void __attribute__ ((always_inline)) +__lll_mutex_cond_lock (int *futex) +{ + int val = atomic_exchange_acq (futex, 2); + + if (__builtin_expect (val != 0, 0)) + { + while (atomic_exchange_acq (futex, 2) != 0) + lll_futex_wait (futex, 2); + } +} +#define lll_mutex_cond_lock(futex) __lll_mutex_cond_lock (&(futex)) + + +#define lll_robust_mutex_cond_lock(futex, id) \ + __lll_robust_mutex_lock (&(futex), (id) | FUTEX_WAITERS) + + +extern int __lll_timedlock_wait (int *futex, const struct timespec *) + attribute_hidden; +extern int __lll_robust_timedlock_wait (int *futex, const struct timespec *) + attribute_hidden; + +static inline int __attribute__ ((always_inline)) +__lll_mutex_timedlock (int *futex, const struct timespec *abstime) +{ + int result = 0; + int val = atomic_exchange_acq (futex, 1); + + if (__builtin_expect (val != 0, 0)) + result = __lll_timedlock_wait (futex, abstime); + return result; +} +#define lll_mutex_timedlock(futex, abstime) \ + __lll_mutex_timedlock (&(futex), abstime) + + +static inline int __attribute__ ((always_inline)) +__lll_robust_mutex_timedlock (int *futex, const struct timespec *abstime, + int id) +{ + int result = 0; + if (atomic_compare_and_exchange_bool_acq (futex, id, 0) != 0) + result = __lll_robust_timedlock_wait (futex, abstime); + return result; +} +#define lll_robust_mutex_timedlock(futex, abstime, id) \ + __lll_robust_mutex_timedlock (&(futex), abstime, id) + + +static inline void __attribute__ ((always_inline)) +__lll_mutex_unlock (int *futex) +{ + int val = atomic_exchange_rel (futex, 0); + if (__builtin_expect (val > 1, 0)) + lll_futex_wake (futex, 1); +} +#define lll_mutex_unlock(futex) __lll_mutex_unlock(&(futex)) + + +static inline void __attribute__ ((always_inline)) +__lll_robust_mutex_unlock (int *futex, int mask) +{ + int val = atomic_exchange_rel (futex, 0); + if (__builtin_expect (val & mask, 0)) + lll_futex_wake (futex, 1); +} +#define lll_robust_mutex_unlock(futex) \ + __lll_robust_mutex_unlock(&(futex), FUTEX_WAITERS) + + +static inline void __attribute__ ((always_inline)) +__lll_mutex_unlock_force (int *futex) +{ + (void) atomic_exchange_rel (futex, 0); + lll_futex_wake (futex, 1); +} +#define lll_mutex_unlock_force(futex) __lll_mutex_unlock_force(&(futex)) + + +#define lll_mutex_islocked(futex) \ + (futex != 0) + + +/* Our internal lock implementation is identical to the binary-compatible + mutex implementation. */ + +/* Type for lock object. */ +typedef int lll_lock_t; + +/* Initializers for lock. */ +#define LLL_LOCK_INITIALIZER (0) +#define LLL_LOCK_INITIALIZER_LOCKED (1) + +extern int lll_unlock_wake_cb (int *__futex) attribute_hidden; + +/* The states of a lock are: + 0 - untaken + 1 - taken by one user + >1 - taken by more users */ + +#define lll_trylock(lock) lll_mutex_trylock (lock) +#define lll_lock(lock) lll_mutex_lock (lock) +#define lll_unlock(lock) lll_mutex_unlock (lock) +#define lll_islocked(lock) lll_mutex_islocked (lock) + +/* The kernel notifies a process which uses CLONE_CLEARTID via futex + wakeup when the clone terminates. The memory location contains the + thread ID while the clone is running and is reset to zero + afterwards. */ +#define lll_wait_tid(tid) \ + do { \ + __typeof (tid) __tid; \ + while ((__tid = (tid)) != 0) \ + lll_futex_wait (&(tid), __tid); \ + } while (0) + +extern int __lll_timedwait_tid (int *, const struct timespec *) + attribute_hidden; + +#define lll_timedwait_tid(tid, abstime) \ + ({ \ + int __res = 0; \ + if ((tid) != 0) \ + __res = __lll_timedwait_tid (&(tid), (abstime)); \ + __res; \ + }) + + +/* Conditional variable handling. */ + +extern void __lll_cond_wait (pthread_cond_t *cond) + attribute_hidden; +extern int __lll_cond_timedwait (pthread_cond_t *cond, + const struct timespec *abstime) + attribute_hidden; +extern void __lll_cond_wake (pthread_cond_t *cond) + attribute_hidden; +extern void __lll_cond_broadcast (pthread_cond_t *cond) + attribute_hidden; + +#define lll_cond_wait(cond) \ + __lll_cond_wait (cond) +#define lll_cond_timedwait(cond, abstime) \ + __lll_cond_timedwait (cond, abstime) +#define lll_cond_wake(cond) \ + __lll_cond_wake (cond) +#define lll_cond_broadcast(cond) \ + __lll_cond_broadcast (cond) + +#endif /* lowlevellock.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/nptl-aeabi_unwind_cpp_pr1.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/nptl-aeabi_unwind_cpp_pr1.c new file mode 100644 index 000000000..7b8352243 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/nptl-aeabi_unwind_cpp_pr1.c @@ -0,0 +1 @@ +#include <aeabi_unwind_cpp_pr1.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-__syscall_error.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-__syscall_error.c new file mode 100644 index 000000000..5a48a9b2e --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-__syscall_error.c @@ -0,0 +1 @@ +#include <../../../../../../../libc/sysdeps/linux/arm/__syscall_error.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-__syscall_rt_sigaction.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-__syscall_rt_sigaction.c new file mode 100644 index 000000000..50137c84a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-__syscall_rt_sigaction.c @@ -0,0 +1 @@ +#include <../../../../../../../libc/sysdeps/linux/common/__syscall_rt_sigaction.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-gettimeofday.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-gettimeofday.c new file mode 100644 index 000000000..08710f1c8 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-gettimeofday.c @@ -0,0 +1,5 @@ +#include <sys/syscall.h> +#include <sys/time.h> + +int gettimeofday (struct timeval *, struct timezone *) attribute_hidden; +_syscall2(int, gettimeofday, struct timeval *, tv, struct timezone *, tz); diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-vfork.S new file mode 100644 index 000000000..9764e9ee2 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-vfork.S @@ -0,0 +1,38 @@ +/* Copyright (C) 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <tcb-offsets.h> + +/* Save the PID value. */ +#define SAVE_PID \ + str lr, [sp, #-4]!; /* Save LR. */ \ + mov r0, #0xffff0fff; /* Point to the high page. */ \ + mov lr, pc; /* Save our return address. */ \ + sub pc, r0, #31; /* Jump to the TLS entry. */ \ + ldr lr, [sp], #4; /* Restore LR. */ \ + mov r2, r0; /* Save the TLS addr in r2. */ \ + ldr r3, [r2, #PID_OFFSET]; /* Load the saved PID. */ \ + rsb r0, r3, #0; /* Negate it. */ \ + str r0, [r2, #PID_OFFSET] /* Store the temporary PID. */ + +/* Restore the old PID value in the parent. */ +#define RESTORE_PID \ + cmp r0, #0; /* If we are the parent... */ \ + strne r3, [r2, #PID_OFFSET] /* ... restore the saved PID. */ + +#INCLUDE <../../../../../../../LIBC/SYSDEPS/LINUX/ARM/VFORK.S> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pthread_once.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pthread_once.c new file mode 100644 index 000000000..c8925810c --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pthread_once.c @@ -0,0 +1,99 @@ +/* Copyright (C) 2004, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" +#include <lowlevellock.h> + +unsigned long int __fork_generation attribute_hidden; + +static void +clear_once_control (void *arg) +{ + pthread_once_t *once_control = (pthread_once_t *) arg; + + *once_control = 0; + lll_futex_wake (once_control, INT_MAX); +} + +int +__pthread_once (pthread_once_t *once_control, void (*init_routine) (void)) +{ + for (;;) + { + int oldval; + int newval; + + /* Pseudo code: + newval = __fork_generation | 1; + oldval = *once_control; + if ((oldval & 2) == 0) + *once_control = newval; + Do this atomically. + */ + do + { + newval = __fork_generation | 1; + oldval = *once_control; + if (oldval & 2) + break; + } while (atomic_compare_and_exchange_val_acq (once_control, newval, oldval) != oldval); + + /* Check if the initializer has already been done. */ + if ((oldval & 2) != 0) + return 0; + + /* Check if another thread already runs the initializer. */ + if ((oldval & 1) == 0) + break; + + /* Check whether the initializer execution was interrupted by a fork. */ + if (oldval != newval) + break; + + /* Same generation, some other thread was faster. Wait. */ + lll_futex_wait (once_control, oldval); + } + + /* This thread is the first here. Do the initialization. + Register a cleanup handler so that in case the thread gets + interrupted the initialization can be restarted. */ + pthread_cleanup_push (clear_once_control, once_control); + + init_routine (); + + pthread_cleanup_pop (0); + + /* Say that the initialisation is done. */ + *once_control = __fork_generation | 2; + + /* Wake up all other threads. */ + lll_futex_wake (once_control, INT_MAX); + + return 0; +} +weak_alias (__pthread_once, pthread_once) +strong_alias (__pthread_once, __pthread_once_internal) + +#if defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__PIC__) +/* When statically linked, if pthread_create is used, this file + will be brought in. The exception handling code in GCC assumes + that if pthread_create is available, so are these. */ +const void *include_pthread_getspecific attribute_hidden = pthread_getspecific; +const void *include_pthread_setspecific attribute_hidden = pthread_setspecific; +const void *include_pthread_key_create attribute_hidden = pthread_key_create; +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/sysdep-cancel.h new file mode 100644 index 000000000..350d9af50 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/sysdep-cancel.h @@ -0,0 +1,153 @@ +/* Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <tls.h> +#ifndef __ASSEMBLER__ +# include <pthreadP.h> +#endif + +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt + +/* NOTE: We do mark syscalls with unwind annotations, for the benefit of + cancellation; but they're really only accurate at the point of the + syscall. The ARM unwind directives are not rich enough without adding + a custom personality function. */ + +# undef PSEUDO +# define PSEUDO(name, syscall_name, args) \ + .section ".text"; \ + PSEUDO_PROLOGUE; \ + .type __##syscall_name##_nocancel,%function; \ + .globl __##syscall_name##_nocancel; \ + __##syscall_name##_nocancel: \ + DO_CALL (syscall_name, args); \ + PSEUDO_RET; \ + .size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel; \ + ENTRY (name); \ + SINGLE_THREAD_P; \ + DOARGS_##args; \ + bne .Lpseudo_cancel; \ + DO_CALL (syscall_name, 0); \ + UNDOARGS_##args; \ + cmn r0, $4096; \ + PSEUDO_RET; \ + .Lpseudo_cancel: \ + .fnstart; \ + DOCARGS_##args; /* save syscall args etc. around CENABLE. */ \ + CENABLE; \ + mov ip, r0; /* put mask in safe place. */ \ + UNDOCARGS_##args; /* restore syscall args. */ \ + ldr r7, =SYS_ify (syscall_name); \ + swi 0x0; /* do the call. */ \ + .fnend; /* Past here we can't easily unwind. */ \ + mov r7, r0; /* save syscall return value. */ \ + mov r0, ip; /* get mask back. */ \ + CDISABLE; \ + mov r0, r7; /* retrieve return value. */ \ + RESTORE_LR_##args; \ + UNDOARGS_##args; \ + cmn r0, $4096; + +/* DOARGS pushes four bytes on the stack for five arguments, eight bytes for + six arguments, and nothing for fewer. In order to preserve doubleword + alignment, sometimes we must save an extra register. */ + +# define RESTART_UNWIND .fnend; .fnstart; .save {r7, lr} + +# define DOCARGS_0 stmfd sp!, {r7, lr}; .save {r7, lr} +# define UNDOCARGS_0 +# define RESTORE_LR_0 ldmfd sp!, {r7, lr}; + +# define DOCARGS_1 stmfd sp!, {r0, r1, r7, lr}; .save {r7, lr}; .pad #8 +# define UNDOCARGS_1 ldr r0, [sp], #8; RESTART_UNWIND +# define RESTORE_LR_1 RESTORE_LR_0 + +# define DOCARGS_2 stmfd sp!, {r0, r1, r7, lr}; .save {r7, lr}; .pad #8 +# define UNDOCARGS_2 ldmfd sp!, {r0, r1}; RESTART_UNWIND +# define RESTORE_LR_2 RESTORE_LR_0 + +# define DOCARGS_3 stmfd sp!, {r0, r1, r2, r3, r7, lr}; .save {r7, lr}; .pad #16 +# define UNDOCARGS_3 ldmfd sp!, {r0, r1, r2, r3}; RESTART_UNWIND +# define RESTORE_LR_3 RESTORE_LR_0 + +# define DOCARGS_4 stmfd sp!, {r0, r1, r2, r3, r7, lr}; .save {r7, lr}; .pad #16 +# define UNDOCARGS_4 ldmfd sp!, {r0, r1, r2, r3}; RESTART_UNWIND +# define RESTORE_LR_4 RESTORE_LR_0 + +# define DOCARGS_5 .save {r4}; stmfd sp!, {r0, r1, r2, r3, r4, r7, lr}; .save {r7, lr}; .pad #20 +# define UNDOCARGS_5 ldmfd sp!, {r0, r1, r2, r3}; .fnend; .fnstart; .save {r4}; .save {r7, lr}; .pad #4 +# define RESTORE_LR_5 ldmfd sp!, {r4, r7, lr} + +# define DOCARGS_6 .save {r4, r5}; stmfd sp!, {r0, r1, r2, r3, r7, lr}; .save {r7, lr}; .pad #20 +# define UNDOCARGS_6 ldmfd sp!, {r0, r1, r2, r3}; .fnend; .fnstart; .save {r4, r5}; .save {r7, lr} +# define RESTORE_LR_6 RESTORE_LR_0 + +# ifdef IS_IN_libpthread +# define CENABLE bl PLTJMP(__pthread_enable_asynccancel) +# define CDISABLE bl PLTJMP(__pthread_disable_asynccancel) +# define __local_multiple_threads __pthread_multiple_threads +# elif !defined NOT_IN_libc +# define CENABLE bl PLTJMP(__libc_enable_asynccancel) +# define CDISABLE bl PLTJMP(__libc_disable_asynccancel) +# define __local_multiple_threads __libc_multiple_threads +# elif defined IS_IN_librt +# define CENABLE bl PLTJMP(__librt_enable_asynccancel) +# define CDISABLE bl PLTJMP(__librt_disable_asynccancel) +# else +# error Unsupported library +# endif + +# if defined IS_IN_libpthread || !defined NOT_IN_libc +# ifndef __ASSEMBLER__ +extern int __local_multiple_threads attribute_hidden; +# define SINGLE_THREAD_P __builtin_expect (__local_multiple_threads == 0, 1) +# else +# define SINGLE_THREAD_P \ + ldr ip, 1b; \ +2: \ + ldr ip, [pc, ip]; \ + teq ip, #0; +# define PSEUDO_PROLOGUE \ + 1: .word __local_multiple_threads - 2f - 8; +# endif +# else +/* There is no __local_multiple_threads for librt, so use the TCB. */ +# ifndef __ASSEMBLER__ +# define SINGLE_THREAD_P \ + __builtin_expect (THREAD_GETMEM (THREAD_SELF, \ + header.multiple_threads) == 0, 1) +# else +# define PSEUDO_PROLOGUE +# define SINGLE_THREAD_P \ + stmfd sp!, {r0, lr}; \ + bl __aeabi_read_tp; \ + ldr ip, [r0, #MULTIPLE_THREADS_OFFSET]; \ + ldmfd sp!, {r0, lr}; \ + teq ip, #0 +# define SINGLE_THREAD_P_PIC(x) SINGLE_THREAD_P +# endif +# endif + +#elif !defined __ASSEMBLER__ + +/* For rtld, et cetera. */ +# define SINGLE_THREAD_P 1 +# define NO_CANCELLATION 1 + +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/sysdep.h b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/sysdep.h new file mode 100644 index 000000000..23c2bfc8c --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/sysdep.h @@ -0,0 +1,334 @@ +/* Copyright (C) 1992, 93, 1995-2000, 2002, 2003, 2005, 2006 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper, <drepper@gnu.ai.mit.edu>, August 1995. + ARM changes by Philip Blundell, <pjb27@cam.ac.uk>, May 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _LINUX_ARM_SYSDEP_H +#define _LINUX_ARM_SYSDEP_H 1 + +#include <sys/syscall.h> + +/* There is some commonality. */ +#include <sysdeps/arm/sysdep.h> + +/* For Linux we can use the system call table in the header file + /usr/include/asm/unistd.h + of the kernel. But these symbols do not follow the SYS_* syntax + so we have to redefine the `SYS_ify' macro here. */ +#undef SYS_ify +#define SWI_BASE (0x900000) +#define SYS_ify(syscall_name) (__NR_##syscall_name) + + +#ifdef __ASSEMBLER__ + +/* Linux uses a negative return value to indicate syscall errors, + unlike most Unices, which use the condition codes' carry flag. + + Since version 2.1 the return value of a system call might be + negative even if the call succeeded. E.g., the `lseek' system call + might return a large offset. Therefore we must not anymore test + for < 0, but test for a real error by making sure the value in R0 + is a real error number. Linus said he will make sure the no syscall + returns a value in -1 .. -4095 as a valid result so we can safely + test with -4095. */ + +#undef PSEUDO +#define PSEUDO(name, syscall_name, args) \ + .text; \ + ENTRY (name); \ + DO_CALL (syscall_name, args); \ + cmn r0, $4096; + +#define PSEUDO_RET \ + RETINSTR(cc, lr); \ + b PLTJMP(SYSCALL_ERROR) +#undef ret +#define ret PSEUDO_RET + +#undef PSEUDO_END +#define PSEUDO_END(name) \ + SYSCALL_ERROR_HANDLER \ + END (name) + +#undef PSEUDO_NOERRNO +#define PSEUDO_NOERRNO(name, syscall_name, args) \ + .text; \ + ENTRY (name); \ + DO_CALL (syscall_name, args); + +#define PSEUDO_RET_NOERRNO \ + DO_RET (lr); + +#undef ret_NOERRNO +#define ret_NOERRNO PSEUDO_RET_NOERRNO + +#undef PSEUDO_END_NOERRNO +#define PSEUDO_END_NOERRNO(name) \ + END (name) + +/* The function has to return the error code. */ +#undef PSEUDO_ERRVAL +#define PSEUDO_ERRVAL(name, syscall_name, args) \ + .text; \ + ENTRY (name) \ + DO_CALL (syscall_name, args); \ + rsb r0, r0, #0 + +#undef PSEUDO_END_ERRVAL +#define PSEUDO_END_ERRVAL(name) \ + END (name) + +#define ret_ERRVAL PSEUDO_RET_NOERRNO + +#if NOT_IN_libc +# define SYSCALL_ERROR __local_syscall_error +# ifdef RTLD_PRIVATE_ERRNO +# define SYSCALL_ERROR_HANDLER \ +__local_syscall_error: \ + ldr r1, 1f; \ + rsb r0, r0, #0; \ +0: str r0, [pc, r1]; \ + mvn r0, #0; \ + DO_RET(lr); \ +1: .word C_SYMBOL_NAME(rtld_errno) - 0b - 8; +# else +# define SYSCALL_ERROR_HANDLER \ +__local_syscall_error: \ + str lr, [sp, #-4]!; \ + str r0, [sp, #-4]!; \ + bl PLTJMP(C_SYMBOL_NAME(__errno_location)); \ + ldr r1, [sp], #4; \ + rsb r1, r1, #0; \ + str r1, [r0]; \ + mvn r0, #0; \ + ldr pc, [sp], #4; +# endif +#else +# define SYSCALL_ERROR_HANDLER /* Nothing here; code in sysdep.S is used. */ +# define SYSCALL_ERROR __syscall_error +#endif + +/* Linux takes system call args in registers: + syscall number in the SWI instruction + arg 1 r0 + arg 2 r1 + arg 3 r2 + arg 4 r3 + arg 5 r4 (this is different from the APCS convention) + arg 6 r5 + arg 7 r6 + + The compiler is going to form a call by coming here, through PSEUDO, with + arguments + syscall number in the DO_CALL macro + arg 1 r0 + arg 2 r1 + arg 3 r2 + arg 4 r3 + arg 5 [sp] + arg 6 [sp+4] + arg 7 [sp+8] + + We need to shuffle values between R4..R6 and the stack so that the + caller's v1..v3 and stack frame are not corrupted, and the kernel + sees the right arguments. + +*/ + +#undef DO_CALL +#if defined(__ARM_EABI__) +#define DO_CALL(syscall_name, args) \ + DOARGS_##args \ + mov ip, r7; \ + ldr r7, =SYS_ify (syscall_name); \ + swi 0x0; \ + mov r7, ip; \ + UNDOARGS_##args +#else +#define DO_CALL(syscall_name, args) \ + DOARGS_##args \ + swi SYS_ify (syscall_name); \ + UNDOARGS_##args +#endif + +#define DOARGS_0 /* nothing */ +#define DOARGS_1 /* nothing */ +#define DOARGS_2 /* nothing */ +#define DOARGS_3 /* nothing */ +#define DOARGS_4 /* nothing */ +#define DOARGS_5 str r4, [sp, $-4]!; ldr r4, [sp, $4]; +#define DOARGS_6 mov ip, sp; stmfd sp!, {r4, r5}; ldmia ip, {r4, r5}; +#define DOARGS_7 mov ip, sp; stmfd sp!, {r4, r5, r6}; ldmia ip, {r4, r5, r6}; + +#define UNDOARGS_0 /* nothing */ +#define UNDOARGS_1 /* nothing */ +#define UNDOARGS_2 /* nothing */ +#define UNDOARGS_3 /* nothing */ +#define UNDOARGS_4 /* nothing */ +#define UNDOARGS_5 ldr r4, [sp], $4; +#define UNDOARGS_6 ldmfd sp!, {r4, r5}; +#define UNDOARGS_7 ldmfd sp!, {r4, r5, r6}; + +#else /* not __ASSEMBLER__ */ + +/* Define a macro which expands into the inline wrapper code for a system + call. */ +#undef INLINE_SYSCALL +#define INLINE_SYSCALL(name, nr, args...) \ + ({ unsigned int _sys_result = INTERNAL_SYSCALL (name, , nr, args); \ + if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (_sys_result, ), 0)) \ + { \ + __set_errno (INTERNAL_SYSCALL_ERRNO (_sys_result, )); \ + _sys_result = (unsigned int) -1; \ + } \ + (int) _sys_result; }) + +#undef INTERNAL_SYSCALL_DECL +#define INTERNAL_SYSCALL_DECL(err) do { } while (0) + +#undef INTERNAL_SYSCALL_RAW +#if defined(__thumb__) +/* Hide the use of r7 from the compiler, this would be a lot + * easier but for the fact that the syscalls can exceed 255. + * For the moment the LOAD_ARG_7 is sacrificed. + * We can't use push/pop inside the asm because that breaks + * unwinding (ie. thread cancellation). + */ +#define INTERNAL_SYSCALL_RAW(name, err, nr, args...) \ + ({ unsigned int _sys_result; \ + { \ + int _sys_buf[2]; \ + register int _a1 __asm__ ("a1"); \ + register int *_v3 __asm__ ("v3") = _sys_buf; \ + LOAD_ARGS_##nr (args) \ + *_v3 = (int) (name); \ + __asm__ __volatile__ ("str r7, [v3, #4]\n" \ + "\tldr r7, [v3]\n" \ + "\tswi 0 @ syscall " #name "\n" \ + "\tldr r7, [v3, #4]" \ + : "=r" (_a1) \ + : "r" (_v3) ASM_ARGS_##nr \ + : "memory"); \ + _sys_result = _a1; \ + } \ + (int) _sys_result; }) +#elif defined(__ARM_EABI__) +#define INTERNAL_SYSCALL_RAW(name, err, nr, args...) \ + ({unsigned int _sys_result; \ + { \ + register int _a1 __asm__ ("r0"), _nr __asm__ ("r7"); \ + LOAD_ARGS_##nr (args) \ + _nr = name; \ + __asm__ __volatile__ ("swi 0x0 @ syscall " #name \ + : "=r" (_a1) \ + : "r" (_nr) ASM_ARGS_##nr \ + : "memory"); \ + _sys_result = _a1; \ + } \ + (int) _sys_result; }) +#else /* !defined(__ARM_EABI__) */ +#define INTERNAL_SYSCALL_RAW(name, err, nr, args...) \ + ({ unsigned int _sys_result; \ + { \ + register int _a1 __asm__ ("a1"); \ + LOAD_ARGS_##nr (args) \ + __asm__ __volatile__ ("swi %1 @ syscall " #name \ + : "=r" (_a1) \ + : "i" (name) ASM_ARGS_##nr \ + : "memory"); \ + _sys_result = _a1; \ + } \ + (int) _sys_result; }) +#endif + +#undef INTERNAL_SYSCALL +#define INTERNAL_SYSCALL(name, err, nr, args...) \ + INTERNAL_SYSCALL_RAW(SYS_ify(name), err, nr, args) + +#undef INTERNAL_SYSCALL_ARM +#define INTERNAL_SYSCALL_ARM(name, err, nr, args...) \ + INTERNAL_SYSCALL_RAW(__ARM_NR_##name, err, nr, args) + +#undef INTERNAL_SYSCALL_ERROR_P +#define INTERNAL_SYSCALL_ERROR_P(val, err) \ + ((unsigned int) (val) >= 0xfffff001u) + +#undef INTERNAL_SYSCALL_ERRNO +#define INTERNAL_SYSCALL_ERRNO(val, err) (-(val)) + +#define LOAD_ARGS_0() +#define ASM_ARGS_0 +#define LOAD_ARGS_1(a1) \ + _a1 = (int) (a1); \ + LOAD_ARGS_0 () +#define ASM_ARGS_1 ASM_ARGS_0, "r" (_a1) +#define LOAD_ARGS_2(a1, a2) \ + register int _a2 __asm__ ("a2") = (int) (a2); \ + LOAD_ARGS_1 (a1) +#define ASM_ARGS_2 ASM_ARGS_1, "r" (_a2) +#define LOAD_ARGS_3(a1, a2, a3) \ + register int _a3 __asm__ ("a3") = (int) (a3); \ + LOAD_ARGS_2 (a1, a2) +#define ASM_ARGS_3 ASM_ARGS_2, "r" (_a3) +#define LOAD_ARGS_4(a1, a2, a3, a4) \ + register int _a4 __asm__ ("a4") = (int) (a4); \ + LOAD_ARGS_3 (a1, a2, a3) +#define ASM_ARGS_4 ASM_ARGS_3, "r" (_a4) +#define LOAD_ARGS_5(a1, a2, a3, a4, a5) \ + register int _v1 __asm__ ("v1") = (int) (a5); \ + LOAD_ARGS_4 (a1, a2, a3, a4) +#define ASM_ARGS_5 ASM_ARGS_4, "r" (_v1) +#define LOAD_ARGS_6(a1, a2, a3, a4, a5, a6) \ + register int _v2 __asm__ ("v2") = (int) (a6); \ + LOAD_ARGS_5 (a1, a2, a3, a4, a5) +#define ASM_ARGS_6 ASM_ARGS_5, "r" (_v2) +#define LOAD_ARGS_7(a1, a2, a3, a4, a5, a6, a7) \ + register int _v3 __asm__ ("v3") = (int) (a7); \ + LOAD_ARGS_6 (a1, a2, a3, a4, a5, a6) +#define ASM_ARGS_7 ASM_ARGS_6, "r" (_v3) + +#if defined(__ARM_EABI__) +#undef INTERNAL_SYSCALL_NCS +#define INTERNAL_SYSCALL_NCS(number, err, nr, args...) \ + INTERNAL_SYSCALL_RAW(number, err, nr, args) +#else +/* We can't implement non-constant syscalls directly since the syscall + number is normally encoded in the instruction. So use SYS_syscall. */ +#undef INTERNAL_SYSCALL_NCS +#define INTERNAL_SYSCALL_NCS(number, err, nr, args...) \ + INTERNAL_SYSCALL_NCS_##nr (number, err, args) + +#define INTERNAL_SYSCALL_NCS_0(number, err, args...) \ + INTERNAL_SYSCALL (syscall, err, 1, number, args) +#define INTERNAL_SYSCALL_NCS_1(number, err, args...) \ + INTERNAL_SYSCALL (syscall, err, 2, number, args) +#define INTERNAL_SYSCALL_NCS_2(number, err, args...) \ + INTERNAL_SYSCALL (syscall, err, 3, number, args) +#define INTERNAL_SYSCALL_NCS_3(number, err, args...) \ + INTERNAL_SYSCALL (syscall, err, 4, number, args) +#define INTERNAL_SYSCALL_NCS_4(number, err, args...) \ + INTERNAL_SYSCALL (syscall, err, 5, number, args) +#define INTERNAL_SYSCALL_NCS_5(number, err, args...) \ + INTERNAL_SYSCALL (syscall, err, 6, number, args) +#endif + +#endif /* __ASSEMBLER__ */ + +#endif /* linux/arm/sysdep.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind-forcedunwind.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind-forcedunwind.c new file mode 100644 index 000000000..206202809 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind-forcedunwind.c @@ -0,0 +1,129 @@ +/* Copyright (C) 2003, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <dlfcn.h> +#include <string.h> +#include <unwind.h> +#include <unistd.h> +#include <pthreadP.h> + +#define __libc_dlopen(x) dlopen(x, (RTLD_LOCAL | RTLD_LAZY)) +#define __libc_dlsym dlsym + +static void (*libgcc_s_resume) (struct _Unwind_Exception *exc); +static _Unwind_Reason_Code (*libgcc_s_personality) + (_Unwind_State, 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 +pthread_cancel_init (void) +{ + void *resume, *personality, *forcedunwind, *getcfa; + void *handle; + + if (__builtin_expect (libgcc_s_getcfa != NULL, 1)) + return; + + handle = __libc_dlopen ("libgcc_s.so.1"); + + 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 + ) + { +# define STR_N_LEN(str) str, strlen (str) + INTERNAL_SYSCALL_DECL (err); + INTERNAL_SYSCALL (write, err, 3, STDERR_FILENO, + STR_N_LEN ("libgcc_s.so.1 must be installed for pthread_cancel to work\n")); + abort (); + } + + libgcc_s_resume = resume; + libgcc_s_personality = personality; + libgcc_s_forcedunwind = forcedunwind; + libgcc_s_getcfa = getcfa; +} + +/* It's vitally important that _Unwind_Resume not have a stack frame; the + ARM unwinder relies on register state at entrance. So we write this in + assembly. */ + +asm ( +#ifdef __thumb__ +" .code 32" +#endif +" .globl _Unwind_Resume\n" +" .type _Unwind_Resume, %function\n" +"_Unwind_Resume:\n" +" stmfd sp!, {r4, r5, r6, lr}\n" +" ldr r4, 1f\n" +" ldr r5, 2f\n" +"3: add r4, pc, r4\n" +" ldr r3, [r4, r5]\n" +" mov r6, r0\n" +" cmp r3, #0\n" +" beq 4f\n" +"5: mov r0, r6\n" +" ldmfd sp!, {r4, r5, r6, lr}\n" +" bx r3\n" +"4: bl pthread_cancel_init\n" +" ldr r3, [r4, r5]\n" +" b 5b\n" +"1: .word _GLOBAL_OFFSET_TABLE_ - 3b - 8\n" +"2: .word libgcc_s_resume(GOTOFF)\n" +" .size _Unwind_Resume, .-_Unwind_Resume\n" +#ifdef __thumb__ +" .code 16" +#endif +); + +_Unwind_Reason_Code +__gcc_personality_v0 (_Unwind_State state, + struct _Unwind_Exception *ue_header, + struct _Unwind_Context *context) +{ + if (__builtin_expect (libgcc_s_personality == NULL, 0)) + pthread_cancel_init (); + return libgcc_s_personality (state, ue_header, context); +} + +_Unwind_Reason_Code +_Unwind_ForcedUnwind (struct _Unwind_Exception *exc, _Unwind_Stop_Fn stop, + void *stop_argument) +{ + if (__builtin_expect (libgcc_s_forcedunwind == NULL, 0)) + pthread_cancel_init (); + return libgcc_s_forcedunwind (exc, stop, stop_argument); +} + +_Unwind_Word +_Unwind_GetCFA (struct _Unwind_Context *context) +{ + if (__builtin_expect (libgcc_s_getcfa == NULL, 0)) + pthread_cancel_init (); + return libgcc_s_getcfa (context); +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind-resume.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind-resume.c new file mode 100644 index 000000000..99b15746a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind-resume.c @@ -0,0 +1,95 @@ +/* Copyright (C) 2003, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <dlfcn.h> +#include <stdio.h> +#include <stdlib.h> +#include <unwind.h> + +#define __libc_dlopen(x) dlopen(x, (RTLD_LOCAL | RTLD_LAZY)) +#define __libc_dlsym dlsym + +static void (*libgcc_s_resume) (struct _Unwind_Exception *exc); +static _Unwind_Reason_Code (*libgcc_s_personality) + (_Unwind_State, struct _Unwind_Exception *, struct _Unwind_Context *); + +static void init (void) __attribute_used__; + +static void +init (void) +{ + void *resume, *personality; + void *handle; + + handle = __libc_dlopen ("libgcc_s.so.1"); + + if (handle == NULL + || (resume = __libc_dlsym (handle, "_Unwind_Resume")) == NULL + || (personality = __libc_dlsym (handle, "__gcc_personality_v0")) == NULL) { + fprintf(stderr, "libgcc_s.so.1 must be installed for pthread_cancel to work\n"); + abort (); + } + + libgcc_s_resume = resume; + libgcc_s_personality = personality; +} + +/* It's vitally important that _Unwind_Resume not have a stack frame; the + ARM unwinder relies on register state at entrance. So we write this in + assembly. */ + +__asm__ ( +#ifdef __thumb__ +" .code 32\n" +#endif +" .globl _Unwind_Resume\n" +" .type _Unwind_Resume, %function\n" +"_Unwind_Resume:\n" +" stmfd sp!, {r4, r5, r6, lr}\n" +" ldr r4, 1f\n" +" ldr r5, 2f\n" +"3: add r4, pc, r4\n" +" ldr r3, [r4, r5]\n" +" mov r6, r0\n" +" cmp r3, #0\n" +" beq 4f\n" +"5: mov r0, r6\n" +" ldmfd sp!, {r4, r5, r6, lr}\n" +" bx r3\n" +"4: bl init\n" +" ldr r3, [r4, r5]\n" +" b 5b\n" +"1: .word _GLOBAL_OFFSET_TABLE_ - 3b - 8\n" +"2: .word libgcc_s_resume(GOTOFF)\n" +" .size _Unwind_Resume, .-_Unwind_Resume\n" +#ifdef __thumb__ +" .code 16\n" +#endif + +); + +_Unwind_Reason_Code +__gcc_personality_v0 (_Unwind_State state, + struct _Unwind_Exception *ue_header, + struct _Unwind_Context *context) +{ + if (__builtin_expect (libgcc_s_personality == NULL, 0)) + init (); + return libgcc_s_personality (state, ue_header, context); +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind.h b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind.h new file mode 100644 index 000000000..d625fb288 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind.h @@ -0,0 +1,274 @@ +/* Header file for the ARM EABI unwinder + Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. + Contributed by Paul Brook + + This file is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + In addition to the permissions in the GNU General Public License, the + Free Software Foundation gives you unlimited permission to link the + compiled version of this file into combinations with other programs, + and to distribute those combinations without any restriction coming + from the use of this file. (The General Public License restrictions + do apply in other respects; for example, they cover modification of + the file, and distribution when not linked into a combine + executable.) + + This file is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ + +/* Language-independent unwinder header public defines. This contains both + ABI defined objects, and GNU support routines. */ + +#ifndef UNWIND_ARM_H +#define UNWIND_ARM_H + +#define __ARM_EABI_UNWINDER__ 1 + +#ifdef __cplusplus +extern "C" { +#endif + typedef unsigned _Unwind_Word __attribute__((__mode__(__word__))); + typedef signed _Unwind_Sword __attribute__((__mode__(__word__))); + typedef unsigned _Unwind_Ptr __attribute__((__mode__(__pointer__))); + typedef unsigned _Unwind_Internal_Ptr __attribute__((__mode__(__pointer__))); + typedef _Unwind_Word _uw; + typedef unsigned _uw64 __attribute__((mode(__DI__))); + typedef unsigned _uw16 __attribute__((mode(__HI__))); + typedef unsigned _uw8 __attribute__((mode(__QI__))); + + typedef enum + { + _URC_OK = 0, /* operation completed successfully */ + _URC_FOREIGN_EXCEPTION_CAUGHT = 1, + _URC_END_OF_STACK = 5, + _URC_HANDLER_FOUND = 6, + _URC_INSTALL_CONTEXT = 7, + _URC_CONTINUE_UNWIND = 8, + _URC_FAILURE = 9 /* unspecified failure of some kind */ + } + _Unwind_Reason_Code; + + typedef enum + { + _US_VIRTUAL_UNWIND_FRAME = 0, + _US_UNWIND_FRAME_STARTING = 1, + _US_UNWIND_FRAME_RESUME = 2, + _US_ACTION_MASK = 3, + _US_FORCE_UNWIND = 8, + _US_END_OF_STACK = 16 + } + _Unwind_State; + + /* Provided only for for compatibility with existing code. */ + typedef int _Unwind_Action; +#define _UA_SEARCH_PHASE 1 +#define _UA_CLEANUP_PHASE 2 +#define _UA_HANDLER_FRAME 4 +#define _UA_FORCE_UNWIND 8 +#define _UA_END_OF_STACK 16 +#define _URC_NO_REASON _URC_OK + + typedef struct _Unwind_Control_Block _Unwind_Control_Block; + typedef struct _Unwind_Context _Unwind_Context; + typedef _uw _Unwind_EHT_Header; + + + /* UCB: */ + + struct _Unwind_Control_Block + { +#ifdef _LIBC + /* For the benefit of code which assumes this is a scalar. All + glibc ever does is clear it. */ + _uw64 exception_class; +#else + char exception_class[8]; +#endif + void (*exception_cleanup)(_Unwind_Reason_Code, _Unwind_Control_Block *); + /* Unwinder cache, private fields for the unwinder's use */ + struct + { + _uw reserved1; /* Forced unwind stop fn, 0 if not forced */ + _uw reserved2; /* Personality routine address */ + _uw reserved3; /* Saved callsite address */ + _uw reserved4; /* Forced unwind stop arg */ + _uw reserved5; + } + unwinder_cache; + /* Propagation barrier cache (valid after phase 1): */ + struct + { + _uw sp; + _uw bitpattern[5]; + } + barrier_cache; + /* Cleanup cache (preserved over cleanup): */ + struct + { + _uw bitpattern[4]; + } + cleanup_cache; + /* Pr cache (for pr's benefit): */ + struct + { + _uw fnstart; /* function start address */ + _Unwind_EHT_Header *ehtp; /* pointer to EHT entry header word */ + _uw additional; /* additional data */ + _uw reserved1; + } + pr_cache; + long long int :0; /* Force alignment to 8-byte boundary */ + }; + + /* Virtual Register Set*/ + + typedef enum + { + _UVRSC_CORE = 0, /* integer register */ + _UVRSC_VFP = 1, /* vfp */ + _UVRSC_FPA = 2, /* fpa */ + _UVRSC_WMMXD = 3, /* Intel WMMX data register */ + _UVRSC_WMMXC = 4 /* Intel WMMX control register */ + } + _Unwind_VRS_RegClass; + + typedef enum + { + _UVRSD_UINT32 = 0, + _UVRSD_VFPX = 1, + _UVRSD_FPAX = 2, + _UVRSD_UINT64 = 3, + _UVRSD_FLOAT = 4, + _UVRSD_DOUBLE = 5 + } + _Unwind_VRS_DataRepresentation; + + typedef enum + { + _UVRSR_OK = 0, + _UVRSR_NOT_IMPLEMENTED = 1, + _UVRSR_FAILED = 2 + } + _Unwind_VRS_Result; + + /* Frame unwinding state. */ + typedef struct + { + /* The current word (bytes packed msb first). */ + _uw data; + /* Pointer to the next word of data. */ + _uw *next; + /* The number of bytes left in this word. */ + _uw8 bytes_left; + /* The number of words pointed to by ptr. */ + _uw8 words_left; + } + __gnu_unwind_state; + + typedef _Unwind_Reason_Code (*personality_routine) (_Unwind_State, + _Unwind_Control_Block *, _Unwind_Context *); + + _Unwind_VRS_Result _Unwind_VRS_Set(_Unwind_Context *, _Unwind_VRS_RegClass, + _uw, _Unwind_VRS_DataRepresentation, + void *); + + _Unwind_VRS_Result _Unwind_VRS_Get(_Unwind_Context *, _Unwind_VRS_RegClass, + _uw, _Unwind_VRS_DataRepresentation, + void *); + + _Unwind_VRS_Result _Unwind_VRS_Pop(_Unwind_Context *, _Unwind_VRS_RegClass, + _uw, _Unwind_VRS_DataRepresentation); + + + /* Support functions for the PR. */ +#define _Unwind_Exception _Unwind_Control_Block + typedef char _Unwind_Exception_Class[8]; + + void * _Unwind_GetLanguageSpecificData (_Unwind_Context *); + _Unwind_Ptr _Unwind_GetRegionStart (_Unwind_Context *); + + /* These two should never be used. */ + _Unwind_Ptr _Unwind_GetDataRelBase (_Unwind_Context *); + _Unwind_Ptr _Unwind_GetTextRelBase (_Unwind_Context *); + + /* Interface functions: */ + _Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Control_Block *ucbp); + void __attribute__((noreturn)) _Unwind_Resume(_Unwind_Control_Block *ucbp); + _Unwind_Reason_Code _Unwind_Resume_or_Rethrow (_Unwind_Control_Block *ucbp); + + typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn) + (int, _Unwind_Action, _Unwind_Exception_Class, + _Unwind_Control_Block *, struct _Unwind_Context *, void *); + _Unwind_Reason_Code _Unwind_ForcedUnwind (_Unwind_Control_Block *, + _Unwind_Stop_Fn, void *); + _Unwind_Word _Unwind_GetCFA (struct _Unwind_Context *); + void _Unwind_Complete(_Unwind_Control_Block *ucbp); + void _Unwind_DeleteException (_Unwind_Exception *); + + _Unwind_Reason_Code __gnu_unwind_frame (_Unwind_Control_Block *, + _Unwind_Context *); + _Unwind_Reason_Code __gnu_unwind_execute (_Unwind_Context *, + __gnu_unwind_state *); + + /* Decode an R_ARM_TARGET2 relocation. */ + static inline _Unwind_Word + _Unwind_decode_target2 (_Unwind_Word ptr) + { + _Unwind_Word tmp; + + tmp = *(_Unwind_Word *) ptr; + /* Zero values are always NULL. */ + if (!tmp) + return 0; + +#if defined(linux) || defined(__NetBSD__) + /* Pc-relative indirect. */ + tmp += ptr; + tmp = *(_Unwind_Word *) tmp; +#elif defined(__symbian__) + /* Absolute pointer. Nothing more to do. */ +#else + /* Pc-relative pointer. */ + tmp += ptr; +#endif + return tmp; + } + + static inline _Unwind_Word + _Unwind_GetGR (_Unwind_Context *context, int regno) + { + _uw val; + _Unwind_VRS_Get (context, _UVRSC_CORE, regno, _UVRSD_UINT32, &val); + return val; + } + + /* Return the address of the instruction, not the actual IP value. */ +#define _Unwind_GetIP(context) \ + (_Unwind_GetGR (context, 15) & ~(_Unwind_Word)1) + + static inline void + _Unwind_SetGR (_Unwind_Context *context, int regno, _Unwind_Word val) + { + _Unwind_VRS_Set (context, _UVRSC_CORE, regno, _UVRSD_UINT32, &val); + } + + /* The dwarf unwinder doesn't understand arm/thumb state. We assume the + landing pad uses the same instruction set as the call site. */ +#define _Unwind_SetIP(context, val) \ + _Unwind_SetGR (context, 15, val | (_Unwind_GetGR (context, 15) & 1)) + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* defined UNWIND_ARM_H */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/vfork.S new file mode 100644 index 000000000..935a4e904 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/vfork.S @@ -0,0 +1,39 @@ +/* Copyright (C) 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <tcb-offsets.h> + +/* Save the PID value. */ +#define SAVE_PID \ + str lr, [sp, #-4]!; /* Save LR. */ \ + mov r0, #0xffff0fff; /* Point to the high page. */ \ + mov lr, pc; /* Save our return address. */ \ + sub pc, r0, #31; /* Jump to the TLS entry. */ \ + ldr lr, [sp], #4; /* Restore LR. */ \ + mov r2, r0; /* Save the TLS addr in r2. */ \ + ldr r3, [r2, #PID_OFFSET]; /* Load the saved PID. */ \ + rsbs r0, r3, #0; /* Negate it. */ \ + moveq r0, #0x80000000; /* Use 0x80000000 if it was 0. */ \ + str r0, [r2, #PID_OFFSET] /* Store the temporary PID. */ + +/* Restore the old PID value in the parent. */ +#define RESTORE_PID \ + cmp r0, #0; /* If we are the parent... */ \ + strne r3, [r2, #PID_OFFSET] /* ... restore the saved PID. */ + +#include "../../../../../../../libc/sysdeps/linux/arm/vfork.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/bits/local_lim.h b/libpthread/nptl/sysdeps/unix/sysv/linux/bits/local_lim.h new file mode 100644 index 000000000..b639ba44a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/bits/local_lim.h @@ -0,0 +1,89 @@ +/* Minimum guaranteed maximum values for system limits. Linux version. + Copyright (C) 1993-1998,2000,2002,2003,2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* The kernel header pollutes the namespace with the NR_OPEN symbol + and defines LINK_MAX although filesystems have different maxima. A + similar thing is true for OPEN_MAX: the limit can be changed at + runtime and therefore the macro must not be defined. Remove this + after including the header if necessary. */ +#ifndef NR_OPEN +# define __undef_NR_OPEN +#endif +#ifndef LINK_MAX +# define __undef_LINK_MAX +#endif +#ifndef OPEN_MAX +# define __undef_OPEN_MAX +#endif + +/* The kernel sources contain a file with all the needed information. */ +#include <linux/limits.h> + +/* Have to remove NR_OPEN? */ +#ifdef __undef_NR_OPEN +# undef NR_OPEN +# undef __undef_NR_OPEN +#endif +/* Have to remove LINK_MAX? */ +#ifdef __undef_LINK_MAX +# undef LINK_MAX +# undef __undef_LINK_MAX +#endif +/* Have to remove OPEN_MAX? */ +#ifdef __undef_OPEN_MAX +# undef OPEN_MAX +# undef __undef_OPEN_MAX +#endif + +/* The number of data keys per process. */ +#define _POSIX_THREAD_KEYS_MAX 128 +/* This is the value this implementation supports. */ +#define PTHREAD_KEYS_MAX 1024 + +/* Controlling the iterations of destructors for thread-specific data. */ +#define _POSIX_THREAD_DESTRUCTOR_ITERATIONS 4 +/* Number of iterations this implementation does. */ +#define PTHREAD_DESTRUCTOR_ITERATIONS _POSIX_THREAD_DESTRUCTOR_ITERATIONS + +/* The number of threads per process. */ +#define _POSIX_THREAD_THREADS_MAX 64 +/* We have no predefined limit on the number of threads. */ +#undef PTHREAD_THREADS_MAX + +/* Maximum amount by which a process can descrease its asynchronous I/O + priority level. */ +#define AIO_PRIO_DELTA_MAX 20 + +/* Minimum size for a thread. We are free to choose a reasonable value. */ +#define PTHREAD_STACK_MIN 16384 + +/* Maximum number of timer expiration overruns. */ +#define DELAYTIMER_MAX 2147483647 + +/* Maximum tty name length. */ +#define TTY_NAME_MAX 32 + +/* Maximum login name length. This is arbitrary. */ +#define LOGIN_NAME_MAX 256 + +/* Maximum host name length. */ +#define HOST_NAME_MAX 64 + +/* Maximum message queue priority level. */ +#define MQ_PRIO_MAX 32768 diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/bits/posix_opt.h b/libpthread/nptl/sysdeps/unix/sysv/linux/bits/posix_opt.h new file mode 100644 index 000000000..92c2d3282 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/bits/posix_opt.h @@ -0,0 +1,178 @@ +/* Define POSIX options for Linux. + Copyright (C) 1996-2001, 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef _POSIX_OPT_H +#define _POSIX_OPT_H 1 + +/* Job control is supported. */ +#define _POSIX_JOB_CONTROL 1 + +/* Processes have a saved set-user-ID and a saved set-group-ID. */ +#define _POSIX_SAVED_IDS 1 + +/* Priority scheduling is supported. */ +#define _POSIX_PRIORITY_SCHEDULING 200112L + +/* Synchronizing file data is supported. */ +#define _POSIX_SYNCHRONIZED_IO 200112L + +/* The fsync function is present. */ +#define _POSIX_FSYNC 200112L + +/* Mapping of files to memory is supported. */ +#define _POSIX_MAPPED_FILES 200112L + +/* Locking of all memory is supported. */ +#define _POSIX_MEMLOCK 200112L + +/* Locking of ranges of memory is supported. */ +#define _POSIX_MEMLOCK_RANGE 200112L + +/* Setting of memory protections is supported. */ +#define _POSIX_MEMORY_PROTECTION 200112L + +/* Only root can change owner of file. */ +#define _POSIX_CHOWN_RESTRICTED 1 + +/* `c_cc' member of 'struct termios' structure can be disabled by + using the value _POSIX_VDISABLE. */ +#define _POSIX_VDISABLE '\0' + +/* Filenames are not silently truncated. */ +#define _POSIX_NO_TRUNC 1 + +/* X/Open realtime support is available. */ +#define _XOPEN_REALTIME 1 + +/* XPG4.2 shared memory is supported. */ +#define _XOPEN_SHM 1 + +/* Tell we have POSIX threads. */ +#define _POSIX_THREADS 200112L + +/* We have the reentrant functions described in POSIX. */ +#define _POSIX_REENTRANT_FUNCTIONS 1 +#define _POSIX_THREAD_SAFE_FUNCTIONS 200112L + +/* We provide priority scheduling for threads. */ +#define _POSIX_THREAD_PRIORITY_SCHEDULING 200112L + +/* We support user-defined stack sizes. */ +#define _POSIX_THREAD_ATTR_STACKSIZE 200112L + +/* We support user-defined stacks. */ +#define _POSIX_THREAD_ATTR_STACKADDR 200112L + +/* We support POSIX.1b semaphores. */ +#define _POSIX_SEMAPHORES 200112L + +/* Real-time signals are supported. */ +#define _POSIX_REALTIME_SIGNALS 200112L + +/* We support asynchronous I/O. */ +#define _POSIX_ASYNCHRONOUS_IO 200112L +#define _POSIX_ASYNC_IO 1 +/* Alternative name for Unix98. */ +#define _LFS_ASYNCHRONOUS_IO 1 +/* Support for prioritization is also available. */ +#define _POSIX_PRIORITIZED_IO 200112L + +/* The LFS support in asynchronous I/O is also available. */ +#define _LFS64_ASYNCHRONOUS_IO 1 + +/* The rest of the LFS is also available. */ +#define _LFS_LARGEFILE 1 +#define _LFS64_LARGEFILE 1 +#define _LFS64_STDIO 1 + +/* POSIX shared memory objects are implemented. */ +#define _POSIX_SHARED_MEMORY_OBJECTS 200112L + +/* CPU-time clocks support needs to be checked at runtime. */ +#define _POSIX_CPUTIME 0 + +/* Clock support in threads must be also checked at runtime. */ +#define _POSIX_THREAD_CPUTIME 0 + +/* GNU libc provides regular expression handling. */ +#define _POSIX_REGEXP 1 + +/* Reader/Writer locks are available. */ +#define _POSIX_READER_WRITER_LOCKS 200112L + +/* We have a POSIX shell. */ +#define _POSIX_SHELL 1 + +/* We support the Timeouts option. */ +#define _POSIX_TIMEOUTS 200112L + +/* We support spinlocks. */ +#define _POSIX_SPIN_LOCKS 200112L + +/* The `spawn' function family is supported. */ +#define _POSIX_SPAWN 200112L + +/* We have POSIX timers. */ +#define _POSIX_TIMERS 200112L + +/* The barrier functions are available. */ +#define _POSIX_BARRIERS 200112L + +/* POSIX message queues are available. */ +#define _POSIX_MESSAGE_PASSING 200112L + +/* Thread process-shared synchronization is supported. */ +#define _POSIX_THREAD_PROCESS_SHARED 200112L + +/* The monotonic clock might be available. */ +#define _POSIX_MONOTONIC_CLOCK 0 + +/* The clock selection interfaces are available. */ +#define _POSIX_CLOCK_SELECTION 200112L + +/* Advisory information interfaces are available. */ +#define _POSIX_ADVISORY_INFO 200112L + +/* IPv6 support is available. */ +#define _POSIX_IPV6 200112L + +/* Raw socket support is available. */ +#define _POSIX_RAW_SOCKETS 200112L + +/* We have at least one terminal. */ +#define _POSIX2_CHAR_TERM 200112L + +/* Neither process nor thread sporadic server interfaces is available. */ +#define _POSIX_SPORADIC_SERVER -1 +#define _POSIX_THREAD_SPORADIC_SERVER -1 + +/* trace.h is not available. */ +#define _POSIX_TRACE -1 +#define _POSIX_TRACE_EVENT_FILTER -1 +#define _POSIX_TRACE_INHERIT -1 +#define _POSIX_TRACE_LOG -1 + +/* Typed memory objects are not available. */ +#define _POSIX_TYPED_MEMORY_OBJECTS -1 + +/* No support for priority inheritance or protection so far. */ +#define _POSIX_THREAD_PRIO_INHERIT -1 +#define _POSIX_THREAD_PRIO_PROTECT -1 + +#endif /* posix_opt.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/close.S b/libpthread/nptl/sysdeps/unix/sysv/linux/close.S new file mode 100644 index 000000000..cf50a1eae --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/close.S @@ -0,0 +1,21 @@ +#include <sysdep-cancel.h> + +/* +extern int __close_nocancel (int) attribute_hidden; +*/ +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt + + +PSEUDO (__libc_close, close, 1) +ret +PSEUDO_END(__libc_close) + +libc_hidden_def (__close_nocancel) +libc_hidden_def (__libc_close) +weak_alias (__libc_close, __close) +libc_hidden_weak (__close) +weak_alias (__libc_close, close) +libc_hidden_weak (close) + + +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/connect.S b/libpthread/nptl/sysdeps/unix/sysv/linux/connect.S new file mode 100644 index 000000000..441843fa0 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/connect.S @@ -0,0 +1,12 @@ +#include <sysdep-cancel.h> +#ifndef __NR_connect +#error Missing definition of NR_connect needed for cancellation. +#endif +PSEUDO (__libc_connect, connect, 3) +ret +PSEUDO_END(__libc_connect) +libc_hidden_def (__libc_connect) +weak_alias (__libc_connect, __connect) +libc_hidden_weak (__connect) +weak_alias (__libc_connect, connect) +libc_hidden_weak (connect) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/creat.S b/libpthread/nptl/sysdeps/unix/sysv/linux/creat.S new file mode 100644 index 000000000..cd0e1b879 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/creat.S @@ -0,0 +1,7 @@ +#include <sysdep-cancel.h> +PSEUDO (__libc_creat, creat, 2) +ret +PSEUDO_END(__libc_creat) +libc_hidden_def (__libc_creat) +weak_alias (__libc_creat, creat) +libc_hidden_weak (creat) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/createthread.c b/libpthread/nptl/sysdeps/unix/sysv/linux/createthread.c new file mode 100644 index 000000000..9149efe58 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/createthread.c @@ -0,0 +1,24 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* Value passed to 'clone' for initialization of the thread register. */ +#define TLS_VALUE pd + +/* Get the real implementation. */ +#include <sysdeps/pthread/createthread.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/exit-thread.S b/libpthread/nptl/sysdeps/unix/sysv/linux/exit-thread.S new file mode 100644 index 000000000..bb996fecf --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/exit-thread.S @@ -0,0 +1,23 @@ +/* Copyright (C) 1991,92,97,99,2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> + +PSEUDO (__exit_thread, exit, 1) + /* Shouldn't get here. */ +PSEUDO_END(__exit_thread) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/fork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/fork.c new file mode 100644 index 000000000..a84b5c237 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/fork.c @@ -0,0 +1,220 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <sys/types.h> +#include <sysdep.h> +#include <tls.h> +#include "fork.h" +#include <hp-timing.h> +#include <ldsodefs.h> +#include <atomic.h> +#include <errno.h> + +unsigned long int *__fork_generation_pointer; + + + +/* The single linked list of all currently registered for handlers. */ +struct fork_handler *__fork_handlers; + + +static void +fresetlockfiles (void) +{ + FILE *fp; +#ifdef __USE_STDIO_FUTEXES__ + for (fp = _stdio_openlist; fp != NULL; fp = fp->__nextopen) + STDIO_INIT_MUTEX(fp->__lock); +#else + pthread_mutexattr_t attr; + + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP); + + for (fp = _stdio_openlist; fp != NULL; fp = fp->__nextopen) + pthread_mutex_init(&fp->__lock, &attr); + + pthread_mutexattr_destroy(&attr); +#endif +} + +extern __typeof(fork) __libc_fork; +pid_t __libc_fork (void) +{ + pid_t pid; + struct used_handler + { + struct fork_handler *handler; + struct used_handler *next; + } *allp = NULL; + + /* Run all the registered preparation handlers. In reverse order. + While doing this we build up a list of all the entries. */ + struct fork_handler *runp; + while ((runp = __fork_handlers) != NULL) + { + unsigned int oldval = runp->refcntr; + + if (oldval == 0) + /* This means some other thread removed the list just after + the pointer has been loaded. Try again. Either the list + is empty or we can retry it. */ + continue; + + /* Bump the reference counter. */ + if (atomic_compare_and_exchange_bool_acq (&__fork_handlers->refcntr, + oldval + 1, oldval)) + /* The value changed, try again. */ + continue; + + /* We bumped the reference counter for the first entry in the + list. That means that none of the following entries will + just go away. The unloading code works in the order of the + list. + + While executing the registered handlers we are building a + list of all the entries so that we can go backward later on. */ + while (1) + { + /* Execute the handler if there is one. */ + if (runp->prepare_handler != NULL) + runp->prepare_handler (); + + /* Create a new element for the list. */ + struct used_handler *newp + = (struct used_handler *) alloca (sizeof (*newp)); + newp->handler = runp; + newp->next = allp; + allp = newp; + + /* Advance to the next handler. */ + runp = runp->next; + if (runp == NULL) + break; + + /* Bump the reference counter for the next entry. */ + atomic_increment (&runp->refcntr); + } + + /* We are done. */ + break; + } + + __UCLIBC_IO_MUTEX_LOCK_CANCEL_UNSAFE(_stdio_openlist_add_lock); + +#ifndef NDEBUG + pid_t ppid = THREAD_GETMEM (THREAD_SELF, tid); +#endif + + /* We need to prevent the getpid() code to update the PID field so + that, if a signal arrives in the child very early and the signal + handler uses getpid(), the value returned is correct. */ + pid_t parentpid = THREAD_GETMEM (THREAD_SELF, pid); + THREAD_SETMEM (THREAD_SELF, pid, -parentpid); + +#ifdef ARCH_FORK + pid = ARCH_FORK (); +#else +# error "ARCH_FORK must be defined so that the CLONE_SETTID flag is used" + pid = INLINE_SYSCALL (fork, 0); +#endif + + + if (pid == 0) + { + struct pthread *self = THREAD_SELF; + + assert (THREAD_GETMEM (self, tid) != ppid); + + if (__fork_generation_pointer != NULL) + *__fork_generation_pointer += 4; + + /* Adjust the PID field for the new process. */ + THREAD_SETMEM (self, pid, THREAD_GETMEM (self, tid)); + +#if HP_TIMING_AVAIL + /* The CPU clock of the thread and process have to be set to zero. */ + hp_timing_t now; + HP_TIMING_NOW (now); + THREAD_SETMEM (self, cpuclock_offset, now); + GL(dl_cpuclock_offset) = now; +#endif + + /* Reset the file list. These are recursive mutexes. */ + fresetlockfiles (); + + /* Reset locks in the I/O code. */ + STDIO_INIT_MUTEX(_stdio_openlist_add_lock); + + /* Run the handlers registered for the child. */ + while (allp != NULL) + { + if (allp->handler->child_handler != NULL) + allp->handler->child_handler (); + + /* Note that we do not have to wake any possible waiter. + This is the only thread in the new process. */ + --allp->handler->refcntr; + + /* XXX We could at this point look through the object pool + and mark all objects not on the __fork_handlers list as + unused. This is necessary in case the fork() happened + while another thread called dlclose() and that call had + to create a new list. */ + + allp = allp->next; + } + + /* Initialize the fork lock. */ + __fork_lock = (lll_lock_t) LLL_LOCK_INITIALIZER; + } + else + { + assert (THREAD_GETMEM (THREAD_SELF, tid) == ppid); + + /* Restore the PID value. */ + THREAD_SETMEM (THREAD_SELF, pid, parentpid); + + /* We execute this even if the 'fork' call failed. */ + __UCLIBC_IO_MUTEX_UNLOCK_CANCEL_UNSAFE(_stdio_openlist_add_lock); + + /* Run the handlers registered for the parent. */ + while (allp != NULL) + { + if (allp->handler->parent_handler != NULL) + allp->handler->parent_handler (); + + if (atomic_decrement_and_test (&allp->handler->refcntr) + && allp->handler->need_signal) + lll_futex_wake (allp->handler->refcntr, 1); + + allp = allp->next; + } + } + + return pid; +} +weak_alias(__libc_fork,__fork) +libc_hidden_proto(fork) +weak_alias(__libc_fork,fork) +libc_hidden_weak(fork) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/fork.h b/libpthread/nptl/sysdeps/unix/sysv/linux/fork.h new file mode 100644 index 000000000..bcdf6217c --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/fork.h @@ -0,0 +1,56 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <lowlevellock.h> + +/* The fork generation counter, defined in libpthread. */ +extern unsigned long int __fork_generation attribute_hidden; + +/* Pointer to the fork generation counter in the thread library. */ +extern unsigned long int *__fork_generation_pointer attribute_hidden; + +/* Lock to protect allocation and deallocation of fork handlers. */ +extern lll_lock_t __fork_lock attribute_hidden; + +/* Elements of the fork handler lists. */ +struct fork_handler +{ + struct fork_handler *next; + void (*prepare_handler) (void); + void (*parent_handler) (void); + void (*child_handler) (void); + void *dso_handle; + unsigned int refcntr; + int need_signal; +}; + +/* The single linked list of all currently registered for handlers. */ +extern struct fork_handler *__fork_handlers; + + +/* Function to call to unregister fork handlers. */ +extern void __unregister_atfork (void *dso_handle) attribute_hidden; +#define UNREGISTER_ATFORK(dso_handle) __unregister_atfork (dso_handle) + + +/* C library side function to register new fork handlers. */ +extern int __register_atfork (void (*__prepare) (void), + void (*__parent) (void), + void (*__child) (void), + void *dso_handle); diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/getpid.c b/libpthread/nptl/sysdeps/unix/sysv/linux/getpid.c new file mode 100644 index 000000000..9a4f51c9d --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/getpid.c @@ -0,0 +1,63 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <unistd.h> +#include <tls.h> +#include <sysdep.h> + + +extern __typeof(getpid) __getpid; +#ifndef NOT_IN_libc +static __always_inline pid_t really_getpid (pid_t oldval); + +static __always_inline pid_t really_getpid (pid_t oldval) +{ + if (__builtin_expect (oldval == 0, 1)) + { + pid_t selftid = THREAD_GETMEM (THREAD_SELF, tid); + if (__builtin_expect (selftid != 0, 1)) + return selftid; + } + + INTERNAL_SYSCALL_DECL (err); + pid_t result = INTERNAL_SYSCALL (getpid, err, 0); + + /* We do not set the PID field in the TID here since we might be + called from a signal handler while the thread executes fork. */ + if (oldval == 0) + THREAD_SETMEM (THREAD_SELF, tid, result); + return result; +} +#endif + +pid_t __getpid (void) +{ +#ifdef NOT_IN_libc + INTERNAL_SYSCALL_DECL (err); + pid_t result = INTERNAL_SYSCALL (getpid, err, 0); +#else + pid_t result = THREAD_GETMEM (THREAD_SELF, pid); + if (__builtin_expect (result <= 0, 0)) + result = really_getpid (result); +#endif + return result; +} +libc_hidden_proto(getpid) +weak_alias(__getpid, getpid) +libc_hidden_weak(getpid) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/Makefile b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/Makefile new file mode 100644 index 000000000..43a6fad84 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/Makefile @@ -0,0 +1,13 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2005 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +top_srcdir=../../../../../../../ +top_builddir=../../../../../../../ +all: objs +include $(top_builddir)Rules.mak +include Makefile.arch +include $(top_srcdir)Makerules diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/Makefile.arch b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/Makefile.arch new file mode 100644 index 000000000..740ee7fcb --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/Makefile.arch @@ -0,0 +1,74 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2006 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# +LINUX_ARCH_DIR:=$(top_srcdir)libpthread/nptl/sysdeps/unix/sysv/linux/i386 +LINUX_ARCH_OUT:=$(top_builddir)libpthread/nptl/sysdeps/unix/sysv/linux/i386 + + +libpthread_SSRC = pt-vfork.S clone.S pthread_spin_unlock.S pthread_once.S +libpthread_CSRC = pthread_spin_init.c pt-__syscall_error.c + +libc_a_CSRC = fork.c +libc_a_SSRC = clone.S vfork.S + +libpthread_SSRC += i486/lowlevellock.S i486/pthread_barrier_wait.S i486/pthread_cond_signal.S i486/pthread_cond_broadcast.S \ + i486/sem_post.S i486/sem_timedwait.S \ + i486/sem_trywait.S i486/sem_wait.S i486/pthread_rwlock_rdlock.S i486/pthread_rwlock_wrlock.S \ + i486/pthread_rwlock_timedrdlock.S i486/pthread_rwlock_timedwrlock.S i486/pthread_rwlock_unlock.S +#i486/pthread_cond_timedwait.S i486/pthread_cond_wait.S + +libc_a_SSRC += i486/libc-lowlevellock.S + + +CFLAGS-OMIT-fork.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 + +ifeq ($(UCLIBC_HAS_STDIO_FUTEXES),y) +CFLAGS-fork.c = -D__USE_STDIO_FUTEXES__ +endif + +ASFLAGS-pt-vfork.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 -D_LIBC_REENTRANT -DUSE___THREAD +ASFLAGS-lowlevellock.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 -D_LIBC_REENTRANT -DUSE___THREAD +ASFLAGS-pthread_once.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 -D_LIBC_REENTRANT -DUSE___THREAD +ASFLAGS-pthread_spin_unlock.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 -D_LIBC_REENTRANT -DUSE___THREAD + + +ASFLAGS-clone.S = -D_LIBC_REENTRANT +ASFLAGS-vfork.S = -D_LIBC_REENTRANT +ASFLAGS-libc-lowlevellock.S = -D_LIBC_REENTRANT + +ifeq ($(UCLIBC_HAS_THREADS_NATIVE),y) +#Needed to use the correct SYSCALL_ERROR_HANDLER +ASFLAGS-clone.S += -DUSE___THREAD +ASFLAGS-vfork.S += -DUSE___THREAD +endif + +CFLAGS += $(SSP_ALL_CFLAGS) +#CFLAGS:=$(CFLAGS:-O1=-O2) + +LINUX_ARCH_OBJ:=$(patsubst %.S,$(LINUX_ARCH_OUT)/%.o,$(libpthread_SSRC)) +LINUX_ARCH_OBJ+=$(patsubst %.c,$(LINUX_ARCH_OUT)/%.o,$(libpthread_CSRC)) + +ifeq ($(DOPIC),y) +libpthread-a-y += $(LINUX_ARCH_OBJ:.o=.os) +else +libpthread-a-y += $(LINUX_ARCH_OBJ) +endif +libpthread-so-y += $(LINUX_ARCH_OBJ:.o=.oS) + +libpthread-nomulti-y+=$(LINUX_ARCH_OBJS) + +LIBC_LINUX_ARCH_OBJ:=$(patsubst %.c,$(LINUX_ARCH_OUT)/%.o,$(libc_a_CSRC)) +LIBC_LINUX_ARCH_OBJ+=$(patsubst %.S,$(LINUX_ARCH_OUT)/%.o,$(libc_a_SSRC)) + +libc-static-y+=$(LIBC_LINUX_ARCH_OBJ) +libc-shared-y+=$(LIBC_LINUX_ARCH_OBJ:.o=.oS) + +libc-nomulti-y+=$(LIBC_LINUX_ARCH_OBJ) + +objclean-y+=nptl_linux_arch_clean + +nptl_linux_arch_clean: + $(do_rm) $(addprefix $(LINUX_ARCH_OUT)/*., o os oS) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h new file mode 100644 index 000000000..0ec6e5534 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h @@ -0,0 +1,170 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _BITS_PTHREADTYPES_H +#define _BITS_PTHREADTYPES_H 1 + +#define __SIZEOF_PTHREAD_ATTR_T 36 +#define __SIZEOF_PTHREAD_MUTEX_T 24 +#define __SIZEOF_PTHREAD_MUTEXATTR_T 4 +#define __SIZEOF_PTHREAD_COND_T 48 +#define __SIZEOF_PTHREAD_COND_COMPAT_T 12 +#define __SIZEOF_PTHREAD_CONDATTR_T 4 +#define __SIZEOF_PTHREAD_RWLOCK_T 32 +#define __SIZEOF_PTHREAD_RWLOCKATTR_T 8 +#define __SIZEOF_PTHREAD_BARRIER_T 20 +#define __SIZEOF_PTHREAD_BARRIERATTR_T 4 + + +/* Thread identifiers. The structure of the attribute type is not + exposed on purpose. */ +typedef unsigned long int pthread_t; + + +typedef union +{ + char __size[__SIZEOF_PTHREAD_ATTR_T]; + long int __align; +} pthread_attr_t; + + +typedef struct __pthread_internal_slist +{ + struct __pthread_internal_slist *__next; +} __pthread_slist_t; + + +/* Data structures for mutex handling. The structure of the attribute + type is not exposed on purpose. */ +typedef union +{ + struct __pthread_mutex_s + { + int __lock; + unsigned int __count; + int __owner; + /* KIND must stay at this position in the structure to maintain + binary compatibility. */ + int __kind; + unsigned int __nusers; + __extension__ union + { + int __spins; + __pthread_slist_t __list; + }; + } __data; + char __size[__SIZEOF_PTHREAD_MUTEX_T]; + long int __align; +} pthread_mutex_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_MUTEXATTR_T]; + long int __align; +} pthread_mutexattr_t; + + +/* Data structure for conditional variable handling. The structure of + the attribute type is not exposed on purpose. */ +typedef union +{ + struct + { + int __lock; + unsigned int __futex; + __extension__ unsigned long long int __total_seq; + __extension__ unsigned long long int __wakeup_seq; + __extension__ unsigned long long int __woken_seq; + void *__mutex; + unsigned int __nwaiters; + unsigned int __broadcast_seq; + } __data; + char __size[__SIZEOF_PTHREAD_COND_T]; + __extension__ long long int __align; +} pthread_cond_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_CONDATTR_T]; + long int __align; +} pthread_condattr_t; + + +/* Keys for thread-specific data */ +typedef unsigned int pthread_key_t; + + +/* Once-only execution */ +typedef int pthread_once_t; + + +#if defined __USE_UNIX98 || defined __USE_XOPEN2K +/* Data structure for read-write lock variable handling. The + structure of the attribute type is not exposed on purpose. */ +typedef union +{ + struct + { + int __lock; + unsigned int __nr_readers; + unsigned int __readers_wakeup; + unsigned int __writer_wakeup; + unsigned int __nr_readers_queued; + unsigned int __nr_writers_queued; + /* FLAGS must stay at this position in the structure to maintain + binary compatibility. */ + unsigned int __flags; + int __writer; + } __data; + char __size[__SIZEOF_PTHREAD_RWLOCK_T]; + long int __align; +} pthread_rwlock_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_RWLOCKATTR_T]; + long int __align; +} pthread_rwlockattr_t; +#endif + + +#ifdef __USE_XOPEN2K +/* POSIX spinlock data type. */ +typedef volatile int pthread_spinlock_t; + + +/* POSIX barriers data type. The structure of the type is + deliberately not exposed. */ +typedef union +{ + char __size[__SIZEOF_PTHREAD_BARRIER_T]; + long int __align; +} pthread_barrier_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_BARRIERATTR_T]; + int __align; +} pthread_barrierattr_t; +#endif + + +/* Extra attributes for the cleanup functions. */ +#define __cleanup_fct_attribute __attribute ((regparm (1))) + +#endif /* bits/pthreadtypes.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/bits/semaphore.h b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/bits/semaphore.h new file mode 100644 index 000000000..e6c5d845c --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/bits/semaphore.h @@ -0,0 +1,39 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _SEMAPHORE_H +# error "Never use <bits/semaphore.h> directly; include <semaphore.h> instead." +#endif + + +#define __SIZEOF_SEM_T 16 + + +/* Value returned if `sem_open' failed. */ +#define SEM_FAILED ((sem_t *) 0) + +/* Maximum value the semaphore can have. */ +#define SEM_VALUE_MAX (2147483647) + + +typedef union +{ + char __size[__SIZEOF_SEM_T]; + long int __align; +} sem_t; diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/clone.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/clone.S new file mode 100644 index 000000000..9c7c46467 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/clone.S @@ -0,0 +1,2 @@ +#define RESET_PID +#include <libc/sysdeps/linux/i386/clone.S> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/createthread.c b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/createthread.c new file mode 100644 index 000000000..35719be96 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/createthread.c @@ -0,0 +1,49 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* The "thread register" gets initialized from a segment descriptor. + Initialize such a descriptor first. */ +#define PREPARE_CREATE \ + union user_desc_init desc; \ + \ + /* Describe the thread-local storage segment. */ \ + \ + /* The 'entry_number' field. The first three bits of the segment \ + register value select the GDT, ignore them. We get the index \ + from the value of the %gs register in the current thread. */ \ + desc.vals[0] = TLS_GET_GS () >> 3; \ + /* The 'base_addr' field. Pointer to the TCB. */ \ + desc.vals[1] = (unsigned long int) pd; \ + /* The 'limit' field. We use 4GB which is 0xfffff pages. */ \ + desc.vals[2] = 0xfffff; \ + /* Collapsed value of the bitfield: \ + .seg_32bit = 1 \ + .contents = 0 \ + .read_exec_only = 0 \ + .limit_in_pages = 1 \ + .seg_not_present = 0 \ + .useable = 1 */ \ + desc.vals[3] = 0x51 + +/* Value passed to 'clone' for initialization of the thread register. */ +#define TLS_VALUE &desc.desc + + +/* Get the real implementation. */ +#include <sysdeps/pthread/createthread.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/fork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/fork.c new file mode 100644 index 000000000..b874538b3 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/fork.c @@ -0,0 +1,31 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sched.h> +#include <signal.h> +#include <stdio.h> +#include <sysdep.h> +#include <tls.h> + +#define ARCH_FORK() \ + INLINE_SYSCALL (clone, 5, \ + CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD, 0, \ + NULL, NULL, &THREAD_SELF->tid) + +#include "../fork.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S new file mode 100644 index 000000000..223b11108 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S @@ -0,0 +1,30 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* In libc.so we do not unconditionally use the lock prefix. Only if + the application is using threads. */ +#ifndef UP +# define LOCK \ + cmpl $0, %gs:MULTIPLE_THREADS_OFFSET; \ + je,pt 0f; \ + lock; \ +0: +#endif + +#include "lowlevellock.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S new file mode 100644 index 000000000..955e119ab --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S @@ -0,0 +1,283 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <pthread-errnos.h> + + .text + +#ifndef LOCK +# ifdef UP +# define LOCK +# else +# define LOCK lock +# endif +#endif + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + + + .globl __lll_mutex_lock_wait + .type __lll_mutex_lock_wait,@function + .hidden __lll_mutex_lock_wait + .align 16 +__lll_mutex_lock_wait: + pushl %edx + pushl %ebx + pushl %esi + + movl $2, %edx + movl %ecx, %ebx + xorl %esi, %esi /* No timeout. */ + xorl %ecx, %ecx /* movl $FUTEX_WAIT, %ecx */ + + cmpl %edx, %eax /* NB: %edx == 2 */ + jne 2f + +1: movl $SYS_futex, %eax + ENTER_KERNEL + +2: movl %edx, %eax + xchgl %eax, (%ebx) /* NB: lock is implied */ + + testl %eax, %eax + jnz,pn 1b + + popl %esi + popl %ebx + popl %edx + ret + .size __lll_mutex_lock_wait,.-__lll_mutex_lock_wait + + +#ifdef NOT_IN_libc + .globl __lll_mutex_timedlock_wait + .type __lll_mutex_timedlock_wait,@function + .hidden __lll_mutex_timedlock_wait + .align 16 +__lll_mutex_timedlock_wait: + /* Check for a valid timeout value. */ + cmpl $1000000000, 4(%edx) + jae 3f + + pushl %edi + pushl %esi + pushl %ebx + pushl %ebp + + /* Stack frame for the timespec and timeval structs. */ + subl $8, %esp + + movl %ecx, %ebp + movl %edx, %edi + +1: + /* Get current time. */ + movl %esp, %ebx + xorl %ecx, %ecx + movl $SYS_gettimeofday, %eax + ENTER_KERNEL + + /* Compute relative timeout. */ + movl 4(%esp), %eax + movl $1000, %edx + mul %edx /* Milli seconds to nano seconds. */ + movl (%edi), %ecx + movl 4(%edi), %edx + subl (%esp), %ecx + subl %eax, %edx + jns 4f + addl $1000000000, %edx + subl $1, %ecx +4: testl %ecx, %ecx + js 5f /* Time is already up. */ + + /* Store relative timeout. */ + movl %ecx, (%esp) + movl %edx, 4(%esp) + + movl %ebp, %ebx + + movl $1, %eax + movl $2, %edx + LOCK + cmpxchgl %edx, (%ebx) + + testl %eax, %eax + je 8f + + /* Futex call. */ + movl %esp, %esi + xorl %ecx, %ecx /* movl $FUTEX_WAIT, %ecx */ + movl $SYS_futex, %eax + ENTER_KERNEL + movl %eax, %ecx + +8: /* NB: %edx == 2 */ + xorl %eax, %eax + LOCK + cmpxchgl %edx, (%ebx) + + jnz 7f + +6: addl $8, %esp + popl %ebp + popl %ebx + popl %esi + popl %edi + ret + + /* Check whether the time expired. */ +7: cmpl $-ETIMEDOUT, %ecx + je 5f + + /* Make sure the current holder knows we are going to sleep. */ + movl %edx, %eax + xchgl %eax, (%ebx) + testl %eax, %eax + jz 6b + jmp 1b + +3: movl $EINVAL, %eax + ret + +5: movl $ETIMEDOUT, %eax + jmp 6b + .size __lll_mutex_timedlock_wait,.-__lll_mutex_timedlock_wait +#endif + + +#ifdef NOT_IN_libc + .globl lll_unlock_wake_cb + .type lll_unlock_wake_cb,@function + .hidden lll_unlock_wake_cb + .align 16 +lll_unlock_wake_cb: + pushl %ebx + pushl %ecx + pushl %edx + + movl 20(%esp), %ebx + LOCK + subl $1, (%ebx) + je 1f + + movl $FUTEX_WAKE, %ecx + movl $1, %edx /* Wake one thread. */ + movl $SYS_futex, %eax + movl $0, (%ebx) + ENTER_KERNEL + +1: popl %edx + popl %ecx + popl %ebx + ret + .size lll_unlock_wake_cb,.-lll_unlock_wake_cb +#endif + + + .globl __lll_mutex_unlock_wake + .type __lll_mutex_unlock_wake,@function + .hidden __lll_mutex_unlock_wake + .align 16 +__lll_mutex_unlock_wake: + pushl %ebx + pushl %ecx + pushl %edx + + movl %eax, %ebx + movl $0, (%eax) + movl $FUTEX_WAKE, %ecx + movl $1, %edx /* Wake one thread. */ + movl $SYS_futex, %eax + ENTER_KERNEL + + popl %edx + popl %ecx + popl %ebx + ret + .size __lll_mutex_unlock_wake,.-__lll_mutex_unlock_wake + + +#ifdef NOT_IN_libc + .globl __lll_timedwait_tid + .type __lll_timedwait_tid,@function + .hidden __lll_timedwait_tid + .align 16 +__lll_timedwait_tid: + pushl %edi + pushl %esi + pushl %ebx + pushl %ebp + + movl %eax, %ebp + movl %edx, %edi + subl $8, %esp + + /* Get current time. */ +2: movl %esp, %ebx + xorl %ecx, %ecx + movl $SYS_gettimeofday, %eax + ENTER_KERNEL + + /* Compute relative timeout. */ + movl 4(%esp), %eax + movl $1000, %edx + mul %edx /* Milli seconds to nano seconds. */ + movl (%edi), %ecx + movl 4(%edi), %edx + subl (%esp), %ecx + subl %eax, %edx + jns 5f + addl $1000000000, %edx + subl $1, %ecx +5: testl %ecx, %ecx + js 6f /* Time is already up. */ + + movl %ecx, (%esp) /* Store relative timeout. */ + movl %edx, 4(%esp) + + movl (%ebp), %edx + testl %edx, %edx + jz 4f + + movl %esp, %esi + xorl %ecx, %ecx /* movl $FUTEX_WAIT, %ecx */ + movl %ebp, %ebx + movl $SYS_futex, %eax + ENTER_KERNEL + + cmpl $0, (%ebx) + jne 1f +4: xorl %eax, %eax + +3: addl $8, %esp + popl %ebp + popl %ebx + popl %esi + popl %edi + ret + +1: cmpl $-ETIMEDOUT, %eax + jne 2b +6: movl $ETIMEDOUT, %eax + jmp 3b + .size __lll_timedwait_tid,.-__lll_timedwait_tid +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_barrier_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_barrier_wait.S new file mode 100644 index 000000000..2af9e38cd --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_barrier_wait.S @@ -0,0 +1,162 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <lowlevelbarrier.h> + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + +#ifndef UP +# define LOCK lock +#else +# define LOCK +#endif + + + .text + + .globl pthread_barrier_wait + .type pthread_barrier_wait,@function + .align 16 +pthread_barrier_wait: + pushl %ebx + + movl 8(%esp), %ebx + + /* Get the mutex. */ + movl $1, %edx + xorl %eax, %eax + LOCK + cmpxchgl %edx, MUTEX(%ebx) + jnz 1f + + /* One less waiter. If this was the last one needed wake + everybody. */ +2: subl $1, LEFT(%ebx) + je 3f + + /* There are more threads to come. */ + pushl %esi + +#if CURR_EVENT == 0 + movl (%ebx), %edx +#else + movl CURR_EVENT(%ebx), %edx +#endif + + /* Release the mutex. */ + LOCK + subl $1, MUTEX(%ebx) + jne 6f + + /* Wait for the remaining threads. The call will return immediately + if the CURR_EVENT memory has meanwhile been changed. */ +7: xorl %ecx, %ecx /* movl $FUTEX_WAIT, %ecx */ + xorl %esi, %esi +8: movl $SYS_futex, %eax + ENTER_KERNEL + + /* Don't return on spurious wakeups. The syscall does not change + any register except %eax so there is no need to reload any of + them. */ +#if CURR_EVENT == 0 + cmpl %edx, (%ebx) +#else + cmpl %edx, CURR_EVENT(%ebx) +#endif + je,pn 8b + + /* Increment LEFT. If this brings the count back to the + initial count unlock the object. */ + movl $1, %edx + movl INIT_COUNT(%ebx), %ecx + LOCK + xaddl %edx, LEFT(%ebx) + subl $1, %ecx + cmpl %ecx, %edx + jne,pt 10f + + /* Release the mutex. We cannot release the lock before + waking the waiting threads since otherwise a new thread might + arrive and gets waken up, too. */ + LOCK + subl $1, MUTEX(%ebx) + jne 9f + + /* Note: %esi is still zero. */ +10: movl %esi, %eax /* != PTHREAD_BARRIER_SERIAL_THREAD */ + + popl %esi + popl %ebx + ret + + /* The necessary number of threads arrived. */ +3: +#if CURR_EVENT == 0 + addl $1, (%ebx) +#else + addl $1, CURR_EVENT(%ebx) +#endif + + /* Wake up all waiters. The count is a signed number in the kernel + so 0x7fffffff is the highest value. */ + movl $0x7fffffff, %edx + movl $FUTEX_WAKE, %ecx + movl $SYS_futex, %eax + ENTER_KERNEL + + /* Increment LEFT. If this brings the count back to the + initial count unlock the object. */ + movl $1, %edx + movl INIT_COUNT(%ebx), %ecx + LOCK + xaddl %edx, LEFT(%ebx) + subl $1, %ecx + cmpl %ecx, %edx + jne,pt 5f + + /* Release the mutex. We cannot release the lock before + waking the waiting threads since otherwise a new thread might + arrive and gets waken up, too. */ + LOCK + subl $1, MUTEX(%ebx) + jne 4f + +5: orl $-1, %eax /* == PTHREAD_BARRIER_SERIAL_THREAD */ + + popl %ebx + ret + +1: leal MUTEX(%ebx), %ecx + call __lll_mutex_lock_wait + jmp 2b + +4: leal MUTEX(%ebx), %eax + call __lll_mutex_unlock_wake + jmp 5b + +6: leal MUTEX(%ebx), %eax + call __lll_mutex_unlock_wake + jmp 7b + +9: leal MUTEX(%ebx), %eax + call __lll_mutex_unlock_wake + jmp 10b + .size pthread_barrier_wait,.-pthread_barrier_wait diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S new file mode 100644 index 000000000..6e8ffe6f6 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S @@ -0,0 +1,161 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <lowlevelcond.h> +#include <bits/kernel-features.h> + +#ifdef UP +# define LOCK +#else +# define LOCK lock +#endif + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 +#define FUTEX_REQUEUE 3 +#define FUTEX_CMP_REQUEUE 4 + +#define EINVAL 22 + + + .text + + /* int pthread_cond_broadcast (pthread_cond_t *cond) */ + .globl __pthread_cond_broadcast + .type __pthread_cond_broadcast, @function + .align 16 +__pthread_cond_broadcast: + + pushl %ebx + pushl %esi + pushl %edi + pushl %ebp + + movl 20(%esp), %ebx + + /* Get internal lock. */ + movl $1, %edx + xorl %eax, %eax + LOCK +#if cond_lock == 0 + cmpxchgl %edx, (%ebx) +#else + cmpxchgl %edx, cond_lock(%ebx) +#endif + jnz 1f + +2: addl $cond_futex, %ebx + movl total_seq+4-cond_futex(%ebx), %eax + movl total_seq-cond_futex(%ebx), %ebp + cmpl wakeup_seq+4-cond_futex(%ebx), %eax + ja 3f + jb 4f + cmpl wakeup_seq-cond_futex(%ebx), %ebp + jna 4f + + /* Cause all currently waiting threads to recognize they are + woken up. */ +3: movl %ebp, wakeup_seq-cond_futex(%ebx) + movl %eax, wakeup_seq-cond_futex+4(%ebx) + movl %ebp, woken_seq-cond_futex(%ebx) + movl %eax, woken_seq-cond_futex+4(%ebx) + addl %ebp, %ebp + addl $1, broadcast_seq-cond_futex(%ebx) + movl %ebp, (%ebx) + + /* Get the address of the mutex used. */ + movl dep_mutex-cond_futex(%ebx), %edi + + /* Unlock. */ + LOCK + subl $1, cond_lock-cond_futex(%ebx) + jne 7f + + /* Don't use requeue for pshared condvars. */ +8: cmpl $-1, %edi + je 9f + + /* Wake up all threads. */ + movl $FUTEX_CMP_REQUEUE, %ecx + movl $SYS_futex, %eax + movl $0x7fffffff, %esi + movl $1, %edx + /* Get the address of the futex involved. */ +# if MUTEX_FUTEX != 0 + addl $MUTEX_FUTEX, %edi +# endif +/* FIXME: Until Ingo fixes 4G/4G vDSO, 6 arg syscalls are broken for sysenter. + ENTER_KERNEL */ + int $0x80 + + /* For any kind of error, which mainly is EAGAIN, we try again + with WAKE. The general test also covers running on old + kernels. */ + cmpl $0xfffff001, %eax + jae 9f + +10: xorl %eax, %eax + popl %ebp + popl %edi + popl %esi + popl %ebx + ret + + .align 16 + /* Unlock. */ +4: LOCK + subl $1, cond_lock-cond_futex(%ebx) + jne 5f + +6: xorl %eax, %eax + popl %ebp + popl %edi + popl %esi + popl %ebx + ret + + /* Initial locking failed. */ +1: +#if cond_lock == 0 + movl %ebx, %ecx +#else + leal cond_lock(%ebx), %ecx +#endif + call __lll_mutex_lock_wait + jmp 2b + + /* Unlock in loop requires waekup. */ +5: leal cond_lock-cond_futex(%ebx), %eax + call __lll_mutex_unlock_wake + jmp 6b + + /* Unlock in loop requires waekup. */ +7: leal cond_lock-cond_futex(%ebx), %eax + call __lll_mutex_unlock_wake + jmp 8b + +9: /* The futex requeue functionality is not available. */ + movl $0x7fffffff, %edx + movl $FUTEX_WAKE, %ecx + movl $SYS_futex, %eax + ENTER_KERNEL + jmp 10b + .size __pthread_cond_broadcast, .-__pthread_cond_broadcast +weak_alias(__pthread_cond_broadcast, pthread_cond_broadcast) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_signal.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_signal.S new file mode 100644 index 000000000..ec8217987 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_signal.S @@ -0,0 +1,111 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <lowlevelcond.h> +#include <bits/kernel-features.h> + +#ifdef UP +# define LOCK +#else +# define LOCK lock +#endif + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 +#define FUTEX_REQUEUE 3 + +#define EINVAL 22 + + + .text + + /* int pthread_cond_signal (pthread_cond_t *cond) */ + .globl __pthread_cond_signal + .type __pthread_cond_signal, @function + .align 16 +__pthread_cond_signal: + + pushl %ebx + pushl %edi + + movl 12(%esp), %edi + + /* Get internal lock. */ + movl $1, %edx + xorl %eax, %eax + LOCK +#if cond_lock == 0 + cmpxchgl %edx, (%edi) +#else + cmpxchgl %edx, cond_lock(%edi) +#endif + jnz 1f + +2: leal cond_futex(%edi), %ebx + movl total_seq+4(%edi), %eax + movl total_seq(%edi), %ecx + cmpl wakeup_seq+4(%edi), %eax +#if cond_lock != 0 + /* Must use leal to preserve the flags. */ + leal cond_lock(%edi), %edi +#endif + ja 3f + jb 4f + cmpl wakeup_seq-cond_futex(%ebx), %ecx + jbe 4f + + /* Bump the wakeup number. */ +3: addl $1, wakeup_seq-cond_futex(%ebx) + adcl $0, wakeup_seq-cond_futex+4(%ebx) + addl $1, (%ebx) + + /* Wake up one thread. */ + movl $FUTEX_WAKE, %ecx + movl $SYS_futex, %eax + movl $1, %edx + ENTER_KERNEL + + /* Unlock. Note that at this point %edi always points to + cond_lock. */ +4: LOCK + subl $1, (%edi) + jne 5f + +6: xorl %eax, %eax + popl %edi + popl %ebx + ret + + /* Initial locking failed. */ +1: +#if cond_lock == 0 + movl %edi, %ecx +#else + leal cond_lock(%edi), %ecx +#endif + call __lll_mutex_lock_wait + jmp 2b + + /* Unlock in loop requires wakeup. */ +5: movl %edi, %eax + call __lll_mutex_unlock_wake + jmp 6b + .size __pthread_cond_signal, .-__pthread_cond_signal +weak_alias(__pthread_cond_signal, pthread_cond_signal) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S new file mode 100644 index 000000000..b8f0d2e4b --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S @@ -0,0 +1,465 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <lowlevelcond.h> +#include <pthread-errnos.h> + +#ifdef UP +# define LOCK +#else +# define LOCK lock +#endif + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + + + .text + +/* int pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex, + const struct timespec *abstime) */ + .globl __pthread_cond_timedwait + .type __pthread_cond_timedwait, @function + .align 16 +__pthread_cond_timedwait: +.LSTARTCODE: + pushl %ebp +.Lpush_ebp: + pushl %edi +.Lpush_edi: + pushl %esi +.Lpush_esi: + pushl %ebx +.Lpush_ebx: + + movl 20(%esp), %ebx + movl 28(%esp), %ebp + + cmpl $1000000000, 4(%ebp) + movl $EINVAL, %eax + jae 18f + + /* Get internal lock. */ + movl $1, %edx + xorl %eax, %eax + LOCK +#if cond_lock == 0 + cmpxchgl %edx, (%ebx) +#else + cmpxchgl %edx, cond_lock(%ebx) +#endif + jnz 1f + + /* Store the reference to the mutex. If there is already a + different value in there this is a bad user bug. */ +2: cmpl $-1, dep_mutex(%ebx) + movl 24(%esp), %eax + je 17f + movl %eax, dep_mutex(%ebx) + + /* Unlock the mutex. */ +17: xorl %edx, %edx + call __pthread_mutex_unlock_usercnt + + testl %eax, %eax + jne 16f + + addl $1, total_seq(%ebx) + adcl $0, total_seq+4(%ebx) + addl $1, cond_futex(%ebx) + addl $(1 << clock_bits), cond_nwaiters(%ebx) + +#define FRAME_SIZE 24 + subl $FRAME_SIZE, %esp +.Lsubl: + + /* Get and store current wakeup_seq value. */ + movl wakeup_seq(%ebx), %edi + movl wakeup_seq+4(%ebx), %edx + movl broadcast_seq(%ebx), %eax + movl %edi, 12(%esp) + movl %edx, 16(%esp) + movl %eax, 20(%esp) + + /* Get the current time. */ +8: movl %ebx, %edx +#ifdef __NR_clock_gettime + /* Get the clock number. */ + movl cond_nwaiters(%ebx), %ebx + andl $((1 << clock_bits) - 1), %ebx + /* Only clocks 0 and 1 are allowed so far. Both are handled in the + kernel. */ + leal 4(%esp), %ecx + movl $__NR_clock_gettime, %eax + ENTER_KERNEL +# ifndef __ASSUME_POSIX_TIMERS + cmpl $-ENOSYS, %eax + je 19f +# endif + movl %edx, %ebx + + /* Compute relative timeout. */ + movl (%ebp), %ecx + movl 4(%ebp), %edx + subl 4(%esp), %ecx + subl 8(%esp), %edx +#else + /* Get the current time. */ + leal 4(%esp), %ebx + xorl %ecx, %ecx + movl $SYS_gettimeofday, %eax + ENTER_KERNEL + movl %edx, %ebx + + /* Compute relative timeout. */ + movl 8(%esp), %eax + movl $1000, %edx + mul %edx /* Milli seconds to nano seconds. */ + movl (%ebp), %ecx + movl 4(%ebp), %edx + subl 4(%esp), %ecx + subl %eax, %edx +#endif + jns 12f + addl $1000000000, %edx + subl $1, %ecx +12: testl %ecx, %ecx + movl $-ETIMEDOUT, %esi + js 6f + + /* Store relative timeout. */ +21: movl %ecx, 4(%esp) + movl %edx, 8(%esp) + + movl cond_futex(%ebx), %edi + + /* Unlock. */ + LOCK +#if cond_lock == 0 + subl $1, (%ebx) +#else + subl $1, cond_lock(%ebx) +#endif + jne 3f + +.LcleanupSTART: +4: call __pthread_enable_asynccancel + movl %eax, (%esp) + + leal 4(%esp), %esi + xorl %ecx, %ecx /* movl $FUTEX_WAIT, %ecx */ + movl %edi, %edx + addl $cond_futex, %ebx +.Ladd_cond_futex: + movl $SYS_futex, %eax + ENTER_KERNEL + subl $cond_futex, %ebx +.Lsub_cond_futex: + movl %eax, %esi + + movl (%esp), %eax + call __pthread_disable_asynccancel +.LcleanupEND: + + /* Lock. */ + movl $1, %edx + xorl %eax, %eax + LOCK +#if cond_lock == 0 + cmpxchgl %edx, (%ebx) +#else + cmpxchgl %edx, cond_lock(%ebx) +#endif + jnz 5f + +6: movl broadcast_seq(%ebx), %eax + cmpl 20(%esp), %eax + jne 23f + + movl woken_seq(%ebx), %eax + movl woken_seq+4(%ebx), %ecx + + movl wakeup_seq(%ebx), %edi + movl wakeup_seq+4(%ebx), %edx + + cmpl 16(%esp), %edx + jne 7f + cmpl 12(%esp), %edi + je 15f + +7: cmpl %ecx, %edx + jne 9f + cmp %eax, %edi + jne 9f + +15: cmpl $-ETIMEDOUT, %esi + jne 8b + + addl $1, wakeup_seq(%ebx) + adcl $0, wakeup_seq+4(%ebx) + addl $1, cond_futex(%ebx) + movl $ETIMEDOUT, %esi + jmp 14f + +23: xorl %esi, %esi + jmp 24f + +9: xorl %esi, %esi +14: addl $1, woken_seq(%ebx) + adcl $0, woken_seq+4(%ebx) + +24: subl $(1 << clock_bits), cond_nwaiters(%ebx) + + /* Wake up a thread which wants to destroy the condvar object. */ + movl total_seq(%ebx), %eax + andl total_seq+4(%ebx), %eax + cmpl $0xffffffff, %eax + jne 25f + movl cond_nwaiters(%ebx), %eax + andl $~((1 << clock_bits) - 1), %eax + jne 25f + + addl $cond_nwaiters, %ebx + movl $SYS_futex, %eax + movl $FUTEX_WAKE, %ecx + movl $1, %edx + ENTER_KERNEL + subl $cond_nwaiters, %ebx + +25: LOCK +#if cond_lock == 0 + subl $1, (%ebx) +#else + subl $1, cond_lock(%ebx) +#endif + jne 10f + + /* Remove cancellation handler. */ +11: movl 24+FRAME_SIZE(%esp), %eax + call __pthread_mutex_cond_lock + addl $FRAME_SIZE, %esp +.Laddl: + + /* We return the result of the mutex_lock operation if it failed. */ + testl %eax, %eax +#ifdef HAVE_CMOV + cmovel %esi, %eax +#else + jne 22f + movl %esi, %eax +22: +#endif + +18: popl %ebx +.Lpop_ebx: + popl %esi +.Lpop_esi: + popl %edi +.Lpop_edi: + popl %ebp +.Lpop_ebp: + + ret + + /* Initial locking failed. */ +1: +.LSbl1: +#if cond_lock == 0 + movl %ebx, %ecx +#else + leal cond_lock(%ebx), %ecx +#endif + call __lll_mutex_lock_wait + jmp 2b + + /* Unlock in loop requires wakeup. */ +3: +.LSbl2: +#if cond_lock == 0 + movl %ebx, %eax +#else + leal cond_lock(%ebx), %eax +#endif + call __lll_mutex_unlock_wake + jmp 4b + + /* Locking in loop failed. */ +5: +#if cond_lock == 0 + movl %ebx, %ecx +#else + leal cond_lock(%ebx), %ecx +#endif + call __lll_mutex_lock_wait + jmp 6b + + /* Unlock after loop requires wakeup. */ +10: +#if cond_lock == 0 + movl %ebx, %eax +#else + leal cond_lock(%ebx), %eax +#endif + call __lll_mutex_unlock_wake + jmp 11b + + /* The initial unlocking of the mutex failed. */ +16: +.LSbl3: + LOCK +#if cond_lock == 0 + subl $1, (%ebx) +#else + subl $1, cond_lock(%ebx) +#endif + jne 18b + + movl %eax, %esi +#if cond_lock == 0 + movl %ebx, %eax +#else + leal cond_lock(%ebx), %eax +#endif + call __lll_mutex_unlock_wake + + movl %esi, %eax + jmp 18b + +#if defined __NR_clock_gettime && !defined __ASSUME_POSIX_TIMERS + /* clock_gettime not available. */ +.LSbl4: +19: leal 4(%esp), %ebx + xorl %ecx, %ecx + movl $SYS_gettimeofday, %eax + ENTER_KERNEL + movl %edx, %ebx + + /* Compute relative timeout. */ + movl 8(%esp), %eax + movl $1000, %edx + mul %edx /* Milli seconds to nano seconds. */ + movl (%ebp), %ecx + movl 4(%ebp), %edx + subl 4(%esp), %ecx + subl %eax, %edx + jns 20f + addl $1000000000, %edx + subl $1, %ecx +20: testl %ecx, %ecx + movl $-ETIMEDOUT, %esi + js 6b + jmp 21b +#endif + .size __pthread_cond_timedwait, .-__pthread_cond_timedwait +weak_alias(__pthread_cond_timedwait, pthread_cond_timedwait) + + + .type __condvar_tw_cleanup2, @function +__condvar_tw_cleanup2: + subl $cond_futex, %ebx +.LSbl5: + .size __condvar_tw_cleanup2, .-__condvar_tw_cleanup2 + .type __condvar_tw_cleanup, @function +__condvar_tw_cleanup: + movl %eax, %esi + + /* Get internal lock. */ + movl $1, %edx + xorl %eax, %eax + LOCK +#if cond_lock == 0 + cmpxchgl %edx, (%ebx) +#else + cmpxchgl %edx, cond_lock(%ebx) +#endif + jz 1f + +#if cond_lock == 0 + movl %ebx, %ecx +#else + leal cond_lock(%ebx), %ecx +#endif + call __lll_mutex_lock_wait + +1: movl broadcast_seq(%ebx), %eax + cmpl 20(%esp), %eax + jne 3f + + addl $1, wakeup_seq(%ebx) + adcl $0, wakeup_seq+4(%ebx) + + addl $1, cond_futex(%ebx) + + addl $1, woken_seq(%ebx) + adcl $0, woken_seq+4(%ebx) + +3: subl $(1 << clock_bits), cond_nwaiters(%ebx) + + /* Wake up a thread which wants to destroy the condvar object. */ + xorl %edi, %edi + movl total_seq(%ebx), %eax + andl total_seq+4(%ebx), %eax + cmpl $0xffffffff, %eax + jne 4f + movl cond_nwaiters(%ebx), %eax + andl $~((1 << clock_bits) - 1), %eax + jne 4f + + addl $cond_nwaiters, %ebx + movl $SYS_futex, %eax + movl $FUTEX_WAKE, %ecx + movl $1, %edx + ENTER_KERNEL + subl $cond_nwaiters, %ebx + movl $1, %edi + +4: LOCK +#if cond_lock == 0 + subl $1, (%ebx) +#else + subl $1, cond_lock(%ebx) +#endif + je 2f + +#if cond_lock == 0 + movl %ebx, %eax +#else + leal cond_lock(%ebx), %eax +#endif + call __lll_mutex_unlock_wake + + /* Wake up all waiters to make sure no signal gets lost. */ +2: testl %edi, %edi + jnz 5f + addl $cond_futex, %ebx + movl $FUTEX_WAKE, %ecx + movl $SYS_futex, %eax + movl $0x7fffffff, %edx + ENTER_KERNEL + +5: movl 24+FRAME_SIZE(%esp), %eax + call __pthread_mutex_cond_lock + + movl %esi, (%esp) +.LcallUR: + call _Unwind_Resume + hlt +.LENDCODE: + .size __condvar_tw_cleanup, .-__condvar_tw_cleanup diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S new file mode 100644 index 000000000..377a7340f --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S @@ -0,0 +1,357 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <lowlevelcond.h> +#include <tcb-offsets.h> + +#ifdef UP +# define LOCK +#else +# define LOCK lock +#endif + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + + + .text + +/* int pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex) */ + .globl __pthread_cond_wait + .type __pthread_cond_wait, @function + .align 16 +__pthread_cond_wait: +.LSTARTCODE: + + pushl %edi +.Lpush_edi: + pushl %esi +.Lpush_esi: + pushl %ebx +.Lpush_ebx: + + xorl %esi, %esi + movl 16(%esp), %ebx + + /* Get internal lock. */ + movl $1, %edx + xorl %eax, %eax + LOCK +#if cond_lock == 0 + cmpxchgl %edx, (%ebx) +#else + cmpxchgl %edx, cond_lock(%ebx) +#endif + jnz 1f + + /* Store the reference to the mutex. If there is already a + different value in there this is a bad user bug. */ +2: cmpl $-1, dep_mutex(%ebx) + movl 20(%esp), %eax + je 15f + movl %eax, dep_mutex(%ebx) + + /* Unlock the mutex. */ +15: xorl %edx, %edx + call __pthread_mutex_unlock_usercnt + + testl %eax, %eax + jne 12f + + addl $1, total_seq(%ebx) + adcl $0, total_seq+4(%ebx) + addl $1, cond_futex(%ebx) + addl $(1 << clock_bits), cond_nwaiters(%ebx) + +#define FRAME_SIZE 16 + subl $FRAME_SIZE, %esp +.Lsubl: + + /* Get and store current wakeup_seq value. */ + movl wakeup_seq(%ebx), %edi + movl wakeup_seq+4(%ebx), %edx + movl broadcast_seq(%ebx), %eax + movl %edi, 4(%esp) + movl %edx, 8(%esp) + movl %eax, 12(%esp) + +8: movl cond_futex(%ebx), %edi + + /* Unlock. */ + LOCK +#if cond_lock == 0 + subl $1, (%ebx) +#else + subl $1, cond_lock(%ebx) +#endif + jne 3f + +.LcleanupSTART: +4: call __pthread_enable_asynccancel + movl %eax, (%esp) + + movl %esi, %ecx /* movl $FUTEX_WAIT, %ecx */ + movl %edi, %edx + addl $cond_futex, %ebx +.Ladd_cond_futex: + movl $SYS_futex, %eax + ENTER_KERNEL + subl $cond_futex, %ebx +.Lsub_cond_futex: + + movl (%esp), %eax + call __pthread_disable_asynccancel +.LcleanupEND: + + /* Lock. */ + movl $1, %edx + xorl %eax, %eax + LOCK +#if cond_lock == 0 + cmpxchgl %edx, (%ebx) +#else + cmpxchgl %edx, cond_lock(%ebx) +#endif + jnz 5f + +6: movl broadcast_seq(%ebx), %eax + cmpl 12(%esp), %eax + jne 16f + + movl woken_seq(%ebx), %eax + movl woken_seq+4(%ebx), %ecx + + movl wakeup_seq(%ebx), %edi + movl wakeup_seq+4(%ebx), %edx + + cmpl 8(%esp), %edx + jne 7f + cmpl 4(%esp), %edi + je 8b + +7: cmpl %ecx, %edx + jne 9f + cmp %eax, %edi + je 8b + +9: addl $1, woken_seq(%ebx) + adcl $0, woken_seq+4(%ebx) + + /* Unlock */ +16: subl $(1 << clock_bits), cond_nwaiters(%ebx) + + /* Wake up a thread which wants to destroy the condvar object. */ + movl total_seq(%ebx), %eax + andl total_seq+4(%ebx), %eax + cmpl $0xffffffff, %eax + jne 17f + movl cond_nwaiters(%ebx), %eax + andl $~((1 << clock_bits) - 1), %eax + jne 17f + + addl $cond_nwaiters, %ebx + movl $SYS_futex, %eax + movl $FUTEX_WAKE, %ecx + movl $1, %edx + ENTER_KERNEL + subl $cond_nwaiters, %ebx + +17: LOCK +#if cond_lock == 0 + subl $1, (%ebx) +#else + subl $1, cond_lock(%ebx) +#endif + jne 10f + +11: movl 20+FRAME_SIZE(%esp), %eax + call __pthread_mutex_cond_lock + addl $FRAME_SIZE, %esp +.Laddl: + +14: popl %ebx +.Lpop_ebx: + popl %esi +.Lpop_esi: + popl %edi +.Lpop_edi: + + /* We return the result of the mutex_lock operation. */ + ret + + /* Initial locking failed. */ +1: +.LSbl1: +#if cond_lock == 0 + movl %ebx, %ecx +#else + leal cond_lock(%ebx), %ecx +#endif + call __lll_mutex_lock_wait + jmp 2b + + /* Unlock in loop requires waekup. */ +3: +.LSbl2: +#if cond_lock == 0 + movl %ebx, %eax +#else + leal cond_lock(%ebx), %eax +#endif + call __lll_mutex_unlock_wake + jmp 4b + + /* Locking in loop failed. */ +5: +#if cond_lock == 0 + movl %ebx, %ecx +#else + leal cond_lock(%ebx), %ecx +#endif + call __lll_mutex_lock_wait + jmp 6b + + /* Unlock after loop requires wakeup. */ +10: +#if cond_lock == 0 + movl %ebx, %eax +#else + leal cond_lock(%ebx), %eax +#endif + call __lll_mutex_unlock_wake + jmp 11b + + /* The initial unlocking of the mutex failed. */ +12: +.LSbl3: + LOCK +#if cond_lock == 0 + subl $1, (%ebx) +#else + subl $1, cond_lock(%ebx) +#endif + jne 14b + + movl %eax, %esi +#if cond_lock == 0 + movl %ebx, %eax +#else + leal cond_lock(%ebx), %eax +#endif + call __lll_mutex_unlock_wake + + movl %esi, %eax + jmp 14b + .size __pthread_cond_wait, .-__pthread_cond_wait +weak_alias(__pthread_cond_wait, pthread_cond_wait) + + + .type __condvar_w_cleanup2, @function +__condvar_w_cleanup2: + subl $cond_futex, %ebx + .size __condvar_w_cleanup2, .-__condvar_w_cleanup2 +.LSbl4: + .type __condvar_w_cleanup, @function +__condvar_w_cleanup: + movl %eax, %esi + + /* Get internal lock. */ + movl $1, %edx + xorl %eax, %eax + LOCK +#if cond_lock == 0 + cmpxchgl %edx, (%ebx) +#else + cmpxchgl %edx, cond_lock(%ebx) +#endif + jz 1f + +#if cond_lock == 0 + movl %ebx, %ecx +#else + leal cond_lock(%ebx), %ecx +#endif + call __lll_mutex_lock_wait + +1: movl broadcast_seq(%ebx), %eax + cmpl 12(%esp), %eax + jne 3f + + addl $1, wakeup_seq(%ebx) + adcl $0, wakeup_seq+4(%ebx) + + addl $1, cond_futex(%ebx) + + addl $1, woken_seq(%ebx) + adcl $0, woken_seq+4(%ebx) + +3: subl $(1 << clock_bits), cond_nwaiters(%ebx) + + /* Wake up a thread which wants to destroy the condvar object. */ + xorl %edi, %edi + movl total_seq(%ebx), %eax + andl total_seq+4(%ebx), %eax + cmpl $0xffffffff, %eax + jne 4f + movl cond_nwaiters(%ebx), %eax + andl $~((1 << clock_bits) - 1), %eax + jne 4f + + addl $cond_nwaiters, %ebx + movl $SYS_futex, %eax + movl $FUTEX_WAKE, %ecx + movl $1, %edx + ENTER_KERNEL + subl $cond_nwaiters, %ebx + movl $1, %edi + +4: LOCK +#if cond_lock == 0 + subl $1, (%ebx) +#else + subl $1, cond_lock(%ebx) +#endif + je 2f + +#if cond_lock == 0 + movl %ebx, %eax +#else + leal cond_lock(%ebx), %eax +#endif + call __lll_mutex_unlock_wake + + /* Wake up all waiters to make sure no signal gets lost. */ +2: testl %edi, %edi + jnz 5f + addl $cond_futex, %ebx + movl $FUTEX_WAKE, %ecx + movl $SYS_futex, %eax + movl $0x7fffffff, %edx + ENTER_KERNEL + +5: movl 20+FRAME_SIZE(%esp), %eax + call __pthread_mutex_cond_lock + + movl %esi, (%esp) +.LcallUR: + call _Unwind_Resume + hlt +.LENDCODE: + .size __condvar_w_cleanup, .-__condvar_w_cleanup diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_rdlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_rdlock.S new file mode 100644 index 000000000..aec79f07e --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_rdlock.S @@ -0,0 +1,175 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <lowlevelrwlock.h> +#include <pthread-errnos.h> +#include <tcb-offsets.h> + + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + +#ifndef UP +# define LOCK lock +#else +# define LOCK +#endif + + + .text + + .globl __pthread_rwlock_rdlock + .type __pthread_rwlock_rdlock,@function + .align 16 +__pthread_rwlock_rdlock: + pushl %esi + pushl %ebx + + xorl %esi, %esi + movl 12(%esp), %ebx + + /* Get the lock. */ + movl $1, %edx + xorl %eax, %eax + LOCK +#if MUTEX == 0 + cmpxchgl %edx, (%ebx) +#else + cmpxchgl %edx, MUTEX(%ebx) +#endif + jnz 1f + +2: movl WRITER(%ebx), %eax + testl %eax, %eax + jne 14f + cmpl $0, WRITERS_QUEUED(%ebx) + je 5f + cmpl $0, FLAGS(%ebx) + je 5f + +3: addl $1, READERS_QUEUED(%ebx) + je 4f + + movl READERS_WAKEUP(%ebx), %edx + + LOCK +#if MUTEX == 0 + subl $1, (%ebx) +#else + subl $1, MUTEX(%ebx) +#endif + jne 10f + +11: addl $READERS_WAKEUP, %ebx + movl %esi, %ecx /* movl $FUTEX_WAIT, %ecx */ + movl $SYS_futex, %eax + ENTER_KERNEL + + subl $READERS_WAKEUP, %ebx + + /* Reget the lock. */ + movl $1, %edx + xorl %eax, %eax + LOCK +#if MUTEX == 0 + cmpxchgl %edx, (%ebx) +#else + cmpxchgl %edx, MUTEX(%ebx) +#endif + jnz 12f + +13: subl $1, READERS_QUEUED(%ebx) + jmp 2b + +5: xorl %ecx, %ecx + addl $1, NR_READERS(%ebx) + je 8f +9: LOCK +#if MUTEX == 0 + subl $1, (%ebx) +#else + subl $1, MUTEX(%ebx) +#endif + jne 6f +7: + + movl %ecx, %eax + popl %ebx + popl %esi + ret + +1: +#if MUTEX == 0 + movl %ebx, %ecx +#else + leal MUTEX(%ebx), %ecx +#endif + call __lll_mutex_lock_wait + jmp 2b + +14: cmpl %gs:TID, %eax + jne 3b + /* Deadlock detected. */ + movl $EDEADLK, %ecx + jmp 9b + +6: +#if MUTEX == 0 + movl %ebx, %eax +#else + leal MUTEX(%ebx), %eax +#endif + call __lll_mutex_unlock_wake + jmp 7b + + /* Overflow. */ +8: subl $1, NR_READERS(%ebx) + movl $EAGAIN, %ecx + jmp 9b + + /* Overflow. */ +4: subl $1, READERS_QUEUED(%ebx) + movl $EAGAIN, %ecx + jmp 9b + +10: +#if MUTEX == 0 + movl %ebx, %eax +#else + leal MUTEX(%ebx), %eax +#endif + call __lll_mutex_unlock_wake + jmp 11b + +12: +#if MUTEX == 0 + movl %ebx, %ecx +#else + leal MUTEX(%ebx), %ecx +#endif + call __lll_mutex_lock_wait + jmp 13b + .size __pthread_rwlock_rdlock,.-__pthread_rwlock_rdlock + + .globl pthread_rwlock_rdlock +pthread_rwlock_rdlock = __pthread_rwlock_rdlock + + .globl __pthread_rwlock_rdlock_internal +__pthread_rwlock_rdlock_internal = __pthread_rwlock_rdlock diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedrdlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedrdlock.S new file mode 100644 index 000000000..3717d7ef5 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedrdlock.S @@ -0,0 +1,214 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <lowlevelrwlock.h> +#include <pthread-errnos.h> +#include <tcb-offsets.h> + + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + +#ifndef UP +# define LOCK lock +#else +# define LOCK +#endif + + + .text + + .globl pthread_rwlock_timedrdlock + .type pthread_rwlock_timedrdlock,@function + .align 16 +pthread_rwlock_timedrdlock: + pushl %esi + pushl %edi + pushl %ebx + pushl %ebp + subl $8, %esp + + movl 28(%esp), %ebp + movl 32(%esp), %edi + + /* Get the lock. */ + movl $1, %edx + xorl %eax, %eax + LOCK +#if MUTEX == 0 + cmpxchgl %edx, (%ebp) +#else + cmpxchgl %edx, MUTEX(%ebp) +#endif + jnz 1f + +2: movl WRITER(%ebp), %eax + testl %eax, %eax + jne 14f + cmpl $0, WRITERS_QUEUED(%ebp) + je 5f + cmpl $0, FLAGS(%ebp) + je 5f + + /* Check the value of the timeout parameter. */ +3: cmpl $1000000000, 4(%edi) + jae 19f + + addl $1, READERS_QUEUED(%ebp) + je 4f + + movl READERS_WAKEUP(%ebp), %esi + + LOCK +#if MUTEX == 0 + subl $1, (%ebp) +#else + subl $1, MUTEX(%ebp) +#endif + jne 10f + + /* Get current time. */ +11: movl %esp, %ebx + xorl %ecx, %ecx + movl $SYS_gettimeofday, %eax + ENTER_KERNEL + + /* Compute relative timeout. */ + movl 4(%esp), %eax + movl $1000, %edx + mul %edx /* Milli seconds to nano seconds. */ + movl (%edi), %ecx + movl 4(%edi), %edx + subl (%esp), %ecx + subl %eax, %edx + jns 15f + addl $1000000000, %edx + subl $1, %ecx +15: testl %ecx, %ecx + js 16f /* Time is already up. */ + + /* Futex call. */ + movl %ecx, (%esp) /* Store relative timeout. */ + movl %edx, 4(%esp) + movl %esi, %edx + xorl %ecx, %ecx /* movl $FUTEX_WAIT, %ecx */ + movl %esp, %esi + leal READERS_WAKEUP(%ebp), %ebx + movl $SYS_futex, %eax + ENTER_KERNEL + movl %eax, %ecx +17: + + /* Reget the lock. */ + movl $1, %edx + xorl %eax, %eax + LOCK +#if MUTEX == 0 + cmpxchgl %edx, (%ebp) +#else + cmpxchgl %edx, MUTEX(%ebp) +#endif + jnz 12f + +13: subl $1, READERS_QUEUED(%ebp) + cmpl $-ETIMEDOUT, %ecx + jne 2b + +18: movl $ETIMEDOUT, %ecx + jmp 9f + + +5: xorl %ecx, %ecx + addl $1, NR_READERS(%ebp) + je 8f +9: LOCK +#if MUTEX == 0 + subl $1, (%ebp) +#else + subl $1, MUTEX(%ebp) +#endif + jne 6f + +7: movl %ecx, %eax + + addl $8, %esp + popl %ebp + popl %ebx + popl %edi + popl %esi + ret + +1: +#if MUTEX == 0 + movl %ebp, %ecx +#else + leal MUTEX(%ebp), %ecx +#endif + call __lll_mutex_lock_wait + jmp 2b + +14: cmpl %gs:TID, %eax + jne 3b + movl $EDEADLK, %ecx + jmp 9b + +6: +#if MUTEX == 0 + movl %ebp, %eax +#else + leal MUTEX(%ebp), %eax +#endif + call __lll_mutex_unlock_wake + jmp 7b + + /* Overflow. */ +8: subl $1, NR_READERS(%ebp) + movl $EAGAIN, %ecx + jmp 9b + + /* Overflow. */ +4: subl $1, READERS_QUEUED(%ebp) + movl $EAGAIN, %ecx + jmp 9b + +10: +#if MUTEX == 0 + movl %ebp, %eax +#else + leal MUTEX(%ebp), %eax +#endif + call __lll_mutex_unlock_wake + jmp 11b + +12: +#if MUTEX == 0 + movl %ebp, %ecx +#else + leal MUTEX(%ebp), %ecx +#endif + call __lll_mutex_lock_wait + jmp 13b + +16: movl $-ETIMEDOUT, %ecx + jmp 17b + +19: movl $EINVAL, %ecx + jmp 9b + .size pthread_rwlock_timedrdlock,.-pthread_rwlock_timedrdlock diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedwrlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedwrlock.S new file mode 100644 index 000000000..09c9e30ca --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedwrlock.S @@ -0,0 +1,207 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <lowlevelrwlock.h> +#include <pthread-errnos.h> +#include <tcb-offsets.h> + + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + +#ifndef UP +# define LOCK lock +#else +# define LOCK +#endif + + + .text + + .globl pthread_rwlock_timedwrlock + .type pthread_rwlock_timedwrlock,@function + .align 16 +pthread_rwlock_timedwrlock: + pushl %esi + pushl %edi + pushl %ebx + pushl %ebp + subl $8, %esp + + movl 28(%esp), %ebp + movl 32(%esp), %edi + + /* Get the lock. */ + movl $1, %edx + xorl %eax, %eax + LOCK +#if MUTEX == 0 + cmpxchgl %edx, (%ebp) +#else + cmpxchgl %edx, MUTEX(%ebp) +#endif + jnz 1f + +2: movl WRITER(%ebp), %eax + testl %eax, %eax + jne 14f + cmpl $0, NR_READERS(%ebp) + je 5f + + /* Check the value of the timeout parameter. */ +3: cmpl $1000000000, 4(%edi) + jae 19f + + addl $1, WRITERS_QUEUED(%ebp) + je 4f + + movl WRITERS_WAKEUP(%ebp), %esi + + LOCK +#if MUTEX == 0 + subl $1, (%ebp) +#else + subl $1, MUTEX(%ebp) +#endif + jne 10f + + /* Get current time. */ +11: movl %esp, %ebx + xorl %ecx, %ecx + movl $SYS_gettimeofday, %eax + ENTER_KERNEL + + /* Compute relative timeout. */ + movl 4(%esp), %eax + movl $1000, %edx + mul %edx /* Milli seconds to nano seconds. */ + movl (%edi), %ecx + movl 4(%edi), %edx + subl (%esp), %ecx + subl %eax, %edx + jns 15f + addl $1000000000, %edx + subl $1, %ecx +15: testl %ecx, %ecx + js 16f /* Time is already up. */ + + /* Futex call. */ + movl %ecx, (%esp) /* Store relative timeout. */ + movl %edx, 4(%esp) + movl %esi, %edx + xorl %ecx, %ecx /* movl $FUTEX_WAIT, %ecx */ + movl %esp, %esi + leal WRITERS_WAKEUP(%ebp), %ebx + movl $SYS_futex, %eax + ENTER_KERNEL + movl %eax, %ecx +17: + + /* Reget the lock. */ + movl $1, %edx + xorl %eax, %eax + LOCK +#if MUTEX == 0 + cmpxchgl %edx, (%ebp) +#else + cmpxchgl %edx, MUTEX(%ebp) +#endif + jnz 12f + +13: subl $1, WRITERS_QUEUED(%ebp) + cmpl $-ETIMEDOUT, %ecx + jne 2b + +18: movl $ETIMEDOUT, %ecx + jmp 9f + + +5: xorl %ecx, %ecx + movl %gs:TID, %eax + movl %eax, WRITER(%ebp) +9: LOCK +#if MUTEX == 0 + subl $1, (%ebp) +#else + subl $1, MUTEX(%ebp) +#endif + jne 6f + +7: movl %ecx, %eax + + addl $8, %esp + popl %ebp + popl %ebx + popl %edi + popl %esi + ret + +1: +#if MUTEX == 0 + movl %ebp, %ecx +#else + leal MUTEX(%ebp), %ecx +#endif + call __lll_mutex_lock_wait + jmp 2b + +14: cmpl %gs:TID, %eax + jne 3b +20: movl $EDEADLK, %ecx + jmp 9b + +6: +#if MUTEX == 0 + movl %ebp, %eax +#else + leal MUTEX(%ebp), %eax +#endif + call __lll_mutex_unlock_wake + jmp 7b + + /* Overflow. */ +4: subl $1, WRITERS_QUEUED(%ebp) + movl $EAGAIN, %ecx + jmp 9b + +10: +#if MUTEX == 0 + movl %ebp, %eax +#else + leal MUTEX(%ebp), %eax +#endif + call __lll_mutex_unlock_wake + jmp 11b + +12: +#if MUTEX == 0 + movl %ebp, %ecx +#else + leal MUTEX(%ebp), %ecx +#endif + call __lll_mutex_lock_wait + jmp 13b + +16: movl $-ETIMEDOUT, %ecx + jmp 17b + +19: movl $EINVAL, %ecx + jmp 9b + .size pthread_rwlock_timedwrlock,.-pthread_rwlock_timedwrlock diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_unlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_unlock.S new file mode 100644 index 000000000..597c82fa8 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_unlock.S @@ -0,0 +1,140 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <lowlevelrwlock.h> + + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + +#ifndef UP +# define LOCK lock +#else +# define LOCK +#endif + + + .text + + .globl __pthread_rwlock_unlock + .type __pthread_rwlock_unlock,@function + .align 16 +__pthread_rwlock_unlock: + pushl %ebx + pushl %edi + + movl 12(%esp), %edi + + /* Get the lock. */ + movl $1, %edx + xorl %eax, %eax + LOCK +#if MUTEX == 0 + cmpxchgl %edx, (%edi) +#else + cmpxchgl %edx, MUTEX(%edi) +#endif + jnz 1f + +2: cmpl $0, WRITER(%edi) + jne 5f + subl $1, NR_READERS(%edi) + jnz 6f + +5: movl $0, WRITER(%edi) + + movl $1, %ecx + leal WRITERS_WAKEUP(%edi), %ebx + movl %ecx, %edx + cmpl $0, WRITERS_QUEUED(%edi) + jne 0f + + /* If also no readers waiting nothing to do. */ + cmpl $0, READERS_QUEUED(%edi) + je 6f + + movl $0x7fffffff, %edx + leal READERS_WAKEUP(%edi), %ebx + +0: addl $1, (%ebx) + LOCK +#if MUTEX == 0 + subl $1, (%edi) +#else + subl $1, MUTEX(%edi) +#endif + jne 7f + +8: movl $SYS_futex, %eax + ENTER_KERNEL + + xorl %eax, %eax + popl %edi + popl %ebx + ret + + .align 16 +6: LOCK +#if MUTEX == 0 + subl $1, (%edi) +#else + subl $1, MUTEX(%edi) +#endif + jne 3f + +4: xorl %eax, %eax + popl %edi + popl %ebx + ret + +1: +#if MUTEX == 0 + movl %edi, %ecx +#else + leal MUTEX(%edx), %ecx +#endif + call __lll_mutex_lock_wait + jmp 2b + +3: +#if MUTEX == 0 + movl %edi, %eax +#else + leal MUTEX(%edx), %eax +#endif + call __lll_mutex_unlock_wake + jmp 4b + +7: +#if MUTEX == 0 + movl %edi, %eax +#else + leal MUTEX(%edx), %eax +#endif + call __lll_mutex_unlock_wake + jmp 8b + + .size __pthread_rwlock_unlock,.-__pthread_rwlock_unlock + + .globl pthread_rwlock_unlock +pthread_rwlock_unlock = __pthread_rwlock_unlock + + .globl __pthread_rwlock_unlock_internal +__pthread_rwlock_unlock_internal = __pthread_rwlock_unlock diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_wrlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_wrlock.S new file mode 100644 index 000000000..bb384a267 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_wrlock.S @@ -0,0 +1,165 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <lowlevelrwlock.h> +#include <pthread-errnos.h> +#include <tcb-offsets.h> + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + +#ifndef UP +# define LOCK lock +#else +# define LOCK +#endif + + + .text + + .globl __pthread_rwlock_wrlock + .type __pthread_rwlock_wrlock,@function + .align 16 +__pthread_rwlock_wrlock: + pushl %esi + pushl %ebx + + xorl %esi, %esi + movl 12(%esp), %ebx + + /* Get the lock. */ + movl $1, %edx + xorl %eax, %eax + LOCK +#if MUTEX == 0 + cmpxchgl %edx, (%ebx) +#else + cmpxchgl %edx, MUTEX(%ebx) +#endif + jnz 1f + +2: movl WRITER(%ebx), %eax + testl %eax, %eax + jne 14f + cmpl $0, NR_READERS(%ebx) + je 5f + +3: addl $1, WRITERS_QUEUED(%ebx) + je 4f + + movl WRITERS_WAKEUP(%ebx), %edx + + LOCK +#if MUTEX == 0 + subl $1, (%ebx) +#else + subl $1, MUTEX(%ebx) +#endif + jne 10f + +11: addl $WRITERS_WAKEUP, %ebx + movl %esi, %ecx /* movl $FUTEX_WAIT, %ecx */ + movl $SYS_futex, %eax + ENTER_KERNEL + + subl $WRITERS_WAKEUP, %ebx + + /* Reget the lock. */ + movl $1, %edx + xorl %eax, %eax + LOCK +#if MUTEX == 0 + cmpxchgl %edx, (%ebx) +#else + cmpxchgl %edx, MUTEX(%ebx) +#endif + jnz 12f + +13: subl $1, WRITERS_QUEUED(%ebx) + jmp 2b + +5: xorl %ecx, %ecx + movl %gs:TID, %eax + movl %eax, WRITER(%ebx) +9: LOCK +#if MUTEX == 0 + subl $1, (%ebx) +#else + subl $1, MUTEX(%ebx) +#endif + jne 6f +7: + + movl %ecx, %eax + popl %ebx + popl %esi + ret + +1: +#if MUTEX == 0 + movl %ebx, %ecx +#else + leal MUTEX(%ebx), %ecx +#endif + call __lll_mutex_lock_wait + jmp 2b + +14: cmpl %gs:TID , %eax + jne 3b + movl $EDEADLK, %ecx + jmp 9b + +6: +#if MUTEX == 0 + movl %ebx, %eax +#else + leal MUTEX(%ebx), %eax +#endif + call __lll_mutex_unlock_wake + jmp 7b + +4: subl $1, WRITERS_QUEUED(%ebx) + movl $EAGAIN, %ecx + jmp 9b + +10: +#if MUTEX == 0 + movl %ebx, %eax +#else + leal MUTEX(%ebx), %eax +#endif + call __lll_mutex_unlock_wake + jmp 11b + +12: +#if MUTEX == 0 + movl %ebx, %ecx +#else + leal MUTEX(%ebx), %ecx +#endif + call __lll_mutex_lock_wait + jmp 13b + .size __pthread_rwlock_wrlock,.-__pthread_rwlock_wrlock + + .globl pthread_rwlock_wrlock +pthread_rwlock_wrlock = __pthread_rwlock_wrlock + + .globl __pthread_rwlock_wrlock_internal +__pthread_rwlock_wrlock_internal = __pthread_rwlock_wrlock diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_post.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_post.S new file mode 100644 index 000000000..a0dc39c8f --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_post.S @@ -0,0 +1,96 @@ +/* Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <pthread-errnos.h> +#include <tls.h> + +#ifndef UP +# define LOCK lock +#else +# define +#endif + +#define FUTEX_WAKE 1 + + + .text + + .globl __new_sem_post + .type __new_sem_post,@function + .align 16 +__new_sem_post: + pushl %ebx + + movl 8(%esp), %ebx + movl $1, %edx + LOCK + xaddl %edx, (%ebx) + + movl $SYS_futex, %eax + movl $FUTEX_WAKE, %ecx + addl $1, %edx + ENTER_KERNEL + + testl %eax, %eax + js 1f + + xorl %eax, %eax + popl %ebx + ret + +1: +#ifdef __PIC__ + call __x86.get_pc_thunk.bx +#else + movl $4f, %ebx +4: +#endif + addl $_GLOBAL_OFFSET_TABLE_, %ebx +#if USE___THREAD +# ifdef NO_TLS_DIRECT_SEG_REFS + movl errno@gotntpoff(%ebx), %edx + addl %gs:0, %edx + movl $EINVAL, (%edx) +# else + movl errno@gotntpoff(%ebx), %edx + movl $EINVAL, %gs:(%edx) +# endif +#else + call __errno_location@plt + movl $EINVAL, (%eax) +#endif + + orl $-1, %eax + popl %ebx + ret + .size __new_sem_post,.-__new_sem_post +weak_alias(__new_sem_post, sem_post) + + +#ifdef __PIC__ + .section .gnu.linkonce.t.__x86.get_pc_thunk.bx,"ax",@progbits + .globl __x86.get_pc_thunk.bx + .hidden __x86.get_pc_thunk.bx + .type __x86.get_pc_thunk.bx,@function +__x86.get_pc_thunk.bx: + movl (%esp), %ebx; + ret + .size __x86.get_pc_thunk.bx,.-__x86.get_pc_thunk.bx +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_timedwait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_timedwait.S new file mode 100644 index 000000000..972b49fac --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_timedwait.S @@ -0,0 +1,193 @@ +/* Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <pthread-errnos.h> +#include <tcb-offsets.h> + +#ifndef UP +# define LOCK lock +#else +# define +#endif + +#define FUTEX_WAKE 1 + + + .text + + .globl sem_timedwait + .type sem_timedwait,@function + .align 16 + cfi_startproc +sem_timedwait: + /* First check for cancellation. */ + movl %gs:CANCELHANDLING, %eax + andl $0xfffffff9, %eax + cmpl $8, %eax + je 10f + + movl 4(%esp), %ecx + + movl (%ecx), %eax +2: testl %eax, %eax + je,pn 1f + + leal -1(%eax), %edx + LOCK + cmpxchgl %edx, (%ecx) + jne,pn 2b + + xorl %eax, %eax + ret + + /* Check whether the timeout value is valid. */ +1: pushl %esi + cfi_adjust_cfa_offset(4) + pushl %edi + cfi_adjust_cfa_offset(4) + pushl %ebx + cfi_adjust_cfa_offset(4) + subl $12, %esp + cfi_adjust_cfa_offset(12) + + movl 32(%esp), %edi + cfi_offset(7, -12) /* %edi */ + + /* Check for invalid nanosecond field. */ + cmpl $1000000000, 4(%edi) + movl $EINVAL, %esi + cfi_offset(6, -8) /* %esi */ + jae 6f + + cfi_offset(3, -16) /* %ebx */ +7: call __pthread_enable_asynccancel + movl %eax, 8(%esp) + + xorl %ecx, %ecx + movl %esp, %ebx + movl %ecx, %edx + movl $SYS_gettimeofday, %eax + ENTER_KERNEL + + /* Compute relative timeout. */ + movl 4(%esp), %eax + movl $1000, %edx + mul %edx /* Milli seconds to nano seconds. */ + movl (%edi), %ecx + movl 4(%edi), %edx + subl (%esp), %ecx + subl %eax, %edx + jns 5f + addl $1000000000, %edx + subl $1, %ecx +5: testl %ecx, %ecx + movl $ETIMEDOUT, %esi + js 6f /* Time is already up. */ + + movl %ecx, (%esp) /* Store relative timeout. */ + movl %edx, 4(%esp) + movl 28(%esp), %ebx + xorl %ecx, %ecx + movl %esp, %esi + movl $SYS_futex, %eax + xorl %edx, %edx + ENTER_KERNEL + movl %eax, %esi + + movl 8(%esp), %eax + call __pthread_disable_asynccancel + + testl %esi, %esi + je,pt 9f + cmpl $-EWOULDBLOCK, %esi + jne 3f + +9: movl (%ebx), %eax +8: testl %eax, %eax + je 7b + + leal -1(%eax), %ecx + LOCK + cmpxchgl %ecx, (%ebx) + jne,pn 8b + + addl $12, %esp + cfi_adjust_cfa_offset(-12) + xorl %eax, %eax + popl %ebx + cfi_adjust_cfa_offset(-4) + cfi_restore(3) + popl %edi + cfi_adjust_cfa_offset(-4) + cfi_restore(7) + popl %esi + cfi_adjust_cfa_offset(-4) + cfi_restore(6) + ret + + cfi_adjust_cfa_offset(24) + cfi_offset(6, -8) /* %esi */ + cfi_offset(7, -12) /* %edi */ + cfi_offset(3, -16) /* %ebx */ +3: negl %esi +6: +#ifdef __PIC__ + call __x86.get_pc_thunk.bx +#else + movl $4f, %ebx +4: +#endif + addl $_GLOBAL_OFFSET_TABLE_, %ebx +#if USE___THREAD +# ifdef NO_TLS_DIRECT_SEG_REFS + movl errno@gotntpoff(%ebx), %edx + addl %gs:0, %edx + movl %esi, (%edx) +# else + movl errno@gotntpoff(%ebx), %edx + movl %esi, %gs:(%edx) +# endif +#else + call __errno_location@plt + movl %esi, (%eax) +#endif + + addl $12, %esp + cfi_adjust_cfa_offset(-12) + orl $-1, %eax + popl %ebx + cfi_adjust_cfa_offset(-4) + cfi_restore(3) + popl %edi + cfi_adjust_cfa_offset(-4) + cfi_restore(7) + popl %esi + cfi_adjust_cfa_offset(-4) + cfi_restore(6) + ret + +10: /* Canceled. */ + movl $0xffffffff, %gs:RESULT + LOCK + orl $0x10, %gs:CANCELHANDLING + movl %gs:CLEANUP_JMP_BUF, %eax + jmp HIDDEN_JUMPTARGET (__pthread_unwind) + cfi_endproc + .size sem_timedwait,.-sem_timedwait diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_trywait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_trywait.S new file mode 100644 index 000000000..7db64820f --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_trywait.S @@ -0,0 +1,85 @@ +/* Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <pthread-errnos.h> +#include <tls.h> + +#ifndef UP +# define LOCK lock +#else +# define +#endif + + .text + + .globl __new_sem_trywait + .type __new_sem_trywait,@function + .align 16 +__new_sem_trywait: + movl 4(%esp), %ecx + + movl (%ecx), %eax +2: testl %eax, %eax + jz 1f + + leal -1(%eax), %edx + LOCK + cmpxchgl %edx, (%ecx) + jne,pn 2b + xorl %eax, %eax + ret + +1: +#ifdef __PIC__ + call __x86.get_pc_thunk.cx +#else + movl $3f, %ecx +3: +#endif + addl $_GLOBAL_OFFSET_TABLE_, %ecx +#if USE___THREAD +# ifdef NO_TLS_DIRECT_SEG_REFS + movl errno@gotntpoff(%ecx), %edx + addl %gs:0, %edx + movl $EAGAIN, (%edx) +# else + movl errno@gotntpoff(%ecx), %edx + movl $EAGAIN, %gs:(%edx) +# endif +#else + call __errno_location@plt + movl $EAGAIN, (%eax) +#endif + orl $-1, %eax + ret + .size __new_sem_trywait,.-__new_sem_trywait +weak_alias(__new_sem_trywait, sem_trywait) + + +#ifdef __PIC__ + .section .gnu.linkonce.t.__x86.get_pc_thunk.cx,"ax",@progbits + .globl __x86.get_pc_thunk.cx + .hidden __x86.get_pc_thunk.cx + .type __x86.get_pc_thunk.cx,@function +__x86.get_pc_thunk.cx: + movl (%esp), %ecx; + ret + .size __x86.get_pc_thunk.cx,.-__x86.get_pc_thunk.cx +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_wait.S new file mode 100644 index 000000000..c3e6cbce6 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_wait.S @@ -0,0 +1,134 @@ +/* Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <pthread-errnos.h> +#include <tcb-offsets.h> +#include <tls.h> + +#ifndef UP +# define LOCK lock +#else +# define +#endif + +#define FUTEX_WAKE 1 + + + .text + + .globl __new_sem_wait + .type __new_sem_wait,@function + .align 16 + cfi_startproc +__new_sem_wait: + /* First check for cancellation. */ + movl %gs:CANCELHANDLING, %eax + andl $0xfffffff9, %eax + cmpl $8, %eax + je 5f + + pushl %ebx + cfi_adjust_cfa_offset(4) + pushl %esi + cfi_adjust_cfa_offset(4) + subl $4, %esp + cfi_adjust_cfa_offset(4) + + movl 16(%esp), %ebx + cfi_offset(3, -8) /* %ebx */ + + cfi_offset(6, -12) /* %esi */ +3: movl (%ebx), %eax +2: testl %eax, %eax + je,pn 1f + + leal -1(%eax), %edx + LOCK + cmpxchgl %edx, (%ebx) + jne,pn 2b + xorl %eax, %eax + + movl 4(%esp), %esi + cfi_restore(6) + movl 8(%esp), %ebx + cfi_restore(3) + addl $12, %esp + cfi_adjust_cfa_offset(-12) + ret + + cfi_adjust_cfa_offset(8) + cfi_offset(3, -8) /* %ebx */ + cfi_offset(6, -12) /* %esi */ +1: call __pthread_enable_asynccancel + movl %eax, (%esp) + + xorl %esi, %esi + movl $SYS_futex, %eax + movl %esi, %ecx + movl %esi, %edx + ENTER_KERNEL + movl %eax, %esi + + movl (%esp), %eax + call __pthread_disable_asynccancel + + testl %esi, %esi + je 3b + cmpl $-EWOULDBLOCK, %esi + je 3b + negl %esi +#ifdef __PIC__ + call __x86.get_pc_thunk.bx +#else + movl $4f, %ebx +4: +#endif + addl $_GLOBAL_OFFSET_TABLE_, %ebx +#if USE___THREAD +# ifdef NO_TLS_DIRECT_SEG_REFS + movl errno@gotntpoff(%ebx), %edx + addl %gs:0, %edx + movl %esi, (%edx) +# else + movl errno@gotntpoff(%ebx), %edx + movl %esi, %gs:(%edx) +# endif +#else + call __errno_location@plt + movl %esi, (%eax) +#endif + orl $-1, %eax + movl 4(%esp), %esi + cfi_restore(6) + movl 8(%esp), %ebx + cfi_restore(3) + addl $12, %esp + cfi_adjust_cfa_offset(-12) + ret + +5: /* Canceled. */ + movl $0xffffffff, %gs:RESULT + LOCK + orl $0x10, %gs:CANCELHANDLING + movl %gs:CLEANUP_JMP_BUF, %eax + jmp HIDDEN_JUMPTARGET (__pthread_unwind) + cfi_endproc + .size __new_sem_wait,.-__new_sem_wait +weak_alias(__new_sem_wait, sem_wait) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/libc-lowlevellock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/libc-lowlevellock.S new file mode 100644 index 000000000..f567c1d6d --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/libc-lowlevellock.S @@ -0,0 +1 @@ +#include "../i486/libc-lowlevellock.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevellock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevellock.S new file mode 100644 index 000000000..e60dea89e --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevellock.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/lowlevellock.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_barrier_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_barrier_wait.S new file mode 100644 index 000000000..6d20b9a95 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_barrier_wait.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/pthread_barrier_wait.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_cond_broadcast.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_cond_broadcast.S new file mode 100644 index 000000000..5e1024eab --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_cond_broadcast.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/pthread_cond_broadcast.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_cond_signal.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_cond_signal.S new file mode 100644 index 000000000..da4e8cbab --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_cond_signal.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/pthread_cond_signal.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_cond_timedwait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_cond_timedwait.S new file mode 100644 index 000000000..c0131555b --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_cond_timedwait.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/pthread_cond_timedwait.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_cond_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_cond_wait.S new file mode 100644 index 000000000..9b57fbaca --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_cond_wait.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/pthread_cond_wait.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_rdlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_rdlock.S new file mode 100644 index 000000000..da2bc4704 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_rdlock.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/pthread_rwlock_rdlock.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_timedrdlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_timedrdlock.S new file mode 100644 index 000000000..0f2ec168b --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_timedrdlock.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/pthread_rwlock_timedrdlock.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_timedwrlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_timedwrlock.S new file mode 100644 index 000000000..26501590a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_timedwrlock.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/pthread_rwlock_timedwrlock.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_unlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_unlock.S new file mode 100644 index 000000000..5515e4895 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_unlock.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/pthread_rwlock_unlock.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_wrlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_wrlock.S new file mode 100644 index 000000000..04ac275f6 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_wrlock.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/pthread_rwlock_wrlock.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/sem_post.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/sem_post.S new file mode 100644 index 000000000..7317e1582 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/sem_post.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/sem_post.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/sem_timedwait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/sem_timedwait.S new file mode 100644 index 000000000..f34539d56 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/sem_timedwait.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/sem_timedwait.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/sem_trywait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/sem_trywait.S new file mode 100644 index 000000000..64145c2e3 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/sem_trywait.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/sem_trywait.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/sem_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/sem_wait.S new file mode 100644 index 000000000..b3d462125 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/sem_wait.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/sem_wait.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/libc-lowlevellock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/libc-lowlevellock.S new file mode 100644 index 000000000..f567c1d6d --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/libc-lowlevellock.S @@ -0,0 +1 @@ +#include "../i486/libc-lowlevellock.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevellock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevellock.S new file mode 100644 index 000000000..e60dea89e --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevellock.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/lowlevellock.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_barrier_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_barrier_wait.S new file mode 100644 index 000000000..6d20b9a95 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_barrier_wait.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/pthread_barrier_wait.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_cond_broadcast.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_cond_broadcast.S new file mode 100644 index 000000000..5e1024eab --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_cond_broadcast.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/pthread_cond_broadcast.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_cond_signal.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_cond_signal.S new file mode 100644 index 000000000..da4e8cbab --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_cond_signal.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/pthread_cond_signal.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_cond_timedwait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_cond_timedwait.S new file mode 100644 index 000000000..07d481f37 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_cond_timedwait.S @@ -0,0 +1,21 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#define HAVE_CMOV 1 +#include "../i486/pthread_cond_timedwait.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_cond_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_cond_wait.S new file mode 100644 index 000000000..9b57fbaca --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_cond_wait.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/pthread_cond_wait.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_rdlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_rdlock.S new file mode 100644 index 000000000..da2bc4704 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_rdlock.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/pthread_rwlock_rdlock.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_timedrdlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_timedrdlock.S new file mode 100644 index 000000000..0f2ec168b --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_timedrdlock.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/pthread_rwlock_timedrdlock.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_timedwrlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_timedwrlock.S new file mode 100644 index 000000000..26501590a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_timedwrlock.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/pthread_rwlock_timedwrlock.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_unlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_unlock.S new file mode 100644 index 000000000..0894f0546 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_unlock.S @@ -0,0 +1,21 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#define HAVE_CMOV 1 +#include "../i486/pthread_rwlock_unlock.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_wrlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_wrlock.S new file mode 100644 index 000000000..04ac275f6 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_wrlock.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/pthread_rwlock_wrlock.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/sem_post.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/sem_post.S new file mode 100644 index 000000000..7317e1582 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/sem_post.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/sem_post.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/sem_timedwait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/sem_timedwait.S new file mode 100644 index 000000000..f34539d56 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/sem_timedwait.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/sem_timedwait.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/sem_trywait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/sem_trywait.S new file mode 100644 index 000000000..64145c2e3 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/sem_trywait.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/sem_trywait.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/sem_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/sem_wait.S new file mode 100644 index 000000000..b3d462125 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/sem_wait.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/sem_wait.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h new file mode 100644 index 000000000..97f3b09e2 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h @@ -0,0 +1,365 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _LOWLEVELLOCK_H +#define _LOWLEVELLOCK_H 1 + +#include <time.h> +#include <sys/param.h> +#include <bits/pthreadtypes.h> +#include <atomic.h> +#include <sysdep.h> + +/* We have a separate internal lock implementation which is not tied + to binary compatibility. */ + +/* Type for lock object. */ +typedef int lll_lock_t; + +/* Initializers for lock. */ +#define LLL_LOCK_INITIALIZER (0) +#define LLL_LOCK_INITIALIZER_LOCKED (1) + +#include <tls.h> + +#ifndef LOCK_INSTR +# define LOCK_INSTR "lock;" +#endif + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + + +/* Initializer for compatibility lock. */ +#define LLL_MUTEX_LOCK_INITIALIZER (0) +#define LLL_MUTEX_LOCK_INITIALIZER_LOCKED (1) +#define LLL_MUTEX_LOCK_INITIALIZER_WAITERS (2) + + +#ifdef __PIC__ +# define LLL_EBX_LOAD "xchgl %2, %%ebx\n" +# define LLL_EBX_REG "D" +#else +# define LLL_EBX_LOAD +# define LLL_EBX_REG "b" +#endif + +#define LLL_ENTER_KERNEL "int $0x80\n\t" + +/* Delay in spinlock loop. */ +#define BUSY_WAIT_NOP __asm__ ("rep; nop") + +#define lll_futex_wait(futex, val) \ + lll_futex_timed_wait (futex, val, NULL) + +#define lll_futex_timed_wait(futex, val, timeout) \ + ({ \ + int __ret; \ + register __typeof (val) _val __asm__ ("edx") = (val); \ + __asm__ __volatile (LLL_EBX_LOAD \ + LLL_ENTER_KERNEL \ + LLL_EBX_LOAD \ + : "=a" (__ret) \ + : "0" (SYS_futex), LLL_EBX_REG (futex), "S" (timeout), \ + "c" (FUTEX_WAIT), "d" (_val), \ + "i" (offsetof (tcbhead_t, sysinfo))); \ + __ret; }) + + +#define lll_futex_wake(futex, nr) \ + ({ \ + int __ret; \ + register __typeof (nr) _nr __asm__ ("edx") = (nr); \ + __asm__ __volatile (LLL_EBX_LOAD \ + LLL_ENTER_KERNEL \ + LLL_EBX_LOAD \ + : "=a" (__ret) \ + : "0" (SYS_futex), LLL_EBX_REG (futex), \ + "c" (FUTEX_WAKE), "d" (_nr), \ + "i" (0) /* phony, to align next arg's number */, \ + "i" (offsetof (tcbhead_t, sysinfo))); \ + __ret; }) + + +/* Does not preserve %eax and %ecx. */ +extern int __lll_mutex_lock_wait (int val, int *__futex) + __attribute ((regparm (2))) attribute_hidden; +/* Does not preserve %eax, %ecx, and %edx. */ +extern int __lll_mutex_timedlock_wait (int val, int *__futex, + const struct timespec *abstime) + __attribute ((regparm (3))) attribute_hidden; +/* Preserves all registers but %eax. */ +extern int __lll_mutex_unlock_wake (int *__futex) + __attribute ((regparm (1))) attribute_hidden; + + +/* NB: in the lll_mutex_trylock macro we simply return the value in %eax + after the cmpxchg instruction. In case the operation succeded this + value is zero. In case the operation failed, the cmpxchg instruction + has loaded the current value of the memory work which is guaranteed + to be nonzero. */ +#define lll_mutex_trylock(futex) \ + ({ int ret; \ + __asm__ __volatile (LOCK_INSTR "cmpxchgl %2, %1" \ + : "=a" (ret), "=m" (futex) \ + : "r" (LLL_MUTEX_LOCK_INITIALIZER_LOCKED), "m" (futex),\ + "0" (LLL_MUTEX_LOCK_INITIALIZER) \ + : "memory"); \ + ret; }) + + +#define lll_mutex_cond_trylock(futex) \ + ({ int ret; \ + __asm__ __volatile (LOCK_INSTR "cmpxchgl %2, %1" \ + : "=a" (ret), "=m" (futex) \ + : "r" (LLL_MUTEX_LOCK_INITIALIZER_WAITERS), \ + "m" (futex), "0" (LLL_MUTEX_LOCK_INITIALIZER) \ + : "memory"); \ + ret; }) + + +#define lll_mutex_lock(futex) \ + (void) ({ int ignore1, ignore2; \ + __asm__ __volatile (LOCK_INSTR "cmpxchgl %1, %2\n\t" \ + "jnz _L_mutex_lock_%=\n\t" \ + ".subsection 1\n\t" \ + ".type _L_mutex_lock_%=,@function\n" \ + "_L_mutex_lock_%=:\n\t" \ + "leal %2, %%ecx\n\t" \ + "call __lll_mutex_lock_wait\n\t" \ + "jmp 1f\n\t" \ + ".size _L_mutex_lock_%=,.-_L_mutex_lock_%=\n" \ + ".previous\n" \ + "1:" \ + : "=a" (ignore1), "=c" (ignore2), "=m" (futex) \ + : "0" (0), "1" (1), "m" (futex) \ + : "memory"); }) + + +/* Special version of lll_mutex_lock which causes the unlock function to + always wakeup waiters. */ +#define lll_mutex_cond_lock(futex) \ + (void) ({ int ignore1, ignore2; \ + __asm__ __volatile (LOCK_INSTR "cmpxchgl %1, %2\n\t" \ + "jnz _L_mutex_cond_lock_%=\n\t" \ + ".subsection 1\n\t" \ + ".type _L_mutex_cond_lock_%=,@function\n" \ + "_L_mutex_cond_lock_%=:\n\t" \ + "leal %2, %%ecx\n\t" \ + "call __lll_mutex_lock_wait\n\t" \ + "jmp 1f\n\t" \ + ".size _L_mutex_cond_lock_%=,.-_L_mutex_cond_lock_%=\n" \ + ".previous\n" \ + "1:" \ + : "=a" (ignore1), "=c" (ignore2), "=m" (futex) \ + : "0" (0), "1" (2), "m" (futex) \ + : "memory"); }) + + +#define lll_mutex_timedlock(futex, timeout) \ + ({ int _result, ignore1, ignore2; \ + __asm__ __volatile (LOCK_INSTR "cmpxchgl %1, %3\n\t" \ + "jnz _L_mutex_timedlock_%=\n\t" \ + ".subsection 1\n\t" \ + ".type _L_mutex_timedlock_%=,@function\n" \ + "_L_mutex_timedlock_%=:\n\t" \ + "leal %3, %%ecx\n\t" \ + "movl %7, %%edx\n\t" \ + "call __lll_mutex_timedlock_wait\n\t" \ + "jmp 1f\n\t" \ + ".size _L_mutex_timedlock_%=,.-_L_mutex_timedlock_%=\n"\ + ".previous\n" \ + "1:" \ + : "=a" (_result), "=c" (ignore1), "=&d" (ignore2), \ + "=m" (futex) \ + : "0" (0), "1" (1), "m" (futex), "m" (timeout) \ + : "memory"); \ + _result; }) + + +#define lll_mutex_unlock(futex) \ + (void) ({ int ignore; \ + __asm__ __volatile (LOCK_INSTR "subl $1,%0\n\t" \ + "jne _L_mutex_unlock_%=\n\t" \ + ".subsection 1\n\t" \ + ".type _L_mutex_unlock_%=,@function\n" \ + "_L_mutex_unlock_%=:\n\t" \ + "leal %0, %%eax\n\t" \ + "call __lll_mutex_unlock_wake\n\t" \ + "jmp 1f\n\t" \ + ".size _L_mutex_unlock_%=,.-_L_mutex_unlock_%=\n" \ + ".previous\n" \ + "1:" \ + : "=m" (futex), "=&a" (ignore) \ + : "m" (futex) \ + : "memory"); }) + + +#define lll_mutex_islocked(futex) \ + (futex != 0) + + +extern int __lll_lock_wait (int val, int *__futex) + __attribute ((regparm (2))) attribute_hidden; +extern int __lll_unlock_wake (int *__futex) + __attribute ((regparm (1))) attribute_hidden; +extern int lll_unlock_wake_cb (int *__futex) attribute_hidden; + + +/* The states of a lock are: + 0 - untaken + 1 - taken by one user + 2 - taken by more users */ + + +#if defined NOT_IN_libc +# define lll_trylock(futex) lll_mutex_trylock (futex) +# define lll_lock(futex) lll_mutex_lock (futex) +# define lll_unlock(futex) lll_mutex_unlock (futex) +#else +/* Special versions of the macros for use in libc itself. They avoid + the lock prefix when the thread library is not used. */ + + + +# define lll_trylock(futex) \ + ({ unsigned char ret; \ + __asm__ __volatile ("cmpl $0, %%gs:%P5\n\t" \ + "je,pt 0f\n\t" \ + "lock\n" \ + "0:\tcmpxchgl %2, %1; setne %0" \ + : "=a" (ret), "=m" (futex) \ + : "r" (LLL_MUTEX_LOCK_INITIALIZER_LOCKED), "m" (futex),\ + "0" (LLL_MUTEX_LOCK_INITIALIZER), \ + "i" (offsetof (tcbhead_t, multiple_threads)) \ + : "memory"); \ + ret; }) + + +# define lll_lock(futex) \ + (void) ({ int ignore1, ignore2; \ + __asm__ __volatile ("cmpl $0, %%gs:%P6\n\t" \ + "je,pt 0f\n\t" \ + "lock\n" \ + "0:\tcmpxchgl %1, %2\n\t" \ + "jnz _L_mutex_lock_%=\n\t" \ + ".subsection 1\n\t" \ + ".type _L_mutex_lock_%=,@function\n" \ + "_L_mutex_lock_%=:\n\t" \ + "leal %2, %%ecx\n\t" \ + "call __lll_mutex_lock_wait\n\t" \ + "jmp 1f\n\t" \ + ".size _L_mutex_lock_%=,.-_L_mutex_lock_%=\n" \ + ".previous\n" \ + "1:" \ + : "=a" (ignore1), "=c" (ignore2), "=m" (futex) \ + : "0" (0), "1" (1), "m" (futex), \ + "i" (offsetof (tcbhead_t, multiple_threads)) \ + : "memory"); }) + + +# define lll_unlock(futex) \ + (void) ({ int ignore; \ + __asm__ __volatile ("cmpl $0, %%gs:%P3\n\t" \ + "je,pt 0f\n\t" \ + "lock\n" \ + "0:\tsubl $1,%0\n\t" \ + "jne _L_mutex_unlock_%=\n\t" \ + ".subsection 1\n\t" \ + ".type _L_mutex_unlock_%=,@function\n" \ + "_L_mutex_unlock_%=:\n\t" \ + "leal %0, %%eax\n\t" \ + "call __lll_mutex_unlock_wake\n\t" \ + "jmp 1f\n\t" \ + ".size _L_mutex_unlock_%=,.-_L_mutex_unlock_%=\n" \ + ".previous\n" \ + "1:" \ + : "=m" (futex), "=&a" (ignore) \ + : "m" (futex), \ + "i" (offsetof (tcbhead_t, multiple_threads)) \ + : "memory"); }) +#endif + + +#define lll_islocked(futex) \ + (futex != LLL_LOCK_INITIALIZER) + + +/* The kernel notifies a process with uses CLONE_CLEARTID via futex + wakeup when the clone terminates. The memory location contains the + thread ID while the clone is running and is reset to zero + afterwards. + + The macro parameter must not have any side effect. */ +#define lll_wait_tid(tid) \ + ({ \ + int __ret; \ + register __typeof (tid) _tid __asm__ ("edx") = (tid); \ + if (_tid != 0) \ + __asm__ __volatile (LLL_EBX_LOAD \ + "1:\tmovl %1, %%eax\n\t" \ + LLL_ENTER_KERNEL \ + "cmpl $0, (%%ebx)\n\t" \ + "jne,pn 1b\n\t" \ + LLL_EBX_LOAD \ + : "=&a" (__ret) \ + : "i" (SYS_futex), LLL_EBX_REG (&tid), "S" (0), \ + "c" (FUTEX_WAIT), "d" (_tid), \ + "i" (offsetof (tcbhead_t, sysinfo))); \ + __ret; }) + +extern int __lll_timedwait_tid (int *tid, const struct timespec *abstime) + __attribute__ ((regparm (2))) attribute_hidden; +#define lll_timedwait_tid(tid, abstime) \ + ({ \ + int __result = 0; \ + if (tid != 0) \ + { \ + if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) \ + __result = EINVAL; \ + else \ + __result = __lll_timedwait_tid (&tid, abstime); \ + } \ + __result; }) + + +/* Conditional variable handling. */ + +extern void __lll_cond_wait (pthread_cond_t *cond) + __attribute ((regparm (1))) attribute_hidden; +extern int __lll_cond_timedwait (pthread_cond_t *cond, + const struct timespec *abstime) + __attribute ((regparm (2))) attribute_hidden; +extern void __lll_cond_wake (pthread_cond_t *cond) + __attribute ((regparm (1))) attribute_hidden; +extern void __lll_cond_broadcast (pthread_cond_t *cond) + __attribute ((regparm (1))) attribute_hidden; + + +#define lll_cond_wait(cond) \ + __lll_cond_wait (cond) +#define lll_cond_timedwait(cond, abstime) \ + __lll_cond_timedwait (cond, abstime) +#define lll_cond_wake(cond) \ + __lll_cond_wake (cond) +#define lll_cond_broadcast(cond) \ + __lll_cond_broadcast (cond) + + +#endif /* lowlevellock.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/not-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/not-cancel.h new file mode 100644 index 000000000..5bdba3f51 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/not-cancel.h @@ -0,0 +1,82 @@ +/* Uncancelable versions of cancelable interfaces. Linux/NPTL version. + Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> + +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt +extern int __open_nocancel (const char *, int, ...) attribute_hidden; +extern int __close_nocancel (int) attribute_hidden; +extern int __read_nocancel (int, void *, size_t) attribute_hidden; +extern int __write_nocancel (int, const void *, size_t) attribute_hidden; +extern pid_t __waitpid_nocancel (pid_t, int *, int) attribute_hidden; + +libc_hidden_proto(__open_nocancel) +libc_hidden_proto(__close_nocancel) +libc_hidden_proto(__read_nocancel) +libc_hidden_proto(__write_nocancel) +libc_hidden_proto(__waitpid_nocancel) + +#else +#define __open_nocancel(name, ...) open (name, __VA_ARGS__) +#define __close_nocancel(fd) close (fd) +#define __read_nocancel(fd, buf, len) read (fd, buf, len) +#define __write_nocancel(fd, buf, len) write (fd, buf, len) +#define __waitpid_nocancel(pid, stat_loc, options) \ + waitpid (pid, stat_loc, options) +#endif + +/* Uncancelable open. */ +#define open_not_cancel(name, flags, mode) \ + __open_nocancel (name, flags, mode) +#define open_not_cancel_2(name, flags) \ + __open_nocancel (name, flags) + +/* Uncancelable close. */ +#define close_not_cancel(fd) \ + __close_nocancel (fd) +#define close_not_cancel_no_status(fd) \ + (void) ({ INTERNAL_SYSCALL_DECL (err); \ + INTERNAL_SYSCALL (close, err, 1, (fd)); }) + +/* Uncancelable read. */ +#define read_not_cancel(fd, buf, n) \ + __read_nocancel (fd, buf, n) + +/* Uncancelable write. */ +#define write_not_cancel(fd, buf, n) \ + __write_nocancel (fd, buf, n) + +/* Uncancelable writev. */ +#define writev_not_cancel_no_status(fd, iov, n) \ + (void) ({ INTERNAL_SYSCALL_DECL (err); \ + INTERNAL_SYSCALL (writev, err, 3, (fd), (iov), (n)); }) + +/* Uncancelable fcntl. */ +#define fcntl_not_cancel(fd, cmd, val) \ + __fcntl_nocancel (fd, cmd, val) + +/* Uncancelable waitpid. */ +#ifdef __NR_waitpid +# define waitpid_not_cancel(pid, stat_loc, options) \ + __waitpid_nocancel (pid, stat_loc, options) +#else +# define waitpid_not_cancel(pid, stat_loc, options) \ + INLINE_SYSCALL (wait4, 4, pid, stat_loc, options, NULL) +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/pt-__syscall_error.c b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/pt-__syscall_error.c new file mode 100644 index 000000000..620640ad6 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/pt-__syscall_error.c @@ -0,0 +1 @@ +#include <../../../../../../../libc/sysdeps/linux/i386/__syscall_error.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/pt-vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/pt-vfork.S new file mode 100644 index 000000000..939538927 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/pt-vfork.S @@ -0,0 +1,36 @@ +/* Copyright (C) 1999, 2002, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Andreas Schwab <schwab@gnu.org>. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <tcb-offsets.h> + +/* Save the PID value. */ +#define SAVE_PID \ + movl %gs:PID, %edx; \ + movl %edx, %eax; \ + negl %eax; \ + movl %eax, %gs:PID + +/* Restore the old PID value in the parent. */ +#define RESTORE_PID \ + testl %eax, %eax; \ + je 1f; \ + movl %edx, %gs:PID; \ +1: + +#include <../../../../../../../libc/sysdeps/linux/i386/vfork.S> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/pthread_once.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/pthread_once.S new file mode 100644 index 000000000..5ab2c5856 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/pthread_once.S @@ -0,0 +1,181 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <unwindbuf.h> +#include <sysdep.h> + +#ifndef UP +# define LOCK lock +#else +# define LOCK +#endif + +#define FUTEX_WAKE 1 + + .comm __fork_generation, 4, 4 + + .text + + + .globl __pthread_once + .type __pthread_once,@function + .align 16 + cfi_startproc +__pthread_once: + movl 4(%esp), %ecx + testl $2, (%ecx) + jz 1f + xorl %eax, %eax + ret + +1: pushl %ebx + cfi_adjust_cfa_offset (4) + cfi_rel_offset (3, 0) + pushl %esi + cfi_adjust_cfa_offset (4) + cfi_rel_offset (6, 0) + movl %ecx, %ebx + xorl %esi, %esi + + /* Not yet initialized or initialization in progress. + Get the fork generation counter now. */ +6: movl (%ebx), %eax +#ifdef __PIC__ + call __x86.get_pc_thunk.cx + addl $_GLOBAL_OFFSET_TABLE_, %ecx +#endif + +5: movl %eax, %edx + + testl $2, %eax + jnz 4f + + andl $3, %edx +#ifdef __PIC__ + orl __fork_generation@GOTOFF(%ecx), %edx +#else + orl __fork_generation, %edx +#endif + orl $1, %edx + + LOCK + cmpxchgl %edx, (%ebx) + jnz 5b + + /* Check whether another thread already runs the initializer. */ + testl $1, %eax + jz 3f /* No -> do it. */ + + /* Check whether the initializer execution was interrupted + by a fork. */ + xorl %edx, %eax + testl $0xfffffffc, %eax + jnz 3f /* Different for generation -> run initializer. */ + + /* Somebody else got here first. Wait. */ + movl %esi, %ecx /* movl $FUTEX_WAIT, %ecx */ + movl $SYS_futex, %eax + ENTER_KERNEL + jmp 6b + +3: /* Call the initializer function after setting up the + cancellation handler. Note that it is not possible here + to use the unwind-based cleanup handling. This would require + that the user-provided function and all the code it calls + is compiled with exceptions. Unfortunately this cannot be + guaranteed. */ + subl $UNWINDBUFSIZE+8, %esp + cfi_adjust_cfa_offset (UNWINDBUFSIZE+8) + movl %ecx, %ebx /* PIC register value. */ + + leal 8+UWJMPBUF(%esp), %eax + movl $0, 4(%esp) + movl %eax, (%esp) + call __sigsetjmp@PLT + testl %eax, %eax + jne 7f + + leal 8(%esp), %eax + call HIDDEN_JUMPTARGET(__pthread_register_cancel) + + /* Call the user-provided initialization function. */ + call *24+UNWINDBUFSIZE(%esp) + + /* Pop the cleanup handler. */ + leal 8(%esp), %eax + call HIDDEN_JUMPTARGET(__pthread_unregister_cancel) + addl $UNWINDBUFSIZE+8, %esp + cfi_adjust_cfa_offset (-UNWINDBUFSIZE-8) + + /* Sucessful run of the initializer. Signal that we are done. */ + movl 12(%esp), %ebx + LOCK + addl $1, (%ebx) + + /* Wake up all other threads. */ + movl $0x7fffffff, %edx + movl $FUTEX_WAKE, %ecx + movl $SYS_futex, %eax + ENTER_KERNEL + +4: popl %esi + cfi_adjust_cfa_offset (-4) + cfi_restore (6) + popl %ebx + cfi_adjust_cfa_offset (-4) + cfi_restore (3) + xorl %eax, %eax + ret + +7: /* __sigsetjmp returned for the second time. */ + movl 20+UNWINDBUFSIZE(%esp), %ebx + cfi_adjust_cfa_offset (UNWINDBUFSIZE+16) + cfi_offset (3, -8) + cfi_offset (6, -12) + movl $0, (%ebx) + + movl $0x7fffffff, %edx + movl $FUTEX_WAKE, %ecx + movl $SYS_futex, %eax + ENTER_KERNEL + + leal 8(%esp), %eax + call HIDDEN_JUMPTARGET (__pthread_unwind_next) + /* NOTREACHED */ + hlt + cfi_endproc + .size __pthread_once,.-__pthread_once + + .globl __pthread_once_internal +__pthread_once_internal = __pthread_once + + .globl pthread_once +pthread_once = __pthread_once + + +#ifdef __PIC__ + .section .gnu.linkonce.t.__x86.get_pc_thunk.cx,"ax",@progbits + .globl __x86.get_pc_thunk.cx + .hidden __x86.get_pc_thunk.cx + .type __x86.get_pc_thunk.cx,@function +__x86.get_pc_thunk.cx: + movl (%esp), %ecx; + ret + .size __x86.get_pc_thunk.cx,.-__x86.get_pc_thunk.cx +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/pthread_spin_init.c b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/pthread_spin_init.c new file mode 100644 index 000000000..d36e5373d --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/pthread_spin_init.c @@ -0,0 +1 @@ +#include <sysdeps/i386/pthread_spin_init.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/pthread_spin_unlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/pthread_spin_unlock.S new file mode 100644 index 000000000..8bae0fd31 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/pthread_spin_unlock.S @@ -0,0 +1 @@ +#include <sysdeps/i386/pthread_spin_unlock.S> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/smp.h b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/smp.h new file mode 100644 index 000000000..2c0cbe99a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/smp.h @@ -0,0 +1,24 @@ +/* Determine whether the host has multiple processors. SH version. + Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +static inline int +is_smp_system (void) +{ + return 0; +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/sysdep-cancel.h new file mode 100644 index 000000000..f32c5bd20 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/sysdep-cancel.h @@ -0,0 +1,139 @@ +/* Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <tls.h> +#ifndef __ASSEMBLER__ +# include <pthreadP.h> +#endif + +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt + +# undef PSEUDO +# define PSEUDO(name, syscall_name, args) \ + .text; \ + ENTRY (name) \ + cmpl $0, %gs:MULTIPLE_THREADS_OFFSET; \ + jne L(pseudo_cancel); \ + .type __##syscall_name##_nocancel,@function; \ + .globl __##syscall_name##_nocancel; \ + __##syscall_name##_nocancel: \ + DO_CALL (syscall_name, args); \ + cmpl $-4095, %eax; \ + jae SYSCALL_ERROR_LABEL; \ + ret; \ + .size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel; \ + L(pseudo_cancel): \ + CENABLE \ + SAVE_OLDTYPE_##args \ + PUSHCARGS_##args \ + DOCARGS_##args \ + movl $SYS_ify (syscall_name), %eax; \ + ENTER_KERNEL; \ + POPCARGS_##args; \ + POPSTATE_##args \ + cmpl $-4095, %eax; \ + jae SYSCALL_ERROR_LABEL; \ + L(pseudo_end): + +# define SAVE_OLDTYPE_0 movl %eax, %ecx; +# define SAVE_OLDTYPE_1 SAVE_OLDTYPE_0 +# define SAVE_OLDTYPE_2 pushl %eax; cfi_adjust_cfa_offset (4); +# define SAVE_OLDTYPE_3 SAVE_OLDTYPE_2 +# define SAVE_OLDTYPE_4 SAVE_OLDTYPE_2 +# define SAVE_OLDTYPE_5 SAVE_OLDTYPE_2 + +# define PUSHCARGS_0 /* No arguments to push. */ +# define DOCARGS_0 /* No arguments to frob. */ +# define POPCARGS_0 /* No arguments to pop. */ +# define _PUSHCARGS_0 /* No arguments to push. */ +# define _POPCARGS_0 /* No arguments to pop. */ + +# define PUSHCARGS_1 movl %ebx, %edx; cfi_register (ebx, edx); PUSHCARGS_0 +# define DOCARGS_1 _DOARGS_1 (4) +# define POPCARGS_1 POPCARGS_0; movl %edx, %ebx; cfi_restore (ebx); +# define _PUSHCARGS_1 pushl %ebx; cfi_adjust_cfa_offset (4); \ + cfi_rel_offset (ebx, 0); _PUSHCARGS_0 +# define _POPCARGS_1 _POPCARGS_0; popl %ebx; \ + cfi_adjust_cfa_offset (-4); cfi_restore (ebx); + +# define PUSHCARGS_2 PUSHCARGS_1 +# define DOCARGS_2 _DOARGS_2 (12) +# define POPCARGS_2 POPCARGS_1 +# define _PUSHCARGS_2 _PUSHCARGS_1 +# define _POPCARGS_2 _POPCARGS_1 + +# define PUSHCARGS_3 _PUSHCARGS_2 +# define DOCARGS_3 _DOARGS_3 (20) +# define POPCARGS_3 _POPCARGS_3 +# define _PUSHCARGS_3 _PUSHCARGS_2 +# define _POPCARGS_3 _POPCARGS_2 + +# define PUSHCARGS_4 _PUSHCARGS_4 +# define DOCARGS_4 _DOARGS_4 (28) +# define POPCARGS_4 _POPCARGS_4 +# define _PUSHCARGS_4 pushl %esi; cfi_adjust_cfa_offset (4); \ + cfi_rel_offset (esi, 0); _PUSHCARGS_3 +# define _POPCARGS_4 _POPCARGS_3; popl %esi; \ + cfi_adjust_cfa_offset (-4); cfi_restore (esi); + +# define PUSHCARGS_5 _PUSHCARGS_5 +# define DOCARGS_5 _DOARGS_5 (36) +# define POPCARGS_5 _POPCARGS_5 +# define _PUSHCARGS_5 pushl %edi; cfi_adjust_cfa_offset (4); \ + cfi_rel_offset (edi, 0); _PUSHCARGS_4 +# define _POPCARGS_5 _POPCARGS_4; popl %edi; \ + cfi_adjust_cfa_offset (-4); cfi_restore (edi); + +# ifdef IS_IN_libpthread +# define CENABLE call __pthread_enable_asynccancel; +# define CDISABLE call __pthread_disable_asynccancel +# elif !defined NOT_IN_libc +# define CENABLE call __libc_enable_asynccancel; +# define CDISABLE call __libc_disable_asynccancel +# elif defined IS_IN_librt +# define CENABLE call __librt_enable_asynccancel; +# define CDISABLE call __librt_disable_asynccancel +# else +# error Unsupported library +# endif +# define POPSTATE_0 \ + pushl %eax; cfi_adjust_cfa_offset (4); movl %ecx, %eax; \ + CDISABLE; popl %eax; cfi_adjust_cfa_offset (-4); +# define POPSTATE_1 POPSTATE_0 +# define POPSTATE_2 xchgl (%esp), %eax; CDISABLE; popl %eax; \ + cfi_adjust_cfa_offset (-4); +# define POPSTATE_3 POPSTATE_2 +# define POPSTATE_4 POPSTATE_3 +# define POPSTATE_5 POPSTATE_4 + +# ifndef __ASSEMBLER__ +# define SINGLE_THREAD_P \ + __builtin_expect (THREAD_GETMEM (THREAD_SELF, \ + header.multiple_threads) == 0, 1) +# else +# define SINGLE_THREAD_P cmpl $0, %gs:MULTIPLE_THREADS_OFFSET +# endif + +#elif !defined __ASSEMBLER__ + +# define SINGLE_THREAD_P (1) +# define NO_CANCELLATION 1 + +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/sysdep.h b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/sysdep.h new file mode 100644 index 000000000..674d5c699 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/sysdep.h @@ -0,0 +1,336 @@ +/* Copyright (C) 1992,1993,1995-2000,2002-2006,2007 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper, <drepper@gnu.org>, August 1995. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _LINUX_I386_SYSDEP_H +#define _LINUX_I386_SYSDEP_H 1 + +#include <sys/syscall.h> +#include <sysdeps/i386/sysdep.h> + +#ifndef offsetof +# define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +#endif + +/* For Linux we can use the system call table in the header file + /usr/include/asm/unistd.h + of the kernel. But these symbols do not follow the SYS_* syntax + so we have to redefine the `SYS_ify' macro here. */ +#undef SYS_ify +#define SYS_ify(syscall_name) __NR_##syscall_name + +#if defined USE_DL_SYSINFO \ + && (!defined NOT_IN_libc || defined IS_IN_libpthread) +# define I386_USE_SYSENTER 1 +#else +# undef I386_USE_SYSENTER +#endif + +#ifdef __ASSEMBLER__ + +/* Linux uses a negative return value to indicate syscall errors, + unlike most Unices, which use the condition codes' carry flag. + + Since version 2.1 the return value of a system call might be + negative even if the call succeeded. E.g., the `lseek' system call + might return a large offset. Therefore we must not anymore test + for < 0, but test for a real error by making sure the value in %eax + is a real error number. Linus said he will make sure the no syscall + returns a value in -1 .. -4095 as a valid result so we can savely + test with -4095. */ + +/* We don't want the label for the error handle to be global when we define + it here. */ +#ifdef __PIC__ +# define SYSCALL_ERROR_LABEL 0f +#else +# define SYSCALL_ERROR_LABEL syscall_error +#endif + +#undef PSEUDO +#define PSEUDO(name, syscall_name, args) \ + .text; \ + ENTRY (name) \ + DO_CALL (syscall_name, args); \ + cmpl $-4095, %eax; \ + jae SYSCALL_ERROR_LABEL; \ + L(pseudo_end): + +#undef PSEUDO_END +#define PSEUDO_END(name) \ + SYSCALL_ERROR_HANDLER \ + END (name) + +#undef PSEUDO_NOERRNO +#define PSEUDO_NOERRNO(name, syscall_name, args) \ + .text; \ + ENTRY (name) \ + DO_CALL (syscall_name, args) + +#undef PSEUDO_END_NOERRNO +#define PSEUDO_END_NOERRNO(name) \ + END (name) + +#define ret_NOERRNO ret + +/* The function has to return the error code. */ +#undef PSEUDO_ERRVAL +#define PSEUDO_ERRVAL(name, syscall_name, args) \ + .text; \ + ENTRY (name) \ + DO_CALL (syscall_name, args); \ + negl %eax + +#undef PSEUDO_END_ERRVAL +#define PSEUDO_END_ERRVAL(name) \ + END (name) + +#define ret_ERRVAL ret + +#ifndef __PIC__ +# define SYSCALL_ERROR_HANDLER /* Nothing here; code in sysdep.S is used. */ +#else + +# ifdef RTLD_PRIVATE_ERRNO +# define SYSCALL_ERROR_HANDLER \ +0:SETUP_PIC_REG(cx); \ + addl $_GLOBAL_OFFSET_TABLE_, %ecx; \ + xorl %edx, %edx; \ + subl %eax, %edx; \ + movl %edx, rtld_errno@GOTOFF(%ecx); \ + orl $-1, %eax; \ + jmp L(pseudo_end); + +# elif defined _LIBC_REENTRANT + +# if USE___THREAD +# ifndef NOT_IN_libc +# define SYSCALL_ERROR_ERRNO __libc_errno +# else +# define SYSCALL_ERROR_ERRNO errno +# endif +# define SYSCALL_ERROR_HANDLER \ +0:SETUP_PIC_REG (cx); \ + addl $_GLOBAL_OFFSET_TABLE_, %ecx; \ + movl SYSCALL_ERROR_ERRNO@GOTNTPOFF(%ecx), %ecx; \ + xorl %edx, %edx; \ + subl %eax, %edx; \ + SYSCALL_ERROR_HANDLER_TLS_STORE (%edx, %ecx); \ + orl $-1, %eax; \ + jmp L(pseudo_end); +# ifndef NO_TLS_DIRECT_SEG_REFS +# define SYSCALL_ERROR_HANDLER_TLS_STORE(src, destoff) \ + movl src, %gs:(destoff) +# else +# define SYSCALL_ERROR_HANDLER_TLS_STORE(src, destoff) \ + addl %gs:0, destoff; \ + movl src, (destoff) +# endif +# else +# define SYSCALL_ERROR_HANDLER \ +0:pushl %ebx; \ + cfi_adjust_cfa_offset (4); \ + cfi_rel_offset (ebx, 0); \ + SETUP_PIC_REG (bx); \ + addl $_GLOBAL_OFFSET_TABLE_, %ebx; \ + xorl %edx, %edx; \ + subl %eax, %edx; \ + pushl %edx; \ + cfi_adjust_cfa_offset (4); \ + call __errno_location@PLT; \ + popl %ecx; \ + cfi_adjust_cfa_offset (-4); \ + popl %ebx; \ + cfi_adjust_cfa_offset (-4); \ + cfi_restore (ebx); \ + movl %ecx, (%eax); \ + orl $-1, %eax; \ + jmp L(pseudo_end); +/* A quick note: it is assumed that the call to `__errno_location' does + not modify the stack! */ +# endif +# else +/* Store (- %eax) into errno through the GOT. */ +# define SYSCALL_ERROR_HANDLER \ +0:SETUP_PIC_REG(cx); \ + addl $_GLOBAL_OFFSET_TABLE_, %ecx; \ + xorl %edx, %edx; \ + subl %eax, %edx; \ + movl errno@GOT(%ecx), %ecx; \ + movl %edx, (%ecx); \ + orl $-1, %eax; \ + jmp L(pseudo_end); +# endif /* _LIBC_REENTRANT */ +#endif /* __PIC__ */ + + +/* The original calling convention for system calls on Linux/i386 is + to use int $0x80. */ +#ifdef I386_USE_SYSENTER +# ifdef SHARED +# define ENTER_KERNEL call *%gs:SYSINFO_OFFSET +# else +# define ENTER_KERNEL call *_dl_sysinfo +# endif +#else +# define ENTER_KERNEL int $0x80 +#endif + +/* Linux takes system call arguments in registers: + + syscall number %eax call-clobbered + arg 1 %ebx call-saved + arg 2 %ecx call-clobbered + arg 3 %edx call-clobbered + arg 4 %esi call-saved + arg 5 %edi call-saved + arg 6 %ebp call-saved + + The stack layout upon entering the function is: + + 24(%esp) Arg# 6 + 20(%esp) Arg# 5 + 16(%esp) Arg# 4 + 12(%esp) Arg# 3 + 8(%esp) Arg# 2 + 4(%esp) Arg# 1 + (%esp) Return address + + (Of course a function with say 3 arguments does not have entries for + arguments 4, 5, and 6.) + + The following code tries hard to be optimal. A general assumption + (which is true according to the data books I have) is that + + 2 * xchg is more expensive than pushl + movl + popl + + Beside this a neat trick is used. The calling conventions for Linux + tell that among the registers used for parameters %ecx and %edx need + not be saved. Beside this we may clobber this registers even when + they are not used for parameter passing. + + As a result one can see below that we save the content of the %ebx + register in the %edx register when we have less than 3 arguments + (2 * movl is less expensive than pushl + popl). + + Second unlike for the other registers we don't save the content of + %ecx and %edx when we have more than 1 and 2 registers resp. + + The code below might look a bit long but we have to take care for + the pipelined processors (i586). Here the `pushl' and `popl' + instructions are marked as NP (not pairable) but the exception is + two consecutive of these instruction. This gives no penalty on + other processors though. */ + +#undef DO_CALL +#define DO_CALL(syscall_name, args) \ + PUSHARGS_##args \ + DOARGS_##args \ + movl $SYS_ify (syscall_name), %eax; \ + ENTER_KERNEL \ + POPARGS_##args + +#define PUSHARGS_0 /* No arguments to push. */ +#define DOARGS_0 /* No arguments to frob. */ +#define POPARGS_0 /* No arguments to pop. */ +#define _PUSHARGS_0 /* No arguments to push. */ +#define _DOARGS_0(n) /* No arguments to frob. */ +#define _POPARGS_0 /* No arguments to pop. */ + +#define PUSHARGS_1 movl %ebx, %edx; L(SAVEBX1): PUSHARGS_0 +#define DOARGS_1 _DOARGS_1 (4) +#define POPARGS_1 POPARGS_0; movl %edx, %ebx; L(RESTBX1): +#define _PUSHARGS_1 pushl %ebx; cfi_adjust_cfa_offset (4); \ + cfi_rel_offset (ebx, 0); L(PUSHBX1): _PUSHARGS_0 +#define _DOARGS_1(n) movl n(%esp), %ebx; _DOARGS_0(n-4) +#define _POPARGS_1 _POPARGS_0; popl %ebx; cfi_adjust_cfa_offset (-4); \ + cfi_restore (ebx); L(POPBX1): + +#define PUSHARGS_2 PUSHARGS_1 +#define DOARGS_2 _DOARGS_2 (8) +#define POPARGS_2 POPARGS_1 +#define _PUSHARGS_2 _PUSHARGS_1 +#define _DOARGS_2(n) movl n(%esp), %ecx; _DOARGS_1 (n-4) +#define _POPARGS_2 _POPARGS_1 + +#define PUSHARGS_3 _PUSHARGS_2 +#define DOARGS_3 _DOARGS_3 (16) +#define POPARGS_3 _POPARGS_3 +#define _PUSHARGS_3 _PUSHARGS_2 +#define _DOARGS_3(n) movl n(%esp), %edx; _DOARGS_2 (n-4) +#define _POPARGS_3 _POPARGS_2 + +#define PUSHARGS_4 _PUSHARGS_4 +#define DOARGS_4 _DOARGS_4 (24) +#define POPARGS_4 _POPARGS_4 +#define _PUSHARGS_4 pushl %esi; cfi_adjust_cfa_offset (4); \ + cfi_rel_offset (esi, 0); L(PUSHSI1): _PUSHARGS_3 +#define _DOARGS_4(n) movl n(%esp), %esi; _DOARGS_3 (n-4) +#define _POPARGS_4 _POPARGS_3; popl %esi; cfi_adjust_cfa_offset (-4); \ + cfi_restore (esi); L(POPSI1): + +#define PUSHARGS_5 _PUSHARGS_5 +#define DOARGS_5 _DOARGS_5 (32) +#define POPARGS_5 _POPARGS_5 +#define _PUSHARGS_5 pushl %edi; cfi_adjust_cfa_offset (4); \ + cfi_rel_offset (edi, 0); L(PUSHDI1): _PUSHARGS_4 +#define _DOARGS_5(n) movl n(%esp), %edi; _DOARGS_4 (n-4) +#define _POPARGS_5 _POPARGS_4; popl %edi; cfi_adjust_cfa_offset (-4); \ + cfi_restore (edi); L(POPDI1): + +#define PUSHARGS_6 _PUSHARGS_6 +#define DOARGS_6 _DOARGS_6 (40) +#define POPARGS_6 _POPARGS_6 +#define _PUSHARGS_6 pushl %ebp; cfi_adjust_cfa_offset (4); \ + cfi_rel_offset (ebp, 0); L(PUSHBP1): _PUSHARGS_5 +#define _DOARGS_6(n) movl n(%esp), %ebp; _DOARGS_5 (n-4) +#define _POPARGS_6 _POPARGS_5; popl %ebp; cfi_adjust_cfa_offset (-4); \ + cfi_restore (ebp); L(POPBP1): + +#endif /* __ASSEMBLER__ */ + + +/* Pointer mangling support. */ +#if defined NOT_IN_libc && defined IS_IN_rtld +/* We cannot use the thread descriptor because in ld.so we use setjmp + earlier than the descriptor is initialized. Using a global variable + is too complicated here since we have no PC-relative addressing mode. */ +#else +# ifdef __ASSEMBLER__ +# define PTR_MANGLE(reg) xorl %gs:POINTER_GUARD, reg; \ + roll $9, reg +# define PTR_DEMANGLE(reg) rorl $9, reg; \ + xorl %gs:POINTER_GUARD, reg +# else +# define PTR_MANGLE(var) asm ("xorl %%gs:%c2, %0\n" \ + "roll $9, %0" \ + : "=r" (var) \ + : "0" (var), \ + "i" (offsetof (tcbhead_t, \ + pointer_guard))) +# define PTR_DEMANGLE(var) asm ("rorl $9, %0\n" \ + "xorl %%gs:%c2, %0" \ + : "=r" (var) \ + : "0" (var), \ + "i" (offsetof (tcbhead_t, \ + pointer_guard))) +# endif +#endif + +#endif /* linux/i386/sysdep.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/vfork.S new file mode 100644 index 000000000..dc7fb2ec4 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/vfork.S @@ -0,0 +1,38 @@ +/* Copyright (C) 1999, 2002, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <tcb-offsets.h> + +/* Save the PID value. */ +#define SAVE_PID \ + movl %gs:PID, %edx; \ + movl %edx, %eax; \ + negl %eax; \ + jne 1f; \ + movl $0x80000000, %eax; \ +1: movl %eax, %gs:PID + +/* Restore the old PID value in the parent. */ +#define RESTORE_PID \ + testl %eax, %eax; \ + je 1f; \ + movl %edx, %gs:PID; \ +1: + + +#include <libc/sysdeps/linux/i386/vfork.S> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/internaltypes.h b/libpthread/nptl/sysdeps/unix/sysv/linux/internaltypes.h new file mode 100644 index 000000000..07ee9d7dd --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/internaltypes.h @@ -0,0 +1,153 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _INTERNALTYPES_H +#define _INTERNALTYPES_H 1 + +#include <stdint.h> +#include <sched.h> + + +struct pthread_attr +{ + /* Scheduler parameters and priority. */ + struct sched_param schedparam; + int schedpolicy; + /* Various flags like detachstate, scope, etc. */ + int flags; + /* Size of guard area. */ + size_t guardsize; + /* Stack handling. */ + void *stackaddr; + size_t stacksize; + /* Affinity map. */ + cpu_set_t *cpuset; + size_t cpusetsize; +}; + +#define ATTR_FLAG_DETACHSTATE 0x0001 +#define ATTR_FLAG_NOTINHERITSCHED 0x0002 +#define ATTR_FLAG_SCOPEPROCESS 0x0004 +#define ATTR_FLAG_STACKADDR 0x0008 +#define ATTR_FLAG_OLDATTR 0x0010 +#define ATTR_FLAG_SCHED_SET 0x0020 +#define ATTR_FLAG_POLICY_SET 0x0040 + + +/* Mutex attribute data structure. */ +struct pthread_mutexattr +{ + /* Identifier for the kind of mutex. + + Bit 31 is set if the mutex is to be shared between processes. + + Bit 0 to 30 contain one of the PTHREAD_MUTEX_ values to identify + the type of the mutex. */ + int mutexkind; +}; + + +/* Conditional variable attribute data structure. */ +struct pthread_condattr +{ + /* Combination of values: + + Bit 0 : flag whether coditional variable will be shareable between + processes. + + Bit 1-7: clock ID. */ + int value; +}; + + +/* The __NWAITERS field is used as a counter and to house the number + of bits which represent the clock. COND_CLOCK_BITS is the number + of bits reserved for the clock. */ +#define COND_CLOCK_BITS 1 + + +/* Read-write lock variable attribute data structure. */ +struct pthread_rwlockattr +{ + int lockkind; + int pshared; +}; + + +/* Barrier data structure. */ +struct pthread_barrier +{ + unsigned int curr_event; + int lock; + unsigned int left; + unsigned int init_count; +}; + + +/* Barrier variable attribute data structure. */ +struct pthread_barrierattr +{ + int pshared; +}; + + +/* Thread-local data handling. */ +struct pthread_key_struct +{ + /* Sequence numbers. Even numbers indicated vacant entries. Note + that zero is even. We use uintptr_t to not require padding on + 32- and 64-bit machines. On 64-bit machines it helps to avoid + wrapping, too. */ + uintptr_t seq; + + /* Destructor for the data. */ + void (*destr) (void *); +}; + +/* Check whether an entry is unused. */ +#define KEY_UNUSED(p) (((p) & 1) == 0) +/* Check whether a key is usable. We cannot reuse an allocated key if + the sequence counter would overflow after the next destroy call. + This would mean that we potentially free memory for a key with the + same sequence. This is *very* unlikely to happen, A program would + have to create and destroy a key 2^31 times (on 32-bit platforms, + on 64-bit platforms that would be 2^63). If it should happen we + simply don't use this specific key anymore. */ +#define KEY_USABLE(p) (((uintptr_t) (p)) < ((uintptr_t) ((p) + 2))) + + +/* Handling of read-write lock data. */ +// XXX For now there is only one flag. Maybe more in future. +#define RWLOCK_RECURSIVE(rwlock) ((rwlock)->__data.__flags != 0) + + +/* Semaphore variable structure. */ +struct sem +{ + unsigned int count; +}; + + +/* Compatibility type for old conditional variable interfaces. */ +typedef struct +{ + pthread_cond_t *cond; +} pthread_cond_2_0_t; + +#endif /* internaltypes.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/jmp-unwind.c b/libpthread/nptl/sysdeps/unix/sysv/linux/jmp-unwind.c new file mode 100644 index 000000000..c435eff30 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/jmp-unwind.c @@ -0,0 +1,39 @@ +/* Clean up stack frames unwound by longjmp. Linux version. + Copyright (C) 1995, 1997, 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <setjmp.h> +#include <stddef.h> +#include <pthreadP.h> + +extern void __pthread_cleanup_upto (__jmp_buf env, char *targetframe); +#pragma weak __pthread_cleanup_upto + + +void +_longjmp_unwind (jmp_buf env, int val) +{ +#ifdef SHARED +# define fptr __libc_pthread_functions.ptr___pthread_cleanup_upto +#else +# define fptr __pthread_cleanup_upto +#endif + + if (fptr != NULL) + fptr (env->__jmpbuf, CURRENT_STACK_FRAME); +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/kernel-posix-timers.h b/libpthread/nptl/sysdeps/unix/sysv/linux/kernel-posix-timers.h new file mode 100644 index 000000000..9be630268 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/kernel-posix-timers.h @@ -0,0 +1 @@ +#include <../../../../../../librt/kernel-posix-timers.h> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/libc-lowlevellock.c b/libpthread/nptl/sysdeps/unix/sysv/linux/libc-lowlevellock.c new file mode 100644 index 000000000..b19282281 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/libc-lowlevellock.c @@ -0,0 +1,21 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* No difference to lowlevellock.c, except we lose a couple of functions. */ +#include "lowlevellock.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/libc_multiple_threads.c b/libpthread/nptl/sysdeps/unix/sysv/linux/libc_multiple_threads.c new file mode 100644 index 000000000..a96f17490 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/libc_multiple_threads.c @@ -0,0 +1,26 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthreadP.h> + +#ifndef NOT_IN_libc +# ifndef TLS_MULTIPLE_THREADS_IN_TCB +int __libc_multiple_threads attribute_hidden; +# endif +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/libc_pthread_init.c b/libpthread/nptl/sysdeps/unix/sysv/linux/libc_pthread_init.c new file mode 100644 index 000000000..4ad252800 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/libc_pthread_init.c @@ -0,0 +1,59 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <unistd.h> +#include <list.h> +#include "fork.h" +#include <tls.h> +#include <string.h> +#include <pthreadP.h> +#include <bits/libc-lock.h> + +libc_hidden_proto(memcpy) + +#ifdef TLS_MULTIPLE_THREADS_IN_TCB +void +#else +extern int __libc_multiple_threads attribute_hidden; + +int * +#endif +__libc_pthread_init ( + unsigned long int *ptr, + void (*reclaim) (void), + const struct pthread_functions *functions) +{ + /* Remember the pointer to the generation counter in libpthread. */ + __fork_generation_pointer = ptr; + + /* Called by a child after fork. */ + __register_atfork (NULL, NULL, reclaim, NULL); + +#ifdef SHARED + /* We copy the content of the variable pointed to by the FUNCTIONS + parameter to one in libc.so since this means access to the array + can be done with one memory access instead of two. */ + memcpy (&__libc_pthread_functions, functions, + sizeof (__libc_pthread_functions)); +#endif + +#ifndef TLS_MULTIPLE_THREADS_IN_TCB + return &__libc_multiple_threads; +#endif +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevelbarrier.sym b/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevelbarrier.sym new file mode 100644 index 000000000..36e28eb2a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevelbarrier.sym @@ -0,0 +1,11 @@ +#include <stddef.h> +#include <sched.h> +#include <bits/pthreadtypes.h> +#include "internaltypes.h" + +-- + +CURR_EVENT offsetof (struct pthread_barrier, curr_event) +MUTEX offsetof (struct pthread_barrier, lock) +LEFT offsetof (struct pthread_barrier, left) +INIT_COUNT offsetof (struct pthread_barrier, init_count) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevelcond.sym b/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevelcond.sym new file mode 100644 index 000000000..c5e797806 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevelcond.sym @@ -0,0 +1,16 @@ +#include <stddef.h> +#include <sched.h> +#include <bits/pthreadtypes.h> +#include <internaltypes.h> + +-- + +cond_lock offsetof (pthread_cond_t, __data.__lock) +cond_futex offsetof (pthread_cond_t, __data.__futex) +cond_nwaiters offsetof (pthread_cond_t, __data.__nwaiters) +total_seq offsetof (pthread_cond_t, __data.__total_seq) +wakeup_seq offsetof (pthread_cond_t, __data.__wakeup_seq) +woken_seq offsetof (pthread_cond_t, __data.__woken_seq) +dep_mutex offsetof (pthread_cond_t, __data.__mutex) +broadcast_seq offsetof (pthread_cond_t, __data.__broadcast_seq) +clock_bits COND_CLOCK_BITS diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevellock.c b/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevellock.c new file mode 100644 index 000000000..f93891431 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevellock.c @@ -0,0 +1,131 @@ +/* low level locking for pthread library. Generic futex-using version. + Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <sys/time.h> + + +void +__lll_lock_wait (int *futex) +{ + do + { + int oldval = atomic_compare_and_exchange_val_acq (futex, 2, 1); + if (oldval != 0) + lll_futex_wait (futex, 2); + } + while (atomic_compare_and_exchange_bool_acq (futex, 2, 0) != 0); +} + + +int +__lll_timedlock_wait (int *futex, const struct timespec *abstime) +{ + /* Reject invalid timeouts. */ + if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) + return EINVAL; + + do + { + struct timeval tv; + struct timespec rt; + + /* Get the current time. */ + (void) gettimeofday (&tv, NULL); + + /* Compute relative timeout. */ + rt.tv_sec = abstime->tv_sec - tv.tv_sec; + rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000; + if (rt.tv_nsec < 0) + { + rt.tv_nsec += 1000000000; + --rt.tv_sec; + } + + /* Already timed out? */ + if (rt.tv_sec < 0) + return ETIMEDOUT; + + /* Wait. */ + int oldval = atomic_compare_and_exchange_val_acq (futex, 2, 1); + if (oldval != 0) + lll_futex_timed_wait (futex, 2, &rt); + } + while (atomic_compare_and_exchange_bool_acq (futex, 2, 0) != 0); + + return 0; +} + + +/* These don't get included in libc.so */ +#ifdef IS_IN_libpthread +int +lll_unlock_wake_cb (int *futex) +{ + int val = atomic_exchange_rel (futex, 0); + + if (__builtin_expect (val > 1, 0)) + lll_futex_wake (futex, 1); + + return 0; +} + + +int +__lll_timedwait_tid (int *tidp, const struct timespec *abstime) +{ + int tid; + + if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) + return EINVAL; + + /* Repeat until thread terminated. */ + while ((tid = *tidp) != 0) + { + struct timeval tv; + struct timespec rt; + + /* Get the current time. */ + (void) gettimeofday (&tv, NULL); + + /* Compute relative timeout. */ + rt.tv_sec = abstime->tv_sec - tv.tv_sec; + rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000; + if (rt.tv_nsec < 0) + { + rt.tv_nsec += 1000000000; + --rt.tv_sec; + } + + /* Already timed out? */ + if (rt.tv_sec < 0) + return ETIMEDOUT; + + /* Wait until thread terminates. */ + if (lll_futex_timed_wait (tidp, tid, &rt) == -ETIMEDOUT) + return ETIMEDOUT; + } + + return 0; +} + +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevelrwlock.sym b/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevelrwlock.sym new file mode 100644 index 000000000..e82c878d3 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevelrwlock.sym @@ -0,0 +1,14 @@ +#include <stddef.h> +#include <stdio.h> +#include <bits/pthreadtypes.h> + +-- + +MUTEX offsetof (pthread_rwlock_t, __data.__lock) +NR_READERS offsetof (pthread_rwlock_t, __data.__nr_readers) +READERS_WAKEUP offsetof (pthread_rwlock_t, __data.__readers_wakeup) +WRITERS_WAKEUP offsetof (pthread_rwlock_t, __data.__writer_wakeup) +READERS_QUEUED offsetof (pthread_rwlock_t, __data.__nr_readers_queued) +WRITERS_QUEUED offsetof (pthread_rwlock_t, __data.__nr_writers_queued) +FLAGS offsetof (pthread_rwlock_t, __data.__flags) +WRITER offsetof (pthread_rwlock_t, __data.__writer) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/lseek.S b/libpthread/nptl/sysdeps/unix/sysv/linux/lseek.S new file mode 100644 index 000000000..70a920ba1 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/lseek.S @@ -0,0 +1,7 @@ +#include <sysdep-cancel.h> +PSEUDO (__libc_lseek, lseek, 3) +ret +PSEUDO_END (__libc_lseek) +libc_hidden_def (__libc_lseek) +weak_alias (__libc_lseek, lseek) +libc_hidden_weak (lseek) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/Makefile b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/Makefile new file mode 100644 index 000000000..43a6fad84 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/Makefile @@ -0,0 +1,13 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2005 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +top_srcdir=../../../../../../../ +top_builddir=../../../../../../../ +all: objs +include $(top_builddir)Rules.mak +include Makefile.arch +include $(top_srcdir)Makerules diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/Makefile.arch b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/Makefile.arch new file mode 100644 index 000000000..a7de215e2 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/Makefile.arch @@ -0,0 +1,49 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2006 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +libpthread_SSRC = pt-vfork.S +libpthread_CSRC = pthread_once.c pt-__syscall_rt_sigaction.c + +libc_a_CSRC = fork.c + +CFLAGS-OMIT-fork.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +ifeq ($(UCLIBC_HAS_STDIO_FUTEXES),y) +CFLAGS-fork.c = -D__USE_STDIO_FUTEXES__ +endif +CFLAGS-pthread_once.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 + +ASFLAGS-pt-vfork.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 + +CFLAGS += $(SSP_ALL_CFLAGS) +#CFLAGS:=$(CFLAGS:-O1=-O2) + +LINUX_ARCH_DIR:=$(top_srcdir)libpthread/nptl/sysdeps/unix/sysv/linux/mips +LINUX_ARCH_OUT:=$(top_builddir)libpthread/nptl/sysdeps/unix/sysv/linux/mips + +LINUX_ARCH_OBJ:=$(patsubst %.S,$(LINUX_ARCH_OUT)/%.o,$(libpthread_SSRC)) +LINUX_ARCH_OBJ+=$(patsubst %.c,$(LINUX_ARCH_OUT)/%.o,$(libpthread_CSRC)) + +ifeq ($(DOPIC),y) +libpthread-a-y += $(LINUX_ARCH_OBJ:.o=.os) +else +libpthread-a-y += $(LINUX_ARCH_OBJ) +endif +libpthread-so-y += $(LINUX_ARCH_OBJ:.o=.oS) + +libpthread-nomulti-y+=$(LINUX_ARCH_OBJS) + +LIBC_LINUX_ARCH_OBJ:=$(patsubst %.c,$(LINUX_ARCH_OUT)/%.o,$(libc_a_CSRC)) + +libc-static-y+=$(LIBC_LINUX_ARCH_OBJ) +libc-shared-y+=$(LIBC_LINUX_ARCH_OBJ:.o=.oS) + +libc-nomulti-y+=$(LIBC_LINUX_ARCH_OBJ) + +objclean-y+=pthread_linux_arch_objclean + +pthread_linux_arch_objclean: + $(RM) $(LINUX_ARCH_OUT)/*.{o,os,oS} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/bits/pthreadtypes.h b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/bits/pthreadtypes.h new file mode 100644 index 000000000..f112b8a39 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/bits/pthreadtypes.h @@ -0,0 +1,215 @@ +/* Machine-specific pthread type layouts. MIPS version. + Copyright (C) 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _BITS_PTHREADTYPES_H +#define _BITS_PTHREADTYPES_H 1 + +#include <sgidefs.h> + +#if _MIPS_SIM == _ABI64 +# define __SIZEOF_PTHREAD_ATTR_T 56 +# define __SIZEOF_PTHREAD_MUTEX_T 40 +# define __SIZEOF_PTHREAD_MUTEXATTR_T 4 +# define __SIZEOF_PTHREAD_COND_T 48 +# define __SIZEOF_PTHREAD_CONDATTR_T 4 +# define __SIZEOF_PTHREAD_RWLOCK_T 56 +# define __SIZEOF_PTHREAD_RWLOCKATTR_T 8 +# define __SIZEOF_PTHREAD_BARRIER_T 32 +# define __SIZEOF_PTHREAD_BARRIERATTR_T 4 +#else +# define __SIZEOF_PTHREAD_ATTR_T 36 +# define __SIZEOF_PTHREAD_MUTEX_T 24 +# define __SIZEOF_PTHREAD_MUTEXATTR_T 4 +# define __SIZEOF_PTHREAD_COND_T 48 +# define __SIZEOF_PTHREAD_CONDATTR_T 4 +# define __SIZEOF_PTHREAD_RWLOCK_T 32 +# define __SIZEOF_PTHREAD_RWLOCKATTR_T 8 +# define __SIZEOF_PTHREAD_BARRIER_T 20 +# define __SIZEOF_PTHREAD_BARRIERATTR_T 4 +#endif + + +/* Thread identifiers. The structure of the attribute type is + deliberately not exposed. */ +typedef unsigned long int pthread_t; + + +typedef union +{ + char __size[__SIZEOF_PTHREAD_ATTR_T]; + long int __align; +} pthread_attr_t; + +#if _MIPS_SIM == _ABI64 +typedef struct __pthread_internal_list +{ + struct __pthread_internal_list *__prev; + struct __pthread_internal_list *__next; +} __pthread_list_t; +#else +typedef struct __pthread_internal_slist +{ + struct __pthread_internal_slist *__next; +} __pthread_slist_t; +#endif + +/* Data structures for mutex handling. The structure of the attribute + type is deliberately not exposed. */ +typedef union +{ + struct __pthread_mutex_s + { + int __lock; + unsigned int __count; + int __owner; +#if _MIPS_SIM == _ABI64 + unsigned int __nusers; +#endif + /* KIND must stay at this position in the structure to maintain + binary compatibility. */ + int __kind; +#if _MIPS_SIM == _ABI64 + int __spins; + __pthread_list_t __list; +# define __PTHREAD_MUTEX_HAVE_PREV 1 +#else + unsigned int __nusers; + __extension__ union + { + int __spins; + __pthread_slist_t __list; + }; +#endif + } __data; + char __size[__SIZEOF_PTHREAD_MUTEX_T]; + long int __align; +} pthread_mutex_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_MUTEXATTR_T]; + int __align; +} pthread_mutexattr_t; + + +/* Data structure for conditional variable handling. The structure of + the attribute type is deliberately not exposed. */ +typedef union +{ + struct + { + int __lock; + unsigned int __futex; + __extension__ unsigned long long int __total_seq; + __extension__ unsigned long long int __wakeup_seq; + __extension__ unsigned long long int __woken_seq; + void *__mutex; + unsigned int __nwaiters; + unsigned int __broadcast_seq; + } __data; + char __size[__SIZEOF_PTHREAD_COND_T]; + __extension__ long long int __align; +} pthread_cond_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_CONDATTR_T]; + int __align; +} pthread_condattr_t; + + +/* Keys for thread-specific data */ +typedef unsigned int pthread_key_t; + + +/* Once-only execution */ +typedef int pthread_once_t; + + +#if defined __USE_UNIX98 || defined __USE_XOPEN2K +/* Data structure for read-write lock variable handling. The + structure of the attribute type is deliberately not exposed. */ +typedef union +{ +# if _MIPS_SIM == _ABI64 + struct + { + int __lock; + unsigned int __nr_readers; + unsigned int __readers_wakeup; + unsigned int __writer_wakeup; + unsigned int __nr_readers_queued; + unsigned int __nr_writers_queued; + int __writer; + int __pad1; + unsigned long int __pad2; + unsigned long int __pad3; + /* FLAGS must stay at this position in the structure to maintain + binary compatibility. */ + unsigned int __flags; + } __data; +# else + struct + { + int __lock; + unsigned int __nr_readers; + unsigned int __readers_wakeup; + unsigned int __writer_wakeup; + unsigned int __nr_readers_queued; + unsigned int __nr_writers_queued; + /* FLAGS must stay at this position in the structure to maintain + binary compatibility. */ + unsigned int __flags; + int __writer; + } __data; +# endif + char __size[__SIZEOF_PTHREAD_RWLOCK_T]; + long int __align; +} pthread_rwlock_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_RWLOCKATTR_T]; + long int __align; +} pthread_rwlockattr_t; +#endif + + +#ifdef __USE_XOPEN2K +/* POSIX spinlock data type. */ +typedef volatile int pthread_spinlock_t; + + +/* POSIX barriers data type. The structure of the type is + deliberately not exposed. */ +typedef union +{ + char __size[__SIZEOF_PTHREAD_BARRIER_T]; + long int __align; +} pthread_barrier_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_BARRIERATTR_T]; + int __align; +} pthread_barrierattr_t; +#endif + + +#endif /* bits/pthreadtypes.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/bits/semaphore.h b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/bits/semaphore.h new file mode 100644 index 000000000..c4440f9e9 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/bits/semaphore.h @@ -0,0 +1,40 @@ +/* Copyright (C) 2002, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _SEMAPHORE_H +# error "Never use <bits/semaphore.h> directly; include <semaphore.h> instead." +#endif + +#if _MIPS_SIM == _ABI64 +# define __SIZEOF_SEM_T 32 +#else +# define __SIZEOF_SEM_T 16 +#endif + +/* Value returned if `sem_open' failed. */ +#define SEM_FAILED ((sem_t *) 0) + +/* Maximum value the semaphore can have. */ +#define SEM_VALUE_MAX (2147483647) + + +typedef union +{ + char __size[__SIZEOF_SEM_T]; + long int __align; +} sem_t; diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/createthread.c b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/createthread.c new file mode 100644 index 000000000..d8a7c5539 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/createthread.c @@ -0,0 +1,24 @@ +/* Copyright (C) 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* Value passed to 'clone' for initialization of the thread register. */ +#define TLS_VALUE ((void *) (pd) \ + + TLS_TCB_OFFSET + TLS_PRE_TCB_SIZE) + +/* Get the real implementation. */ +#include <sysdeps/pthread/createthread.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/fork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/fork.c new file mode 100644 index 000000000..06b7e1c69 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/fork.c @@ -0,0 +1 @@ +#include "../i386/fork.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/lowlevellock.h b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/lowlevellock.h new file mode 100644 index 000000000..7edb28794 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/lowlevellock.h @@ -0,0 +1,216 @@ +/* Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _LOWLEVELLOCK_H +#define _LOWLEVELLOCK_H 1 + +#include <time.h> +#include <sys/param.h> +#include <bits/pthreadtypes.h> +#include <atomic.h> +#include <sysdep.h> + + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 +#define FUTEX_REQUEUE 3 +#define FUTEX_CMP_REQUEUE 4 + +/* Initializer for compatibility lock. */ +#define LLL_MUTEX_LOCK_INITIALIZER (0) + +#define lll_futex_wait(futexp, val) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + long int __ret; \ + __ret = INTERNAL_SYSCALL (futex, __err, 4, \ + (futexp), FUTEX_WAIT, (val), 0); \ + INTERNAL_SYSCALL_ERROR_P (__ret, __err) ? -__ret : __ret; \ + }) + +#define lll_futex_timed_wait(futexp, val, timespec) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + long int __ret; \ + __ret = INTERNAL_SYSCALL (futex, __err, 4, \ + (futexp), FUTEX_WAIT, (val), (timespec)); \ + INTERNAL_SYSCALL_ERROR_P (__ret, __err) ? -__ret : __ret; \ + }) + +#define lll_futex_wake(futexp, nr) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + long int __ret; \ + __ret = INTERNAL_SYSCALL (futex, __err, 4, \ + (futexp), FUTEX_WAKE, (nr), 0); \ + INTERNAL_SYSCALL_ERROR_P (__ret, __err) ? -__ret : __ret; \ + }) + +/* Returns non-zero if error happened, zero if success. */ +#define lll_futex_requeue(futexp, nr_wake, nr_move, mutex, val) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + long int __ret; \ + __ret = INTERNAL_SYSCALL (futex, __err, 6, \ + (futexp), FUTEX_CMP_REQUEUE, (nr_wake), \ + (nr_move), (mutex), (val)); \ + INTERNAL_SYSCALL_ERROR_P (__ret, __err); \ + }) + + +static inline int __attribute__((always_inline)) +__lll_mutex_trylock(int *futex) +{ + return atomic_compare_and_exchange_val_acq (futex, 1, 0) != 0; +} +#define lll_mutex_trylock(lock) __lll_mutex_trylock (&(lock)) + + +static inline int __attribute__((always_inline)) +__lll_mutex_cond_trylock(int *futex) +{ + return atomic_compare_and_exchange_val_acq (futex, 2, 0) != 0; +} +#define lll_mutex_cond_trylock(lock) __lll_mutex_cond_trylock (&(lock)) + + +extern void __lll_lock_wait (int *futex) attribute_hidden; + +static inline void __attribute__((always_inline)) +__lll_mutex_lock(int *futex) +{ + if (atomic_compare_and_exchange_bool_acq (futex, 1, 0) != 0) + __lll_lock_wait (futex); +} +#define lll_mutex_lock(futex) __lll_mutex_lock (&(futex)) + + +static inline void __attribute__ ((always_inline)) +__lll_mutex_cond_lock (int *futex) +{ + if (atomic_compare_and_exchange_bool_acq (futex, 2, 0) != 0) + __lll_lock_wait (futex); +} +#define lll_mutex_cond_lock(futex) __lll_mutex_cond_lock (&(futex)) + + +extern int __lll_timedlock_wait (int *futex, const struct timespec *) + attribute_hidden; + +static inline int __attribute__ ((always_inline)) +__lll_mutex_timedlock (int *futex, const struct timespec *abstime) +{ + int result = 0; + if (atomic_compare_and_exchange_bool_acq (futex, 1, 0) != 0) + result = __lll_timedlock_wait (futex, abstime); + return result; +} +#define lll_mutex_timedlock(futex, abstime) \ + __lll_mutex_timedlock (&(futex), abstime) + + +static inline void __attribute__ ((always_inline)) +__lll_mutex_unlock (int *futex) +{ + int val = atomic_exchange_rel (futex, 0); + if (__builtin_expect (val > 1, 0)) + lll_futex_wake (futex, 1); +} +#define lll_mutex_unlock(futex) __lll_mutex_unlock(&(futex)) + + +static inline void __attribute__ ((always_inline)) +__lll_mutex_unlock_force (int *futex) +{ + (void) atomic_exchange_rel (futex, 0); + lll_futex_wake (futex, 1); +} +#define lll_mutex_unlock_force(futex) __lll_mutex_unlock_force(&(futex)) + + +#define lll_mutex_islocked(futex) \ + (futex != 0) + + +/* Our internal lock implementation is identical to the binary-compatible + mutex implementation. */ + +/* Type for lock object. */ +typedef int lll_lock_t; + +/* Initializers for lock. */ +#define LLL_LOCK_INITIALIZER (0) +#define LLL_LOCK_INITIALIZER_LOCKED (1) + +extern int lll_unlock_wake_cb (int *__futex) attribute_hidden; + +/* The states of a lock are: + 0 - untaken + 1 - taken by one user + >1 - taken by more users */ + +#define lll_trylock(lock) lll_mutex_trylock (lock) +#define lll_lock(lock) lll_mutex_lock (lock) +#define lll_unlock(lock) lll_mutex_unlock (lock) +#define lll_islocked(lock) lll_mutex_islocked (lock) + +/* The kernel notifies a process which uses CLONE_CLEARTID via futex + wakeup when the clone terminates. The memory location contains the + thread ID while the clone is running and is reset to zero + afterwards. */ +#define lll_wait_tid(tid) \ + do { \ + __typeof (tid) __tid; \ + while ((__tid = (tid)) != 0) \ + lll_futex_wait (&(tid), __tid); \ + } while (0) + +extern int __lll_timedwait_tid (int *, const struct timespec *) + attribute_hidden; + +#define lll_timedwait_tid(tid, abstime) \ + ({ \ + int __res = 0; \ + if ((tid) != 0) \ + __res = __lll_timedwait_tid (&(tid), (abstime)); \ + __res; \ + }) + + +/* Conditional variable handling. */ + +extern void __lll_cond_wait (pthread_cond_t *cond) + attribute_hidden; +extern int __lll_cond_timedwait (pthread_cond_t *cond, + const struct timespec *abstime) + attribute_hidden; +extern void __lll_cond_wake (pthread_cond_t *cond) + attribute_hidden; +extern void __lll_cond_broadcast (pthread_cond_t *cond) + attribute_hidden; + +#define lll_cond_wait(cond) \ + __lll_cond_wait (cond) +#define lll_cond_timedwait(cond, abstime) \ + __lll_cond_timedwait (cond, abstime) +#define lll_cond_wake(cond) \ + __lll_cond_wake (cond) +#define lll_cond_broadcast(cond) \ + __lll_cond_broadcast (cond) + +#endif /* lowlevellock.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pt-__syscall_rt_sigaction.c b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pt-__syscall_rt_sigaction.c new file mode 100644 index 000000000..50137c84a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pt-__syscall_rt_sigaction.c @@ -0,0 +1 @@ +#include <../../../../../../../libc/sysdeps/linux/common/__syscall_rt_sigaction.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pt-clone.S b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pt-clone.S new file mode 100644 index 000000000..add405523 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pt-clone.S @@ -0,0 +1,2 @@ +#define RESET_PID +#include <../../../../../../../libc/sysdeps/linux/mips/clone.S> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pt-vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pt-vfork.S new file mode 100644 index 000000000..c02ffca93 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pt-vfork.S @@ -0,0 +1,38 @@ +/* Copyright (C) 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <features.h> +#include <tls.h> + +/* Save the PID value. */ +#define SAVE_PID \ + READ_THREAD_POINTER(v1); /* Get the thread pointer. */ \ + lw a2, PID_OFFSET(v1); /* Load the saved PID. */ \ + subu a2, $0, a2; /* Negate it. */ \ + sw a2, PID_OFFSET(v1); /* Store the temporary PID. */ + +/* Restore the old PID value in the parent. */ +#define RESTORE_PID \ + beqz v0, 1f; /* If we are the parent... */ \ + READ_THREAD_POINTER(v1); /* Get the thread pointer. */ \ + lw a2, PID_OFFSET(v1); /* Load the saved PID. */ \ + subu a2, $0, a2; /* Re-negate it. */ \ + sw a2, PID_OFFSET(v1); /* Restore the PID. */ \ +1: + +#include <../../../../../../../libc/sysdeps/linux/mips/vfork.S> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pthread_once.c b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pthread_once.c new file mode 100644 index 000000000..649b752f5 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pthread_once.c @@ -0,0 +1,94 @@ +/* Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" +#include <lowlevellock.h> + + +unsigned long int __fork_generation attribute_hidden; + + +static void +clear_once_control (void *arg) +{ + pthread_once_t *once_control = (pthread_once_t *) arg; + + *once_control = 0; + lll_futex_wake (once_control, INT_MAX); +} + + +int +__pthread_once (once_control, init_routine) + pthread_once_t *once_control; + void (*init_routine) (void); +{ + while (1) + { + int oldval, val, newval; + + val = *once_control; + do + { + /* Check if the initialized has already been done. */ + if ((val & 2) != 0) + return 0; + + oldval = val; + newval = (oldval & 3) | __fork_generation | 1; + val = atomic_compare_and_exchange_val_acq (once_control, newval, + oldval); + } + while (__builtin_expect (val != oldval, 0)); + + /* Check if another thread already runs the initializer. */ + if ((oldval & 1) != 0) + { + /* Check whether the initializer execution was interrupted + by a fork. */ + if (((oldval ^ newval) & -4) == 0) + { + /* Same generation, some other thread was faster. Wait. */ + lll_futex_wait (once_control, newval); + continue; + } + } + + /* This thread is the first here. Do the initialization. + Register a cleanup handler so that in case the thread gets + interrupted the initialization can be restarted. */ + pthread_cleanup_push (clear_once_control, once_control); + + init_routine (); + + pthread_cleanup_pop (0); + + + /* Add one to *once_control. */ + atomic_increment (once_control); + + /* Wake up all other threads. */ + lll_futex_wake (once_control, INT_MAX); + break; + } + + return 0; +} +weak_alias (__pthread_once, pthread_once) +strong_alias (__pthread_once, __pthread_once_internal) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/sysdep-cancel.h new file mode 100644 index 000000000..5fee89235 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/sysdep-cancel.h @@ -0,0 +1,169 @@ +/* Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <tls.h> +#ifndef __ASSEMBLER__ +# include <pthreadP.h> +#endif + +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt + +#ifdef __PIC__ +# undef PSEUDO +# define PSEUDO(name, syscall_name, args) \ + .align 2; \ + L(pseudo_start): \ + cfi_startproc; \ + 99: la t9,__syscall_error; \ + jr t9; \ + .type __##syscall_name##_nocancel, @function; \ + .globl __##syscall_name##_nocancel; \ + __##syscall_name##_nocancel: \ + .set noreorder; \ + .cpload t9; \ + li v0, SYS_ify(syscall_name); \ + syscall; \ + .set reorder; \ + bne a3, zero, SYSCALL_ERROR_LABEL; \ + ret; \ + .size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel; \ + ENTRY (name) \ + .set noreorder; \ + .cpload t9; \ + .set reorder; \ + SINGLE_THREAD_P(v1); \ + bne zero, v1, L(pseudo_cancel); \ + .set noreorder; \ + li v0, SYS_ify(syscall_name); \ + syscall; \ + .set reorder; \ + bne a3, zero, SYSCALL_ERROR_LABEL; \ + ret; \ + L(pseudo_cancel): \ + SAVESTK_##args; \ + sw ra, 28(sp); \ + cfi_rel_offset (ra, 28); \ + sw gp, 32(sp); \ + cfi_rel_offset (gp, 32); \ + PUSHARGS_##args; /* save syscall args */ \ + CENABLE; \ + lw gp, 32(sp); \ + sw v0, 44(sp); /* save mask */ \ + POPARGS_##args; /* restore syscall args */ \ + .set noreorder; \ + li v0, SYS_ify (syscall_name); \ + syscall; \ + .set reorder; \ + sw v0, 36(sp); /* save syscall result */ \ + sw a3, 40(sp); /* save syscall error flag */ \ + lw a0, 44(sp); /* pass mask as arg1 */ \ + CDISABLE; \ + lw gp, 32(sp); \ + lw v0, 36(sp); /* restore syscall result */ \ + lw a3, 40(sp); /* restore syscall error flag */ \ + lw ra, 28(sp); /* restore return address */ \ + .set noreorder; \ + bne a3, zero, SYSCALL_ERROR_LABEL; \ + RESTORESTK; \ + L(pseudo_end): \ + .set reorder; + +# undef PSEUDO_END +# define PSEUDO_END(sym) cfi_endproc; .end sym; .size sym,.-sym + +#endif + +# define PUSHARGS_0 /* nothing to do */ +# define PUSHARGS_1 PUSHARGS_0 sw a0, 0(sp); cfi_rel_offset (a0, 0); +# define PUSHARGS_2 PUSHARGS_1 sw a1, 4(sp); cfi_rel_offset (a1, 4); +# define PUSHARGS_3 PUSHARGS_2 sw a2, 8(sp); cfi_rel_offset (a2, 8); +# define PUSHARGS_4 PUSHARGS_3 sw a3, 12(sp); cfi_rel_offset (a3, 12); +# define PUSHARGS_5 PUSHARGS_4 /* handled by SAVESTK_## */ +# define PUSHARGS_6 PUSHARGS_5 +# define PUSHARGS_7 PUSHARGS_6 + +# define POPARGS_0 /* nothing to do */ +# define POPARGS_1 POPARGS_0 lw a0, 0(sp); +# define POPARGS_2 POPARGS_1 lw a1, 4(sp); +# define POPARGS_3 POPARGS_2 lw a2, 8(sp); +# define POPARGS_4 POPARGS_3 lw a3, 12(sp); +# define POPARGS_5 POPARGS_4 /* args already in new stackframe */ +# define POPARGS_6 POPARGS_5 +# define POPARGS_7 POPARGS_6 + + +# define STKSPACE 48 +# define SAVESTK_0 subu sp, STKSPACE; cfi_adjust_cfa_offset(STKSPACE) +# define SAVESTK_1 SAVESTK_0 +# define SAVESTK_2 SAVESTK_1 +# define SAVESTK_3 SAVESTK_2 +# define SAVESTK_4 SAVESTK_3 +# define SAVESTK_5 lw t0, 16(sp); \ + SAVESTK_0; \ + sw t0, 16(sp) + +# define SAVESTK_6 lw t0, 16(sp); \ + lw t1, 20(sp); \ + SAVESTK_0; \ + sw t0, 16(sp); \ + sw t1, 20(sp) + +# define SAVESTK_7 lw t0, 16(sp); \ + lw t1, 20(sp); \ + lw t2, 24(sp); \ + SAVESTK_0; \ + sw t0, 16(sp); \ + sw t1, 20(sp); \ + sw t2, 24(sp) + +# define RESTORESTK addu sp, STKSPACE; cfi_adjust_cfa_offset(-STKSPACE) + + +/* We use jalr rather than jal. This means that the assembler will not + automatically restore $gp (in case libc has multiple GOTs) so we must + do it manually - which we have to do anyway since we don't use .cprestore. + It also shuts up the assembler warning about not using .cprestore. */ +# ifdef IS_IN_libpthread +# define CENABLE la t9, __pthread_enable_asynccancel; jalr t9; +# define CDISABLE la t9, __pthread_disable_asynccancel; jalr t9; +# elif defined IS_IN_librt +# define CENABLE la t9, __librt_enable_asynccancel; jalr t9; +# define CDISABLE la t9, __librt_disable_asynccancel; jalr t9; +# else +# define CENABLE la t9, __libc_enable_asynccancel; jalr t9; +# define CDISABLE la t9, __libc_disable_asynccancel; jalr t9; +# endif + +# ifndef __ASSEMBLER__ +# define SINGLE_THREAD_P \ + __builtin_expect (THREAD_GETMEM (THREAD_SELF, \ + header.multiple_threads) \ + == 0, 1) +# else +# define SINGLE_THREAD_P(reg) \ + READ_THREAD_POINTER(reg); \ + lw reg, MULTIPLE_THREADS_OFFSET(reg) +#endif + +#elif !defined __ASSEMBLER__ + +# define SINGLE_THREAD_P 1 +# define NO_CANCELLATION 1 + +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/sysdep.h b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/sysdep.h new file mode 100644 index 000000000..bfaab1f3a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/sysdep.h @@ -0,0 +1,302 @@ +/* Copyright (C) 2000, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _LINUX_MIPS_MIPS32_SYSDEP_H +#define _LINUX_MIPS_MIPS32_SYSDEP_H 1 + +#include <sys/syscall.h> + +/* There is some commonality. */ +#include <sysdeps/mips/sysdep.h> + +/* For Linux we can use the system call table in the header file + /usr/include/asm/unistd.h + of the kernel. But these symbols do not follow the SYS_* syntax + so we have to redefine the `SYS_ify' macro here. */ +#undef SYS_ify +#ifdef __STDC__ +# define SYS_ify(syscall_name) __NR_##syscall_name +#else +# define SYS_ify(syscall_name) __NR_/**/syscall_name +#endif + +#ifdef __ASSEMBLER__ + +/* We don't want the label for the error handler to be visible in the symbol + table when we define it here. */ +#ifdef __PIC__ +# define SYSCALL_ERROR_LABEL 99b +#endif + +#else /* ! __ASSEMBLER__ */ + +/* Define a macro which expands into the inline wrapper code for a system + call. */ +#undef INLINE_SYSCALL +#define INLINE_SYSCALL(name, nr, args...) \ + ({ INTERNAL_SYSCALL_DECL(err); \ + long result_var = INTERNAL_SYSCALL (name, err, nr, args); \ + if ( INTERNAL_SYSCALL_ERROR_P (result_var, err) ) \ + { \ + __set_errno (INTERNAL_SYSCALL_ERRNO (result_var, err)); \ + result_var = -1L; \ + } \ + result_var; }) + +#undef INTERNAL_SYSCALL_DECL +#define INTERNAL_SYSCALL_DECL(err) long err + +#undef INTERNAL_SYSCALL_ERROR_P +#define INTERNAL_SYSCALL_ERROR_P(val, err) ((long) (err)) + +#undef INTERNAL_SYSCALL_ERRNO +#define INTERNAL_SYSCALL_ERRNO(val, err) (val) + +#undef INTERNAL_SYSCALL +#define INTERNAL_SYSCALL(name, err, nr, args...) \ + internal_syscall##nr (, "li\t$2, %2\t\t\t# " #name "\n\t", \ + "i" (SYS_ify (name)), err, args) + +#undef INTERNAL_SYSCALL_NCS +#define INTERNAL_SYSCALL_NCS(number, err, nr, args...) \ + internal_syscall##nr (= number, , "r" (__v0), err, args) +#undef internal_syscall0 +#define internal_syscall0(ncs_init, cs_init, input, err, dummy...) \ +({ \ + long _sys_result; \ + \ + { \ + register long __v0 __asm__("$2") ncs_init; \ + register long __a3 __asm__("$7"); \ + __asm__ volatile ( \ + ".set\tnoreorder\n\t" \ + cs_init \ + "syscall\n\t" \ + ".set reorder" \ + : "=r" (__v0), "=r" (__a3) \ + : input \ + : __SYSCALL_CLOBBERS); \ + err = __a3; \ + _sys_result = __v0; \ + } \ + _sys_result; \ +}) + +#undef internal_syscall1 +#define internal_syscall1(ncs_init, cs_init, input, err, arg1) \ +({ \ + long _sys_result; \ + \ + { \ + register long __v0 __asm__("$2") ncs_init; \ + register long __a0 __asm__("$4") = (long) arg1; \ + register long __a3 __asm__("$7"); \ + __asm__ volatile ( \ + ".set\tnoreorder\n\t" \ + cs_init \ + "syscall\n\t" \ + ".set reorder" \ + : "=r" (__v0), "=r" (__a3) \ + : input, "r" (__a0) \ + : __SYSCALL_CLOBBERS); \ + err = __a3; \ + _sys_result = __v0; \ + } \ + _sys_result; \ +}) + +#undef internal_syscall2 +#define internal_syscall2(ncs_init, cs_init, input, err, arg1, arg2) \ +({ \ + long _sys_result; \ + \ + { \ + register long __v0 __asm__("$2") ncs_init; \ + register long __a0 __asm__("$4") = (long) arg1; \ + register long __a1 __asm__("$5") = (long) arg2; \ + register long __a3 __asm__("$7"); \ + __asm__ volatile ( \ + ".set\tnoreorder\n\t" \ + cs_init \ + "syscall\n\t" \ + ".set\treorder" \ + : "=r" (__v0), "=r" (__a3) \ + : input, "r" (__a0), "r" (__a1) \ + : __SYSCALL_CLOBBERS); \ + err = __a3; \ + _sys_result = __v0; \ + } \ + _sys_result; \ +}) + +#undef internal_syscall3 +#define internal_syscall3(ncs_init, cs_init, input, err, arg1, arg2, arg3)\ +({ \ + long _sys_result; \ + \ + { \ + register long __v0 __asm__("$2") ncs_init; \ + register long __a0 __asm__("$4") = (long) arg1; \ + register long __a1 __asm__("$5") = (long) arg2; \ + register long __a2 __asm__("$6") = (long) arg3; \ + register long __a3 __asm__("$7"); \ + __asm__ volatile ( \ + ".set\tnoreorder\n\t" \ + cs_init \ + "syscall\n\t" \ + ".set\treorder" \ + : "=r" (__v0), "=r" (__a3) \ + : input, "r" (__a0), "r" (__a1), "r" (__a2) \ + : __SYSCALL_CLOBBERS); \ + err = __a3; \ + _sys_result = __v0; \ + } \ + _sys_result; \ +}) + +#undef internal_syscall4 +#define internal_syscall4(ncs_init, cs_init, input, err, arg1, arg2, arg3, arg4)\ +({ \ + long _sys_result; \ + \ + { \ + register long __v0 __asm__("$2") ncs_init; \ + register long __a0 __asm__("$4") = (long) arg1; \ + register long __a1 __asm__("$5") = (long) arg2; \ + register long __a2 __asm__("$6") = (long) arg3; \ + register long __a3 __asm__("$7") = (long) arg4; \ + __asm__ volatile ( \ + ".set\tnoreorder\n\t" \ + cs_init \ + "syscall\n\t" \ + ".set\treorder" \ + : "=r" (__v0), "+r" (__a3) \ + : input, "r" (__a0), "r" (__a1), "r" (__a2) \ + : __SYSCALL_CLOBBERS); \ + err = __a3; \ + _sys_result = __v0; \ + } \ + _sys_result; \ +}) + +/* We need to use a frame pointer for the functions in which we + adjust $sp around the syscall, or debug information and unwind + information will be $sp relative and thus wrong during the syscall. As + of GCC 3.4.3, this is sufficient. */ +#define FORCE_FRAME_POINTER alloca (4) + +#undef internal_syscall5 +#define internal_syscall5(ncs_init, cs_init, input, err, arg1, arg2, arg3, arg4, arg5)\ +({ \ + long _sys_result; \ + \ + FORCE_FRAME_POINTER; \ + { \ + register long __v0 __asm__("$2") ncs_init; \ + register long __a0 __asm__("$4") = (long) arg1; \ + register long __a1 __asm__("$5") = (long) arg2; \ + register long __a2 __asm__("$6") = (long) arg3; \ + register long __a3 __asm__("$7") = (long) arg4; \ + __asm__ volatile ( \ + ".set\tnoreorder\n\t" \ + "subu\t$29, 32\n\t" \ + "sw\t%6, 16($29)\n\t" \ + cs_init \ + "syscall\n\t" \ + "addiu\t$29, 32\n\t" \ + ".set\treorder" \ + : "=r" (__v0), "+r" (__a3) \ + : input, "r" (__a0), "r" (__a1), "r" (__a2), \ + "r" ((long)arg5) \ + : __SYSCALL_CLOBBERS); \ + err = __a3; \ + _sys_result = __v0; \ + } \ + _sys_result; \ +}) + +#undef internal_syscall6 +#define internal_syscall6(ncs_init, cs_init, input, err, arg1, arg2, arg3, arg4, arg5, arg6)\ +({ \ + long _sys_result; \ + \ + FORCE_FRAME_POINTER; \ + { \ + register long __v0 __asm__("$2") ncs_init; \ + register long __a0 __asm__("$4") = (long) arg1; \ + register long __a1 __asm__("$5") = (long) arg2; \ + register long __a2 __asm__("$6") = (long) arg3; \ + register long __a3 __asm__("$7") = (long) arg4; \ + __asm__ volatile ( \ + ".set\tnoreorder\n\t" \ + "subu\t$29, 32\n\t" \ + "sw\t%6, 16($29)\n\t" \ + "sw\t%7, 20($29)\n\t" \ + cs_init \ + "syscall\n\t" \ + "addiu\t$29, 32\n\t" \ + ".set\treorder" \ + : "=r" (__v0), "+r" (__a3) \ + : input, "r" (__a0), "r" (__a1), "r" (__a2), \ + "r" ((long)arg5), "r" ((long)arg6) \ + : __SYSCALL_CLOBBERS); \ + err = __a3; \ + _sys_result = __v0; \ + } \ + _sys_result; \ +}) + +#undef internal_syscall7 +#define internal_syscall7(ncs_init, cs_init, input, err, arg1, arg2, arg3, arg4, arg5, arg6, arg7)\ +({ \ + long _sys_result; \ + \ + FORCE_FRAME_POINTER; \ + { \ + register long __v0 __asm__("$2") ncs_init; \ + register long __a0 __asm__("$4") = (long) arg1; \ + register long __a1 __asm__("$5") = (long) arg2; \ + register long __a2 __asm__("$6") = (long) arg3; \ + register long __a3 __asm__("$7") = (long) arg4; \ + __asm__ volatile ( \ + ".set\tnoreorder\n\t" \ + "subu\t$29, 32\n\t" \ + "sw\t%6, 16($29)\n\t" \ + "sw\t%7, 20($29)\n\t" \ + "sw\t%8, 24($29)\n\t" \ + cs_init \ + "syscall\n\t" \ + "addiu\t$29, 32\n\t" \ + ".set\treorder" \ + : "=r" (__v0), "+r" (__a3) \ + : input, "r" (__a0), "r" (__a1), "r" (__a2), \ + "r" ((long)arg5), "r" ((long)arg6), "r" ((long)arg7) \ + : __SYSCALL_CLOBBERS); \ + err = __a3; \ + _sys_result = __v0; \ + } \ + _sys_result; \ +}) + +#undef __SYSCALL_CLOBBERS +#define __SYSCALL_CLOBBERS "$1", "$3", "$8", "$9", "$10", "$11", "$12", "$13", \ + "$14", "$15", "$24", "$25", "memory" + +#endif /* __ASSEMBLER__ */ + +#endif /* sysdeps/unix/sysv/linux/mips/sysdep.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mq_notify.c b/libpthread/nptl/sysdeps/unix/sysv/linux/mq_notify.c new file mode 100644 index 000000000..9d16fee56 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mq_notify.c @@ -0,0 +1,285 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contribute by Ulrich Drepper <drepper@redhat.com>, 2004. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include <errno.h> +#include <fcntl.h> +#include <mqueue.h> +#include <pthread.h> +#include <signal.h> +#include <stdlib.h> +#include <string.h> +#include <sysdep.h> +#include <unistd.h> +#include <sys/socket.h> +#include <not-cancel.h> + + +#ifdef __NR_mq_notify + +/* Defined in the kernel headers: */ +#define NOTIFY_COOKIE_LEN 32 /* Length of the cookie used. */ +#define NOTIFY_WOKENUP 1 /* Code for notifcation. */ +#define NOTIFY_REMOVED 2 /* Code for closed message queue + of de-notifcation. */ + + +/* Data structure for the queued notification requests. */ +union notify_data +{ + struct + { + void (*fct) (union sigval); /* The function to run. */ + union sigval param; /* The parameter to pass. */ + pthread_attr_t *attr; /* Attributes to create the thread with. */ + /* NB: on 64-bit machines the struct as a size of 24 bytes. Which means + byte 31 can still be used for returning the status. */ + }; + char raw[NOTIFY_COOKIE_LEN]; +}; + + +/* Keep track of the initialization. */ +static pthread_once_t once = PTHREAD_ONCE_INIT; + + +/* The netlink socket. */ +static int netlink_socket = -1; + + +/* Barrier used to make sure data passed to the new thread is not + resused by the parent. */ +static pthread_barrier_t notify_barrier; + + +/* Modify the signal mask. We move this into a separate function so + that the stack space needed for sigset_t is not deducted from what + the thread can use. */ +static int +__attribute__ ((noinline)) +change_sigmask (int how, sigset_t *oss) +{ + sigset_t ss; + sigfillset (&ss); + return pthread_sigmask (how, &ss, oss); +} + + +/* The function used for the notification. */ +static void * +notification_function (void *arg) +{ + /* Copy the function and parameter so that the parent thread can go + on with its life. */ + volatile union notify_data *data = (volatile union notify_data *) arg; + void (*fct) (union sigval) = data->fct; + union sigval param = data->param; + + /* Let the parent go. */ + (void) pthread_barrier_wait (¬ify_barrier); + + /* Make the thread detached. */ + (void) pthread_detach (pthread_self ()); + + /* The parent thread has all signals blocked. This is probably a + bit surprising for this thread. So we unblock all of them. */ + (void) change_sigmask (SIG_UNBLOCK, NULL); + + /* Now run the user code. */ + fct (param); + + /* And we are done. */ + return NULL; +} + + +/* Helper thread. */ +static void * +helper_thread (void *arg) +{ + while (1) + { + union notify_data data; + + ssize_t n = recv (netlink_socket, &data, sizeof (data), + MSG_NOSIGNAL | MSG_WAITALL); + if (n < NOTIFY_COOKIE_LEN) + continue; + + if (data.raw[NOTIFY_COOKIE_LEN - 1] == NOTIFY_WOKENUP) + { + /* Just create the thread as instructed. There is no way to + report a problem with creating a thread. */ + pthread_t th; + if (__builtin_expect (pthread_create (&th, data.attr, + notification_function, &data) + == 0, 0)) + /* Since we passed a pointer to DATA to the new thread we have + to wait until it is done with it. */ + (void) pthread_barrier_wait (¬ify_barrier); + } + else if (data.raw[NOTIFY_COOKIE_LEN - 1] == NOTIFY_REMOVED) + /* The only state we keep is the copy of the thread attributes. */ + free (data.attr); + } + return NULL; +} + + +static void +reset_once (void) +{ + once = PTHREAD_ONCE_INIT; +} + + +static void +init_mq_netlink (void) +{ + /* This code might be called a second time after fork(). The file + descriptor is inherited from the parent. */ + if (netlink_socket == -1) + { + /* Just a normal netlink socket, not bound. */ + netlink_socket = socket (AF_NETLINK, SOCK_RAW, 0); + /* No need to do more if we have no socket. */ + if (netlink_socket == -1) + return; + + /* Make sure the descriptor is closed on exec. */ + if (fcntl (netlink_socket, F_SETFD, FD_CLOEXEC) != 0) + goto errout; + } + + int err = 1; + + /* Initialize the barrier. */ + if (__builtin_expect (pthread_barrier_init (¬ify_barrier, NULL, 2) == 0, + 0)) + { + /* Create the helper thread. */ + pthread_attr_t attr; + (void) pthread_attr_init (&attr); + (void) pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); + /* We do not need much stack space, the bare minimum will be enough. */ + (void) pthread_attr_setstacksize (&attr, PTHREAD_STACK_MIN); + + /* Temporarily block all signals so that the newly created + thread inherits the mask. */ + sigset_t oss; + int have_no_oss = change_sigmask (SIG_BLOCK, &oss); + + pthread_t th; + err = pthread_create (&th, &attr, helper_thread, NULL); + + /* Reset the signal mask. */ + if (!have_no_oss) + pthread_sigmask (SIG_SETMASK, &oss, NULL); + + (void) pthread_attr_destroy (&attr); + + if (err == 0) + { + static int added_atfork; + + if (added_atfork == 0 + && pthread_atfork (NULL, NULL, reset_once) != 0) + { + /* The child thread will call recv() which is a + cancellation point. */ + (void) pthread_cancel (th); + err = 1; + } + else + added_atfork = 1; + } + } + + if (err != 0) + { + errout: + close_not_cancel_no_status (netlink_socket); + netlink_socket = -1; + } +} + + +/* Register notification upon message arrival to an empty message queue + MQDES. */ +int +mq_notify (mqd_t mqdes, const struct sigevent *notification) +{ + /* Make sure the type is correctly defined. */ + assert (sizeof (union notify_data) == NOTIFY_COOKIE_LEN); + + /* Special treatment needed for SIGEV_THREAD. */ + if (notification == NULL || notification->sigev_notify != SIGEV_THREAD) + return INLINE_SYSCALL (mq_notify, 2, mqdes, notification); + + /* The kernel cannot directly start threads. This will have to be + done at userlevel. Since we cannot start threads from signal + handlers we have to create a dedicated thread which waits for + notifications for arriving messages and creates threads in + response. */ + + /* Initialize only once. */ + pthread_once (&once, init_mq_netlink); + + /* If we cannot create the netlink socket we cannot provide + SIGEV_THREAD support. */ + if (__builtin_expect (netlink_socket == -1, 0)) + { + __set_errno (ENOSYS); + return -1; + } + + /* Create the cookie. It will hold almost all the state. */ + union notify_data data; + memset (&data, '\0', sizeof (data)); + data.fct = notification->sigev_notify_function; + data.param = notification->sigev_value; + + if (notification->sigev_notify_attributes != NULL) + { + /* The thread attribute has to be allocated separately. */ + data.attr = (pthread_attr_t *) malloc (sizeof (pthread_attr_t)); + if (data.attr == NULL) + return -1; + + memcpy (data.attr, notification->sigev_notify_attributes, + sizeof (pthread_attr_t)); + } + + /* Construct the new request. */ + struct sigevent se; + se.sigev_notify = SIGEV_THREAD; + se.sigev_signo = netlink_socket; + se.sigev_value.sival_ptr = &data; + + /* Tell the kernel. */ + int retval = INLINE_SYSCALL (mq_notify, 2, mqdes, &se); + + /* If it failed, free the allocated memory. */ + if (__builtin_expect (retval != 0, 0)) + free (data.attr); + + return retval; +} + +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/msync.S b/libpthread/nptl/sysdeps/unix/sysv/linux/msync.S new file mode 100644 index 000000000..074a0d717 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/msync.S @@ -0,0 +1,7 @@ +#include <sysdep-cancel.h> +PSEUDO (__libc_msync, msync, 3) +ret +PSEUDO_END(__libc_msync) +libc_hidden_def (__libc_msync) +weak_alias (__libc_msync, msync) +libc_hidden_weak (msync) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/nanosleep.S b/libpthread/nptl/sysdeps/unix/sysv/linux/nanosleep.S new file mode 100644 index 000000000..71efe32f9 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/nanosleep.S @@ -0,0 +1,9 @@ +#include <sysdep-cancel.h> +PSEUDO (__libc_nanosleep, nanosleep, 3) +ret +PSEUDO_END (__libc_nanosleep) +libc_hidden_def (__libc_nanosleep) +weak_alias (__libc_nanosleep, __nanosleep) +libc_hidden_weak (__nanosleep) +weak_alias (__libc_nanosleep, nanosleep) +libc_hidden_weak (nanosleep) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/not-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/not-cancel.h new file mode 100644 index 000000000..9418417b4 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/not-cancel.h @@ -0,0 +1,60 @@ +/* Uncancelable versions of cancelable interfaces. Linux version. + Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> + +/* Uncancelable open. */ +#define open_not_cancel(name, flags, mode) \ + INLINE_SYSCALL (open, 3, (const char *) (name), (flags), (mode)) +#define open_not_cancel_2(name, flags) \ + INLINE_SYSCALL (open, 2, (const char *) (name), (flags)) + +/* Uncancelable close. */ +#define close_not_cancel(fd) \ + INLINE_SYSCALL (close, 1, fd) +#define close_not_cancel_no_status(fd) \ + (void) ({ INTERNAL_SYSCALL_DECL (err); \ + INTERNAL_SYSCALL (close, err, 1, (fd)); }) + +/* Uncancelable read. */ +#define read_not_cancel(fd, buf, n) \ + INLINE_SYSCALL (read, 3, (fd), (buf), (n)) + +/* Uncancelable write. */ +#define write_not_cancel(fd, buf, n) \ + INLINE_SYSCALL (write, 3, (fd), (buf), (n)) + +/* Uncancelable writev. */ +#define writev_not_cancel_no_status(fd, iov, n) \ + (void) ({ INTERNAL_SYSCALL_DECL (err); \ + INTERNAL_SYSCALL (writev, err, 3, (fd), (iov), (n)); }) + +/* Uncancelable fcntl. */ +#define fcntl_not_cancel(fd, cmd, val) \ + __fcntl_nocancel (fd, cmd, val) + +/* Uncancelable waitpid. */ +#ifdef __NR_waitpid +# define waitpid_not_cancel(pid, stat_loc, options) \ + INLINE_SYSCALL (waitpid, 3, pid, stat_loc, options) +#else +# define waitpid_not_cancel(pid, stat_loc, options) \ + INLINE_SYSCALL (wait4, 4, pid, stat_loc, options, NULL) +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/open.S b/libpthread/nptl/sysdeps/unix/sysv/linux/open.S new file mode 100644 index 000000000..486686a22 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/open.S @@ -0,0 +1,21 @@ +#include <sysdep-cancel.h> + +/* +extern int __open_nocancel (const char *, int, ...) attribute_hidden; +*/ +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt + +PSEUDO (__libc_open, open, 3) +ret +PSEUDO_END(__libc_open) + +libc_hidden_def (__open_nocancel) +libc_hidden_def (__libc_open) +weak_alias (__libc_open, __open) +libc_hidden_weak (__open) +weak_alias (__libc_open, open) +libc_hidden_weak (open) + + + +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pause.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pause.S new file mode 100644 index 000000000..3841018a8 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pause.S @@ -0,0 +1,7 @@ +#include <sysdep-cancel.h> +PSEUDO (__libc_pause, pause, 0) +ret +PSEUDO_END (__libc_pause) +libc_hidden_def (__libc_pause) +weak_alias (__libc_pause, pause) +libc_hidden_weak (pause) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/Makefile b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/Makefile new file mode 100644 index 000000000..e98c9bd86 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/Makefile @@ -0,0 +1,2 @@ +# pull in __syscall_error routine +libpthread-routines += sysdep diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/Versions b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/Versions new file mode 100644 index 000000000..997784798 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/Versions @@ -0,0 +1,5 @@ +libpthread { + GLIBC_2.3.4 { + longjmp; siglongjmp; + } +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h new file mode 100644 index 000000000..c94ed0c38 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h @@ -0,0 +1,216 @@ +/* Machine-specific pthread type layouts. PowerPC version. + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _BITS_PTHREADTYPES_H +#define _BITS_PTHREADTYPES_H 1 + +#include <bits/wordsize.h> + +#if __WORDSIZE == 64 +# define __SIZEOF_PTHREAD_ATTR_T 56 +# define __SIZEOF_PTHREAD_MUTEX_T 40 +# define __SIZEOF_PTHREAD_MUTEXATTR_T 4 +# define __SIZEOF_PTHREAD_COND_T 48 +# define __SIZEOF_PTHREAD_CONDATTR_T 4 +# define __SIZEOF_PTHREAD_RWLOCK_T 56 +# define __SIZEOF_PTHREAD_RWLOCKATTR_T 8 +# define __SIZEOF_PTHREAD_BARRIER_T 32 +# define __SIZEOF_PTHREAD_BARRIERATTR_T 4 +#else +# define __SIZEOF_PTHREAD_ATTR_T 36 +# define __SIZEOF_PTHREAD_MUTEX_T 24 +# define __SIZEOF_PTHREAD_MUTEXATTR_T 4 +# define __SIZEOF_PTHREAD_COND_T 48 +# define __SIZEOF_PTHREAD_CONDATTR_T 4 +# define __SIZEOF_PTHREAD_RWLOCK_T 32 +# define __SIZEOF_PTHREAD_RWLOCKATTR_T 8 +# define __SIZEOF_PTHREAD_BARRIER_T 20 +# define __SIZEOF_PTHREAD_BARRIERATTR_T 4 +#endif + + +/* Thread identifiers. The structure of the attribute type is + deliberately not exposed. */ +typedef unsigned long int pthread_t; + + +typedef union +{ + char __size[__SIZEOF_PTHREAD_ATTR_T]; + long int __align; +} pthread_attr_t; + +#if __WORDSIZE == 64 +typedef struct __pthread_internal_list +{ + struct __pthread_internal_list *__prev; + struct __pthread_internal_list *__next; +} __pthread_list_t; +#else +typedef struct __pthread_internal_slist +{ + struct __pthread_internal_slist *__next; +} __pthread_slist_t; +#endif + +/* Data structures for mutex handling. The structure of the attribute + type is deliberately not exposed. */ +typedef union +{ + struct __pthread_mutex_s + { + int __lock; + unsigned int __count; + int __owner; +#if __WORDSIZE == 64 + unsigned int __nusers; +#endif + /* KIND must stay at this position in the structure to maintain + binary compatibility. */ + int __kind; +#if __WORDSIZE == 64 + int __spins; + __pthread_list_t __list; +# define __PTHREAD_MUTEX_HAVE_PREV 1 +#else + unsigned int __nusers; + __extension__ union + { + int __spins; + __pthread_slist_t __list; + }; +#endif + } __data; + char __size[__SIZEOF_PTHREAD_MUTEX_T]; + long int __align; +} pthread_mutex_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_MUTEXATTR_T]; + int __align; +} pthread_mutexattr_t; + + +/* Data structure for conditional variable handling. The structure of + the attribute type is deliberately not exposed. */ +typedef union +{ + struct + { + int __lock; + unsigned int __futex; + __extension__ unsigned long long int __total_seq; + __extension__ unsigned long long int __wakeup_seq; + __extension__ unsigned long long int __woken_seq; + void *__mutex; + unsigned int __nwaiters; + unsigned int __broadcast_seq; + } __data; + char __size[__SIZEOF_PTHREAD_COND_T]; + __extension__ long long int __align; +} pthread_cond_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_CONDATTR_T]; + int __align; +} pthread_condattr_t; + + +/* Keys for thread-specific data */ +typedef unsigned int pthread_key_t; + + +/* Once-only execution */ +typedef int pthread_once_t; + + +#if defined __USE_UNIX98 || defined __USE_XOPEN2K +/* Data structure for read-write lock variable handling. The + structure of the attribute type is deliberately not exposed. */ +typedef union +{ +# if __WORDSIZE == 64 + struct + { + int __lock; + unsigned int __nr_readers; + unsigned int __readers_wakeup; + unsigned int __writer_wakeup; + unsigned int __nr_readers_queued; + unsigned int __nr_writers_queued; + int __writer; + int __pad1; + unsigned long int __pad2; + unsigned long int __pad3; + /* FLAGS must stay at this position in the structure to maintain + binary compatibility. */ + unsigned int __flags; + } __data; +# else + struct + { + int __lock; + unsigned int __nr_readers; + unsigned int __readers_wakeup; + unsigned int __writer_wakeup; + unsigned int __nr_readers_queued; + unsigned int __nr_writers_queued; + /* FLAGS must stay at this position in the structure to maintain + binary compatibility. */ + unsigned int __flags; + int __writer; + } __data; +# endif + char __size[__SIZEOF_PTHREAD_RWLOCK_T]; + long int __align; +} pthread_rwlock_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_RWLOCKATTR_T]; + long int __align; +} pthread_rwlockattr_t; +#endif + + +#ifdef __USE_XOPEN2K +/* POSIX spinlock data type. */ +typedef volatile int pthread_spinlock_t; + + +/* POSIX barriers data type. The structure of the type is + deliberately not exposed. */ +typedef union +{ + char __size[__SIZEOF_PTHREAD_BARRIER_T]; + long int __align; +} pthread_barrier_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_BARRIERATTR_T]; + int __align; +} pthread_barrierattr_t; +#endif + + +#endif /* bits/pthreadtypes.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/bits/semaphore.h b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/bits/semaphore.h new file mode 100644 index 000000000..8123b418b --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/bits/semaphore.h @@ -0,0 +1,44 @@ +/* Machine-specific POSIX semaphore type layouts. PowerPC version. + Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _SEMAPHORE_H +# error "Never use <bits/semaphore.h> directly; include <semaphore.h> instead." +#endif + +#include <bits/wordsize.h> + +#if __WORDSIZE == 64 +# define __SIZEOF_SEM_T 32 +#else +# define __SIZEOF_SEM_T 16 +#endif + +/* Value returned if `sem_open' failed. */ +#define SEM_FAILED ((sem_t *) 0) + +/* Maximum value the semaphore can have. */ +#define SEM_VALUE_MAX (2147483647) + + +typedef union +{ + char __size[__SIZEOF_SEM_T]; + long int __align; +} sem_t; diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/createthread.c b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/createthread.c new file mode 100644 index 000000000..e811ad74e --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/createthread.c @@ -0,0 +1,25 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Paul Mackerras <paulus@au.ibm.com>. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* Value passed to 'clone' for initialization of the thread register. */ +#define TLS_VALUE ((void *) (pd) \ + + TLS_TCB_OFFSET + TLS_PRE_TCB_SIZE) + +/* Get the real implementation. */ +#include <nptl/sysdeps/pthread/createthread.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/fork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/fork.c new file mode 100644 index 000000000..06b7e1c69 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/fork.c @@ -0,0 +1 @@ +#include "../i386/fork.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/lowlevellock.h b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/lowlevellock.h new file mode 100644 index 000000000..1f2f481d6 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/lowlevellock.h @@ -0,0 +1,241 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _LOWLEVELLOCK_H +#define _LOWLEVELLOCK_H 1 + +#include <time.h> +#include <sys/param.h> +#include <bits/pthreadtypes.h> +#include <atomic.h> + + +#ifndef __NR_futex +# define __NR_futex 221 +#endif +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 +#define FUTEX_REQUEUE 3 +#define FUTEX_CMP_REQUEUE 4 + +/* Initializer for compatibility lock. */ +#define LLL_MUTEX_LOCK_INITIALIZER (0) + +#define lll_futex_wait(futexp, val) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + long int __ret; \ + \ + __ret = INTERNAL_SYSCALL (futex, __err, 4, \ + (futexp), FUTEX_WAIT, (val), 0); \ + INTERNAL_SYSCALL_ERROR_P (__ret, __err) ? -__ret : __ret; \ + }) + +#define lll_futex_timed_wait(futexp, val, timespec) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + long int __ret; \ + \ + __ret = INTERNAL_SYSCALL (futex, __err, 4, \ + (futexp), FUTEX_WAIT, (val), (timespec)); \ + INTERNAL_SYSCALL_ERROR_P (__ret, __err) ? -__ret : __ret; \ + }) + +#define lll_futex_wake(futexp, nr) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + long int __ret; \ + \ + __ret = INTERNAL_SYSCALL (futex, __err, 4, \ + (futexp), FUTEX_WAKE, (nr), 0); \ + INTERNAL_SYSCALL_ERROR_P (__ret, __err) ? -__ret : __ret; \ + }) + +/* Returns non-zero if error happened, zero if success. */ +#define lll_futex_requeue(futexp, nr_wake, nr_move, mutex, val) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + long int __ret; \ + \ + __ret = INTERNAL_SYSCALL (futex, __err, 6, \ + (futexp), FUTEX_CMP_REQUEUE, (nr_wake), \ + (nr_move), (mutex), (val)); \ + INTERNAL_SYSCALL_ERROR_P (__ret, __err); \ + }) + +#ifdef UP +# define __lll_acq_instr "" +# define __lll_rel_instr "" +#else +# define __lll_acq_instr "isync" +# define __lll_rel_instr "sync" +#endif + +/* Set *futex to 1 if it is 0, atomically. Returns the old value */ +#define __lll_trylock(futex) \ + ({ int __val; \ + __asm __volatile ("1: lwarx %0,0,%2\n" \ + " cmpwi 0,%0,0\n" \ + " bne 2f\n" \ + " stwcx. %3,0,%2\n" \ + " bne- 1b\n" \ + "2: " __lll_acq_instr \ + : "=&r" (__val), "=m" (*futex) \ + : "r" (futex), "r" (1), "m" (*futex) \ + : "cr0", "memory"); \ + __val; \ + }) + +#define lll_mutex_trylock(lock) __lll_trylock (&(lock)) + +/* Set *futex to 2 if it is 0, atomically. Returns the old value */ +#define __lll_cond_trylock(futex) \ + ({ int __val; \ + __asm __volatile ("1: lwarx %0,0,%2\n" \ + " cmpwi 0,%0,0\n" \ + " bne 2f\n" \ + " stwcx. %3,0,%2\n" \ + " bne- 1b\n" \ + "2: " __lll_acq_instr \ + : "=&r" (__val), "=m" (*futex) \ + : "r" (futex), "r" (2), "m" (*futex) \ + : "cr0", "memory"); \ + __val; \ + }) +#define lll_mutex_cond_trylock(lock) __lll_cond_trylock (&(lock)) + + +extern void __lll_lock_wait (int *futex) attribute_hidden; + +#define lll_mutex_lock(lock) \ + (void) ({ \ + int *__futex = &(lock); \ + if (__builtin_expect (atomic_compare_and_exchange_val_acq (__futex, 1, 0),\ + 0) != 0) \ + __lll_lock_wait (__futex); \ + }) + +#define lll_mutex_cond_lock(lock) \ + (void) ({ \ + int *__futex = &(lock); \ + if (__builtin_expect (atomic_compare_and_exchange_val_acq (__futex, 2, 0),\ + 0) != 0) \ + __lll_lock_wait (__futex); \ + }) + +extern int __lll_timedlock_wait + (int *futex, const struct timespec *) attribute_hidden; + +#define lll_mutex_timedlock(lock, abstime) \ + ({ \ + int *__futex = &(lock); \ + int __val = 0; \ + if (__builtin_expect (atomic_compare_and_exchange_val_acq (__futex, 1, 0),\ + 0) != 0) \ + __val = __lll_timedlock_wait (__futex, abstime); \ + __val; \ + }) + +#define lll_mutex_unlock(lock) \ + ((void) ({ \ + int *__futex = &(lock); \ + int __val = atomic_exchange_rel (__futex, 0); \ + if (__builtin_expect (__val > 1, 0)) \ + lll_futex_wake (__futex, 1); \ + })) + +#define lll_mutex_unlock_force(lock) \ + ((void) ({ \ + int *__futex = &(lock); \ + *__futex = 0; \ + __asm __volatile (__lll_rel_instr ::: "memory"); \ + lll_futex_wake (__futex, 1); \ + })) + +#define lll_mutex_islocked(futex) \ + (futex != 0) + + +/* Our internal lock implementation is identical to the binary-compatible + mutex implementation. */ + +/* Type for lock object. */ +typedef int lll_lock_t; + +/* Initializers for lock. */ +#define LLL_LOCK_INITIALIZER (0) +#define LLL_LOCK_INITIALIZER_LOCKED (1) + +extern int lll_unlock_wake_cb (int *__futex) attribute_hidden; + +/* The states of a lock are: + 0 - untaken + 1 - taken by one user + >1 - taken by more users */ + +#define lll_trylock(lock) lll_mutex_trylock (lock) +#define lll_lock(lock) lll_mutex_lock (lock) +#define lll_unlock(lock) lll_mutex_unlock (lock) +#define lll_islocked(lock) lll_mutex_islocked (lock) + +/* The kernel notifies a process which uses CLONE_CLEARTID via futex + wakeup when the clone terminates. The memory location contains the + thread ID while the clone is running and is reset to zero + afterwards. */ +#define lll_wait_tid(tid) \ + do { \ + __typeof (tid) __tid; \ + while ((__tid = (tid)) != 0) \ + lll_futex_wait (&(tid), __tid); \ + } while (0) + +extern int __lll_timedwait_tid (int *, const struct timespec *) + attribute_hidden; + +#define lll_timedwait_tid(tid, abstime) \ + ({ \ + int __res = 0; \ + if ((tid) != 0) \ + __res = __lll_timedwait_tid (&(tid), (abstime)); \ + __res; \ + }) + + +/* Conditional variable handling. */ + +extern void __lll_cond_wait (pthread_cond_t *cond) + attribute_hidden; +extern int __lll_cond_timedwait (pthread_cond_t *cond, + const struct timespec *abstime) + attribute_hidden; +extern void __lll_cond_wake (pthread_cond_t *cond) + attribute_hidden; +extern void __lll_cond_broadcast (pthread_cond_t *cond) + attribute_hidden; + +#define lll_cond_wait(cond) \ + __lll_cond_wait (cond) +#define lll_cond_timedwait(cond, abstime) \ + __lll_cond_timedwait (cond, abstime) +#define lll_cond_wake(cond) \ + __lll_cond_wake (cond) +#define lll_cond_broadcast(cond) \ + __lll_cond_broadcast (cond) + +#endif /* lowlevellock.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/not-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/not-cancel.h new file mode 100644 index 000000000..acf1a617e --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/not-cancel.h @@ -0,0 +1 @@ +#include "../i386/not-cancel.h" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc32/clone.S b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc32/clone.S new file mode 100644 index 000000000..e19579e84 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc32/clone.S @@ -0,0 +1,3 @@ +#define RESET_PID +#include <tcb-offsets.h> +#include <sysdeps/unix/sysv/linux/powerpc/powerpc32/clone.S> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc32/pt-vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc32/pt-vfork.S new file mode 100644 index 000000000..61651fd97 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc32/pt-vfork.S @@ -0,0 +1,49 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2004. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#define _ERRNO_H 1 +#include <bits/errno.h> +#include <bits/kernel-features.h> +#include <tcb-offsets.h> + +/* Clone the calling process, but without copying the whole address space. + The calling process is suspended until the new process exits or is + replaced by a call to `execve'. Return -1 for errors, 0 to the new process, + and the process ID of the new process to the old process. */ + +ENTRY (__vfork) + lwz 0,PID(2) + neg 0,0 + stw 0,PID(2) + + DO_CALL (SYS_ify (vfork)) + + cmpwi 1,3,0 + beqlr- 1 + + lwz 0,PID(2) + neg 0,0 + stw 0,PID(2) + + PSEUDO_RET + +PSEUDO_END (__vfork) + +weak_alias (__vfork, vfork) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h new file mode 100644 index 000000000..0e6225624 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h @@ -0,0 +1,132 @@ +/* Cancellable system call stubs. Linux/PowerPC version. + Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Franz Sirl <Franz.Sirl-kernel@lauterbach.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <tls.h> +#ifndef __ASSEMBLER__ +# include <nptl/pthreadP.h> +#endif + +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt + +# undef PSEUDO +# define PSEUDO(name, syscall_name, args) \ + .section ".text"; \ + ENTRY (name) \ + cfi_startproc; \ + SINGLE_THREAD_P; \ + bne- .Lpseudo_cancel; \ + .type __##syscall_name##_nocancel,@function; \ + .globl __##syscall_name##_nocancel; \ + __##syscall_name##_nocancel: \ + DO_CALL (SYS_ify (syscall_name)); \ + PSEUDO_RET; \ + .size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel; \ + .Lpseudo_cancel: \ + stwu 1,-48(1); \ + cfi_adjust_cfa_offset (48); \ + mflr 9; \ + stw 9,52(1); \ + cfi_offset (lr, 4); \ + CGOTSETUP; \ + DOCARGS_##args; /* save syscall args around CENABLE. */ \ + CENABLE; \ + stw 3,16(1); /* store CENABLE return value (MASK). */ \ + UNDOCARGS_##args; /* restore syscall args. */ \ + DO_CALL (SYS_ify (syscall_name)); \ + mfcr 0; /* save CR/R3 around CDISABLE. */ \ + stw 3,8(1); \ + stw 0,12(1); \ + lwz 3,16(1); /* pass MASK to CDISABLE. */ \ + CDISABLE; \ + lwz 4,52(1); \ + lwz 0,12(1); /* restore CR/R3. */ \ + lwz 3,8(1); \ + CGOTRESTORE; \ + mtlr 4; \ + mtcr 0; \ + addi 1,1,48; \ + cfi_endproc; + +# define DOCARGS_0 +# define UNDOCARGS_0 + +# define DOCARGS_1 stw 3,20(1); DOCARGS_0 +# define UNDOCARGS_1 lwz 3,20(1); UNDOCARGS_0 + +# define DOCARGS_2 stw 4,24(1); DOCARGS_1 +# define UNDOCARGS_2 lwz 4,24(1); UNDOCARGS_1 + +# define DOCARGS_3 stw 5,28(1); DOCARGS_2 +# define UNDOCARGS_3 lwz 5,28(1); UNDOCARGS_2 + +# define DOCARGS_4 stw 6,32(1); DOCARGS_3 +# define UNDOCARGS_4 lwz 6,32(1); UNDOCARGS_3 + +# define DOCARGS_5 stw 7,36(1); DOCARGS_4 +# define UNDOCARGS_5 lwz 7,36(1); UNDOCARGS_4 + +# define DOCARGS_6 stw 8,40(1); DOCARGS_5 +# define UNDOCARGS_6 lwz 8,40(1); UNDOCARGS_5 + +# define CGOTSETUP +# define CGOTRESTORE + +# ifdef IS_IN_libpthread +# define CENABLE bl __pthread_enable_asynccancel@local +# define CDISABLE bl __pthread_disable_asynccancel@local +# elif !defined NOT_IN_libc +# define CENABLE bl __libc_enable_asynccancel@local +# define CDISABLE bl __libc_disable_asynccancel@local +# elif defined IS_IN_librt +# define CENABLE bl JUMPTARGET(__librt_enable_asynccancel) +# define CDISABLE bl JUMPTARGET(__librt_disable_asynccancel) +# if defined HAVE_AS_REL16 && defined __PIC__ +# undef CGOTSETUP +# define CGOTSETUP \ + bcl 20,31,1f; \ + 1: stw 30,44(1); \ + mflr 30; \ + addis 30,30,_GLOBAL_OFFSET_TABLE-1b@ha; \ + addi 30,30,_GLOBAL_OFFSET_TABLE-1b@l +# undef CGOTRESTORE +# define CGOTRESTORE \ + lwz 30,44(1) +# endif +# else +# error Unsupported library +# endif + +# ifndef __ASSEMBLER__ +# define SINGLE_THREAD_P \ + __builtin_expect (THREAD_GETMEM (THREAD_SELF, \ + header.multiple_threads) == 0, 1) +# else +# define SINGLE_THREAD_P \ + lwz 10,MULTIPLE_THREADS_OFFSET(2); \ + cmpwi 10,0 +# endif + +#elif !defined __ASSEMBLER__ + +# define SINGLE_THREAD_P (1) +# define NO_CANCELLATION 1 + +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc32/vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc32/vfork.S new file mode 100644 index 000000000..b7e2cf6e7 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc32/vfork.S @@ -0,0 +1,57 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2004. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#define _ERRNO_H 1 +#include <bits/errno.h> +#include <bits/kernel-features.h> +#include <tcb-offsets.h> + +/* Clone the calling process, but without copying the whole address space. + The calling process is suspended until the new process exits or is + replaced by a call to `execve'. Return -1 for errors, 0 to the new process, + and the process ID of the new process to the old process. */ + +ENTRY (__vfork) + lwz 0,PID(2) + cmpwi 0,0,0 + neg 0,0 + bne- 0,1f + lis 0,0x8000 +1: stw 0,PID(2) + + DO_CALL (SYS_ify (vfork)) + + cmpwi 1,3,0 + beqlr- 1 + + lwz 0,PID(2) + /* Cannot use clrlwi. here, because cr0 needs to be preserved + until PSEUDO_RET. */ + clrlwi 4,0,1 + cmpwi 1,4,0 + beq- 1,1f + neg 4,0 +1: stw 4,PID(2) + + PSEUDO_RET + +PSEUDO_END (__vfork) +hidden_def (__vfork) +weak_alias (__vfork, vfork) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/Versions b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/Versions new file mode 100644 index 000000000..3b111ddb5 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/Versions @@ -0,0 +1,7 @@ +librt { + GLIBC_2.3.3 { + # Changed timer_t. + timer_create; timer_delete; timer_getoverrun; timer_gettime; + timer_settime; + } +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/clone.S b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/clone.S new file mode 100644 index 000000000..f87adf473 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/clone.S @@ -0,0 +1,3 @@ +#define RESET_PID +#include <tcb-offsets.h> +#include <sysdeps/unix/sysv/linux/powerpc/powerpc64/clone.S> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/pt-vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/pt-vfork.S new file mode 100644 index 000000000..e5b7b535c --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/pt-vfork.S @@ -0,0 +1,49 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2004. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#define _ERRNO_H 1 +#include <bits/errno.h> +#include <bits/kernel-features.h> +#include <tcb-offsets.h> + +/* Clone the calling process, but without copying the whole address space. + The calling process is suspended until the new process exits or is + replaced by a call to `execve'. Return -1 for errors, 0 to the new process, + and the process ID of the new process to the old process. */ + +ENTRY (__vfork) + lwz 0,PID(13) + neg 0,0 + stw 0,PID(13) + + DO_CALL (SYS_ify (vfork)) + + cmpwi 1,3,0 + beqlr- 1 + + lwz 0,PID(13) + neg 0,0 + stw 0,PID(13) + + PSEUDO_RET + +PSEUDO_END (__vfork) + +weak_alias (__vfork, vfork) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h new file mode 100644 index 000000000..226aaafdc --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h @@ -0,0 +1,121 @@ +/* Cancellable system call stubs. Linux/PowerPC64 version. + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Franz Sirl <Franz.Sirl-kernel@lauterbach.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <tls.h> +#ifndef __ASSEMBLER__ +# include <nptl/pthreadP.h> +#endif + +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt + +# ifdef HAVE_ASM_GLOBAL_DOT_NAME +# define DASHDASHPFX(str) .__##str +# else +# define DASHDASHPFX(str) __##str +# endif + +# undef PSEUDO +# define PSEUDO(name, syscall_name, args) \ + .section ".text"; \ + ENTRY (name) \ + cfi_startproc; \ + SINGLE_THREAD_P; \ + bne- .Lpseudo_cancel; \ + .type DASHDASHPFX(syscall_name##_nocancel),@function; \ + .globl DASHDASHPFX(syscall_name##_nocancel); \ + DASHDASHPFX(syscall_name##_nocancel): \ + DO_CALL (SYS_ify (syscall_name)); \ + PSEUDO_RET; \ + .size DASHDASHPFX(syscall_name##_nocancel),.-DASHDASHPFX(syscall_name##_nocancel); \ + .Lpseudo_cancel: \ + stdu 1,-128(1); \ + cfi_adjust_cfa_offset (128); \ + mflr 9; \ + std 9,128+16(1); \ + cfi_offset (lr, 16); \ + DOCARGS_##args; /* save syscall args around CENABLE. */ \ + CENABLE; \ + std 3,72(1); /* store CENABLE return value (MASK). */ \ + UNDOCARGS_##args; /* restore syscall args. */ \ + DO_CALL (SYS_ify (syscall_name)); \ + mfcr 0; /* save CR/R3 around CDISABLE. */ \ + std 3,64(1); \ + std 0,8(1); \ + ld 3,72(1); /* pass MASK to CDISABLE. */ \ + CDISABLE; \ + ld 9,128+16(1); \ + ld 0,8(1); /* restore CR/R3. */ \ + ld 3,64(1); \ + mtlr 9; \ + mtcr 0; \ + addi 1,1,128; \ + cfi_endproc; + +# define DOCARGS_0 +# define UNDOCARGS_0 + +# define DOCARGS_1 std 3,80(1); DOCARGS_0 +# define UNDOCARGS_1 ld 3,80(1); UNDOCARGS_0 + +# define DOCARGS_2 std 4,88(1); DOCARGS_1 +# define UNDOCARGS_2 ld 4,88(1); UNDOCARGS_1 + +# define DOCARGS_3 std 5,96(1); DOCARGS_2 +# define UNDOCARGS_3 ld 5,96(1); UNDOCARGS_2 + +# define DOCARGS_4 std 6,104(1); DOCARGS_3 +# define UNDOCARGS_4 ld 6,104(1); UNDOCARGS_3 + +# define DOCARGS_5 std 7,112(1); DOCARGS_4 +# define UNDOCARGS_5 ld 7,112(1); UNDOCARGS_4 + +# define DOCARGS_6 std 8,120(1); DOCARGS_5 +# define UNDOCARGS_6 ld 8,120(1); UNDOCARGS_5 + +# ifdef IS_IN_libpthread +# define CENABLE bl JUMPTARGET(__pthread_enable_asynccancel) +# define CDISABLE bl JUMPTARGET(__pthread_disable_asynccancel) +# elif !defined NOT_IN_libc +# define CENABLE bl JUMPTARGET(__libc_enable_asynccancel) +# define CDISABLE bl JUMPTARGET(__libc_disable_asynccancel) +# elif defined IS_IN_librt +# define CENABLE bl JUMPTARGET(__librt_enable_asynccancel) +# define CDISABLE bl JUMPTARGET(__librt_disable_asynccancel) +# else +# error Unsupported library +# endif + +# ifndef __ASSEMBLER__ +# define SINGLE_THREAD_P \ + __builtin_expect (THREAD_GETMEM (THREAD_SELF, \ + header.multiple_threads) == 0, 1) +# else +# define SINGLE_THREAD_P \ + lwz 10,MULTIPLE_THREADS_OFFSET(13); \ + cmpwi 10,0 +# endif + +#elif !defined __ASSEMBLER__ + +# define SINGLE_THREAD_P (1) +# define NO_CANCELLATION 1 + +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_create.c b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_create.c new file mode 100644 index 000000000..172223af3 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_create.c @@ -0,0 +1 @@ +#include "../x86_64/timer_create.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_delete.c b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_delete.c new file mode 100644 index 000000000..537516e0a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_delete.c @@ -0,0 +1 @@ +#include "../x86_64/timer_delete.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_getoverr.c b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_getoverr.c new file mode 100644 index 000000000..3f21a73c9 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_getoverr.c @@ -0,0 +1 @@ +#include "../x86_64/timer_getoverr.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_gettime.c b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_gettime.c new file mode 100644 index 000000000..a50143adc --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_gettime.c @@ -0,0 +1 @@ +#include "../x86_64/timer_gettime.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_settime.c b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_settime.c new file mode 100644 index 000000000..37baeffac --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_settime.c @@ -0,0 +1 @@ +#include "../x86_64/timer_settime.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/vfork.S new file mode 100644 index 000000000..018132136 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/vfork.S @@ -0,0 +1,55 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2004. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#define _ERRNO_H 1 +#include <bits/errno.h> +#include <bits/kernel-features.h> +#include <tcb-offsets.h> + +/* Clone the calling process, but without copying the whole address space. + The calling process is suspended until the new process exits or is + replaced by a call to `execve'. Return -1 for errors, 0 to the new process, + and the process ID of the new process to the old process. */ + +ENTRY (__vfork) + lwz 0,PID(13) + cmpwi 0,0,0 + neg 0,0 + bne- 0,1f + lis 0,0x8000 +1: stw 0,PID(13) + + DO_CALL (SYS_ify (vfork)) + + cmpwi 1,3,0 + beqlr- 1 + + lwz 0,PID(13) + clrlwi 4,0,1 + cmpwi 1,4,0 + beq- 1,1f + neg 4,0 +1: stw 4,PID(13) + + PSEUDO_RET + +PSEUDO_END (__vfork) +hidden_def (__vfork) +weak_alias (__vfork, vfork) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/pt-longjmp.c b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/pt-longjmp.c new file mode 100644 index 000000000..b6d6b3d55 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/pt-longjmp.c @@ -0,0 +1,37 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <setjmp.h> +#include <stdlib.h> +#include <bits/wordsize.h> +#include "pthreadP.h" + +void +__vmx_longjmp (jmp_buf env, int val) +{ + __libc_longjmp (env, val); +} + +void +__vmx_siglongjmp (jmp_buf env, int val) +{ + __libc_siglongjmp (env, val); +} +weak_alias(__vmx_longjmp, longjmp) +weak_alias(__vmx_siglongjmp, siglongjmp) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/pthread_once.c b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/pthread_once.c new file mode 100644 index 000000000..e1afff8a3 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/pthread_once.c @@ -0,0 +1,100 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" +#include <lowlevellock.h> + + +unsigned long int __fork_generation attribute_hidden; + + +static void +clear_once_control (void *arg) +{ + pthread_once_t *once_control = (pthread_once_t *) arg; + + *once_control = 0; + lll_futex_wake (once_control, INT_MAX); +} + + +int +__pthread_once (pthread_once_t *once_control, void (*init_routine) (void)) +{ + for (;;) + { + int oldval; + int newval; + int tmp; + + /* Pseudo code: + newval = __fork_generation | 1; + oldval = *once_control; + if ((oldval & 2) == 0) + *once_control = newval; + Do this atomically. + */ + newval = __fork_generation | 1; + __asm __volatile ("1: lwarx %0,0,%3\n" + " andi. %1,%0,2\n" + " bne 2f\n" + " stwcx. %4,0,%3\n" + " bne 1b\n" + "2: isync" + : "=&r" (oldval), "=&r" (tmp), "=m" (*once_control) + : "r" (once_control), "r" (newval), "m" (*once_control) + : "cr0"); + + /* Check if the initializer has already been done. */ + if ((oldval & 2) != 0) + return 0; + + /* Check if another thread already runs the initializer. */ + if ((oldval & 1) == 0) + break; + + /* Check whether the initializer execution was interrupted by a fork. */ + if (oldval != newval) + break; + + /* Same generation, some other thread was faster. Wait. */ + lll_futex_wait (once_control, oldval); + } + + + /* This thread is the first here. Do the initialization. + Register a cleanup handler so that in case the thread gets + interrupted the initialization can be restarted. */ + pthread_cleanup_push (clear_once_control, once_control); + + init_routine (); + + pthread_cleanup_pop (0); + + + /* Add one to *once_control to take the bottom 2 bits from 01 to 10. */ + atomic_increment (once_control); + + /* Wake up all other threads. */ + lll_futex_wake (once_control, INT_MAX); + + return 0; +} +weak_alias (__pthread_once, pthread_once) +strong_alias (__pthread_once, __pthread_once_internal) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/sem_post.c b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/sem_post.c new file mode 100644 index 000000000..06b3bd0ab --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/sem_post.c @@ -0,0 +1,42 @@ +/* sem_post -- post to a POSIX semaphore. Powerpc version. + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <internaltypes.h> +#include <semaphore.h> + +int +__new_sem_post (sem_t *sem) +{ + int *futex = (int *) sem; + + __asm __volatile (__lll_rel_instr ::: "memory"); + int nr = atomic_increment_val (futex); + int err = lll_futex_wake (futex, nr); + if (__builtin_expect (err, 0) < 0) + { + __set_errno (-err); + return -1; + } + return 0; +} +weak_alias(__new_sem_post, sem_post) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-accept.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-accept.S new file mode 100644 index 000000000..24062101d --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-accept.S @@ -0,0 +1,12 @@ +#include <sysdep-cancel.h> +#ifndef __NR_accept +#error Missing definition of NR_accept needed for cancellation. +#endif +PSEUDO (__libc_accept, accept, 3) +ret +PSEUDO_END(__libc_accept) +libpthread_hidden_def (__libc_accept) +weak_alias (__libc_accept, __accept) +libpthread_hidden_weak (__accept) +weak_alias (__libc_accept, accept) +libpthread_hidden_weak (accept) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-close.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-close.S new file mode 100644 index 000000000..ab32ca598 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-close.S @@ -0,0 +1,9 @@ +#include <sysdep-cancel.h> +PSEUDO (__libc_close, close, 1) +ret +PSEUDO_END (__libc_close) +libpthread_hidden_def (__libc_close) +weak_alias (__libc_close, __close) +libpthread_hidden_weak (__close) +weak_alias (__libc_close, close) +libpthread_hidden_weak (close) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-connect.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-connect.S new file mode 100644 index 000000000..b5124f8ec --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-connect.S @@ -0,0 +1,12 @@ +#include <sysdep-cancel.h> +#ifndef __NR_connect +#error Missing definition of NR_connect needed for cancellation. +#endif +PSEUDO (__libc_connect, connect, 3) +ret +PSEUDO_END(__libc_connect) +libpthread_hidden_def (__libc_connect) +weak_alias (__libc_connect, __connect) +libpthread_hidden_weak (__connect) +weak_alias (__libc_connect, connect) +libpthread_hidden_weak (connect) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-fcntl.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-fcntl.c new file mode 100644 index 000000000..0a8fd3cc2 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-fcntl.c @@ -0,0 +1 @@ +#include <../../../../../../libc/sysdeps/linux/common/__syscall_fcntl.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-fork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-fork.c new file mode 100644 index 000000000..3e1b70f86 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-fork.c @@ -0,0 +1,29 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <unistd.h> + +extern int __libc_fork (void); + +pid_t +__fork (void) +{ + return __libc_fork (); +} +strong_alias (__fork, fork) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-fsync.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-fsync.c new file mode 100644 index 000000000..6ec4821c7 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-fsync.c @@ -0,0 +1,2 @@ +#include <pthreadP.h> +#include <../../../../../../libc/sysdeps/linux/common/fsync.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-llseek.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-llseek.c new file mode 100644 index 000000000..1d0d57870 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-llseek.c @@ -0,0 +1,3 @@ +#include <pthreadP.h> +#define libc_hidden libpthread_hidden +#include <../../../../../../libc/sysdeps/linux/common/llseek.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-lseek.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-lseek.S new file mode 100644 index 000000000..4db71722a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-lseek.S @@ -0,0 +1,7 @@ +#include <sysdep-cancel.h> +PSEUDO (__libc_lseek, lseek, 3) +ret +PSEUDO_END (__libc_lseek) +libpthread_hidden_def (__libc_lseek) +weak_alias (__libc_lseek, lseek) +libpthread_hidden_weak (lseek) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-msgrcv.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-msgrcv.c new file mode 100644 index 000000000..3bb9d53df --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-msgrcv.c @@ -0,0 +1,2 @@ +#define L_msgrcv +#include <../../../../../../libc/misc/sysvipc/msgq.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-msgsnd.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-msgsnd.c new file mode 100644 index 000000000..1566f65f4 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-msgsnd.c @@ -0,0 +1,2 @@ +#define L_msgsnd +#include <../../../../../../libc/misc/sysvipc/msgq.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-msync.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-msync.S new file mode 100644 index 000000000..640270ad9 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-msync.S @@ -0,0 +1,7 @@ +#include <sysdep-cancel.h> +PSEUDO (__libc_msync, msync, 3) +ret +PSEUDO_END(__libc_msync) +libpthread_hidden_def (__libc_msync) +weak_alias (__libc_msync, msync) +libpthread_hidden_weak (msync) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-nanosleep.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-nanosleep.S new file mode 100644 index 000000000..08d8f0150 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-nanosleep.S @@ -0,0 +1,9 @@ +#include <sysdep-cancel.h> +PSEUDO (__libc_nanosleep, nanosleep, 3) +ret +PSEUDO_END (__libc_nanosleep) +libpthread_hidden_def (__libc_nanosleep) +weak_alias (__libc_nanosleep, __nanosleep) +libpthread_hidden_weak (__nanosleep) +weak_alias (__libc_nanosleep, nanosleep) +libpthread_hidden_weak (nanosleep) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-open.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-open.S new file mode 100644 index 000000000..39ed92cc7 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-open.S @@ -0,0 +1,9 @@ +#include <sysdep-cancel.h> +PSEUDO (__libc_open, open, 3) +ret +PSEUDO_END (__libc_open) +libpthread_hidden_def (__libc_open) +weak_alias (__libc_open, __open) +libpthread_hidden_weak (__open) +weak_alias (__libc_open, open) +libpthread_hidden_weak (open) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-open64.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-open64.c new file mode 100644 index 000000000..2029539a7 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-open64.c @@ -0,0 +1 @@ +#include <../../../../../../libc/sysdeps/linux/common/open64.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-pause.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-pause.S new file mode 100644 index 000000000..c6cb57180 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-pause.S @@ -0,0 +1,7 @@ +#include <sysdep-cancel.h> +PSEUDO (__libc_pause, pause, 0) +ret +PSEUDO_END (__libc_pause) +libpthread_hidden_def (__libc_pause) +weak_alias (__libc_pause, pause) +libpthread_hidden_weak (pause) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-pread_pwrite.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-pread_pwrite.c new file mode 100644 index 000000000..f32c0a670 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-pread_pwrite.c @@ -0,0 +1 @@ +#include "pread_write.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-raise.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-raise.c new file mode 100644 index 000000000..7bee29784 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-raise.c @@ -0,0 +1,53 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <signal.h> +#include <sysdep.h> +#include <tls.h> +#include <bits/kernel-features.h> + +extern __typeof(raise) __raise; +int __raise (int sig) +{ +#if __ASSUME_TGKILL || defined __NR_tgkill + /* raise is an async-safe function. It could be called while the + fork function temporarily invalidated the PID field. Adjust for + that. */ + pid_t pid = THREAD_GETMEM (THREAD_SELF, pid); + if (__builtin_expect (pid < 0, 0)) + pid = -pid; +#endif + +#if __ASSUME_TGKILL + return INLINE_SYSCALL (tgkill, 3, pid, THREAD_GETMEM (THREAD_SELF, tid), + sig); +#else +# ifdef __NR_tgkill + int res = INLINE_SYSCALL (tgkill, 3, pid, THREAD_GETMEM (THREAD_SELF, tid), + sig); + if (res != -1 || errno != ENOSYS) + return res; +# endif + return INLINE_SYSCALL (tkill, 2, THREAD_GETMEM (THREAD_SELF, tid), sig); +#endif +} +libc_hidden_proto(raise) +weak_alias(__raise, raise) +libc_hidden_weak(raise) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-read.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-read.S new file mode 100644 index 000000000..623ba27a8 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-read.S @@ -0,0 +1,9 @@ +#include <sysdep-cancel.h> +PSEUDO (__libc_read, read, 3) +ret +PSEUDO_END (__libc_read) +libpthread_hidden_def (__libc_read) +weak_alias (__libc_read, __read) +libpthread_hidden_weak (__read) +weak_alias (__libc_read, read) +libpthread_hidden_weak (read) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-recv.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-recv.S new file mode 100644 index 000000000..6d2e3c2d6 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-recv.S @@ -0,0 +1,12 @@ +#include <sysdep-cancel.h> +#ifndef __NR_recv +#error Missing definition of NR_recv needed for cancellation. +#endif +PSEUDO (__libc_recv, recv, 4) +ret +PSEUDO_END(__libc_recv) +libpthread_hidden_def (__libc_recv) +weak_alias (__libc_recv, __recv) +libpthread_hidden_weak (__recv) +weak_alias (__libc_recv, recv) +libpthread_hidden_weak (recv) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-recvfrom.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-recvfrom.S new file mode 100644 index 000000000..96aeeaa3d --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-recvfrom.S @@ -0,0 +1,12 @@ +#include <sysdep-cancel.h> +#ifndef __NR_recvfrom +#error Missing definition of NR_recvfrom needed for cancellation. +#endif +PSEUDO (__libc_recvfrom, recvfrom, 6) +ret +PSEUDO_END(__libc_recvfrom) +libpthread_hidden_def (__libc_recvfrom) +weak_alias (__libc_recvfrom, __recvfrom) +libpthread_hidden_weak (__recvfrom) +weak_alias (__libc_recvfrom, recvfrom) +libpthread_hidden_weak (recvfrom) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-recvmsg.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-recvmsg.S new file mode 100644 index 000000000..f7161e47c --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-recvmsg.S @@ -0,0 +1,12 @@ +#include <sysdep-cancel.h> +#ifndef __NR_recvmsg +#error Missing definition of NR_recvmsg needed for cancellation. +#endif +PSEUDO (__libc_recvmsg, recvmsg, 3) +ret +PSEUDO_END(__libc_recvmsg) +libpthread_hidden_def (__libc_recvmsg) +weak_alias (__libc_recvmsg, __recvmsg) +libpthread_hidden_weak (__recvmsg) +weak_alias (__libc_recvmsg, recvmsg) +libpthread_hidden_weak (recvmsg) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-send.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-send.S new file mode 100644 index 000000000..76bed39ec --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-send.S @@ -0,0 +1,12 @@ +#include <sysdep-cancel.h> +#ifndef __NR_send +#error Missing definition of NR_send needed for cancellation. +#endif +PSEUDO (__libc_send, send, 4) +ret +PSEUDO_END (__libc_send) +libpthread_hidden_def (__libc_send) +weak_alias (__libc_send, __send) +libpthread_hidden_weak (__send) +weak_alias (__libc_send, send) +libpthread_hidden_weak (send) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-sendmsg.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-sendmsg.S new file mode 100644 index 000000000..d17096eae --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-sendmsg.S @@ -0,0 +1,12 @@ +#include <sysdep-cancel.h> +#ifndef __NR_sendmsg +#error Missing definition of NR_sendmsg needed for cancellation. +#endif +PSEUDO (__libc_sendmsg, sendmsg, 3) +ret +PSEUDO_END(__libc_sendmsg) +libpthread_hidden_def (__libc_sendmsg) +weak_alias (__libc_sendmsg, __sendmsg) +libpthread_hidden_weak (__sendmsg) +weak_alias (__libc_sendmsg, sendmsg) +libpthread_hidden_weak (sendmsg) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-sendto.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-sendto.S new file mode 100644 index 000000000..d07a71f8a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-sendto.S @@ -0,0 +1,12 @@ +#include <sysdep-cancel.h> +#ifndef __NR_sendto +#error Missing definition of NR_sendto needed for cancellation. +#endif +PSEUDO (__libc_sendto, sendto, 6) +ret +PSEUDO_END(__libc_sendto) +libpthread_hidden_def (__libc_sendto) +weak_alias (__libc_sendto, __sendto) +libpthread_hidden_weak (__sendto) +weak_alias (__libc_sendto, sendto) +libpthread_hidden_weak (sendto) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-sigwait.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-sigwait.c new file mode 100644 index 000000000..bde0a9292 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-sigwait.c @@ -0,0 +1,2 @@ +#include <pthreadP.h> +#include "../../../../../../libc/signal/sigwait.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-sleep.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-sleep.c new file mode 100644 index 000000000..9e948adce --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-sleep.c @@ -0,0 +1,2 @@ +#include <pthreadP.h> +#include <../../../../../../libc/unistd/sleep.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-tcdrain.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-tcdrain.c new file mode 100644 index 000000000..07c1f8233 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-tcdrain.c @@ -0,0 +1 @@ +#include <../../../../../../libc/termios/tcdrain.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-wait.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-wait.c new file mode 100644 index 000000000..a05c3eb49 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-wait.c @@ -0,0 +1,2 @@ +#include <pthreadP.h> +#include <../../../../../../libc/sysdeps/linux/common/wait.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-waitpid.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-waitpid.c new file mode 100644 index 000000000..8461c3ff2 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-waitpid.c @@ -0,0 +1 @@ +#include <../../../../../../libc/sysdeps/linux/common/waitpid.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-write.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-write.S new file mode 100644 index 000000000..6bc666779 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-write.S @@ -0,0 +1,9 @@ +#include <sysdep-cancel.h> +PSEUDO (__libc_write, write, 3) +ret +PSEUDO_END (__libc_write) +libpthread_hidden_def (__libc_write) +weak_alias (__libc_write, __write) +libpthread_hidden_weak (__write) +weak_alias (__libc_write, write) +libpthread_hidden_weak (write) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_attr_getaffinity.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_attr_getaffinity.c new file mode 100644 index 000000000..5a3d418a9 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_attr_getaffinity.c @@ -0,0 +1,56 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include <errno.h> +#include <pthreadP.h> +#include <string.h> +#include <sysdep.h> +#include <sys/types.h> + + +int +__pthread_attr_getaffinity_new (const pthread_attr_t *attr, size_t cpusetsize, + cpu_set_t *cpuset) +{ + const struct pthread_attr *iattr; + + assert (sizeof (*attr) >= sizeof (struct pthread_attr)); + iattr = (const struct pthread_attr *) attr; + + if (iattr->cpuset != NULL) + { + /* Check whether there are any bits set beyond the limits + the user requested. */ + size_t cnt; + for (cnt = cpusetsize; cnt < iattr->cpusetsize; ++cnt) + if (((char *) iattr->cpuset)[cnt] != 0) + return EINVAL; + + void *p = mempcpy (cpuset, iattr->cpuset, iattr->cpusetsize); + if (cpusetsize > iattr->cpusetsize) + memset (p, '\0', cpusetsize - iattr->cpusetsize); + } + else + /* We have no information. */ + memset (cpuset, -1, cpusetsize); + + return 0; +} +weak_alias(__pthread_attr_getaffinity_new, pthread_attr_getaffinity_np) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_attr_setaffinity.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_attr_setaffinity.c new file mode 100644 index 000000000..e3414999c --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_attr_setaffinity.c @@ -0,0 +1,82 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include <errno.h> +#include <limits.h> +#include <stdlib.h> +#include <string.h> +#include <pthreadP.h> + + +/* Defined in pthread_setaffinity.c. */ +extern size_t __kernel_cpumask_size; +extern int __determine_cpumask_size (pid_t tid); + + +int +__pthread_attr_setaffinity_new (pthread_attr_t *attr, size_t cpusetsize, + const cpu_set_t *cpuset) +{ + struct pthread_attr *iattr; + + assert (sizeof (*attr) >= sizeof (struct pthread_attr)); + iattr = (struct pthread_attr *) attr; + + if (cpuset == NULL || cpusetsize == 0) + { + free (iattr->cpuset); + iattr->cpuset = NULL; + iattr->cpusetsize = 0; + } + else + { + if (__kernel_cpumask_size == 0) + { + int res = __determine_cpumask_size (THREAD_SELF->tid); + if (res != 0) + /* Some serious problem. */ + return res; + } + + /* Check whether the new bitmask has any bit set beyond the + last one the kernel accepts. */ + size_t cnt; + for (cnt = __kernel_cpumask_size; cnt < cpusetsize; ++cnt) + if (((char *) cpuset)[cnt] != '\0') + /* Found a nonzero byte. This means the user request cannot be + fulfilled. */ + return EINVAL; + + if (iattr->cpusetsize != cpusetsize) + { + void *newp = (cpu_set_t *) realloc (iattr->cpuset, cpusetsize); + if (newp == NULL) + return ENOMEM; + + iattr->cpuset = newp; + iattr->cpusetsize = cpusetsize; + } + + memcpy (iattr->cpuset, cpuset, cpusetsize); + } + + return 0; +} +weak_alias(__pthread_attr_setaffinity_new, pthread_attr_setaffinity_np) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_getaffinity.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_getaffinity.c new file mode 100644 index 000000000..3ca9d7d94 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_getaffinity.c @@ -0,0 +1,46 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <limits.h> +#include <pthreadP.h> +#include <string.h> +#include <sysdep.h> +#include <sys/param.h> +#include <sys/types.h> + + +int +__pthread_getaffinity_new (pthread_t th, size_t cpusetsize, cpu_set_t *cpuset) +{ + const struct pthread *pd = (const struct pthread *) th; + + INTERNAL_SYSCALL_DECL (err); + int res = INTERNAL_SYSCALL (sched_getaffinity, err, 3, pd->tid, + MIN (INT_MAX, cpusetsize), cpuset); + if (INTERNAL_SYSCALL_ERROR_P (res, err)) + return INTERNAL_SYSCALL_ERRNO (res, err); + + /* Clean the rest of the memory the kernel didn't do. */ + memset ((char *) cpuset + res, '\0', cpusetsize - res); + + return 0; +} +strong_alias(__pthread_getaffinity_new, __pthread_getaffinity_np) +strong_alias(__pthread_getaffinity_new, pthread_getaffinity_np) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_getcpuclockid.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_getcpuclockid.c new file mode 100644 index 000000000..155d3645f --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_getcpuclockid.c @@ -0,0 +1,111 @@ +/* pthread_getcpuclockid -- Get POSIX clockid_t for a pthread_t. Linux version + Copyright (C) 2000,2001,2002,2003,2004,2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <errno.h> +#include <pthreadP.h> +#include <sys/time.h> +#include <tls.h> +#include <bits/kernel-features.h> +#include <kernel-posix-cpu-timers.h> + + +#if !(__ASSUME_POSIX_CPU_TIMERS > 0) +int __libc_missing_posix_cpu_timers attribute_hidden; +#endif +#if !(__ASSUME_POSIX_TIMERS > 0) +int __libc_missing_posix_timers attribute_hidden; +#endif + +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 __NR_clock_getres + /* The clockid_t value is a simple computation from the TID. + But we do a clock_getres call to validate it if we aren't + yet sure we have the kernel support. */ + + const clockid_t tidclock = MAKE_THREAD_CPUCLOCK (pd->tid, CPUCLOCK_SCHED); + +# if !(__ASSUME_POSIX_CPU_TIMERS > 0) +# if !(__ASSUME_POSIX_TIMERS > 0) + if (__libc_missing_posix_timers && !__libc_missing_posix_cpu_timers) + __libc_missing_posix_cpu_timers = 1; +# endif + if (!__libc_missing_posix_cpu_timers) + { + INTERNAL_SYSCALL_DECL (err); + int r = INTERNAL_SYSCALL (clock_getres, err, 2, tidclock, NULL); + if (!INTERNAL_SYSCALL_ERROR_P (r, err)) +# endif + { + *clockid = tidclock; + return 0; + } + +# if !(__ASSUME_POSIX_CPU_TIMERS > 0) +# if !(__ASSUME_POSIX_TIMERS > 0) + if (INTERNAL_SYSCALL_ERRNO (r, err) == ENOSYS) + { + /* The kernel doesn't support these calls at all. */ + __libc_missing_posix_timers = 1; + __libc_missing_posix_cpu_timers = 1; + } + else +# endif + if (INTERNAL_SYSCALL_ERRNO (r, err) == EINVAL) + { + /* The kernel doesn't support these clocks at all. */ + __libc_missing_posix_cpu_timers = 1; + } + else + return INTERNAL_SYSCALL_ERRNO (r, err); + } +# endif +#endif + +#ifdef CLOCK_THREAD_CPUTIME_ID + /* We need to store the thread ID in the CLOCKID variable together + with a number identifying the clock. We reserve the low 3 bits + for the clock ID and the rest for the thread ID. This is + problematic if the thread ID is too large. But 29 bits should be + fine. + + If some day more clock IDs are needed the ID part can be + enlarged. The IDs are entirely internal. */ + if (pd->tid >= 1 << (8 * sizeof (*clockid) - CLOCK_IDFIELD_SIZE)) + return ERANGE; + + /* Store the number. */ + *clockid = CLOCK_THREAD_CPUTIME_ID | (pd->tid << CLOCK_IDFIELD_SIZE); + + return 0; +#else + /* We don't have a timer for that. */ + return ENOENT; +#endif +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_kill.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_kill.c new file mode 100644 index 000000000..8d887e020 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_kill.c @@ -0,0 +1,70 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <signal.h> +#include <pthreadP.h> +#include <tls.h> +#include <sysdep.h> +#include <bits/kernel-features.h> + + +int +__pthread_kill ( + pthread_t threadid, + int signo) +{ + struct pthread *pd = (struct pthread *) threadid; + + /* Make sure the descriptor is valid. */ + if (INVALID_TD_P (pd)) + /* Not a valid thread handle. */ + return ESRCH; + + /* Disallow sending the signal we use for cancellation, timers, for + for the setxid implementation. */ + if (signo == SIGCANCEL || signo == SIGTIMER || signo == SIGSETXID) + return EINVAL; + + /* We have a special syscall to do the work. */ + INTERNAL_SYSCALL_DECL (err); + + /* One comment: The PID field in the TCB can temporarily be changed + (in fork). But this must not affect this code here. Since this + function would have to be called while the thread is executing + fork, it would have to happen in a signal handler. But this is + no allowed, pthread_kill is not guaranteed to be async-safe. */ + int val; +#if __ASSUME_TGKILL + val = INTERNAL_SYSCALL (tgkill, err, 3, THREAD_GETMEM (THREAD_SELF, pid), + pd->tid, signo); +#else +# ifdef __NR_tgkill + val = INTERNAL_SYSCALL (tgkill, err, 3, THREAD_GETMEM (THREAD_SELF, pid), + pd->tid, signo); + if (INTERNAL_SYSCALL_ERROR_P (val, err) + && INTERNAL_SYSCALL_ERRNO (val, err) == ENOSYS) +# endif + val = INTERNAL_SYSCALL (tkill, err, 2, pd->tid, signo); +#endif + + return (INTERNAL_SYSCALL_ERROR_P (val, err) + ? INTERNAL_SYSCALL_ERRNO (val, err) : 0); +} +strong_alias (__pthread_kill, pthread_kill) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_mutex_cond_lock.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_mutex_cond_lock.c new file mode 100644 index 000000000..047c64322 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_mutex_cond_lock.c @@ -0,0 +1,8 @@ +#include <pthreadP.h> + +#define LLL_MUTEX_LOCK(mutex) lll_mutex_cond_lock(mutex) +#define LLL_MUTEX_TRYLOCK(mutex) lll_mutex_cond_trylock(mutex) +#define __pthread_mutex_lock __pthread_mutex_cond_lock +#define NO_INCR + +#include <pthread_mutex_lock.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_setaffinity.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_setaffinity.c new file mode 100644 index 000000000..fa7b48904 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_setaffinity.c @@ -0,0 +1,86 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <alloca.h> +#include <errno.h> +#include <pthreadP.h> +#include <sysdep.h> +#include <sys/types.h> + + +size_t __kernel_cpumask_size; + + +/* Determine the current affinity. As a side affect we learn + about the size of the cpumask_t in the kernel. */ +int +__determine_cpumask_size (pid_t tid) +{ + INTERNAL_SYSCALL_DECL (err); + int res; + + size_t psize = 128; + void *p = alloca (psize); + + while (res = INTERNAL_SYSCALL (sched_getaffinity, err, 3, tid, psize, p), + INTERNAL_SYSCALL_ERROR_P (res, err) + && INTERNAL_SYSCALL_ERRNO (res, err) == EINVAL) + p = extend_alloca (p, psize, 2 * psize); + + if (res == 0 || INTERNAL_SYSCALL_ERROR_P (res, err)) + return INTERNAL_SYSCALL_ERRNO (res, err); + + __kernel_cpumask_size = res; + + return 0; +} + + +int +__pthread_setaffinity_new (pthread_t th, size_t cpusetsize, + const cpu_set_t *cpuset) +{ + const struct pthread *pd = (const struct pthread *) th; + + INTERNAL_SYSCALL_DECL (err); + int res; + + if (__builtin_expect (__kernel_cpumask_size == 0, 0)) + { + res = __determine_cpumask_size (pd->tid); + if (res != 0) + return res; + } + + /* We now know the size of the kernel cpumask_t. Make sure the user + does not request to set a bit beyond that. */ + size_t cnt; + for (cnt = __kernel_cpumask_size; cnt < cpusetsize; ++cnt) + if (((char *) cpuset)[cnt] != '\0') + /* Found a nonzero byte. This means the user request cannot be + fulfilled. */ + return EINVAL; + + res = INTERNAL_SYSCALL (sched_setaffinity, err, 3, pd->tid, cpusetsize, + cpuset); + return (INTERNAL_SYSCALL_ERROR_P (res, err) + ? INTERNAL_SYSCALL_ERRNO (res, err) + : 0); +} +weak_alias(__pthread_setaffinity_new, pthread_setaffinity_np) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_yield.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_yield.c new file mode 100644 index 000000000..5aecffcf0 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_yield.c @@ -0,0 +1,30 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <sched.h> + + +/* With the 1-on-1 model we implement this function is equivalent to + the 'sched_yield' function. */ +int +pthread_yield (void) +{ + return sched_yield (); +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/raise.c b/libpthread/nptl/sysdeps/unix/sysv/linux/raise.c new file mode 100644 index 000000000..de794e4ab --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/raise.c @@ -0,0 +1,75 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <sysdep.h> +#include <pthreadP.h> +#include <bits/kernel-features.h> + + +extern __typeof(raise) __raise; +int __raise (int sig) +{ + struct pthread *pd = THREAD_SELF; +#if __ASSUME_TGKILL || defined __NR_tgkill + pid_t pid = THREAD_GETMEM (pd, pid); +#endif + pid_t selftid = THREAD_GETMEM (pd, tid); + if (selftid == 0) + { + /* This system call is not supposed to fail. */ +#ifdef INTERNAL_SYSCALL + INTERNAL_SYSCALL_DECL (err); + selftid = INTERNAL_SYSCALL (gettid, err, 0); +#else + selftid = INLINE_SYSCALL (gettid, 0); +#endif + THREAD_SETMEM (pd, tid, selftid); + +#if __ASSUME_TGKILL || defined __NR_tgkill + /* We do not set the PID field in the TID here since we might be + called from a signal handler while the thread executes fork. */ + pid = selftid; +#endif + } +#if __ASSUME_TGKILL || defined __NR_tgkill + else + /* raise is an async-safe function. It could be called while the + fork/vfork function temporarily invalidated the PID field. Adjust for + that. */ + if (__builtin_expect (pid <= 0, 0)) + pid = (pid & INT_MAX) == 0 ? selftid : -pid; +#endif + +#if __ASSUME_TGKILL + return INLINE_SYSCALL (tgkill, 3, pid, selftid, sig); +#else +# ifdef __NR_tgkill + int res = INLINE_SYSCALL (tgkill, 3, pid, selftid, sig); + if (res != -1 || errno != ENOSYS) + return res; +# endif + return INLINE_SYSCALL (tkill, 2, selftid, sig); +#endif +} +libc_hidden_proto(raise) +weak_alias(__raise, raise) +libc_hidden_weak(raise) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/read.S b/libpthread/nptl/sysdeps/unix/sysv/linux/read.S new file mode 100644 index 000000000..d3adfa84c --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/read.S @@ -0,0 +1,19 @@ +#include <sysdep-cancel.h> + +/* +extern int __read_nocancel (int, void *, size_t) attribute_hidden; +*/ +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt + +PSEUDO (__libc_read, read, 3) +ret +PSEUDO_END(__libc_read) + +libc_hidden_def (__read_nocancel) +libc_hidden_def (__libc_read) +weak_alias (__libc_read, __read) +libc_hidden_weak (__read) +weak_alias (__libc_read, read) +libc_hidden_weak (read) + +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/recv.S b/libpthread/nptl/sysdeps/unix/sysv/linux/recv.S new file mode 100644 index 000000000..95fa6516e --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/recv.S @@ -0,0 +1,12 @@ +#include <sysdep-cancel.h> +#ifndef __NR_recv +#error Missing definition of NR_recv needed for cancellation. +#endif +PSEUDO (__libc_recv, recv, 4) +ret +PSEUDO_END(__libc_recv) +libc_hidden_def (__libc_recv) +weak_alias (__libc_recv, __recv) +libc_hidden_weak (__recv) +weak_alias (__libc_recv, recv) +libc_hidden_weak (recv) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/recvfrom.S b/libpthread/nptl/sysdeps/unix/sysv/linux/recvfrom.S new file mode 100644 index 000000000..d9cc1e9b4 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/recvfrom.S @@ -0,0 +1,12 @@ +#include <sysdep-cancel.h> +#ifndef __NR_recvfrom +#error Missing definition of NR_recvfrom needed for cancellation. +#endif +PSEUDO (__libc_recvfrom, recvfrom, 6) +ret +PSEUDO_END(__libc_recvfrom) +libc_hidden_def (__libc_recvfrom) +weak_alias (__libc_recvfrom, __recvfrom) +libc_hidden_weak (__recvfrom) +weak_alias (__libc_recvfrom, recvfrom) +libc_hidden_weak (recvfrom) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/recvmsg.S b/libpthread/nptl/sysdeps/unix/sysv/linux/recvmsg.S new file mode 100644 index 000000000..c761b907c --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/recvmsg.S @@ -0,0 +1,12 @@ +#include <sysdep-cancel.h> +#ifndef __NR_recvmsg +#error Missing definition of NR_recvmsg needed for cancellation. +#endif +PSEUDO (__libc_recvmsg, recvmsg, 3) +ret +PSEUDO_END(__libc_recvmsg) +libc_hidden_def (__libc_recvmsg) +weak_alias (__libc_recvmsg, __recvmsg) +libc_hidden_weak (__recvmsg) +weak_alias (__libc_recvmsg, recvmsg) +libc_hidden_weak (recvmsg) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/register-atfork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/register-atfork.c new file mode 100644 index 000000000..f6c3de4bc --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/register-atfork.c @@ -0,0 +1,108 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include "fork.h" + + +/* Lock to protect allocation and deallocation of fork handlers. */ +lll_lock_t __fork_lock = LLL_LOCK_INITIALIZER; + + +/* Number of pre-allocated handler entries. */ +#define NHANDLER 48 + +/* Memory pool for fork handler structures. */ +static struct fork_handler_pool +{ + struct fork_handler_pool *next; + struct fork_handler mem[NHANDLER]; +} fork_handler_pool; + + +static struct fork_handler * +fork_handler_alloc (void) +{ + struct fork_handler_pool *runp = &fork_handler_pool; + struct fork_handler *result = NULL; + unsigned int i; + + do + { + /* Search for an empty entry. */ + for (i = 0; i < NHANDLER; ++i) + if (runp->mem[i].refcntr == 0) + goto found; + } + while ((runp = runp->next) != NULL); + + /* We have to allocate a new entry. */ + runp = (struct fork_handler_pool *) calloc (1, sizeof (*runp)); + if (runp != NULL) + { + /* Enqueue the new memory pool into the list. */ + runp->next = fork_handler_pool.next; + fork_handler_pool.next = runp; + + /* We use the last entry on the page. This means when we start + searching from the front the next time we will find the first + entry unused. */ + i = NHANDLER - 1; + + found: + result = &runp->mem[i]; + result->refcntr = 1; + result->need_signal = 0; + } + + return result; +} + + +int +__register_atfork ( + void (*prepare) (void), + void (*parent) (void), + void (*child) (void), + void *dso_handle) +{ + /* Get the lock to not conflict with other allocations. */ + lll_lock (__fork_lock); + + struct fork_handler *newp = fork_handler_alloc (); + + if (newp != NULL) + { + /* Initialize the new record. */ + newp->prepare_handler = prepare; + newp->parent_handler = parent; + newp->child_handler = child; + newp->dso_handle = dso_handle; + + newp->next = __fork_handlers; + __fork_handlers = newp; + } + + /* Release the lock. */ + lll_unlock (__fork_lock); + + return newp == NULL ? ENOMEM : 0; +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sem_post.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sem_post.c new file mode 100644 index 000000000..7f0b67918 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sem_post.c @@ -0,0 +1,41 @@ +/* sem_post -- post to a POSIX semaphore. Generic futex-using version. + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <internaltypes.h> +#include <semaphore.h> + +int +__new_sem_post (sem_t *sem) +{ + int *futex = (int *) sem; + + int nr = atomic_increment_val (futex); + int err = lll_futex_wake (futex, nr); + if (__builtin_expect (err, 0) < 0) + { + __set_errno (-err); + return -1; + } + return 0; +} +weak_alias(__new_sem_post, sem_post) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sem_timedwait.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sem_timedwait.c new file mode 100644 index 000000000..79b11948c --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sem_timedwait.c @@ -0,0 +1,97 @@ +/* sem_timedwait -- wait on a semaphore. Generic futex-using version. + Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <internaltypes.h> +#include <semaphore.h> +#include <pthreadP.h> + + +int +sem_timedwait (sem_t *sem, const struct timespec *abstime) +{ + /* First check for cancellation. */ + CANCELLATION_P (THREAD_SELF); + + int *futex = (int *) sem; + int val; + int err; + + if (*futex > 0) + { + val = atomic_decrement_if_positive (futex); + if (val > 0) + return 0; + } + + err = -EINVAL; + if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) + goto error_return; + + do + { + struct timeval tv; + struct timespec rt; + int sec, nsec; + + /* Get the current time. */ + gettimeofday (&tv, NULL); + + /* Compute relative timeout. */ + sec = abstime->tv_sec - tv.tv_sec; + nsec = abstime->tv_nsec - tv.tv_usec * 1000; + if (nsec < 0) + { + nsec += 1000000000; + --sec; + } + + /* Already timed out? */ + err = -ETIMEDOUT; + if (sec < 0) + goto error_return; + + /* Do wait. */ + rt.tv_sec = sec; + rt.tv_nsec = nsec; + + /* Enable asynchronous cancellation. Required by the standard. */ + int oldtype = __pthread_enable_asynccancel (); + + err = lll_futex_timed_wait (futex, 0, &rt); + + /* Disable asynchronous cancellation. */ + __pthread_disable_asynccancel (oldtype); + + if (err != 0 && err != -EWOULDBLOCK) + goto error_return; + + val = atomic_decrement_if_positive (futex); + } + while (val <= 0); + + return 0; + + error_return: + __set_errno (-err); + return -1; +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sem_trywait.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sem_trywait.c new file mode 100644 index 000000000..3cf1d9a8a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sem_trywait.c @@ -0,0 +1,44 @@ +/* sem_trywait -- wait on a semaphore. Generic futex-using version. + Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <internaltypes.h> +#include <semaphore.h> + + +int +__new_sem_trywait (sem_t *sem) +{ + int *futex = (int *) sem; + int val; + + if (*futex > 0) + { + val = atomic_decrement_if_positive (futex); + if (val > 0) + return 0; + } + + __set_errno (EAGAIN); + return -1; +} +weak_alias(__new_sem_trywait, sem_trywait) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sem_wait.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sem_wait.c new file mode 100644 index 000000000..416d8634b --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sem_wait.c @@ -0,0 +1,56 @@ +/* sem_wait -- wait on a semaphore. Generic futex-using version. + Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <internaltypes.h> +#include <semaphore.h> +#include <pthreadP.h> + + +int +__new_sem_wait (sem_t *sem) +{ + /* First check for cancellation. */ + CANCELLATION_P (THREAD_SELF); + + int *futex = (int *) sem; + int err; + + do + { + if (atomic_decrement_if_positive (futex) > 0) + return 0; + + /* Enable asynchronous cancellation. Required by the standard. */ + int oldtype = __pthread_enable_asynccancel (); + + err = lll_futex_wait (futex, 0); + + /* Disable asynchronous cancellation. */ + __pthread_disable_asynccancel (oldtype); + } + while (err == 0 || err == -EWOULDBLOCK); + + __set_errno (-err); + return -1; +} +weak_alias(__new_sem_wait, sem_wait) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/send.S b/libpthread/nptl/sysdeps/unix/sysv/linux/send.S new file mode 100644 index 000000000..eb744c712 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/send.S @@ -0,0 +1,12 @@ +#include <sysdep-cancel.h> +#ifndef __NR_send +#error Missing definition of NR_send needed for cancellation. +#endif +PSEUDO (__libc_send, send, 4) +ret +PSEUDO_END (__libc_send) +libc_hidden_def (__libc_send) +weak_alias (__libc_send, __send) +libc_hidden_weak (__send) +weak_alias (__libc_send, send) +libc_hidden_weak (send) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sendmsg.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sendmsg.S new file mode 100644 index 000000000..4c41e01c1 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sendmsg.S @@ -0,0 +1,12 @@ +#include <sysdep-cancel.h> +#ifndef __NR_sendmsg +#error Missing definition of NR_sendmsg needed for cancellation. +#endif +PSEUDO (__libc_sendmsg, sendmsg, 3) +ret +PSEUDO_END(__libc_sendmsg) +libc_hidden_def (__libc_sendmsg) +weak_alias (__libc_sendmsg, __sendmsg) +libc_hidden_weak (__sendmsg) +weak_alias (__libc_sendmsg, sendmsg) +libc_hidden_weak (sendmsg) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sendto.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sendto.S new file mode 100644 index 000000000..7cb5278e9 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sendto.S @@ -0,0 +1,12 @@ +#include <sysdep-cancel.h> +#ifndef __NR_sendto +#error Missing definition of NR_sendto needed for cancellation. +#endif +PSEUDO (__libc_sendto, sendto, 6) +ret +PSEUDO_END(__libc_sendto) +libc_hidden_def (__libc_sendto) +weak_alias (__libc_sendto, __sendto) +libc_hidden_weak (__sendto) +weak_alias (__libc_sendto, sendto) +libc_hidden_weak (sendto) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/Makefile b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/Makefile new file mode 100644 index 000000000..43a6fad84 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/Makefile @@ -0,0 +1,13 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2005 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +top_srcdir=../../../../../../../ +top_builddir=../../../../../../../ +all: objs +include $(top_builddir)Rules.mak +include Makefile.arch +include $(top_srcdir)Makerules diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/Makefile.arch b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/Makefile.arch new file mode 100644 index 000000000..9bd7569c9 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/Makefile.arch @@ -0,0 +1,84 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2006 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +libpthread_SSRC = pt-vfork.S pthread_once.S pthread_rwlock_wrlock.S \ + pthread_rwlock_rdlock.S pthread_rwlock_unlock.S \ + lowlevellock.S pthread_barrier_wait.S pthread_cond_broadcast.S \ + pthread_cond_signal.S \ + pthread_rwlock_timedwrlock.S pthread_rwlock_timedrdlock.S \ + sem_post.S sem_timedwait.S sem_trywait.S sem_wait.S + +libc_a_CSRC = fork.c +libc_a_SSRC = libc-lowlevellock.S clone.S vfork.S + +ifeq ($(UCLIBC_HAS_STDIO_FUTEXES),y) +CFLAGS-fork.c = -D__USE_STDIO_FUTEXES__ +endif + +ASFLAGS-pt-vfork.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 -D_LIBC_REENTRANT -DUSE___THREAD +ASFLAGS-pthread_once.S = -D_LIBC_REENTRANT -DUSE___THREAD +ASFLAGS-pthread_rwlock_wrlock.S = -D_LIBC_REENTRANT -DUSE___THREAD +ASFLAGS-pthread_rwlock_rdlock.S = -D_LIBC_REENTRANT -DUSE___THREAD +ASFLAGS-pthread_rwlock_unlock.S = -D_LIBC_REENTRANT -DUSE___THREAD +ASFLAGS-pthread_rwlock_unlock.S = -D_LIBC_REENTRANT -DUSE___THREAD + +ASFLAGS-pthread_barrier_wait.S = -D_LIBC_REENTRANT -DUSE___THREAD +ASFLAGS-pthread_cond_broadcast.S = -D_LIBC_REENTRANT -DUSE___THREAD +ASFLAGS-pthread_cond_signal.S = -D_LIBC_REENTRANT -DUSE___THREAD +ASFLAGS-pthread_cond_wait.S = -D_LIBC_REENTRANT -DUSE___THREAD +ASFLAGS-pthread_cond_timedwait.S = -D_LIBC_REENTRANT -DUSE___THREAD + +ASFLAGS-pthread_rwlock_timedwrlock.S = -D_LIBC_REENTRANT -DUSE___THREAD +ASFLAGS-pthread_rwlock_timedrdlock.S = -D_LIBC_REENTRANT -DUSE___THREAD + +ASFLAGS-sem_post.S = -D_LIBC_REENTRANT -DUSE___THREAD +ASFLAGS-sem_timedwait.S = -D_LIBC_REENTRANT -DUSE___THREAD +ASFLAGS-sem_trywait.S = -D_LIBC_REENTRANT -DUSE___THREAD +ASFLAGS-sem_wait.S = -D_LIBC_REENTRANT -DUSE___THREAD + +ASFLAGS-libc-lowlevellock.S = -D_LIBC_REENTRANT -DUSE___THREAD + +ASFLAGS-lowlevellock.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 -D_LIBC_REENTRANT -DUSE___THREAD + +ASFLAGS-clone.S = -D_LIBC_REENTRANT +ASFLAGS-vfork.S = -D_LIBC_REENTRANT + +ifeq ($(UCLIBC_HAS_THREADS_NATIVE),y) +#Needed to use the correct SYSCALL_ERROR_HANDLER +ASFLAGS-clone.S += -DUSE___THREAD +ASFLAGS-vfork.S += -DUSE___THREAD +endif + +CFLAGS += $(SSP_ALL_CFLAGS) +#CFLAGS:=$(CFLAGS:-O1=-O2) + +LINUX_ARCH_DIR:=$(top_srcdir)libpthread/nptl/sysdeps/unix/sysv/linux/sh +LINUX_ARCH_OUT:=$(top_builddir)libpthread/nptl/sysdeps/unix/sysv/linux/sh + +LINUX_ARCH_OBJ:=$(patsubst %.S,$(LINUX_ARCH_OUT)/%.o,$(libpthread_SSRC)) + +ifeq ($(DOPIC),y) +libpthread-a-y += $(LINUX_ARCH_OBJ:.o=.os) +else +libpthread-a-y += $(LINUX_ARCH_OBJ) +endif +libpthread-so-y += $(LINUX_ARCH_OBJ:.o=.oS) + +libpthread-nomulti-y+=$(LINUX_ARCH_OBJS) + +LIBC_LINUX_ARCH_OBJ:=$(patsubst %.c,$(LINUX_ARCH_OUT)/%.o,$(libc_a_CSRC)) +LIBC_LINUX_ARCH_OBJ+=$(patsubst %.S,$(LINUX_ARCH_OUT)/%.o,$(libc_a_SSRC)) + +libc-static-y+=$(LIBC_LINUX_ARCH_OBJ) +libc-shared-y+=$(LIBC_LINUX_ARCH_OBJ:.o=.oS) + +libc-nomulti-y+=$(LIBC_LINUX_ARCH_OBJ) + +objclean-y+=nptl_linux_arch_clean + +nptl_linux_arch_clean: + $(do_rm) $(addprefix $(LINUX_ARCH_OUT)/*., o os oS) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h new file mode 100644 index 000000000..969686dd5 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h @@ -0,0 +1,168 @@ +/* Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _BITS_PTHREADTYPES_H +#define _BITS_PTHREADTYPES_H 1 + +#define __SIZEOF_PTHREAD_ATTR_T 36 +#define __SIZEOF_PTHREAD_MUTEX_T 24 +#define __SIZEOF_PTHREAD_MUTEXATTR_T 4 +#define __SIZEOF_PTHREAD_COND_T 48 +#define __SIZEOF_PTHREAD_COND_COMPAT_T 12 +#define __SIZEOF_PTHREAD_CONDATTR_T 4 +#define __SIZEOF_PTHREAD_RWLOCK_T 32 +#define __SIZEOF_PTHREAD_RWLOCKATTR_T 8 +#define __SIZEOF_PTHREAD_BARRIER_T 20 +#define __SIZEOF_PTHREAD_BARRIERATTR_T 4 + + +/* Thread identifiers. The structure of the attribute type is not + exposed on purpose. */ +typedef unsigned long int pthread_t; + + +typedef union +{ + char __size[__SIZEOF_PTHREAD_ATTR_T]; + long int __align; +} pthread_attr_t; + + +typedef struct __pthread_internal_slist +{ + struct __pthread_internal_slist *__next; +} __pthread_slist_t; + + +/* Data structures for mutex handling. The structure of the attribute + type is not exposed on purpose. */ +typedef union +{ + struct __pthread_mutex_s + { + int __lock; + unsigned int __count; + int __owner; + /* KIND must stay at this position in the structure to maintain + binary compatibility. */ + int __kind; + unsigned int __nusers; + __extension__ union + { + int __spins; + __pthread_slist_t __list; + }; + } __data; + char __size[__SIZEOF_PTHREAD_MUTEX_T]; + long int __align; +} pthread_mutex_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_MUTEXATTR_T]; + long int __align; +} pthread_mutexattr_t; + + +/* Data structure for conditional variable handling. The structure of + the attribute type is not exposed on purpose. */ +typedef union +{ + struct + { + int __lock; + unsigned int __futex; + __extension__ unsigned long long int __total_seq; + __extension__ unsigned long long int __wakeup_seq; + __extension__ unsigned long long int __woken_seq; + void *__mutex; + unsigned int __nwaiters; + unsigned int __broadcast_seq; + } __data; + char __size[__SIZEOF_PTHREAD_COND_T]; + __extension__ long long int __align; +} pthread_cond_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_CONDATTR_T]; + long int __align; +} pthread_condattr_t; + + +/* Keys for thread-specific data */ +typedef unsigned int pthread_key_t; + + +/* Once-only execution */ +typedef int pthread_once_t; + + +#if defined __USE_UNIX98 || defined __USE_XOPEN2K +/* Data structure for read-write lock variable handling. The + structure of the attribute type is not exposed on purpose. */ +typedef union +{ + struct + { + int __lock; + unsigned int __nr_readers; + unsigned int __readers_wakeup; + unsigned int __writer_wakeup; + unsigned int __nr_readers_queued; + unsigned int __nr_writers_queued; + /* FLAGS must stay at this position in the structure to maintain + binary compatibility. */ + unsigned int __flags; + pthread_t __writer; + } __data; + char __size[__SIZEOF_PTHREAD_RWLOCK_T]; + long int __align; +} pthread_rwlock_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_RWLOCKATTR_T]; + long int __align; +} pthread_rwlockattr_t; +#endif + + +#ifdef __USE_XOPEN2K +/* POSIX spinlock data type. */ +typedef volatile int pthread_spinlock_t; + + +/* POSIX barriers data type. The structure of the type is + deliberately not exposed. */ +typedef union +{ + char __size[__SIZEOF_PTHREAD_BARRIER_T]; + long int __align; +} pthread_barrier_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_BARRIERATTR_T]; + int __align; +} pthread_barrierattr_t; +#endif + + +#endif /* bits/pthreadtypes.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/bits/semaphore.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/bits/semaphore.h new file mode 100644 index 000000000..e6c5d845c --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/bits/semaphore.h @@ -0,0 +1,39 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _SEMAPHORE_H +# error "Never use <bits/semaphore.h> directly; include <semaphore.h> instead." +#endif + + +#define __SIZEOF_SEM_T 16 + + +/* Value returned if `sem_open' failed. */ +#define SEM_FAILED ((sem_t *) 0) + +/* Maximum value the semaphore can have. */ +#define SEM_VALUE_MAX (2147483647) + + +typedef union +{ + char __size[__SIZEOF_SEM_T]; + long int __align; +} sem_t; diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/clone.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/clone.S new file mode 100644 index 000000000..918d57926 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/clone.S @@ -0,0 +1,2 @@ +#define RESET_PID +#include <libc/sysdeps/linux/sh/clone.S> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/createthread.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/createthread.c new file mode 100644 index 000000000..e17c0174b --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/createthread.c @@ -0,0 +1,24 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* Value passed to 'clone' for initialization of the thread register. */ +#define TLS_VALUE (pd + 1) + + +/* Get the real implementation. */ +#include <sysdeps/pthread/createthread.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/fork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/fork.c new file mode 100644 index 000000000..dcedd2625 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/fork.c @@ -0,0 +1,31 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sched.h> +#include <signal.h> +#include <stdio.h> +#include <sysdep.h> +#include <tls.h> + +/* TLS pointer argument is passed as the 5-th argument. */ +#define ARCH_FORK() \ + INLINE_SYSCALL (clone, 5, \ + CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD, 0, \ + NULL, &THREAD_SELF->tid, NULL) + +#include "../fork.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/libc-lowlevellock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/libc-lowlevellock.S new file mode 100644 index 000000000..94a24b46e --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/libc-lowlevellock.S @@ -0,0 +1,19 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "lowlevellock.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/lowlevel-atomic.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/lowlevel-atomic.h new file mode 100644 index 000000000..062ce2871 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/lowlevel-atomic.h @@ -0,0 +1,81 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifdef __ASSEMBLER__ + +#define _IMP1 #1 +#define _IMM1 #-1 +#define _IMM4 #-4 +#define _IMM6 #-6 +#define _IMM8 #-8 + +#define INC(mem, reg) \ + .align 2; \ + mova 99f, r0; \ + mov r15, r1; \ + mov _IMM6, r15; \ +98: mov.l mem, reg; \ + add _IMP1, reg; \ + mov.l reg, mem; \ +99: mov r1, r15 + +#define DEC(mem, reg) \ + .align 2; \ + mova 99f, r0; \ + mov r15, r1; \ + mov _IMM6, r15; \ +98: mov.l mem, reg; \ + add _IMM1, reg; \ + mov.l reg, mem; \ +99: mov r1, r15 + +#define XADD(reg, mem, new, old) \ + .align 2; \ + mova 99f, r0; \ + nop; \ + mov r15, r1; \ + mov _IMM4, r15; \ +98: mov.l mem, old; \ + mov old, new; \ + add reg, new; \ + mov.l new, mem; \ +99: mov r1, r15 + +#define XCHG(reg, mem, old) \ + .align 2; \ + mova 99f, r0; \ + nop; \ + mov r15, r1; \ + mov _IMM4, r15; \ +98: mov.l mem, old; \ + mov.l reg, mem; \ +99: mov r1, r15 + +#define CMPXCHG(reg, mem, new, old) \ + .align 2; \ + mova 99f, r0; \ + nop; \ + mov r15, r1; \ + mov _IMM8, r15; \ +98: mov.l mem, old; \ + cmp/eq old, reg; \ + bf 99f; \ + mov.l new, mem; \ +99: mov r1, r15 + +#endif /* __ASSEMBLER__ */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/lowlevellock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/lowlevellock.S new file mode 100644 index 000000000..a5c916bb7 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/lowlevellock.S @@ -0,0 +1,296 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <pthread-errnos.h> +#include "lowlevel-atomic.h" + + .text + +#define SYS_gettimeofday __NR_gettimeofday + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + + + .globl __lll_mutex_lock_wait + .type __lll_mutex_lock_wait,@function + .hidden __lll_mutex_lock_wait + .align 5 + /* void __lll_mutex_lock_wait (int val, int *__futex) */ +__lll_mutex_lock_wait: + mov #2, r6 + cmp/eq r4, r6 + mov r5, r4 + mov #0, r7 /* No timeout. */ + mov #FUTEX_WAIT, r5 + + bf 2f + +1: + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + +2: + XCHG (r6, @r4, r2) + tst r2, r2 + bf 1b + + rts + nop + .size __lll_mutex_lock_wait,.-__lll_mutex_lock_wait + + +#ifdef NOT_IN_libc + .globl __lll_mutex_timedlock_wait + .type __lll_mutex_timedlock_wait,@function + .hidden __lll_mutex_timedlock_wait + .align 5 + /* int __lll_mutex_timedlock_wait (int val, int *__futex, + const struct timespec *abstime) */ +__lll_mutex_timedlock_wait: + /* Check for a valid timeout value. */ + mov.l @(4,r6), r1 + mov.l .L1g, r0 + cmp/hs r0, r1 + bt 3f + + mov.l r9, @-r15 + mov.l r8, @-r15 + mov r6, r9 + mov r5, r8 + + /* Stack frame for the timespec and timeval structs. */ + add #-8, r15 + +1: + /* Get current time. */ + mov r15, r4 + mov #0, r5 + mov #SYS_gettimeofday, r3 + trapa #0x12 + SYSCALL_INST_PAD + + /* Compute relative timeout. */ + mov.l @(4,r15), r0 + mov.w .L1k, r1 + dmulu.l r0, r1 /* Micro seconds to nano seconds. */ + mov.l @r9, r2 + mov.l @(4,r9), r3 + mov.l @r15, r0 + sts macl, r1 + sub r0, r2 + clrt + subc r1, r3 + bf 4f + mov.l .L1g, r1 + add r1, r3 + add #-1, r2 +4: + cmp/pz r2 + bf 5f /* Time is already up. */ + + mov.l r2, @r15 /* Store relative timeout. */ + mov.l r3, @(4,r15) + + mov #1, r3 + mov #2, r6 + CMPXCHG (r3, @r8, r6, r2) + tst r2, r2 + bt 8f + + mov r8, r4 + mov #FUTEX_WAIT, r5 + mov r15, r7 + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + mov r0, r4 + +8: + mov #0, r3 + CMPXCHG (r3, @r8, r6, r2) + bf/s 7f + mov #0, r0 + +6: + add #8, r15 + mov.l @r15+, r8 + rts + mov.l @r15+, r9 +7: + /* Check whether the time expired. */ + mov #-ETIMEDOUT, r1 + cmp/eq r5, r1 + bt 5f + + /* Make sure the current holder knows we are going to sleep. */ + XCHG (r2, @r8, r3) + tst r3, r3 + bt/s 6b + mov #0, r0 + bra 1b + nop +3: + rts + mov #EINVAL, r0 +5: + bra 6b + mov #ETIMEDOUT, r0 + +.L1k: + .word 1000 + .align 2 +.L1g: + .long 1000000000 + + .size __lll_mutex_timedlock_wait,.-__lll_mutex_timedlock_wait +#endif + + +#ifdef NOT_IN_libc + .globl lll_unlock_wake_cb + .type lll_unlock_wake_cb,@function + .hidden lll_unlock_wake_cb + .align 5 +lll_unlock_wake_cb: + DEC (@r4, r2) + tst r2, r2 + bt 1f + + mov #FUTEX_WAKE, r5 + mov #1, r6 /* Wake one thread. */ + mov #0, r7 + mov.l r7, @r4 /* Stores 0. */ + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + +1: + rts + nop + .size lll_unlock_wake_cb,.-lll_unlock_wake_cb +#endif + + + .globl __lll_mutex_unlock_wake + .type __lll_mutex_unlock_wake,@function + .hidden __lll_mutex_unlock_wake + .align 5 + /* void __lll_mutex_unlock_wake(int *__futex) */ +__lll_mutex_unlock_wake: + mov #FUTEX_WAKE, r5 + mov #1, r6 /* Wake one thread. */ + mov #0, r7 + mov.l r7, @r4 /* Stores 0. */ + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + rts + nop + .size __lll_mutex_unlock_wake,.-__lll_mutex_unlock_wake + + +#ifdef NOT_IN_libc + .globl __lll_timedwait_tid + .type __lll_timedwait_tid,@function + .hidden __lll_timedwait_tid + .align 5 +__lll_timedwait_tid: + mov.l r9, @-r15 + mov.l r8, @-r15 + mov r4, r8 + mov r5, r9 + + /* Stack frame for the timespec and timeval structs. */ + add #-8, r15 + +2: + /* Get current time. */ + mov r15, r4 + mov #0, r5 + mov #SYS_gettimeofday, r3 + trapa #0x12 + SYSCALL_INST_PAD + + /* Compute relative timeout. */ + mov.l @(4,r15), r0 + mov.w .L1k2, r1 + dmulu.l r0, r1 /* Micro seconds to nano seconds. */ + mov.l @r9, r2 + mov.l @(4,r9), r3 + mov.l @r15, r0 + sts macl, r1 + sub r0, r2 + clrt + subc r1, r3 + bf 5f + mov.l .L1g2, r1 + add r1, r3 + add #-1, r2 +5: + cmp/pz r2 + bf 6f /* Time is already up. */ + + mov.l r2, @r15 /* Store relative timeout. */ + mov.l r3, @(4,r15) + + mov.l @r8, r2 + tst r2, r2 + bt 4f + + mov r8, r4 + mov #FUTEX_WAIT, r5 + mov r2, r6 + mov r15, r7 + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + + mov.l @r8, r2 + tst r2, r2 + bf 1f +4: + mov #0, r0 +3: + add #8, r15 + mov.l @r15+, r8 + rts + mov.l @r15+, r9 +1: + /* Check whether the time expired. */ + mov #-ETIMEDOUT, r1 + cmp/eq r0, r1 + bf 2b +6: + bra 3b + mov #ETIMEDOUT, r0 + +.L1k2: + .word 1000 + .align 2 +.L1g2: + .long 1000000000 + .size __lll_timedwait_tid,.-__lll_timedwait_tid +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/lowlevellock.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/lowlevellock.h new file mode 100644 index 000000000..45339f5e0 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/lowlevellock.h @@ -0,0 +1,294 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _LOWLEVELLOCK_H +#define _LOWLEVELLOCK_H 1 + +#include <syscall.h> +#include <time.h> +#include <sys/param.h> +#include <bits/pthreadtypes.h> + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + + +/* Initializer for compatibility lock. */ +#define LLL_MUTEX_LOCK_INITIALIZER (0) +#define LLL_MUTEX_LOCK_INITIALIZER_LOCKED (1) +#define LLL_MUTEX_LOCK_INITIALIZER_WAITERS (2) + +extern int __lll_mutex_lock_wait (int val, int *__futex) attribute_hidden; +extern int __lll_mutex_timedlock_wait (int val, int *__futex, + const struct timespec *abstime) + attribute_hidden; +extern int __lll_mutex_unlock_wake (int *__futex) attribute_hidden; + + +#define lll_mutex_trylock(futex) \ + ({ unsigned char __result; \ + __asm __volatile ("\ + .align 2\n\ + mova 1f,r0\n\ + nop\n\ + mov r15,r1\n\ + mov #-8,r15\n\ + 0: mov.l @%1,r2\n\ + cmp/eq r2,%3\n\ + bf 1f\n\ + mov.l %2,@%1\n\ + 1: mov r1,r15\n\ + mov #-1,%0\n\ + negc %0,%0"\ + : "=r" (__result) \ + : "r" (&(futex)), \ + "r" (LLL_MUTEX_LOCK_INITIALIZER_LOCKED), \ + "r" (LLL_MUTEX_LOCK_INITIALIZER) \ + : "r0", "r1", "r2", "t", "memory"); \ + __result; }) + +#define lll_mutex_cond_trylock(futex) \ + ({ unsigned char __result; \ + __asm __volatile ("\ + .align 2\n\ + mova 1f,r0\n\ + nop\n\ + mov r15,r1\n\ + mov #-8,r15\n\ + 0: mov.l @%1,r2\n\ + cmp/eq r2,%3\n\ + bf 1f\n\ + mov.l %2,@%1\n\ + 1: mov r1,r15\n\ + mov #-1,%0\n\ + negc %0,%0"\ + : "=r" (__result) \ + : "r" (&(futex)), \ + "r" (LLL_MUTEX_LOCK_INITIALIZER_WAITERS), \ + "r" (LLL_MUTEX_LOCK_INITIALIZER) \ + : "r0", "r1", "r2", "t", "memory"); \ + __result; }) + +#define lll_mutex_lock(futex) \ + (void) ({ int __result, *__futex = &(futex); \ + __asm __volatile ("\ + .align 2\n\ + mova 1f,r0\n\ + nop\n\ + mov r15,r1\n\ + mov #-8,r15\n\ + 0: mov.l @%2,%0\n\ + tst %0,%0\n\ + bf 1f\n\ + mov.l %1,@%2\n\ + 1: mov r1,r15"\ + : "=&r" (__result) : "r" (1), "r" (__futex) \ + : "r0", "r1", "t", "memory"); \ + if (__result) \ + __lll_mutex_lock_wait (__result, __futex); }) + +/* Special version of lll_mutex_lock which causes the unlock function to + always wakeup waiters. */ +#define lll_mutex_cond_lock(futex) \ + (void) ({ int __result, *__futex = &(futex); \ + __asm __volatile ("\ + .align 2\n\ + mova 1f,r0\n\ + nop\n\ + mov r15,r1\n\ + mov #-8,r15\n\ + 0: mov.l @%2,%0\n\ + tst %0,%0\n\ + bf 1f\n\ + mov.l %1,@%2\n\ + 1: mov r1,r15"\ + : "=&r" (__result) : "r" (2), "r" (__futex) \ + : "r0", "r1", "t", "memory"); \ + if (__result) \ + __lll_mutex_lock_wait (__result, __futex); }) + +#define lll_mutex_timedlock(futex, timeout) \ + ({ int __result, *__futex = &(futex); \ + __asm __volatile ("\ + .align 2\n\ + mova 1f,r0\n\ + nop\n\ + mov r15,r1\n\ + mov #-8,r15\n\ + 0: mov.l @%2,%0\n\ + tst %0,%0\n\ + bf 1f\n\ + mov.l %1,@%2\n\ + 1: mov r1,r15"\ + : "=&r" (__result) : "r" (1), "r" (__futex) \ + : "r0", "r1", "t", "memory"); \ + if (__result) \ + __result = __lll_mutex_timedlock_wait (__result, __futex, timeout); \ + __result; }) + +#define lll_mutex_unlock(futex) \ + (void) ({ int __result, *__futex = &(futex); \ + __asm __volatile ("\ + .align 2\n\ + mova 1f,r0\n\ + mov r15,r1\n\ + mov #-6,r15\n\ + 0: mov.l @%1,%0\n\ + add #-1,%0\n\ + mov.l %0,@%1\n\ + 1: mov r1,r15"\ + : "=&r" (__result) : "r" (__futex) \ + : "r0", "r1", "memory"); \ + if (__result) \ + __lll_mutex_unlock_wake (__futex); }) + +#define lll_mutex_islocked(futex) \ + (futex != 0) + + +/* We have a separate internal lock implementation which is not tied + to binary compatibility. */ + +/* Type for lock object. */ +typedef int lll_lock_t; + +/* Initializers for lock. */ +#define LLL_LOCK_INITIALIZER (0) +#define LLL_LOCK_INITIALIZER_LOCKED (1) + + +# ifdef NEED_SYSCALL_INST_PAD +# define SYSCALL_WITH_INST_PAD "\ + trapa #0x14; or r0,r0; or r0,r0; or r0,r0; or r0,r0; or r0,r0" +# else +# define SYSCALL_WITH_INST_PAD "\ + trapa #0x14" +# endif + +#define lll_futex_wait(futex, val) \ + do { \ + int __ignore; \ + register unsigned long __r3 __asm ("r3") = SYS_futex; \ + register unsigned long __r4 __asm ("r4") = (unsigned long) (futex); \ + register unsigned long __r5 __asm ("r5") = FUTEX_WAIT; \ + register unsigned long __r6 __asm ("r6") = (unsigned long) (val); \ + register unsigned long __r7 __asm ("r7") = 0; \ + __asm __volatile (SYSCALL_WITH_INST_PAD \ + : "=z" (__ignore) \ + : "r" (__r3), "r" (__r4), "r" (__r5), \ + "r" (__r6), "r" (__r7) \ + : "memory", "t"); \ + } while (0) + +#define lll_futex_timed_wait(futex, val, timeout) \ + ({ \ + int __status; \ + register unsigned long __r3 __asm ("r3") = SYS_futex; \ + register unsigned long __r4 __asm ("r4") = (unsigned long) (futex); \ + register unsigned long __r5 __asm ("r5") = FUTEX_WAIT; \ + register unsigned long __r6 __asm ("r6") = (unsigned long) (val); \ + register unsigned long __r7 __asm ("r7") = (timeout); \ + __asm __volatile (SYSCALL_WITH_INST_PAD \ + : "=z" (__status) \ + : "r" (__r3), "r" (__r4), "r" (__r5), \ + "r" (__r6), "r" (__r7) \ + : "memory", "t"); \ + __status; \ + }) + + +#define lll_futex_wake(futex, nr) \ + do { \ + int __ignore; \ + register unsigned long __r3 __asm ("r3") = SYS_futex; \ + register unsigned long __r4 __asm ("r4") = (unsigned long) (futex); \ + register unsigned long __r5 __asm ("r5") = FUTEX_WAKE; \ + register unsigned long __r6 __asm ("r6") = (unsigned long) (nr); \ + register unsigned long __r7 __asm ("r7") = 0; \ + __asm __volatile (SYSCALL_WITH_INST_PAD \ + : "=z" (__ignore) \ + : "r" (__r3), "r" (__r4), "r" (__r5), \ + "r" (__r6), "r" (__r7) \ + : "memory", "t"); \ + } while (0) + + +extern int lll_unlock_wake_cb (int *__futex) attribute_hidden; + + +/* The states of a lock are: + 0 - untaken + 1 - taken by one user + 2 - taken by more users */ + +#define lll_trylock(futex) lll_mutex_trylock (futex) +#define lll_lock(futex) lll_mutex_lock (futex) +#define lll_unlock(futex) lll_mutex_unlock (futex) + +#define lll_islocked(futex) \ + (futex != LLL_LOCK_INITIALIZER) + + +/* The kernel notifies a process with uses CLONE_CLEARTID via futex + wakeup when the clone terminates. The memory location contains the + thread ID while the clone is running and is reset to zero + afterwards. */ + +extern int __lll_wait_tid (int *tid) attribute_hidden; +#define lll_wait_tid(tid) \ + do { \ + __typeof (tid) *__tid = &(tid); \ + while (*__tid != 0) \ + lll_futex_wait (__tid, *__tid); \ + } while (0) + +extern int __lll_timedwait_tid (int *tid, const struct timespec *abstime) + attribute_hidden; +#define lll_timedwait_tid(tid, abstime) \ + ({ \ + int __result = 0; \ + if (tid != 0) \ + { \ + if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) \ + __result = EINVAL; \ + else \ + __result = __lll_timedwait_tid (&tid, abstime); \ + } \ + __result; }) + + +/* Conditional variable handling. */ + +extern void __lll_cond_wait (pthread_cond_t *cond) attribute_hidden; +extern int __lll_cond_timedwait (pthread_cond_t *cond, + const struct timespec *abstime) + attribute_hidden; +extern void __lll_cond_wake (pthread_cond_t *cond) attribute_hidden; +extern void __lll_cond_broadcast (pthread_cond_t *cond) attribute_hidden; + + +#define lll_cond_wait(cond) \ + __lll_cond_wait (cond) +#define lll_cond_timedwait(cond, abstime) \ + __lll_cond_timedwait (cond, abstime) +#define lll_cond_wake(cond) \ + __lll_cond_wake (cond) +#define lll_cond_broadcast(cond) \ + __lll_cond_broadcast (cond) + +#endif /* lowlevellock.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/not-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/not-cancel.h new file mode 100644 index 000000000..eb83653d3 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/not-cancel.h @@ -0,0 +1,82 @@ +/* Uncancelable versions of cancelable interfaces. Linux/NPTL version. + Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> + +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt +extern int __open_nocancel (const char *, int, ...) attribute_hidden; +extern int __close_nocancel (int) attribute_hidden; +extern int __read_nocancel (int, void *, size_t) attribute_hidden; +extern int __write_nocancel (int, const void *, size_t) attribute_hidden; +extern pid_t __waitpid_nocancel (pid_t, int *, int) attribute_hidden; + +libc_hidden_proto(__open_nocancel) +libc_hidden_proto(__close_nocancel) +libc_hidden_proto(__read_nocancel) +libc_hidden_proto(__write_nocancel) +libc_hidden_proto(__waitpid_nocancel) + +#else +#define __open_nocancel(name, ...) __open (name, __VA_ARGS__) +#define __close_nocancel(fd) __close (fd) +#define __read_nocancel(fd, buf, len) __read (fd, buf, len) +#define __write_nocancel(fd, buf, len) __write (fd, buf, len) +#define __waitpid_nocancel(pid, stat_loc, options) \ + __waitpid (pid, stat_loc, options) +#endif + +/* Uncancelable open. */ +#define open_not_cancel(name, flags, mode) \ + __open_nocancel (name, flags, mode) +#define open_not_cancel_2(name, flags) \ + __open_nocancel (name, flags) + +/* Uncancelable close. */ +#define close_not_cancel(fd) \ + __close_nocancel (fd) +#define close_not_cancel_no_status(fd) \ + (void) ({ INTERNAL_SYSCALL_DECL (err); \ + INTERNAL_SYSCALL (close, err, 1, (fd)); }) + +/* Uncancelable read. */ +#define read_not_cancel(fd, buf, n) \ + __read_nocancel (fd, buf, n) + +/* Uncancelable write. */ +#define write_not_cancel(fd, buf, n) \ + __write_nocancel (fd, buf, n) + +/* Uncancelable writev. */ +#define writev_not_cancel_no_status(fd, iov, n) \ + (void) ({ INTERNAL_SYSCALL_DECL (err); \ + INTERNAL_SYSCALL (writev, err, 3, (fd), (iov), (n)); }) + +/* Uncancelable fcntl. */ +#define fcntl_not_cancel(fd, cmd, val) \ + __fcntl_nocancel (fd, cmd, val) + +/* Uncancelable waitpid. */ +#ifdef __NR_waitpid +# define waitpid_not_cancel(pid, stat_loc, options) \ + __waitpid_nocancel (pid, stat_loc, options) +#else +# define waitpid_not_cancel(pid, stat_loc, options) \ + INLINE_SYSCALL (wait4, 4, pid, stat_loc, options, NULL) +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pt-initfini.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pt-initfini.c new file mode 100644 index 000000000..5391d5cc8 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pt-initfini.c @@ -0,0 +1,143 @@ +/* Special .init and .fini section support for SH. NPTL version. + Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it + and/or modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + In addition to the permissions in the GNU Library General Public + License, the Free Software Foundation gives you unlimited + permission to link the compiled version of this file with other + programs, and to distribute those programs without any restriction + coming from the use of this file. (The Library General Public + License restrictions do apply in other respects; for example, they + cover modification of the file, and distribution when not linked + into another program.) + + The GNU C Library is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* This file is compiled into assembly code which is then munged by a sed + script into two files: crti.s and crtn.s. + + * crti.s puts a function prologue at the beginning of the + .init and .fini sections and defines global symbols for + those addresses, so they can be called as functions. + + * crtn.s puts the corresponding function epilogues + in the .init and .fini sections. */ + +__asm__ ("\n\ +\n\ +#include \"defs.h\"\n\ +\n\ +/*@HEADER_ENDS*/\n\ +\n\ +/*@TESTS_BEGIN*/\n\ +\n\ +/*@TESTS_END*/\n\ +\n\ +/*@_init_PROLOG_BEGINS*/\n\ + .section .init\n\ + .align 5\n\ + .global _init\n\ + .type _init,@function\n\ +_init:\n\ + mov.l r12,@-r15\n\ + mov.l r14,@-r15\n\ + sts.l pr,@-r15\n\ + mova .L22,r0\n\ + mov.l .L22,r12\n\ + add r0,r12\n\ + mova .L24,r0\n\ + mov.l .L24,r1\n\ + add r0,r1\n\ + jsr @r1\n\ + nop\n\ + mova .L23,r0\n\ + mov.l .L23,r1\n\ + add r0,r1\n\ + jsr @r1\n\ + mov r15,r14\n\ + bra 1f\n\ + nop\n\ + .align 2\n\ +.L22:\n\ + .long _GLOBAL_OFFSET_TABLE_\n\ +.L23:\n\ + .long __gmon_start__@PLT\n\ +.L24:\n\ + .long __pthread_initialize_minimal_internal@PLT\n\ +1:\n\ + ALIGN\n\ + END_INIT\n\ +\n\ +/*@_init_PROLOG_ENDS*/\n\ +\n\ +/*@_init_EPILOG_BEGINS*/\n\ + .section .init\n\ + mov r14,r15\n\ + lds.l @r15+,pr\n\ + mov.l @r15+,r14\n\ + rts \n\ + mov.l @r15+,r12\n\ + END_INIT\n\ + .section .text\n\ + .align 5\n\ + .weak __gmon_start__\n\ + .type __gmon_start__,@function\n\ +__gmon_start__:\n\ + mov.l r14,@-r15\n\ + mov r15,r14\n\ + mov r14,r15\n\ + rts \n\ + mov.l @r15+,r14\n\ + \n\ +/*@_init_EPILOG_ENDS*/\n\ +\n\ +/*@_fini_PROLOG_BEGINS*/\n\ + .section .fini\n\ + .align 5\n\ + .global _fini\n\ + .type _fini,@function\n\ +_fini:\n\ + mov.l r12,@-r15\n\ + mov.l r14,@-r15\n\ + sts.l pr,@-r15\n\ + mova .L27,r0\n\ + mov.l .L27,r12\n\ + add r0,r12\n\ + mov r15,r14\n\ + ALIGN\n\ + END_FINI\n\ + bra 1f\n\ + nop\n\ + .align 2\n\ +.L27:\n\ + .long _GLOBAL_OFFSET_TABLE_\n\ +1:\n\ +/*@_fini_PROLOG_ENDS*/\n\ +\n\ +/*@_fini_EPILOG_BEGINS*/\n\ + .section .fini\n\ + mov r14,r15\n\ + lds.l @r15+,pr\n\ + mov.l @r15+,r14\n\ + rts \n\ + mov.l @r15+,r12\n\ +\n\ + END_FINI\n\ + \n\ +/*@_fini_EPILOG_ENDS*/\n\ +\n\ +/*@TRAILER_BEGINS*/\n\ +"); diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pt-vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pt-vfork.S new file mode 100644 index 000000000..54f2281d7 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pt-vfork.S @@ -0,0 +1,65 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#define _ERRNO_H 1 +#include <bits/errno.h> +#include <tcb-offsets.h> + +/* Clone the calling process, but without copying the whole address space. + The calling process is suspended until the new process exits or is + replaced by a call to `execve'. Return -1 for errors, 0 to the new process, + and the process ID of the new process to the old process. */ + +ENTRY (__vfork) + /* Save the PID value. */ + stc gbr, r2 + mov.w .L2, r0 + mov.l @(r0,r2), r4 + neg r4, r1 + mov.l r1, @(r0,r2) + + mov.w .L1, r3 + trapa #0x10 + mov r0, r1 + + /* Restore the old PID value in the parent. */ + tst r0, r0 + bt/s 2f + stc gbr, r2 + mov.w .L2, r0 + mov.l r4, @(r0,r2) + mov r1, r0 +2: + mov #-12, r2 + shad r2, r1 + not r1, r1 // r1=0 means r0 = -1 to -4095 + tst r1, r1 // i.e. error in linux + bf .Lpseudo_end + SYSCALL_ERROR_HANDLER +.Lpseudo_end: + rts + nop +.L1: + .word __NR_vfork +.L2: + .word PID - TLS_PRE_TCB_SIZE + +PSEUDO_END (__vfork) + +weak_alias (__vfork, vfork) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_barrier_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_barrier_wait.S new file mode 100644 index 000000000..608c7364c --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_barrier_wait.S @@ -0,0 +1,191 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <lowlevelbarrier.h> +#include "lowlevel-atomic.h" + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + + + .text + + .globl pthread_barrier_wait + .type pthread_barrier_wait,@function + .align 5 +pthread_barrier_wait: + mov.l r9, @-r15 + mov.l r8, @-r15 + sts.l pr, @-r15 + mov r4, r8 + + /* Get the mutex. */ + mov #0, r3 + mov #1, r4 + CMPXCHG (r3, @(MUTEX,r8), r4, r2) + bf 1f + + /* One less waiter. If this was the last one needed wake + everybody. */ +2: + mov.l @(LEFT,r8), r0 + add #-1, r0 + mov.l r0, @(LEFT,r8) + tst r0, r0 + bt 3f + + /* There are more threads to come. */ + mov.l @(CURR_EVENT,r8), r6 + + /* Release the mutex. */ + DEC (@(MUTEX,r8), r2) + tst r2, r2 + bf 6f +7: + /* Wait for the remaining threads. The call will return immediately + if the CURR_EVENT memory has meanwhile been changed. */ + mov r8, r4 +#if CURR_EVENT != 0 + add #CURR_EVENT, r4 +#endif + mov #FUTEX_WAIT, r5 + mov #0, r7 +8: + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + + /* Don't return on spurious wakeups. The syscall does not change + any register except r0 so there is no need to reload any of + them. */ + mov.l @(CURR_EVENT,r8), r0 + cmp/eq r0, r6 + bt 8b + + /* Increment LEFT. If this brings the count back to the + initial count unlock the object. */ + INC (@(LEFT,r8), r2) + mov.l @(INIT_COUNT,r8), r4 + cmp/eq r2, r4 + bf 10f + + /* Release the mutex. We cannot release the lock before + waking the waiting threads since otherwise a new thread might + arrive and gets waken up, too. */ + DEC (@(MUTEX,r8), r2) + tst r2, r2 + bf 9f + +10: + mov #0, r0 /* != PTHREAD_BARRIER_SERIAL_THREAD */ + lds.l @r15+, pr + mov.l @r15+, r8 + rts + mov.l @r15+, r9 + +3: + /* The necessary number of threads arrived. */ + mov.l @(CURR_EVENT,r8), r1 + add #1, r1 + mov.l r1, @(CURR_EVENT,r8) + + /* Wake up all waiters. The count is a signed number in the kernel + so 0x7fffffff is the highest value. */ + mov.l .Lall, r6 + mov r8, r4 +#if CURR_EVENT != 0 + add #CURR_EVENT, r4 +#endif + mov #0, r7 + mov #FUTEX_WAKE, r5 + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + + /* Increment LEFT. If this brings the count back to the + initial count unlock the object. */ + INC (@(LEFT,r8), r2) + mov.l @(INIT_COUNT,r8), r4 + cmp/eq r2, r4 + bf 5f + + /* Release the mutex. */ + DEC (@(MUTEX,r8), r2) + tst r2, r2 + bf 4f +5: + mov #-1, r0 /* == PTHREAD_BARRIER_SERIAL_THREAD */ + lds.l @r15+, pr + mov.l @r15+, r8 + rts + mov.l @r15+, r9 + +1: + mov r2, r4 + mov r8, r5 + mov.l .Lwait0, r1 + bsrf r1 + add #MUTEX, r5 +.Lwait0b: + bra 2b + nop + +4: + mov r8, r4 + mov.l .Lwake0, r1 + bsrf r1 + add #MUTEX, r4 +.Lwake0b: + bra 5b + nop + +6: + mov r6, r9 + mov r8, r4 + mov.l .Lwake1, r1 + bsrf r1 + add #MUTEX, r4 +.Lwake1b: + bra 7b + mov r9, r6 + +9: + mov r6, r9 + mov r8, r4 + mov.l .Lwake2, r1 + bsrf r1 + add #MUTEX, r4 +.Lwake2b: + bra 10b + mov r9, r6 + + .align 2 +.Lall: + .long 0x7fffffff +.Lwait0: + .long __lll_mutex_lock_wait-.Lwait0b +.Lwake0: + .long __lll_mutex_unlock_wake-.Lwake0b +.Lwake1: + .long __lll_mutex_unlock_wake-.Lwake1b +.Lwake2: + .long __lll_mutex_unlock_wake-.Lwake2b + .size pthread_barrier_wait,.-pthread_barrier_wait diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_cond_broadcast.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_cond_broadcast.S new file mode 100644 index 000000000..36eccf1e6 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_cond_broadcast.S @@ -0,0 +1,210 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <lowlevelcond.h> +#include <bits/kernel-features.h> +#include "lowlevel-atomic.h" + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 +#define FUTEX_REQUEUE 3 +#define FUTEX_CMP_REQUEUE 4 + +#define EINVAL 22 + + .text + + /* int pthread_cond_broadcast (pthread_cond_t *cond) */ + .globl __pthread_cond_broadcast + .type __pthread_cond_broadcast, @function + .align 5 +__pthread_cond_broadcast: + mov.l r10, @-r15 + mov.l r9, @-r15 + mov.l r8, @-r15 + sts.l pr, @-r15 + mov r4, r8 + + /* Get internal lock. */ + mov #0, r3 + mov #1, r4 +#if cond_lock != 0 + CMPXCHG (r3, @(cond_lock,r8), r4, r2) +#else + CMPXCHG (r3, @r8, r4, r2) +#endif + bf 1f +2: + mov.l @(total_seq+4,r8),r0 + mov.l @(total_seq,r8),r1 + mov.l @(wakeup_seq+4,r8), r2 + cmp/hi r2, r0 + bt 3f + cmp/hi r0, r2 + bt 4f + mov.l @(wakeup_seq,r8), r2 + cmp/hi r2, r1 + bf 4f + +3: + /* Cause all currently waiting threads to recognize they are + woken up. */ + mov.l r1, @(wakeup_seq,r8) + mov.l r0, @(wakeup_seq+4,r8) + mov.l r1, @(woken_seq,r8) + mov.l r0, @(woken_seq+4,r8) + mov.l @(broadcast_seq,r8), r2 + add #1, r2 + mov.l r2, @(broadcast_seq,r8) + add r1, r1 + mov r1, r10 + mov.l r10, @(cond_futex,r8) + + /* Get the address of the mutex used. */ + mov.l @(dep_mutex,r8), r9 + + /* Unlock. */ +#if cond_lock != 0 + DEC (@(cond_lock,r8), r2) +#else + DEC (@r8, r2) +#endif + tst r2, r2 + bf 7f + +8: + /* Don't use requeue for pshared condvars. */ + mov #-1, r0 + cmp/eq r0, r9 + mov r8, r4 + bt/s 9f + add #cond_futex, r4 + + /* Wake up all threads. */ + mov #FUTEX_CMP_REQUEUE, r5 + mov #1, r6 + mov #-1, r7 + shlr r7 /* r7 = 0x7fffffff */ + mov r9, r0 +# if MUTEX_FUTEX != 0 + add #MUTEX_FUTEX, r0 +# endif + mov r10, r1 + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x16 + SYSCALL_INST_PAD + + /* For any kind of error, which mainly is EAGAIN, we try again + with WAKE. The general test also covers running on old + kernels. */ + mov r0, r1 + mov #-12, r2 + shad r2, r1 + not r1, r1 + tst r1, r1 + mov r8, r4 + bt/s 9f + add #cond_futex, r4 + +10: + mov #0, r0 + lds.l @r15+, pr + mov.l @r15+, r8 + mov.l @r15+, r9 + rts + mov.l @r15+, r10 + +4: + /* Unlock. */ +#if cond_lock != 0 + DEC (@(cond_lock,r8), r2) +#else + DEC (@r8, r2) +#endif + tst r2, r2 + bf 5f +6: + mov #0, r0 + lds.l @r15+, pr + mov.l @r15+, r8 + mov.l @r15+, r9 + rts + mov.l @r15+, r10 + +1: + /* Initial locking failed. */ + mov r8, r5 +#if cond_lock != 0 + add #cond_lock, r5 +#endif + mov.l .Lmwait5, r1 + bsrf r1 + mov r2, r4 +.Lmwait5b: + bra 2b + nop + +5: + /* Unlock in loop requires wakeup. */ + mov r8, r4 +#if cond_lock != 0 + add #cond_lock, r4 +#endif + mov.l .Lmwake5, r1 + bsrf r1 + nop +.Lmwake5b: + bra 6b + nop + +7: + /* Unlock in loop requires wakeup. */ + mov r8, r4 +#if cond_lock != 0 + add #cond_lock, r4 +#endif + mov.l .Lmwake6, r1 + bsrf r1 + nop +.Lmwake6b: + bra 8b + nop + +9: + mov #FUTEX_WAKE, r5 + mov #-1, r6 + shlr r6 /* r6 = 0x7fffffff */ + mov #0, r7 + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + bra 10b + nop + + .align 2 +.Lmwait5: + .long __lll_mutex_lock_wait-.Lmwait5b +.Lmwake5: + .long __lll_mutex_unlock_wake-.Lmwake5b +.Lmwake6: + .long __lll_mutex_unlock_wake-.Lmwake6b + .size __pthread_cond_broadcast, .-__pthread_cond_broadcast +weak_alias (__pthread_cond_broadcast, pthread_cond_broadcast) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_cond_signal.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_cond_signal.S new file mode 100644 index 000000000..d92f11cbb --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_cond_signal.S @@ -0,0 +1,135 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <lowlevelcond.h> +#include <bits/kernel-features.h> +#include "lowlevel-atomic.h" + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 +#define FUTEX_REQUEUE 3 + +#define EINVAL 22 + + .text + + /* int pthread_cond_signal (pthread_cond_t *cond) */ + .globl __pthread_cond_signal + .type __pthread_cond_signal, @function + .align 5 +__pthread_cond_signal: + mov.l r8, @-r15 + sts.l pr, @-r15 + mov r4, r8 + + /* Get internal lock. */ + mov #0, r3 + mov #1, r4 +#if cond_lock != 0 + CMPXCHG (r3, @(cond_lock,r8), r4, r2) +#else + CMPXCHG (r3, @r8, r4, r2) +#endif + bf 1f +2: + mov.l @(total_seq+4,r8),r0 + mov.l @(total_seq,r8),r1 + mov.l @(wakeup_seq+4,r8), r2 + cmp/hi r2, r0 + bt 3f + cmp/hi r0, r2 + bt 4f + mov.l @(wakeup_seq,r8), r2 + cmp/hi r2, r1 + bf 4f + +3: + /* Bump the wakeup number. */ + mov #1, r2 + mov #0, r3 + clrt + mov.l @(wakeup_seq,r8),r0 + mov.l @(wakeup_seq+4,r8),r1 + addc r2, r0 + addc r3, r1 + mov.l r0,@(wakeup_seq,r8) + mov.l r1,@(wakeup_seq+4,r8) + mov.l @(cond_futex,r8),r0 + add r2, r0 + mov.l r0,@(cond_futex,r8) + + /* Wake up one thread. */ + mov r8, r4 + add #cond_futex, r4 + mov #FUTEX_WAKE, r5 + mov #1, r6 + mov #0, r7 + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + +4: + /* Unlock. */ +#if cond_lock != 0 + DEC (@(cond_lock,r8), r2) +#else + DEC (@r8, r2) +#endif + tst r2, r2 + bf 5f +6: + mov #0, r0 + lds.l @r15+, pr + rts + mov.l @r15+, r8 + +1: + /* Initial locking failed. */ + mov r8, r5 +#if cond_lock != 0 + add #cond_lock, r5 +#endif + mov.l .Lmwait4, r1 + bsrf r1 + mov r2, r4 +.Lmwait4b: + bra 2b + nop + +5: + /* Unlock in loop requires wakeup. */ + mov r8, r4 +#if cond_lock != 0 + add #cond_lock, r4 +#endif + mov.l .Lmwake4, r1 + bsrf r1 + nop +.Lmwake4b: + bra 6b + nop + + .align 2 +.Lmwait4: + .long __lll_mutex_lock_wait-.Lmwait4b +.Lmwake4: + .long __lll_mutex_unlock_wake-.Lmwake4b + .size __pthread_cond_signal, .-__pthread_cond_signal +weak_alias (__pthread_cond_signal, pthread_cond_signal) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_cond_timedwait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_cond_timedwait.S new file mode 100644 index 000000000..5812488b2 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_cond_timedwait.S @@ -0,0 +1,768 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <lowlevelcond.h> +#include <pthread-errnos.h> +#include "lowlevel-atomic.h" + +#define SYS_gettimeofday __NR_gettimeofday + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + + + .text + +/* int pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex, + const struct timespec *abstime) */ + .globl __pthread_cond_timedwait + .type __pthread_cond_timedwait, @function + .align 5 +__pthread_cond_timedwait: +.LSTARTCODE: + mov.l r8, @-r15 +.Lpush_r8: + mov.l r9, @-r15 +.Lpush_r9: + mov.l r10, @-r15 +.Lpush_r10: + mov.l r11, @-r15 +.Lpush_r11: + mov.l r12, @-r15 +.Lpush_r12: + mov.l r13, @-r15 +.Lpush_r13: + sts.l pr, @-r15 +.Lpush_pr: + add #-64, r15 +.Lalloc: + mov r4, r8 + mov r5, r9 + mov r6, r13 +#ifdef __PIC__ + mova .Lgot0, r0 + mov.l .Lgot0, r12 + add r0, r12 +#endif + + mov.l @(4,r13), r0 + mov.l .L1g, r1 + cmp/hs r1, r0 + bf 0f + bra 18f + mov #EINVAL, r0 +0: + /* Get internal lock. */ + mov #0, r3 + mov #1, r4 +#if cond_lock != 0 + CMPXCHG (r3, @(cond_lock,r8), r4, r2) +#else + CMPXCHG (r3, @r8, r4, r2) +#endif + bt 2f + bra 1f + nop +#ifdef __PIC__ + .align 2 +.Lgot0: + .long _GLOBAL_OFFSET_TABLE_ +#endif + +2: + /* Store the reference to the mutex. If there is already a + different value in there this is a bad user bug. */ + mov.l @(dep_mutex,r8),r0 + cmp/eq #-1, r0 + bt 17f + mov.l r9, @(dep_mutex,r8) + +17: + /* Unlock the mutex. */ + mov.l .Lmunlock1, r1 + mov #0, r5 + bsrf r1 + mov r9, r4 +.Lmunlock1b: + + tst r0, r0 + bt 0f + bra 16f + nop +0: + mov #1, r2 + mov #0, r3 + + clrt + mov.l @(total_seq,r8),r0 + mov.l @(total_seq+4,r8),r1 + addc r2, r0 + addc r3, r1 + mov.l r0,@(total_seq,r8) + mov.l r1,@(total_seq+4,r8) + mov.l @(cond_futex,r8), r0 + add r2, r0 + mov.l r0, @(cond_futex,r8) + mov #(1 << clock_bits), r2 + mov.l @(cond_nwaiters,r8), r0 + add r2, r0 + mov.l r0, @(cond_nwaiters,r8) + + /* Get and store current wakeup_seq value. */ + mov.l @(wakeup_seq,r8), r10 + mov.l @(wakeup_seq+4,r8), r11 + mov.l @(broadcast_seq,r8), r0 + mov.l r0, @(4,r15) + +8: + /* Get current time. */ +#ifdef __NR_clock_gettime + /* Get the clock number. */ + mov.l @(cond_nwaiters,r8), r4 + mov #((1 << clock_bits) - 1), r0 + and r0, r4 + /* Only clocks 0 and 1 are allowed. Both are handled in the + kernel. */ + mov r15, r5 + add #16, r5 + mov.w .L__NR_clock_gettime, r3 + trapa #0x12 + SYSCALL_INST_PAD +# ifndef __ASSUME_POSIX_TIMERS + cmp/eq #-ENOSYS, r0 + bt 19f +# endif + + /* Compute relative timeout. */ + mov.l @r13, r2 + mov.l @(4,r13), r3 + mov.l @(16,r15), r0 + bra 0f + mov.l @(20,r15), r1 +.L__NR_clock_gettime: + .word __NR_clock_gettime + +# ifndef __ASSUME_POSIX_TIMERS +19: + mov r15, r4 + add #16, r4 + mov #0, r5 + mov #SYS_gettimeofday, r3 + trapa #0x12 + SYSCALL_INST_PAD + + /* Compute relative timeout. */ + mov.l @(20,r15), r0 + mov.w .L1k, r1 + dmulu.l r0, r1 /* Micro seconds to nano seconds. */ + mov.l @r13, r2 + mov.l @(4,r13), r3 + mov.l @(16,r15), r0 + sts macl, r1 +#endif +0: +#else + mov r15, r4 + add #16, r4 + mov #0, r5 + mov #SYS_gettimeofday, r3 + trapa #0x12 + SYSCALL_INST_PAD + + /* Compute relative timeout. */ + mov.l @(20,r15), r0 + mov.w .L1k, r1 + dmulu.l r0, r1 /* Micro seconds to nano seconds. */ + mov.l @r13, r2 + mov.l @(4,r13), r3 + mov.l @(16,r15), r0 + sts macl, r1 +#endif + sub r0, r2 + clrt + subc r1, r3 + bf 12f + mov.l .L1g, r1 + add r1, r3 + add #-1, r2 +12: + mov #-ETIMEDOUT, r1 + mov.l r1, @(12,r15) + cmp/pz r2 + bf 6f /* Time is already up. */ + + /* Store relative timeout. */ + mov.l r2, @(16,r15) + mov.l r3, @(20,r15) + mov.l @(cond_futex,r8), r1 + mov.l r1, @(8,r15) + + /* Unlock. */ +#if cond_lock != 0 + DEC (@(cond_lock,r8), r2) +#else + DEC (@r8, r2) +#endif + tst r2, r2 + bt 4f + bra 3f + nop +4: +.LcleanupSTART: + mov.l .Lenable1, r1 + bsrf r1 + nop +.Lenable1b: + mov.l r0, @r15 + + mov r15, r7 + add #16, r7 + mov #FUTEX_WAIT, r5 + mov.l @(8,r15), r6 + mov r8, r4 + add #cond_futex, r4 + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + mov.l r0, @(12,r15) + + mov.l .Ldisable1, r1 + bsrf r1 + mov.l @r15, r4 +.Ldisable1b: +.LcleanupEND: + + /* Lock. */ + mov #0, r3 + mov #1, r4 +#if cond_lock != 0 + CMPXCHG (r3, @(cond_lock,r8), r4, r2) +#else + CMPXCHG (r3, @r8, r4, r2) +#endif + bf 5f +6: + mov.l @(broadcast_seq,r8), r0 + mov.l @(4,r15), r1 + cmp/eq r0, r1 + bf 23f + + mov.l @(woken_seq,r8), r0 + mov.l @(woken_seq+4,r8), r1 + + mov.l @(wakeup_seq,r8), r2 + mov.l @(wakeup_seq+4,r8), r3 + + cmp/eq r3, r11 + bf 7f + cmp/eq r2, r10 + bt 15f +7: + cmp/eq r1, r3 + bf 9f + cmp/eq r0, r2 + bf 9f +15: + mov.l @(12,r15),r0 + cmp/eq #-ETIMEDOUT, r0 + bf 8b + + mov #1, r2 + mov #0, r3 + + clrt + mov.l @(wakeup_seq,r8),r0 + mov.l @(wakeup_seq+4,r8),r1 + addc r2, r0 + addc r3, r1 + mov.l r0,@(wakeup_seq,r8) + mov.l r1,@(wakeup_seq+4,r8) + mov.l @(cond_futex,r8),r0 + add r2, r0 + mov.l r0,@(cond_futex,r8) + mov #ETIMEDOUT, r0 + bra 14f + mov.l r0, @(24,r15) + +23: + mov #0, r0 + bra 24f + mov.l r0, @(24,r15) + +9: + mov #0, r0 + mov.l r0, @(24,r15) +14: + mov #1, r2 + mov #0, r3 + + clrt + mov.l @(woken_seq,r8),r0 + mov.l @(woken_seq+4,r8),r1 + addc r2, r0 + addc r3, r1 + mov.l r0,@(woken_seq,r8) + mov.l r1,@(woken_seq+4,r8) + +24: + mov #(1 << clock_bits), r2 + mov.l @(cond_nwaiters,r8),r0 + sub r2, r0 + mov.l r0,@(cond_nwaiters,r8) + + /* Wake up a thread which wants to destroy the condvar object. */ + mov.l @(total_seq,r8),r0 + mov.l @(total_seq+4,r8),r1 + and r1, r0 + not r0, r0 + cmp/eq #0, r0 + bf/s 25f + mov #((1 << clock_bits) - 1), r1 + not r1, r1 + mov.l @(cond_nwaiters,r8),r0 + tst r1, r0 + bf 25f + + mov r8, r4 + add #cond_nwaiters, r4 + mov #FUTEX_WAKE, r5 + mov #1, r6 + mov #0, r7 + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + +25: +#if cond_lock != 0 + DEC (@(cond_lock,r8), r2) +#else + DEC (@r8, r2) +#endif + tst r2, r2 + bf 10f + +11: + mov r9, r4 + mov.l .Lmlocki1, r1 + bsrf r1 + nop +.Lmlocki1b: + + /* We return the result of the mutex_lock operation if it failed. */ + tst r0, r0 + bf 18f + mov.l @(24,r15), r0 + +18: + add #64, r15 + lds.l @r15+, pr + mov.l @r15+, r13 + mov.l @r15+, r12 + mov.l @r15+, r11 + mov.l @r15+, r10 + mov.l @r15+, r9 + rts + mov.l @r15+, r8 + +.L1k: + .word 1000 + .align 2 +.Lmunlock1: + .long __pthread_mutex_unlock_usercnt-.Lmunlock1b +.Lenable1: + .long __pthread_enable_asynccancel-.Lenable1b +.Ldisable1: + .long __pthread_disable_asynccancel-.Ldisable1b +.Lmlocki1: + .long __pthread_mutex_cond_lock-.Lmlocki1b +.L1g: + .long 1000000000 + +1: + /* Initial locking failed. */ + mov r8, r5 +#if cond_lock != 0 + add #cond_lock, r5 +#endif + mov.l .Lmwait2, r1 + bsrf r1 + mov r2, r4 +.Lmwait2b: + bra 2b + nop + +3: + /* Unlock in loop requires wakeup. */ + mov r8, r4 +#if cond_lock != 0 + add #cond_lock, r4 +#endif + mov.l .Lmwake2, r1 + bsrf r1 + nop +.Lmwake2b: + bra 4b + nop + +5: + /* Locking in loop failed. */ + mov r8, r5 +#if cond_lock != 0 + add #cond_lock, r5 +#endif + mov.l .Lmwait3, r1 + bsrf r1 + mov r2, r4 +.Lmwait3b: + bra 6b + nop + +10: + /* Unlock after loop requires wakeup. */ + mov r8, r4 +#if cond_lock != 0 + add #cond_lock, r4 +#endif + mov.l .Lmwake3, r1 + bsrf r1 + nop +.Lmwake3b: + bra 11b + nop + +16: + /* The initial unlocking of the mutex failed. */ + mov.l r0, @(24,r15) +#if cond_lock != 0 + DEC (@(cond_lock,r8), r2) +#else + DEC (@r8, r2) +#endif + tst r2, r2 + bf 17f + + mov r8, r4 +#if cond_lock != 0 + add #cond_lock, r4 +#endif + mov.l .Lmwake4, r1 + bsrf r1 + nop +.Lmwake4b: +17: + bra 18b + mov.l @(24,r15), r0 + + .align 2 +.Lmwait2: + .long __lll_mutex_lock_wait-.Lmwait2b +.Lmwake2: + .long __lll_mutex_unlock_wake-.Lmwake2b +.Lmwait3: + .long __lll_mutex_lock_wait-.Lmwait3b +.Lmwake3: + .long __lll_mutex_unlock_wake-.Lmwake3b +.Lmwake4: + .long __lll_mutex_unlock_wake-.Lmwake4b + .size __pthread_cond_timedwait, .-__pthread_cond_timedwait +weak_alias (__pthread_cond_timedwait, pthread_cond_timedwait) + + + .type __condvar_tw_cleanup, @function +__condvar_tw_cleanup: + mov r4, r11 + + /* Get internal lock. */ + mov #0, r3 + mov #1, r4 +#if cond_lock != 0 + CMPXCHG (r3, @(cond_lock,r8), r4, r2) +#else + CMPXCHG (r3, @r8, r4, r2) +#endif + bt 1f + nop + + mov r8, r5 +#if cond_lock != 0 + add #cond_lock, r5 +#endif + mov.l .Lmwait5, r1 + bsrf r1 + mov r2, r4 +.Lmwait5b: + +1: + mov.l @(broadcast_seq,r8), r0 + mov.l @(4,r15), r1 + cmp/eq r0, r1 + bf 3f + + mov #1, r2 + mov #0, r3 + + clrt + mov.l @(wakeup_seq,r8),r0 + mov.l @(wakeup_seq+4,r8),r1 + addc r2, r0 + addc r3, r1 + mov.l r0,@(wakeup_seq,r8) + mov.l r1,@(wakeup_seq+4,r8) + mov.l @(cond_futex,r8),r0 + add r2, r0 + mov.l r0,@(cond_futex,r8) + + clrt + mov.l @(woken_seq,r8),r0 + mov.l @(woken_seq+4,r8),r1 + addc r2, r0 + addc r3, r1 + mov.l r0,@(woken_seq,r8) + mov.l r1,@(woken_seq+4,r8) + +3: + mov #(1 << clock_bits), r2 + mov.l @(cond_nwaiters,r8),r0 + sub r2, r0 + mov.l r0,@(cond_nwaiters,r8) + + /* Wake up a thread which wants to destroy the condvar object. */ + mov #0, r10 + mov.l @(total_seq,r8),r0 + mov.l @(total_seq+4,r8),r1 + and r1, r0 + not r0, r0 + cmp/eq #0, r0 + bf/s 4f + mov #((1 << clock_bits) - 1), r1 + not r1, r1 + mov.l @(cond_nwaiters,r8),r0 + tst r1, r0 + bf 4f + + mov r8, r4 + add #cond_nwaiters, r4 + mov #FUTEX_WAKE, r5 + mov #1, r6 + mov #0, r7 + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + mov #1, r10 + +4: +#if cond_lock != 0 + DEC (@(cond_lock,r8), r2) +#else + DEC (@r8, r2) +#endif + tst r2, r2 + bt 2f + + mov r8, r4 +#if cond_lock != 0 + add #cond_lock, r4 +#endif + mov.l .Lmwake5, r1 + bsrf r1 + nop +.Lmwake5b: + +2: + /* Wake up all waiters to make sure no signal gets lost. */ + tst r10, r10 + bf/s 5f + mov r8, r4 + add #cond_futex, r4 + mov #FUTEX_WAKE, r5 + mov #-1, r6 + shlr r6 /* r6 = 0x7fffffff */ + mov #0, r7 + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + +5: + mov.l .Lmlocki5, r1 + bsrf r1 + mov r9, r4 +.Lmlocki5b: + +.LcallUR: + mov.l .Lresume, r1 +#ifdef __PIC__ + add r12, r1 +#endif + jsr @r1 + mov r11, r4 + sleep + + .align 2 +.Lmwait5: + .long __lll_mutex_lock_wait-.Lmwait5b +.Lmwake5: + .long __lll_mutex_unlock_wake-.Lmwake5b +.Lmlocki5: + .long __pthread_mutex_cond_lock-.Lmlocki5b +.Lresume: +#ifdef __PIC__ + .long _Unwind_Resume@GOTOFF +#else + .long _Unwind_Resume +#endif +.LENDCODE: + .size __condvar_tw_cleanup, .-__condvar_tw_cleanup + + + .section .gcc_except_table,"a",@progbits +.LexceptSTART: + .byte 0xff ! @LPStart format (omit) + .byte 0xff ! @TType format (omit) + .byte 0x0b ! call-site format + ! DW_EH_PE_sdata4 + .uleb128 .Lcstend-.Lcstbegin +.Lcstbegin: + .ualong .LcleanupSTART-.LSTARTCODE + .ualong .LcleanupEND-.LcleanupSTART + .ualong __condvar_tw_cleanup-.LSTARTCODE + .uleb128 0 + .ualong .LcallUR-.LSTARTCODE + .ualong .LENDCODE-.LcallUR + .ualong 0 + .uleb128 0 +.Lcstend: + + .section .eh_frame,"a",@progbits +.LSTARTFRAME: + .ualong .LENDCIE-.LSTARTCIE ! Length of the CIE. +.LSTARTCIE: + .ualong 0 ! CIE ID. + .byte 1 ! Version number. +#ifdef SHARED + .string "zPLR" ! NUL-terminated augmentation + ! string. +#else + .string "zPL" ! NUL-terminated augmentation + ! string. +#endif + .uleb128 1 ! Code alignment factor. + .sleb128 -4 ! Data alignment factor. + .byte 0x11 ! Return address register + ! column. +#ifdef SHARED + .uleb128 7 ! Augmentation value length. + .byte 0x9b ! Personality: DW_EH_PE_pcrel + ! + DW_EH_PE_sdata4 + ! + DW_EH_PE_indirect + .ualong DW.ref.__gcc_personality_v0-. + .byte 0x1b ! LSDA Encoding: DW_EH_PE_pcrel + ! + DW_EH_PE_sdata4. + .byte 0x1b ! FDE Encoding: DW_EH_PE_pcrel + ! + DW_EH_PE_sdata4. +#else + .uleb128 6 ! Augmentation value length. + .byte 0x0 ! Personality: absolute + .ualong __gcc_personality_v0 + .byte 0x0 ! LSDA Encoding: absolute +#endif + .byte 0x0c ! DW_CFA_def_cfa + .uleb128 0xf + .uleb128 0 + .align 2 +.LENDCIE: + + .ualong .LENDFDE-.LSTARTFDE ! Length of the FDE. +.LSTARTFDE: + .ualong .LSTARTFDE-.LSTARTFRAME ! CIE pointer. +#ifdef SHARED + .ualong .LSTARTCODE-. ! PC-relative start address + ! of the code. +#else + .ualong .LSTARTCODE ! Start address of the code. +#endif + .ualong .LENDCODE-.LSTARTCODE ! Length of the code. + .uleb128 4 ! Augmentation size +#ifdef SHARED + .ualong .LexceptSTART-. +#else + .ualong .LexceptSTART +#endif + .byte 0x4 + .ualong .Lpush_r8-.LSTARTCODE + .byte 0xe + .uleb128 4 + .byte 0x88 + .uleb128 1 + .byte 0x4 + .ualong .Lpush_r9-.Lpush_r8 + .byte 0xe + .uleb128 8 + .byte 0x89 + .uleb128 2 + .byte 0x4 + .ualong .Lpush_r10-.Lpush_r9 + .byte 0xe + .uleb128 12 + .byte 0x8a + .uleb128 3 + .byte 0x4 + .ualong .Lpush_r11-.Lpush_r10 + .byte 0xe + .uleb128 16 + .byte 0x8b + .uleb128 4 + .byte 0x4 + .ualong .Lpush_r12-.Lpush_r11 + .byte 0xe + .uleb128 20 + .byte 0x8c + .uleb128 5 + .byte 0x4 + .ualong .Lpush_r13-.Lpush_r12 + .byte 0xe + .uleb128 24 + .byte 0x8d + .uleb128 6 + .byte 0x4 + .ualong .Lpush_pr-.Lpush_r13 + .byte 0xe + .uleb128 28 + .byte 0x91 + .uleb128 7 + .byte 0x4 + .ualong .Lalloc-.Lpush_pr + .byte 0xe + .uleb128 92 + .align 2 +.LENDFDE: + +#ifdef SHARED + .hidden DW.ref.__gcc_personality_v0 + .weak DW.ref.__gcc_personality_v0 + .section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits + .align 4 + .type DW.ref.__gcc_personality_v0, @object + .size DW.ref.__gcc_personality_v0, 4 +DW.ref.__gcc_personality_v0: + .long __gcc_personality_v0 +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_cond_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_cond_wait.S new file mode 100644 index 000000000..c7df9bf86 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_cond_wait.S @@ -0,0 +1,625 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <lowlevelcond.h> +#include "lowlevel-atomic.h" + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + + + .text + +/* int pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex) */ + .globl __pthread_cond_wait + .type __pthread_cond_wait, @function + .align 5 +__pthread_cond_wait: +.LSTARTCODE: + mov.l r8, @-r15 +.Lpush_r8: + mov.l r9, @-r15 +.Lpush_r9: + mov.l r10, @-r15 +.Lpush_r10: + mov.l r11, @-r15 +.Lpush_r11: + mov.l r12, @-r15 +.Lpush_r12: + sts.l pr, @-r15 +.Lpush_pr: + add #-48, r15 +.Lalloc: + mov r4, r8 + mov r5, r9 +#ifdef __PIC__ + mova .Lgot0, r0 + mov.l .Lgot0, r12 + add r0, r12 +#endif + + /* Get internal lock. */ + mov #0, r3 + mov #1, r4 +#if cond_lock != 0 + CMPXCHG (r3, @(cond_lock,r8), r4, r2) +#else + CMPXCHG (r3, @r8, r4, r2) +#endif + bt 2f + bra 1f + nop +#ifdef __PIC__ + .align 2 +.Lgot0: + .long _GLOBAL_OFFSET_TABLE_ +#endif + +2: + /* Store the reference to the mutex. If there is already a + different value in there this is a bad user bug. */ + mov.l @(dep_mutex,r8),r0 + cmp/eq #-1, r0 + bt 15f + mov.l r9, @(dep_mutex,r8) + +15: + /* Unlock the mutex. */ + mov.l .Lmunlock0, r1 + mov #0, r5 + bsrf r1 + mov r9, r4 +.Lmunlock0b: + + tst r0, r0 + bt 0f + bra 12f + nop +0: + mov #1, r2 + mov #0, r3 + + clrt + mov.l @(total_seq,r8),r0 + mov.l @(total_seq+4,r8),r1 + addc r2, r0 + addc r3, r1 + mov.l r0,@(total_seq,r8) + mov.l r1,@(total_seq+4,r8) + mov.l @(cond_futex,r8),r0 + add r2, r0 + mov.l r0,@(cond_futex,r8) + mov #(1 << clock_bits), r2 + mov.l @(cond_nwaiters,r8), r0 + add r2, r0 + mov.l r0, @(cond_nwaiters,r8) + + /* Get and store current wakeup_seq value. */ + mov.l @(wakeup_seq,r8), r10 + mov.l @(wakeup_seq+4,r8), r11 + mov.l @(broadcast_seq,r8), r0 + mov.l r0, @(4,r15) + +8: + mov.l @(cond_futex,r8),r0 + mov.l r0, @(8,r15) + + /* Unlock. */ +#if cond_lock != 0 + DEC (@(cond_lock,r8), r2) +#else + DEC (@r8, r2) +#endif + tst r2, r2 + bf 3f +4: +.LcleanupSTART: + mov.l .Lenable0, r1 + bsrf r1 + nop +.Lenable0b: + mov.l r0, @r15 + + mov #0, r7 + mov #FUTEX_WAIT, r5 + mov.l @(8,r15), r6 + mov r8, r4 + add #cond_futex, r4 + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + + mov.l .Ldisable0, r1 + bsrf r1 + mov.l @r15, r4 +.Ldisable0b: +.LcleanupEND: + + /* Lock. */ + mov #0, r3 + mov #1, r4 +#if cond_lock != 0 + CMPXCHG (r3, @(cond_lock,r8), r4, r2) +#else + CMPXCHG (r3, @r8, r4, r2) +#endif + bf 5f +6: + mov.l @(broadcast_seq,r8), r0 + mov.l @(4,r15), r1 + cmp/eq r0, r1 + bf 16f + + mov.l @(woken_seq,r8), r0 + mov.l @(woken_seq+4,r8), r1 + + mov.l @(wakeup_seq,r8), r2 + mov.l @(wakeup_seq+4,r8), r3 + + cmp/eq r3, r11 + bf 7f + cmp/eq r2, r10 + bt 8b +7: + cmp/eq r1, r3 + bf 9f + cmp/eq r0, r2 + bt 8b +9: + mov #1, r2 + mov #0, r3 + + clrt + mov.l @(woken_seq,r8),r0 + mov.l @(woken_seq+4,r8),r1 + addc r2, r0 + addc r3, r1 + mov.l r0,@(woken_seq,r8) + mov.l r1,@(woken_seq+4,r8) + +16: + mov #(1 << clock_bits), r2 + mov.l @(cond_nwaiters,r8),r0 + sub r2, r0 + mov.l r0,@(cond_nwaiters,r8) + + /* Wake up a thread which wants to destroy the condvar object. */ + mov.l @(total_seq,r8),r0 + mov.l @(total_seq+4,r8),r1 + and r1, r0 + not r0, r0 + cmp/eq #0, r0 + bf/s 17f + mov #((1 << clock_bits) - 1), r1 + not r1, r1 + mov.l @(cond_nwaiters,r8),r0 + tst r1, r0 + bf 17f + + mov r8, r4 + add #cond_nwaiters, r4 + mov #FUTEX_WAKE, r5 + mov #1, r6 + mov #0, r7 + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + +17: +#if cond_lock != 0 + DEC (@(cond_lock,r8), r2) +#else + DEC (@r8, r2) +#endif + tst r2, r2 + bf 10f + +11: + mov.l .Lmlocki0, r1 + bsrf r1 + mov r9, r4 +.Lmlocki0b: + /* We return the result of the mutex_lock operation. */ + +14: + add #48, r15 + lds.l @r15+, pr + mov.l @r15+, r12 + mov.l @r15+, r11 + mov.l @r15+, r10 + mov.l @r15+, r9 + rts + mov.l @r15+, r8 + + .align 2 +.Lmunlock0: + .long __pthread_mutex_unlock_usercnt-.Lmunlock0b +.Lenable0: + .long __pthread_enable_asynccancel-.Lenable0b +.Ldisable0: + .long __pthread_disable_asynccancel-.Ldisable0b +.Lmlocki0: + .long __pthread_mutex_cond_lock-.Lmlocki0b + +1: + /* Initial locking failed. */ + mov r8, r5 +#if cond_lock != 0 + add #cond_lock, r5 +#endif + mov.l .Lmwait0, r1 + bsrf r1 + mov r2, r4 +.Lmwait0b: + bra 2b + nop +3: + /* Unlock in loop requires waekup. */ + mov r8, r4 +#if cond_lock != 0 + add #cond_lock, r4 +#endif + mov.l .Lmwake0, r1 + bsrf r1 + nop +.Lmwake0b: + bra 4b + nop + +5: + /* Locking in loop failed. */ + mov r8, r5 +#if cond_lock != 0 + add #cond_lock, r5 +#endif + mov.l .Lmwait1, r1 + bsrf r1 + mov r2, r4 +.Lmwait1b: + bra 6b + nop + +10: + /* Unlock after loop requires wakeup. */ + mov r8, r4 +#if cond_lock != 0 + add #cond_lock, r4 +#endif + mov.l .Lmwake1, r1 + bsrf r1 + nop +.Lmwake1b: + bra 11b + nop + +12: + /* The initial unlocking of the mutex failed. */ + mov.l r0, @(12,r15) +#if cond_lock != 0 + DEC (@(cond_lock,r8), r2) +#else + DEC (@r8, r2) +#endif + tst r2, r2 + bf 13f + + mov r8, r4 +#if cond_lock != 0 + add #cond_lock, r4 +#endif + mov.l .Lmwake2, r1 + bsrf r1 + nop +.Lmwake2b: + +13: + bra 14b + mov.l @(12,r15), r0 + + .align 2 +.Lmwait0: + .long __lll_mutex_lock_wait-.Lmwait0b +.Lmwake0: + .long __lll_mutex_unlock_wake-.Lmwake0b +.Lmwait1: + .long __lll_mutex_lock_wait-.Lmwait1b +.Lmwake1: + .long __lll_mutex_unlock_wake-.Lmwake1b +.Lmwake2: + .long __lll_mutex_unlock_wake-.Lmwake2b + .size __pthread_cond_wait, .-__pthread_cond_wait +weak_alias (__pthread_cond_wait, pthread_cond_wait) + + + .type __condvar_w_cleanup, @function +__condvar_w_cleanup: + mov r4, r11 + + /* Get internal lock. */ + mov #0, r3 + mov #1, r4 +#if cond_lock != 0 + CMPXCHG (r3, @(cond_lock,r8), r4, r2) +#else + CMPXCHG (r3, @r8, r4, r2) +#endif + bt 1f + nop + + mov r8, r5 +#if cond_lock != 0 + add #cond_lock, r5 +#endif + mov.l .Lmwait3, r1 + bsrf r1 + mov r2, r4 +.Lmwait3b: + +1: + mov.l @(broadcast_seq,r8), r0 + mov.l @(4,r15), r1 + cmp/eq r0, r1 + bf 3f + + mov #1, r2 + mov #0, r3 + + clrt + mov.l @(wakeup_seq,r8),r0 + mov.l @(wakeup_seq+4,r8),r1 + addc r2, r0 + addc r3, r1 + mov.l r0,@(wakeup_seq,r8) + mov.l r1,@(wakeup_seq+4,r8) + mov.l @(cond_futex,r8),r0 + add r2, r0 + mov.l r0,@(cond_futex,r8) + + clrt + mov.l @(woken_seq,r8),r0 + mov.l @(woken_seq+4,r8),r1 + addc r2, r0 + addc r3, r1 + mov.l r0,@(woken_seq,r8) + mov.l r1,@(woken_seq+4,r8) + +3: + mov #(1 << clock_bits), r2 + mov.l @(cond_nwaiters,r8),r0 + sub r2, r0 + mov.l r0,@(cond_nwaiters,r8) + + /* Wake up a thread which wants to destroy the condvar object. */ + mov #0, r10 + mov.l @(total_seq,r8),r0 + mov.l @(total_seq+4,r8),r1 + and r1, r0 + not r0, r0 + cmp/eq #0, r0 + bf/s 4f + mov #((1 << clock_bits) - 1), r1 + not r1, r1 + mov.l @(cond_nwaiters,r8),r0 + tst r1, r0 + bf 4f + + mov r8, r4 + add #cond_nwaiters, r4 + mov #FUTEX_WAKE, r5 + mov #1, r6 + mov #0, r7 + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + mov #1, r10 + +4: +#if cond_lock != 0 + DEC (@(cond_lock,r8), r2) +#else + DEC (@r8, r2) +#endif + tst r2, r2 + bt 2f + + mov r8, r4 +#if cond_lock != 0 + add #cond_lock, r4 +#endif + mov.l .Lmwake3, r1 + bsrf r1 + nop +.Lmwake3b: + +2: + /* Wake up all waiters to make sure no signal gets lost. */ + tst r10, r10 + bf/s 5f + mov r8, r4 + add #cond_futex, r4 + mov #FUTEX_WAKE, r5 + mov #-1, r6 + shlr r6 /* r6 = 0x7fffffff */ + mov #0, r7 + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + +5: + mov.l .Lmlocki3, r1 + bsrf r1 + mov r9, r4 +.Lmlocki3b: + +.LcallUR: + mov.l .Lresume, r1 +#ifdef __PIC__ + add r12, r1 +#endif + jsr @r1 + mov r11, r4 + sleep + + .align 2 +.Lmwait3: + .long __lll_mutex_lock_wait-.Lmwait3b +.Lmwake3: + .long __lll_mutex_unlock_wake-.Lmwake3b +.Lmlocki3: + .long __pthread_mutex_cond_lock-.Lmlocki3b +.Lresume: +#ifdef __PIC__ + .long _Unwind_Resume@GOTOFF +#else + .long _Unwind_Resume +#endif +.LENDCODE: + .size __condvar_w_cleanup, .-__condvar_w_cleanup + + + .section .gcc_except_table,"a",@progbits +.LexceptSTART: + .byte 0xff ! @LPStart format (omit) + .byte 0xff ! @TType format (omit) + .byte 0x0b ! call-site format + ! DW_EH_PE_sdata4 + .uleb128 .Lcstend-.Lcstbegin +.Lcstbegin: + .ualong .LcleanupSTART-.LSTARTCODE + .ualong .LcleanupEND-.LcleanupSTART + .ualong __condvar_w_cleanup-.LSTARTCODE + .uleb128 0 + .ualong .LcallUR-.LSTARTCODE + .ualong .LENDCODE-.LcallUR + .ualong 0 + .uleb128 0 +.Lcstend: + + .section .eh_frame,"a",@progbits +.LSTARTFRAME: + .ualong .LENDCIE-.LSTARTCIE ! Length of the CIE. +.LSTARTCIE: + .ualong 0 ! CIE ID. + .byte 1 ! Version number. +#ifdef SHARED + .string "zPLR" ! NUL-terminated augmentation + ! string. +#else + .string "zPL" ! NUL-terminated augmentation + ! string. +#endif + .uleb128 1 ! Code alignment factor. + .sleb128 -4 ! Data alignment factor. + .byte 0x11 ! Return address register + ! column. +#ifdef SHARED + .uleb128 7 ! Augmentation value length. + .byte 0x9b ! Personality: DW_EH_PE_pcrel + ! + DW_EH_PE_sdata4 + ! + DW_EH_PE_indirect + .ualong DW.ref.__gcc_personality_v0-. + .byte 0x1b ! LSDA Encoding: DW_EH_PE_pcrel + ! + DW_EH_PE_sdata4. + .byte 0x1b ! FDE Encoding: DW_EH_PE_pcrel + ! + DW_EH_PE_sdata4. +#else + .uleb128 6 ! Augmentation value length. + .byte 0x0 ! Personality: absolute + .ualong __gcc_personality_v0 + .byte 0x0 ! LSDA Encoding: absolute +#endif + .byte 0x0c ! DW_CFA_def_cfa + .uleb128 0xf + .uleb128 0 + .align 2 +.LENDCIE: + + .ualong .LENDFDE-.LSTARTFDE ! Length of the FDE. +.LSTARTFDE: + .ualong .LSTARTFDE-.LSTARTFRAME ! CIE pointer. +#ifdef SHARED + .ualong .LSTARTCODE-. ! PC-relative start address + ! of the code. +#else + .ualong .LSTARTCODE ! Start address of the code. +#endif + .ualong .LENDCODE-.LSTARTCODE ! Length of the code. + .uleb128 4 ! Augmentation size +#ifdef SHARED + .ualong .LexceptSTART-. +#else + .ualong .LexceptSTART +#endif + .byte 0x4 + .ualong .Lpush_r8-.LSTARTCODE + .byte 0xe + .uleb128 4 + .byte 0x88 + .uleb128 1 + .byte 0x4 + .ualong .Lpush_r9-.Lpush_r8 + .byte 0xe + .uleb128 8 + .byte 0x89 + .uleb128 2 + .byte 0x4 + .ualong .Lpush_r10-.Lpush_r9 + .byte 0xe + .uleb128 12 + .byte 0x8a + .uleb128 3 + .byte 0x4 + .ualong .Lpush_r11-.Lpush_r10 + .byte 0xe + .uleb128 16 + .byte 0x8b + .uleb128 4 + .byte 0x4 + .ualong .Lpush_r12-.Lpush_r11 + .byte 0xe + .uleb128 20 + .byte 0x8c + .uleb128 5 + .byte 0x4 + .ualong .Lpush_pr-.Lpush_r12 + .byte 0xe + .uleb128 24 + .byte 0x91 + .uleb128 6 + .byte 0x4 + .ualong .Lalloc-.Lpush_pr + .byte 0xe + .uleb128 72 + .align 2 +.LENDFDE: + +#ifdef SHARED + .hidden DW.ref.__gcc_personality_v0 + .weak DW.ref.__gcc_personality_v0 + .section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits + .align 4 + .type DW.ref.__gcc_personality_v0, @object + .size DW.ref.__gcc_personality_v0, 4 +DW.ref.__gcc_personality_v0: + .long __gcc_personality_v0 +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_once.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_once.S new file mode 100644 index 000000000..de83dec1b --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_once.S @@ -0,0 +1,245 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <unwindbuf.h> +#include <sysdep.h> +#include "lowlevel-atomic.h" + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + + .comm __fork_generation, 4, 4 + + .text + .globl __pthread_once + .type __pthread_once,@function + .align 5 + cfi_startproc +__pthread_once: + mov.l @r4, r0 + tst #2, r0 + bt 1f + rts + mov #0, r0 + +1: + mov.l r12, @-r15 + cfi_adjust_cfa_offset (4) + cfi_rel_offset (r12, 0) + mov.l r9, @-r15 + cfi_adjust_cfa_offset (4) + cfi_rel_offset (r9, 0) + mov.l r8, @-r15 + cfi_adjust_cfa_offset (4) + cfi_rel_offset (r8, 0) + sts.l pr, @-r15 + cfi_adjust_cfa_offset (4) + cfi_rel_offset (pr, 0) + mov r5, r8 + mov r4, r9 + + /* Not yet initialized or initialization in progress. + Get the fork generation counter now. */ +6: + mov.l @r4, r1 + mova .Lgot, r0 + mov.l .Lgot, r12 + add r0, r12 + +5: + mov r1, r0 + + tst #2, r0 + bf 4f + + and #3, r0 + mov.l .Lfgen, r2 +#ifdef __PIC__ + add r12, r2 +#endif + mov.l @r2, r3 + or r3, r0 + or #1, r0 + mov r0, r3 + mov r1, r5 + + CMPXCHG (r5, @r4, r3, r2) + bf 5b + + /* Check whether another thread already runs the initializer. */ + mov r2, r0 + tst #1, r0 + bt 3f /* No -> do it. */ + + /* Check whether the initializer execution was interrupted + by a fork. */ + xor r3, r0 + mov #-4, r1 /* -4 = 0xfffffffc */ + tst r1, r0 + bf 3f /* Different for generation -> run initializer. */ + + /* Somebody else got here first. Wait. */ + mov #FUTEX_WAIT, r5 + mov r3, r6 + mov #0, r7 + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + bra 6b + nop + + .align 2 +.Lgot: + .long _GLOBAL_OFFSET_TABLE_ +#ifdef __PIC__ +.Lfgen: + .long __fork_generation@GOTOFF +#else +.Lfgen: + .long __fork_generation +#endif + +3: + /* Call the initializer function after setting up the + cancellation handler. Note that it is not possible here + to use the unwind-based cleanup handling. This would require + that the user-provided function and all the code it calls + is compiled with exceptions. Unfortunately this cannot be + guaranteed. */ + add #-UNWINDBUFSIZE, r15 + cfi_adjust_cfa_offset (UNWINDBUFSIZE) + + mov.l .Lsigsetjmp, r1 + mov #UWJMPBUF, r4 + add r15, r4 + bsrf r1 + mov #0, r5 +.Lsigsetjmp0: + tst r0, r0 + bf 7f + + mov.l .Lcpush, r1 + bsrf r1 + mov r15, r4 +.Lcpush0: + + /* Call the user-provided initialization function. */ + jsr @r8 + nop + + /* Pop the cleanup handler. */ + mov.l .Lcpop, r1 + bsrf r1 + mov r15, r4 +.Lcpop0: + + add #UNWINDBUFSIZE, r15 + cfi_adjust_cfa_offset (-UNWINDBUFSIZE) + + /* Sucessful run of the initializer. Signal that we are done. */ + INC (@r9, r2) + /* Wake up all other threads. */ + mov r9, r4 + mov #FUTEX_WAKE, r5 + mov #-1, r6 + shlr r6 /* r6 = 0x7fffffff */ + mov #0, r7 + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + +4: + lds.l @r15+, pr + cfi_adjust_cfa_offset (-4) + cfi_restore (pr) + mov.l @r15+, r8 + cfi_adjust_cfa_offset (-4) + cfi_restore (r8) + mov.l @r15+, r9 + cfi_adjust_cfa_offset (-4) + cfi_restore (r9) + mov.l @r15+, r12 + cfi_adjust_cfa_offset (-4) + cfi_restore (r12) + rts + mov #0, r0 + +7: + /* __sigsetjmp returned for the second time. */ + cfi_adjust_cfa_offset (UNWINDBUFSIZE+16) + cfi_offset (r12, -4) + cfi_offset (r9, -8) + cfi_offset (r8, -12) + cfi_offset (pr, -16) + mov #0, r7 + mov.l r7, @r9 + mov r9, r4 + mov #FUTEX_WAKE, r5 + mov #-1, r6 + shlr r6 /* r6 = 0x7fffffff */ + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + + mov.l .Lunext, r1 + bsrf r1 + mov r15, r4 +.Lunext0: + /* NOTREACHED */ + sleep + cfi_endproc + + .align 2 +.Lsigsetjmp: + .long __sigsetjmp@PLT-(.Lsigsetjmp0-.) +.Lcpush: + .long HIDDEN_JUMPTARGET(__pthread_register_cancel)-.Lcpush0 +.Lcpop: + .long HIDDEN_JUMPTARGET(__pthread_unregister_cancel)-.Lcpop0 +.Lunext: + .long HIDDEN_JUMPTARGET(__pthread_unwind_next)-.Lunext0 + .size __pthread_once,.-__pthread_once + + .globl __pthread_once_internal +__pthread_once_internal = __pthread_once + + .globl pthread_once +pthread_once = __pthread_once + + + .type clear_once_control,@function + .align 5 +clear_once_control: + mov #0, r0 + mov.l r0, @r4 + + mov #FUTEX_WAKE, r5 + mov #-1, r6 + shlr r6 /* r6 = 0x7fffffff */ + mov #0, r7 + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + + rts + nop + .size clear_once_control,.-clear_once_control diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_rdlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_rdlock.S new file mode 100644 index 000000000..ce1ab37c8 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_rdlock.S @@ -0,0 +1,220 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <lowlevelrwlock.h> +#include <pthread-errnos.h> +#include <tcb-offsets.h> +#include "lowlevel-atomic.h" + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + + + .text + + .globl __pthread_rwlock_rdlock + .type __pthread_rwlock_rdlock,@function + .align 5 +__pthread_rwlock_rdlock: + mov.l r12, @-r15 + mov.l r9, @-r15 + mov.l r8, @-r15 + sts.l pr, @-r15 + mov r4, r8 + + /* Get the lock. */ + mov #0, r3 + mov #1, r4 +#if MUTEX == 0 + CMPXCHG (r3, @r8, r4, r2) +#else + CMPXCHG (r3, @(MUTEX,r8), r4, r2) +#endif + bf 1f +2: + mov.l @(WRITER,r8), r0 + tst r0, r0 + bf 14f + mov.l @(WRITERS_QUEUED,r8), r0 + tst r0, r0 + bt 5f + mov.l @(FLAGS,r8), r0 + tst r0, r0 + bt 5f +3: + mov.l @(READERS_QUEUED,r8), r0 + add #1, r0 + mov.l r0, @(READERS_QUEUED,r8) + tst r0, r0 + bt 4f + + mov.l @(READERS_WAKEUP,r8), r9 + +#if MUTEX == 0 + DEC (@r8, r2) +#else + DEC (@(MUTEX,r8), r2) +#endif + tst r2, r2 + bf 10f +11: + mov r8, r4 + add #READERS_WAKEUP, r4 + mov #FUTEX_WAIT, r5 + mov r9, r6 + mov #0, r7 + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + + /* Reget the lock. */ + mov #0, r3 + mov #1, r4 +#if MUTEX == 0 + CMPXCHG (r3, @r8, r4, r2) +#else + CMPXCHG (r3, @(MUTEX,r8), r4, r2) +#endif + bf 12f +13: + mov.l @(READERS_QUEUED,r8), r0 + add #-1, r0 + bra 2b + mov.l r0, @(READERS_QUEUED,r8) + +5: + mov #0, r3 + mov.l @(NR_READERS,r8), r0 + add #1, r0 + mov.l r0, @(NR_READERS,r8) + tst r0, r0 + bt 8f + +9: +#if MUTEX == 0 + DEC (@r8, r2) +#else + DEC (@(MUTEX,r8), r2) +#endif + tst r2, r2 + bf 6f +7: + lds.l @r15+, pr + mov.l @r15+, r8 + mov.l @r15+, r9 + mov.l @r15+, r12 + rts + mov r3, r0 + +1: + mov r8, r5 +#if MUTEX != 0 + add #MUTEX, r5 +#endif + mov r2, r4 + mov.l .Lwait0, r1 + bsrf r1 + nop +.Lwait0b: + bra 2b + nop +14: + stc gbr, r1 + mov.w .Ltidoff, r2 + add r2, r1 + mov.l @r1, r1 + cmp/eq r1, r0 + bf 3b + /* Deadlock detected. */ + bra 9b + mov #EDEADLK, r3 + +.Ltidoff: + .word TID - TLS_PRE_TCB_SIZE + +6: + mov r8, r4 +#if MUTEX != 0 + add #MUTEX, r4 +#endif + mov.l .Lwake0, r1 + bsrf r1 + nop +.Lwake0b: + bra 7b + mov #0, r3 + +8: + /* Overflow. */ + mov.l @(NR_READERS,r8), r1 + add #-1, r1 + mov.l r1, @(NR_READERS,r8) + bra 9b + mov #EAGAIN, r3 + +4: + /* Overflow. */ + mov.l @(READERS_QUEUED,r8), r1 + add #-1, r1 + mov.l r1, @(READERS_QUEUED,r8) + bra 9b + mov #EAGAIN, r3 + +10: + mov r8, r4 +#if MUTEX != 0 + add #MUTEX, r4 +#endif + mov.l .Lwake1, r1 + bsrf r1 + nop +.Lwake1b: + bra 11b + nop + +12: + mov r8, r5 +#if MUTEX != 0 + add #MUTEX, r5 +#endif + mov r2, r4 + mov.l .Lwait1, r1 + bsrf r1 + nop +.Lwait1b: + bra 13b + nop + + .align 2 +.Lwait0: + .long __lll_mutex_lock_wait-.Lwait0b +.Lwake0: + .long __lll_mutex_unlock_wake-.Lwake0b +.Lwait1: + .long __lll_mutex_lock_wait-.Lwait1b +.Lwake1: + .long __lll_mutex_unlock_wake-.Lwake1b + .size __pthread_rwlock_rdlock,.-__pthread_rwlock_rdlock + + .globl pthread_rwlock_rdlock +pthread_rwlock_rdlock = __pthread_rwlock_rdlock + + .globl __pthread_rwlock_rdlock_internal +__pthread_rwlock_rdlock_internal = __pthread_rwlock_rdlock diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedrdlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedrdlock.S new file mode 100644 index 000000000..8a4e7d3bc --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedrdlock.S @@ -0,0 +1,280 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <lowlevelrwlock.h> +#include <pthread-errnos.h> +#include <tcb-offsets.h> +#include "lowlevel-atomic.h" + +#define SYS_gettimeofday __NR_gettimeofday +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + + + .text + + .globl pthread_rwlock_timedrdlock + .type pthread_rwlock_timedrdlock,@function + .align 5 +pthread_rwlock_timedrdlock: + mov.l r12, @-r15 + mov.l r10, @-r15 + mov.l r9, @-r15 + mov.l r8, @-r15 + sts.l pr, @-r15 + add #-8, r15 + mov r4, r8 + mov r5, r9 + + /* Get the lock. */ + mov #0, r3 + mov #1, r4 +#if MUTEX == 0 + CMPXCHG (r3, @r8, r4, r2) +#else + CMPXCHG (r3, @(MUTEX,r8), r4, r2) +#endif + bf 1f +2: + mov.l @(WRITER,r8), r0 + tst r0, r0 + bf 14f + mov.l @(WRITERS_QUEUED,r8), r0 + tst r0, r0 + bt 5f + mov.l @(FLAGS,r8), r0 + tst r0, r0 + bt 5f +3: + /* Check the value of the timeout parameter. */ + mov.l .L1g0, r1 + mov.l @(4,r9), r0 + cmp/hs r1, r0 + bt 19f + + mov.l @(READERS_QUEUED,r8), r0 + add #1, r0 + mov.l r0, @(READERS_QUEUED,r8) + tst r0, r0 + bt 4f + + mov.l @(READERS_WAKEUP,r8), r10 + +#if MUTEX == 0 + DEC (@r8, r2) +#else + DEC (@(MUTEX,r8), r2) +#endif + tst r2, r2 + bf 10f + +11: + /* Get current time. */ + mov r15, r4 + mov #0, r5 + mov #SYS_gettimeofday, r3 + trapa #0x12 + SYSCALL_INST_PAD + + mov.l @(4,r15), r0 + mov.w .L1k0, r1 + dmulu.l r0, r1 /* Milli seconds to nano seconds. */ + mov.l @r9, r2 + mov.l @(4,r9), r3 + mov.l @r15, r0 + sts macl, r1 + sub r0, r2 + clrt + subc r1, r3 + bf 15f + mov.l .L1g0, r1 + add r1, r3 + add #-1, r2 +15: + cmp/pz r2 + bf 16f /* Time is already up. */ + + /* Store relative timeout. */ + mov.l r2, @r15 + mov.l r3, @(4,r15) + + /* Futex call. */ + mov r15, r7 + mov #FUTEX_WAIT, r5 + mov r10, r6 + mov r8, r4 + add #READERS_WAKEUP, r4 + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + mov r0, r3 + +17: + /* Reget the lock. */ + mov #0, r5 + mov #1, r4 +#if MUTEX == 0 + CMPXCHG (r5, @r8, r4, r2) +#else + CMPXCHG (r5, @(MUTEX,r8), r4, r2) +#endif + bf 12f + +13: + mov.l @(READERS_QUEUED,r8), r0 + add #-1, r0 + mov.l r0, @(READERS_QUEUED,r8) + mov #-ETIMEDOUT, r0 + cmp/eq r0, r3 + bf 2b + +18: + bra 9f + mov #ETIMEDOUT, r3 + +5: + mov #0, r3 + mov.l @(NR_READERS,r8), r0 + add #1, r0 + mov.l r0, @(NR_READERS,r8) + tst r0, r0 + bt 8f + +9: +#if MUTEX == 0 + DEC (@r8, r2) +#else + DEC (@(MUTEX,r8), r2) +#endif + tst r2, r2 + bf 6f +7: + add #8,r15 + lds.l @r15+, pr + mov.l @r15+, r8 + mov.l @r15+, r9 + mov.l @r15+, r10 + mov.l @r15+, r12 + rts + mov r3, r0 + + .align 2 +.L1k0: + .long 1000 +.L1g0: + .long 1000000000 + +1: + mov r8, r5 +#if MUTEX != 0 + add #MUTEX, r5 +#endif + mov r2, r4 + mov.l .Lwait2, r1 + bsrf r1 + nop +.Lwait2b: + bra 2b + nop +14: + stc gbr, r1 + mov.w .Ltidoff, r2 + add r2, r1 + mov.l @r1, r1 + cmp/eq r1, r0 + bf 3b + /* Deadlock detected. */ + bra 9b + mov #EDEADLK, r3 + +.Ltidoff: + .word TID - TLS_PRE_TCB_SIZE + +6: + mov r8, r4 +#if MUTEX != 0 + add #MUTEX, r4 +#endif + mov.l .Lwake2, r1 + bsrf r1 + nop +.Lwake2b: + bra 7b + mov #0, r3 + +8: + /* Overflow. */ + mov.l @(NR_READERS,r8), r1 + add #-1, r1 + mov.l r1, @(NR_READERS,r8) + bra 9b + mov #EAGAIN, r3 + +4: + /* Overflow. */ + mov.l @(READERS_QUEUED,r8), r1 + add #-1, r1 + mov.l r1, @(READERS_QUEUED,r8) + bra 9b + mov #EAGAIN, r3 + +10: + mov r8, r4 +#if MUTEX != 0 + add #MUTEX, r4 +#endif + mov.l .Lwake3, r1 + bsrf r1 + nop +.Lwake3b: + bra 11b + nop + +12: + mov r8, r5 +#if MUTEX != 0 + add #MUTEX, r5 +#endif + mov r2, r4 + mov.l .Lwait3, r1 + bsrf r1 + nop +.Lwait3b: + bra 13b + nop + +16: + bra 17b + mov #-ETIMEDOUT, r3 + +19: + bra 9b + mov #EINVAL, r3 + + .align 2 +.Lwait2: + .long __lll_mutex_lock_wait-.Lwait2b +.Lwake2: + .long __lll_mutex_unlock_wake-.Lwake2b +.Lwait3: + .long __lll_mutex_lock_wait-.Lwait3b +.Lwake3: + .long __lll_mutex_unlock_wake-.Lwake3b + .size pthread_rwlock_timedrdlock,.-pthread_rwlock_timedrdlock diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedwrlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedwrlock.S new file mode 100644 index 000000000..6284140a6 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedwrlock.S @@ -0,0 +1,265 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <lowlevelrwlock.h> +#include <pthread-errnos.h> +#include <tcb-offsets.h> +#include "lowlevel-atomic.h" + +#define SYS_gettimeofday __NR_gettimeofday +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + + + .text + + .globl pthread_rwlock_timedwrlock + .type pthread_rwlock_timedwrlock,@function + .align 5 +pthread_rwlock_timedwrlock: + mov.l r12, @-r15 + mov.l r10, @-r15 + mov.l r9, @-r15 + mov.l r8, @-r15 + sts.l pr, @-r15 + add #-8, r15 + mov r4, r8 + mov r5, r9 + + /* Get the lock. */ + mov #0, r3 + mov #1, r4 +#if MUTEX == 0 + CMPXCHG (r3, @r8, r4, r2) +#else + CMPXCHG (r3, @(MUTEX,r8), r4, r2) +#endif + bf 1f +2: + mov.l @(WRITER,r8), r0 + tst r0, r0 + bf 14f + mov.l @(NR_READERS,r8), r0 + tst r0, r0 + bt 5f +3: + /* Check the value of the timeout parameter. */ + mov.l .L1g1, r1 + mov.l @(4,r9), r0 + cmp/hs r1, r0 + bt 19f + + mov.l @(WRITERS_QUEUED,r8), r0 + add #1, r0 + mov.l r0, @(WRITERS_QUEUED,r8) + tst r0, r0 + bt 4f + + mov.l @(WRITERS_WAKEUP,r8), r10 + +#if MUTEX == 0 + DEC (@r8, r2) +#else + DEC (@(MUTEX,r8), r2) +#endif + tst r2, r2 + bf 10f + +11: + /* Get current time. */ + mov r15, r4 + mov #0, r5 + mov #SYS_gettimeofday, r3 + trapa #0x12 + SYSCALL_INST_PAD + + mov.l @(4,r15), r0 + mov.w .L1k1, r1 + dmulu.l r0, r1 /* Milli seconds to nano seconds. */ + mov.l @r9, r2 + mov.l @(4,r9), r3 + mov.l @r15, r0 + sts macl, r1 + sub r0, r2 + clrt + subc r1, r3 + bf 15f + mov.l .L1g1, r1 + add r1, r3 + add #-1, r2 +15: + cmp/pz r2 + bf 16f /* Time is already up. */ + + /* Store relative timeout. */ + mov.l r2, @r15 + mov.l r3, @(4,r15) + + /* Futex call. */ + mov r15, r7 + mov #FUTEX_WAIT, r5 + mov r10, r6 + mov r8, r4 + add #WRITERS_WAKEUP, r4 + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + mov r0, r3 + +17: + /* Reget the lock. */ + mov #0, r5 + mov #1, r4 +#if MUTEX == 0 + CMPXCHG (r5, @r8, r4, r2) +#else + CMPXCHG (r5, @(MUTEX,r8), r4, r2) +#endif + bf 12f + +13: + mov.l @(WRITERS_QUEUED,r8), r0 + add #-1, r0 + mov.l r0, @(WRITERS_QUEUED,r8) + mov #-ETIMEDOUT, r0 + cmp/eq r0, r3 + bf 2b + +18: + bra 9f + mov #ETIMEDOUT, r3 + +19: + bra 9f + mov #EINVAL, r3 + +5: + mov #0, r3 + stc gbr, r0 + mov.w .Ltidoff, r1 + mov.l @(r0,r1), r0 + mov.l r0, @(WRITER,r8) +9: +#if MUTEX == 0 + DEC (@r8, r2) +#else + DEC (@(MUTEX,r8), r2) +#endif + tst r2, r2 + bf 6f +7: + add #8,r15 + lds.l @r15+, pr + mov.l @r15+, r8 + mov.l @r15+, r9 + mov.l @r15+, r10 + mov.l @r15+, r12 + rts + mov r3, r0 + +.L1k1: + .word 1000 + .align 2 +.L1g1: + .long 1000000000 + +1: + mov r8, r5 +#if MUTEX != 0 + add #MUTEX, r5 +#endif + mov r2, r4 + mov.l .Lwait6, r1 + bsrf r1 + nop +.Lwait6b: + bra 2b + nop +14: + stc gbr, r1 + mov.w .Ltidoff, r2 + add r2, r1 + mov.l @r1, r1 + cmp/eq r1, r0 + bf 3b + bra 9b + mov #EDEADLK, r3 +6: + mov r8, r4 +#if MUTEX != 0 + add #MUTEX, r4 +#endif + mov.l .Lwake6, r1 + bsrf r1 + nop +.Lwake6b: + bra 7b + mov #0, r3 + +.Ltidoff: + .word TID - TLS_PRE_TCB_SIZE + +4: + /* Overflow. */ + mov.l @(WRITERS_QUEUED,r8), r1 + add #-1, r1 + mov.l r1, @(WRITERS_QUEUED,r8) + bra 9b + mov #EAGAIN, r3 + +10: + mov r8, r4 +#if MUTEX != 0 + add #MUTEX, r4 +#endif + mov.l .Lwake7, r1 + bsrf r1 + nop +.Lwake7b: + bra 11b + nop + +12: + mov r8, r5 +#if MUTEX != 0 + add #MUTEX, r5 +#endif + mov r2, r4 + mov.l .Lwait7, r1 + bsrf r1 + nop +.Lwait7b: + bra 13b + nop + +16: + bra 17b + mov #-ETIMEDOUT, r3 + + .align 2 +.Lwait6: + .long __lll_mutex_lock_wait-.Lwait6b +.Lwake6: + .long __lll_mutex_unlock_wake-.Lwake6b +.Lwait7: + .long __lll_mutex_lock_wait-.Lwait7b +.Lwake7: + .long __lll_mutex_unlock_wake-.Lwake7b + .size pthread_rwlock_timedwrlock,.-pthread_rwlock_timedwrlock diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_unlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_unlock.S new file mode 100644 index 000000000..74f32f8f9 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_unlock.S @@ -0,0 +1,169 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <lowlevelrwlock.h> +#include "lowlevel-atomic.h" + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + + + .text + + .globl __pthread_rwlock_unlock + .type __pthread_rwlock_unlock,@function + .align 5 +__pthread_rwlock_unlock: + mov.l r12, @-r15 + mov.l r8, @-r15 + sts.l pr, @-r15 + mov r4, r8 + + /* Get the lock. */ + mov #0, r3 + mov #1, r4 +#if MUTEX == 0 + CMPXCHG (r3, @r8, r4, r2) +#else + CMPXCHG (r3, @(MUTEX,r8), r4, r2) +#endif + bf 1f +2: + mov.l @(WRITER,r8), r0 + tst r0, r0 + bf 5f + mov.l @(NR_READERS,r8), r0 + add #-1, r0 + mov.l r0, @(NR_READERS,r8) + tst r0, r0 + bf 6f +5: + mov #0, r0 + mov.l r0, @(WRITER,r8) + mov #1, r6 + mov r8, r4 + add #WRITERS_WAKEUP, r4 + mov.l @(WRITERS_QUEUED,r8), r0 + tst r0, r0 + bf 0f + + /* If also no readers waiting nothing to do. */ + mov.l @(READERS_QUEUED,r8), r0 + tst r0, r0 + bt 6f + + mov #-1, r6 + shlr r6 /* r6 = 0x7fffffff */ + mov r8, r4 + add #READERS_WAKEUP, r4 + +0: + mov.l @r4, r0 + add #1, r0 + mov.l r0, @r4 +#if MUTEX == 0 + DEC (@r8, r2) +#else + DEC (@(MUTEX,r8), r2) +#endif + tst r2, r2 + bf 7f + +8: + mov #FUTEX_WAKE, r5 + mov #SYS_futex, r3 + mov #0, r7 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + + lds.l @r15+, pr + mov.l @r15+, r8 + mov.l @r15+, r12 + rts + mov #0, r0 +6: +#if MUTEX == 0 + DEC (@r8, r2) +#else + DEC (@(MUTEX,r8), r2) +#endif + tst r2, r2 + bf 3f +4: + lds.l @r15+, pr + mov.l @r15+, r8 + mov.l @r15+, r12 + rts + mov #0, r0 + +1: + mov r8, r5 +#if MUTEX != 0 + add #MUTEX, r5 +#endif + mov r2, r4 + mov.l .Lwait8, r1 + bsrf r1 + nop +.Lwait8b: + bra 2b + nop +3: + mov r8, r4 +#if MUTEX != 0 + add #MUTEX, r4 +#endif + mov.l .Lwake8, r1 + bsrf r1 + nop +.Lwake8b: + bra 4b + nop + +7: + mov.l r4, @-r15 + mov.l r6, @-r15 + mov r8, r4 +#if MUTEX != 0 + add #MUTEX, r4 +#endif + mov.l .Lwake9, r1 + bsrf r1 + nop +.Lwake9b: + + mov.l @r15+, r6 + bra 8b + mov.l @r15+, r4 + + .align 2 +.Lwait8: + .long __lll_mutex_lock_wait-.Lwait8b +.Lwake8: + .long __lll_mutex_unlock_wake-.Lwake8b +.Lwake9: + .long __lll_mutex_unlock_wake-.Lwake9b + .size __pthread_rwlock_unlock,.-__pthread_rwlock_unlock + + .globl pthread_rwlock_unlock +pthread_rwlock_unlock = __pthread_rwlock_unlock + + .globl __pthread_rwlock_unlock_internal +__pthread_rwlock_unlock_internal = __pthread_rwlock_unlock diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_wrlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_wrlock.S new file mode 100644 index 000000000..d071f7f03 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_wrlock.S @@ -0,0 +1,202 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <lowlevelrwlock.h> +#include <pthread-errnos.h> +#include <tcb-offsets.h> +#include "lowlevel-atomic.h" + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + + + .text + + .globl __pthread_rwlock_wrlock + .type __pthread_rwlock_wrlock,@function + .align 5 +__pthread_rwlock_wrlock: + mov.l r12, @-r15 + mov.l r9, @-r15 + mov.l r8, @-r15 + sts.l pr, @-r15 + mov r4, r8 + + /* Get the lock. */ + mov #0, r3 + mov #1, r4 +#if MUTEX == 0 + CMPXCHG (r3, @r8, r4, r2) +#else + CMPXCHG (r3, @(MUTEX,r8), r4, r2) +#endif + bf 1f +2: + mov.l @(WRITER,r8), r0 + tst r0, r0 + bf 14f + mov.l @(NR_READERS,r8), r0 + tst r0, r0 + bt 5f +3: + mov.l @(WRITERS_QUEUED,r8), r0 + add #1, r0 + mov.l r0, @(WRITERS_QUEUED,r8) + tst r0, r0 + bt 4f + + mov.l @(WRITERS_WAKEUP,r8), r9 + +#if MUTEX == 0 + DEC (@r8, r2) +#else + DEC (@(MUTEX,r8), r2) +#endif + tst r2, r2 + bf 10f +11: + mov r8, r4 + add #WRITERS_WAKEUP, r4 + mov #FUTEX_WAIT, r5 + mov r9, r6 + mov #0, r7 + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + + /* Reget the lock. */ + mov #0, r3 + mov #1, r4 +#if MUTEX == 0 + CMPXCHG (r3, @r8, r4, r2) +#else + CMPXCHG (r3, @(MUTEX,r8), r4, r2) +#endif + bf 12f +13: + mov.l @(WRITERS_QUEUED,r8), r0 + add #-1, r0 + bra 2b + mov.l r0, @(WRITERS_QUEUED,r8) + +5: + mov #0, r3 + stc gbr, r0 + mov.w .Ltidoff, r1 + mov.l @(r0,r1), r0 + mov.l r0, @(WRITER,r8) +9: +#if MUTEX == 0 + DEC (@r8, r2) +#else + DEC (@(MUTEX,r8), r2) +#endif + tst r2, r2 + bf 6f +7: + lds.l @r15+, pr + mov.l @r15+, r8 + mov.l @r15+, r9 + mov.l @r15+, r12 + rts + mov r3, r0 + +1: + mov r8, r5 +#if MUTEX != 0 + add #MUTEX, r5 +#endif + mov r2, r4 + mov.l .Lwait4, r1 + bsrf r1 + nop +.Lwait4b: + bra 2b + nop +14: + stc gbr, r1 + mov.w .Ltidoff, r2 + add r2, r1 + mov.l @r1, r1 + cmp/eq r1, r0 + bf 3b + bra 9b + mov #EDEADLK, r3 +6: + mov r8, r4 +#if MUTEX != 0 + add #MUTEX, r4 +#endif + mov.l .Lwake4, r1 + bsrf r1 + nop +.Lwake4b: + bra 7b + mov #0, r3 + +.Ltidoff: + .word TID - TLS_PRE_TCB_SIZE + +4: + mov.l @(WRITERS_QUEUED,r8), r1 + add #-1, r1 + mov.l r1, @(WRITERS_QUEUED,r8) + bra 9b + mov #EAGAIN, r3 + +10: + mov r8, r4 +#if MUTEX != 0 + add #MUTEX, r4 +#endif + mov.l .Lwake5, r1 + bsrf r1 + nop +.Lwake5b: + bra 11b + nop + +12: + mov r8, r5 +#if MUTEX != 0 + add #MUTEX, r5 +#endif + mov r2, r4 + mov.l .Lwait5, r1 + bsrf r1 + nop +.Lwait5b: + bra 13b + nop + + .align 2 +.Lwait4: + .long __lll_mutex_lock_wait-.Lwait4b +.Lwake4: + .long __lll_mutex_unlock_wake-.Lwake4b +.Lwait5: + .long __lll_mutex_lock_wait-.Lwait5b +.Lwake5: + .long __lll_mutex_unlock_wake-.Lwake5b + .globl pthread_rwlock_wrlock +pthread_rwlock_wrlock = __pthread_rwlock_wrlock + + .globl __pthread_rwlock_wrlock_internal +__pthread_rwlock_wrlock_internal = __pthread_rwlock_wrlock diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sem_post.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sem_post.S new file mode 100644 index 000000000..9755b7e16 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sem_post.S @@ -0,0 +1,84 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <pthread-errnos.h> +#include "lowlevel-atomic.h" + + +#define SYS_gettimeofday __NR_gettimeofday +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + + .text + + .globl __new_sem_post + .type __new_sem_post,@function + .align 5 +__new_sem_post: + INC (@r4, r6) + + mov #FUTEX_WAKE, r5 + mov #0, r7 + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + + cmp/pz r0 + bf 1f + rts + mov #0, r0 + +1: + mov #EINVAL, r2 + mova .Lgot3, r0 + mov.l .Lgot3, r12 + add r0, r12 + +#if USE___THREAD + mov.l .Lerrno3, r0 + stc gbr, r1 + mov.l @(r0, r12), r0 + bra .Lexit + add r1, r0 + .align 2 +.Lerrno3: + .long errno@GOTTPOFF +.Lexit: +#else + mov.l .Lerrloc3, r1 + bsrf r1 + nop +.Lerrloc3b: +#endif + mov.l r2, @r0 + lds.l @r15+, pr + mov.l @r15+, r12 + rts + mov #-1, r0 + + .align 2 +.Lgot3: + .long _GLOBAL_OFFSET_TABLE_ +#if !USE___THREAD +.Lerrloc3: + .long __errno_location@PLT-(.Lerrloc3b-.) +#endif + .size __new_sem_post,.-__new_sem_post + weak_alias(__new_sem_post, sem_post) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sem_timedwait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sem_timedwait.S new file mode 100644 index 000000000..40782fcaf --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sem_timedwait.S @@ -0,0 +1,240 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <pthread-errnos.h> +#include <tcb-offsets.h> +#include "lowlevel-atomic.h" + + +#define SYS_gettimeofday __NR_gettimeofday +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + + .text + + .globl sem_timedwait + .type sem_timedwait,@function + .align 5 + cfi_startproc +sem_timedwait: + /* First check for cancellation. */ + stc gbr, r0 + mov.w .Lchand, r1 + mov.l @(r0,r1), r0 + mov #0xf9, r1 + and r1, r0 + cmp/eq #8, r0 + bf 0f + bra 10f + stc gbr, r0 +0: + mov.l @r4, r0 +2: + tst r0, r0 + bt 1f + mov r0, r3 + mov r0, r6 + add #-1, r3 + CMPXCHG (r6, @r4, r3, r2) + bf/s 2b + mov r2, r0 + rts + mov #0, r0 + +1: + /* Check whether the timeout value is valid. */ + mov.l r8, @-r15 + cfi_adjust_cfa_offset(4) + cfi_rel_offset (r8, 0) + mov.l r9, @-r15 + cfi_adjust_cfa_offset(4) + cfi_rel_offset (r9, 0) + mov.l r10, @-r15 + cfi_adjust_cfa_offset(4) + cfi_rel_offset (r10, 0) + mov.l r12, @-r15 + cfi_adjust_cfa_offset(4) + cfi_rel_offset (r12, 0) + sts.l pr, @-r15 + cfi_adjust_cfa_offset(4) + cfi_rel_offset (pr, 0) + add #-8, r15 + cfi_adjust_cfa_offset(8) + mov r4, r8 + mov r5, r9 + + /* Check for invalid nanosecond field. */ + mov.l @(4,r9), r0 + mov.l .L1g, r1 + cmp/hs r1, r0 + bt/s 6f + mov #EINVAL, r0 +7: + mov.l .Lenable0, r1 + bsrf r1 + nop +.Lenable0b: + mov r0, r10 + + /* Compute relative timeout. */ + mov r15, r4 + mov #0, r5 + mov #SYS_gettimeofday, r3 + trapa #0x12 + SYSCALL_INST_PAD + + mov.l @(4,r15), r0 + mov.w .L1k, r1 + dmulu.l r0, r1 /* Milli seconds to nano seconds. */ + mov.l @r9, r2 + mov.l @(4,r9), r3 + mov.l @r15, r0 + sts macl, r1 + sub r0, r2 + clrt + subc r1, r3 + bf 5f + mov.l .L1g, r1 + add r1, r3 + add #-1, r2 +5: + cmp/pz r2 + bf/s 6f /* Time is already up. */ + mov #ETIMEDOUT, r0 + + /* Store relative timeout. */ + mov.l r2, @r15 + mov.l r3, @(4,r15) + + /* Futex call. */ + mov r8, r4 + mov #FUTEX_WAIT, r5 + mov #0, r6 + mov r15, r7 + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + + mov.l .Ldisable0, r1 + mov r10, r4 + bsrf r1 + mov r0, r10 +.Ldisable0b: + mov r10, r0 + + tst r0, r0 + bt 9f + cmp/eq #-EWOULDBLOCK, r0 + bf 3f +9: + mov.l @r8, r0 +8: + tst r0, r0 + bt 7b + + mov r0, r3 + mov r0, r4 + add #-1, r3 + CMPXCHG (r4, @r8, r3, r2) + bf/s 8b + mov r2, r0 + + add #8, r15 + lds.l @r15+, pr + mov.l @r15+, r12 + mov.l @r15+, r10 + mov.l @r15+, r9 + mov.l @r15+, r8 + rts + mov #0, r0 + +3: + neg r0, r0 +6: + mov r0, r8 + mova .Lgot2, r0 + mov.l .Lgot2, r12 + add r0, r12 + +#if USE___THREAD + mov.l .Lerrno2, r0 + stc gbr, r1 + mov.l @(r0, r12), r0 + bra .Lexit + add r1, r0 + .align 2 +.Lerrno2: + .long errno@GOTTPOFF +.Lexit: +#else + mov.l .Lerrloc2, r1 + bsrf r1 + nop +.Lerrloc2b: +#endif + mov.l r8, @r0 + add #8, r15 + lds.l @r15+, pr + mov.l @r15+, r12 + mov.l @r15+, r10 + mov.l @r15+, r9 + mov.l @r15+, r8 + rts + mov #-1, r0 + +10: + /* Canceled. */ + mov.w .Lresult, r1 + mov #-1, r2 + mov.l r2, @(r0,r1) + mov.w .Lchand, r0 + or.b #0x10, @(r0,gbr) + stc gbr, r0 + mov.w .Lclbuf, r1 + mov.l .Lunwind, r2 + braf r2 + mov.l @(r0,r1), r4 +.Lunwindb: + cfi_endproc + +.L1k: + .word 1000 +.Lchand: + .word CANCELHANDLING - TLS_PRE_TCB_SIZE +.Lresult: + .word RESULT - TLS_PRE_TCB_SIZE +.Lclbuf: + .word CLEANUP_JMP_BUF - TLS_PRE_TCB_SIZE + .align 2 +.L1g: + .long 1000000000 +.Lgot2: + .long _GLOBAL_OFFSET_TABLE_ +#if !USE___THREAD +.Lerrloc2: + .long __errno_location@PLT-(.Lerrloc2b-.) +#endif +.Lenable0: + .long __pthread_enable_asynccancel-.Lenable0b +.Ldisable0: + .long __pthread_disable_asynccancel-.Ldisable0b +.Lunwind: + .long HIDDEN_JUMPTARGET (__pthread_unwind)-.Lunwindb + .size sem_timedwait,.-sem_timedwait diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sem_trywait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sem_trywait.S new file mode 100644 index 000000000..00c61f3bb --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sem_trywait.S @@ -0,0 +1,89 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <pthread-errnos.h> +#include "lowlevel-atomic.h" + + + .text + + .globl __new_sem_trywait + .type __new_sem_trywait,@function + .align 5 +__new_sem_trywait: + mov.l r12, @-r15 + mov.l r8, @-r15 + sts.l pr, @-r15 + mov r4, r8 + mov.l @r8, r0 +2: + tst r0, r0 + bt 1f + + mov r0, r3 + mov r0, r4 + add #-1, r3 + CMPXCHG (r4, @r8, r3, r2) + bf/s 2b + mov r2, r0 + + lds.l @r15+, pr + mov.l @r15+, r8 + mov.l @r15+, r12 + rts + mov #0, r0 + +1: + mov #EAGAIN, r8 + mova .Lgot1, r0 + mov.l .Lgot1, r12 + add r0, r12 + +#if USE___THREAD + mov.l .Lerrno1, r0 + stc gbr, r1 + mov.l @(r0, r12), r0 + bra .Lexit + add r1, r0 + .align 2 +.Lerrno1: + .long errno@GOTTPOFF +.Lexit: +#else + mov.l .Lerrloc1, r1 + bsrf r1 + nop +.Lerrloc1b: +#endif + mov.l r8, @r0 + lds.l @r15+, pr + mov.l @r15+, r8 + mov.l @r15+, r12 + rts + mov #-1, r0 + + .align 2 +.Lgot1: + .long _GLOBAL_OFFSET_TABLE_ +#if !USE___THREAD +.Lerrloc1: + .long __errno_location@PLT-(.Lerrloc1b-.) +#endif + .size __new_sem_trywait,.-__new_sem_trywait + weak_alias(__new_sem_trywait, sem_trywait) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sem_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sem_wait.S new file mode 100644 index 000000000..7d13fa130 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sem_wait.S @@ -0,0 +1,166 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <pthread-errnos.h> +#include <tcb-offsets.h> +#include "lowlevel-atomic.h" + + +#define SYS_gettimeofday __NR_gettimeofday +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + + .text + + .globl __new_sem_wait + .type __new_sem_wait,@function + .align 5 + cfi_startproc +__new_sem_wait: + /* First check for cancellation. */ + stc gbr, r0 + mov.w .Lchand, r1 + mov.l @(r0,r1), r0 + mov #0xf9, r1 + and r1, r0 + cmp/eq #8, r0 + bt 5f + + mov.l r8, @-r15 + cfi_adjust_cfa_offset(4) + cfi_rel_offset (r8, 0) + mov.l r10, @-r15 + cfi_adjust_cfa_offset(4) + cfi_rel_offset (r10, 0) + mov.l r12, @-r15 + cfi_adjust_cfa_offset(4) + cfi_rel_offset (r12, 0) + sts.l pr, @-r15 + cfi_adjust_cfa_offset(4) + cfi_rel_offset (pr, 0) + mov r4, r8 +3: + mov.l @r8, r0 +2: + tst r0, r0 + bt 1f + mov r0, r3 + mov r0, r4 + add #-1, r3 + CMPXCHG (r4, @r8, r3, r2) + bf/s 2b + mov r2, r0 + bra 9f + mov #0, r0 + +1: + mov.l .Lenable0, r1 + bsrf r1 + nop +.Lenable0b: + mov r0, r10 + + mov r8, r4 + mov #FUTEX_WAIT, r5 + mov #0, r6 + mov #0, r7 + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + + mov.l .Ldisable0, r1 + mov r10, r4 + bsrf r1 + mov r0, r10 +.Ldisable0b: + mov r10, r0 + + tst r0, r0 + bt 3b + cmp/eq #-EWOULDBLOCK, r0 + bt 3b + neg r0, r0 + + mov r0, r8 + mova .Lgot0, r0 + mov.l .Lgot0, r12 + add r0, r12 + +#if USE___THREAD + mov.l .Lerrno0, r0 + stc gbr, r1 + mov.l @(r0, r12), r0 + bra .Lexit + add r1, r0 + .align 2 +.Lerrno0: + .long errno@GOTTPOFF +.Lexit: +#else + mov.l .Lerrloc0, r1 + bsrf r1 + nop +.Lerrloc0b: +#endif + mov.l r8, @r0 + mov #-1, r0 +9: + lds.l @r15+, pr + mov.l @r15+, r12 + mov.l @r15+, r10 + rts + mov.l @r15+, r8 +5: + /* Canceled. */ + stc gbr, r0 + mov.w .Lresult, r1 + mov #-1, r2 + mov.l r2, @(r0,r1) + mov.w .Lchand, r0 + or.b #0x10, @(r0,gbr) + stc gbr, r0 + mov.w .Lclbuf, r1 + mov.l .Lunwind, r2 + braf r2 + mov.l @(r0,r1), r4 +.Lunwindb: + cfi_endproc + +.Lchand: + .word CANCELHANDLING - TLS_PRE_TCB_SIZE +.Lresult: + .word RESULT - TLS_PRE_TCB_SIZE +.Lclbuf: + .word CLEANUP_JMP_BUF - TLS_PRE_TCB_SIZE + .align 2 +.Lgot0: + .long _GLOBAL_OFFSET_TABLE_ +#if !USE___THREAD +.Lerrloc0: + .long __errno_location@PLT-(.Lerrloc0b-.) +#endif +.Lenable0: + .long __pthread_enable_asynccancel-.Lenable0b +.Ldisable0: + .long __pthread_disable_asynccancel-.Ldisable0b +.Lunwind: + .long HIDDEN_JUMPTARGET (__pthread_unwind)-.Lunwindb + .size __new_sem_wait,.-__new_sem_wait + weak_alias(__new_sem_wait, sem_wait) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sh4/lowlevellock.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sh4/lowlevellock.h new file mode 100644 index 000000000..8cdcac556 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sh4/lowlevellock.h @@ -0,0 +1,4 @@ +/* 4 instruction cycles not accessing cache and TLB are needed after + trapa instruction to avoid an SH-4 silicon bug. */ +#define NEED_SYSCALL_INST_PAD +#include <sysdeps/unix/sysv/linux/sh/lowlevellock.h> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sh4/sysdep.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sh4/sysdep.h new file mode 100644 index 000000000..1aed1a14a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sh4/sysdep.h @@ -0,0 +1,4 @@ +/* 4 instruction cycles not accessing cache and TLB are needed after + trapa instruction to avoid an SH-4 silicon bug. */ +#define NEED_SYSCALL_INST_PAD +#include_next <sysdep.h> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/smp.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/smp.h new file mode 100644 index 000000000..2c0cbe99a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/smp.h @@ -0,0 +1,24 @@ +/* Determine whether the host has multiple processors. SH version. + Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +static inline int +is_smp_system (void) +{ + return 0; +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sysdep-cancel.h new file mode 100644 index 000000000..dbaa44385 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sysdep-cancel.h @@ -0,0 +1,247 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <tls.h> +#include <sysdep.h> +#ifndef __ASSEMBLER__ +# include <pthreadP.h> +#endif + +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt + +# define _IMM12 #-12 +# define _IMM16 #-16 +# define _IMP16 #16 +# undef PSEUDO +# define PSEUDO(name, syscall_name, args) \ + .text; \ + ENTRY (name); \ + .Lpseudo_start: \ + SINGLE_THREAD_P; \ + bf .Lpseudo_cancel; \ + .type __##syscall_name##_nocancel,@function; \ + .globl __##syscall_name##_nocancel; \ + __##syscall_name##_nocancel: \ + DO_CALL (syscall_name, args); \ + mov r0,r1; \ + mov _IMM12,r2; \ + shad r2,r1; \ + not r1,r1; \ + tst r1,r1; \ + bt .Lsyscall_error; \ + bra .Lpseudo_end; \ + nop; \ + .size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel; \ + .Lpseudo_cancel: \ + sts.l pr,@-r15; \ + .LCFI0: \ + add _IMM16,r15; \ + SAVE_ARGS_##args; \ + .LCFI1: \ + CENABLE; \ + LOAD_ARGS_##args; \ + add _IMP16,r15; \ + .LCFI2: \ + lds.l @r15+,pr; \ + .LCFI3: \ + DO_CALL(syscall_name, args); \ + SYSCALL_INST_PAD; \ + sts.l pr,@-r15; \ + .LCFI4: \ + mov.l r0,@-r15; \ + .LCFI5: \ + CDISABLE; \ + mov.l @r15+,r0; \ + .LCFI6: \ + lds.l @r15+,pr; \ + .LCFI7: \ + mov r0,r1; \ + mov _IMM12,r2; \ + shad r2,r1; \ + not r1,r1; \ + tst r1,r1; \ + bf .Lpseudo_end; \ + .Lsyscall_error: \ + SYSCALL_ERROR_HANDLER; \ + .Lpseudo_end: \ + /* Create unwinding information for the syscall wrapper. */ \ + .section .eh_frame,"a",@progbits; \ + .Lframe1: \ + .ualong .LECIE1-.LSCIE1; \ + .LSCIE1: \ + .ualong 0x0; \ + .byte 0x1; \ + AUGMENTATION_STRING; \ + .uleb128 0x1; \ + .sleb128 -4; \ + .byte 0x11; \ + AUGMENTATION_PARAM; \ + .byte 0xc; \ + .uleb128 0xf; \ + .uleb128 0x0; \ + .align 2; \ + .LECIE1: \ + .LSFDE1: \ + .ualong .LEFDE1-.LASFDE1; \ + .LASFDE1: \ + .ualong .LASFDE1-.Lframe1; \ + START_SYMBOL_REF; \ + .ualong .Lpseudo_end - .Lpseudo_start; \ + AUGMENTATION_PARAM_FDE; \ + .byte 0x4; \ + .ualong .LCFI0-.Lpseudo_start; \ + .byte 0xe; \ + .uleb128 0x4; \ + .byte 0x91; \ + .uleb128 0x1; \ + .byte 0x4; \ + .ualong .LCFI1-.LCFI0; \ + .byte 0xe; \ + .uleb128 0x14; \ + FRAME_REG_##args; \ + .byte 0x4; \ + .ualong .LCFI2-.LCFI1; \ + .byte 0xe; \ + .uleb128 0x4; \ + .byte 0x4; \ + .ualong .LCFI3-.LCFI2; \ + .byte 0xe; \ + .uleb128 0x0; \ + .byte 0xd1; \ + .byte 0x4; \ + .ualong .LCFI4-.LCFI3; \ + .byte 0xe; \ + .uleb128 0x4; \ + .byte 0x91; \ + .uleb128 0x1; \ + .byte 0x4; \ + .ualong .LCFI5-.LCFI4; \ + .byte 0xe; \ + .uleb128 0x8; \ + .byte 0x80; \ + .uleb128 0x2; \ + .byte 0x4; \ + .ualong .LCFI6-.LCFI5; \ + .byte 0xe; \ + .uleb128 0x4; \ + .byte 0xc0; \ + .byte 0x4; \ + .ualong .LCFI7-.LCFI6; \ + .byte 0xe; \ + .uleb128 0x0; \ + .byte 0xd1; \ + .align 2; \ + .LEFDE1: \ + .previous + +# ifdef SHARED +# define AUGMENTATION_STRING .string "zR" +# define AUGMENTATION_PARAM .uleb128 1; .byte 0x1b +# define AUGMENTATION_PARAM_FDE .uleb128 0 +# define START_SYMBOL_REF .long .Lpseudo_start-. +# else +# define AUGMENTATION_STRING .ascii "\0" +# define AUGMENTATION_PARAM +# define AUGMENTATION_PARAM_FDE +# define START_SYMBOL_REF .long .Lpseudo_start +# endif + +# define FRAME_REG_0 /* Nothing. */ +# define FRAME_REG_1 FRAME_REG_0; .byte 0x84; .uleb128 5 +# define FRAME_REG_2 FRAME_REG_1; .byte 0x85; .uleb128 4 +# define FRAME_REG_3 FRAME_REG_2; .byte 0x86; .uleb128 3 +# define FRAME_REG_4 FRAME_REG_3; .byte 0x87; .uleb128 2 +# define FRAME_REG_5 FRAME_REG_4 +# define FRAME_REG_6 FRAME_REG_5 + +# undef PSEUDO_END +# define PSEUDO_END(sym) \ + END (sym) + +# define SAVE_ARGS_0 /* Nothing. */ +# define SAVE_ARGS_1 SAVE_ARGS_0; mov.l r4,@(0,r15) +# define SAVE_ARGS_2 SAVE_ARGS_1; mov.l r5,@(4,r15) +# define SAVE_ARGS_3 SAVE_ARGS_2; mov.l r6,@(8,r15) +# define SAVE_ARGS_4 SAVE_ARGS_3; mov.l r7,@(12,r15) +# define SAVE_ARGS_5 SAVE_ARGS_4 +# define SAVE_ARGS_6 SAVE_ARGS_5 + +# define LOAD_ARGS_0 /* Nothing. */ +# define LOAD_ARGS_1 LOAD_ARGS_0; mov.l @(0,r15),r4 +# define LOAD_ARGS_2 LOAD_ARGS_1; mov.l @(4,r15),r5 +# define LOAD_ARGS_3 LOAD_ARGS_2; mov.l @(8,r15),r6 +# define LOAD_ARGS_4 LOAD_ARGS_3; mov.l @(12,r15),r7 +# define LOAD_ARGS_5 LOAD_ARGS_4 +# define LOAD_ARGS_6 LOAD_ARGS_5 + +# ifdef IS_IN_libpthread +# define __local_enable_asynccancel __pthread_enable_asynccancel +# define __local_disable_asynccancel __pthread_disable_asynccancel +# elif !defined NOT_IN_libc +# define __local_enable_asynccancel __libc_enable_asynccancel +# define __local_disable_asynccancel __libc_disable_asynccancel +# elif defined IS_IN_librt +# define __local_enable_asynccancel __librt_enable_asynccancel +# define __local_disable_asynccancel __librt_disable_asynccancel +# else +# error Unsupported library +# endif + +# define CENABLE \ + mov.l 1f,r0; \ + bsrf r0; \ + nop; \ + 0: bra 2f; \ + mov r0,r2; \ + .align 2; \ + 1: .long __local_enable_asynccancel - 0b; \ + 2: + +# define CDISABLE \ + mov.l 1f,r0; \ + bsrf r0; \ + mov r2,r4; \ + 0: bra 2f; \ + nop; \ + .align 2; \ + 1: .long __local_disable_asynccancel - 0b; \ + 2: + +# ifndef __ASSEMBLER__ +# define SINGLE_THREAD_P \ + __builtin_expect (THREAD_GETMEM (THREAD_SELF, \ + header.multiple_threads) == 0, 1) +# else +# define SINGLE_THREAD_P \ + stc gbr,r0; \ + mov.w 0f,r1; \ + sub r1,r0; \ + mov.l @(MULTIPLE_THREADS_OFFSET,r0),r0; \ + bra 1f; \ + tst r0,r0; \ + 0: .word TLS_PRE_TCB_SIZE; \ + 1: + +# endif + +#elif !defined __ASSEMBLER__ + +# define SINGLE_THREAD_P (1) +# define NO_CANCELLATION 1 + +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sysdep.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sysdep.h new file mode 100644 index 000000000..7e9223b70 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sysdep.h @@ -0,0 +1,224 @@ +/* Copyright (C) 1992,1993,1995,1996,1997,1998,1999,2000,2002,2003,2004 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper, <drepper@gnu.ai.mit.edu>, August 1995. + Changed by Kaz Kojima, <kkojima@rr.iij4u.or.jp>. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _LINUX_SH_SYSDEP_H +#define _LINUX_SH_SYSDEP_H 1 + +/* There is some commonality. */ +#include <sysdeps/unix/sh/sysdep.h> + +/* For Linux we can use the system call table in the header file + /usr/include/asm/unistd.h + of the kernel. But these symbols do not follow the SYS_* syntax + so we have to redefine the `SYS_ify' macro here. */ +#undef SYS_ify +#define SYS_ify(syscall_name) (__NR_##syscall_name) + + +#ifdef __ASSEMBLER__ + +/* Linux uses a negative return value to indicate syscall errors, + unlike most Unices, which use the condition codes' carry flag. + + Since version 2.1 the return value of a system call might be + negative even if the call succeeded. E.g., the `lseek' system call + might return a large offset. Therefore we must not anymore test + for < 0, but test for a real error by making sure the value in R0 + is a real error number. Linus said he will make sure the no syscall + returns a value in -1 .. -4095 as a valid result so we can savely + test with -4095. */ + +#define _IMM1 #-1 +#define _IMM12 #-12 +#undef PSEUDO +#define PSEUDO(name, syscall_name, args) \ + .text; \ + ENTRY (name); \ + DO_CALL (syscall_name, args); \ + mov r0,r1; \ + mov _IMM12,r2; \ + shad r2,r1; \ + not r1,r1; \ + tst r1,r1; \ + bf .Lpseudo_end; \ + SYSCALL_ERROR_HANDLER; \ + .Lpseudo_end: + +#undef PSEUDO_END +#define PSEUDO_END(name) \ + END (name) + +#undef PSEUDO_NOERRNO +#define PSEUDO_NOERRNO(name, syscall_name, args) \ + .text; \ + ENTRY (name); \ + DO_CALL (syscall_name, args) + +#undef PSEUDO_END_NOERRNO +#define PSEUDO_END_NOERRNO(name) \ + END (name) + +#define ret_NOERRNO ret + +#define PSEUDO_ERRVAL(name, syscall_name, args) \ + .text; \ + ENTRY (name); \ + DO_CALL (syscall_name, args); + +#undef PSEUDO_END_ERRVAL +#define PSEUDO_END_ERRVAL(name) \ + END (name) + +#define ret_ERRVAL ret + +#ifndef __PIC__ +# define SYSCALL_ERROR_HANDLER \ + mov.l 0f,r1; \ + jmp @r1; \ + mov r0,r4; \ + .align 2; \ + 0: .long __syscall_error + +#include <libc/sysdeps/linux/sh/syscall_error.S> +#else +# ifdef RTLD_PRIVATE_ERRNO + +# define SYSCALL_ERROR_HANDLER \ + neg r0,r1; \ + mov.l 0f,r12; \ + mova 0f,r0; \ + add r0,r12; \ + mov.l 1f,r0; \ + mov.l r1,@(r0,r12) + bra .Lpseudo_end; \ + mov _IMM1,r0; \ + .align 2; \ + 0: .long _GLOBAL_OFFSET_TABLE_; \ + 1: .long rtld_errno@GOTOFF + +# elif defined _LIBC_REENTRANT + +# if USE___THREAD + +# ifndef NOT_IN_libc +# define SYSCALL_ERROR_ERRNO __libc_errno +# else +# define SYSCALL_ERROR_ERRNO errno +# endif +# define SYSCALL_ERROR_HANDLER \ + neg r0,r1; \ + mov r12,r2; \ + mov.l 0f,r12; \ + mova 0f,r0; \ + add r0,r12; \ + mov.l 1f,r0; \ + stc gbr, r4; \ + mov.l @(r0,r12),r0; \ + bra .Lskip; \ + add r4,r0; \ + .align 2; \ + 1: .long SYSCALL_ERROR_ERRNO@GOTTPOFF; \ + .Lskip: \ + mov r2,r12; \ + mov.l r1,@r0; \ + bra .Lpseudo_end; \ + mov _IMM1,r0; \ + .align 2; \ + 0: .long _GLOBAL_OFFSET_TABLE_ +# else + +# define SYSCALL_ERROR_HANDLER \ + neg r0,r1; \ + mov.l r14,@-r15; \ + mov.l r12,@-r15; \ + mov.l r1,@-r15; \ + mov.l 0f,r12; \ + mova 0f,r0; \ + add r0,r12; \ + sts.l pr,@-r15; \ + mov r15,r14; \ + mov.l 1f,r1; \ + bsrf r1; \ + nop; \ + 2: mov r14,r15; \ + lds.l @r15+,pr; \ + mov.l @r15+,r1; \ + mov.l r1,@r0; \ + mov.l @r15+,r12; \ + mov.l @r15+,r14; \ + bra .Lpseudo_end; \ + mov _IMM1,r0; \ + .align 2; \ + 0: .long _GLOBAL_OFFSET_TABLE_; \ + 1: .long PLTJMP(C_SYMBOL_NAME(__errno_location))-(2b-.) +/* A quick note: it is assumed that the call to `__errno_location' does + not modify the stack! */ +# endif +# else + +/* Store (-r0) into errno through the GOT. */ +# define SYSCALL_ERROR_HANDLER \ + neg r0,r1; \ + mov r12,r2; \ + mov.l 0f,r12; \ + mova 0f,r0; \ + add r0,r12; \ + mov.l 1f,r0; \ + mov.l @(r0,r12),r0; \ + mov r2,r12; \ + mov.l r1,@r0; \ + bra .Lpseudo_end; \ + mov _IMM1,r0; \ + .align 2; \ + 0: .long _GLOBAL_OFFSET_TABLE_; \ + 1: .long errno@GOT +# endif /* _LIBC_REENTRANT */ +#endif /* __PIC__ */ + +# ifdef NEED_SYSCALL_INST_PAD +# define SYSCALL_INST_PAD \ + or r0,r0; or r0,r0; or r0,r0; or r0,r0; or r0,r0 +# else +# define SYSCALL_INST_PAD +# endif + +#define SYSCALL_INST0 trapa #0x10 +#define SYSCALL_INST1 trapa #0x11 +#define SYSCALL_INST2 trapa #0x12 +#define SYSCALL_INST3 trapa #0x13 +#define SYSCALL_INST4 trapa #0x14 +#define SYSCALL_INST5 mov.l @(0,r15),r0; trapa #0x15 +#define SYSCALL_INST6 mov.l @(0,r15),r0; mov.l @(4,r15),r1; trapa #0x16 + +#undef DO_CALL +#define DO_CALL(syscall_name, args) \ + mov.l 1f,r3; \ + SYSCALL_INST##args; \ + SYSCALL_INST_PAD; \ + bra 2f; \ + nop; \ + .align 2; \ + 1: .long SYS_ify (syscall_name); \ + 2: + +#endif /* __ASSEMBLER__ */ + +#endif /* linux/sh/sysdep.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/vfork.S new file mode 100644 index 000000000..a45c09fd6 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/vfork.S @@ -0,0 +1,71 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#define _ERRNO_H 1 +#include <bits/errno.h> +#include <tcb-offsets.h> + +/* Clone the calling process, but without copying the whole address space. + The calling process is suspended until the new process exits or is + replaced by a call to `execve'. Return -1 for errors, 0 to the new process, + and the process ID of the new process to the old process. */ + +ENTRY (__vfork) + /* Save the PID value. */ + stc gbr, r2 + mov.w .L2, r0 + mov.l @(r0,r2), r4 + neg r4, r1 + tst r1, r1 + bf 1f + mov #1, r1 + rotr r1 +1: + mov.l r1, @(r0,r2) + + mov.w .L1, r3 + trapa #0x10 + mov r0, r1 + + /* Restore the old PID value in the parent. */ + tst r0, r0 + bt.s 2f + stc gbr, r2 + mov.w .L2, r0 + mov.l r4, @(r0,r2) + mov r1, r0 +2: + mov #-12, r2 + shad r2, r1 + not r1, r1 // r1=0 means r0 = -1 to -4095 + tst r1, r1 // i.e. error in linux + bf .Lpseudo_end + SYSCALL_ERROR_HANDLER +.Lpseudo_end: + rts + nop +.L1: + .word __NR_vfork +.L2: + .word PID - TLS_PRE_TCB_SIZE + .align 2 +PSEUDO_END (__vfork) +hidden_def (vfork) + +weak_alias (__vfork, vfork) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sigtimedwait.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sigtimedwait.c new file mode 100644 index 000000000..5159bf9b8 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sigtimedwait.c @@ -0,0 +1,88 @@ +/* Copyright (C) 1997,1998,2000,2002,2003,2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthreadP.h> +#include <errno.h> +#include <signal.h> +#include <string.h> + +#include <sysdep-cancel.h> +#include <sys/syscall.h> + +#ifdef __NR_rt_sigtimedwait + +static int +do_sigtimedwait (const sigset_t *set, siginfo_t *info, + const struct timespec *timeout) +{ +#ifdef SIGCANCEL + sigset_t tmpset; + if (set != NULL + && (__builtin_expect (__sigismember (set, SIGCANCEL), 0) +# ifdef SIGSETXID + || __builtin_expect (__sigismember (set, SIGSETXID), 0) +# endif + )) + { + /* Create a temporary mask without the bit for SIGCANCEL set. */ + // We are not copying more than we have to. + memcpy (&tmpset, set, _NSIG / 8); + __sigdelset (&tmpset, SIGCANCEL); +# ifdef SIGSETXID + __sigdelset (&tmpset, SIGSETXID); +# endif + set = &tmpset; + } +#endif + + /* XXX The size argument hopefully will have to be changed to the + real size of the user-level sigset_t. */ + int result = INLINE_SYSCALL (rt_sigtimedwait, 4, set, + info, timeout, _NSIG / 8); + + /* The kernel generates a SI_TKILL code in si_code in case tkill is + used. tkill is transparently used in raise(). Since having + SI_TKILL as a code is useful in general we fold the results + here. */ + if (result != -1 && info != NULL && info->si_code == SI_TKILL) + info->si_code = SI_USER; + + return result; +} + + +/* Return any pending signal or wait for one for the given time. */ +int attribute_hidden +__sigtimedwait (const sigset_t *set, siginfo_t *info, + const struct timespec *timeout) +{ + if (SINGLE_THREAD_P) + return do_sigtimedwait (set, info, timeout); + + int oldtype = LIBC_CANCEL_ASYNC (); + + /* XXX The size argument hopefully will have to be changed to the + real size of the user-level sigset_t. */ + int result = do_sigtimedwait (set, info, timeout); + + LIBC_CANCEL_RESET (oldtype); + + return result; +} +weak_alias (__sigtimedwait, sigtimedwait) +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sigwait.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sigwait.c new file mode 100644 index 000000000..bde0a9292 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sigwait.c @@ -0,0 +1,2 @@ +#include <pthreadP.h> +#include "../../../../../../libc/signal/sigwait.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sigwaitinfo.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sigwaitinfo.c new file mode 100644 index 000000000..6c47fdee6 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sigwaitinfo.c @@ -0,0 +1,88 @@ +/* Copyright (C) 1997,1998,2000,2002,2003,2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthreadP.h> +#include <errno.h> +#include <signal.h> +#define __need_NULL +#include <stddef.h> +#include <string.h> + +#include <sysdep-cancel.h> +#include <sys/syscall.h> + +#ifdef __NR_rt_sigtimedwait + +static int +do_sigwaitinfo (const sigset_t *set, siginfo_t *info) +{ +#ifdef SIGCANCEL + sigset_t tmpset; + if (set != NULL + && (__builtin_expect (__sigismember (set, SIGCANCEL), 0) +# ifdef SIGSETXID + || __builtin_expect (__sigismember (set, SIGSETXID), 0) +# endif + )) + { + /* Create a temporary mask without the bit for SIGCANCEL set. */ + // We are not copying more than we have to. + memcpy (&tmpset, set, _NSIG / 8); + __sigdelset (&tmpset, SIGCANCEL); +# ifdef SIGSETXID + __sigdelset (&tmpset, SIGSETXID); +# endif + set = &tmpset; + } +#endif + + /* XXX The size argument hopefully will have to be changed to the + real size of the user-level sigset_t. */ + int result = INLINE_SYSCALL (rt_sigtimedwait, 4, set, + info, NULL, _NSIG / 8); + + /* The kernel generates a SI_TKILL code in si_code in case tkill is + used. tkill is transparently used in raise(). Since having + SI_TKILL as a code is useful in general we fold the results + here. */ + if (result != -1 && info != NULL && info->si_code == SI_TKILL) + info->si_code = SI_USER; + + return result; +} + + +/* Return any pending signal or wait for one for the given time. */ +int +__sigwaitinfo (const sigset_t *set, siginfo_t *info) +{ + if (SINGLE_THREAD_P) + return do_sigwaitinfo (set, info); + + int oldtype = LIBC_CANCEL_ASYNC (); + + /* XXX The size argument hopefully will have to be changed to the + real size of the user-level sigset_t. */ + int result = do_sigwaitinfo (set, info); + + LIBC_CANCEL_RESET (oldtype); + + return result; +} +weak_alias (__sigwaitinfo, sigwaitinfo) +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sleep.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sleep.c new file mode 100644 index 000000000..9e948adce --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sleep.c @@ -0,0 +1,2 @@ +#include <pthreadP.h> +#include <../../../../../../libc/unistd/sleep.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/smp.h b/libpthread/nptl/sysdeps/unix/sysv/linux/smp.h new file mode 100644 index 000000000..41fa97ff4 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/smp.h @@ -0,0 +1,52 @@ +/* Determine whether the host has multiple processors. Linux version. + Copyright (C) 1996, 2002, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <errno.h> +#include <fcntl.h> +#include <string.h> +#include <sys/sysctl.h> +#include <not-cancel.h> + +/* Test whether the machine has more than one processor. This is not the + best test but good enough. More complicated tests would require `malloc' + which is not available at that time. */ +static inline int +is_smp_system (void) +{ + static const int sysctl_args[] = { CTL_KERN, KERN_VERSION }; + char buf[512]; + size_t reslen = sizeof (buf); + + /* Try reading the number using `sysctl' first. */ + if (sysctl ((int *) sysctl_args, + sizeof (sysctl_args) / sizeof (sysctl_args[0]), + buf, &reslen, NULL, 0) < 0) + { + /* This was not successful. Now try reading the /proc filesystem. */ + int fd = open_not_cancel_2 ("/proc/sys/kernel/version", O_RDONLY); + if (__builtin_expect (fd, 0) == -1 + || (reslen = read_not_cancel (fd, buf, sizeof (buf))) <= 0) + /* This also didn't work. We give up and say it's a UP machine. */ + buf[0] = '\0'; + + close_not_cancel_no_status (fd); + } + + return strstr (buf, "SMP") != NULL; +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/Makefile b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/Makefile new file mode 100644 index 000000000..43a6fad84 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/Makefile @@ -0,0 +1,13 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2005 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +top_srcdir=../../../../../../../ +top_builddir=../../../../../../../ +all: objs +include $(top_builddir)Rules.mak +include Makefile.arch +include $(top_srcdir)Makerules diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/Makefile.arch b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/Makefile.arch new file mode 100644 index 000000000..b54731075 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/Makefile.arch @@ -0,0 +1,66 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2006 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +libpthread_SSRC = pt-vfork.S clone.S +libpthread_CSRC = pthread_once.c lowlevellock.c + +libc_a_CSRC = fork.c libc-lowlevellock.c +libc_a_SSRC = clone.S vfork.S + +CFLAGS-OMIT-fork.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +CFLAGS-OMIT-libc-lowlevellock.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 + +ifeq ($(UCLIBC_HAS_STDIO_FUTEXES),y) +CFLAGS-fork.c = -D__USE_STDIO_FUTEXES__ +endif + +ASFLAGS-pt-vfork.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 -D_LIBC_REENTRANT -DUSE___THREAD + +CFLAGS-pthread_once.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +CFLAGS-lowlevellock.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 + + +ASFLAGS-clone.S = -D_LIBC_REENTRANT +ASFLAGS-vfork.S = -D_LIBC_REENTRANT + +ifeq ($(UCLIBC_HAS_THREADS_NATIVE),y) +#Needed to use the correct SYSCALL_ERROR_HANDLER +ASFLAGS-clone.S += -DUSE___THREAD +ASFLAGS-vfork.S += -DUSE___THREAD +ASFLAGS-pt-vfork.S += -DUSE___THREAD +endif + +CFLAGS += $(SSP_ALL_CFLAGS) +#CFLAGS:=$(CFLAGS:-O1=-O2) + +LINUX_ARCH_DIR:=$(top_srcdir)libpthread/nptl/sysdeps/unix/sysv/linux/sparc +LINUX_ARCH_OUT:=$(top_builddir)libpthread/nptl/sysdeps/unix/sysv/linux/sparc + +LINUX_ARCH_OBJ:=$(patsubst %.S,$(LINUX_ARCH_OUT)/%.o,$(libpthread_SSRC)) +LINUX_ARCH_OBJ+=$(patsubst %.c,$(LINUX_ARCH_OUT)/%.o,$(libpthread_CSRC)) + +ifeq ($(DOPIC),y) +libpthread-a-y += $(LINUX_ARCH_OBJ:.o=.os) +else +libpthread-a-y += $(LINUX_ARCH_OBJ) +endif +libpthread-so-y += $(LINUX_ARCH_OBJ:.o=.oS) + +libpthread-nomulti-y+=$(LINUX_ARCH_OBJS) + +LIBC_LINUX_ARCH_OBJ:=$(patsubst %.c,$(LINUX_ARCH_OUT)/%.o,$(libc_a_CSRC)) +LIBC_LINUX_ARCH_OBJ+=$(patsubst %.S,$(LINUX_ARCH_OUT)/%.o,$(libc_a_SSRC)) + +libc-static-y+=$(LIBC_LINUX_ARCH_OBJ) +libc-shared-y+=$(LIBC_LINUX_ARCH_OBJ:.o=.oS) + +libc-nomulti-y+=$(LIBC_LINUX_ARCH_OBJ) + +objclean-y+=nptl_linux_arch_clean + +nptl_linux_arch_clean: + $(do_rm) $(addprefix $(LINUX_ARCH_OUT)/*., o os oS) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/Versions b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/Versions new file mode 100644 index 000000000..d10277248 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/Versions @@ -0,0 +1,6 @@ +libpthread { + GLIBC_2.3.3 { + # Changed PTHREAD_STACK_MIN. + pthread_attr_setstack; pthread_attr_setstacksize; + } +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/bits/local_lim.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/bits/local_lim.h new file mode 100644 index 000000000..e082ea8f0 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/bits/local_lim.h @@ -0,0 +1,89 @@ +/* Minimum guaranteed maximum values for system limits. Linux/SPARC version. + Copyright (C) 1993-1998,2000,2002,2003,2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* The kernel header pollutes the namespace with the NR_OPEN symbol + and defines LINK_MAX although filesystems have different maxima. A + similar thing is true for OPEN_MAX: the limit can be changed at + runtime and therefore the macro must not be defined. Remove this + after including the header if necessary. */ +#ifndef NR_OPEN +# define __undef_NR_OPEN +#endif +#ifndef LINK_MAX +# define __undef_LINK_MAX +#endif +#ifndef OPEN_MAX +# define __undef_OPEN_MAX +#endif + +/* The kernel sources contain a file with all the needed information. */ +#include <linux/limits.h> + +/* Have to remove NR_OPEN? */ +#ifdef __undef_NR_OPEN +# undef NR_OPEN +# undef __undef_NR_OPEN +#endif +/* Have to remove LINK_MAX? */ +#ifdef __undef_LINK_MAX +# undef LINK_MAX +# undef __undef_LINK_MAX +#endif +/* Have to remove OPEN_MAX? */ +#ifdef __undef_OPEN_MAX +# undef OPEN_MAX +# undef __undef_OPEN_MAX +#endif + +/* The number of data keys per process. */ +#define _POSIX_THREAD_KEYS_MAX 128 +/* This is the value this implementation supports. */ +#define PTHREAD_KEYS_MAX 1024 + +/* Controlling the iterations of destructors for thread-specific data. */ +#define _POSIX_THREAD_DESTRUCTOR_ITERATIONS 4 +/* Number of iterations this implementation does. */ +#define PTHREAD_DESTRUCTOR_ITERATIONS _POSIX_THREAD_DESTRUCTOR_ITERATIONS + +/* The number of threads per process. */ +#define _POSIX_THREAD_THREADS_MAX 64 +/* We have no predefined limit on the number of threads. */ +#undef PTHREAD_THREADS_MAX + +/* Maximum amount by which a process can descrease its asynchronous I/O + priority level. */ +#define AIO_PRIO_DELTA_MAX 20 + +/* Minimum size for a thread. We are free to choose a reasonable value. */ +#define PTHREAD_STACK_MIN 24576 + +/* Maximum number of timer expiration overruns. */ +#define DELAYTIMER_MAX 2147483647 + +/* Maximum tty name length. */ +#define TTY_NAME_MAX 32 + +/* Maximum login name length. This is arbitrary. */ +#define LOGIN_NAME_MAX 256 + +/* Maximum host name length. */ +#define HOST_NAME_MAX 64 + +/* Maximum message queue priority level. */ +#define MQ_PRIO_MAX 32768 diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/bits/pthreadtypes.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/bits/pthreadtypes.h new file mode 100644 index 000000000..459d1ca79 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/bits/pthreadtypes.h @@ -0,0 +1,218 @@ +/* Machine-specific pthread type layouts. SPARC version. + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _BITS_PTHREADTYPES_H +#define _BITS_PTHREADTYPES_H 1 + +#include <bits/wordsize.h> + +#if __WORDSIZE == 64 +# define __SIZEOF_PTHREAD_ATTR_T 56 +# define __SIZEOF_PTHREAD_MUTEX_T 40 +# define __SIZEOF_PTHREAD_MUTEXATTR_T 4 +# define __SIZEOF_PTHREAD_COND_T 48 +# define __SIZEOF_PTHREAD_CONDATTR_T 4 +# define __SIZEOF_PTHREAD_RWLOCK_T 56 +# define __SIZEOF_PTHREAD_RWLOCKATTR_T 8 +# define __SIZEOF_PTHREAD_BARRIER_T 32 +# define __SIZEOF_PTHREAD_BARRIERATTR_T 4 +#else +# define __SIZEOF_PTHREAD_ATTR_T 36 +# define __SIZEOF_PTHREAD_MUTEX_T 24 +# define __SIZEOF_PTHREAD_MUTEXATTR_T 4 +# define __SIZEOF_PTHREAD_COND_T 48 +# define __SIZEOF_PTHREAD_CONDATTR_T 4 +# define __SIZEOF_PTHREAD_RWLOCK_T 32 +# define __SIZEOF_PTHREAD_RWLOCKATTR_T 8 +# define __SIZEOF_PTHREAD_BARRIER_T 20 +# define __SIZEOF_PTHREAD_BARRIERATTR_T 4 +#endif + + +/* Thread identifiers. The structure of the attribute type is + deliberately not exposed. */ +typedef unsigned long int pthread_t; + + +typedef union +{ + char __size[__SIZEOF_PTHREAD_ATTR_T]; + long int __align; +} pthread_attr_t; + + +#if __WORDSIZE == 64 +typedef struct __pthread_internal_list +{ + struct __pthread_internal_list *__prev; + struct __pthread_internal_list *__next; +} __pthread_list_t; +#else +typedef struct __pthread_internal_slist +{ + struct __pthread_internal_slist *__next; +} __pthread_slist_t; +#endif + + +/* Data structures for mutex handling. The structure of the attribute + type is deliberately not exposed. */ +typedef union +{ + struct __pthread_mutex_s + { + int __lock; + unsigned int __count; + int __owner; +#if __WORDSIZE == 64 + unsigned int __nusers; +#endif + /* KIND must stay at this position in the structure to maintain + binary compatibility. */ + int __kind; +#if __WORDSIZE == 64 + int __spins; + __pthread_list_t __list; +# define __PTHREAD_MUTEX_HAVE_PREV 1 +#else + unsigned int __nusers; + __extension__ union + { + int __spins; + __pthread_slist_t __list; + }; +#endif + } __data; + char __size[__SIZEOF_PTHREAD_MUTEX_T]; + long int __align; +} pthread_mutex_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_MUTEXATTR_T]; + int __align; +} pthread_mutexattr_t; + + +/* Data structure for conditional variable handling. The structure of + the attribute type is deliberately not exposed. */ +typedef union +{ + struct + { + int __lock; + unsigned int __futex; + __extension__ unsigned long long int __total_seq; + __extension__ unsigned long long int __wakeup_seq; + __extension__ unsigned long long int __woken_seq; + void *__mutex; + unsigned int __nwaiters; + unsigned int __broadcast_seq; + } __data; + char __size[__SIZEOF_PTHREAD_COND_T]; + __extension__ long long int __align; +} pthread_cond_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_CONDATTR_T]; + int __align; +} pthread_condattr_t; + + +/* Keys for thread-specific data */ +typedef unsigned int pthread_key_t; + + +/* Once-only execution */ +typedef int pthread_once_t; + + +#if defined __USE_UNIX98 || defined __USE_XOPEN2K +/* Data structure for read-write lock variable handling. The + structure of the attribute type is deliberately not exposed. */ +typedef union +{ +# if __WORDSIZE == 64 + struct + { + int __lock; + unsigned int __nr_readers; + unsigned int __readers_wakeup; + unsigned int __writer_wakeup; + unsigned int __nr_readers_queued; + unsigned int __nr_writers_queued; + int __writer; + int __pad1; + unsigned long int __pad2; + unsigned long int __pad3; + /* FLAGS must stay at this position in the structure to maintain + binary compatibility. */ + unsigned int __flags; + } __data; +# else + struct + { + int __lock; + unsigned int __nr_readers; + unsigned int __readers_wakeup; + unsigned int __writer_wakeup; + unsigned int __nr_readers_queued; + unsigned int __nr_writers_queued; + /* FLAGS must stay at this position in the structure to maintain + binary compatibility. */ + unsigned int __flags; + int __writer; + } __data; +# endif + char __size[__SIZEOF_PTHREAD_RWLOCK_T]; + long int __align; +} pthread_rwlock_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_RWLOCKATTR_T]; + long int __align; +} pthread_rwlockattr_t; +#endif + + +#ifdef __USE_XOPEN2K +/* POSIX spinlock data type. */ +typedef volatile int pthread_spinlock_t; + + +/* POSIX barriers data type. The structure of the type is + deliberately not exposed. */ +typedef union +{ + char __size[__SIZEOF_PTHREAD_BARRIER_T]; + long int __align; +} pthread_barrier_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_BARRIERATTR_T]; + int __align; +} pthread_barrierattr_t; +#endif + + +#endif /* bits/pthreadtypes.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/bits/semaphore.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/bits/semaphore.h new file mode 100644 index 000000000..7f3a32832 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/bits/semaphore.h @@ -0,0 +1,44 @@ +/* Machine-specific POSIX semaphore type layouts. SPARC version. + Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _SEMAPHORE_H +# error "Never use <bits/semaphore.h> directly; include <semaphore.h> instead." +#endif + +#include <bits/wordsize.h> + +#if __WORDSIZE == 64 +# define __SIZEOF_SEM_T 32 +#else +# define __SIZEOF_SEM_T 16 +#endif + +/* Value returned if `sem_open' failed. */ +#define SEM_FAILED ((sem_t *) 0) + +/* Maximum value the semaphore can have. */ +#define SEM_VALUE_MAX (2147483647) + + +typedef union +{ + char __size[__SIZEOF_SEM_T]; + long int __align; +} sem_t; diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/clone.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/clone.S new file mode 100644 index 000000000..dfc5e8261 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/clone.S @@ -0,0 +1,5 @@ +#if defined(__arch64__) +#include "./sparc64/clone.S" +#else +#include "./sparc32/clone.S" +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/fork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/fork.c new file mode 100644 index 000000000..1cd79110a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/fork.c @@ -0,0 +1,29 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sched.h> +#include <signal.h> +#include <sysdep.h> +#include <tls.h> + +#define ARCH_FORK() \ + INLINE_CLONE_SYSCALL (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD, \ + 0, NULL, NULL, &THREAD_SELF->tid) + +#include "../fork.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/libc-lowlevellock.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/libc-lowlevellock.c new file mode 100644 index 000000000..b19282281 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/libc-lowlevellock.c @@ -0,0 +1,21 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* No difference to lowlevellock.c, except we lose a couple of functions. */ +#include "lowlevellock.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/lowlevellock.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/lowlevellock.c new file mode 100644 index 000000000..e9ec4df1e --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/lowlevellock.c @@ -0,0 +1,131 @@ +/* low level locking for pthread library. SPARC version. + Copyright (C) 2003, 2006, 2007 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <sys/time.h> + + +/* These functions don't get included in libc.so */ +void +__lll_lock_wait (int *futex) +{ + do + { + int oldval = atomic_compare_and_exchange_val_24_acq (futex, 2, 1); + if (oldval != 0) + lll_futex_wait (futex, 2); + } + while (atomic_compare_and_exchange_val_24_acq (futex, 2, 0) != 0); +} + + +#ifdef IS_IN_libpthread +int +__lll_timedlock_wait (int *futex, const struct timespec *abstime) +{ + /* Reject invalid timeouts. */ + if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) + return EINVAL; + + do + { + struct timeval tv; + struct timespec rt; + + /* Get the current time. */ + (void) gettimeofday (&tv, NULL); + + /* Compute relative timeout. */ + rt.tv_sec = abstime->tv_sec - tv.tv_sec; + rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000; + if (rt.tv_nsec < 0) + { + rt.tv_nsec += 1000000000; + --rt.tv_sec; + } + + /* Already timed out? */ + if (rt.tv_sec < 0) + return ETIMEDOUT; + + /* Wait. */ + int oldval = atomic_compare_and_exchange_val_24_acq (futex, 2, 1); + if (oldval != 0) + lll_futex_timed_wait (futex, 2, &rt); + } + while (atomic_compare_and_exchange_val_24_acq (futex, 2, 0) != 0); + + return 0; +} + +int +lll_unlock_wake_cb(int* futex) +{ + int val = atomic_exchange_24_rel(futex, 0); + + if( __builtin_expect( val > 1, 0 ) ) { + lll_futex_wake( futex, 1 ); + } + + return 0; +} + + +int +__lll_timedwait_tid (int *tidp, const struct timespec *abstime) +{ + int tid; + + if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) + return EINVAL; + + /* Repeat until thread terminated. */ + while ((tid = *tidp) != 0) + { + struct timeval tv; + struct timespec rt; + + /* Get the current time. */ + (void) gettimeofday (&tv, NULL); + + /* Compute relative timeout. */ + rt.tv_sec = abstime->tv_sec - tv.tv_sec; + rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000; + if (rt.tv_nsec < 0) + { + rt.tv_nsec += 1000000000; + --rt.tv_sec; + } + + /* Already timed out? */ + if (rt.tv_sec < 0) + return ETIMEDOUT; + + /* Wait until thread terminates. The kernel so far does not use + the private futex operations for this. */ + if (lll_futex_timed_wait (tidp, tid, &rt) == -ETIMEDOUT) + return ETIMEDOUT; + } + + return 0; +} +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/lowlevellock.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/lowlevellock.h new file mode 100644 index 000000000..4db6fb0b4 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/lowlevellock.h @@ -0,0 +1,258 @@ +/* Copyright (C) 2003, 2004, 2006, 2007, 2008 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Libr \ary; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _LOWLEVELLOCK_H +#define _LOWLEVELLOCK_H 1 + +#include <time.h> +#include <sys/param.h> +#include <bits/pthreadtypes.h> +#include <atomic.h> +#include <sysdep.h> + + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 +#define FUTEX_REQUEUE 3 +#define FUTEX_CMP_REQUEUE 4 +#define FUTEX_WAKE_OP 5 +#define FUTEX_OP_CLEAR_WAKE_IF_GT_ONE ((4 << 24) | 1) + +/* Initializer for compatibility lock. */ +#define LLL_MUTEX_LOCK_INITIALIZER (0) + +#define lll_futex_wait(futexp, val) \ + lll_futex_timed_wait (futexp, val, NULL) + +#define lll_futex_timed_wait(futexp, val, timespec) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + long int __ret; \ + __ret = INTERNAL_SYSCALL (futex, __err, 4, (futexp), \ + FUTEX_WAIT, (val), (timespec)); \ + __ret; \ + }) + +#define lll_futex_wake(futexp, nr) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + long int __ret; \ + __ret = INTERNAL_SYSCALL (futex, __err, 4, (futexp), \ + FUTEX_WAKE, (nr), 0); \ + __ret; \ + }) + +/* Returns non-zero if error happened, zero if success. */ +#define lll_futex_requeue(futexp, nr_wake, nr_move, mutex, val) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + long int __ret; \ + __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp), \ + FUTEX_CMP_REQUEUE, (nr_wake), (nr_move), (mutex), (val)); \ + INTERNAL_SYSCALL_ERROR_P (__ret, __err); \ + }) + +#define lll_robust_dead(futexv) \ + do \ + { \ + int *__futexp = &(futexv); \ + atomic_or (__futexp, FUTEX_OWNER_DIED); \ + lll_futex_wake (__futexp, 1); \ + } \ + while (0) + +/* Returns non-zero if error happened, zero if success. */ +#ifdef __sparc32_atomic_do_lock +/* Avoid FUTEX_WAKE_OP if supporting pre-v9 CPUs. */ +# define lll_futex_wake_unlock(futexp, nr_wake, nr_wake2, futexp2) 1 +#else +# define lll_futex_wake_unlock(futexp, nr_wake, nr_wake2, futexp2) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + long int __ret; \ + \ + __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp), \ + FUTEX_WAKE_OP, \ + (nr_wake), (nr_wake2), (futexp2), \ + FUTEX_OP_CLEAR_WAKE_IF_GT_ONE); \ + INTERNAL_SYSCALL_ERROR_P (__ret, __err); \ + }) +#endif + +static inline int +__attribute__ ((always_inline)) +__lll_trylock (int *futex) +{ + return atomic_compare_and_exchange_val_24_acq (futex, 1, 0) != 0; +} +#define lll_mutex_trylock(futex) __lll_trylock (&(futex)) + +static inline int +__attribute__ ((always_inline)) +__lll_cond_trylock (int *futex) +{ + return atomic_compare_and_exchange_val_24_acq (futex, 2, 0) != 0; +} +#define lll_mutex_cond_trylock(futex) __lll_cond_trylock (&(futex)) + +static inline int +__attribute__ ((always_inline)) +__lll_robust_trylock (int *futex, int id) +{ + return atomic_compare_and_exchange_val_acq (futex, id, 0) != 0; +} +#define lll_robust_trylock(futex, id) \ + __lll_robust_trylock (&(futex), id) + + +extern void __lll_lock_wait (int *futex) attribute_hidden; +extern int __lll_robust_lock_wait (int *futex) attribute_hidden; + +static inline void +__attribute__ ((always_inline)) +__lll_lock (int *futex) +{ + int val = atomic_compare_and_exchange_val_24_acq (futex, 1, 0); + + if (__builtin_expect (val != 0, 0)) + { + __lll_lock_wait (futex); + } +} +#define lll_mutex_lock(futex) __lll_lock (&(futex)) + +static inline int +__attribute__ ((always_inline)) +__lll_robust_lock (int *futex, int id) +{ + int result = 0; + if (atomic_compare_and_exchange_bool_acq (futex, id, 0) != 0) + result = __lll_robust_lock_wait (futex); + return result; +} +#define lll_robust_lock(futex, id) \ + __lll_robust_lock (&(futex), id) + +static inline void +__attribute__ ((always_inline)) +__lll_cond_lock (int *futex) +{ + int val = atomic_compare_and_exchange_val_24_acq (futex, 2, 0); + + if (__builtin_expect (val != 0, 0)) + __lll_lock_wait (futex); +} +#define lll_mutex_cond_lock(futex) __lll_cond_lock (&(futex)) + +#define lll_robust_cond_lock(futex, id) \ + __lll_robust_lock (&(futex), (id) | FUTEX_WAITERS) + + +extern int __lll_timedlock_wait (int *futex, const struct timespec *) attribute_hidden; +extern int __lll_robust_timedlock_wait (int *futex, const struct timespec *) attribute_hidden; + +static inline int +__attribute__ ((always_inline)) +__lll_timedlock (int *futex, const struct timespec *abstime) +{ + int val = atomic_compare_and_exchange_val_24_acq (futex, 1, 0); + int result = 0; + + if (__builtin_expect (val != 0, 0)) + result = __lll_timedlock_wait (futex, abstime); + return result; +} +#define lll_mutex_timedlock(futex, abstime) \ + __lll_timedlock (&(futex), abstime) + +static inline int +__attribute__ ((always_inline)) +__lll_robust_timedlock (int *futex, const struct timespec *abstime, + int id) +{ + int result = 0; + if (atomic_compare_and_exchange_bool_acq (futex, id, 0) != 0) + result = __lll_robust_timedlock_wait (futex, abstime); + return result; +} +#define lll_robust_timedlock(futex, abstime, id) \ + __lll_robust_timedlock (&(futex), abstime, id) + +#define lll_mutex_unlock(lock) \ + ((void) ({ \ + int *__futex = &(lock); \ + int __val = atomic_exchange_24_rel (__futex, 0); \ + if (__builtin_expect (__val > 1, 0)) \ + lll_futex_wake (__futex, 1); \ + })) + +#define lll_robust_unlock(lock) \ + ((void) ({ \ + int *__futex = &(lock); \ + int __val = atomic_exchange_rel (__futex, 0); \ + if (__builtin_expect (__val & FUTEX_WAITERS, 0)) \ + lll_futex_wake (__futex, 1); \ + })) + +#define lll_mutex_islocked(futex) \ + (futex != 0) + +/* We have a separate internal lock implementation which is not tied + to binary compatibility. */ + +/* Type for lock object. */ +typedef int lll_lock_t; + +/* Initializers for lock. */ +#define LLL_LOCK_INITIALIZER (0) +#define LLL_LOCK_INITIALIZER_LOCKED (1) + +extern int lll_unlock_wake_cb (int *__futex) attribute_hidden; + +#define lll_trylock(lock) lll_mutex_trylock (lock) +#define lll_lock(lock) lll_mutex_lock (lock) +#define lll_unlock(lock) lll_mutex_unlock (lock) +#define lll_islocked(lock) lll_mutex_islocked (lock) + + +/* The kernel notifies a process with uses CLONE_CLEARTID via futex + wakeup when the clone terminates. The memory location contains the + thread ID while the clone is running and is reset to zero + afterwards. */ +#define lll_wait_tid(tid) \ + do \ + { \ + __typeof (tid) __tid; \ + while ((__tid = (tid)) != 0) \ + lll_futex_wait (&(tid), __tid); \ + } \ + while (0) + +extern int __lll_timedwait_tid (int *, const struct timespec *) + attribute_hidden; + +#define lll_timedwait_tid(tid, abstime) \ + ({ \ + int __res = 0; \ + if ((tid) != 0) \ + __res = __lll_timedwait_tid (&(tid), (abstime)); \ + __res; \ + }) + +#endif /* lowlevellock.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/pt-vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/pt-vfork.S new file mode 100644 index 000000000..e8705c54b --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/pt-vfork.S @@ -0,0 +1,5 @@ +#if defined(__arch64__) +#include "sparc64/pt-vfork.S" +#else +#include "sparc32/pt-vfork.S" +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/pthread_once.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/pthread_once.c new file mode 100644 index 000000000..3b07cc127 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/pthread_once.c @@ -0,0 +1,94 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" +#include <lowlevellock.h> + + +unsigned long int __fork_generation attribute_hidden; + + +static void +clear_once_control (void *arg) +{ + pthread_once_t *once_control = (pthread_once_t *) arg; + + *once_control = 0; + lll_futex_wake (once_control, INT_MAX); +} + + +int +__pthread_once (once_control, init_routine) + pthread_once_t *once_control; + void (*init_routine) (void); +{ + while (1) + { + int oldval, val, newval; + + val = *once_control; + do + { + /* Check if the initialized has already been done. */ + if ((val & 2) != 0) + return 0; + + oldval = val; + newval = (oldval & 3) | __fork_generation | 1; + val = atomic_compare_and_exchange_val_acq (once_control, newval, + oldval); + } + while (__builtin_expect (val != oldval, 0)); + + /* Check if another thread already runs the initializer. */ + if ((oldval & 1) != 0) + { + /* Check whether the initializer execution was interrupted + by a fork. */ + if (((oldval ^ newval) & -4) == 0) + { + /* Same generation, some other thread was faster. Wait. */ + lll_futex_wait (once_control, newval); + continue; + } + } + + /* This thread is the first here. Do the initialization. + Register a cleanup handler so that in case the thread gets + interrupted the initialization can be restarted. */ + pthread_cleanup_push (clear_once_control, once_control); + + init_routine (); + + pthread_cleanup_pop (0); + + + /* Add one to *once_control. */ + atomic_increment (once_control); + + /* Wake up all other threads. */ + lll_futex_wake (once_control, INT_MAX); + break; + } + + return 0; +} +weak_alias (__pthread_once, pthread_once) +strong_alias (__pthread_once, __pthread_once_internal) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/clone.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/clone.S new file mode 100644 index 000000000..a6142aafe --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/clone.S @@ -0,0 +1,2 @@ +#define RESET_PID +#include <libc/sysdeps/linux/sparc/clone.S> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/pt-vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/pt-vfork.S new file mode 100644 index 000000000..fb01242b5 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/pt-vfork.S @@ -0,0 +1,45 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2004. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <tcb-offsets.h> + + .text + .globl __syscall_error +ENTRY(__vfork) + ld [%g7 + PID], %o5 + sub %g0, %o5, %o4 + st %o4, [%g7 + PID] + + LOADSYSCALL(vfork) + ta 0x10 + bcc 2f + mov %o7, %g1 + st %o5, [%g7 + PID] + call __syscall_error + mov %g1, %o7 +2: sub %o1, 1, %o1 + andcc %o0, %o1, %o0 + bne,a 1f + st %o5, [%g7 + PID] +1: retl + nop +END(__vfork) + +weak_alias (__vfork, vfork) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sysdep-cancel.h new file mode 100644 index 000000000..ad650d040 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sysdep-cancel.h @@ -0,0 +1,105 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <tls.h> +#include <sysdep.h> +#ifndef __ASSEMBLER__ +# include <pthreadP.h> +#endif + +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt + +# undef PSEUDO +# define PSEUDO(name, syscall_name, args) \ + .text; \ + .globl __syscall_error; \ +ENTRY(name) \ + ld [%g7 + MULTIPLE_THREADS_OFFSET], %g1;\ + cmp %g1, 0; \ + bne 1f; \ +.type __##syscall_name##_nocancel,@function; \ +.globl __##syscall_name##_nocancel; \ +__##syscall_name##_nocancel: \ + mov SYS_ify(syscall_name), %g1; \ + ta 0x10; \ + bcc 8f; \ + mov %o7, %g1; \ + call __syscall_error; \ + mov %g1, %o7; \ +8: jmpl %o7 + 8, %g0; \ + nop; \ +.size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel;\ +1: save %sp, -96, %sp; \ + cfi_def_cfa_register(%fp); \ + cfi_window_save; \ + cfi_register(%o7, %i7); \ + CENABLE; \ + nop; \ + mov %o0, %l0; \ + COPY_ARGS_##args \ + mov SYS_ify(syscall_name), %g1; \ + ta 0x10; \ + bcc 1f; \ + mov %o0, %l1; \ + CDISABLE; \ + mov %l0, %o0; \ + call __syscall_error; \ + mov %l1, %o0; \ + b 2f; \ + mov -1, %l1; \ +1: CDISABLE; \ + mov %l0, %o0; \ +2: jmpl %i7 + 8, %g0; \ + restore %g0, %l1, %o0; + +# ifdef IS_IN_libpthread +# define CENABLE call __pthread_enable_asynccancel +# define CDISABLE call __pthread_disable_asynccancel +# elif !defined NOT_IN_libc +# define CENABLE call __libc_enable_asynccancel +# define CDISABLE call __libc_disable_asynccancel +# elif defined IS_IN_librt +# define CENABLE call __librt_enable_asynccancel +# define CDISABLE call __librt_disable_asynccancel +# else +# error Unsupported library +# endif + +#define COPY_ARGS_0 /* Nothing */ +#define COPY_ARGS_1 COPY_ARGS_0 mov %i0, %o0; +#define COPY_ARGS_2 COPY_ARGS_1 mov %i1, %o1; +#define COPY_ARGS_3 COPY_ARGS_2 mov %i2, %o2; +#define COPY_ARGS_4 COPY_ARGS_3 mov %i3, %o3; +#define COPY_ARGS_5 COPY_ARGS_4 mov %i4, %o4; +#define COPY_ARGS_6 COPY_ARGS_5 mov %i5, %o5; + +# ifndef __ASSEMBLER__ +# define SINGLE_THREAD_P \ + __builtin_expect (THREAD_GETMEM (THREAD_SELF, \ + header.multiple_threads) == 0, 1) +# else +# define SINGLE_THREAD_P ld [%g7 + MULTIPLE_THREADS_OFFSET], %g1 +# endif + +#elif !defined __ASSEMBLER__ + +# define SINGLE_THREAD_P (1) +# define NO_CANCELLATION 1 + +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S new file mode 100644 index 000000000..1a3827789 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S @@ -0,0 +1,49 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2004. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <tcb-offsets.h> + + .text + .globl __syscall_error +ENTRY(__vfork) + ld [%g7 + PID], %o5 + cmp %o5, 0 + bne 1f + sub %g0, %o5, %o4 + sethi %hi(0x80000000), %o4 +1: st %o4, [%g7 + PID] + + LOADSYSCALL(vfork) + ta 0x10 + bcc 2f + mov %o7, %g1 + st %o5, [%g7 + PID] + call __syscall_error + mov %g1, %o7 +2: sub %o1, 1, %o1 + andcc %o0, %o1, %o0 + bne,a 1f + st %o5, [%g7 + PID] +1: retl + nop +END(__vfork) + +hidden_def (vfork) +weak_alias (__vfork, vfork) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/Versions b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/Versions new file mode 100644 index 000000000..3b111ddb5 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/Versions @@ -0,0 +1,7 @@ +librt { + GLIBC_2.3.3 { + # Changed timer_t. + timer_create; timer_delete; timer_getoverrun; timer_gettime; + timer_settime; + } +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/clone.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/clone.S new file mode 100644 index 000000000..64e3bfc12 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/clone.S @@ -0,0 +1,2 @@ +#define RESET_PID +#include <libc/sysdeps/linux/sparc/sparcv9/clone.S> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/pt-vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/pt-vfork.S new file mode 100644 index 000000000..8941043c3 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/pt-vfork.S @@ -0,0 +1,45 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2004. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <tcb-offsets.h> + + .text + .globl __syscall_error +ENTRY(__vfork) + ld [%g7 + PID], %o5 + sub %g0, %o5, %o4 + st %o4, [%g7 + PID] + + LOADSYSCALL(vfork) + ta 0x6d + bcc,pt %xcc, 2f + mov %o7, %g1 + st %o5, [%g7 + PID] + call __syscall_error + mov %g1, %o7 +2: sub %o1, 1, %o1 + andcc %o0, %o1, %o0 + bne,a,pt %icc, 1f + st %o5, [%g7 + PID] +1: retl + nop +END(__vfork) + +weak_alias (__vfork, vfork) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/sysdep-cancel.h new file mode 100644 index 000000000..aec2d4a86 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/sysdep-cancel.h @@ -0,0 +1,110 @@ +/* Copyright (C) 2002, 2003, 2004, 2006 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <tls.h> +#ifndef __ASSEMBLER__ +# include <pthreadP.h> +#endif + +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt + +# undef PSEUDO +# define PSEUDO(name, syscall_name, args) \ + .text; \ + .globl __syscall_error; \ +ENTRY(name) \ + ld [%g7 + MULTIPLE_THREADS_OFFSET], %g1;\ + brnz,pn %g1, 1f; \ +.type __##syscall_name##_nocancel,@function; \ +.globl __##syscall_name##_nocancel; \ +__##syscall_name##_nocancel: \ + mov SYS_ify(syscall_name), %g1; \ + ta 0x6d; \ + bcc,pt %xcc, 8f; \ + mov %o7, %g1; \ + call __syscall_error; \ + mov %g1, %o7; \ +8: jmpl %o7 + 8, %g0; \ + nop; \ +.size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel;\ +1: save %sp, -192, %sp; \ + cfi_def_cfa_register(%fp); \ + cfi_window_save; \ + cfi_register(%o7, %i7); \ + CENABLE; \ + nop; \ + mov %o0, %l0; \ + COPY_ARGS_##args \ + mov SYS_ify(syscall_name), %g1; \ + ta 0x6d; \ + bcc,pt %xcc, 1f; \ + mov %o0, %l1; \ + CDISABLE; \ + mov %l0, %o0; \ + call __syscall_error; \ + mov %l1, %o0; \ + ba,pt %xcc, 2f; \ + mov -1, %l1; \ +1: CDISABLE; \ + mov %l0, %o0; \ +2: jmpl %i7 + 8, %g0; \ + restore %g0, %l1, %o0; + +# ifdef IS_IN_libpthread +# define CENABLE call __pthread_enable_asynccancel +# define CDISABLE call __pthread_disable_asynccancel +# elif !defined NOT_IN_libc +# define CENABLE call __libc_enable_asynccancel +# define CDISABLE call __libc_disable_asynccancel +# elif defined IS_IN_librt +# define CENABLE call __librt_enable_asynccancel +# define CDISABLE call __librt_disable_asynccancel +# else +# error Unsupported library +# endif + +#define COPY_ARGS_0 /* Nothing */ +#define COPY_ARGS_1 COPY_ARGS_0 mov %i0, %o0; +#define COPY_ARGS_2 COPY_ARGS_1 mov %i1, %o1; +#define COPY_ARGS_3 COPY_ARGS_2 mov %i2, %o2; +#define COPY_ARGS_4 COPY_ARGS_3 mov %i3, %o3; +#define COPY_ARGS_5 COPY_ARGS_4 mov %i4, %o4; +#define COPY_ARGS_6 COPY_ARGS_5 mov %i5, %o5; + +# ifndef __ASSEMBLER__ +# define SINGLE_THREAD_P \ + __builtin_expect (THREAD_GETMEM (THREAD_SELF, \ + header.multiple_threads) == 0, 1) +# else +# define SINGLE_THREAD_P ld [%g7 + MULTIPLE_THREADS_OFFSET], %g1 +# endif + +#elif !defined __ASSEMBLER__ + +# define SINGLE_THREAD_P (1) +# define NO_CANCELLATION 1 + +#endif + +#ifndef __ASSEMBLER__ +# define RTLD_SINGLE_THREAD_P \ + __builtin_expect (THREAD_GETMEM (THREAD_SELF, \ + header.multiple_threads) == 0, 1) +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_create.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_create.c new file mode 100644 index 000000000..0a9c3372b --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_create.c @@ -0,0 +1 @@ +#include "../../x86_64/timer_create.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_delete.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_delete.c new file mode 100644 index 000000000..f0d4fd21d --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_delete.c @@ -0,0 +1 @@ +#include "../../x86_64/timer_delete.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_getoverr.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_getoverr.c new file mode 100644 index 000000000..82121a7a2 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_getoverr.c @@ -0,0 +1 @@ +#include "../../x86_64/timer_getoverr.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_gettime.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_gettime.c new file mode 100644 index 000000000..313c05fea --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_gettime.c @@ -0,0 +1 @@ +#include "../../x86_64/timer_gettime.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_settime.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_settime.c new file mode 100644 index 000000000..76f549cb4 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_settime.c @@ -0,0 +1 @@ +#include "../../x86_64/timer_settime.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S new file mode 100644 index 000000000..b4e89aceb --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S @@ -0,0 +1,49 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2004. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <tcb-offsets.h> + + .text + .globl __syscall_error +ENTRY(__vfork) + ld [%g7 + PID], %o5 + sethi %hi(0x80000000), %o3 + cmp %o5, 0 + sub %g0, %o5, %o4 + move %icc, %o3, %o4 + st %o4, [%g7 + PID] + + LOADSYSCALL(vfork) + ta 0x6d + bcc,pt %xcc, 2f + mov %o7, %g1 + st %o5, [%g7 + PID] + call __syscall_error + mov %g1, %o7 +2: sub %o1, 1, %o1 + andcc %o0, %o1, %o0 + bne,a,pt %icc, 1f + st %o5, [%g7 + PID] +1: retl + nop +END(__vfork) + +hidden_def (vfork) +weak_alias (__vfork, vfork) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sysdep-cancel.h new file mode 100644 index 000000000..5be9beb92 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sysdep-cancel.h @@ -0,0 +1,5 @@ +#if defined(__arch64__) +#include "sparc64/sysdep-cancel.h" +#else +#include "sparc32/sysdep-cancel.h" +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sysdep.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sysdep.h new file mode 100644 index 000000000..744e587a3 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sysdep.h @@ -0,0 +1,65 @@ +#ifndef _LINUX_SPARC_SYSDEP_H +#define _LINUX_SPARC_SYSDEP_H 1 + +#include <sysdeps/unix/sysdep.h> + +#undef ENTRY +#undef END + +#ifdef __ASSEMBLER__ + +#define LOADSYSCALL(x) mov __NR_##x, %g1 + +#define ENTRY(name) \ + .align 4; \ + .global C_SYMBOL_NAME(name); \ + .type name, @function; \ +C_LABEL(name) \ + cfi_startproc; + +#define END(name) \ + cfi_endproc; \ + .size name, . - name + +#define LOC(name) .L##name + + /* If the offset to __syscall_error fits into a signed 22-bit + * immediate branch offset, the linker will relax the call into + * a normal branch. + */ +#undef PSEUDO +#undef PSEUDO_END +#undef PSEUDO_NOERRNO +#undef PSEUDO_ERRVAL + +#define PSEUDO(name, syscall_name, args) \ + .text; \ + .globl __syscall_error; \ +ENTRY(name); \ + LOADSYSCALL(syscall_name); \ + ta 0x10; \ + bcc 1f; \ + mov %o7, %g1; \ + call __syscall_error; \ + mov %g1, %o7; \ +1: + +#define PSEUDO_NOERRNO(name, syscall_name, args)\ + .text; \ +ENTRY(name); \ + LOADSYSCALL(syscall_name); \ + ta 0x10; + +#define PSEUDO_ERRVAL(name, syscall_name, args) \ + .text; \ +ENTRY(name); \ + LOADSYSCALL(syscall_name); \ + ta 0x10; + +#define PSEUDO_END(name) \ + END(name) + + +#endif + +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/vfork.S new file mode 100644 index 000000000..160cd0b10 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/vfork.S @@ -0,0 +1,5 @@ +#if defined(__arch64__) +#include "sparc64/vfork.S" +#else +#include "sparc32/vfork.S" +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/timer_create.c b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_create.c new file mode 100644 index 000000000..9f02fe3b2 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_create.c @@ -0,0 +1,236 @@ +/* Copyright (C) 2003,2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <errno.h> +#include <pthread.h> +#include <signal.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <sysdep.h> +#include <bits/kernel-features.h> +#include <internaltypes.h> +#include <pthreadP.h> +#include "kernel-posix-timers.h" +#include "kernel-posix-cpu-timers.h" + + +#ifdef __NR_timer_create +# ifndef __ASSUME_POSIX_TIMERS +static int compat_timer_create (clockid_t clock_id, struct sigevent *evp, + timer_t *timerid); +# define timer_create static compat_timer_create +# include <nptl/sysdeps/pthread/timer_create.c> +# undef timer_create + +/* Nonzero if the system calls are not available. */ +int __no_posix_timers attribute_hidden; +# endif + +# ifdef timer_create_alias +# define timer_create timer_create_alias +# endif + + +int +timer_create ( + clockid_t clock_id, + struct sigevent *evp, + timer_t *timerid) +{ +# undef timer_create +# ifndef __ASSUME_POSIX_TIMERS + if (__no_posix_timers >= 0) +# endif + { + clockid_t syscall_clockid = (clock_id == CLOCK_PROCESS_CPUTIME_ID + ? MAKE_PROCESS_CPUCLOCK (0, CPUCLOCK_SCHED) + : clock_id == CLOCK_THREAD_CPUTIME_ID + ? MAKE_THREAD_CPUCLOCK (0, CPUCLOCK_SCHED) + : clock_id); + + /* If the user wants notification via a thread we need to handle + this special. */ + if (evp == NULL + || __builtin_expect (evp->sigev_notify != SIGEV_THREAD, 1)) + { + struct sigevent local_evp; + + /* We avoid allocating too much memory by basically + using struct timer as a derived class with the + first two elements being in the superclass. We only + need these two elements here. */ + struct timer *newp = (struct timer *) malloc (offsetof (struct timer, + thrfunc)); + if (newp == NULL) + /* No more memory. */ + return -1; + + if (evp == NULL) + { + /* The kernel has to pass up the timer ID which is a + userlevel object. Therefore we cannot leave it up to + the kernel to determine it. */ + local_evp.sigev_notify = SIGEV_SIGNAL; + local_evp.sigev_signo = SIGALRM; + local_evp.sigev_value.sival_ptr = newp; + + evp = &local_evp; + } + + kernel_timer_t ktimerid; + int retval = INLINE_SYSCALL (timer_create, 3, syscall_clockid, evp, + &ktimerid); + +# ifndef __ASSUME_POSIX_TIMERS + if (retval != -1 || errno != ENOSYS) +# endif + { +# ifndef __ASSUME_POSIX_TIMERS + __no_posix_timers = 1; +# endif + + if (retval != -1) + { + newp->sigev_notify = (evp != NULL + ? evp->sigev_notify : SIGEV_SIGNAL); + newp->ktimerid = ktimerid; + + *timerid = (timer_t) newp; + } + else + { + /* Cannot allocate the timer, fail. */ + free (newp); + retval = -1; + } + + return retval; + } + + free (newp); + +# ifndef __ASSUME_POSIX_TIMERS + /* When we come here the syscall does not exist. Make sure we + do not try to use it again. */ + __no_posix_timers = -1; +# endif + } + else + { +# ifndef __ASSUME_POSIX_TIMERS + /* Make sure we have the necessary kernel support. */ + if (__no_posix_timers == 0) + { + INTERNAL_SYSCALL_DECL (err); + struct timespec ts; + int res; + res = INTERNAL_SYSCALL (clock_getres, err, 2, + CLOCK_REALTIME, &ts); + __no_posix_timers = (INTERNAL_SYSCALL_ERROR_P (res, err) + ? -1 : 1); + } + + if (__no_posix_timers > 0) +# endif + { + /* Create the helper thread. */ + pthread_once (&__helper_once, __start_helper_thread); + if (__helper_tid == 0) + { + /* No resources to start the helper thread. */ + __set_errno (EAGAIN); + return -1; + } + + struct timer *newp; + newp = (struct timer *) malloc (sizeof (struct timer)); + if (newp == NULL) + return -1; + + /* Copy the thread parameters the user provided. */ + newp->sival = evp->sigev_value; + newp->thrfunc = evp->sigev_notify_function; + + /* We cannot simply copy the thread attributes since the + implementation might keep internal information for + each instance. */ + (void) pthread_attr_init (&newp->attr); + if (evp->sigev_notify_attributes != NULL) + { + struct pthread_attr *nattr; + struct pthread_attr *oattr; + + nattr = (struct pthread_attr *) &newp->attr; + oattr = (struct pthread_attr *) evp->sigev_notify_attributes; + + nattr->schedparam = oattr->schedparam; + nattr->schedpolicy = oattr->schedpolicy; + nattr->flags = oattr->flags; + nattr->guardsize = oattr->guardsize; + nattr->stackaddr = oattr->stackaddr; + nattr->stacksize = oattr->stacksize; + } + + /* In any case set the detach flag. */ + (void) pthread_attr_setdetachstate (&newp->attr, + PTHREAD_CREATE_DETACHED); + + /* Create the event structure for the kernel timer. */ + struct sigevent sev; + sev.sigev_value.sival_ptr = newp; + sev.sigev_signo = SIGTIMER; + sev.sigev_notify = SIGEV_SIGNAL | SIGEV_THREAD_ID; + /* This is the thread ID of the helper thread. */ + sev._sigev_un._pad[0] = __helper_tid; + + /* Create the timer. */ + INTERNAL_SYSCALL_DECL (err); + int res; + res = INTERNAL_SYSCALL (timer_create, err, 3, + syscall_clockid, &sev, &newp->ktimerid); + if (! INTERNAL_SYSCALL_ERROR_P (res, err)) + { + *timerid = (timer_t) newp; + return 0; + } + + /* Free the resources. */ + free (newp); + + __set_errno (INTERNAL_SYSCALL_ERRNO (res, err)); + + return -1; + } + } + } + +# ifndef __ASSUME_POSIX_TIMERS + /* Compatibility code. */ + return compat_timer_create (clock_id, evp, timerid); +# endif +} +#else +# ifdef timer_create_alias +# define timer_create timer_create_alias +# endif +/* The new system calls are not available. Use the userlevel + implementation. */ +# include <nptl/sysdeps/pthread/timer_create.c> +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/timer_delete.c b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_delete.c new file mode 100644 index 000000000..9b92446d5 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_delete.c @@ -0,0 +1,93 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <errno.h> +#include <stdlib.h> +#include <time.h> +#include <sysdep.h> +#include <bits/kernel-features.h> +#include "kernel-posix-timers.h" + + +#ifdef __NR_timer_delete +# ifndef __ASSUME_POSIX_TIMERS +static int compat_timer_delete (timer_t timerid); +# define timer_delete static compat_timer_delete +# include <nptl/sysdeps/pthread/timer_delete.c> +# undef timer_delete +# endif + +# ifdef timer_delete_alias +# define timer_delete timer_delete_alias +# endif + + +int +timer_delete (timer_t timerid) +{ +# undef timer_delete +# ifndef __ASSUME_POSIX_TIMERS + if (__no_posix_timers >= 0) +# endif + { + struct timer *kt = (struct timer *) timerid; + + /* Delete the kernel timer object. */ + int res = INLINE_SYSCALL (timer_delete, 1, kt->ktimerid); + + if (res == 0) + { +# ifndef __ASSUME_POSIX_TIMERS + /* We know the syscall support is available. */ + __no_posix_timers = 1; +# endif + + /* Free the memory. */ + (void) free (kt); + + return 0; + } + + /* The kernel timer is not known or something else bad happened. + Return the error. */ +# ifndef __ASSUME_POSIX_TIMERS + if (errno != ENOSYS) + { + __no_posix_timers = 1; +# endif + return -1; +# ifndef __ASSUME_POSIX_TIMERS + } + + __no_posix_timers = -1; +# endif + } + +# ifndef __ASSUME_POSIX_TIMERS + return compat_timer_delete (timerid); +# endif +} +#else +# ifdef timer_delete_alias +# define timer_delete timer_delete_alias +# endif +/* The new system calls are not available. Use the userlevel + implementation. */ +# include <nptl/sysdeps/pthread/timer_delete.c> +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/timer_getoverr.c b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_getoverr.c new file mode 100644 index 000000000..7afc5ec6f --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_getoverr.c @@ -0,0 +1,80 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <errno.h> +#include <time.h> +#include <sysdep.h> +#include <bits/kernel-features.h> +#include "kernel-posix-timers.h" + + +#ifdef __NR_timer_getoverrun +# ifndef __ASSUME_POSIX_TIMERS +static int compat_timer_getoverrun (timer_t timerid); +# define timer_getoverrun static compat_timer_getoverrun +# include <nptl/sysdeps/pthread/timer_getoverr.c> +# undef timer_getoverrun +# endif + +# ifdef timer_getoverrun_alias +# define timer_getoverrun timer_getoverrun_alias +# endif + + +int +timer_getoverrun (timer_t timerid) +{ +# undef timer_getoverrun +# ifndef __ASSUME_POSIX_TIMERS + if (__no_posix_timers >= 0) +# endif + { + struct timer *kt = (struct timer *) timerid; + + /* Get the information from the kernel. */ + int res = INLINE_SYSCALL (timer_getoverrun, 1, kt->ktimerid); + +# ifndef __ASSUME_POSIX_TIMERS + if (res != -1 || errno != ENOSYS) + { + /* We know the syscall support is available. */ + __no_posix_timers = 1; +# endif + return res; +# ifndef __ASSUME_POSIX_TIMERS + } +# endif + +# ifndef __ASSUME_POSIX_TIMERS + __no_posix_timers = -1; +# endif + } + +# ifndef __ASSUME_POSIX_TIMERS + return compat_timer_getoverrun (timerid); +# endif +} +#else +# ifdef timer_getoverrun_alias +# define timer_getoverrun timer_getoverrun_alias +# endif +/* The new system calls are not available. Use the userlevel + implementation. */ +# include <nptl/sysdeps/pthread/timer_getoverr.c> +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/timer_gettime.c b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_gettime.c new file mode 100644 index 000000000..31401b19b --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_gettime.c @@ -0,0 +1,83 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <errno.h> +#include <stdlib.h> +#include <time.h> +#include <sysdep.h> +#include <bits/kernel-features.h> +#include "kernel-posix-timers.h" + + +#ifdef __NR_timer_gettime +# ifndef __ASSUME_POSIX_TIMERS +static int compat_timer_gettime (timer_t timerid, struct itimerspec *value); +# define timer_gettime static compat_timer_gettime +# include <nptl/sysdeps/pthread/timer_gettime.c> +# undef timer_gettime +# endif + +# ifdef timer_gettime_alias +# define timer_gettime timer_gettime_alias +# endif + + +int +timer_gettime ( + timer_t timerid, + struct itimerspec *value) +{ +# undef timer_gettime +# ifndef __ASSUME_POSIX_TIMERS + if (__no_posix_timers >= 0) +# endif + { + struct timer *kt = (struct timer *) timerid; + + /* Delete the kernel timer object. */ + int res = INLINE_SYSCALL (timer_gettime, 2, kt->ktimerid, value); + +# ifndef __ASSUME_POSIX_TIMERS + if (res != -1 || errno != ENOSYS) + { + /* We know the syscall support is available. */ + __no_posix_timers = 1; +# endif + return res; +# ifndef __ASSUME_POSIX_TIMERS + } +# endif + +# ifndef __ASSUME_POSIX_TIMERS + __no_posix_timers = -1; +# endif + } + +# ifndef __ASSUME_POSIX_TIMERS + return compat_timer_gettime (timerid, value); +# endif +} +#else +# ifdef timer_gettime_alias +# define timer_gettime timer_gettime_alias +# endif +/* The new system calls are not available. Use the userlevel + implementation. */ +# include <nptl/sysdeps/pthread/timer_gettime.c> +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/timer_routines.c b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_routines.c new file mode 100644 index 000000000..924c524ba --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_routines.c @@ -0,0 +1,159 @@ +/* Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <errno.h> +#include <setjmp.h> +#include <signal.h> +#include <stdbool.h> +#include <sysdep.h> +#include <bits/kernel-features.h> +#include <pthreadP.h> +#include "kernel-posix-timers.h" + + +#ifdef __NR_timer_create +/* Helper thread to call the user-provided function. */ +static void * +timer_sigev_thread (void *arg) +{ + /* The parent thread has all signals blocked. This is a bit + surprising for user code, although valid. We unblock all + signals. */ + sigset_t ss; + sigemptyset (&ss); + INTERNAL_SYSCALL_DECL (err); + INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_SETMASK, &ss, NULL, _NSIG / 8); + + struct timer *tk = (struct timer *) arg; + + /* Call the user-provided function. */ + tk->thrfunc (tk->sival); + + return NULL; +} + + +/* Helper function to support starting threads for SIGEV_THREAD. */ +static void * +timer_helper_thread (void *arg) +{ + /* Wait for the SIGTIMER signal, allowing the setXid signal, and + none else. */ + sigset_t ss; + sigemptyset (&ss); + __sigaddset (&ss, SIGTIMER); + + /* Endless loop of waiting for signals. The loop is only ended when + the thread is canceled. */ + while (1) + { + siginfo_t si; + + /* sigwaitinfo cannot be used here, since it deletes + SIGCANCEL == SIGTIMER from the set. */ + + int oldtype = LIBC_CANCEL_ASYNC (); + + /* XXX The size argument hopefully will have to be changed to the + real size of the user-level sigset_t. */ + int result = INLINE_SYSCALL (rt_sigtimedwait, 4, &ss, &si, NULL, + _NSIG / 8); + + LIBC_CANCEL_RESET (oldtype); + + if (result > 0) + { + if (si.si_code == SI_TIMER) + { + struct timer *tk = (struct timer *) si.si_ptr; + + /* That the signal we are waiting for. */ + pthread_t th; + (void) pthread_create (&th, &tk->attr, timer_sigev_thread, tk); + } + else if (si.si_code == SI_TKILL) + /* The thread is canceled. */ + pthread_exit (NULL); + } + } +} + + +/* Control variable for helper thread creation. */ +pthread_once_t __helper_once attribute_hidden; + + +/* TID of the helper thread. */ +pid_t __helper_tid attribute_hidden; + + +/* Reset variables so that after a fork a new helper thread gets started. */ +static void +reset_helper_control (void) +{ + __helper_once = PTHREAD_ONCE_INIT; + __helper_tid = 0; +} + + +void +attribute_hidden +__start_helper_thread (void) +{ + /* The helper thread needs only very little resources + and should go away automatically when canceled. */ + pthread_attr_t attr; + (void) pthread_attr_init (&attr); + (void) pthread_attr_setstacksize (&attr, PTHREAD_STACK_MIN); + + /* Block all signals in the helper thread but SIGSETXID. To do this + thoroughly we temporarily have to block all signals here. The + helper can lose wakeups if SIGCANCEL is not blocked throughout, + but sigfillset omits it SIGSETXID. So, we add it back + explicitly here. */ + sigset_t ss; + sigset_t oss; + sigfillset (&ss); + __sigaddset (&ss, SIGCANCEL); + INTERNAL_SYSCALL_DECL (err); + INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_SETMASK, &ss, &oss, _NSIG / 8); + + /* Create the helper thread for this timer. */ + pthread_t th; + int res = pthread_create (&th, &attr, timer_helper_thread, NULL); + if (res == 0) + /* We managed to start the helper thread. */ + __helper_tid = ((struct pthread *) th)->tid; + + /* Restore the signal mask. */ + INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_SETMASK, &oss, NULL, + _NSIG / 8); + + /* No need for the attribute anymore. */ + (void) pthread_attr_destroy (&attr); + + /* We have to make sure that after fork()ing a new helper thread can + be created. */ + pthread_atfork (NULL, NULL, reset_helper_control); +} +#endif + +#ifndef __ASSUME_POSIX_TIMERS +# include <nptl/sysdeps/pthread/timer_routines.c> +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/timer_settime.c b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_settime.c new file mode 100644 index 000000000..8c6ad91fa --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_settime.c @@ -0,0 +1,88 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <errno.h> +#include <stdlib.h> +#include <time.h> +#include <sysdep.h> +#include <bits/kernel-features.h> +#include "kernel-posix-timers.h" + + +#ifdef __NR_timer_settime +# ifndef __ASSUME_POSIX_TIMERS +static int compat_timer_settime (timer_t timerid, int flags, + const struct itimerspec *value, + struct itimerspec *ovalue); +# define timer_settime static compat_timer_settime +# include <nptl/sysdeps/pthread/timer_settime.c> +# undef timer_settime +# endif + +# ifdef timer_settime_alias +# define timer_settime timer_settime_alias +# endif + + +int +timer_settime ( + timer_t timerid, + int flags, + const struct itimerspec *value, + struct itimerspec *ovalue) +{ +# undef timer_settime +# ifndef __ASSUME_POSIX_TIMERS + if (__no_posix_timers >= 0) +# endif + { + struct timer *kt = (struct timer *) timerid; + + /* Delete the kernel timer object. */ + int res = INLINE_SYSCALL (timer_settime, 4, kt->ktimerid, flags, + value, ovalue); + +# ifndef __ASSUME_POSIX_TIMERS + if (res != -1 || errno != ENOSYS) + { + /* We know the syscall support is available. */ + __no_posix_timers = 1; +# endif + return res; +# ifndef __ASSUME_POSIX_TIMERS + } +# endif + +# ifndef __ASSUME_POSIX_TIMERS + __no_posix_timers = -1; +# endif + } + +# ifndef __ASSUME_POSIX_TIMERS + return compat_timer_settime (timerid, flags, value, ovalue); +# endif +} +#else +# ifdef timer_settime_alias +# define timer_settime timer_settime_alias +# endif +/* The new system calls are not available. Use the userlevel + implementation. */ +# include <nptl/sysdeps/pthread/timer_settime.c> +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/unregister-atfork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/unregister-atfork.c new file mode 100644 index 000000000..35955238b --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/unregister-atfork.c @@ -0,0 +1,110 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <stdlib.h> +#include "fork.h" +#include <atomic.h> + + +void +__unregister_atfork (void *dso_handle) +{ + /* Check whether there is any entry in the list which we have to + remove. It is likely that this is not the case so don't bother + getting the lock. + + We do not worry about other threads adding entries for this DSO + right this moment. If this happens this is a race and we can do + whatever we please. The program will crash anyway seen. */ + struct fork_handler *runp = __fork_handlers; + struct fork_handler *lastp = NULL; + + while (runp != NULL) + if (runp->dso_handle == dso_handle) + break; + else + { + lastp = runp; + runp = runp->next; + } + + if (runp == NULL) + /* Nothing to do. */ + return; + + /* Get the lock to not conflict with additions or deletions. Note + that there couldn't have been another thread deleting something. + The __unregister_atfork function is only called from the + dlclose() code which itself serializes the operations. */ + lll_lock (__fork_lock); + + /* We have to create a new list with all the entries we don't remove. */ + struct deleted_handler + { + struct fork_handler *handler; + struct deleted_handler *next; + } *deleted = NULL; + + /* Remove the entries for the DSO which is unloaded from the list. + It's a single linked list so readers are. */ + do + { + if (runp->dso_handle == dso_handle) + { + if (lastp == NULL) + __fork_handlers = runp->next; + else + lastp->next = runp->next; + + /* We cannot overwrite the ->next element now. Put the deleted + entries in a separate list. */ + struct deleted_handler *newp = alloca (sizeof (*newp)); + newp->handler = runp; + newp->next = deleted; + deleted = newp; + } + else + lastp = runp; + + runp = runp->next; + } + while (runp != NULL); + + /* Release the lock. */ + lll_unlock (__fork_lock); + + /* Walk the list of all entries which have to be deleted. */ + while (deleted != NULL) + { + /* We need to be informed by possible current users. */ + deleted->handler->need_signal = 1; + /* Make sure this gets written out first. */ + atomic_write_barrier (); + + /* Decrement the reference counter. If it does not reach zero + wait for the last user. */ + atomic_decrement (&deleted->handler->refcntr); + unsigned int val; + while ((val = deleted->handler->refcntr) != 0) + lll_futex_wait (&deleted->handler->refcntr, val); + + deleted = deleted->next; + } +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/unwindbuf.sym b/libpthread/nptl/sysdeps/unix/sysv/linux/unwindbuf.sym new file mode 100644 index 000000000..8044b4078 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/unwindbuf.sym @@ -0,0 +1,7 @@ +#include <pthread.h> +#include <stddef.h> + +-- + +UNWINDBUFSIZE sizeof (__pthread_unwind_buf_t) +UWJMPBUF offsetof (__pthread_unwind_buf_t, __cancel_jmp_buf) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/waitpid.S b/libpthread/nptl/sysdeps/unix/sysv/linux/waitpid.S new file mode 100644 index 000000000..f55d34629 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/waitpid.S @@ -0,0 +1,19 @@ +#include <sysdep-cancel.h> + +/* +extern pid_t __waitpid_nocancel (pid_t, int *, int) attribute_hidden; +*/ +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt + + +PSEUDO (__waitpid, waitpid, 3) +ret +PSEUDO_END(__waitpid) + +libc_hidden_def (__waitpid) +weak_alias (__waitpid, waitpid) +libc_hidden_weak (waitpid) +weak_alias (__waitpid, __libc_waitpid) +libc_hidden_weak (__libc_waitpid) + +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/write.S b/libpthread/nptl/sysdeps/unix/sysv/linux/write.S new file mode 100644 index 000000000..43de3320d --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/write.S @@ -0,0 +1,19 @@ +#include <sysdep-cancel.h> + +/* +extern int __write_nocancel (int, const void *, size_t) attribute_hidden; +*/ +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt + +PSEUDO (__libc_write, write, 3) +ret +PSEUDO_END(__libc_write) + +libc_hidden_def (__write_nocancel) +libc_hidden_def (__libc_write) +weak_alias (__libc_write, __write) +libc_hidden_weak (__write) +weak_alias (__libc_write, write) +libc_hidden_weak (write) + +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/Makefile b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/Makefile new file mode 100644 index 000000000..43a6fad84 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/Makefile @@ -0,0 +1,13 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2005 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +top_srcdir=../../../../../../../ +top_builddir=../../../../../../../ +all: objs +include $(top_builddir)Rules.mak +include Makefile.arch +include $(top_srcdir)Makerules diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/Makefile.arch b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/Makefile.arch new file mode 100644 index 000000000..f059e2db2 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/Makefile.arch @@ -0,0 +1,73 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2006 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# +LINUX_ARCH_DIR:=$(top_srcdir)libpthread/nptl/sysdeps/unix/sysv/linux/x86_64 +LINUX_ARCH_OUT:=$(top_builddir)libpthread/nptl/sysdeps/unix/sysv/linux/x86_64 + + +libpthread_SSRC = pt-vfork.S clone.S pthread_once.S +libpthread_CSRC = pthread_spin_init.c + +libc_a_CSRC = fork.c +libc_a_SSRC = clone.S vfork.S + +libpthread_SSRC += lowlevellock.S pthread_barrier_wait.S pthread_cond_signal.S pthread_cond_broadcast.S \ + sem_post.S sem_timedwait.S \ + sem_trywait.S sem_wait.S pthread_rwlock_rdlock.S pthread_rwlock_wrlock.S \ + pthread_rwlock_timedrdlock.S pthread_rwlock_timedwrlock.S pthread_rwlock_unlock.S \ + pthread_cond_timedwait.S pthread_cond_wait.S pthread_spin_unlock.S + +libc_a_SSRC += libc-lowlevellock.S + + +CFLAGS-OMIT-fork.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 + +ifeq ($(UCLIBC_HAS_STDIO_FUTEXES),y) +CFLAGS-fork.c = -D__USE_STDIO_FUTEXES__ +endif + +ASFLAGS-pt-vfork.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 -D_LIBC_REENTRANT -DUSE___THREAD +ASFLAGS-lowlevellock.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 -D_LIBC_REENTRANT -DUSE___THREAD +ASFLAGS-pthread_once.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 -D_LIBC_REENTRANT -DUSE___THREAD + + +ASFLAGS-clone.S = -D_LIBC_REENTRANT +ASFLAGS-vfork.S = -D_LIBC_REENTRANT +ASFLAGS-libc-lowlevellock.S = -D_LIBC_REENTRANT + +ifeq ($(UCLIBC_HAS_THREADS_NATIVE),y) +#Needed to use the correct SYSCALL_ERROR_HANDLER +ASFLAGS-clone.S += -DUSE___THREAD +ASFLAGS-vfork.S += -DUSE___THREAD +endif + +CFLAGS += $(SSP_ALL_CFLAGS) +#CFLAGS:=$(CFLAGS:-O1=-O2) + +LINUX_ARCH_OBJ:=$(patsubst %.S,$(LINUX_ARCH_OUT)/%.o,$(libpthread_SSRC)) +LINUX_ARCH_OBJ+=$(patsubst %.c,$(LINUX_ARCH_OUT)/%.o,$(libpthread_CSRC)) + +ifeq ($(DOPIC),y) +libpthread-a-y += $(LINUX_ARCH_OBJ:.o=.os) +else +libpthread-a-y += $(LINUX_ARCH_OBJ) +endif +libpthread-so-y += $(LINUX_ARCH_OBJ:.o=.oS) + +libpthread-nomulti-y+=$(LINUX_ARCH_OBJS) + +LIBC_LINUX_ARCH_OBJ:=$(patsubst %.c,$(LINUX_ARCH_OUT)/%.o,$(libc_a_CSRC)) +LIBC_LINUX_ARCH_OBJ+=$(patsubst %.S,$(LINUX_ARCH_OUT)/%.o,$(libc_a_SSRC)) + +libc-static-y+=$(LIBC_LINUX_ARCH_OBJ) +libc-shared-y+=$(LIBC_LINUX_ARCH_OBJ:.o=.oS) + +libc-nomulti-y+=$(LIBC_LINUX_ARCH_OBJ) + +objclean-y+=nptl_linux_arch_clean + +nptl_linux_arch_clean: + $(do_rm) $(addprefix $(LINUX_ARCH_OUT)/*., o os oS) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/Versions b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/Versions new file mode 100644 index 000000000..3b111ddb5 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/Versions @@ -0,0 +1,7 @@ +librt { + GLIBC_2.3.3 { + # Changed timer_t. + timer_create; timer_delete; timer_getoverrun; timer_gettime; + timer_settime; + } +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h new file mode 100644 index 000000000..7a09c8119 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h @@ -0,0 +1,225 @@ +/* Copyright (C) 2002,2003,2004,2005,2006,2007 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _BITS_PTHREADTYPES_H +#define _BITS_PTHREADTYPES_H 1 + +#include <bits/wordsize.h> + +#if __WORDSIZE == 64 +# define __SIZEOF_PTHREAD_ATTR_T 56 +# define __SIZEOF_PTHREAD_MUTEX_T 40 +# define __SIZEOF_PTHREAD_MUTEXATTR_T 4 +# define __SIZEOF_PTHREAD_COND_T 48 +# define __SIZEOF_PTHREAD_CONDATTR_T 4 +# define __SIZEOF_PTHREAD_RWLOCK_T 56 +# define __SIZEOF_PTHREAD_RWLOCKATTR_T 8 +# define __SIZEOF_PTHREAD_BARRIER_T 32 +# define __SIZEOF_PTHREAD_BARRIERATTR_T 4 +#else +# define __SIZEOF_PTHREAD_ATTR_T 36 +# define __SIZEOF_PTHREAD_MUTEX_T 24 +# define __SIZEOF_PTHREAD_MUTEXATTR_T 4 +# define __SIZEOF_PTHREAD_COND_T 48 +# define __SIZEOF_PTHREAD_CONDATTR_T 4 +# define __SIZEOF_PTHREAD_RWLOCK_T 32 +# define __SIZEOF_PTHREAD_RWLOCKATTR_T 8 +# define __SIZEOF_PTHREAD_BARRIER_T 20 +# define __SIZEOF_PTHREAD_BARRIERATTR_T 4 +#endif + + +/* Thread identifiers. The structure of the attribute type is not + exposed on purpose. */ +typedef unsigned long int pthread_t; + + +typedef union +{ + char __size[__SIZEOF_PTHREAD_ATTR_T]; + long int __align; +} pthread_attr_t; + + +#if __WORDSIZE == 64 +typedef struct __pthread_internal_list +{ + struct __pthread_internal_list *__prev; + struct __pthread_internal_list *__next; +} __pthread_list_t; +#else +typedef struct __pthread_internal_slist +{ + struct __pthread_internal_slist *__next; +} __pthread_slist_t; +#endif + + +/* Data structures for mutex handling. The structure of the attribute + type is not exposed on purpose. */ +typedef union +{ + struct __pthread_mutex_s + { + int __lock; + unsigned int __count; + int __owner; +#if __WORDSIZE == 64 + unsigned int __nusers; +#endif + /* KIND must stay at this position in the structure to maintain + binary compatibility. */ + int __kind; +#if __WORDSIZE == 64 + int __spins; + __pthread_list_t __list; +# define __PTHREAD_MUTEX_HAVE_PREV 1 +#else + unsigned int __nusers; + __extension__ union + { + int __spins; + __pthread_slist_t __list; + }; +#endif + } __data; + char __size[__SIZEOF_PTHREAD_MUTEX_T]; + long int __align; +} pthread_mutex_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_MUTEXATTR_T]; + int __align; +} pthread_mutexattr_t; + + +/* Data structure for conditional variable handling. The structure of + the attribute type is not exposed on purpose. */ +typedef union +{ + struct + { + int __lock; + unsigned int __futex; + __extension__ unsigned long long int __total_seq; + __extension__ unsigned long long int __wakeup_seq; + __extension__ unsigned long long int __woken_seq; + void *__mutex; + unsigned int __nwaiters; + unsigned int __broadcast_seq; + } __data; + char __size[__SIZEOF_PTHREAD_COND_T]; + __extension__ long long int __align; +} pthread_cond_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_CONDATTR_T]; + int __align; +} pthread_condattr_t; + + +/* Keys for thread-specific data */ +typedef unsigned int pthread_key_t; + + +/* Once-only execution */ +typedef int pthread_once_t; + + +#if defined __USE_UNIX98 || defined __USE_XOPEN2K +/* Data structure for read-write lock variable handling. The + structure of the attribute type is not exposed on purpose. */ +typedef union +{ +# if __WORDSIZE == 64 + struct + { + int __lock; + unsigned int __nr_readers; + unsigned int __readers_wakeup; + unsigned int __writer_wakeup; + unsigned int __nr_readers_queued; + unsigned int __nr_writers_queued; + int __writer; + int __shared; + unsigned long int __pad1; + unsigned long int __pad2; + /* FLAGS must stay at this position in the structure to maintain + binary compatibility. */ + unsigned int __flags; + } __data; +# else + struct + { + int __lock; + unsigned int __nr_readers; + unsigned int __readers_wakeup; + unsigned int __writer_wakeup; + unsigned int __nr_readers_queued; + unsigned int __nr_writers_queued; + /* FLAGS must stay at this position in the structure to maintain + binary compatibility. */ + unsigned char __flags; + unsigned char __shared; + unsigned char __pad1; + unsigned char __pad2; + int __writer; + } __data; +# endif + char __size[__SIZEOF_PTHREAD_RWLOCK_T]; + long int __align; +} pthread_rwlock_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_RWLOCKATTR_T]; + long int __align; +} pthread_rwlockattr_t; +#endif + + +#ifdef __USE_XOPEN2K +/* POSIX spinlock data type. */ +typedef volatile int pthread_spinlock_t; + + +/* POSIX barriers data type. The structure of the type is + deliberately not exposed. */ +typedef union +{ + char __size[__SIZEOF_PTHREAD_BARRIER_T]; + long int __align; +} pthread_barrier_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_BARRIERATTR_T]; + int __align; +} pthread_barrierattr_t; +#endif + + +#if __WORDSIZE == 32 +/* Extra attributes for the cleanup functions. */ +# define __cleanup_fct_attribute __attribute__ ((__regparm__ (1))) +#endif + +#endif /* bits/pthreadtypes.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/bits/semaphore.h b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/bits/semaphore.h new file mode 100644 index 000000000..57edbbbfb --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/bits/semaphore.h @@ -0,0 +1,44 @@ +/* Copyright (C) 2002, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _SEMAPHORE_H +# error "Never use <bits/semaphore.h> directly; include <semaphore.h> instead." +#endif + +#include <bits/wordsize.h> + +#if __WORDSIZE == 64 +# define __SIZEOF_SEM_T 32 +#else +# define __SIZEOF_SEM_T 16 +#endif + + +/* Value returned if `sem_open' failed. */ +#define SEM_FAILED ((sem_t *) 0) + +/* Maximum value the semaphore can have. */ +#define SEM_VALUE_MAX (2147483647) + + +typedef union +{ + char __size[__SIZEOF_SEM_T]; + long int __align; +} sem_t; diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/cancellation.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/cancellation.S new file mode 100644 index 000000000..680696200 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/cancellation.S @@ -0,0 +1,116 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2009. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <tcb-offsets.h> +#include <kernel-features.h> +#include "lowlevellock.h" + +#ifdef IS_IN_libpthread +# ifdef SHARED +# define __pthread_unwind __GI___pthread_unwind +# endif +#else +# ifndef SHARED + .weak __pthread_unwind +# endif +#endif + + +#ifdef __ASSUME_PRIVATE_FUTEX +# define LOAD_PRIVATE_FUTEX_WAIT(reg) \ + movl $(FUTEX_WAIT | FUTEX_PRIVATE_FLAG), reg +#else +# if FUTEX_WAIT == 0 +# define LOAD_PRIVATE_FUTEX_WAIT(reg) \ + movl %fs:PRIVATE_FUTEX, reg +# else +# define LOAD_PRIVATE_FUTEX_WAIT(reg) \ + movl %fs:PRIVATE_FUTEX, reg ; \ + orl $FUTEX_WAIT, reg +# endif +#endif + +/* It is crucial that the functions in this file don't modify registers + other than %rax and %r11. The syscall wrapper code depends on this + because it doesn't explicitly save the other registers which hold + relevant values. */ + .text + + .hidden __pthread_enable_asynccancel +ENTRY(__pthread_enable_asynccancel) + movl %fs:CANCELHANDLING, %eax +2: movl %eax, %r11d + orl $TCB_CANCELTYPE_BITMASK, %r11d + cmpl %eax, %r11d + je 1f + + lock + cmpxchgl %r11d, %fs:CANCELHANDLING + jnz 2b + + andl $(TCB_CANCELSTATE_BITMASK|TCB_CANCELTYPE_BITMASK|TCB_CANCELED_BITMASK|TCB_EXITING_BITMASK|TCB_CANCEL_RESTMASK|TCB_TERMINATED_BITMASK), %r11d + cmpl $(TCB_CANCELTYPE_BITMASK|TCB_CANCELED_BITMASK), %r11d + je 3f + +1: ret + +3: movq $TCB_PTHREAD_CANCELED, %fs:RESULT + lock + orl $TCB_EXITING_BITMASK, %fs:CANCELHANDLING + movq %fs:CLEANUP_JMP_BUF, %rdi +#ifdef SHARED + call __pthread_unwind@PLT +#else + call __pthread_unwind +#endif + hlt +END(__pthread_enable_asynccancel) + + + .hidden __pthread_disable_asynccancel +ENTRY(__pthread_disable_asynccancel) + testl $TCB_CANCELTYPE_BITMASK, %edi + jnz 1f + + movl %fs:CANCELHANDLING, %eax +2: movl %eax, %r11d + andl $~TCB_CANCELTYPE_BITMASK, %r11d + lock + cmpxchgl %r11d, %fs:CANCELHANDLING + jnz 2b + + movl %r11d, %eax +3: andl $(TCB_CANCELING_BITMASK|TCB_CANCELED_BITMASK), %eax + cmpl $TCB_CANCELING_BITMASK, %eax + je 4f +1: ret + + /* Performance doesn't matter in this loop. We will + delay until the thread is canceled. And we will unlikely + enter the loop twice. */ +4: movq %fs:0, %rdi + movl $__NR_futex, %eax + xorq %r10, %r10 + addq $CANCELHANDLING, %rdi + LOAD_PRIVATE_FUTEX_WAIT (%esi) + syscall + movl %fs:CANCELHANDLING, %eax + jmp 3b +END(__pthread_disable_asynccancel) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/clone.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/clone.S new file mode 100644 index 000000000..675a997e9 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/clone.S @@ -0,0 +1,9 @@ +/* We want an #include_next, but we are the main source file. + So, #include ourselves and in that incarnation we can use #include_next. */ +#ifndef INCLUDED_SELF +# define INCLUDED_SELF +# include <clone.S> +#else +# define RESET_PID +# include_next <clone.S> +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/compat-timer.h b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/compat-timer.h new file mode 100644 index 000000000..02485daa5 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/compat-timer.h @@ -0,0 +1,46 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <signal.h> +#include <time.h> +#include <sys/types.h> + +#define OLD_TIMER_MAX 256 + +extern timer_t __compat_timer_list[OLD_TIMER_MAX] attribute_hidden; + + +extern int __timer_create_new (clockid_t clock_id, struct sigevent *evp, + timer_t *timerid); +extern int __timer_delete_new (timer_t timerid); +extern int __timer_getoverrun_new (timer_t timerid); +extern int __timer_gettime_new (timer_t timerid, struct itimerspec *value); +extern int __timer_settime_new (timer_t timerid, int flags, + const struct itimerspec *value, + struct itimerspec *ovalue); + + +extern int __timer_create_old (clockid_t clock_id, struct sigevent *evp, + int *timerid); +extern int __timer_delete_old (int timerid); +extern int __timer_getoverrun_old (int timerid); +extern int __timer_gettime_old (int timerid, struct itimerspec *value); +extern int __timer_settime_old (int timerid, int flags, + const struct itimerspec *value, + struct itimerspec *ovalue); diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/fork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/fork.c new file mode 100644 index 000000000..c828e158d --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/fork.c @@ -0,0 +1,31 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sched.h> +#include <signal.h> +#include <sysdep.h> +#include <tls.h> + + +#define ARCH_FORK() \ + INLINE_SYSCALL (clone, 4, \ + CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD, 0, \ + NULL, &THREAD_SELF->tid) + +#include "../fork.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/libc-cancellation.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/libc-cancellation.S new file mode 100644 index 000000000..110058850 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/libc-cancellation.S @@ -0,0 +1,22 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2009. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#define __pthread_enable_asynccancel __libc_enable_asynccancel +#define __pthread_disable_asynccancel __libc_disable_asynccancel +#include "cancellation.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/libc-lowlevellock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/libc-lowlevellock.S new file mode 100644 index 000000000..ce8ad27aa --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/libc-lowlevellock.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2002, 2003, 2007 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "lowlevellock.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/librt-cancellation.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/librt-cancellation.S new file mode 100644 index 000000000..ce4192b5d --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/librt-cancellation.S @@ -0,0 +1,22 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2009. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#define __pthread_enable_asynccancel __librt_enable_asynccancel +#define __pthread_disable_asynccancel __librt_disable_asynccancel +#include "cancellation.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S new file mode 100644 index 000000000..1e461ad41 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S @@ -0,0 +1,282 @@ +/* Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <pthread-errnos.h> + + .text + +#ifndef LOCK +# ifdef UP +# define LOCK +# else +# define LOCK lock +# endif +#endif + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + +/* For the calculation see asm/vsyscall.h. */ +#define VSYSCALL_ADDR_vgettimeofday 0xffffffffff600000 + + + .globl __lll_mutex_lock_wait + .type __lll_mutex_lock_wait,@function + .hidden __lll_mutex_lock_wait + .align 16 +__lll_mutex_lock_wait: + pushq %r10 + pushq %rdx + + xorq %r10, %r10 /* No timeout. */ + movl $2, %edx +#if FUTEX_WAIT == 0 + xorl %esi, %esi +#else + movl $FUTEX_WAIT, %esi +#endif + + cmpl %edx, %eax /* NB: %edx == 2 */ + jne 2f + +1: movl $SYS_futex, %eax + syscall + +2: movl %edx, %eax + xchgl %eax, (%rdi) /* NB: lock is implied */ + + testl %eax, %eax + jnz 1b + + popq %rdx + popq %r10 + retq + .size __lll_mutex_lock_wait,.-__lll_mutex_lock_wait + + +#ifdef NOT_IN_libc + .globl __lll_mutex_timedlock_wait + .type __lll_mutex_timedlock_wait,@function + .hidden __lll_mutex_timedlock_wait + .align 16 +__lll_mutex_timedlock_wait: + /* Check for a valid timeout value. */ + cmpq $1000000000, 8(%rdx) + jae 3f + + pushq %r8 + pushq %r9 + pushq %r12 + pushq %r13 + pushq %r14 + + /* Stack frame for the timespec and timeval structs. */ + subq $16, %rsp + + movq %rdi, %r12 + movq %rdx, %r13 + +1: + /* Get current time. */ + movq %rsp, %rdi + xorl %esi, %esi + movq $VSYSCALL_ADDR_vgettimeofday, %rax + /* This is a regular function call, all caller-save registers + might be clobbered. */ + callq *%rax + + /* Compute relative timeout. */ + movq 8(%rsp), %rax + movl $1000, %edi + mul %rdi /* Milli seconds to nano seconds. */ + movq (%r13), %rdi + movq 8(%r13), %rsi + subq (%rsp), %rdi + subq %rax, %rsi + jns 4f + addq $1000000000, %rsi + decq %rdi +4: testq %rdi, %rdi + js 5f /* Time is already up. */ + + /* Futex call. */ + movq %rdi, (%rsp) /* Store relative timeout. */ + movq %rsi, 8(%rsp) + + movl $1, %eax + movl $2, %edx + LOCK + cmpxchgl %edx, (%r12) + + testl %eax, %eax + je 8f + + movq %rsp, %r10 +#if FUTEX_WAIT == 0 + xorl %esi, %esi +#else + movl $FUTEX_WAIT, %esi +#endif + movq %r12, %rdi + movl $SYS_futex, %eax + syscall + movq %rax, %rcx + +8: /* NB: %edx == 2 */ + xorl %eax, %eax + LOCK + cmpxchgl %edx, (%rdi) + jnz 7f + +6: addq $16, %rsp + popq %r14 + popq %r13 + popq %r12 + popq %r9 + popq %r8 + retq + + /* Check whether the time expired. */ +7: cmpq $-ETIMEDOUT, %rcx + je 5f + + /* Make sure the current holder knows we are going to sleep. */ + movl %edx, %eax + xchgl %eax, (%rdi) + testl %eax, %eax + jz 6b + jmp 1b + +3: movl $EINVAL, %eax + retq + +5: movl $ETIMEDOUT, %eax + jmp 6b + .size __lll_mutex_timedlock_wait,.-__lll_mutex_timedlock_wait +#endif + + +#ifdef NOT_IN_libc + .globl lll_unlock_wake_cb + .type lll_unlock_wake_cb,@function + .hidden lll_unlock_wake_cb + .align 16 +lll_unlock_wake_cb: + pushq %rsi + pushq %rdx + + LOCK + addl $1, (%rdi) + jng 1f + + popq %rdx + popq %rsi + retq + .size lll_unlock_wake_cb,.-lll_unlock_wake_cb +#endif + + + .globl __lll_mutex_unlock_wake + .type __lll_mutex_unlock_wake,@function + .hidden __lll_mutex_unlock_wake + .align 16 +__lll_mutex_unlock_wake: + pushq %rsi + pushq %rdx + + movl $0, (%rdi) + movl $FUTEX_WAKE, %esi + movl $1, %edx /* Wake one thread. */ + movl $SYS_futex, %eax + syscall + + popq %rdx + popq %rsi + retq + .size __lll_mutex_unlock_wake,.-__lll_mutex_unlock_wake + + +#ifdef NOT_IN_libc + .globl __lll_timedwait_tid + .type __lll_timedwait_tid,@function + .hidden __lll_timedwait_tid + .align 16 +__lll_timedwait_tid: + pushq %r12 + pushq %r13 + + movq %rdi, %r12 + movq %rsi, %r13 + + subq $16, %rsp + + /* Get current time. */ +2: movq %rsp, %rdi + xorl %esi, %esi + movq $VSYSCALL_ADDR_vgettimeofday, %rax + callq *%rax + + /* Compute relative timeout. */ + movq 8(%rsp), %rax + movl $1000, %edi + mul %rdi /* Milli seconds to nano seconds. */ + movq (%r13), %rdi + movq 8(%r13), %rsi + subq (%rsp), %rdi + subq %rax, %rsi + jns 5f + addq $1000000000, %rsi + decq %rdi +5: testq %rdi, %rdi + js 6f /* Time is already up. */ + + movq %rdi, (%rsp) /* Store relative timeout. */ + movq %rsi, 8(%rsp) + + movl (%r12), %edx + testl %edx, %edx + jz 4f + + movq %rsp, %r10 +#if FUTEX_WAIT == 0 + xorl %esi, %esi +#else + movl $FUTEX_WAIT, %esi +#endif + movq %r12, %rdi + movl $SYS_futex, %eax + syscall + + cmpl $0, (%rdi) + jne 1f +4: xorl %eax, %eax + +8: addq $16, %rsp + popq %r13 + popq %r12 + retq + +1: cmpq $-ETIMEDOUT, %rax + jne 2b + +6: movl $ETIMEDOUT, %eax + jmp 8b + .size __lll_timedwait_tid,.-__lll_timedwait_tid +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.h b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.h new file mode 100644 index 000000000..c9f30e962 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.h @@ -0,0 +1,342 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _LOWLEVELLOCK_H +#define _LOWLEVELLOCK_H 1 + +#include <time.h> +#include <sys/param.h> +#include <bits/pthreadtypes.h> +#include <atomic.h> +#include <sysdep.h> + +#ifndef LOCK_INSTR +# ifdef UP +# define LOCK_INSTR /* nothing */ +# else +# define LOCK_INSTR "lock;" +# endif +#endif + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + + +/* Initializer for compatibility lock. */ +#define LLL_MUTEX_LOCK_INITIALIZER (0) +#define LLL_MUTEX_LOCK_INITIALIZER_LOCKED (1) +#define LLL_MUTEX_LOCK_INITIALIZER_WAITERS (2) + +/* Delay in spinlock loop. */ +#define BUSY_WAIT_NOP __asm__ ("rep; nop") + + +#define lll_futex_wait(futex, val) \ + do { \ + int __ignore; \ + register __typeof (val) _val __asm__ ("edx") = (val); \ + __asm__ __volatile ("xorq %%r10, %%r10\n\t" \ + "syscall" \ + : "=a" (__ignore) \ + : "0" (SYS_futex), "D" (futex), "S" (FUTEX_WAIT), \ + "d" (_val) \ + : "memory", "cc", "r10", "r11", "cx"); \ + } while (0) + + +#define lll_futex_wake(futex, nr) \ + do { \ + int __ignore; \ + register __typeof (nr) _nr __asm__ ("edx") = (nr); \ + __asm__ __volatile ("syscall" \ + : "=a" (__ignore) \ + : "0" (SYS_futex), "D" (futex), "S" (FUTEX_WAKE), \ + "d" (_nr) \ + : "memory", "cc", "r10", "r11", "cx"); \ + } while (0) + + +/* Does not preserve %eax and %ecx. */ +extern int __lll_mutex_lock_wait (int *__futex, int __val) attribute_hidden; +/* Does not preserver %eax, %ecx, and %edx. */ +extern int __lll_mutex_timedlock_wait (int *__futex, int __val, + const struct timespec *__abstime) + attribute_hidden; +/* Preserves all registers but %eax. */ +extern int __lll_mutex_unlock_wait (int *__futex) attribute_hidden; + + +/* NB: in the lll_mutex_trylock macro we simply return the value in %eax + after the cmpxchg instruction. In case the operation succeded this + value is zero. In case the operation failed, the cmpxchg instruction + has loaded the current value of the memory work which is guaranteed + to be nonzero. */ +#define lll_mutex_trylock(futex) \ + ({ int ret; \ + __asm__ __volatile (LOCK_INSTR "cmpxchgl %2, %1" \ + : "=a" (ret), "=m" (futex) \ + : "r" (LLL_MUTEX_LOCK_INITIALIZER_LOCKED), "m" (futex),\ + "0" (LLL_MUTEX_LOCK_INITIALIZER) \ + : "memory"); \ + ret; }) + + +#define lll_mutex_cond_trylock(futex) \ + ({ int ret; \ + __asm__ __volatile (LOCK_INSTR "cmpxchgl %2, %1" \ + : "=a" (ret), "=m" (futex) \ + : "r" (LLL_MUTEX_LOCK_INITIALIZER_WAITERS), \ + "m" (futex), "0" (LLL_MUTEX_LOCK_INITIALIZER) \ + : "memory"); \ + ret; }) + + +#define lll_mutex_lock(futex) \ + (void) ({ int ignore1, ignore2, ignore3; \ + __asm__ __volatile (LOCK_INSTR "cmpxchgl %0, %2\n\t" \ + "jnz 1f\n\t" \ + ".subsection 1\n" \ + "1:\tleaq %2, %%rdi\n\t" \ + "subq $128, %%rsp\n\t" \ + "callq __lll_mutex_lock_wait\n\t" \ + "addq $128, %%rsp\n\t" \ + "jmp 2f\n\t" \ + ".previous\n" \ + "2:" \ + : "=S" (ignore1), "=&D" (ignore2), "=m" (futex),\ + "=a" (ignore3) \ + : "0" (1), "m" (futex), "3" (0) \ + : "cx", "r11", "cc", "memory"); }) + + +#define lll_mutex_cond_lock(futex) \ + (void) ({ int ignore1, ignore2, ignore3; \ + __asm__ __volatile (LOCK_INSTR "cmpxchgl %0, %2\n\t" \ + "jnz 1f\n\t" \ + ".subsection 1\n" \ + "1:\tleaq %2, %%rdi\n\t" \ + "subq $128, %%rsp\n\t" \ + "callq __lll_mutex_lock_wait\n\t" \ + "addq $128, %%rsp\n\t" \ + "jmp 2f\n\t" \ + ".previous\n" \ + "2:" \ + : "=S" (ignore1), "=&D" (ignore2), "=m" (futex),\ + "=a" (ignore3) \ + : "0" (2), "m" (futex), "3" (0) \ + : "cx", "r11", "cc", "memory"); }) + + +#define lll_mutex_timedlock(futex, timeout) \ + ({ int _result, ignore1, ignore2, ignore3; \ + __asm__ __volatile (LOCK_INSTR "cmpxchgl %2, %4\n\t" \ + "jnz 1f\n\t" \ + ".subsection 1\n" \ + "1:\tleaq %4, %%rdi\n\t" \ + "movq %8, %%rdx\n\t" \ + "subq $128, %%rsp\n\t" \ + "callq __lll_mutex_timedlock_wait\n\t" \ + "addq $128, %%rsp\n\t" \ + "jmp 2f\n\t" \ + ".previous\n" \ + "2:" \ + : "=a" (_result), "=&D" (ignore1), "=S" (ignore2), \ + "=&d" (ignore3), "=m" (futex) \ + : "0" (0), "2" (1), "m" (futex), "m" (timeout) \ + : "memory", "cx", "cc", "r10", "r11"); \ + _result; }) + + +#define lll_mutex_unlock(futex) \ + (void) ({ int ignore; \ + __asm__ __volatile (LOCK_INSTR "decl %0\n\t" \ + "jne 1f\n\t" \ + ".subsection 1\n" \ + "1:\tleaq %0, %%rdi\n\t" \ + "subq $128, %%rsp\n\t" \ + "callq __lll_mutex_unlock_wake\n\t" \ + "addq $128, %%rsp\n\t" \ + "jmp 2f\n\t" \ + ".previous\n" \ + "2:" \ + : "=m" (futex), "=&D" (ignore) \ + : "m" (futex) \ + : "ax", "cx", "r11", "cc", "memory"); }) + + +#define lll_mutex_islocked(futex) \ + (futex != LLL_MUTEX_LOCK_INITIALIZER) + + +/* We have a separate internal lock implementation which is not tied + to binary compatibility. */ + +/* Type for lock object. */ +typedef int lll_lock_t; + +/* Initializers for lock. */ +#define LLL_LOCK_INITIALIZER (0) +#define LLL_LOCK_INITIALIZER_LOCKED (1) + + +extern int lll_unlock_wake_cb (int *__futex) attribute_hidden; + + +/* The states of a lock are: + 0 - untaken + 1 - taken by one user + 2 - taken by more users */ + + +#if defined NOT_IN_libc || defined UP +# define lll_trylock(futex) lll_mutex_trylock (futex) +# define lll_lock(futex) lll_mutex_lock (futex) +# define lll_unlock(futex) lll_mutex_unlock (futex) +#else +/* Special versions of the macros for use in libc itself. They avoid + the lock prefix when the thread library is not used. + + The code sequence to avoid unnecessary lock prefixes is what the AMD + guys suggested. If you do not like it, bring it up with AMD. + + XXX In future we might even want to avoid it on UP machines. */ + +# define lll_trylock(futex) \ + ({ unsigned char ret; \ + __asm__ __volatile ("cmpl $0, __libc_multiple_threads(%%rip)\n\t" \ + "je 0f\n\t" \ + "lock; cmpxchgl %2, %1\n\t" \ + "jmp 1f\n" \ + "0:\tcmpxchgl %2, %1\n\t" \ + "1:setne %0" \ + : "=a" (ret), "=m" (futex) \ + : "r" (LLL_MUTEX_LOCK_INITIALIZER_LOCKED), "m" (futex),\ + "0" (LLL_MUTEX_LOCK_INITIALIZER) \ + : "memory"); \ + ret; }) + + +# define lll_lock(futex) \ + (void) ({ int ignore1, ignore2, ignore3; \ + __asm__ __volatile ("cmpl $0, __libc_multiple_threads(%%rip)\n\t" \ + "je 0f\n\t" \ + "lock; cmpxchgl %0, %2\n\t" \ + "jnz 1f\n\t" \ + "jmp 2f\n" \ + "0:\tcmpxchgl %0, %2\n\t" \ + "jnz 1f\n\t" \ + ".subsection 1\n" \ + "1:\tleaq %2, %%rdi\n\t" \ + "subq $128, %%rsp\n\t" \ + "callq __lll_mutex_lock_wait\n\t" \ + "addq $128, %%rsp\n\t" \ + "jmp 2f\n\t" \ + ".previous\n" \ + "2:" \ + : "=S" (ignore1), "=&D" (ignore2), "=m" (futex),\ + "=a" (ignore3) \ + : "0" (1), "m" (futex), "3" (0) \ + : "cx", "r11", "cc", "memory"); }) + + +# define lll_unlock(futex) \ + (void) ({ int ignore; \ + __asm__ __volatile ("cmpl $0, __libc_multiple_threads(%%rip)\n\t" \ + "je 0f\n\t" \ + "lock; decl %0\n\t" \ + "jne 1f\n\t" \ + "jmp 2f\n" \ + "0:\tdecl %0\n\t" \ + "jne 1f\n\t" \ + ".subsection 1\n" \ + "1:\tleaq %0, %%rdi\n\t" \ + "subq $128, %%rsp\n\t" \ + "callq __lll_mutex_unlock_wake\n\t" \ + "addq $128, %%rsp\n\t" \ + "jmp 2f\n\t" \ + ".previous\n" \ + "2:" \ + : "=m" (futex), "=&D" (ignore) \ + : "m" (futex) \ + : "ax", "cx", "r11", "cc", "memory"); }) +#endif + + +#define lll_islocked(futex) \ + (futex != LLL_MUTEX_LOCK_INITIALIZER) + + +/* The kernel notifies a process with uses CLONE_CLEARTID via futex + wakeup when the clone terminates. The memory location contains the + thread ID while the clone is running and is reset to zero + afterwards. + + The macro parameter must not have any side effect. */ +#define lll_wait_tid(tid) \ + do { \ + int __ignore; \ + register __typeof (tid) _tid __asm__ ("edx") = (tid); \ + if (_tid != 0) \ + __asm__ __volatile ("xorq %%r10, %%r10\n\t" \ + "1:\tmovq %2, %%rax\n\t" \ + "syscall\n\t" \ + "cmpl $0, (%%rdi)\n\t" \ + "jne 1b" \ + : "=&a" (__ignore) \ + : "S" (FUTEX_WAIT), "i" (SYS_futex), "D" (&tid), \ + "d" (_tid) \ + : "memory", "cc", "r10", "r11", "cx"); \ + } while (0) + +extern int __lll_timedwait_tid (int *tid, const struct timespec *abstime) + attribute_hidden; +#define lll_timedwait_tid(tid, abstime) \ + ({ \ + int __result = 0; \ + if (tid != 0) \ + { \ + if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) \ + __result = EINVAL; \ + else \ + __result = __lll_timedwait_tid (&tid, abstime); \ + } \ + __result; }) + + +/* Conditional variable handling. */ + +extern void __lll_cond_wait (pthread_cond_t *cond) attribute_hidden; +extern int __lll_cond_timedwait (pthread_cond_t *cond, + const struct timespec *abstime) + attribute_hidden; +extern void __lll_cond_wake (pthread_cond_t *cond) attribute_hidden; +extern void __lll_cond_broadcast (pthread_cond_t *cond) attribute_hidden; + + +#define lll_cond_wait(cond) \ + __lll_cond_wait (cond) +#define lll_cond_timedwait(cond, abstime) \ + __lll_cond_timedwait (cond, abstime) +#define lll_cond_wake(cond) \ + __lll_cond_wake (cond) +#define lll_cond_broadcast(cond) \ + __lll_cond_broadcast (cond) + + +#endif /* lowlevellock.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevelrobustlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevelrobustlock.S new file mode 100644 index 000000000..4b434632e --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevelrobustlock.S @@ -0,0 +1,306 @@ +/* Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2009 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <pthread-errnos.h> +#include <lowlevellock.h> +#include <lowlevelrobustlock.h> +#include <kernel-features.h> + + .text + +#define FUTEX_WAITERS 0x80000000 +#define FUTEX_OWNER_DIED 0x40000000 + +#ifdef __ASSUME_PRIVATE_FUTEX +# define LOAD_FUTEX_WAIT(reg) \ + xorl $(FUTEX_WAIT | FUTEX_PRIVATE_FLAG), reg +# define LOAD_FUTEX_WAIT_ABS(reg) \ + xorl $(FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME), reg +#else +# if FUTEX_WAIT == 0 +# define LOAD_FUTEX_WAIT(reg) \ + xorl $FUTEX_PRIVATE_FLAG, reg ; \ + andl %fs:PRIVATE_FUTEX, reg +# else +# define LOAD_FUTEX_WAIT(reg) \ + xorl $FUTEX_PRIVATE_FLAG, reg ; \ + andl %fs:PRIVATE_FUTEX, reg ; \ + orl $FUTEX_WAIT, reg +# endif +# define LOAD_FUTEX_WAIT_ABS(reg) \ + xorl $FUTEX_PRIVATE_FLAG, reg ; \ + andl %fs:PRIVATE_FUTEX, reg ; \ + orl $FUTEX_WAIT_BITSET | FUTEX_CLOCK_REALTIME, reg +#endif + +/* For the calculation see asm/vsyscall.h. */ +#define VSYSCALL_ADDR_vgettimeofday 0xffffffffff600000 + + + .globl __lll_robust_lock_wait + .type __lll_robust_lock_wait,@function + .hidden __lll_robust_lock_wait + .align 16 +__lll_robust_lock_wait: + cfi_startproc + pushq %r10 + cfi_adjust_cfa_offset(8) + pushq %rdx + cfi_adjust_cfa_offset(8) + cfi_offset(%r10, -16) + cfi_offset(%rdx, -24) + + xorq %r10, %r10 /* No timeout. */ + LOAD_FUTEX_WAIT (%esi) + +4: movl %eax, %edx + orl $FUTEX_WAITERS, %edx + + testl $FUTEX_OWNER_DIED, %eax + jnz 3f + + cmpl %edx, %eax + je 1f + + LOCK + cmpxchgl %edx, (%rdi) + jnz 2f + +1: movl $SYS_futex, %eax + syscall + + movl (%rdi), %eax + +2: testl %eax, %eax + jne 4b + + movl %fs:TID, %edx + orl $FUTEX_WAITERS, %edx + LOCK + cmpxchgl %edx, (%rdi) + jnz 4b + /* NB: %rax == 0 */ + +3: popq %rdx + cfi_adjust_cfa_offset(-8) + cfi_restore(%rdx) + popq %r10 + cfi_adjust_cfa_offset(-8) + cfi_restore(%r10) + retq + cfi_endproc + .size __lll_robust_lock_wait,.-__lll_robust_lock_wait + + + .globl __lll_robust_timedlock_wait + .type __lll_robust_timedlock_wait,@function + .hidden __lll_robust_timedlock_wait + .align 16 +__lll_robust_timedlock_wait: + cfi_startproc +# ifndef __ASSUME_FUTEX_CLOCK_REALTIME +# ifdef __PIC__ + cmpl $0, __have_futex_clock_realtime(%rip) +# else + cmpl $0, __have_futex_clock_realtime +# endif + je .Lreltmo +# endif + + pushq %r9 + cfi_adjust_cfa_offset(8) + cfi_rel_offset(%r9, 0) + movq %rdx, %r10 + movl $0xffffffff, %r9d + LOAD_FUTEX_WAIT_ABS (%esi) + +1: testl $FUTEX_OWNER_DIED, %eax + jnz 3f + + movl %eax, %edx + orl $FUTEX_WAITERS, %edx + + cmpl %eax, %edx + je 5f + + LOCK + cmpxchgl %edx, (%rdi) + movq $0, %rcx /* Must use mov to avoid changing cc. */ + jnz 6f + +5: movl $SYS_futex, %eax + syscall + movl %eax, %ecx + + movl (%rdi), %eax + +6: testl %eax, %eax + jne 2f + + movl %fs:TID, %edx + orl $FUTEX_WAITERS, %edx + LOCK + cmpxchgl %edx, (%rdi) + jnz 2f + +3: popq %r9 + cfi_adjust_cfa_offset(-8) + cfi_restore(%r9) + retq + + cfi_adjust_cfa_offset(8) + cfi_rel_offset(%r9, 0) + /* Check whether the time expired. */ +2: cmpl $-ETIMEDOUT, %ecx + je 4f + cmpl $-EINVAL, %ecx + jne 1b + +4: movl %ecx, %eax + negl %eax + jmp 3b + cfi_adjust_cfa_offset(-8) + cfi_restore(%r9) + + +# ifndef __ASSUME_FUTEX_CLOCK_REALTIME +.Lreltmo: + /* Check for a valid timeout value. */ + cmpq $1000000000, 8(%rdx) + jae 3f + + pushq %r8 + cfi_adjust_cfa_offset(8) + pushq %r9 + cfi_adjust_cfa_offset(8) + pushq %r12 + cfi_adjust_cfa_offset(8) + pushq %r13 + cfi_adjust_cfa_offset(8) + cfi_offset(%r8, -16) + cfi_offset(%r9, -24) + cfi_offset(%r12, -32) + cfi_offset(%r13, -40) + pushq %rsi + cfi_adjust_cfa_offset(8) + + /* Stack frame for the timespec and timeval structs. */ + subq $32, %rsp + cfi_adjust_cfa_offset(32) + + movq %rdi, %r12 + movq %rdx, %r13 + +1: movq %rax, 16(%rsp) + + /* Get current time. */ + movq %rsp, %rdi + xorl %esi, %esi + movq $VSYSCALL_ADDR_vgettimeofday, %rax + /* This is a regular function call, all caller-save registers + might be clobbered. */ + callq *%rax + + /* Compute relative timeout. */ + movq 8(%rsp), %rax + movl $1000, %edi + mul %rdi /* Milli seconds to nano seconds. */ + movq (%r13), %rdi + movq 8(%r13), %rsi + subq (%rsp), %rdi + subq %rax, %rsi + jns 4f + addq $1000000000, %rsi + decq %rdi +4: testq %rdi, %rdi + js 8f /* Time is already up. */ + + /* Futex call. */ + movq %rdi, (%rsp) /* Store relative timeout. */ + movq %rsi, 8(%rsp) + + movq 16(%rsp), %rdx + movl %edx, %eax + orl $FUTEX_WAITERS, %edx + + testl $FUTEX_OWNER_DIED, %eax + jnz 6f + + cmpl %eax, %edx + je 2f + + LOCK + cmpxchgl %edx, (%r12) + movq $0, %rcx /* Must use mov to avoid changing cc. */ + jnz 5f + +2: movq %rsp, %r10 + movl 32(%rsp), %esi + LOAD_FUTEX_WAIT (%esi) + movq %r12, %rdi + movl $SYS_futex, %eax + syscall + movq %rax, %rcx + + movl (%r12), %eax + +5: testl %eax, %eax + jne 7f + + movl %fs:TID, %edx + orl $FUTEX_WAITERS, %edx + LOCK + cmpxchgl %edx, (%r12) + jnz 7f + +6: addq $40, %rsp + cfi_adjust_cfa_offset(-40) + popq %r13 + cfi_adjust_cfa_offset(-8) + cfi_restore(%r13) + popq %r12 + cfi_adjust_cfa_offset(-8) + cfi_restore(%r12) + popq %r9 + cfi_adjust_cfa_offset(-8) + cfi_restore(%r9) + popq %r8 + cfi_adjust_cfa_offset(-8) + cfi_restore(%r8) + retq + +3: movl $EINVAL, %eax + retq + + cfi_adjust_cfa_offset(72) + cfi_offset(%r8, -16) + cfi_offset(%r9, -24) + cfi_offset(%r12, -32) + cfi_offset(%r13, -40) + /* Check whether the time expired. */ +7: cmpl $-ETIMEDOUT, %ecx + jne 1b + +8: movl $ETIMEDOUT, %eax + jmp 6b +#endif + cfi_endproc + .size __lll_robust_timedlock_wait,.-__lll_robust_timedlock_wait diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/not-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/not-cancel.h new file mode 100644 index 000000000..acf1a617e --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/not-cancel.h @@ -0,0 +1 @@ +#include "../i386/not-cancel.h" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pt-vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pt-vfork.S new file mode 100644 index 000000000..c20ef73e7 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pt-vfork.S @@ -0,0 +1,31 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#define SAVE_PID \ + movl %fs:PID, %esi; \ + movl %esi, %edx; \ + negl %edx; \ + movl %edx, %fs:PID + +#define RESTORE_PID \ + testq %rax, %rax; \ + je 1f; \ + movl %esi, %fs:PID; \ +1: + +#include <../../../../../../../libc/sysdeps/linux/x86_64/vfork.S> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_barrier_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_barrier_wait.S new file mode 100644 index 000000000..f6e15a2d7 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_barrier_wait.S @@ -0,0 +1,159 @@ +/* Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <lowlevelbarrier.h> + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + +#ifndef UP +# define LOCK lock +#else +# define LOCK +#endif + + + .text + + .globl pthread_barrier_wait + .type pthread_barrier_wait,@function + .align 16 +pthread_barrier_wait: + /* Get the mutex. */ + xorl %eax, %eax + movl $1, %esi + LOCK + cmpxchgl %esi, MUTEX(%rdi) + jnz 1f + + /* One less waiter. If this was the last one needed wake + everybody. */ +2: decl LEFT(%rdi) + je 3f + + /* There are more threads to come. */ +#if CURR_EVENT == 0 + movl (%rdi), %edx +#else + movl CURR_EVENT(%rdi), %edx +#endif + + /* Release the mutex. */ + LOCK + decl MUTEX(%rdi) + jne 6f + + /* Wait for the remaining threads. The call will return immediately + if the CURR_EVENT memory has meanwhile been changed. */ +7: +#if FUTEX_WAIT == 0 + xorl %esi, %esi +#else + movl $FUTEX_WAIT, %esi +#endif + xorq %r10, %r10 +8: movl $SYS_futex, %eax + syscall + + /* Don't return on spurious wakeups. The syscall does not change + any register except %eax so there is no need to reload any of + them. */ +#if CURR_EVENT == 0 + cmpl %edx, (%rdi) +#else + cmpl %edx, CURR_EVENT(%rdi) +#endif + je 8b + + /* Increment LEFT. If this brings the count back to the + initial count unlock the object. */ + movl $1, %edx + movl INIT_COUNT(%rdi), %eax + LOCK + xaddl %edx, LEFT(%rdi) + subl $1, %eax + cmpl %eax, %edx + jne,pt 10f + + /* Release the mutex. We cannot release the lock before + waking the waiting threads since otherwise a new thread might + arrive and gets waken up, too. */ + LOCK + decl MUTEX(%rdi) + jne 9f + +10: xorl %eax, %eax /* != PTHREAD_BARRIER_SERIAL_THREAD */ + + retq + + /* The necessary number of threads arrived. */ +3: +#if CURR_EVENT == 0 + incl (%rdi) +#else + incl CURR_EVENT(%rdi) +#endif + + /* Wake up all waiters. The count is a signed number in the kernel + so 0x7fffffff is the highest value. */ + movl $0x7fffffff, %edx + movl $FUTEX_WAKE, %esi + movl $SYS_futex, %eax + syscall + + /* Increment LEFT. If this brings the count back to the + initial count unlock the object. */ + movl $1, %edx + movl INIT_COUNT(%rdi), %eax + LOCK + xaddl %edx, LEFT(%rdi) + subl $1, %eax + cmpl %eax, %edx + jne,pt 5f + + /* Release the mutex. We cannot release the lock before + waking the waiting threads since otherwise a new thread might + arrive and gets waken up, too. */ + LOCK + decl MUTEX(%rdi) + jne 4f + +5: orl $-1, %eax /* == PTHREAD_BARRIER_SERIAL_THREAD */ + + retq + +1: addq $MUTEX, %rdi + callq __lll_mutex_lock_wait + subq $MUTEX, %rdi + jmp 2b + +4: addq $MUTEX, %rdi + callq __lll_mutex_unlock_wake + jmp 5b + +6: addq $MUTEX, %rdi + callq __lll_mutex_unlock_wake + subq $MUTEX, %rdi + jmp 7b + +9: addq $MUTEX, %rdi + callq __lll_mutex_unlock_wake + jmp 10b + .size pthread_barrier_wait,.-pthread_barrier_wait diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S new file mode 100644 index 000000000..d8ebdfab8 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S @@ -0,0 +1,136 @@ +/* Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <lowlevelcond.h> +#include <bits/kernel-features.h> + +#ifdef UP +# define LOCK +#else +# define LOCK lock +#endif + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 +#define FUTEX_REQUEUE 3 +#define FUTEX_CMP_REQUEUE 4 + +#define EINVAL 22 + + + .text + + /* int pthread_cond_broadcast (pthread_cond_t *cond) */ + .globl __pthread_cond_broadcast + .type __pthread_cond_broadcast, @function + .align 16 +__pthread_cond_broadcast: + + /* Get internal lock. */ + movl $1, %esi + xorl %eax, %eax + LOCK +#if cond_lock == 0 + cmpxchgl %esi, (%rdi) +#else + cmpxchgl %esi, cond_lock(%rdi) +#endif + jnz 1f + +2: addq $cond_futex, %rdi + movq total_seq-cond_futex(%rdi), %r9 + cmpq wakeup_seq-cond_futex(%rdi), %r9 + jna 4f + + /* Cause all currently waiting threads to recognize they are + woken up. */ + movq %r9, wakeup_seq-cond_futex(%rdi) + movq %r9, woken_seq-cond_futex(%rdi) + addq %r9, %r9 + movl %r9d, (%rdi) + incl broadcast_seq-cond_futex(%rdi) + + /* Get the address of the mutex used. */ + movq dep_mutex-cond_futex(%rdi), %r8 + + /* Unlock. */ + LOCK + decl cond_lock-cond_futex(%rdi) + jne 7f + +8: cmpq $-1, %r8 + je 9f + + /* Wake up all threads. */ + movl $FUTEX_CMP_REQUEUE, %esi + movl $SYS_futex, %eax + movl $1, %edx + movl $0x7fffffff, %r10d + syscall + + /* For any kind of error, which mainly is EAGAIN, we try again + with WAKE. The general test also covers running on old + kernels. */ + cmpq $-4095, %rax + jae 9f + +10: xorl %eax, %eax + retq + + .align 16 + /* Unlock. */ +4: LOCK + decl cond_lock-cond_futex(%rdi) + jne 5f + +6: xorl %eax, %eax + retq + + /* Initial locking failed. */ +1: +#if cond_lock != 0 + addq $cond_lock, %rdi +#endif + callq __lll_mutex_lock_wait +#if cond_lock != 0 + subq $cond_lock, %rdi +#endif + jmp 2b + + /* Unlock in loop requires wakeup. */ +5: addq $cond_lock-cond_futex, %rdi + callq __lll_mutex_unlock_wake + jmp 6b + + /* Unlock in loop requires wakeup. */ +7: addq $cond_lock-cond_futex, %rdi + callq __lll_mutex_unlock_wake + subq $cond_lock-cond_futex, %rdi + jmp 8b + +9: /* The futex requeue functionality is not available. */ + movl $0x7fffffff, %edx + movl $FUTEX_WAKE, %esi + movl $SYS_futex, %eax + syscall + jmp 10b + .size __pthread_cond_broadcast, .-__pthread_cond_broadcast +weak_alias(__pthread_cond_broadcast, pthread_cond_broadcast) + diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_signal.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_signal.S new file mode 100644 index 000000000..c7cc3ddd8 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_signal.S @@ -0,0 +1,101 @@ +/* Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <lowlevelcond.h> +#include <bits/kernel-features.h> + +#ifdef UP +# define LOCK +#else +# define LOCK lock +#endif + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 +#define FUTEX_REQUEUE 3 + +#define EINVAL 22 + + + .text + + /* int pthread_cond_signal (pthread_cond_t *cond) */ + .globl __pthread_cond_signal + .type __pthread_cond_signal, @function + .align 16 +__pthread_cond_signal: + + /* Get internal lock. */ + movq %rdi, %r8 + movl $1, %esi + xorl %eax, %eax + LOCK +#if cond_lock == 0 + cmpxchgl %esi, (%rdi) +#else + cmpxchgl %esi, cond_lock(%rdi) +#endif + jnz 1f + +2: addq $cond_futex, %rdi + movq total_seq(%r8), %rcx + cmpq wakeup_seq(%r8), %rcx + jbe 4f + + /* Bump the wakeup number. */ + addq $1, wakeup_seq(%r8) + addl $1, (%rdi) + + /* Wake up one thread. */ + movl $FUTEX_WAKE, %esi + movl $SYS_futex, %eax + movl $1, %edx + syscall + + /* Unlock. */ +4: LOCK +#if cond_lock == 0 + decl (%r8) +#else + decl cond_lock(%r8) +#endif + jne 5f + +6: xorl %eax, %eax + retq + + /* Initial locking failed. */ +1: +#if cond_lock != 0 + addq $cond_lock, %rdi +#endif + callq __lll_mutex_lock_wait +#if cond_lock != 0 + subq $cond_lock, %rdi +#endif + jmp 2b + + /* Unlock in loop requires wakeup. */ +5: + movq %r8, %rdi + callq __lll_mutex_unlock_wake + jmp 6b + .size __pthread_cond_signal, .-__pthread_cond_signal +weak_alias(__pthread_cond_signal, pthread_cond_signal) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S new file mode 100644 index 000000000..f0dcdb750 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S @@ -0,0 +1,468 @@ +/* Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <lowlevelcond.h> +#include <pthread-errnos.h> +#include <tcb-offsets.h> + +#ifdef UP +# define LOCK +#else +# define LOCK lock +#endif + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + +/* For the calculation see asm/vsyscall.h. */ +#define VSYSCALL_ADDR_vgettimeofday 0xffffffffff600000 + + + .text + +/* int pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex, + const struct timespec *abstime) */ + .globl __pthread_cond_timedwait + .type __pthread_cond_timedwait, @function + .align 16 +__pthread_cond_timedwait: +.LSTARTCODE: + pushq %r12 +.Lpush_r12: + pushq %r13 +.Lpush_r13: + pushq %r14 +.Lpush_r14: +#define FRAME_SIZE 80 + subq $FRAME_SIZE, %rsp +.Lsubq: + + cmpq $1000000000, 8(%rdx) + movl $EINVAL, %eax + jae 18f + + /* Stack frame: + + rsp + 80 + +--------------------------+ + rsp + 48 | cleanup buffer | + +--------------------------+ + rsp + 40 | old wake_seq value | + +--------------------------+ + rsp + 24 | timeout value | + +--------------------------+ + rsp + 16 | mutex pointer | + +--------------------------+ + rsp + 8 | condvar pointer | + +--------------------------+ + rsp + 4 | old broadcast_seq value | + +--------------------------+ + rsp + 0 | old cancellation mode | + +--------------------------+ + */ + + cmpq $-1, dep_mutex(%rdi) + + /* Prepare structure passed to cancellation handler. */ + movq %rdi, 8(%rsp) + movq %rsi, 16(%rsp) + movq %rdx, %r13 + + je 22f + movq %rsi, dep_mutex(%rdi) + + /* Get internal lock. */ +22: movl $1, %esi + xorl %eax, %eax + LOCK +#if cond_lock == 0 + cmpxchgl %esi, (%rdi) +#else + cmpxchgl %esi, cond_lock(%rdi) +#endif + jnz 1f + + /* Unlock the mutex. */ +2: movq 16(%rsp), %rdi + xorl %esi, %esi + callq __pthread_mutex_unlock_usercnt + + testl %eax, %eax + jne 16f + + movq 8(%rsp), %rdi + incq total_seq(%rdi) + incl cond_futex(%rdi) + addl $(1 << clock_bits), cond_nwaiters(%rdi) + + /* Install cancellation handler. */ +#ifdef __PIC__ + leaq __condvar_cleanup(%rip), %rsi +#else + leaq __condvar_cleanup, %rsi +#endif + leaq 48(%rsp), %rdi + movq %rsp, %rdx + callq __pthread_cleanup_push + + /* Get and store current wakeup_seq value. */ + movq 8(%rsp), %rdi + movq wakeup_seq(%rdi), %r9 + movl broadcast_seq(%rdi), %edx + movq %r9, 40(%rsp) + movl %edx, 4(%rsp) + + /* Get the current time. */ +8: +#ifdef __NR_clock_gettime + /* Get the clock number. Note that the field in the condvar + structure stores the number minus 1. */ + movq 8(%rsp), %rdi + movl cond_nwaiters(%rdi), %edi + andl $((1 << clock_bits) - 1), %edi + /* Only clocks 0 and 1 are allowed so far. Both are handled in the + kernel. */ + leaq 24(%rsp), %rsi + movl $__NR_clock_gettime, %eax + syscall +# ifndef __ASSUME_POSIX_TIMERS + cmpq $-ENOSYS, %rax + je 19f +# endif + + /* Compute relative timeout. */ + movq (%r13), %rcx + movq 8(%r13), %rdx + subq 24(%rsp), %rcx + subq 32(%rsp), %rdx +#else + leaq 24(%rsp), %rdi + xorl %esi, %esi + movq $VSYSCALL_ADDR_vgettimeofday, %rax + callq *%rax + + /* Compute relative timeout. */ + movq 32(%rsp), %rax + movl $1000, %edx + mul %rdx /* Milli seconds to nano seconds. */ + movq (%r13), %rcx + movq 8(%r13), %rdx + subq 24(%rsp), %rcx + subq %rax, %rdx +#endif + jns 12f + addq $1000000000, %rdx + decq %rcx +12: testq %rcx, %rcx + movq 8(%rsp), %rdi + movq $-ETIMEDOUT, %r14 + js 6f + + /* Store relative timeout. */ +21: movq %rcx, 24(%rsp) + movq %rdx, 32(%rsp) + + movl cond_futex(%rdi), %r12d + + /* Unlock. */ + LOCK +#if cond_lock == 0 + decl (%rdi) +#else + decl cond_lock(%rdi) +#endif + jne 3f + +4: callq __pthread_enable_asynccancel + movl %eax, (%rsp) + + leaq 24(%rsp), %r10 +#if FUTEX_WAIT == 0 + xorl %esi, %esi +#else + movl $FUTEX_WAIT, %esi +#endif + movq %r12, %rdx + addq $cond_futex, %rdi + movl $SYS_futex, %eax + syscall + movq %rax, %r14 + + movl (%rsp), %edi + callq __pthread_disable_asynccancel + + /* Lock. */ + movq 8(%rsp), %rdi + movl $1, %esi + xorl %eax, %eax + LOCK +#if cond_lock == 0 + cmpxchgl %esi, (%rdi) +#else + cmpxchgl %esi, cond_lock(%rdi) +#endif + jne 5f + +6: movl broadcast_seq(%rdi), %edx + + movq woken_seq(%rdi), %rax + + movq wakeup_seq(%rdi), %r9 + + cmpl 4(%rsp), %edx + jne 23f + + cmpq 40(%rsp), %r9 + jbe 15f + + cmpq %rax, %r9 + ja 9f + +15: cmpq $-ETIMEDOUT, %r14 + jne 8b + +13: incq wakeup_seq(%rdi) + incl cond_futex(%rdi) + movl $ETIMEDOUT, %r14d + jmp 14f + +23: xorq %r14, %r14 + jmp 24f + +9: xorq %r14, %r14 +14: incq woken_seq(%rdi) + +24: subl $(1 << clock_bits), cond_nwaiters(%rdi) + + /* Wake up a thread which wants to destroy the condvar object. */ + cmpq $0xffffffffffffffff, total_seq(%rdi) + jne 25f + movl cond_nwaiters(%rdi), %eax + andl $~((1 << clock_bits) - 1), %eax + jne 25f + + addq $cond_nwaiters, %rdi + movl $SYS_futex, %eax + movl $FUTEX_WAKE, %esi + movl $1, %edx + syscall + subq $cond_nwaiters, %rdi + +25: LOCK +#if cond_lock == 0 + decl (%rdi) +#else + decl cond_lock(%rdi) +#endif + jne 10f + + /* Remove cancellation handler. */ +11: movq 48+CLEANUP_PREV(%rsp), %rdx + movq %rdx, %fs:CLEANUP + + movq 16(%rsp), %rdi + callq __pthread_mutex_cond_lock + + testq %rax, %rax + cmoveq %r14, %rax + +18: addq $FRAME_SIZE, %rsp +.Laddq: + popq %r14 +.Lpop_r14: + popq %r13 +.Lpop_r13: + popq %r12 +.Lpop_r12: + + retq + + /* Initial locking failed. */ +1: +.LSbl1: +#if cond_lock != 0 + addq $cond_lock, %rdi +#endif + callq __lll_mutex_lock_wait + jmp 2b + + /* Unlock in loop requires wakeup. */ +3: +#if cond_lock != 0 + addq $cond_lock, %rdi +#endif + callq __lll_mutex_unlock_wake + jmp 4b + + /* Locking in loop failed. */ +5: +#if cond_lock != 0 + addq $cond_lock, %rdi +#endif + callq __lll_mutex_lock_wait +#if cond_lock != 0 + subq $cond_lock, %rdi +#endif + jmp 6b + + /* Unlock after loop requires wakeup. */ +10: +#if cond_lock != 0 + addq $cond_lock, %rdi +#endif + callq __lll_mutex_unlock_wake + jmp 11b + + /* The initial unlocking of the mutex failed. */ +16: movq 8(%rsp), %rdi + movq %rax, (%rsp) + LOCK +#if cond_lock == 0 + decl (%rdi) +#else + decl cond_lock(%rdi) +#endif + jne 17f + +#if cond_lock != 0 + addq $cond_lock, %rdi +#endif + callq __lll_mutex_unlock_wake + +17: movq (%rsp), %rax + jmp 18b + +#if defined __NR_clock_gettime && !defined __ASSUME_POSIX_TIMERS + /* clock_gettime not available. */ +19: leaq 24(%rsp), %rdi + xorl %esi, %esi + movq $VSYSCALL_ADDR_vgettimeofday, %rax + callq *%rax + + /* Compute relative timeout. */ + movq 32(%rsp), %rax + movl $1000, %edx + mul %rdx /* Milli seconds to nano seconds. */ + movq (%r13), %rcx + movq 8(%r13), %rdx + subq 24(%rsp), %rcx + subq %rax, %rdx + jns 20f + addq $1000000000, %rdx + decq %rcx +20: testq %rcx, %rcx + movq 8(%rsp), %rdi + movq $-ETIMEDOUT, %r14 + js 6b + jmp 21b +#endif +.LENDCODE: + .size __pthread_cond_timedwait, .-__pthread_cond_timedwait +weak_alias(__pthread_cond_timedwait, pthread_cond_timedwait) + + + .section .eh_frame,"a",@progbits +.LSTARTFRAME: + .long .LENDCIE-.LSTARTCIE # Length of the CIE. +.LSTARTCIE: + .long 0 # CIE ID. + .byte 1 # Version number. +#ifdef SHARED + .string "zR" # NUL-terminated augmentation + # string. +#else + .ascii "\0" # NUL-terminated augmentation + # string. +#endif + .uleb128 1 # Code alignment factor. + .sleb128 -8 # Data alignment factor. + .byte 16 # Return address register + # column. +#ifdef SHARED + .uleb128 1 # Augmentation value length. + .byte 0x1b # Encoding: DW_EH_PE_pcrel + # + DW_EH_PE_sdata4. +#endif + .byte 0x0c # DW_CFA_def_cfa + .uleb128 7 + .uleb128 8 + .byte 0x90 # DW_CFA_offset, column 0x8 + .uleb128 1 + .align 8 +.LENDCIE: + + .long .LENDFDE-.LSTARTFDE # Length of the FDE. +.LSTARTFDE: + .long .LSTARTFDE-.LSTARTFRAME # CIE pointer. +#ifdef SHARED + .long .LSTARTCODE-. # PC-relative start address + # of the code +#else + .long .LSTARTCODE # Start address of the code. +#endif + .long .LENDCODE-.LSTARTCODE # Length of the code. +#ifdef SHARED + .uleb128 0 # No augmentation data. +#endif + .byte 0x40+.Lpush_r12-.LSTARTCODE # DW_CFA_advance_loc+N + .byte 14 # DW_CFA_def_cfa_offset + .uleb128 16 + .byte 0x8c # DW_CFA_offset %r12 + .uleb128 2 + .byte 0x40+.Lpush_r13-.Lpush_r12 # DW_CFA_advance_loc+N + .byte 14 # DW_CFA_def_cfa_offset + .uleb128 24 + .byte 0x8d # DW_CFA_offset %r13 + .uleb128 3 + .byte 0x40+.Lpush_r14-.Lpush_r13 # DW_CFA_advance_loc+N + .byte 14 # DW_CFA_def_cfa_offset + .uleb128 32 + .byte 0x84 # DW_CFA_offset %r14 + .uleb128 4 + .byte 0x40+.Lsubq-.Lpush_r14 # DW_CFA_advance_loc+N + .byte 14 # DW_CFA_def_cfa_offset + .uleb128 32+FRAME_SIZE + .byte 3 # DW_CFA_advance_loc2 + .2byte .Laddq-.Lsubq + .byte 14 # DW_CFA_def_cfa_offset + .uleb128 32 + .byte 0x40+.Lpop_r14-.Laddq # DW_CFA_advance_loc+N + .byte 14 # DW_CFA_def_cfa_offset + .uleb128 24 + .byte 0xce # DW_CFA_restore %r14 + .byte 0x40+.Lpop_r13-.Lpop_r14 # DW_CFA_advance_loc+N + .byte 14 # DW_CFA_def_cfa_offset + .uleb128 16 + .byte 0xcd # DW_CFA_restore %r13 + .byte 0x40+.Lpop_r12-.Lpop_r13 # DW_CFA_advance_loc+N + .byte 14 # DW_CFA_def_cfa_offset + .uleb128 8 + .byte 0xcc # DW_CFA_restore %r12 + .byte 0x40+.LSbl1-.Lpop_r12 # DW_CFA_advance_loc+N + .byte 14 # DW_CFA_def_cfa_offset + .uleb128 32+FRAME_SIZE + .byte 0x8c # DW_CFA_offset %r12 + .uleb128 2 + .byte 0x8d # DW_CFA_offset %r13 + .uleb128 3 + .byte 0x84 # DW_CFA_offset %r14 + .uleb128 4 + .align 8 +.LENDFDE: diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S new file mode 100644 index 000000000..544118eb7 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S @@ -0,0 +1,420 @@ +/* Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <lowlevelcond.h> +#include <tcb-offsets.h> + +#ifdef UP +# define LOCK +#else +# define LOCK lock +#endif + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + + + .text + + .align 16 + .type __condvar_cleanup, @function + .globl __condvar_cleanup + .hidden __condvar_cleanup +__condvar_cleanup: + pushq %r12 + + /* Get internal lock. */ + movq %rdi, %r8 + movq 8(%rdi), %rdi + movl $1, %esi + xorl %eax, %eax + LOCK +#if cond_lock == 0 + cmpxchgl %esi, (%rdi) +#else + cmpxchgl %esi, cond_lock(%rdi) +#endif + jz 1f + +#if cond_lock != 0 + addq $cond_lock, %rdi +#endif + callq __lll_mutex_lock_wait +#if cond_lock != 0 + subq $cond_lock, %rdi +#endif + +1: movl broadcast_seq(%rdi), %edx + cmpl 4(%r8), %edx + jne 3f + + incq wakeup_seq(%rdi) + incq woken_seq(%rdi) + incl cond_futex(%rdi) + +3: subl $(1 << clock_bits), cond_nwaiters(%rdi) + + /* Wake up a thread which wants to destroy the condvar object. */ + xorq %r12, %r12 + cmpq $0xffffffffffffffff, total_seq(%rdi) + jne 4f + movl cond_nwaiters(%rdi), %eax + andl $~((1 << clock_bits) - 1), %eax + jne 4f + + addq $cond_nwaiters, %rdi + movl $SYS_futex, %eax + movl $FUTEX_WAKE, %esi + movl $1, %edx + syscall + subq $cond_nwaiters, %rdi + movl $1, %r12d + +4: LOCK +#if cond_lock == 0 + decl (%rdi) +#else + decl cond_lock(%rdi) +#endif + je 2f +#if cond_lock != 0 + addq $cond_lock, %rdi +#endif + callq __lll_mutex_unlock_wake + + /* Wake up all waiters to make sure no signal gets lost. */ +2: testq %r12, %r12 + jnz 5f + addq $cond_futex, %rdi + movl $FUTEX_WAKE, %esi + movl $0x7fffffff, %edx + movl $SYS_futex, %eax + syscall + +5: movq 16(%r8), %rdi + callq __pthread_mutex_cond_lock + + popq %r12 + + retq + .size __condvar_cleanup, .-__condvar_cleanup + + +/* int pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex) */ + .globl __pthread_cond_wait + .type __pthread_cond_wait, @function + .align 16 +__pthread_cond_wait: +.LSTARTCODE: + pushq %r12 +.Lpush_r12: +#define FRAME_SIZE 64 + subq $FRAME_SIZE, %rsp +.Lsubq: + /* Stack frame: + + rsp + 64 + +--------------------------+ + rsp + 32 | cleanup buffer | + +--------------------------+ + rsp + 24 | old wake_seq value | + +--------------------------+ + rsp + 16 | mutex pointer | + +--------------------------+ + rsp + 8 | condvar pointer | + +--------------------------+ + rsp + 4 | old broadcast_seq value | + +--------------------------+ + rsp + 0 | old cancellation mode | + +--------------------------+ + */ + + cmpq $-1, dep_mutex(%rdi) + + /* Prepare structure passed to cancellation handler. */ + movq %rdi, 8(%rsp) + movq %rsi, 16(%rsp) + + je 15f + movq %rsi, dep_mutex(%rdi) + + /* Get internal lock. */ +15: movl $1, %esi + xorl %eax, %eax + LOCK +#if cond_lock == 0 + cmpxchgl %esi, (%rdi) +#else + cmpxchgl %esi, cond_lock(%rdi) +#endif + jne 1f + + /* Unlock the mutex. */ +2: movq 16(%rsp), %rdi + xorl %esi, %esi + callq __pthread_mutex_unlock_usercnt + + testl %eax, %eax + jne 12f + + movq 8(%rsp), %rdi + incq total_seq(%rdi) + incl cond_futex(%rdi) + addl $(1 << clock_bits), cond_nwaiters(%rdi) + + /* Install cancellation handler. */ +#ifdef __PIC__ + leaq __condvar_cleanup(%rip), %rsi +#else + leaq __condvar_cleanup, %rsi +#endif + leaq 32(%rsp), %rdi + movq %rsp, %rdx + callq __pthread_cleanup_push + + /* Get and store current wakeup_seq value. */ + movq 8(%rsp), %rdi + movq wakeup_seq(%rdi), %r9 + movl broadcast_seq(%rdi), %edx + movq %r9, 24(%rsp) + movl %edx, 4(%rsp) + + /* Unlock. */ +8: movl cond_futex(%rdi), %r12d + LOCK +#if cond_lock == 0 + decl (%rdi) +#else + decl cond_lock(%rdi) +#endif + jne 3f + +4: callq __pthread_enable_asynccancel + movl %eax, (%rsp) + + movq 8(%rsp), %rdi + xorq %r10, %r10 + movq %r12, %rdx + addq $cond_futex-cond_lock, %rdi + movl $SYS_futex, %eax +#if FUTEX_WAIT == 0 + xorl %esi, %esi +#else + movl $FUTEX_WAIT, %esi +#endif + syscall + + movl (%rsp), %edi + callq __pthread_disable_asynccancel + + /* Lock. */ + movq 8(%rsp), %rdi + movl $1, %esi + xorl %eax, %eax + LOCK +#if cond_lock == 0 + cmpxchgl %esi, (%rdi) +#else + cmpxchgl %esi, cond_lock(%rdi) +#endif + jnz 5f + +6: movl broadcast_seq(%rdi), %edx + + movq woken_seq(%rdi), %rax + + movq wakeup_seq(%rdi), %r9 + + cmpl 4(%rsp), %edx + jne 16f + + cmpq 24(%rsp), %r9 + jbe 8b + + cmpq %rax, %r9 + jna 8b + + incq woken_seq(%rdi) + + /* Unlock */ +16: subl $(1 << clock_bits), cond_nwaiters(%rdi) + + /* Wake up a thread which wants to destroy the condvar object. */ + cmpq $0xffffffffffffffff, total_seq(%rdi) + jne 17f + movl cond_nwaiters(%rdi), %eax + andl $~((1 << clock_bits) - 1), %eax + jne 17f + + addq $cond_nwaiters, %rdi + movl $SYS_futex, %eax + movl $FUTEX_WAKE, %esi + movl $1, %edx + syscall + subq $cond_nwaiters, %rdi + +17: LOCK +#if cond_lock == 0 + decl (%rdi) +#else + decl cond_lock(%rdi) +#endif + jne 10f + + /* Remove cancellation handler. */ +11: movq 32+CLEANUP_PREV(%rsp), %rdx + movq %rdx, %fs:CLEANUP + + movq 16(%rsp), %rdi + callq __pthread_mutex_cond_lock +14: addq $FRAME_SIZE, %rsp +.Laddq: + + popq %r12 +.Lpop_r12: + + /* We return the result of the mutex_lock operation. */ + retq + + /* Initial locking failed. */ +1: +.LSbl1: +#if cond_lock != 0 + addq $cond_lock, %rdi +#endif + callq __lll_mutex_lock_wait + jmp 2b + + /* Unlock in loop requires wakeup. */ +3: +#if cond_lock != 0 + addq $cond_lock, %rdi +#endif + callq __lll_mutex_unlock_wake + jmp 4b + + /* Locking in loop failed. */ +5: +#if cond_lock != 0 + addq $cond_lock, %rdi +#endif + callq __lll_mutex_lock_wait +#if cond_lock != 0 + subq $cond_lock, %rdi +#endif + jmp 6b + + /* Unlock after loop requires wakeup. */ +10: +#if cond_lock != 0 + addq $cond_lock, %rdi +#endif + callq __lll_mutex_unlock_wake + jmp 11b + + /* The initial unlocking of the mutex failed. */ +12: movq %rax, %r10 + movq 8(%rsp), %rdi + LOCK +#if cond_lock == 0 + decl (%rdi) +#else + decl cond_lock(%rdi) +#endif + jne 13f + +#if cond_lock != 0 + addq $cond_lock, %rdi +#endif + callq __lll_mutex_unlock_wake + +13: movq %r10, %rax + jmp 14b +.LENDCODE: + .size __pthread_cond_wait, .-__pthread_cond_wait +weak_alias(__pthread_cond_wait, pthread_cond_wait) + + + .section .eh_frame,"a",@progbits +.LSTARTFRAME: + .long .LENDCIE-.LSTARTCIE # Length of the CIE. +.LSTARTCIE: + .long 0 # CIE ID. + .byte 1 # Version number. +#ifdef SHARED + .string "zR" # NUL-terminated augmentation + # string. +#else + .ascii "\0" # NUL-terminated augmentation + # string. +#endif + .uleb128 1 # Code alignment factor. + .sleb128 -8 # Data alignment factor. + .byte 16 # Return address register + # column. +#ifdef SHARED + .uleb128 1 # Augmentation value length. + .byte 0x1b # Encoding: DW_EH_PE_pcrel + # + DW_EH_PE_sdata4. +#endif + .byte 0x0c # DW_CFA_def_cfa + .uleb128 7 + .uleb128 8 + .byte 0x90 # DW_CFA_offset, column 0x8 + .uleb128 1 + .align 8 +.LENDCIE: + + .long .LENDFDE-.LSTARTFDE # Length of the FDE. +.LSTARTFDE: + .long .LSTARTFDE-.LSTARTFRAME # CIE pointer. +#ifdef SHARED + .long .LSTARTCODE-. # PC-relative start address + # of the code +#else + .long .LSTARTCODE # Start address of the code. +#endif + .long .LENDCODE-.LSTARTCODE # Length of the code. +#ifdef SHARED + .uleb128 0 # No augmentation data. +#endif + .byte 0x40+.Lpush_r12-.LSTARTCODE # DW_CFA_advance_loc+N + .byte 14 # DW_CFA_def_cfa_offset + .uleb128 16 + .byte 0x8c # DW_CFA_offset %r12 + .uleb128 2 + .byte 0x40+.Lsubq-.Lpush_r12 # DW_CFA_advance_loc+N + .byte 14 # DW_CFA_def_cfa_offset + .uleb128 16+FRAME_SIZE + .byte 3 # DW_CFA_advance_loc2 + .2byte .Laddq-.Lsubq + .byte 14 # DW_CFA_def_cfa_offset + .uleb128 16 + .byte 0x40+.Lpop_r12-.Laddq # DW_CFA_advance_loc+N + .byte 14 # DW_CFA_def_cfa_offset + .uleb128 8 + .byte 0xcc # DW_CFA_restore %r12 + .byte 0x40+.LSbl1-.Lpop_r12 # DW_CFA_advance_loc+N + .byte 14 # DW_CFA_def_cfa_offset + .uleb128 80 + .byte 0x8c # DW_CFA_offset %r12 + .uleb128 2 + .align 8 +.LENDFDE: diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_once.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_once.S new file mode 100644 index 000000000..d8bfa26c6 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_once.S @@ -0,0 +1,259 @@ +/* Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> + +#ifndef UP +# define LOCK lock +#else +# define LOCK +#endif + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + + .comm __fork_generation, 4, 4 + + .text + + + .globl __pthread_once + .type __pthread_once,@function + .align 16 +__pthread_once: +.LSTARTCODE: + testl $2, (%rdi) + jz 1f + xorl %eax, %eax + retq + + /* Preserve the function pointer. */ +1: pushq %rsi +.Lpush_rsi: + xorq %r10, %r10 + + /* Not yet initialized or initialization in progress. + Get the fork generation counter now. */ +6: movl (%rdi), %eax + +5: movl %eax, %edx + + testl $2, %eax + jnz 4f + + andl $3, %edx + orl __fork_generation(%rip), %edx + orl $1, %edx + + LOCK + cmpxchgl %edx, (%rdi) + jnz 5b + + /* Check whether another thread already runs the initializer. */ + testl $1, %eax + jz 3f /* No -> do it. */ + + /* Check whether the initializer execution was interrupted + by a fork. */ + xorl %edx, %eax + testl $0xfffffffc, %eax + jnz 3f /* Different for generation -> run initializer. */ + + /* Somebody else got here first. Wait. */ +#if FUTEX_WAIT == 0 + xorl %esi, %esi +#else + movl $FUTEX_WAIT, %esi +#endif + movl $SYS_futex, %eax + syscall + jmp 6b + + /* Preserve the pointer to the control variable. */ +3: pushq %rdi +.Lpush_rdi: + +.LcleanupSTART: + callq *8(%rsp) +.LcleanupEND: + + /* Get the control variable address back. */ + popq %rdi +.Lpop_rdi: + + /* Sucessful run of the initializer. Signal that we are done. */ + LOCK + incl (%rdi) + + /* Wake up all other threads. */ + movl $0x7fffffff, %edx + movl $FUTEX_WAKE, %esi + movl $SYS_futex, %eax + syscall + +4: addq $8, %rsp +.Ladd: + xorl %eax, %eax + retq + + .size __pthread_once,.-__pthread_once + + + .globl __pthread_once_internal +__pthread_once_internal = __pthread_once + + .globl pthread_once +pthread_once = __pthread_once + + + .type clear_once_control,@function + .align 16 +clear_once_control: + movq (%rsp), %rdi + movq %rax, %r8 + movl $0, (%rdi) + + movl $0x7fffffff, %edx + movl $FUTEX_WAKE, %esi + movl $SYS_futex, %eax + syscall + + movq %r8, %rdi +.LcallUR: + call _Unwind_Resume@PLT + hlt +.LENDCODE: + .size clear_once_control,.-clear_once_control + + + .section .gcc_except_table,"a",@progbits +.LexceptSTART: + .byte 0xff # @LPStart format (omit) + .byte 0xff # @TType format (omit) + .byte 0x01 # call-site format + # DW_EH_PE_uleb128 + .uleb128 .Lcstend-.Lcstbegin +.Lcstbegin: + .uleb128 .LcleanupSTART-.LSTARTCODE + .uleb128 .LcleanupEND-.LcleanupSTART + .uleb128 clear_once_control-.LSTARTCODE + .uleb128 0 + .uleb128 .LcallUR-.LSTARTCODE + .uleb128 .LENDCODE-.LcallUR + .uleb128 0 + .uleb128 0 +.Lcstend: + + + .section .eh_frame,"a",@progbits +.LSTARTFRAME: + .long .LENDCIE-.LSTARTCIE # Length of the CIE. +.LSTARTCIE: + .long 0 # CIE ID. + .byte 1 # Version number. +#ifdef SHARED + .string "zPLR" # NUL-terminated augmentation + # string. +#else + .string "zPL" # NUL-terminated augmentation + # string. +#endif + .uleb128 1 # Code alignment factor. + .sleb128 -8 # Data alignment factor. + .byte 16 # Return address register + # column. +#ifdef SHARED + .uleb128 7 # Augmentation value length. + .byte 0x9b # Personality: DW_EH_PE_pcrel + # + DW_EH_PE_sdata4 + # + DW_EH_PE_indirect + .long DW.ref.__gcc_personality_v0-. + .byte 0x1b # LSDA Encoding: DW_EH_PE_pcrel + # + DW_EH_PE_sdata4. + .byte 0x1b # FDE Encoding: DW_EH_PE_pcrel + # + DW_EH_PE_sdata4. +#else + .uleb128 10 # Augmentation value length. + .byte 0x0 # Personality: absolute + .quad __gcc_personality_v0 + .byte 0x0 # LSDA Encoding: absolute +#endif + .byte 0x0c # DW_CFA_def_cfa + .uleb128 7 + .uleb128 8 + .byte 0x90 # DW_CFA_offset, column 0x10 + .uleb128 1 + .align 8 +.LENDCIE: + + .long .LENDFDE-.LSTARTFDE # Length of the FDE. +.LSTARTFDE: + .long .LSTARTFDE-.LSTARTFRAME # CIE pointer. +#ifdef SHARED + .long .LSTARTCODE-. # PC-relative start address + # of the code. + .long .LENDCODE-.LSTARTCODE # Length of the code. + .uleb128 4 # Augmentation size + .long .LexceptSTART-. +#else + .quad .LSTARTCODE # Start address of the code. + .quad .LENDCODE-.LSTARTCODE # Length of the code. + .uleb128 8 # Augmentation size + .quad .LexceptSTART +#endif + .byte 4 # DW_CFA_advance_loc4 + .long .Lpush_rsi-.LSTARTCODE + .byte 14 # DW_CFA_def_cfa_offset + .uleb128 16 + .byte 4 # DW_CFA_advance_loc4 + .long .Lpush_rdi-.Lpush_rsi + .byte 14 # DW_CFA_def_cfa_offset + .uleb128 24 + .byte 4 # DW_CFA_advance_loc4 + .long .Lpop_rdi-.Lpush_rdi + .byte 14 # DW_CFA_def_cfa_offset + .uleb128 16 + .byte 4 # DW_CFA_advance_loc4 + .long .Ladd-.Lpop_rdi + .byte 14 # DW_CFA_def_cfa_offset + .uleb128 8 + .byte 4 # DW_CFA_advance_loc4 + .long clear_once_control-.Ladd + .byte 14 # DW_CFA_def_cfa_offset + .uleb128 24 +#if 0 + .byte 4 # DW_CFA_advance_loc4 + .long .Lpop_rdi2-clear_once_control + .byte 14 # DW_CFA_def_cfa_offset + .uleb128 16 +#endif + .align 8 +.LENDFDE: + + +#ifdef SHARED + .hidden DW.ref.__gcc_personality_v0 + .weak DW.ref.__gcc_personality_v0 + .section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits + .align 8 + .type DW.ref.__gcc_personality_v0, @object + .size DW.ref.__gcc_personality_v0, 8 +DW.ref.__gcc_personality_v0: + .quad __gcc_personality_v0 +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_rdlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_rdlock.S new file mode 100644 index 000000000..d7543572a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_rdlock.S @@ -0,0 +1,177 @@ +/* Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <lowlevelrwlock.h> +#include <pthread-errnos.h> +#include <tcb-offsets.h> + + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + +#ifndef UP +# define LOCK lock +#else +# define LOCK +#endif + + + .text + + .globl __pthread_rwlock_rdlock + .type __pthread_rwlock_rdlock,@function + .align 16 +__pthread_rwlock_rdlock: + xorq %r10, %r10 + + /* Get the lock. */ + movl $1, %esi + xorl %eax, %eax + LOCK +#if MUTEX == 0 + cmpxchgl %esi, (%rdi) +#else + cmpxchgl %esi, MUTEX(%rdi) +#endif + jnz 1f + +2: movl WRITER(%rdi), %eax + testl %eax, %eax + jne 14f + cmpl $0, WRITERS_QUEUED(%rdi) + je 5f + cmpl $0, FLAGS(%rdi) + je 5f + +3: incl READERS_QUEUED(%rdi) + je 4f + + movl READERS_WAKEUP(%rdi), %edx + + LOCK +#if MUTEX == 0 + decl (%rdi) +#else + decl MUTEX(%rdi) +#endif + jne 10f + +11: addq $READERS_WAKEUP, %rdi +#if FUTEX_WAIT == 0 + xorl %esi, %esi +#else + movl $FUTEX_WAIT, %esi +#endif + movl $SYS_futex, %eax + syscall + + subq $READERS_WAKEUP, %rdi + + /* Reget the lock. */ + movl $1, %esi + xorl %eax, %eax + LOCK +#if MUTEX == 0 + cmpxchgl %esi, (%rdi) +#else + cmpxchgl %esi, MUTEX(%rdi) +#endif + jnz 12f + +13: decl READERS_QUEUED(%rdi) + jmp 2b + +5: xorl %edx, %edx + incl NR_READERS(%rdi) + je 8f +9: LOCK +#if MUTEX == 0 + decl (%rdi) +#else + decl MUTEX(%rdi) +#endif + jne 6f +7: + + movq %rdx, %rax + retq + +1: +#if MUTEX != 0 + addq $MUTEX, %rdi +#endif + callq __lll_mutex_lock_wait +#if MUTEX != 0 + subq $MUTEX, %rdi +#endif + jmp 2b + +14: cmpl %fs:TID, %eax + jne 3b + /* Deadlock detected. */ + movl $EDEADLK, %edx + jmp 9b + +6: +#if MUTEX != 0 + addq $MUTEX, %rdi +#endif + callq __lll_mutex_unlock_wake +#if MUTEX != 0 + subq $MUTEX, %rdi +#endif + jmp 7b + + /* Overflow. */ +8: decl NR_READERS(%rdi) + movl $EAGAIN, %edx + jmp 9b + + /* Overflow. */ +4: decl READERS_QUEUED(%rdi) + movl $EAGAIN, %edx + jmp 9b + +10: +#if MUTEX != 0 + addq $MUTEX, %rdi +#endif + callq __lll_mutex_unlock_wake +#if MUTEX != 0 + subq $MUTEX, %rdi +#endif + jmp 11b + +12: +#if MUTEX == 0 + addq $MUTEX, %rdi +#endif + callq __lll_mutex_lock_wait +#if MUTEX != 0 + subq $MUTEX, %rdi +#endif + jmp 13b + .size __pthread_rwlock_rdlock,.-__pthread_rwlock_rdlock + + .globl pthread_rwlock_rdlock +pthread_rwlock_rdlock = __pthread_rwlock_rdlock + + .globl __pthread_rwlock_rdlock_internal +__pthread_rwlock_rdlock_internal = __pthread_rwlock_rdlock diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedrdlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedrdlock.S new file mode 100644 index 000000000..f044842e0 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedrdlock.S @@ -0,0 +1,220 @@ +/* Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <lowlevelrwlock.h> +#include <pthread-errnos.h> +#include <tcb-offsets.h> + + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + +/* For the calculation see asm/vsyscall.h. */ +#define VSYSCALL_ADDR_vgettimeofday 0xffffffffff600000 + + +#ifndef UP +# define LOCK lock +#else +# define LOCK +#endif + + + .text + + .globl pthread_rwlock_timedrdlock + .type pthread_rwlock_timedrdlock,@function + .align 16 +pthread_rwlock_timedrdlock: + pushq %r12 + pushq %r13 + pushq %r14 + subq $16, %rsp + + movq %rdi, %r12 + movq %rsi, %r13 + + /* Get the lock. */ + movl $1, %esi + xorl %eax, %eax + LOCK +#if MUTEX == 0 + cmpxchgl %esi, (%rdi) +#else + cmpxchgl %esi, MUTEX(%rdi) +#endif + jnz 1f + +2: movl WRITER(%r12), %eax + testl %eax, %eax + jne 14f + cmpl $0, WRITERS_QUEUED(%r12) + je 5f + cmpl $0, FLAGS(%r12) + je 5f + + /* Check the value of the timeout parameter. */ +3: cmpq $1000000000, 8(%r13) + jae 19f + + incl READERS_QUEUED(%r12) + je 4f + + movl READERS_WAKEUP(%r12), %r14d + + /* Unlock. */ + LOCK +#if MUTEX == 0 + decl (%r12) +#else + decl MUTEX(%r12) +#endif + jne 10f + + /* Get current time. */ +11: movq %rsp, %rdi + xorl %esi, %esi + movq $VSYSCALL_ADDR_vgettimeofday, %rax + callq *%rax + + /* Compute relative timeout. */ + movq 8(%rsp), %rax + movl $1000, %edi + mul %rdi /* Milli seconds to nano seconds. */ + movq (%r13), %rcx + movq 8(%r13), %rdi + subq (%rsp), %rcx + subq %rax, %rdi + jns 15f + addq $1000000000, %rdi + decq %rcx +15: testq %rcx, %rcx + js 16f /* Time is already up. */ + + /* Futex call. */ + movq %rcx, (%rsp) /* Store relative timeout. */ + movq %rdi, 8(%rsp) + +#if FUTEX_WAIT == 0 + xorl %esi, %esi +#else + movl $FUTEX_WAIT, %esi +#endif + movq %rsp, %r10 + movl %r14d, %edx + leaq READERS_WAKEUP(%r12), %rdi + movl $SYS_futex, %eax + syscall + movq %rax, %rdx +17: + + /* Reget the lock. */ + movl $1, %esi + xorl %eax, %eax + LOCK +#if MUTEX == 0 + cmpxchgl %esi, (%r12) +#else + cmpxchgl %esi, MUTEX(%r12) +#endif + jnz 12f + +13: decl READERS_QUEUED(%r12) + cmpq $-ETIMEDOUT, %rdx + jne 2b + +18: movl $ETIMEDOUT, %edx + jmp 9f + + +5: xorl %edx, %edx + incl NR_READERS(%r12) + je 8f +9: LOCK +#if MUTEX == 0 + decl (%r12) +#else + decl MUTEX(%r12) +#endif + jne 6f + +7: movq %rdx, %rax + + addq $16, %rsp + popq %r14 + popq %r13 + popq %r12 + retq + +1: +#if MUTEX != 0 + addq $MUTEX, %rdi +#endif + callq __lll_mutex_lock_wait + jmp 2b + +14: cmpl %fs:TID, %eax + jne 3b + movl $EDEADLK, %edx + jmp 9b + +6: +#if MUTEX == 0 + movq %r12, %rdi +#else + leal MUTEX(%r12), %rdi +#endif + callq __lll_mutex_unlock_wake + jmp 7b + + /* Overflow. */ +8: decl NR_READERS(%r12) + movl $EAGAIN, %edx + jmp 9b + + /* Overflow. */ +4: decl READERS_QUEUED(%r12) + movl $EAGAIN, %edx + jmp 9b + +10: +#if MUTEX == 0 + movq %r12, %rdi +#else + leaq MUTEX(%r12), %rdi +#endif + callq __lll_mutex_unlock_wake + jmp 11b + +12: +#if MUTEX == 0 + movq %r12, %rdi +#else + leaq MUTEX(%r12), %rdi +#endif + callq __lll_mutex_lock_wait + jmp 13b + +16: movq $-ETIMEDOUT, %rdx + jmp 17b + +19: movl $EINVAL, %edx + jmp 9b + .size pthread_rwlock_timedrdlock,.-pthread_rwlock_timedrdlock diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedwrlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedwrlock.S new file mode 100644 index 000000000..b479da727 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedwrlock.S @@ -0,0 +1,211 @@ +/* Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <lowlevelrwlock.h> +#include <pthread-errnos.h> +#include <tcb-offsets.h> + + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + +/* For the calculation see asm/vsyscall.h. */ +#define VSYSCALL_ADDR_vgettimeofday 0xffffffffff600000 + +#ifndef UP +# define LOCK lock +#else +# define LOCK +#endif + + + .text + + .globl pthread_rwlock_timedwrlock + .type pthread_rwlock_timedwrlock,@function + .align 16 +pthread_rwlock_timedwrlock: + pushq %r12 + pushq %r13 + pushq %r14 + subq $16, %rsp + + movq %rdi, %r12 + movq %rsi, %r13 + + /* Get the lock. */ + movl $1, %esi + xorl %eax, %eax + LOCK +#if MUTEX == 0 + cmpxchgl %esi, (%rdi) +#else + cmpxchgl %esi, MUTEX(%rdi) +#endif + jnz 1f + +2: movl WRITER(%r12), %eax + testl %eax, %eax + jne 14f + cmpl $0, NR_READERS(%r12) + je 5f + + /* Check the value of the timeout parameter. */ +3: cmpq $1000000000, 8(%r13) + jae 19f + + incl WRITERS_QUEUED(%r12) + je 4f + + movl WRITERS_WAKEUP(%r12), %r14d + + LOCK +#if MUTEX == 0 + decl (%r12) +#else + decl MUTEX(%r12) +#endif + jne 10f + + /* Get current time. */ +11: movq %rsp, %rdi + xorl %esi, %esi + movq $VSYSCALL_ADDR_vgettimeofday, %rax + callq *%rax + + /* Compute relative timeout. */ + movq 8(%rsp), %rax + movl $1000, %edi + mul %rdi /* Milli seconds to nano seconds. */ + movq (%r13), %rcx + movq 8(%r13), %rdi + subq (%rsp), %rcx + subq %rax, %rdi + jns 15f + addq $1000000000, %rdi + decq %rcx +15: testq %rcx, %rcx + js 16f /* Time is already up. */ + + /* Futex call. */ + movq %rcx, (%rsp) /* Store relative timeout. */ + movq %rdi, 8(%rsp) + +#if FUTEX_WAIT == 0 + xorl %esi, %esi +#else + movl $FUTEX_WAIT, %esi +#endif + movq %rsp, %r10 + movl %r14d, %edx + leaq WRITERS_WAKEUP(%r12), %rdi + movl $SYS_futex, %eax + syscall + movq %rax, %rdx +17: + + /* Reget the lock. */ + movl $1, %esi + xorl %eax, %eax + LOCK +#if MUTEX == 0 + cmpxchgl %esi, (%r12) +#else + cmpxchgl %esi, MUTEX(%r12) +#endif + jnz 12f + +13: decl WRITERS_QUEUED(%r12) + cmpq $-ETIMEDOUT, %rdx + jne 2b + +18: movl $ETIMEDOUT, %edx + jmp 9f + + +5: xorl %edx, %edx + movl %fs:TID, %eax + movl %eax, WRITER(%r12) +9: LOCK +#if MUTEX == 0 + decl (%r12) +#else + decl MUTEX(%r12) +#endif + jne 6f + +7: movq %rdx, %rax + + addq $16, %rsp + popq %r14 + popq %r13 + popq %r12 + retq + +1: +#if MUTEX != 0 + addq $MUTEX, %rdi +#endif + callq __lll_mutex_lock_wait + jmp 2b + +14: cmpl %fs:TID, %eax + jne 3b +20: movl $EDEADLK, %edx + jmp 9b + +6: +#if MUTEX == 0 + movq %r12, %rdi +#else + leal MUTEX(%r12), %rdi +#endif + callq __lll_mutex_unlock_wake + jmp 7b + + /* Overflow. */ +4: decl WRITERS_QUEUED(%r12) + movl $EAGAIN, %edx + jmp 9b + +10: +#if MUTEX == 0 + movq %r12, %rdi +#else + leaq MUTEX(%r12), %rdi +#endif + callq __lll_mutex_unlock_wake + jmp 11b + +12: +#if MUTEX == 0 + movq %r12, %rdi +#else + leaq MUTEX(%r12), %rdi +#endif + callq __lll_mutex_lock_wait + jmp 13b + +16: movq $-ETIMEDOUT, %rdx + jmp 17b + +19: movl $EINVAL, %edx + jmp 9b + .size pthread_rwlock_timedwrlock,.-pthread_rwlock_timedwrlock diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_unlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_unlock.S new file mode 100644 index 000000000..a0f75226a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_unlock.S @@ -0,0 +1,129 @@ +/* Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <lowlevelrwlock.h> + + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + +#ifndef UP +# define LOCK lock +#else +# define LOCK +#endif + + + .text + + .globl __pthread_rwlock_unlock + .type __pthread_rwlock_unlock,@function + .align 16 +__pthread_rwlock_unlock: + /* Get the lock. */ + movl $1, %esi + xorl %eax, %eax + LOCK +#if MUTEX == 0 + cmpxchgl %esi, (%rdi) +#else + cmpxchgl %esi, MUTEX(%rdi) +#endif + jnz 1f + +2: cmpl $0, WRITER(%rdi) + jne 5f + decl NR_READERS(%rdi) + jnz 6f + +5: movl $0, WRITER(%rdi) + + movl $1, %esi + leaq WRITERS_WAKEUP(%rdi), %r10 + movq %rsi, %rdx + cmpl $0, WRITERS_QUEUED(%rdi) + jne 0f + + /* If also no readers waiting nothing to do. */ + cmpl $0, READERS_QUEUED(%rdi) + je 6f + + movl $0x7fffffff, %edx + leaq READERS_WAKEUP(%rdi), %r10 + +0: incl (%r10) + LOCK +#if MUTEX == 0 + decl (%rdi) +#else + decl MUTEX(%rdi) +#endif + jne 7f + +8: movl $SYS_futex, %eax + movq %r10, %rdi + syscall + + xorl %eax, %eax + retq + + .align 16 +6: LOCK +#if MUTEX == 0 + decl (%rdi) +#else + decl MUTEX(%rdi) +#endif + jne 3f + +4: xorl %eax, %eax + retq + +1: +#if MUTEX != 0 + addq $MUTEX, %rdi +#endif + callq __lll_mutex_lock_wait +#if MUTEX != 0 + subq $MUTEX, %rdi +#endif + jmp 2b + +3: +#if MUTEX != 0 + addq $MUTEX, %rdi +#endif + callq __lll_mutex_unlock_wake + jmp 4b + +7: +#if MUTEX != 0 + addq $MUTEX, %rdi +#endif + callq __lll_mutex_unlock_wake + jmp 8b + + .size __pthread_rwlock_unlock,.-__pthread_rwlock_unlock + + .globl pthread_rwlock_unlock +pthread_rwlock_unlock = __pthread_rwlock_unlock + + .globl __pthread_rwlock_unlock_internal +__pthread_rwlock_unlock_internal = __pthread_rwlock_unlock diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_wrlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_wrlock.S new file mode 100644 index 000000000..39b54dc6b --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_wrlock.S @@ -0,0 +1,165 @@ +/* Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <lowlevelrwlock.h> +#include <pthread-errnos.h> +#include <tcb-offsets.h> + + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + +#ifndef UP +# define LOCK lock +#else +# define LOCK +#endif + + + .text + + .globl __pthread_rwlock_wrlock + .type __pthread_rwlock_wrlock,@function + .align 16 +__pthread_rwlock_wrlock: + xorq %r10, %r10 + + /* Get the lock. */ + movl $1, %esi + xorl %eax, %eax + LOCK +#if MUTEX == 0 + cmpxchgl %esi, (%rdi) +#else + cmpxchgl %esi, MUTEX(%rdi) +#endif + jnz 1f + +2: movl WRITER(%rdi), %eax + testl %eax, %eax + jne 14f + cmpl $0, NR_READERS(%rdi) + je 5f + +3: incl WRITERS_QUEUED(%rdi) + je 4f + + movl WRITERS_WAKEUP(%rdi), %edx + + LOCK +#if MUTEX == 0 + decl (%rdi) +#else + decl MUTEX(%rdi) +#endif + jne 10f + +11: addq $WRITERS_WAKEUP, %rdi +#if FUTEX_WAIT == 0 + xorl %esi, %esi +#else + movl $FUTEX_WAIT, %esi +#endif + movl $SYS_futex, %eax + syscall + + subq $WRITERS_WAKEUP, %rdi + + /* Reget the lock. */ + movl $1, %esi + xorl %eax, %eax + LOCK +#if MUTEX == 0 + cmpxchgl %esi, (%rdi) +#else + cmpxchgl %esi, MUTEX(%rdi) +#endif + jnz 12f + +13: decl WRITERS_QUEUED(%rdi) + jmp 2b + +5: xorl %edx, %edx + movl %fs:TID, %eax + movl %eax, WRITER(%rdi) +9: LOCK +#if MUTEX == 0 + decl (%rdi) +#else + decl MUTEX(%rdi) +#endif + jne 6f +7: + + movq %rdx, %rax + retq + +1: +#if MUTEX != 0 + addq $MUTEX, %rdi +#endif + callq __lll_mutex_lock_wait +#if MUTEX != 0 + subq $MUTEX, %rdi +#endif + jmp 2b + +14: cmpl %fs:TID, %eax + jne 3b + movl $EDEADLK, %edx + jmp 9b + +6: +#if MUTEX != 0 + addq $MUTEX, %rdi +#endif + callq __lll_mutex_unlock_wake + jmp 7b + +4: decl WRITERS_QUEUED(%rdi) + movl $EAGAIN, %edx + jmp 9b + +10: +#if MUTEX != 0 + addq $MUTEX, %rdi +#endif + callq __lll_mutex_unlock_wake +#if MUTEX != 0 + subq $MUTEX, %rdi +#endif + jmp 11b + +12: +#if MUTEX != 0 + addq $MUTEX, %rdi +#endif + callq __lll_mutex_lock_wait +#if MUTEX != 0 + subq $MUTEX, %rdi +#endif + jmp 13b + .size __pthread_rwlock_wrlock,.-__pthread_rwlock_wrlock + + .globl pthread_rwlock_wrlock +pthread_rwlock_wrlock = __pthread_rwlock_wrlock + + .globl __pthread_rwlock_wrlock_internal +__pthread_rwlock_wrlock_internal = __pthread_rwlock_wrlock diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_setaffinity.c b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_setaffinity.c new file mode 100644 index 000000000..640d3044f --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_setaffinity.c @@ -0,0 +1,14 @@ +#include <tls.h> + +#define RESET_VGETCPU_CACHE() \ + do { \ + asm volatile ("movl %0, %%fs:%P1\n\t" \ + "movl %0, %%fs:%P2" \ + : \ + : "ir" (0), "i" (offsetof (struct pthread, \ + header.vgetcpu_cache[0])), \ + "i" (offsetof (struct pthread, \ + header.vgetcpu_cache[1]))); \ + } while (0) + +#include "../pthread_setaffinity.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_spin_init.c b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_spin_init.c new file mode 100644 index 000000000..483de8cac --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_spin_init.c @@ -0,0 +1 @@ +#include <sysdeps/x86_64/pthread_spin_init.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_spin_unlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_spin_unlock.S new file mode 100644 index 000000000..e8e2ba262 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_spin_unlock.S @@ -0,0 +1 @@ +#include <sysdeps/x86_64/pthread_spin_unlock.S> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sem_post.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sem_post.S new file mode 100644 index 000000000..5c8a858ad --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sem_post.S @@ -0,0 +1,64 @@ +/* Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <pthread-errnos.h> + +#ifndef UP +# define LOCK lock +#else +# define +#endif + +#define FUTEX_WAKE 1 + + + .text + + .globl sem_post + .type sem_post,@function + .align 16 +sem_post: + movl $1, %edx + LOCK + xaddl %edx, (%rdi) + + movl $SYS_futex, %eax + movl $FUTEX_WAKE, %esi + incl %edx + syscall + + testq %rax, %rax + js 1f + + xorl %eax, %eax + retq + +1: +#if USE___THREAD + movq errno@gottpoff(%rip), %rdx + movl $EINVAL, %fs:(%rdx) +#else + callq __errno_location@plt + movl $EINVAL, (%rax) +#endif + + orl $-1, %eax + retq + .size sem_post,.-sem_post diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S new file mode 100644 index 000000000..64e168099 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S @@ -0,0 +1,174 @@ +/* Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <pthread-errnos.h> +#include <tcb-offsets.h> +#include <tls.h> + +#ifndef UP +# define LOCK lock +#else +# define +#endif + +/* For the calculation see asm/vsyscall.h. */ +#define VSYSCALL_ADDR_vgettimeofday 0xffffffffff600000 + + + .text + + .globl sem_timedwait + .type sem_timedwait,@function + .align 16 + cfi_startproc +sem_timedwait: + /* First check for cancellation. */ + movl %fs:CANCELHANDLING, %eax + andl $0xfffffff9, %eax + cmpl $8, %eax + je 11f + + movl (%rdi), %eax +2: testl %eax, %eax + je 1f + + leaq -1(%rax), %rdx + LOCK + cmpxchgl %edx, (%rdi) + jne 2b + + xorl %eax, %eax + retq + + /* Check whether the timeout value is valid. */ +1: pushq %r12 + cfi_adjust_cfa_offset(8) + pushq %r13 + cfi_adjust_cfa_offset(8) + pushq %r14 + cfi_adjust_cfa_offset(8) + subq $24, %rsp + cfi_adjust_cfa_offset(24) + + movq %rdi, %r12 + cfi_offset(12, -16) /* %r12 */ + movq %rsi, %r13 + cfi_offset(13, -24) /* %r13 */ + + /* Check for invalid nanosecond field. */ + cmpq $1000000000, 8(%r13) + movl $EINVAL, %r14d + cfi_offset(14, -24) /* %r14 */ + jae 6f + +7: call __pthread_enable_asynccancel + movl %eax, 16(%rsp) + + xorl %esi, %esi + movq %rsp, %rdi + movq $VSYSCALL_ADDR_vgettimeofday, %rax + callq *%rax + + /* Compute relative timeout. */ + movq 8(%rsp), %rax + movl $1000, %edi + mul %rdi /* Milli seconds to nano seconds. */ + movq (%r13), %rdi + movq 8(%r13), %rsi + subq (%rsp), %rdi + subq %rax, %rsi + jns 5f + addq $1000000000, %rsi + decq %rdi +5: testq %rdi, %rdi + movl $ETIMEDOUT, %r14d + js 6f /* Time is already up. */ + + movq %rdi, (%rsp) /* Store relative timeout. */ + movq %rsi, 8(%rsp) + + movq %rsp, %r10 + movq %r12, %rdi + xorl %esi, %esi + movl $SYS_futex, %eax + xorl %edx, %edx + syscall + movq %rax, %r14 + + movl 16(%rsp), %edi + call __pthread_disable_asynccancel + + testq %r14, %r14 + je 9f + cmpq $-EWOULDBLOCK, %r14 + jne 3f + +9: movl (%r12), %eax +8: testl %eax, %eax + je 7b + + leaq -1(%rax), %rcx + LOCK + cmpxchgl %ecx, (%r12) + jne 8b + + xorl %eax, %eax +10: addq $24, %rsp + cfi_adjust_cfa_offset(-24) + popq %r14 + cfi_adjust_cfa_offset(-8) + cfi_restore(14) + popq %r13 + cfi_adjust_cfa_offset(-8) + cfi_restore(13) + popq %r12 + cfi_adjust_cfa_offset(-8) + cfi_restore(12) + retq + + cfi_adjust_cfa_offset(48) + cfi_offset(12, -16) /* %r12 */ + cfi_offset(13, -24) /* %r13 */ + cfi_offset(14, -32) /* %r14 */ +3: negq %r14 +6: +#if USE___THREAD + movq errno@gottpoff(%rip), %rdx + movl %r14d, %fs:(%rdx) +#else + callq __errno_location@plt + movl %r14d, (%rax) +#endif + + orl $-1, %eax + jmp 10b + cfi_adjust_cfa_offset(-48) + cfi_restore(14) + cfi_restore(13) + cfi_restore(12) + +11: /* Canceled. */ + movq $0xffffffffffffffff, %fs:RESULT + LOCK + orl $0x10, %fs:CANCELHANDLING + movq %fs:CLEANUP_JMP_BUF, %rdi + jmp HIDDEN_JUMPTARGET (__pthread_unwind) + cfi_endproc + .size sem_timedwait,.-sem_timedwait diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sem_trywait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sem_trywait.S new file mode 100644 index 000000000..08edc390c --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sem_trywait.S @@ -0,0 +1,57 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <pthread-errnos.h> + +#ifndef UP +# define LOCK lock +#else +# define +#endif + + .text + + .globl sem_trywait + .type sem_trywait,@function + .align 16 +sem_trywait: + movl (%rdi), %eax +2: testl %eax, %eax + jz 1f + + leaq -1(%rax), %rdx + LOCK + cmpxchgl %edx, (%rdi) + jne 2b + + xorl %eax, %eax + retq + +1: +#if USE___THREAD + movq errno@gottpoff(%rip), %rdx + movl $EAGAIN, %fs:(%rdx) +#else + callq __errno_location@plt + movl $EAGAIN, (%rax) +#endif + orl $-1, %eax + retq + .size sem_trywait,.-sem_trywait diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sem_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sem_wait.S new file mode 100644 index 000000000..c2f94d47f --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sem_wait.S @@ -0,0 +1,119 @@ +/* Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <pthread-errnos.h> +#include <tcb-offsets.h> +#include <tls.h> + +#ifndef UP +# define LOCK lock +#else +# define +#endif + + + .text + + .globl sem_wait + .type sem_wait,@function + .align 16 + cfi_startproc +sem_wait: + /* First check for cancellation. */ + movl %fs:CANCELHANDLING, %eax + andl $0xfffffff9, %eax + cmpl $8, %eax + je 4f + + pushq %r12 + cfi_adjust_cfa_offset(8) + cfi_offset(12, -16) + pushq %r13 + cfi_adjust_cfa_offset(8) + movq %rdi, %r13 + cfi_offset(13, -24) + +3: movl (%r13), %eax +2: testl %eax, %eax + je 1f + + leaq -1(%rax), %rdx + LOCK + cmpxchgl %edx, (%r13) + jne 2b + xorl %eax, %eax + + popq %r13 + cfi_adjust_cfa_offset(-8) + cfi_restore(13) + popq %r12 + cfi_adjust_cfa_offset(-8) + cfi_restore(12) + + retq + + cfi_adjust_cfa_offset(16) + cfi_offset(12, -16) + cfi_offset(13, -24) +1: call __pthread_enable_asynccancel + movl %eax, %r8d + + xorq %r10, %r10 + movl $SYS_futex, %eax + movq %r13, %rdi + movq %r10, %rsi + movq %r10, %rdx + syscall + movq %rax, %r12 + + movl %r8d, %edi + call __pthread_disable_asynccancel + + testq %r12, %r12 + je 3b + cmpq $-EWOULDBLOCK, %r12 + je 3b + negq %r12 +#if USE___THREAD + movq errno@gottpoff(%rip), %rdx + movl %r12d, %fs:(%rdx) +#else + callq __errno_location@plt + movl %r12d, (%rax) +#endif + orl $-1, %eax + + popq %r13 + cfi_adjust_cfa_offset(-8) + cfi_restore(13) + popq %r12 + cfi_adjust_cfa_offset(-8) + cfi_restore(12) + + retq + +4: /* Canceled. */ + movq $0xffffffffffffffff, %fs:RESULT + LOCK + orl $0x10, %fs:CANCELHANDLING + movq %fs:CLEANUP_JMP_BUF, %rdi + jmp HIDDEN_JUMPTARGET (__pthread_unwind) + cfi_endproc + .size sem_wait,.-sem_wait diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h new file mode 100644 index 000000000..1c93952d4 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h @@ -0,0 +1,111 @@ +/* Copyright (C) 2002-2006, 2009 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <tls.h> +#ifndef __ASSEMBLER__ +# include <pthreadP.h> +#endif + +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt + +/* The code to disable cancellation depends on the fact that the called + functions are special. They don't modify registers other than %rax + and %r11 if they return. Therefore we don't have to preserve other + registers around these calls. */ +# undef PSEUDO +# define PSEUDO(name, syscall_name, args) \ + .text; \ + ENTRY (name) \ + SINGLE_THREAD_P; \ + jne L(pseudo_cancel); \ + .type __##syscall_name##_nocancel,@function; \ + .globl __##syscall_name##_nocancel; \ + __##syscall_name##_nocancel: \ + DO_CALL (syscall_name, args); \ + cmpq $-4095, %rax; \ + jae SYSCALL_ERROR_LABEL; \ + ret; \ + .size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel; \ + L(pseudo_cancel): \ + /* We always have to align the stack before calling a function. */ \ + subq $8, %rsp; cfi_adjust_cfa_offset (8); \ + CENABLE \ + /* The return value from CENABLE is argument for CDISABLE. */ \ + movq %rax, (%rsp); \ + DO_CALL (syscall_name, args); \ + movq (%rsp), %rdi; \ + /* Save %rax since it's the error code from the syscall. */ \ + movq %rax, %rdx; \ + CDISABLE \ + movq %rdx, %rax; \ + addq $8,%rsp; cfi_adjust_cfa_offset (-8); \ + cmpq $-4095, %rax; \ + jae SYSCALL_ERROR_LABEL; \ + L(pseudo_end): + + +# ifdef IS_IN_libpthread +# define CENABLE call __pthread_enable_asynccancel; +# define CDISABLE call __pthread_disable_asynccancel; +# define __local_multiple_threads __pthread_multiple_threads +# elif !defined NOT_IN_libc +# define CENABLE call __libc_enable_asynccancel; +# define CDISABLE call __libc_disable_asynccancel; +# define __local_multiple_threads __libc_multiple_threads +# elif defined IS_IN_librt +# define CENABLE call __librt_enable_asynccancel; +# define CDISABLE call __librt_disable_asynccancel; +# else +# error Unsupported library +# endif + +# if defined IS_IN_libpthread || !defined NOT_IN_libc +# ifndef __ASSEMBLER__ +extern int __local_multiple_threads attribute_hidden; +# define SINGLE_THREAD_P \ + __builtin_expect (__local_multiple_threads == 0, 1) +# else +# define SINGLE_THREAD_P cmpl $0, __local_multiple_threads(%rip) +# endif + +# else + +# ifndef __ASSEMBLER__ +# define SINGLE_THREAD_P \ + __builtin_expect (THREAD_GETMEM (THREAD_SELF, \ + header.multiple_threads) == 0, 1) +# else +# define SINGLE_THREAD_P cmpl $0, %fs:MULTIPLE_THREADS_OFFSET +# endif + +# endif + +#elif !defined __ASSEMBLER__ + +# define SINGLE_THREAD_P (1) +# define NO_CANCELLATION 1 + +#endif + +#ifndef __ASSEMBLER__ +# define RTLD_SINGLE_THREAD_P \ + __builtin_expect (THREAD_GETMEM (THREAD_SELF, \ + header.multiple_threads) == 0, 1) +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sysdep.h b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sysdep.h new file mode 100644 index 000000000..fe92a8ab5 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sysdep.h @@ -0,0 +1,259 @@ +/* Copyright (C) 2001-2005, 2007 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _LINUX_X86_64_SYSDEP_H +#define _LINUX_X86_64_SYSDEP_H 1 + +/* There is some commonality. */ +#include <sys/syscall.h> +#include <sysdeps/i386/sysdep.h> + +#ifdef IS_IN_rtld +# include <dl-sysdep.h> /* Defines RTLD_PRIVATE_ERRNO. */ +#endif + +/* For Linux we can use the system call table in the header file + /usr/include/asm/unistd.h + of the kernel. But these symbols do not follow the SYS_* syntax + so we have to redefine the `SYS_ify' macro here. */ +#undef SYS_ify +#define SYS_ify(syscall_name) __NR_##syscall_name + +/* This is a kludge to make syscalls.list find these under the names + pread and pwrite, since some kernel headers define those names + and some define the *64 names for the same system calls. */ +#if !defined __NR_pread && defined __NR_pread64 +# define __NR_pread __NR_pread64 +#endif +#if !defined __NR_pwrite && defined __NR_pwrite64 +# define __NR_pwrite __NR_pwrite64 +#endif + +/* This is to help the old kernel headers where __NR_semtimedop is not + available. */ +#ifndef __NR_semtimedop +# define __NR_semtimedop 220 +#endif + + +#ifdef __ASSEMBLER__ + +/* Linux uses a negative return value to indicate syscall errors, + unlike most Unices, which use the condition codes' carry flag. + + Since version 2.1 the return value of a system call might be + negative even if the call succeeded. E.g., the `lseek' system call + might return a large offset. Therefore we must not anymore test + for < 0, but test for a real error by making sure the value in %eax + is a real error number. Linus said he will make sure the no syscall + returns a value in -1 .. -4095 as a valid result so we can savely + test with -4095. */ + +/* We don't want the label for the error handle to be global when we define + it here. */ +# ifdef __PIC__ +# define SYSCALL_ERROR_LABEL 0f +# else +# define SYSCALL_ERROR_LABEL syscall_error +# endif + +# undef PSEUDO +# define PSEUDO(name, syscall_name, args) \ + .text; \ + ENTRY (name) \ + DO_CALL (syscall_name, args); \ + cmpq $-4095, %rax; \ + jae SYSCALL_ERROR_LABEL; \ + L(pseudo_end): + +# undef PSEUDO_END +# define PSEUDO_END(name) \ + SYSCALL_ERROR_HANDLER \ + END (name) + +# undef PSEUDO_NOERRNO +# define PSEUDO_NOERRNO(name, syscall_name, args) \ + .text; \ + ENTRY (name) \ + DO_CALL (syscall_name, args) + +# undef PSEUDO_END_NOERRNO +# define PSEUDO_END_NOERRNO(name) \ + END (name) + +# define ret_NOERRNO ret + +# undef PSEUDO_ERRVAL +# define PSEUDO_ERRVAL(name, syscall_name, args) \ + .text; \ + ENTRY (name) \ + DO_CALL (syscall_name, args); \ + negq %rax + +# undef PSEUDO_END_ERRVAL +# define PSEUDO_END_ERRVAL(name) \ + END (name) + +# define ret_ERRVAL ret + +# ifndef __PIC__ +# define SYSCALL_ERROR_HANDLER /* Nothing here; code in sysdep.S is used. */ +# elif defined(RTLD_PRIVATE_ERRNO) +# define SYSCALL_ERROR_HANDLER \ +0: \ + leaq rtld_errno(%rip), %rcx; \ + xorl %edx, %edx; \ + subq %rax, %rdx; \ + movl %edx, (%rcx); \ + orq $-1, %rax; \ + jmp L(pseudo_end); +# elif USE___THREAD +# ifndef NOT_IN_libc +# define SYSCALL_ERROR_ERRNO __libc_errno +# else +# define SYSCALL_ERROR_ERRNO errno +# endif +# define SYSCALL_ERROR_HANDLER \ +0: \ + movq SYSCALL_ERROR_ERRNO@GOTTPOFF(%rip), %rcx;\ + xorl %edx, %edx; \ + subq %rax, %rdx; \ + movl %edx, %fs:(%rcx); \ + orq $-1, %rax; \ + jmp L(pseudo_end); +# elif defined _LIBC_REENTRANT +/* Store (- %rax) into errno through the GOT. + Note that errno occupies only 4 bytes. */ +# define SYSCALL_ERROR_HANDLER \ +0: \ + xorl %edx, %edx; \ + subq %rax, %rdx; \ + pushq %rdx; \ + cfi_adjust_cfa_offset(8); \ + call __errno_location@PLT; \ + popq %rdx; \ + cfi_adjust_cfa_offset(-8); \ + movl %edx, (%rax); \ + orq $-1, %rax; \ + jmp L(pseudo_end); + +/* A quick note: it is assumed that the call to `__errno_location' does + not modify the stack! */ +# else /* Not _LIBC_REENTRANT. */ +# define SYSCALL_ERROR_HANDLER \ +0:movq errno@GOTPCREL(%RIP), %rcx; \ + xorl %edx, %edx; \ + subq %rax, %rdx; \ + movl %edx, (%rcx); \ + orq $-1, %rax; \ + jmp L(pseudo_end); +# endif /* __PIC__ */ + +/* The Linux/x86-64 kernel expects the system call parameters in + registers according to the following table: + + syscall number rax + arg 1 rdi + arg 2 rsi + arg 3 rdx + arg 4 r10 + arg 5 r8 + arg 6 r9 + + The Linux kernel uses and destroys internally these registers: + return address from + syscall rcx + eflags from syscall r11 + + Normal function call, including calls to the system call stub + functions in the libc, get the first six parameters passed in + registers and the seventh parameter and later on the stack. The + register use is as follows: + + system call number in the DO_CALL macro + arg 1 rdi + arg 2 rsi + arg 3 rdx + arg 4 rcx + arg 5 r8 + arg 6 r9 + + We have to take care that the stack is aligned to 16 bytes. When + called the stack is not aligned since the return address has just + been pushed. + + + Syscalls of more than 6 arguments are not supported. */ + +# undef DO_CALL +# define DO_CALL(syscall_name, args) \ + DOARGS_##args \ + movl $SYS_ify (syscall_name), %eax; \ + syscall; + +# define DOARGS_0 /* nothing */ +# define DOARGS_1 /* nothing */ +# define DOARGS_2 /* nothing */ +# define DOARGS_3 /* nothing */ +# define DOARGS_4 movq %rcx, %r10; +# define DOARGS_5 DOARGS_4 +# define DOARGS_6 DOARGS_5 + +#endif /* __ASSEMBLER__ */ + + +/* Pointer mangling support. */ +#if defined NOT_IN_libc && defined IS_IN_rtld +/* We cannot use the thread descriptor because in ld.so we use setjmp + earlier than the descriptor is initialized. */ +# ifdef __ASSEMBLER__ +# define PTR_MANGLE(reg) xorq __pointer_chk_guard_local(%rip), reg; \ + rolq $17, reg +# define PTR_DEMANGLE(reg) rorq $17, reg; \ + xorq __pointer_chk_guard_local(%rip), reg +# else +# define PTR_MANGLE(reg) asm ("xorq __pointer_chk_guard_local(%%rip), %0\n" \ + "rolq $17, %0" \ + : "=r" (reg) : "0" (reg)) +# define PTR_DEMANGLE(reg) asm ("rorq $17, %0\n" \ + "xorq __pointer_chk_guard_local(%%rip), %0" \ + : "=r" (reg) : "0" (reg)) +# endif +#else +# ifdef __ASSEMBLER__ +# define PTR_MANGLE(reg) xorq %fs:POINTER_GUARD, reg; \ + rolq $17, reg +# define PTR_DEMANGLE(reg) rorq $17, reg; \ + xorq %fs:POINTER_GUARD, reg +# else +# define PTR_MANGLE(var) asm ("xorq %%fs:%c2, %0\n" \ + "rolq $17, %0" \ + : "=r" (var) \ + : "0" (var), \ + "i" (offsetof (tcbhead_t, \ + pointer_guard))) +# define PTR_DEMANGLE(var) asm ("rorq $17, %0\n" \ + "xorq %%fs:%c2, %0" \ + : "=r" (var) \ + : "0" (var), \ + "i" (offsetof (tcbhead_t, \ + pointer_guard))) +# endif +#endif + +#endif /* linux/x86_64/sysdep.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/vfork.S new file mode 100644 index 000000000..9a9912ca8 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/vfork.S @@ -0,0 +1,43 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* We want an #include_next, but we are the main source file. + So, #include ourselves and in that incarnation we can use #include_next. */ +#ifndef INCLUDED_SELF +# define INCLUDED_SELF +# include <vfork.S> +#else + +# include <tcb-offsets.h> + +# define SAVE_PID \ + movl %fs:PID, %esi; \ + movl $0x80000000, %ecx; \ + movl %esi, %edx; \ + negl %edx; \ + cmove %ecx, %edx; \ + movl %edx, %fs:PID + +# define RESTORE_PID \ + testq %rax, %rax; \ + je 1f; \ + movl %esi, %fs:PID; \ +1: + +# include_next <vfork.S> +#endif diff --git a/libpthread/nptl/sysdeps/x86_64/Makefile b/libpthread/nptl/sysdeps/x86_64/Makefile new file mode 100644 index 000000000..2f0d88f30 --- /dev/null +++ b/libpthread/nptl/sysdeps/x86_64/Makefile @@ -0,0 +1,27 @@ +# Copyright (C) 2002, 2003 Free Software Foundation, Inc. +# This file is part of the GNU C Library. + +# The GNU C Library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. + +# The GNU C Library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. + +# You should have received a copy of the GNU Lesser General Public +# License along with the GNU C Library; if not, write to the Free +# Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +# 02111-1307 USA. + +ifeq ($(subdir),csu) +gen-as-const-headers += tcb-offsets.sym +endif + +ifeq ($(subdir),nptl) +CFLAGS-pthread_create.c += -mpreferred-stack-boundary=4 +CFLAGS-tst-align.c += -mpreferred-stack-boundary=4 +CFLAGS-tst-align2.c += -mpreferred-stack-boundary=4 +endif diff --git a/libpthread/nptl/sysdeps/x86_64/Makefile.arch b/libpthread/nptl/sysdeps/x86_64/Makefile.arch new file mode 100644 index 000000000..c1d683fac --- /dev/null +++ b/libpthread/nptl/sysdeps/x86_64/Makefile.arch @@ -0,0 +1,53 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2005 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +libpthread_CSRC = pthread_spin_lock.c +libpthread_SSRC = pthread_spin_trylock.S + +CFLAGS-pthread_spin_lock.c += -D_GNU_SOURCE + +CFLAGS-x86_64 = $(SSP_ALL_CFLAGS) +#CFLAGS:=$(CFLAGS:-O1=-O2) + +PTHREAD_ARCH_DIR := $(top_srcdir)libpthread/nptl/sysdeps/x86_64 +PTHREAD_ARCH_OUT := $(top_builddir)libpthread/nptl/sysdeps/x86_64 +PTHREAD_ARCH_OBJ := $(patsubst %.S,$(PTHREAD_ARCH_OUT)/%.o,$(libpthread_SSRC)) +PTHREAD_ARCH_OBJ += $(patsubst %.c,$(PTHREAD_ARCH_OUT)/%.o,$(libpthread_CSRC)) + +ifeq ($(DOPIC),y) +libpthread-a-y += $(PTHREAD_ARCH_OBJ:.o=.os) +else +libpthread-a-y += $(PTHREAD_ARCH_OBJ) +endif +libpthread-so-y += $(PTHREAD_ARCH_OBJ:.o=.oS) + +libpthread-nomulti-y += $(PTHREAD_ARCH_OBJ) + +objclean-y += nptl_arch_clean +headers_clean-y += nptl_arch_headers_clean + +# +# Create 'tcb-offsets.h' header file. +# +CFLAGS-tcb-offsets.c = -S + +$(PTHREAD_ARCH_OUT)/tcb-offsets.c: $(PTHREAD_ARCH_DIR)/tcb-offsets.sym + $(do_awk) $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@ + +$(PTHREAD_ARCH_OUT)/tcb-offsets.s: $(PTHREAD_ARCH_OUT)/tcb-offsets.c + $(compile.c) + +$(PTHREAD_ARCH_OUT)/tcb-offsets.h: $(PTHREAD_ARCH_OUT)/tcb-offsets.s + @sed -n "s/^.*@@@name@@@\([^@]*\)@@@value@@@[^0-9Xxa-fA-F-]*\([0-9Xxa-fA-F-][0-9Xxa-fA-F-]*\).*@@@end@@@.*$\/#define \1 \2/p" $< > $@ + +nptl_arch_headers: $(PTHREAD_ARCH_OUT)/tcb-offsets.h + +nptl_arch_headers_clean: + $(do_rm) $(addprefix $(PTHREAD_ARCH_OUT)/tcb-offsets., c s h) + +nptl_arch_clean: + $(do_rm) $(addprefix $(PTHREAD_ARCH_OUT)/*., o os oS) diff --git a/libpthread/nptl/sysdeps/x86_64/dl-tls.h b/libpthread/nptl/sysdeps/x86_64/dl-tls.h new file mode 100644 index 000000000..3e4768dc1 --- /dev/null +++ b/libpthread/nptl/sysdeps/x86_64/dl-tls.h @@ -0,0 +1,29 @@ +/* Thread-local storage handling in the ELF dynamic linker. x86-64 version. + Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + + +/* Type used for the representation of TLS information in the GOT. */ +typedef struct +{ + unsigned long int ti_module; + unsigned long int ti_offset; +} tls_index; + + +extern void *__tls_get_addr (tls_index *ti); diff --git a/libpthread/nptl/sysdeps/x86_64/jmpbuf-unwind.h b/libpthread/nptl/sysdeps/x86_64/jmpbuf-unwind.h new file mode 100644 index 000000000..345ed557c --- /dev/null +++ b/libpthread/nptl/sysdeps/x86_64/jmpbuf-unwind.h @@ -0,0 +1,31 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <setjmp.h> +#include <stdint.h> +#include <unwind.h> + +#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \ + _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj) + +#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \ + ((uintptr_t) (_address) - (_adj) < (uintptr_t) (_jmpbuf)[JB_RSP] - (_adj)) + +/* We use the normal lobngjmp for unwinding. */ +#define __libc_unwind_longjmp(buf, val) __libc_longjmp (buf, val) diff --git a/libpthread/nptl/sysdeps/x86_64/pthread_spin_init.c b/libpthread/nptl/sysdeps/x86_64/pthread_spin_init.c new file mode 100644 index 000000000..55696204c --- /dev/null +++ b/libpthread/nptl/sysdeps/x86_64/pthread_spin_init.c @@ -0,0 +1 @@ +#include "../i386/pthread_spin_init.c" diff --git a/libpthread/nptl/sysdeps/x86_64/pthread_spin_lock.c b/libpthread/nptl/sysdeps/x86_64/pthread_spin_lock.c new file mode 100644 index 000000000..7cf0e0ecc --- /dev/null +++ b/libpthread/nptl/sysdeps/x86_64/pthread_spin_lock.c @@ -0,0 +1 @@ +#include "../i386/pthread_spin_lock.c" diff --git a/libpthread/nptl/sysdeps/x86_64/pthread_spin_trylock.S b/libpthread/nptl/sysdeps/x86_64/pthread_spin_trylock.S new file mode 100644 index 000000000..9b5133583 --- /dev/null +++ b/libpthread/nptl/sysdeps/x86_64/pthread_spin_trylock.S @@ -0,0 +1,40 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread-errnos.h> + + +#ifdef UP +# define LOCK +#else +# define LOCK lock +#endif + + .globl pthread_spin_trylock + .type pthread_spin_trylock,@function + .align 16 +pthread_spin_trylock: + movl $1, %eax + xorl %ecx, %ecx + LOCK + cmpxchgl %ecx, (%rdi) + movl $EBUSY, %eax + cmovel %ecx, %eax + retq + .size pthread_spin_trylock,.-pthread_spin_trylock diff --git a/libpthread/nptl/sysdeps/x86_64/pthread_spin_unlock.S b/libpthread/nptl/sysdeps/x86_64/pthread_spin_unlock.S new file mode 100644 index 000000000..d3e13bde9 --- /dev/null +++ b/libpthread/nptl/sysdeps/x86_64/pthread_spin_unlock.S @@ -0,0 +1,31 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + + .globl pthread_spin_unlock + .type pthread_spin_unlock,@function + .align 16 +pthread_spin_unlock: + movl $1, (%rdi) + xorl %eax, %eax + retq + .size pthread_spin_unlock,.-pthread_spin_unlock + + /* The implementation of pthread_spin_init is identical. */ + .globl pthread_spin_init +pthread_spin_init = pthread_spin_unlock diff --git a/libpthread/nptl/sysdeps/x86_64/pthreaddef.h b/libpthread/nptl/sysdeps/x86_64/pthreaddef.h new file mode 100644 index 000000000..b33c18638 --- /dev/null +++ b/libpthread/nptl/sysdeps/x86_64/pthreaddef.h @@ -0,0 +1,43 @@ +/* Copyright (C) 2002, 2003, 2007 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* Default stack size. */ +#define ARCH_STACK_DEFAULT_SIZE (2 * 1024 * 1024) + +/* Required stack pointer alignment at beginning. SSE requires 16 + bytes. */ +#define STACK_ALIGN 16 + +/* Minimal stack size after allocating thread descriptor and guard size. */ +#define MINIMAL_REST_STACK 2048 + +/* Alignment requirement for TCB. */ +#define TCB_ALIGNMENT 16 + + +/* Location of current stack frame. The frame pointer is not usable. */ +#define CURRENT_STACK_FRAME \ + ({ char *frame; __asm__ ("movq %%rsp, %0" : "=r" (frame)); frame; }) + + +/* XXX Until we have a better place keep the definitions here. */ + +/* While there is no such syscall. */ +#define __exit_thread_inline(val) \ + __asm__ volatile ("syscall" :: "a" (__NR_exit), "D" (val)) diff --git a/libpthread/nptl/sysdeps/x86_64/sysdep.h b/libpthread/nptl/sysdeps/x86_64/sysdep.h new file mode 100644 index 000000000..ac74b7c23 --- /dev/null +++ b/libpthread/nptl/sysdeps/x86_64/sysdep.h @@ -0,0 +1,114 @@ +/* Assembler macros for x86-64. + Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdeps/generic/sysdep.h> + +#ifdef __ASSEMBLER__ + +/* Syntactic details of assembler. */ + +#ifdef HAVE_ELF + +/* ELF uses byte-counts for .align, most others use log2 of count of bytes. */ +#define ALIGNARG(log2) 1<<log2 +/* For ELF we need the `.type' directive to make shared libs work right. */ +#define ASM_TYPE_DIRECTIVE(name,typearg) .type name,typearg; +#define ASM_SIZE_DIRECTIVE(name) .size name,.-name; + +/* In ELF C symbols are asm symbols. */ +#undef NO_UNDERSCORES +#define NO_UNDERSCORES + +#else + +#define ALIGNARG(log2) log2 +#define ASM_TYPE_DIRECTIVE(name,type) /* Nothing is specified. */ +#define ASM_SIZE_DIRECTIVE(name) /* Nothing is specified. */ + +#endif + + +/* Define an entry point visible from C. */ +#define ENTRY(name) \ + ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(name); \ + ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name),@function) \ + .align ALIGNARG(4); \ + C_LABEL(name) \ + cfi_startproc; \ + CALL_MCOUNT + +#undef END +#define END(name) \ + cfi_endproc; \ + ASM_SIZE_DIRECTIVE(name) + +/* If compiled for profiling, call `mcount' at the start of each function. */ +#ifdef PROF +/* The mcount code relies on a normal frame pointer being on the stack + to locate our caller, so push one just for its benefit. */ +#define CALL_MCOUNT \ + pushq %rbp; \ + cfi_adjust_cfa_offset(8); \ + movq %rsp, %rbp; \ + cfi_def_cfa_register(%rbp); \ + call JUMPTARGET(mcount); \ + popq %rbp; \ + cfi_def_cfa(rsp,8); +#else +#define CALL_MCOUNT /* Do nothing. */ +#endif + +#ifdef NO_UNDERSCORES +/* Since C identifiers are not normally prefixed with an underscore + on this system, the asm identifier `syscall_error' intrudes on the + C name space. Make sure we use an innocuous name. */ +#define syscall_error __syscall_error +#define mcount _mcount +#endif + +#define PSEUDO(name, syscall_name, args) \ +lose: \ + jmp JUMPTARGET(syscall_error) \ + .globl syscall_error; \ + ENTRY (name) \ + DO_CALL (syscall_name, args); \ + jb lose + +#undef PSEUDO_END +#define PSEUDO_END(name) \ + END (name) + +#undef JUMPTARGET +#ifdef __PIC__ +#define JUMPTARGET(name) name##@PLT +#else +#define JUMPTARGET(name) name +#endif + +/* Local label name for asm code. */ +#ifndef L +# ifdef HAVE_ELF +/* ELF-like local names start with `.L'. */ +# define L(name) .L##name +# else +# define L(name) name +# endif +#endif + +#endif /* __ASSEMBLER__ */ diff --git a/libpthread/nptl/sysdeps/x86_64/tcb-offsets.sym b/libpthread/nptl/sysdeps/x86_64/tcb-offsets.sym new file mode 100644 index 000000000..8118d2df8 --- /dev/null +++ b/libpthread/nptl/sysdeps/x86_64/tcb-offsets.sym @@ -0,0 +1,12 @@ +#include <sysdep.h> +#include <tls.h> + +RESULT offsetof (struct pthread, result) +TID offsetof (struct pthread, tid) +PID offsetof (struct pthread, pid) +CANCELHANDLING offsetof (struct pthread, cancelhandling) +CLEANUP_JMP_BUF offsetof (struct pthread, cleanup_jmp_buf) +CLEANUP offsetof (struct pthread, cleanup) +CLEANUP_PREV offsetof (struct _pthread_cleanup_buffer, __prev) +MUTEX_FUTEX offsetof (pthread_mutex_t, __data.__lock) +MULTIPLE_THREADS_OFFSET offsetof (tcbhead_t, multiple_threads) diff --git a/libpthread/nptl/sysdeps/x86_64/tls.h b/libpthread/nptl/sysdeps/x86_64/tls.h new file mode 100644 index 000000000..7b40e3d57 --- /dev/null +++ b/libpthread/nptl/sysdeps/x86_64/tls.h @@ -0,0 +1,437 @@ +/* Definition for thread-local data handling. nptl/x86_64 version. + Copyright (C) 2002-2007, 2008, 2009 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _TLS_H +#define _TLS_H 1 + +#ifndef __ASSEMBLER__ +# include <asm/prctl.h> /* For ARCH_SET_FS. */ +# include <stdbool.h> +# include <stddef.h> +# include <stdint.h> +# include <stdlib.h> +# include <sysdep.h> +# include <bits/wordsize.h> +# include <xmmintrin.h> + + +/* Type for the dtv. */ +typedef union dtv +{ + size_t counter; + struct + { + void *val; + bool is_static; + } pointer; +} dtv_t; + + +typedef struct +{ + void *tcb; /* Pointer to the TCB. Not necessarily the + thread descriptor used by libpthread. */ + dtv_t *dtv; + void *self; /* Pointer to the thread descriptor. */ + int multiple_threads; + int gscope_flag; + uintptr_t sysinfo; + uintptr_t stack_guard; + uintptr_t pointer_guard; + unsigned long int vgetcpu_cache[2]; +# ifndef __ASSUME_PRIVATE_FUTEX + int private_futex; +# else + int __unused1; +# endif +# if __WORDSIZE == 64 + int rtld_must_xmm_save; +# endif + /* Reservation of some values for the TM ABI. */ + void *__private_tm[5]; +# if __WORDSIZE == 64 + long int __unused2; + /* Have space for the post-AVX register size. */ + __m128 rtld_savespace_sse[8][4]; + + void *__padding[8]; +# endif +} tcbhead_t; + +#else /* __ASSEMBLER__ */ +# include <tcb-offsets.h> +#endif + + +/* We require TLS support in the tools. */ +#define HAVE_TLS_SUPPORT 1 +#define HAVE___THREAD 1 +#define HAVE_TLS_MODEL_ATTRIBUTE 1 + +/* Signal that TLS support is available. */ +#define USE_TLS 1 + +/* Alignment requirement for the stack. */ +#define STACK_ALIGN 16 + + +#ifndef __ASSEMBLER__ +/* Get system call information. */ +# include <sysdep.h> + + +/* Get the thread descriptor definition. */ +# include <descr.h> + +#ifndef LOCK_PREFIX +# ifdef UP +# define LOCK_PREFIX /* nothing */ +# else +# define LOCK_PREFIX "lock;" +# endif +#endif + +/* This is the size of the initial TCB. Can't be just sizeof (tcbhead_t), + because NPTL getpid, __libc_alloca_cutoff etc. need (almost) the whole + struct pthread even when not linked with -lpthread. */ +# define TLS_INIT_TCB_SIZE sizeof (struct pthread) + +/* Alignment requirements for the initial TCB. */ +# define TLS_INIT_TCB_ALIGN __alignof__ (struct pthread) + +/* This is the size of the TCB. */ +# define TLS_TCB_SIZE sizeof (struct pthread) + +/* Alignment requirements for the TCB. */ +//# define TLS_TCB_ALIGN __alignof__ (struct pthread) +// Normally the above would be correct But we have to store post-AVX +// vector registers in the TCB and we want the storage to be aligned. +// unfortunately there isn't yet a type for these values and hence no +// 32-byte alignment requirement. Make this explicit, for now. +# define TLS_TCB_ALIGN 32 + +/* The TCB can have any size and the memory following the address the + thread pointer points to is unspecified. Allocate the TCB there. */ +# define TLS_TCB_AT_TP 1 + + +/* Install the dtv pointer. The pointer passed is to the element with + index -1 which contain the length. */ +# define INSTALL_DTV(descr, dtvp) \ + ((tcbhead_t *) (descr))->dtv = (dtvp) + 1 + +/* Install new dtv for current thread. */ +# define INSTALL_NEW_DTV(dtvp) \ + ({ struct pthread *__pd; \ + THREAD_SETMEM (__pd, header.dtv, (dtvp)); }) + +/* Return dtv of given thread descriptor. */ +# define GET_DTV(descr) \ + (((tcbhead_t *) (descr))->dtv) + + +/* Macros to load from and store into segment registers. */ +# define TLS_GET_FS() \ + ({ int __seg; __asm__ ("movl %%fs, %0" : "=q" (__seg)); __seg; }) +# define TLS_SET_FS(val) \ + __asm__ ("movl %0, %%fs" :: "q" (val)) + + +/* Code to initially initialize the thread pointer. This might need + special attention since 'errno' is not yet available and if the + operation can cause a failure 'errno' must not be touched. + + We have to make the syscall for both uses of the macro since the + address might be (and probably is) different. */ +# define TLS_INIT_TP(thrdescr, secondcall) \ + ({ void *_thrdescr = (thrdescr); \ + tcbhead_t *_head = _thrdescr; \ + int _result; \ + \ + _head->tcb = _thrdescr; \ + /* For now the thread descriptor is at the same address. */ \ + _head->self = _thrdescr; \ + \ + /* It is a simple syscall to set the %fs value for the thread. */ \ + __asm__ volatile ("syscall" \ + : "=a" (_result) \ + : "0" ((unsigned long int) __NR_arch_prctl), \ + "D" ((unsigned long int) ARCH_SET_FS), \ + "S" (_thrdescr) \ + : "memory", "cc", "r11", "cx"); \ + \ + _result ? "cannot set %fs base address for thread-local storage" : 0; \ + }) + + +/* Return the address of the dtv for the current thread. */ +# define THREAD_DTV() \ + ({ struct pthread *__pd; \ + THREAD_GETMEM (__pd, header.dtv); }) + + +/* Return the thread descriptor for the current thread. + + The contained asm must *not* be marked volatile since otherwise + assignments like + pthread_descr self = thread_self(); + do not get optimized away. */ +# define THREAD_SELF \ + ({ struct pthread *__self; \ + __asm__ ("movq %%fs:%c1,%q0" : "=r" (__self) \ + : "i" (offsetof (struct pthread, header.self))); \ + __self;}) + +/* Magic for libthread_db to know how to do THREAD_SELF. */ +# define DB_THREAD_SELF_INCLUDE <sys/reg.h> /* For the FS constant. */ +# define DB_THREAD_SELF CONST_THREAD_AREA (64, FS) + +/* Read member of the thread descriptor directly. */ +# define THREAD_GETMEM(descr, member) \ + ({ __typeof (descr->member) __value; \ + if (sizeof (__value) == 1) \ + __asm__ volatile ("movb %%fs:%P2,%b0" \ + : "=q" (__value) \ + : "0" (0), "i" (offsetof (struct pthread, member))); \ + else if (sizeof (__value) == 4) \ + __asm__ volatile ("movl %%fs:%P1,%0" \ + : "=r" (__value) \ + : "i" (offsetof (struct pthread, member))); \ + else \ + { \ + if (sizeof (__value) != 8) \ + /* There should not be any value with a size other than 1, \ + 4 or 8. */ \ + abort (); \ + \ + __asm__ volatile ("movq %%fs:%P1,%q0" \ + : "=r" (__value) \ + : "i" (offsetof (struct pthread, member))); \ + } \ + __value; }) + + +/* Same as THREAD_GETMEM, but the member offset can be non-constant. */ +# define THREAD_GETMEM_NC(descr, member, idx) \ + ({ __typeof (descr->member[0]) __value; \ + if (sizeof (__value) == 1) \ + __asm__ volatile ("movb %%fs:%P2(%q3),%b0" \ + : "=q" (__value) \ + : "0" (0), "i" (offsetof (struct pthread, member[0])), \ + "r" (idx)); \ + else if (sizeof (__value) == 4) \ + __asm__ volatile ("movl %%fs:%P1(,%q2,4),%0" \ + : "=r" (__value) \ + : "i" (offsetof (struct pthread, member[0])), "r" (idx));\ + else \ + { \ + if (sizeof (__value) != 8) \ + /* There should not be any value with a size other than 1, \ + 4 or 8. */ \ + abort (); \ + \ + __asm__ volatile ("movq %%fs:%P1(,%q2,8),%q0" \ + : "=r" (__value) \ + : "i" (offsetof (struct pthread, member[0])), \ + "r" (idx)); \ + } \ + __value; }) + + +/* Loading addresses of objects on x86-64 needs to be treated special + when generating PIC code. */ +#ifdef __pic__ +# define IMM_MODE "nr" +#else +# define IMM_MODE "ir" +#endif + + +/* Same as THREAD_SETMEM, but the member offset can be non-constant. */ +# define THREAD_SETMEM(descr, member, value) \ + ({ if (sizeof (descr->member) == 1) \ + __asm__ volatile ("movb %b0,%%fs:%P1" : \ + : "iq" (value), \ + "i" (offsetof (struct pthread, member))); \ + else if (sizeof (descr->member) == 4) \ + __asm__ volatile ("movl %0,%%fs:%P1" : \ + : IMM_MODE (value), \ + "i" (offsetof (struct pthread, member))); \ + else \ + { \ + if (sizeof (descr->member) != 8) \ + /* There should not be any value with a size other than 1, \ + 4 or 8. */ \ + abort (); \ + \ + __asm__ volatile ("movq %q0,%%fs:%P1" : \ + : IMM_MODE ((unsigned long int) value), \ + "i" (offsetof (struct pthread, member))); \ + }}) + + +/* Set member of the thread descriptor directly. */ +# define THREAD_SETMEM_NC(descr, member, idx, value) \ + ({ if (sizeof (descr->member[0]) == 1) \ + __asm__ volatile ("movb %b0,%%fs:%P1(%q2)" : \ + : "iq" (value), \ + "i" (offsetof (struct pthread, member[0])), \ + "r" (idx)); \ + else if (sizeof (descr->member[0]) == 4) \ + __asm__ volatile ("movl %0,%%fs:%P1(,%q2,4)" : \ + : IMM_MODE (value), \ + "i" (offsetof (struct pthread, member[0])), \ + "r" (idx)); \ + else \ + { \ + if (sizeof (descr->member[0]) != 8) \ + /* There should not be any value with a size other than 1, \ + 4 or 8. */ \ + abort (); \ + \ + __asm__ volatile ("movq %q0,%%fs:%P1(,%q2,8)" : \ + : IMM_MODE ((unsigned long int) value), \ + "i" (offsetof (struct pthread, member[0])), \ + "r" (idx)); \ + }}) + + +/* Atomic compare and exchange on TLS, returning old value. */ +# define THREAD_ATOMIC_CMPXCHG_VAL(descr, member, newval, oldval) \ + ({ __typeof (descr->member) __ret; \ + __typeof (oldval) __old = (oldval); \ + if (sizeof (descr->member) == 4) \ + __asm__ volatile (LOCK_PREFIX "cmpxchgl %2, %%fs:%P3" \ + : "=a" (__ret) \ + : "0" (__old), "r" (newval), \ + "i" (offsetof (struct pthread, member))); \ + else \ + /* Not necessary for other sizes in the moment. */ \ + abort (); \ + __ret; }) + + +/* Atomic logical and. */ +# define THREAD_ATOMIC_AND(descr, member, val) \ + (void) ({ if (sizeof ((descr)->member) == 4) \ + __asm__ volatile (LOCK_PREFIX "andl %1, %%fs:%P0" \ + :: "i" (offsetof (struct pthread, member)), \ + "ir" (val)); \ + else \ + /* Not necessary for other sizes in the moment. */ \ + abort (); }) + + +/* Atomic set bit. */ +# define THREAD_ATOMIC_BIT_SET(descr, member, bit) \ + (void) ({ if (sizeof ((descr)->member) == 4) \ + __asm__ volatile (LOCK_PREFIX "orl %1, %%fs:%P0" \ + :: "i" (offsetof (struct pthread, member)), \ + "ir" (1 << (bit))); \ + else \ + /* Not necessary for other sizes in the moment. */ \ + abort (); }) + + +# define CALL_THREAD_FCT(descr) \ + ({ void *__res; \ + __asm__ volatile ("movq %%fs:%P2, %%rdi\n\t" \ + "callq *%%fs:%P1" \ + : "=a" (__res) \ + : "i" (offsetof (struct pthread, start_routine)), \ + "i" (offsetof (struct pthread, arg)) \ + : "di", "si", "cx", "dx", "r8", "r9", "r10", "r11", \ + "memory", "cc"); \ + __res; }) + + +/* Set the stack guard field in TCB head. */ +# define THREAD_SET_STACK_GUARD(value) \ + THREAD_SETMEM (THREAD_SELF, header.stack_guard, value) +# define THREAD_COPY_STACK_GUARD(descr) \ + ((descr)->header.stack_guard \ + = THREAD_GETMEM (THREAD_SELF, header.stack_guard)) + + +/* Set the pointer guard field in the TCB head. */ +# define THREAD_SET_POINTER_GUARD(value) \ + THREAD_SETMEM (THREAD_SELF, header.pointer_guard, value) +# define THREAD_COPY_POINTER_GUARD(descr) \ + ((descr)->header.pointer_guard \ + = THREAD_GETMEM (THREAD_SELF, header.pointer_guard)) + + +/* Get and set the global scope generation counter in the TCB head. */ +# define THREAD_GSCOPE_FLAG_UNUSED 0 +# define THREAD_GSCOPE_FLAG_USED 1 +# define THREAD_GSCOPE_FLAG_WAIT 2 +# define THREAD_GSCOPE_RESET_FLAG() \ + do \ + { int __res; \ + __asm__ volatile ("xchgl %0, %%fs:%P1" \ + : "=r" (__res) \ + : "i" (offsetof (struct pthread, header.gscope_flag)), \ + "0" (THREAD_GSCOPE_FLAG_UNUSED)); \ + if (__res == THREAD_GSCOPE_FLAG_WAIT) \ + lll_futex_wake (&THREAD_SELF->header.gscope_flag, 1, LLL_PRIVATE); \ + } \ + while (0) +# define THREAD_GSCOPE_SET_FLAG() \ + THREAD_SETMEM (THREAD_SELF, header.gscope_flag, THREAD_GSCOPE_FLAG_USED) +# define THREAD_GSCOPE_WAIT() \ + GL(dl_wait_lookup_done) () + + +# ifdef SHARED +/* Defined in dl-trampoline.S. */ +extern void _dl_x86_64_save_sse (void); +extern void _dl_x86_64_restore_sse (void); + +# define RTLD_CHECK_FOREIGN_CALL \ + (THREAD_GETMEM (THREAD_SELF, header.rtld_must_xmm_save) != 0) + +/* NB: Don't use the xchg operation because that would imply a lock + prefix which is expensive and unnecessary. The cache line is also + not contested at all. */ +# define RTLD_ENABLE_FOREIGN_CALL \ + int old_rtld_must_xmm_save = THREAD_GETMEM (THREAD_SELF, \ + header.rtld_must_xmm_save); \ + THREAD_SETMEM (THREAD_SELF, header.rtld_must_xmm_save, 1) + +# define RTLD_PREPARE_FOREIGN_CALL \ + do if (THREAD_GETMEM (THREAD_SELF, header.rtld_must_xmm_save)) \ + { \ + _dl_x86_64_save_sse (); \ + THREAD_SETMEM (THREAD_SELF, header.rtld_must_xmm_save, 0); \ + } \ + while (0) + +# define RTLD_FINALIZE_FOREIGN_CALL \ + do { \ + if (THREAD_GETMEM (THREAD_SELF, header.rtld_must_xmm_save) == 0) \ + _dl_x86_64_restore_sse (); \ + THREAD_SETMEM (THREAD_SELF, header.rtld_must_xmm_save, \ + old_rtld_must_xmm_save); \ + } while (0) +# endif + + +#endif /* __ASSEMBLER__ */ + +#endif /* tls.h */ diff --git a/libpthread/nptl/unwind.c b/libpthread/nptl/unwind.c new file mode 100644 index 000000000..56a423815 --- /dev/null +++ b/libpthread/nptl/unwind.c @@ -0,0 +1,176 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com> + and Richard Henderson <rth@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <setjmp.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "pthreadP.h" +#include "jmpbuf-unwind.h" + +#ifdef HAVE_FORCED_UNWIND + +#ifdef _STACK_GROWS_DOWN +# define FRAME_LEFT(frame, other, adj) \ + ((uintptr_t) frame - adj >= (uintptr_t) other - adj) +#elif _STACK_GROWS_UP +# define FRAME_LEFT(frame, other, adj) \ + ((uintptr_t) frame - adj <= (uintptr_t) other - adj) +#else +# error "Define either _STACK_GROWS_DOWN or _STACK_GROWS_UP" +#endif + +static _Unwind_Reason_Code +unwind_stop (int version, _Unwind_Action actions, + _Unwind_Exception_Class exc_class, + struct _Unwind_Exception *exc_obj, + struct _Unwind_Context *context, void *stop_parameter) +{ + struct pthread_unwind_buf *buf = stop_parameter; + struct pthread *self = THREAD_SELF; + struct _pthread_cleanup_buffer *curp = THREAD_GETMEM (self, cleanup); + int do_longjump = 0; + + /* Adjust all pointers used in comparisons, so that top of thread's + stack is at the top of address space. Without that, things break + if stack is allocated above the main stack. */ + uintptr_t adj = (uintptr_t) self->stackblock + self->stackblock_size; + + /* Do longjmp if we're at "end of stack", aka "end of unwind data". + We assume there are only C frame without unwind data in between + here and the jmp_buf target. Otherwise simply note that the CFA + of a function is NOT within it's stack frame; it's the SP of the + previous frame. */ + if ((actions & _UA_END_OF_STACK) + || ! _JMPBUF_CFA_UNWINDS_ADJ (buf->cancel_jmp_buf[0].jmp_buf, context, + adj)) + do_longjump = 1; + + if (__builtin_expect (curp != NULL, 0)) + { + /* Handle the compatibility stuff. Execute all handlers + registered with the old method which would be unwound by this + step. */ + struct _pthread_cleanup_buffer *oldp = buf->priv.data.cleanup; + void *cfa = (void *) _Unwind_GetCFA (context); + + if (curp != oldp && (do_longjump || FRAME_LEFT (cfa, curp, adj))) + { + do + { + /* Pointer to the next element. */ + struct _pthread_cleanup_buffer *nextp = curp->__prev; + + /* Call the handler. */ + curp->__routine (curp->__arg); + + /* To the next. */ + curp = nextp; + } + while (curp != oldp + && (do_longjump || FRAME_LEFT (cfa, curp, adj))); + + /* Mark the current element as handled. */ + THREAD_SETMEM (self, cleanup, curp); + } + } + + if (do_longjump) + __libc_unwind_longjmp ((struct __jmp_buf_tag *) buf->cancel_jmp_buf, 1); + + return _URC_NO_REASON; +} + + +static void +unwind_cleanup (_Unwind_Reason_Code reason, struct _Unwind_Exception *exc) +{ + /* When we get here a C++ catch block didn't rethrow the object. We + cannot handle this case and therefore abort. */ +# define STR_N_LEN(str) str, strlen (str) + INTERNAL_SYSCALL_DECL (err); + INTERNAL_SYSCALL (write, err, 3, STDERR_FILENO, + STR_N_LEN ("FATAL: exception not rethrown\n")); + abort (); +} + +#endif /* have forced unwind */ + + +void +__cleanup_fct_attribute __attribute ((noreturn)) +__pthread_unwind (__pthread_unwind_buf_t *buf) +{ + struct pthread_unwind_buf *ibuf = (struct pthread_unwind_buf *) buf; + struct pthread *self = THREAD_SELF; + +#ifdef HAVE_FORCED_UNWIND + /* This is not a catchable exception, so don't provide any details about + the exception type. We do need to initialize the field though. */ + THREAD_SETMEM (self, exc.exception_class, 0); + THREAD_SETMEM (self, exc.exception_cleanup, unwind_cleanup); + + _Unwind_ForcedUnwind (&self->exc, unwind_stop, ibuf); +#else + /* Handle the compatibility stuff first. Execute all handlers + registered with the old method. We don't execute them in order, + instead, they will run first. */ + struct _pthread_cleanup_buffer *oldp = ibuf->priv.data.cleanup; + struct _pthread_cleanup_buffer *curp = THREAD_GETMEM (self, cleanup); + + if (curp != oldp) + { + do + { + /* Pointer to the next element. */ + struct _pthread_cleanup_buffer *nextp = curp->__prev; + + /* Call the handler. */ + curp->__routine (curp->__arg); + + /* To the next. */ + curp = nextp; + } + while (curp != oldp); + + /* Mark the current element as handled. */ + THREAD_SETMEM (self, cleanup, curp); + } + + /* We simply jump to the registered setjmp buffer. */ + __libc_unwind_longjmp ((struct __jmp_buf_tag *) ibuf->cancel_jmp_buf, 1); +#endif + /* NOTREACHED */ + + /* We better do not get here. */ + abort (); +} +hidden_def (__pthread_unwind) + + +void +__cleanup_fct_attribute __attribute ((noreturn)) +__pthread_unwind_next (__pthread_unwind_buf_t *buf) +{ + struct pthread_unwind_buf *ibuf = (struct pthread_unwind_buf *) buf; + + __pthread_unwind ((__pthread_unwind_buf_t *) ibuf->priv.data.prev); +} +hidden_def (__pthread_unwind_next) diff --git a/libpthread/nptl/vars.c b/libpthread/nptl/vars.c new file mode 100644 index 000000000..c4306737f --- /dev/null +++ b/libpthread/nptl/vars.c @@ -0,0 +1,43 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthreadP.h> +#include <stdlib.h> +#include <tls.h> +#include <unistd.h> + +/* Default stack size. */ +size_t __default_stacksize attribute_hidden +#ifdef SHARED +; +#else + = PTHREAD_STACK_MIN; +#endif + +/* Flag whether the machine is SMP or not. */ +int __is_smp attribute_hidden; + +#ifndef TLS_MULTIPLE_THREADS_IN_TCB +/* Variable set to a nonzero value if more than one thread runs or ran. */ +int __pthread_multiple_threads attribute_hidden; +#endif + +/* Table of the key information. */ +struct pthread_key_struct __pthread_keys[PTHREAD_KEYS_MAX] + __attribute__ ((nocommon)); +hidden_def (__pthread_keys) diff --git a/libpthread/nptl/version.c b/libpthread/nptl/version.c new file mode 100644 index 000000000..f2fd25fd6 --- /dev/null +++ b/libpthread/nptl/version.c @@ -0,0 +1,45 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <unistd.h> +#include <sysdep.h> + + +static const char banner[] = +#include "banner.h" +"Copyright (C) 2003 Free Software Foundation, Inc.\n\ +This is free software; see the source for copying conditions.\n\ +There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A\n\ +PARTICULAR PURPOSE.\n" +#ifdef HAVE_FORCED_UNWIND +"Forced unwind support included.\n" +#endif +; + + +extern void __nptl_main (void) __attribute__ ((noreturn)); +void +__nptl_main (void) +{ + INTERNAL_SYSCALL_DECL (err); + INTERNAL_SYSCALL (write, err, 3, STDOUT_FILENO, (const char *) banner, + sizeof banner - 1); + + _exit (0); +} diff --git a/libpthread/nptl/version.h b/libpthread/nptl/version.h new file mode 100644 index 000000000..f294f5c97 --- /dev/null +++ b/libpthread/nptl/version.h @@ -0,0 +1 @@ +#define VERSION __stringify(__UCLIBC_MAJOR__) "." __stringify(__UCLIBC_MINOR__) "." __stringify(__UCLIBC_SUBLEVEL__) diff --git a/libpthread/nptl_db/ChangeLog b/libpthread/nptl_db/ChangeLog new file mode 100644 index 000000000..52c849138 --- /dev/null +++ b/libpthread/nptl_db/ChangeLog @@ -0,0 +1,207 @@ +2004-09-09 Roland McGrath <roland@redhat.com> + + * td_ta_map_lwp2thr.c (td_ta_map_lwp2thr): Don't abort if inferior's + descriptor is bogus. + +2004-05-27 Roland McGrath <roland@redhat.com> + + * td_thr_validate.c: When we find no threads and the inferior appears + uninitialized, validate the main thread as a special case. + +2004-05-01 Jakub Jelinek <jakub@redhat.com> + + * thread_dbP.h (LOG): Use write instead of __libc_write. + +2004-04-03 Ulrich Drepper <drepper@redhat.com> + + * td_ta_set_event.c (td_ta_set_event): Initialize copy to avoid + warnings. + + * td_ta_thr_iter.c (td_ta_thr_iter): Initialize list to avoid warning. + * td_ta_clear_event.c (td_ta_clear_event): Initialize eventmask to + avoid warning. + * td_ta_set_event.c (td_ta_set_event): Likewise. + +2004-03-24 Roland McGrath <roland@redhat.com> + + * fetch-value.c (_td_locate_field): Cast DB_DESC_OFFSET to int32_t. + * thread_dbP.h (DB_DESC_OFFSET): Remove cast from definition. + +2004-03-13 Jakub Jelinek <jakub@redhat.com> + + * db_info.c: Don't use TLS_TP_OFFSET in the #if, but + TLS_TCB_SIZE == 0 ?: in the DESC macro. + +2004-03-12 Roland McGrath <roland@redhat.com> + + * db_info.c [TLS_DTV_AT_TP && TLS_TP_OFFSET > 0] + (_thread_db_pthread_dtvp): Define differently for this case (PowerPC). + +2003-12-11 Ulrich Weigand <uweigand@de.ibm.com> + + * db_info.c (REGISTER): Add bit size of thread register as second + parameter to REGISTER macro. + +2003-12-02 Roland McGrath <roland@redhat.com> + + * thread_dbP.h (DB_FUNCTION): New macro. + * structs.def: Use it for __nptl_create_event and __nptl_death_event. + * db_info.c (DB_FUNCTION): New macro. + * td_symbol_list.c (DB_FUNCTION): New macro, prepend "." to symbol + name under [HAVE_ASM_GLOBAL_DOT_NAME]. + (td_lookup) [HAVE_ASM_GLOBAL_DOT_NAME]: If lookup fails with PS_NOSYM + and name starts with a dot, try it without the dot. + +2003-09-08 Roland McGrath <roland@redhat.com> + + * td_thr_get_info.c (td_thr_get_info): Cast th_unique to thread_t. + +2003-08-22 Roland McGrath <roland@redhat.com> + + * fetch-value.c (_td_check_sizeof, _td_locate_field): Return + TD_NOCAPAB for PS_NOSYM, instead of vanilla TD_ERR. + * td_thr_tls_get_addr.c (td_thr_tls_get_addr): Return TD_NOAPLIC when + DB_GET_FIELD returns TD_NOCAPAB. + + * thread_db.h (td_thr_tls_get_addr): Use psaddr_t in signature. + * structs.def [USE_TLS]: Add DB_STRUCT_FIELD (link_map, l_tls_modid). + * db_info.c (link_map): Typedef it. + * td_thr_tls_get_addr.c (td_thr_tls_get_addr): Rewritten. + +2003-08-14 Roland McGrath <roland@redhat.com> + + * thread_dbP.h: Mostly rewritten with many new macros and decls. + * td_ta_new.c (td_ta_new): Don't cache a lot of symbol values. + * structs.def: New file. + * db_info.c: New file. + * td_symbol_list.c (symbol_list_arr): Define with structs.def macros. + * td_ta_clear_event.c: Rewritten. + * td_ta_event_addr.c: Rewritten. + * td_ta_event_getmsg.c: Rewritten. + * td_ta_get_nthreads.c: Rewritten. + * td_ta_map_lwp2thr.c: New file. + * td_ta_set_event.c: Rewritten. + * td_ta_thr_iter.c: Rewritten. + * td_ta_tsd_iter.c: Rewritten. + * td_thr_clear_event.c: Rewritten. + * td_thr_event_enable.c: Rewritten. + * td_thr_event_getmsg.c: Rewritten. + * td_thr_get_info.c: Rewritten. + * td_thr_getfpregs.c: Rewritten. + * td_thr_getgregs.c: Rewritten. + * td_thr_set_event.c: Rewritten. + * td_thr_setfpregs.c: Rewritten. + * td_thr_setgregs.c: Rewritten. + * td_thr_tlsbase.c: Rewritten. + * td_thr_tsd.c: Rewritten. + * td_thr_validate.c: Rewritten. + * Makefile (distribute): Add them. + * fetch-value.c: New file. + * Makefile (libthread_db-routines): Add it. + + * thread_db.h (td_err_e): Comment fix. + +2003-08-05 Roland McGrath <roland@redhat.com> + + * thread_dbP.h (td_lookup): Add attribute_hidden to decl. + +2003-08-04 Roland McGrath <roland@redhat.com> + + * td_ta_clear_event.c (td_ta_clear_event): Fix sizes in ps_* calls. + +2003-06-23 Roland McGrath <roland@redhat.com> + + * proc_service.h: Cosmetic and comment fixes. + +2003-06-19 Roland McGrath <roland@redhat.com> + + * td_thr_event_enable.c (td_thr_event_enable): Use proper type `bool' + for value written into inferior's `report_events'. + +2003-03-18 Roland McGrath <roland@redhat.com> + + * td_thr_event_getmsg.c (td_thr_event_getmsg): Splice the thread out + of the ->nextevent linkage. + + * td_ta_event_getmsg.c (td_ta_event_getmsg): Runtime error instead of + assert for reading TD_EVENT_NONE. Clear the event buffer after + reading it. Add a sanity check for foo->nextevent = foo. + +2003-03-15 Roland McGrath <roland@redhat.com> + + * thread_db.h (td_err_e): Add TD_NOTLS and TD_TLSDEFER. + (td_thr_tlsbase): Declare it. + * td_thr_tlsbase.c: New file. + * Makefile (libthread_db-routines): Add it. + * Versions (libthread_db: GLIBC_2.3.3): New set, add td_thr_tlsbase. + * td_thr_tls_get_addr.c (td_thr_tls_get_addr): Use td_thr_tlsbase. + +2003-03-14 Roland McGrath <roland@redhat.com> + + * td_thr_tls_get_addr.c (td_thr_tls_get_addr): Use `header.' prefix. + +2003-03-10 Roland McGrath <roland@redhat.com> + + * td_ta_thr_iter.c (iterate_thread_list): Don't use `header.data.' + prefix for `struct pthread' members. + * td_thr_validate.c (check_thread_list): Likewise. + * td_thr_tls_get_addr.c (td_thr_tls_get_addr): Likewise. + +2003-03-03 Roland McGrath <roland@redhat.com> + + * td_thr_tls_get_addr.c (td_thr_tls_get_addr): Handle TLS_DTV_AT_TP. + +2003-02-15 Ulrich Drepper <drepper@redhat.com> + + * td_symbol_list.c: New symbol name for SYM_PTHREAD_NTHREADS. + +2003-01-07 Jakub Jelinek <jakub@redhat.com> + + * td_ta_event_getmsg.c: Include assert.h. + +-2003-01-05 Ulrich Drepper <drepper@redhat.com> + + * Makefile (libthread_db.so-no-z-defs): Define. + +2003-01-03 Roland McGrath <roland@redhat.com> + + * td_thr_setgregs.c (td_thr_setgregs): *_BIT -> *_BITMASK + * td_thr_setfpregs.c (td_thr_setfpregs): Likewise. + * td_thr_get_info.c (td_thr_get_info): Likewise. + * td_thr_getgregs.c (td_thr_getgregs): Likewise. + * td_thr_getfpregs.c (td_thr_getfpregs): Likewise. + * td_ta_thr_iter.c (iterate_thread_list): Likewise. + +2002-12-12 Roland McGrath <roland@redhat.com> + + * td_ta_thr_iter.c (iterate_thread_list): Handle special case of + uninitialized __stack_user (zeros), hard-wire just the main thread. + + * td_thr_get_info.c (td_thr_get_info): Fix ti_lid initialization. + +2002-12-06 Roland McGrath <roland@redhat.com> + + * td_ta_event_getmsg.c (td_ta_event_getmsg): Write the NEXT pointer + into the inferior's __pthread_last_event variable, not a word from + an inferior address used in the parent. Pass the address of a + null word to ps_pdwrite, not a null pointer. + +2002-12-04 Roland McGrath <roland@redhat.com> + + * td_thr_get_info.c (td_thr_get_info): ti_tid is pthread_t, not a PID. + + * thread_db.h (td_thrinfo_t): Comment fix. + + * td_ta_map_lwp2thr.c: Moved to ../nptl/sysdeps/i386/. + +2002-12-04 Ulrich Drepper <drepper@redhat.com> + + * td_ta_thr_iter.c (iterate_thread_list): At end of iteration read + pointer to the next element from inferior. + +2002-12-02 Roland McGrath <roland@redhat.com> + + * td_symbol_list.c (symbol_list_arr): pthread_keys -> __pthread_keys + + * td_ta_map_lwp2thr.c (td_ta_map_lwp2thr): Fetch inferior registers to + see its %gs value, not our own. diff --git a/libpthread/nptl_db/Makefile b/libpthread/nptl_db/Makefile new file mode 100644 index 000000000..f9100219a --- /dev/null +++ b/libpthread/nptl_db/Makefile @@ -0,0 +1,13 @@ +# Makefile for uClibc +# +# Copyright (C) 2000-2005 Erik Andersen <andersen@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +top_srcdir=../../ +top_builddir=../../ +include $(top_builddir)Rules.mak +all: libs +include Makefile.in +include $(top_srcdir)Makerules diff --git a/libpthread/nptl_db/Makefile.in b/libpthread/nptl_db/Makefile.in new file mode 100644 index 000000000..3eaded59f --- /dev/null +++ b/libpthread/nptl_db/Makefile.in @@ -0,0 +1,71 @@ +# Makefile for uClibc +# +# Copyright (C) 2000-2005 Erik Andersen <andersen@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +subdirs += libpthread/nptl/nptl_db + +# Get the thread include dependencies and shared object name +CFLAGS-nptl_db := -DLIBPTHREAD_SO="\"libpthread.so.$(MAJOR_VERSION)\"" +CFLAGS-nptl_db += -I$(top_srcdir)libpthread/nptl -D_GNU_SOURCE +CFLAGS-nptl_db += -DIS_IN_libthread_db=1 -std=gnu99 -I$(top_srcdir)ldso/include + +LDFLAGS-libthread_db.so := $(LDFLAGS_NOSTRIP) -s --warn-unresolved-symbols + +LIBS-libthread_db.so := $(LIBS) + +libthread_db_FULL_NAME := libthread_db-$(VERSION).so + +libthread_db_DIR := $(top_srcdir)libpthread/nptl_db +libthread_db_OUT := $(top_builddir)libpthread/nptl_db + +libthread_db_SRC := $(wildcard $(libthread_db_DIR)/td_*.c) \ + $(libthread_db_DIR)/fetch-value.c + +libthread_db_OBJ := $(patsubst $(libthread_db_DIR)/%.c,$(libthread_db_OUT)/%.o,$(libthread_db_SRC)) + +libthread_db-so-y := $(libthread_db_OBJ:.o=.oS) +ifeq ($(DOPIC),y) +libthread_db-a-y := $(libthread_db-so-y) +else +libthread_db-a-y := $(libthread_db_OBJ) +endif + +libthread_db-multi-y := $(libthread_db_SRC) + +lib-a-$(PTHREADS_DEBUG_SUPPORT) += $(top_builddir)lib/libthread_db.a +lib-so-$(PTHREADS_DEBUG_SUPPORT) += $(top_builddir)lib/libthread_db.so +objclean-y += libthread_db_clean +headers-$(PTHREADS_DEBUG_SUPPORT) += $(nptl_db_headers) +headers_clean-y += nptl_db_headers_clean + +ifeq ($(DOPIC),y) +$(top_builddir)lib/libthread_db.so: $(top_builddir)lib/libthread_db.a $(libc) +else +$(top_builddir)lib/libthread_db.so: $(libthread_db_OUT)/libthread_db_so.a $(libc) +endif + $(call link.so,$(libthread_db_FULL_NAME),1) + +$(libthread_db_OUT)/libthread_db_so.a: $(libthread_db-so-y) + $(Q)$(RM) $@ + $(do_strip) + $(do_ar) + +$(top_builddir)lib/libthread_db.a: $(libthread_db-a-y) + $(Q)$(INSTALL) -d $(dir $@) + $(Q)$(RM) $@ + $(do_strip) + $(do_ar) + +$(top_builddir)include/thread_db.h: + $(do_ln) $(call rel_srcdir)$(PTDIR)_db/$(@F) $@ + +nptl_db_headers:= $(top_builddir)include/thread_db.h + +nptl_db_headers_clean: + $(do_rm) $(nptl_db_headers) + +libthread_db_clean: + $(do_rm) $(addprefix $(libthread_db_OUT)/*., o oS a) diff --git a/libpthread/nptl_db/db_info.c b/libpthread/nptl_db/db_info.c new file mode 100644 index 000000000..5aec152d5 --- /dev/null +++ b/libpthread/nptl_db/db_info.c @@ -0,0 +1,103 @@ +/* This file is included by pthread_create.c to define in libpthread + all the magic symbols required by libthread_db. + + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" +#include <tls.h> + +typedef struct pthread pthread; +typedef struct pthread_key_struct pthread_key_struct; +typedef struct pthread_key_data pthread_key_data; +typedef struct +{ + struct pthread_key_data data[PTHREAD_KEY_2NDLEVEL_SIZE]; +} +pthread_key_data_level2; + +typedef struct +{ + union dtv dtv[UINT32_MAX / 2 / sizeof (union dtv)]; /* No constant bound. */ +} dtv; + +typedef struct link_map link_map; + + +#define schedparam_sched_priority schedparam.sched_priority + +#define eventbuf_eventmask eventbuf.eventmask +#define eventbuf_eventmask_event_bits eventbuf.eventmask.event_bits + +#define DESC(name, offset, obj) \ + DB_DEFINE_DESC (name, 8 * sizeof (obj), 1, offset); +#define ARRAY_DESC(name, offset, obj) \ + DB_DEFINE_DESC (name, \ + 8 * sizeof (obj)[0], sizeof (obj) / sizeof (obj)[0], \ + offset); + +#if defined(TLS_TCB_AT_TP) +# define dtvp header.dtv +#elif defined(TLS_DTV_AT_TP) +/* Special case hack. If TLS_TCB_SIZE == 0 (on PowerPC), there is no TCB + containing the DTV at the TP, but actually the TCB lies behind the TP, + i.e. at the very end of the area covered by TLS_PRE_TCB_SIZE. */ +DESC (_thread_db_pthread_dtvp, + TLS_PRE_TCB_SIZE + offsetof (tcbhead_t, dtv) + - (TLS_TCB_SIZE == 0 ? sizeof (tcbhead_t) : 0), union dtv) +#endif + + +#define DB_STRUCT(type) \ + const uint32_t _thread_db_sizeof_##type = sizeof (type); +#define DB_STRUCT_FIELD(type, field) \ + DESC (_thread_db_##type##_##field, \ + offsetof (type, field), ((type *) 0)->field) +#define DB_STRUCT_ARRAY_FIELD(type, field) \ + ARRAY_DESC (_thread_db_##type##_##field, \ + offsetof (type, field), ((type *) 0)->field) +#define DB_VARIABLE(name) DESC (_thread_db_##name, 0, name) +#define DB_ARRAY_VARIABLE(name) ARRAY_DESC (_thread_db_##name, 0, name) +#define DB_SYMBOL(name) /* Nothing. */ +#define DB_FUNCTION(name) /* Nothing. */ +#include "structs.def" +#undef DB_STRUCT +#undef DB_STRUCT_FIELD +#undef DB_SYMBOL +#undef DB_FUNCTION +#undef DB_VARIABLE +#undef DESC + + + +#ifdef DB_THREAD_SELF +# ifdef DB_THREAD_SELF_INCLUDE +# include DB_THREAD_SELF_INCLUDE +# endif + +/* This macro is defined in the machine's tls.h using the three below. */ +# define CONST_THREAD_AREA(bits, value) \ + const uint32_t _thread_db_const_thread_area = (value); +# define REGISTER_THREAD_AREA(bits, regofs, scale) \ + DB_DEFINE_DESC (_thread_db_register##bits##_thread_area, \ + bits, (scale), (regofs)); +# define REGISTER(bits, size, regofs, bias) \ + DB_DEFINE_DESC (_thread_db_register##bits, size, (uint32_t)(bias), (regofs)); + +DB_THREAD_SELF +#endif diff --git a/libpthread/nptl_db/fetch-value.c b/libpthread/nptl_db/fetch-value.c new file mode 100644 index 000000000..0d9bb0eb8 --- /dev/null +++ b/libpthread/nptl_db/fetch-value.c @@ -0,0 +1,284 @@ +/* Helper routines for libthread_db. + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" +#include <byteswap.h> +#include <assert.h> + +td_err_e +_td_check_sizeof (td_thragent_t *ta, uint32_t *sizep, int sizep_name) +{ + if (*sizep == 0) + { + psaddr_t descptr; + ps_err_e err = td_lookup (ta->ph, sizep_name, &descptr); + if (err == PS_NOSYM) + return TD_NOCAPAB; + if (err == PS_OK) + err = ps_pdread (ta->ph, descptr, sizep, sizeof *sizep); + if (err != PS_OK) + return TD_ERR; + if (*sizep & 0xff000000U) + *sizep = bswap_32 (*sizep); + } + return TD_OK; +} + +td_err_e +_td_locate_field (td_thragent_t *ta, + db_desc_t desc, int descriptor_name, + psaddr_t idx, psaddr_t *address) +{ + uint32_t elemsize; + + if (DB_DESC_SIZE (desc) == 0) + { + /* Read the information about this field from the inferior. */ + psaddr_t descptr; + ps_err_e err = td_lookup (ta->ph, descriptor_name, &descptr); + if (err == PS_NOSYM) + return TD_NOCAPAB; + if (err == PS_OK) + err = ps_pdread (ta->ph, descptr, desc, DB_SIZEOF_DESC); + if (err != PS_OK) + return TD_ERR; + if (DB_DESC_SIZE (desc) == 0) + return TD_DBERR; + if (DB_DESC_SIZE (desc) & 0xff000000U) + { + /* Byte-swap these words, though we leave the size word + in native order as the handy way to distinguish. */ + DB_DESC_OFFSET (desc) = bswap_32 (DB_DESC_OFFSET (desc)); + DB_DESC_NELEM (desc) = bswap_32 (DB_DESC_NELEM (desc)); + } + } + + if (idx != 0 && idx - (psaddr_t) 0 > DB_DESC_NELEM (desc)) + /* This is an internal indicator to callers with nonzero IDX + that the IDX value is too big. */ + return TD_NOAPLIC; + + elemsize = DB_DESC_SIZE (desc); + if (elemsize & 0xff000000U) + elemsize = bswap_32 (elemsize); + + *address += (int32_t) DB_DESC_OFFSET (desc); + *address += (elemsize / 8 * (idx - (psaddr_t) 0)); + return TD_OK; +} + +td_err_e +_td_fetch_value (td_thragent_t *ta, + db_desc_t desc, int descriptor_name, + psaddr_t idx, psaddr_t address, + psaddr_t *result) +{ + ps_err_e err; + td_err_e terr = _td_locate_field (ta, desc, descriptor_name, idx, &address); + if (terr != TD_OK) + return terr; + + if (DB_DESC_SIZE (desc) == 8 || DB_DESC_SIZE (desc) == bswap_32 (8)) + { + uint8_t value; + err = ps_pdread (ta->ph, address, &value, sizeof value); + *result = (psaddr_t) 0 + value; + } + else if (DB_DESC_SIZE (desc) == 32) + { + uint32_t value; + err = ps_pdread (ta->ph, address, &value, sizeof value); + *result = (psaddr_t) 0 + value; + } + else if (DB_DESC_SIZE (desc) == 64) + { + uint64_t value; + if (sizeof (psaddr_t) < 8) + return TD_NOCAPAB; + err = ps_pdread (ta->ph, address, &value, sizeof value); + *result = (psaddr_t) 0 + value; + } + else if (DB_DESC_SIZE (desc) == bswap_32 (32)) + { + uint32_t value; + err = ps_pdread (ta->ph, address, &value, sizeof value); + value = bswap_32 (value); + *result = (psaddr_t) 0 + value; + } + else if (DB_DESC_SIZE (desc) == bswap_32 (64)) + { + uint64_t value; + if (sizeof (psaddr_t) < 8) + return TD_NOCAPAB; + err = ps_pdread (ta->ph, address, &value, sizeof value); + value = bswap_64 (value); + *result = (psaddr_t) 0 + value; + } + else + return TD_DBERR; + + return err == PS_OK ? TD_OK : TD_ERR; +} + + +td_err_e +_td_store_value (td_thragent_t *ta, + uint32_t desc[2], int descriptor_name, psaddr_t idx, + psaddr_t address, psaddr_t widened_value) +{ + ps_err_e err; + td_err_e terr = _td_locate_field (ta, desc, descriptor_name, idx, &address); + if (terr != TD_OK) + return terr; + + if (DB_DESC_SIZE (desc) == 8 || DB_DESC_SIZE (desc) == bswap_32 (8)) + { + uint8_t value = widened_value - (psaddr_t) 0; + err = ps_pdwrite (ta->ph, address, &value, sizeof value); + } + else if (DB_DESC_SIZE (desc) == 32) + { + uint32_t value = widened_value - (psaddr_t) 0; + err = ps_pdwrite (ta->ph, address, &value, sizeof value); + } + else if (DB_DESC_SIZE (desc) == 64) + { + uint64_t value = widened_value - (psaddr_t) 0; + if (sizeof (psaddr_t) < 8) + return TD_NOCAPAB; + err = ps_pdwrite (ta->ph, address, &value, sizeof value); + } + else if (DB_DESC_SIZE (desc) == bswap_32 (32)) + { + uint32_t value = widened_value - (psaddr_t) 0; + value = bswap_32 (value); + err = ps_pdwrite (ta->ph, address, &value, sizeof value); + } + else if (DB_DESC_SIZE (desc) == bswap_32 (64)) + { + uint64_t value = widened_value - (psaddr_t) 0; + if (sizeof (psaddr_t) < 8) + return TD_NOCAPAB; + value = bswap_64 (value); + err = ps_pdwrite (ta->ph, address, &value, sizeof value); + } + else + return TD_DBERR; + + return err == PS_OK ? TD_OK : TD_ERR; +} + +td_err_e +_td_fetch_value_local (td_thragent_t *ta, + db_desc_t desc, int descriptor_name, psaddr_t idx, + void *address, + psaddr_t *result) +{ + td_err_e terr = _td_locate_field (ta, desc, descriptor_name, idx, &address); + if (terr != TD_OK) + return terr; + + if (DB_DESC_SIZE (desc) == 8 || DB_DESC_SIZE (desc) == bswap_32 (8)) + { + uint8_t value; + memcpy (&value, address, sizeof value); + *result = (psaddr_t) 0 + value; + } + else if (DB_DESC_SIZE (desc) == 32) + { + uint32_t value; + memcpy (&value, address, sizeof value); + *result = (psaddr_t) 0 + value; + } + else if (DB_DESC_SIZE (desc) == 64) + { + uint64_t value; + if (sizeof (psaddr_t) < 8) + return TD_NOCAPAB; + memcpy (&value, address, sizeof value); + *result = (psaddr_t) 0 + value; + } + else if (DB_DESC_SIZE (desc) == bswap_32 (32)) + { + uint32_t value; + memcpy (&value, address, sizeof value); + value = bswap_32 (value); + *result = (psaddr_t) 0 + value; + } + else if (DB_DESC_SIZE (desc) == bswap_32 (64)) + { + uint64_t value; + if (sizeof (psaddr_t) < 8) + return TD_NOCAPAB; + memcpy (&value, address, sizeof value); + value = bswap_64 (value); + *result = (psaddr_t) 0 + value; + } + else + return TD_DBERR; + + return TD_OK; +} + + +td_err_e +_td_store_value_local (td_thragent_t *ta, + uint32_t desc[2], int descriptor_name, psaddr_t idx, + void *address, psaddr_t widened_value) +{ + td_err_e terr = _td_locate_field (ta, desc, descriptor_name, idx, &address); + if (terr != TD_OK) + return terr; + + if (DB_DESC_SIZE (desc) == 8 || DB_DESC_SIZE (desc) == bswap_32 (8)) + { + uint8_t value = widened_value - (psaddr_t) 0; + memcpy (address, &value, sizeof value); + } + else if (DB_DESC_SIZE (desc) == 32) + { + uint32_t value = widened_value - (psaddr_t) 0; + memcpy (address, &value, sizeof value); + } + else if (DB_DESC_SIZE (desc) == 64) + { + uint64_t value = widened_value - (psaddr_t) 0; + if (sizeof (psaddr_t) < 8) + return TD_NOCAPAB; + memcpy (address, &value, sizeof value); + } + else if (DB_DESC_SIZE (desc) == bswap_32 (32)) + { + uint32_t value = widened_value - (psaddr_t) 0; + value = bswap_32 (value); + memcpy (address, &value, sizeof value); + } + else if (DB_DESC_SIZE (desc) == bswap_32 (64)) + { + uint64_t value = widened_value - (psaddr_t) 0; + if (sizeof (psaddr_t) < 8) + return TD_NOCAPAB; + value = bswap_64 (value); + memcpy (address, &value, sizeof value); + } + else + return TD_DBERR; + + return TD_OK; +} diff --git a/libpthread/nptl_db/proc_service.h b/libpthread/nptl_db/proc_service.h new file mode 100644 index 000000000..d49e87ab3 --- /dev/null +++ b/libpthread/nptl_db/proc_service.h @@ -0,0 +1,87 @@ +/* Callback interface for libthread_db, functions users must define. + Copyright (C) 1999,2002,2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* The definitions in this file must correspond to those in the debugger. */ +#include <sys/procfs.h> + +/* Functions in this interface return one of these status codes. */ +typedef enum +{ + PS_OK, /* Generic "call succeeded". */ + PS_ERR, /* Generic error. */ + PS_BADPID, /* Bad process handle. */ + PS_BADLID, /* Bad LWP identifier. */ + PS_BADADDR, /* Bad address. */ + PS_NOSYM, /* Could not find given symbol. */ + PS_NOFREGS /* FPU register set not available for given LWP. */ +} ps_err_e; + + +/* This type is opaque in this interface. + It's defined by the user of libthread_db. */ +struct ps_prochandle; + + +/* Read or write process memory at the given address. */ +extern ps_err_e ps_pdread (struct ps_prochandle *, + psaddr_t, void *, size_t); +extern ps_err_e ps_pdwrite (struct ps_prochandle *, + psaddr_t, const void *, size_t); +extern ps_err_e ps_ptread (struct ps_prochandle *, + psaddr_t, void *, size_t); +extern ps_err_e ps_ptwrite (struct ps_prochandle *, + psaddr_t, const void *, size_t); + + +/* Get and set the given LWP's general or FPU register set. */ +extern ps_err_e ps_lgetregs (struct ps_prochandle *, + lwpid_t, prgregset_t); +extern ps_err_e ps_lsetregs (struct ps_prochandle *, + lwpid_t, const prgregset_t); +extern ps_err_e ps_lgetfpregs (struct ps_prochandle *, + lwpid_t, prfpregset_t *); +extern ps_err_e ps_lsetfpregs (struct ps_prochandle *, + lwpid_t, const prfpregset_t *); + +/* Return the PID of the process. */ +extern pid_t ps_getpid (struct ps_prochandle *); + +/* Fetch the special per-thread address associated with the given LWP. + This call is only used on a few platforms (most use a normal register). + The meaning of the `int' parameter is machine-dependent. */ +extern ps_err_e ps_get_thread_area (const struct ps_prochandle *, + lwpid_t, int, psaddr_t *); + + +/* Look up the named symbol in the named DSO in the symbol tables + associated with the process being debugged, filling in *SYM_ADDR + with the corresponding run-time address. */ +extern ps_err_e ps_pglobal_lookup (struct ps_prochandle *, + const char *object_name, + const char *sym_name, + psaddr_t *sym_addr); + + +/* Stop or continue the entire process. */ +extern ps_err_e ps_pstop (const struct ps_prochandle *); +extern ps_err_e ps_pcontinue (const struct ps_prochandle *); + +/* Stop or continue the given LWP alone. */ +extern ps_err_e ps_lstop (const struct ps_prochandle *, lwpid_t); +extern ps_err_e ps_lcontinue (const struct ps_prochandle *, lwpid_t); diff --git a/libpthread/nptl_db/structs.def b/libpthread/nptl_db/structs.def new file mode 100644 index 000000000..823af5cba --- /dev/null +++ b/libpthread/nptl_db/structs.def @@ -0,0 +1,88 @@ +/* List of types and symbols in libpthread examined by libthread_db. + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef DB_STRUCT_ARRAY_FIELD +# define DB_STRUCT_ARRAY_FIELD(type, field) DB_STRUCT_FIELD (type, field) +# define DB_ARRAY_VARIABLE(name) DB_VARIABLE (name) +# define STRUCTS_DEF_DEFAULTS 1 +#endif + +DB_STRUCT (pthread) +DB_STRUCT_FIELD (pthread, list) +DB_STRUCT_FIELD (pthread, report_events) +DB_STRUCT_FIELD (pthread, tid) +DB_STRUCT_FIELD (pthread, start_routine) +DB_STRUCT_FIELD (pthread, cancelhandling) +DB_STRUCT_FIELD (pthread, schedpolicy) +DB_STRUCT_FIELD (pthread, schedparam_sched_priority) +DB_STRUCT_FIELD (pthread, specific) +DB_STRUCT_FIELD (pthread, eventbuf) +DB_STRUCT_FIELD (pthread, eventbuf_eventmask) +DB_STRUCT_ARRAY_FIELD (pthread, eventbuf_eventmask_event_bits) +DB_STRUCT_FIELD (pthread, nextevent) + +DB_STRUCT (list_t) +DB_STRUCT_FIELD (list_t, next) +DB_STRUCT_FIELD (list_t, prev) + +DB_STRUCT (td_thr_events_t) +DB_STRUCT_ARRAY_FIELD (td_thr_events_t, event_bits) + +DB_STRUCT (td_eventbuf_t) +DB_STRUCT_FIELD (td_eventbuf_t, eventnum) +DB_STRUCT_FIELD (td_eventbuf_t, eventdata) + +DB_SYMBOL (stack_used) +DB_SYMBOL (__stack_user) +DB_SYMBOL (nptl_version) +DB_FUNCTION (__nptl_create_event) +DB_FUNCTION (__nptl_death_event) +DB_SYMBOL (__nptl_threads_events) +DB_VARIABLE (__nptl_nthreads) +DB_VARIABLE (__nptl_last_event) + +DB_ARRAY_VARIABLE (__pthread_keys) +DB_STRUCT (pthread_key_struct) +DB_STRUCT_FIELD (pthread_key_struct, seq) +DB_STRUCT_FIELD (pthread_key_struct, destr) + +DB_STRUCT (pthread_key_data) +DB_STRUCT_FIELD (pthread_key_data, seq) +DB_STRUCT_FIELD (pthread_key_data, data) +DB_STRUCT (pthread_key_data_level2) +DB_STRUCT_ARRAY_FIELD (pthread_key_data_level2, data) + +#if USE_TLS +DB_STRUCT_FIELD (link_map, l_tls_modid) +#endif + +#if !defined IS_IN_libpthread || USE_TLS +DB_STRUCT_ARRAY_FIELD (dtv, dtv) +# define pointer_val pointer.val /* Field of anonymous struct in dtv_t. */ +DB_STRUCT_FIELD (dtv_t, pointer_val) +#endif +#if !defined IS_IN_libpthread || TLS_TCB_AT_TP +DB_STRUCT_FIELD (pthread, dtvp) +#endif + +#ifdef STRUCTS_DEF_DEFAULTS +# undef DB_STRUCT_ARRAY_FIELD +# undef DB_ARRAY_VARIABLE +# undef STRUCTS_DEF_DEFAULTS +#endif diff --git a/libpthread/nptl_db/td_init.c b/libpthread/nptl_db/td_init.c new file mode 100644 index 000000000..946ff7244 --- /dev/null +++ b/libpthread/nptl_db/td_init.c @@ -0,0 +1,32 @@ +/* Initialization function of thread debugger support library. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + +int __td_debug; + + +td_err_e +td_init (void) +{ + /* XXX We have to figure out what has to be done. */ + LOG ("td_init"); + return TD_OK; +} diff --git a/libpthread/nptl_db/td_log.c b/libpthread/nptl_db/td_log.c new file mode 100644 index 000000000..52212a0e9 --- /dev/null +++ b/libpthread/nptl_db/td_log.c @@ -0,0 +1,32 @@ +/* Noop, left for historical reasons. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_log (void) +{ + /* This interface is deprecated in the Sun interface. We provide it + for compatibility but don't do anything ourself. We might in + future do some logging if this seems reasonable. */ + LOG ("td_log"); + return TD_OK; +} diff --git a/libpthread/nptl_db/td_symbol_list.c b/libpthread/nptl_db/td_symbol_list.c new file mode 100644 index 000000000..04aed6787 --- /dev/null +++ b/libpthread/nptl_db/td_symbol_list.c @@ -0,0 +1,87 @@ +/* Return list of symbols the library can request. + Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2001. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#ifndef __UCLIBC__ +#include <gnu/lib-names.h> +#endif +#include "thread_dbP.h" + + +#ifdef HAVE_ASM_GLOBAL_DOT_NAME +# define DOT "." /* PPC64 requires . prefix on code symbols. */ +#else +# define DOT /* No prefix. */ +#endif + +static const char *symbol_list_arr[] = +{ +# define DB_STRUCT(type) \ + [SYM_SIZEOF_##type] = "_thread_db_sizeof_" #type, +# define DB_STRUCT_FIELD(type, field) \ + [SYM_##type##_FIELD_##field] = "_thread_db_" #type "_" #field, +# define DB_SYMBOL(name) \ + [SYM_##name] = #name, +# define DB_FUNCTION(name) \ + [SYM_##name] = DOT #name, +# define DB_VARIABLE(name) \ + [SYM_##name] = #name, \ + [SYM_DESC_##name] = "_thread_db_" #name, +# include "structs.def" +# undef DB_STRUCT +# undef DB_FUNCTION +# undef DB_SYMBOL +# undef DB_VARIABLE + + [SYM_TH_UNIQUE_CONST_THREAD_AREA] = "_thread_db_const_thread_area", + [SYM_TH_UNIQUE_REGISTER64] = "_thread_db_register64", + [SYM_TH_UNIQUE_REGISTER32] = "_thread_db_register32", + [SYM_TH_UNIQUE_REGISTER32_THREAD_AREA] = "_thread_db_register32_thread_area", + [SYM_TH_UNIQUE_REGISTER64_THREAD_AREA] = "_thread_db_register64_thread_area", + + [SYM_NUM_MESSAGES] = NULL +}; + + +const char ** +td_symbol_list (void) +{ + return symbol_list_arr; +} + + +ps_err_e +td_lookup (struct ps_prochandle *ps, int idx, psaddr_t *sym_addr) +{ + ps_err_e result; + assert (idx >= 0 && idx < SYM_NUM_MESSAGES); + result = ps_pglobal_lookup (ps, LIBPTHREAD_SO, symbol_list_arr[idx], + sym_addr); + +#ifdef HAVE_ASM_GLOBAL_DOT_NAME + /* For PowerPC, 64-bit uses dot symbols but 32-bit does not. + We could be a 64-bit libthread_db debugging a 32-bit libpthread. */ + if (result == PS_NOSYM && symbol_list_arr[idx][0] == '.') + result = ps_pglobal_lookup (ps, LIBPTHREAD_SO, &symbol_list_arr[idx][1], + sym_addr); +#endif + + return result; +} diff --git a/libpthread/nptl_db/td_ta_clear_event.c b/libpthread/nptl_db/td_ta_clear_event.c new file mode 100644 index 000000000..7a2850c4e --- /dev/null +++ b/libpthread/nptl_db/td_ta_clear_event.c @@ -0,0 +1,79 @@ +/* Globally disable events. + Copyright (C) 1999, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_ta_clear_event (ta_arg, event) + const td_thragent_t *ta_arg; + td_thr_events_t *event; +{ + td_thragent_t *const ta = (td_thragent_t *) ta_arg; + td_err_e err; + psaddr_t eventmask = 0; + void *copy = NULL; + + LOG ("td_ta_clear_event"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + /* Fetch the old event mask from the inferior and modify it in place. */ + err = DB_GET_SYMBOL (eventmask, ta, __nptl_threads_events); + if (err == TD_OK) + err = DB_GET_STRUCT (copy, ta, eventmask, td_thr_events_t); + if (err == TD_OK) + { + uint32_t idx; + for (idx = 0; idx < TD_EVENTSIZE; ++idx) + { + psaddr_t word; + uint32_t mask; + err = DB_GET_FIELD_LOCAL (word, ta, copy, + td_thr_events_t, event_bits, idx); + if (err != TD_OK) + break; + mask = (uintptr_t) word; + mask &= ~event->event_bits[idx]; + word = (psaddr_t) (uintptr_t) mask; + err = DB_PUT_FIELD_LOCAL (ta, copy, + td_thr_events_t, event_bits, idx, word); + if (err != TD_OK) + break; + } + if (err == TD_NOAPLIC) + { + err = TD_OK; + while (idx < TD_EVENTSIZE) + if (event->event_bits[idx++] != 0) + { + err = TD_NOEVENT; + break; + } + } + if (err == TD_OK) + /* Now write it back to the inferior. */ + err = DB_PUT_STRUCT (ta, eventmask, td_thr_events_t, copy); + } + + return err; +} diff --git a/libpthread/nptl_db/td_ta_delete.c b/libpthread/nptl_db/td_ta_delete.c new file mode 100644 index 000000000..57b90e57f --- /dev/null +++ b/libpthread/nptl_db/td_ta_delete.c @@ -0,0 +1,42 @@ +/* Detach to target process. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <stdlib.h> + +#include "thread_dbP.h" + + +td_err_e +td_ta_delete (td_thragent_t *ta) +{ + LOG ("td_ta_delete"); + + /* Safety check. Note that the test will also fail for TA == NULL. */ + if (!ta_ok (ta)) + return TD_BADTA; + + /* Remove the handle from the list. */ + list_del (&ta->list); + + /* The handle was allocated in `td_ta_new'. */ + free (ta); + + return TD_OK; +} diff --git a/libpthread/nptl_db/td_ta_enable_stats.c b/libpthread/nptl_db/td_ta_enable_stats.c new file mode 100644 index 000000000..ec7014ad2 --- /dev/null +++ b/libpthread/nptl_db/td_ta_enable_stats.c @@ -0,0 +1,35 @@ +/* Enable collection of statistics for process. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_ta_enable_stats (const td_thragent_t *ta, int enable) +{ + /* XXX We have to figure out what has to be done. */ + LOG ("td_ta_enable_stats"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + return TD_OK; +} diff --git a/libpthread/nptl_db/td_ta_event_addr.c b/libpthread/nptl_db/td_ta_event_addr.c new file mode 100644 index 000000000..45c6b113d --- /dev/null +++ b/libpthread/nptl_db/td_ta_event_addr.c @@ -0,0 +1,61 @@ +/* Get event address. + Copyright (C) 1999,2001,2002,2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_ta_event_addr (const td_thragent_t *ta_arg, + td_event_e event, td_notify_t *addr) +{ + td_thragent_t *const ta = (td_thragent_t *) ta_arg; + td_err_e err; + psaddr_t taddr = NULL; + + LOG ("td_ta_event_addr"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + switch (event) + { + case TD_CREATE: + err = DB_GET_SYMBOL (taddr, ta, __nptl_create_event); + break; + + case TD_DEATH: + err = DB_GET_SYMBOL (taddr, ta, __nptl_death_event); + break; + + default: + /* Event cannot be handled. */ + return TD_NOEVENT; + } + + if (err == TD_OK) + { + /* Success, we got the address. */ + addr->type = NOTIFY_BPT; + addr->u.bptaddr = taddr; + } + + return err; +} diff --git a/libpthread/nptl_db/td_ta_event_getmsg.c b/libpthread/nptl_db/td_ta_event_getmsg.c new file mode 100644 index 000000000..d3b46bd56 --- /dev/null +++ b/libpthread/nptl_db/td_ta_event_getmsg.c @@ -0,0 +1,105 @@ +/* Retrieve event. + Copyright (C) 1999, 2001, 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <stddef.h> +#include <string.h> + +#include "thread_dbP.h" + + +td_err_e +td_ta_event_getmsg (const td_thragent_t *ta_arg, td_event_msg_t *msg) +{ + td_thragent_t *const ta = (td_thragent_t *) ta_arg; + td_err_e err; + psaddr_t eventbuf, eventnum, eventdata; + psaddr_t thp, next; + void *copy = NULL; + + /* XXX I cannot think of another way but using a static variable. */ + /* XXX Use at least __thread once it is possible. */ + static td_thrhandle_t th; + + LOG ("td_thr_event_getmsg"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + /* Get the pointer to the thread descriptor with the last event. */ + err = DB_GET_VALUE (thp, ta, __nptl_last_event, 0); + if (err != TD_OK) + return err; + + if (thp == 0) + /* Nothing waiting. */ + return TD_NOMSG; + + /* Copy the event message buffer in from the inferior. */ + err = DB_GET_FIELD_ADDRESS (eventbuf, ta, thp, pthread, eventbuf, 0); + if (err == TD_OK) + err = DB_GET_STRUCT (copy, ta, eventbuf, td_eventbuf_t); + if (err != TD_OK) + return err; + + /* Read the event details from the target thread. */ + err = DB_GET_FIELD_LOCAL (eventnum, ta, copy, td_eventbuf_t, eventnum, 0); + if (err != TD_OK) + return err; + /* If the structure is on the list there better be an event recorded. */ + if ((int) (uintptr_t) eventnum == TD_EVENT_NONE) + return TD_DBERR; + + /* Fill the user's data structure. */ + err = DB_GET_FIELD_LOCAL (eventdata, ta, copy, td_eventbuf_t, eventdata, 0); + if (err != TD_OK) + return err; + + /* Generate the thread descriptor. */ + th.th_ta_p = (td_thragent_t *) ta; + th.th_unique = thp; + + /* Fill the user's data structure. */ + msg->msg.data = (uintptr_t) eventdata; + msg->event = (uintptr_t) eventnum; + msg->th_p = &th; + + /* And clear the event message in the target. */ + memset (copy, 0, ta->ta_sizeof_td_eventbuf_t); + err = DB_PUT_STRUCT (ta, eventbuf, td_eventbuf_t, copy); + if (err != TD_OK) + return err; + + /* Get the pointer to the next descriptor with an event. */ + err = DB_GET_FIELD (next, ta, thp, pthread, nextevent, 0); + if (err != TD_OK) + return err; + + /* Store the pointer in the list head variable. */ + err = DB_PUT_VALUE (ta, __nptl_last_event, 0, next); + if (err != TD_OK) + return err; + + if (next != 0) + /* Clear the next pointer in the current descriptor. */ + err = DB_PUT_FIELD (ta, thp, pthread, nextevent, 0, 0); + + return err; +} diff --git a/libpthread/nptl_db/td_ta_get_nthreads.c b/libpthread/nptl_db/td_ta_get_nthreads.c new file mode 100644 index 000000000..ffe78bd57 --- /dev/null +++ b/libpthread/nptl_db/td_ta_get_nthreads.c @@ -0,0 +1,42 @@ +/* Get the number of threads in the process. + Copyright (C) 1999,2001,2002,2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + +td_err_e +td_ta_get_nthreads (const td_thragent_t *ta_arg, int *np) +{ + td_thragent_t *const ta = (td_thragent_t *) ta_arg; + td_err_e err; + psaddr_t n; + + LOG ("td_ta_get_nthreads"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + /* Access the variable in the inferior that tells us. */ + err = DB_GET_VALUE (n, ta, __nptl_nthreads, 0); + if (err == TD_OK) + *np = (uintptr_t) n; + + return err; +} diff --git a/libpthread/nptl_db/td_ta_get_ph.c b/libpthread/nptl_db/td_ta_get_ph.c new file mode 100644 index 000000000..04e01fb73 --- /dev/null +++ b/libpthread/nptl_db/td_ta_get_ph.c @@ -0,0 +1,36 @@ +/* Get external process handle. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_ta_get_ph (const td_thragent_t *ta, struct ps_prochandle **ph) +{ + LOG ("td_ta_get_ph"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + *ph = ta->ph; + + return TD_OK; +} diff --git a/libpthread/nptl_db/td_ta_get_stats.c b/libpthread/nptl_db/td_ta_get_stats.c new file mode 100644 index 000000000..d5d879c3e --- /dev/null +++ b/libpthread/nptl_db/td_ta_get_stats.c @@ -0,0 +1,35 @@ +/* Retrieve statistics for process. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_ta_get_stats (const td_thragent_t *ta, td_ta_stats_t *statsp) +{ + /* XXX We have to figure out what has to be done. */ + LOG ("td_ta_get_stats"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + return TD_OK; +} diff --git a/libpthread/nptl_db/td_ta_map_id2thr.c b/libpthread/nptl_db/td_ta_map_id2thr.c new file mode 100644 index 000000000..189a67171 --- /dev/null +++ b/libpthread/nptl_db/td_ta_map_id2thr.c @@ -0,0 +1,38 @@ +/* Map thread ID to thread handle. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_ta_map_id2thr (const td_thragent_t *ta, pthread_t pt, td_thrhandle_t *th) +{ + LOG ("td_ta_map_id2thr"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + /* Create the `td_thrhandle_t' object. */ + th->th_ta_p = (td_thragent_t *) ta; + th->th_unique = (psaddr_t) pt; + + return TD_OK; +} diff --git a/libpthread/nptl_db/td_ta_map_lwp2thr.c b/libpthread/nptl_db/td_ta_map_lwp2thr.c new file mode 100644 index 000000000..acfa0fd8a --- /dev/null +++ b/libpthread/nptl_db/td_ta_map_lwp2thr.c @@ -0,0 +1,178 @@ +/* Which thread is running on an LWP? + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" +#include <stdlib.h> +#include <byteswap.h> +#include <sys/procfs.h> + + +td_err_e +td_ta_map_lwp2thr (const td_thragent_t *ta_arg, + lwpid_t lwpid, td_thrhandle_t *th) +{ + td_thragent_t *const ta = (td_thragent_t *) ta_arg; + ps_err_e err; + td_err_e terr; + prgregset_t regs; + psaddr_t addr; + + LOG ("td_ta_map_lwp2thr"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + if (ta->ta_howto == ta_howto_unknown) + { + /* We need to read in from the inferior the instructions what to do. */ + psaddr_t howto; + + err = td_lookup (ta->ph, SYM_TH_UNIQUE_CONST_THREAD_AREA, &howto); + if (err == PS_OK) + { + err = ps_pdread (ta->ph, howto, + &ta->ta_howto_data.const_thread_area, + sizeof ta->ta_howto_data.const_thread_area); + if (err != PS_OK) + return TD_ERR; + ta->ta_howto = ta_howto_const_thread_area; + if (ta->ta_howto_data.const_thread_area & 0xff000000U) + ta->ta_howto_data.const_thread_area + = bswap_32 (ta->ta_howto_data.const_thread_area); + } + else + { + switch (sizeof (regs[0])) + { + case 8: + err = td_lookup (ta->ph, SYM_TH_UNIQUE_REGISTER64, &howto); + if (err == PS_OK) + ta->ta_howto = ta_howto_reg; + else if (err == PS_NOSYM) + { + err = td_lookup (ta->ph, + SYM_TH_UNIQUE_REGISTER64_THREAD_AREA, + &howto); + if (err == PS_OK) + ta->ta_howto = ta_howto_reg_thread_area; + } + break; + + case 4: + err = td_lookup (ta->ph, SYM_TH_UNIQUE_REGISTER32, &howto); + if (err == PS_OK) + ta->ta_howto = ta_howto_reg; + else if (err == PS_NOSYM) + { + err = td_lookup (ta->ph, + SYM_TH_UNIQUE_REGISTER32_THREAD_AREA, + &howto); + if (err == PS_OK) + ta->ta_howto = ta_howto_reg_thread_area; + } + break; + + default: + abort (); + return TD_DBERR; + } + + if (err != PS_OK) + return TD_DBERR; + + /* For either of these methods we read in the same descriptor. */ + err = ps_pdread (ta->ph, howto, + ta->ta_howto_data.reg, DB_SIZEOF_DESC); + if (err != PS_OK) + return TD_ERR; + if (DB_DESC_SIZE (ta->ta_howto_data.reg) == 0) + return TD_DBERR; + if (DB_DESC_SIZE (ta->ta_howto_data.reg) & 0xff000000U) + { + /* Byte-swap these words, though we leave the size word + in native order as the handy way to distinguish. */ + DB_DESC_OFFSET (ta->ta_howto_data.reg) + = bswap_32 (DB_DESC_OFFSET (ta->ta_howto_data.reg)); + DB_DESC_NELEM (ta->ta_howto_data.reg) + = bswap_32 (DB_DESC_NELEM (ta->ta_howto_data.reg)); + } + } + } + + switch (ta->ta_howto) + { + case ta_howto_unknown: + return TD_DBERR; + + default: + return TD_DBERR; + + case ta_howto_reg: + /* On most machines, we are just looking at a register. */ + if (ps_lgetregs (ta->ph, lwpid, regs) != PS_OK) + return TD_ERR; + terr = _td_fetch_value_local (ta, ta->ta_howto_data.reg, -1, + 0, regs, &addr); + if (terr != TD_OK) + return terr; + /* In this descriptor the nelem word is overloaded as the bias. */ + addr += (int32_t) DB_DESC_NELEM (ta->ta_howto_data.reg); + th->th_unique = addr; + break; + + case ta_howto_const_thread_area: + /* Some hosts don't have this call and this case won't be used. */ +# pragma weak ps_get_thread_area + if (&ps_get_thread_area == NULL) + return TD_NOCAPAB; + + /* A la x86-64, there is a constant magic index for get_thread_area. */ + if (ps_get_thread_area (ta->ph, lwpid, + ta->ta_howto_data.const_thread_area, + &th->th_unique) != PS_OK) + return TD_ERR; /* XXX Other error value? */ + break; + + case ta_howto_reg_thread_area: + if (&ps_get_thread_area == NULL) + return TD_NOCAPAB; + + /* A la i386, there is a register with an index for get_thread_area. */ + if (ps_lgetregs (ta->ph, lwpid, regs) != PS_OK) + return TD_ERR; + terr = _td_fetch_value_local (ta, ta->ta_howto_data.reg_thread_area, -1, + 0, regs, &addr); + if (terr != TD_OK) + return terr; + /* In this descriptor the nelem word is overloaded as scale factor. */ + if (ps_get_thread_area + (ta->ph, lwpid, + ((addr - (psaddr_t) 0) + >> DB_DESC_NELEM (ta->ta_howto_data.reg_thread_area)), + &th->th_unique) != PS_OK) + return TD_ERR; /* XXX Other error value? */ + break; + } + + /* Found it. Now complete the `td_thrhandle_t' object. */ + th->th_ta_p = (td_thragent_t *) ta; + + return TD_OK; +} diff --git a/libpthread/nptl_db/td_ta_new.c b/libpthread/nptl_db/td_ta_new.c new file mode 100644 index 000000000..f84049af3 --- /dev/null +++ b/libpthread/nptl_db/td_ta_new.c @@ -0,0 +1,65 @@ +/* Attach to target process. + Copyright (C) 1999,2001,2002,2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <version.h> + +#include "thread_dbP.h" + + +/* Datatype for the list of known thread agents. Normally there will + be exactly one so we don't spend much though on making it fast. */ +LIST_HEAD (__td_agent_list); + + +td_err_e +td_ta_new (struct ps_prochandle *ps, td_thragent_t **ta) +{ + psaddr_t versaddr; + char versbuf[sizeof (VERSION)]; + + LOG ("td_ta_new"); + + /* Check whether the versions match. */ + if (td_lookup (ps, SYM_nptl_version, &versaddr) != PS_OK) + return TD_NOLIBTHREAD; + if (ps_pdread (ps, versaddr, versbuf, sizeof (versbuf)) != PS_OK) + return TD_ERR; + + if (memcmp (versbuf, VERSION, sizeof VERSION) != 0) + /* Not the right version. */ + return TD_VERSION; + + /* Fill in the appropriate information. */ + *ta = (td_thragent_t *) calloc (1, sizeof (td_thragent_t)); + if (*ta == NULL) + return TD_MALLOC; + + /* Store the proc handle which we will pass to the callback functions + back into the debugger. */ + (*ta)->ph = ps; + + /* Now add the new agent descriptor to the list. */ + list_add (&(*ta)->list, &__td_agent_list); + + return TD_OK; +} diff --git a/libpthread/nptl_db/td_ta_reset_stats.c b/libpthread/nptl_db/td_ta_reset_stats.c new file mode 100644 index 000000000..ea59d2cda --- /dev/null +++ b/libpthread/nptl_db/td_ta_reset_stats.c @@ -0,0 +1,35 @@ +/* Reset statistics. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_ta_reset_stats (const td_thragent_t *ta) +{ + /* XXX We have to figure out what has to be done. */ + LOG ("td_ta_reset_stats"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + return TD_OK; +} diff --git a/libpthread/nptl_db/td_ta_set_event.c b/libpthread/nptl_db/td_ta_set_event.c new file mode 100644 index 000000000..29fc14bfb --- /dev/null +++ b/libpthread/nptl_db/td_ta_set_event.c @@ -0,0 +1,79 @@ +/* Globally enable events. + Copyright (C) 1999,2001,2002,2003,2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_ta_set_event (ta_arg, event) + const td_thragent_t *ta_arg; + td_thr_events_t *event; +{ + td_thragent_t *const ta = (td_thragent_t *) ta_arg; + td_err_e err; + psaddr_t eventmask = 0; + void *copy = NULL; + + LOG ("td_ta_set_event"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + /* Fetch the old event mask from the inferior and modify it in place. */ + err = DB_GET_SYMBOL (eventmask, ta, __nptl_threads_events); + if (err == TD_OK) + err = DB_GET_STRUCT (copy, ta, eventmask, td_thr_events_t); + if (err == TD_OK) + { + uint32_t idx; + for (idx = 0; idx < TD_EVENTSIZE; ++idx) + { + psaddr_t word; + uint32_t mask; + err = DB_GET_FIELD_LOCAL (word, ta, copy, + td_thr_events_t, event_bits, idx); + if (err != TD_OK) + break; + mask = (uintptr_t) word; + mask |= event->event_bits[idx]; + word = (psaddr_t) (uintptr_t) mask; + err = DB_PUT_FIELD_LOCAL (ta, copy, + td_thr_events_t, event_bits, idx, word); + if (err != TD_OK) + break; + } + if (err == TD_NOAPLIC) + { + err = TD_OK; + while (idx < TD_EVENTSIZE) + if (event->event_bits[idx++] != 0) + { + err = TD_NOEVENT; + break; + } + } + if (err == TD_OK) + /* Now write it back to the inferior. */ + err = DB_PUT_STRUCT (ta, eventmask, td_thr_events_t, copy); + } + + return err; +} diff --git a/libpthread/nptl_db/td_ta_setconcurrency.c b/libpthread/nptl_db/td_ta_setconcurrency.c new file mode 100644 index 000000000..8552ffbe0 --- /dev/null +++ b/libpthread/nptl_db/td_ta_setconcurrency.c @@ -0,0 +1,35 @@ +/* Set suggested concurrency level for process. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_ta_setconcurrency (const td_thragent_t *ta, int level) +{ + /* This is something LinuxThreads does not need to support. */ + LOG ("td_ta_setconcurrency"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + return TD_NOCAPAB; +} diff --git a/libpthread/nptl_db/td_ta_thr_iter.c b/libpthread/nptl_db/td_ta_thr_iter.c new file mode 100644 index 000000000..66e437665 --- /dev/null +++ b/libpthread/nptl_db/td_ta_thr_iter.c @@ -0,0 +1,148 @@ +/* Iterate over a process's threads. + Copyright (C) 1999,2000,2001,2002,2003,2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +static td_err_e +iterate_thread_list (td_thragent_t *ta, td_thr_iter_f *callback, + void *cbdata_p, td_thr_state_e state, int ti_pri, + psaddr_t head, int fake_empty) +{ + td_err_e err; + psaddr_t next, ofs; + void *copy; + + /* Test the state. + XXX This is incomplete. Normally this test should be in the loop. */ + if (state != TD_THR_ANY_STATE) + return TD_OK; + + err = DB_GET_FIELD (next, ta, head, list_t, next, 0); + if (err != TD_OK) + return err; + + if (next == 0 && fake_empty) + { + /* __pthread_initialize_minimal has not run. + There is just the main thread to return. */ + td_thrhandle_t th; + err = td_ta_map_lwp2thr (ta, ps_getpid (ta->ph), &th); + if (err == TD_OK) + err = callback (&th, cbdata_p) != 0 ? TD_DBERR : TD_OK; + return err; + } + + /* Cache the offset from struct pthread to its list_t member. */ + err = DB_GET_FIELD_ADDRESS (ofs, ta, 0, pthread, list, 0); + if (err != TD_OK) + return err; + + if (ta->ta_sizeof_pthread == 0) + { + err = _td_check_sizeof (ta, &ta->ta_sizeof_pthread, SYM_SIZEOF_pthread); + if (err != TD_OK) + return err; + } + copy = __alloca (ta->ta_sizeof_pthread); + + while (next != head) + { + psaddr_t addr, schedpolicy, schedprio; + + addr = next - (ofs - (psaddr_t) 0); + if (next == 0 || addr == 0) /* Sanity check. */ + return TD_DBERR; + + /* Copy the whole descriptor in once so we can access the several + fields locally. Excess copying in one go is much better than + multiple ps_pdread calls. */ + if (ps_pdread (ta->ph, addr, copy, ta->ta_sizeof_pthread) != PS_OK) + return TD_ERR; + + err = DB_GET_FIELD_LOCAL (schedpolicy, ta, copy, pthread, + schedpolicy, 0); + if (err != TD_OK) + break; + err = DB_GET_FIELD_LOCAL (schedprio, ta, copy, pthread, + schedparam_sched_priority, 0); + if (err != TD_OK) + break; + + /* Now test whether this thread matches the specified conditions. */ + + /* Only if the priority level is as high or higher. */ + int descr_pri = ((uintptr_t) schedpolicy == SCHED_OTHER + ? 0 : (uintptr_t) schedprio); + if (descr_pri >= ti_pri) + { + /* Yep, it matches. Call the callback function. */ + td_thrhandle_t th; + th.th_ta_p = (td_thragent_t *) ta; + th.th_unique = addr; + if (callback (&th, cbdata_p) != 0) + return TD_DBERR; + } + + /* Get the pointer to the next element. */ + err = DB_GET_FIELD_LOCAL (next, ta, copy + (ofs - (psaddr_t) 0), list_t, + next, 0); + if (err != TD_OK) + break; + } + + return err; +} + + +td_err_e +td_ta_thr_iter (const td_thragent_t *ta_arg, td_thr_iter_f *callback, + void *cbdata_p, td_thr_state_e state, int ti_pri, + sigset_t *ti_sigmask_p, unsigned int ti_user_flags) +{ + td_thragent_t *const ta = (td_thragent_t *) ta_arg; + td_err_e err; + psaddr_t list = 0; + + LOG ("td_ta_thr_iter"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + /* The thread library keeps two lists for the running threads. One + list contains the thread which are using user-provided stacks + (this includes the main thread) and the other includes the + threads for which the thread library allocated the stacks. We + have to iterate over both lists separately. We start with the + list of threads with user-defined stacks. */ + + err = DB_GET_SYMBOL (list, ta, __stack_user); + if (err == TD_OK) + err = iterate_thread_list (ta, callback, cbdata_p, state, ti_pri, list, 1); + + /* And the threads with stacks allocated by the implementation. */ + if (err == TD_OK) + err = DB_GET_SYMBOL (list, ta, stack_used); + if (err == TD_OK) + err = iterate_thread_list (ta, callback, cbdata_p, state, ti_pri, list, 0); + + return err; +} diff --git a/libpthread/nptl_db/td_ta_tsd_iter.c b/libpthread/nptl_db/td_ta_tsd_iter.c new file mode 100644 index 000000000..9cfb1e8de --- /dev/null +++ b/libpthread/nptl_db/td_ta_tsd_iter.c @@ -0,0 +1,81 @@ +/* Iterate over a process's thread-specific data. + Copyright (C) 1999,2000,2001,2002,2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" +#include <alloca.h> + +td_err_e +td_ta_tsd_iter (const td_thragent_t *ta_arg, td_key_iter_f *callback, + void *cbdata_p) +{ + td_thragent_t *const ta = (td_thragent_t *) ta_arg; + td_err_e err; + void *keys; + size_t keys_nb, keys_elemsize; + psaddr_t addr; + uint32_t idx; + + LOG ("td_ta_tsd_iter"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + /* This makes sure we have the size information on hand. */ + addr = 0; + err = _td_locate_field (ta, + ta->ta_var___pthread_keys, SYM_DESC___pthread_keys, + (psaddr_t) 0 + 1, &addr); + if (err != TD_OK) + return err; + + /* Now copy in the entire array of key descriptors. */ + keys_elemsize = (addr - (psaddr_t) 0) / 8; + keys_nb = keys_elemsize * DB_DESC_NELEM (ta->ta_var___pthread_keys); + keys = __alloca (keys_nb); + err = DB_GET_SYMBOL (addr, ta, __pthread_keys); + if (err != TD_OK) + return err; + if (ps_pdread (ta->ph, addr, keys, keys_nb) != PS_OK) + return TD_ERR; + + /* Now get all descriptors, one after the other. */ + for (idx = 0; idx < DB_DESC_NELEM (ta->ta_var___pthread_keys); ++idx) + { + psaddr_t seq, destr; + err = DB_GET_FIELD_LOCAL (seq, ta, keys, pthread_key_struct, seq, 0); + if (err != TD_OK) + return err; + if (((uintptr_t) seq) & 1) + { + err = DB_GET_FIELD_LOCAL (destr, ta, keys, pthread_key_struct, + destr, 0); + if (err != TD_OK) + return err; + /* Return with an error if the callback returns a nonzero value. */ + if (callback ((thread_key_t) idx, destr, cbdata_p) != 0) + return TD_DBERR; + } + /* Advance to the next element in the copied array. */ + keys += keys_elemsize; + } + + return TD_OK; +} diff --git a/libpthread/nptl_db/td_thr_clear_event.c b/libpthread/nptl_db/td_thr_clear_event.c new file mode 100644 index 000000000..c43c625a4 --- /dev/null +++ b/libpthread/nptl_db/td_thr_clear_event.c @@ -0,0 +1,77 @@ +/* Disable specific event for thread. + Copyright (C) 1999,2001,2002,2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <stddef.h> + +#include "thread_dbP.h" + + +td_err_e +td_thr_clear_event (th, event) + const td_thrhandle_t *th; + td_thr_events_t *event; +{ + td_err_e err; + psaddr_t eventmask; + void *copy = NULL; + + LOG ("td_thr_clear_event"); + + /* Fetch the old event mask from the inferior and modify it in place. */ + err = DB_GET_FIELD_ADDRESS (eventmask, th->th_ta_p, + th->th_unique, pthread, eventbuf_eventmask, 0); + if (err == TD_OK) + err = DB_GET_STRUCT (copy, th->th_ta_p, eventmask, td_thr_events_t); + if (err == TD_OK) + { + uint32_t idx; + for (idx = 0; idx < TD_EVENTSIZE; ++idx) + { + psaddr_t word; + uint32_t mask; + err = DB_GET_FIELD_LOCAL (word, th->th_ta_p, copy, + td_thr_events_t, event_bits, idx); + if (err != TD_OK) + break; + mask = (uintptr_t) word; + mask &= ~event->event_bits[idx]; + word = (psaddr_t) (uintptr_t) mask; + err = DB_PUT_FIELD_LOCAL (th->th_ta_p, copy, + td_thr_events_t, event_bits, idx, word); + if (err != TD_OK) + break; + } + if (err == TD_NOAPLIC) + { + err = TD_OK; + while (idx < TD_EVENTSIZE) + if (event->event_bits[idx++] != 0) + { + err = TD_NOEVENT; + break; + } + } + if (err == TD_OK) + /* Now write it back to the inferior. */ + err = DB_PUT_STRUCT (th->th_ta_p, eventmask, td_thr_events_t, copy); + } + + return err; +} diff --git a/libpthread/nptl_db/td_thr_dbresume.c b/libpthread/nptl_db/td_thr_dbresume.c new file mode 100644 index 000000000..3fd794377 --- /dev/null +++ b/libpthread/nptl_db/td_thr_dbresume.c @@ -0,0 +1,30 @@ +/* Resume execution of given thread. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_thr_dbresume (const td_thrhandle_t *th) +{ + /* XXX We have to figure out what has to be done. */ + LOG ("td_thr_dbresume"); + return TD_NOCAPAB; +} diff --git a/libpthread/nptl_db/td_thr_dbsuspend.c b/libpthread/nptl_db/td_thr_dbsuspend.c new file mode 100644 index 000000000..6ef82ad34 --- /dev/null +++ b/libpthread/nptl_db/td_thr_dbsuspend.c @@ -0,0 +1,30 @@ +/* Suspend execution of given thread. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_thr_dbsuspend (const td_thrhandle_t *th) +{ + /* XXX We have to figure out what has to be done. */ + LOG ("td_thr_dbsuspend"); + return TD_NOCAPAB; +} diff --git a/libpthread/nptl_db/td_thr_event_enable.c b/libpthread/nptl_db/td_thr_event_enable.c new file mode 100644 index 000000000..a02be5da4 --- /dev/null +++ b/libpthread/nptl_db/td_thr_event_enable.c @@ -0,0 +1,34 @@ +/* Enable event process-wide. + Copyright (C) 1999, 2001, 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_thr_event_enable (th, onoff) + const td_thrhandle_t *th; + int onoff; +{ + LOG ("td_thr_event_enable"); + + /* Write the new value into the thread data structure. */ + return DB_PUT_FIELD (th->th_ta_p, th->th_unique, pthread, report_events, 0, + (psaddr_t) 0 + (onoff != 0)); +} diff --git a/libpthread/nptl_db/td_thr_event_getmsg.c b/libpthread/nptl_db/td_thr_event_getmsg.c new file mode 100644 index 000000000..b24fc25d7 --- /dev/null +++ b/libpthread/nptl_db/td_thr_event_getmsg.c @@ -0,0 +1,119 @@ +/* Retrieve event. + Copyright (C) 1999, 2001, 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" +#include <assert.h> + + +td_err_e +td_thr_event_getmsg (const td_thrhandle_t *th, td_event_msg_t *msg) +{ + td_err_e err; + psaddr_t eventbuf, eventnum, eventdata; + psaddr_t thp, prevp; + void *copy = NULL; + + LOG ("td_thr_event_getmsg"); + + /* Copy the event message buffer in from the inferior. */ + err = DB_GET_FIELD_ADDRESS (eventbuf, th->th_ta_p, th->th_unique, pthread, + eventbuf, 0); + if (err == TD_OK) + err = DB_GET_STRUCT (copy, th->th_ta_p, eventbuf, td_eventbuf_t); + if (err != TD_OK) + return err; + + /* Check whether an event occurred. */ + err = DB_GET_FIELD_LOCAL (eventnum, th->th_ta_p, copy, + td_eventbuf_t, eventnum, 0); + if (err != TD_OK) + return err; + if ((int) (uintptr_t) eventnum == TD_EVENT_NONE) + /* Nothing. */ + return TD_NOMSG; + + /* Fill the user's data structure. */ + err = DB_GET_FIELD_LOCAL (eventdata, th->th_ta_p, copy, + td_eventbuf_t, eventdata, 0); + if (err != TD_OK) + return err; + + msg->msg.data = (uintptr_t) eventdata; + msg->event = (uintptr_t) eventnum; + msg->th_p = th; + + /* And clear the event message in the target. */ + memset (copy, 0, th->th_ta_p->ta_sizeof_td_eventbuf_t); + err = DB_PUT_STRUCT (th->th_ta_p, eventbuf, td_eventbuf_t, copy); + if (err != TD_OK) + return err; + + /* Get the pointer to the thread descriptor with the last event. + If it doesn't match TH, then walk down the list until we find it. + We must splice it out of the list so that there is no dangling + pointer to it later when it dies. */ + err = DB_GET_SYMBOL (prevp, th->th_ta_p, __nptl_last_event); + if (err != TD_OK) + return err; + err = DB_GET_VALUE (thp, th->th_ta_p, __nptl_last_event, 0); + if (err != TD_OK) + return err; + + while (thp != 0) + { + psaddr_t next; + err = DB_GET_FIELD (next, th->th_ta_p, th->th_unique, pthread, + nextevent, 0); + if (err != TD_OK) + return err; + + if (next == thp) + return TD_DBERR; + + if (thp == th->th_unique) + { + /* PREVP points at this thread, splice it out. */ + psaddr_t next_nextp; + err = DB_GET_FIELD_ADDRESS (next_nextp, th->th_ta_p, next, pthread, + nextevent, 0); + assert (err == TD_OK); /* We used this field before. */ + if (prevp == next_nextp) + return TD_DBERR; + + err = _td_store_value (th->th_ta_p, + th->th_ta_p->ta_var___nptl_last_event, -1, + 0, prevp, next); + if (err != TD_OK) + return err; + + /* Now clear this thread's own next pointer so it's not dangling + when the thread resumes and then chains on for its next event. */ + return DB_PUT_FIELD (th->th_ta_p, thp, pthread, nextevent, 0, 0); + } + + err = DB_GET_FIELD_ADDRESS (prevp, th->th_ta_p, thp, pthread, + nextevent, 0); + assert (err == TD_OK); /* We used this field before. */ + thp = next; + } + + /* Ack! This should not happen. */ + return TD_DBERR; +} diff --git a/libpthread/nptl_db/td_thr_get_info.c b/libpthread/nptl_db/td_thr_get_info.c new file mode 100644 index 000000000..bb1388804 --- /dev/null +++ b/libpthread/nptl_db/td_thr_get_info.c @@ -0,0 +1,110 @@ +/* Get thread information. + Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <stddef.h> +#include <string.h> +#include "thread_dbP.h" + + +td_err_e +td_thr_get_info (const td_thrhandle_t *th, td_thrinfo_t *infop) +{ + td_err_e err; + void *copy; + psaddr_t tls, schedpolicy, schedprio, cancelhandling, tid, report_events; + + LOG ("td_thr_get_info"); + + /* Copy the whole descriptor in once so we can access the several + fields locally. Excess copying in one go is much better than + multiple ps_pdread calls. */ + err = DB_GET_STRUCT (copy, th->th_ta_p, th->th_unique, pthread); + if (err != TD_OK) + return err; + + err = DB_GET_FIELD_ADDRESS (tls, th->th_ta_p, th->th_unique, + pthread, specific, 0); + if (err != TD_OK) + return err; + + err = DB_GET_FIELD_LOCAL (schedpolicy, th->th_ta_p, copy, pthread, + schedpolicy, 0); + if (err != TD_OK) + return err; + err = DB_GET_FIELD_LOCAL (schedprio, th->th_ta_p, copy, pthread, + schedparam_sched_priority, 0); + if (err != TD_OK) + return err; + err = DB_GET_FIELD_LOCAL (tid, th->th_ta_p, copy, pthread, tid, 0); + if (err != TD_OK) + return err; + err = DB_GET_FIELD_LOCAL (cancelhandling, th->th_ta_p, copy, pthread, + cancelhandling, 0); + if (err != TD_OK) + return err; + err = DB_GET_FIELD_LOCAL (report_events, th->th_ta_p, copy, pthread, + report_events, 0); + if (err != TD_OK) + return err; + + /* Fill in information. Clear first to provide reproducable + results for the fields we do not fill in. */ + memset (infop, '\0', sizeof (td_thrinfo_t)); + + infop->ti_tid = (thread_t) th->th_unique; + infop->ti_tls = (char *) tls; + infop->ti_pri = ((uintptr_t) schedpolicy == SCHED_OTHER + ? 0 : (uintptr_t) schedprio); + infop->ti_type = TD_THR_USER; + + if ((((int) (uintptr_t) cancelhandling) & EXITING_BITMASK) == 0) + /* XXX For now there is no way to get more information. */ + infop->ti_state = TD_THR_ACTIVE; + else if ((((int) (uintptr_t) cancelhandling) & TERMINATED_BITMASK) == 0) + infop->ti_state = TD_THR_ZOMBIE; + else + infop->ti_state = TD_THR_UNKNOWN; + + /* Initialization which are the same in both cases. */ + infop->ti_ta_p = th->th_ta_p; + infop->ti_lid = tid == 0 ? ps_getpid (th->th_ta_p->ph) : (uintptr_t) tid; + infop->ti_traceme = report_events != 0; + + err = DB_GET_FIELD_LOCAL (infop->ti_startfunc, th->th_ta_p, copy, pthread, + start_routine, 0); + if (err == TD_OK) + { + uint32_t idx; + for (idx = 0; idx < TD_EVENTSIZE; ++idx) + { + psaddr_t word; + err = DB_GET_FIELD_LOCAL (word, th->th_ta_p, copy, pthread, + eventbuf_eventmask_event_bits, idx); + if (err != TD_OK) + break; + infop->ti_events.event_bits[idx] = (uintptr_t) word; + } + if (err == TD_NOAPLIC) + memset (&infop->ti_events.event_bits[idx], 0, + (TD_EVENTSIZE - idx) * sizeof infop->ti_events.event_bits[0]); + } + + return err; +} diff --git a/libpthread/nptl_db/td_thr_getfpregs.c b/libpthread/nptl_db/td_thr_getfpregs.c new file mode 100644 index 000000000..7760512eb --- /dev/null +++ b/libpthread/nptl_db/td_thr_getfpregs.c @@ -0,0 +1,53 @@ +/* Get a thread's floating-point register set. + Copyright (C) 1999, 2001, 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_thr_getfpregs (const td_thrhandle_t *th, prfpregset_t *regset) +{ + psaddr_t cancelhandling, tid; + td_err_e err; + + LOG ("td_thr_getfpregs"); + + /* We have to get the state and the PID for this thread. */ + err = DB_GET_FIELD (cancelhandling, th->th_ta_p, th->th_unique, pthread, + cancelhandling, 0); + if (err != TD_OK) + return err; + + /* If the thread already terminated we return all zeroes. */ + if (((int) (uintptr_t) cancelhandling) & TERMINATED_BITMASK) + memset (regset, '\0', sizeof (*regset)); + /* Otherwise get the register content through the callback. */ + else + { + err = DB_GET_FIELD (tid, th->th_ta_p, th->th_unique, pthread, tid, 0); + if (err != TD_OK) + return err; + + if (ps_lgetfpregs (th->th_ta_p->ph, (uintptr_t) tid, regset) != PS_OK) + return TD_ERR; + } + + return TD_OK; +} diff --git a/libpthread/nptl_db/td_thr_getgregs.c b/libpthread/nptl_db/td_thr_getgregs.c new file mode 100644 index 000000000..4c2373ef6 --- /dev/null +++ b/libpthread/nptl_db/td_thr_getgregs.c @@ -0,0 +1,53 @@ +/* Get a thread's general register set. + Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_thr_getgregs (const td_thrhandle_t *th, prgregset_t regset) +{ + psaddr_t cancelhandling, tid; + td_err_e err; + + LOG ("td_thr_getgregs"); + + /* We have to get the state and the PID for this thread. */ + err = DB_GET_FIELD (cancelhandling, th->th_ta_p, th->th_unique, pthread, + cancelhandling, 0); + if (err != TD_OK) + return err; + + /* If the thread already terminated we return all zeroes. */ + if (((int) (uintptr_t) cancelhandling) & TERMINATED_BITMASK) + memset (regset, '\0', sizeof (*regset)); + /* Otherwise get the register content through the callback. */ + else + { + err = DB_GET_FIELD (tid, th->th_ta_p, th->th_unique, pthread, tid, 0); + if (err != TD_OK) + return err; + + if (ps_lgetregs (th->th_ta_p->ph, (uintptr_t) tid, regset) != PS_OK) + return TD_ERR; + } + + return TD_OK; +} diff --git a/libpthread/nptl_db/td_thr_getxregs.c b/libpthread/nptl_db/td_thr_getxregs.c new file mode 100644 index 000000000..3c77ab6be --- /dev/null +++ b/libpthread/nptl_db/td_thr_getxregs.c @@ -0,0 +1,30 @@ +/* Get a thread's extra state register set. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_thr_getxregs (const td_thrhandle_t *th, void *xregs) +{ + /* XXX This might be platform specific. */ + LOG ("td_thr_getxregs"); + return TD_NOXREGS; +} diff --git a/libpthread/nptl_db/td_thr_getxregsize.c b/libpthread/nptl_db/td_thr_getxregsize.c new file mode 100644 index 000000000..1704e4b0a --- /dev/null +++ b/libpthread/nptl_db/td_thr_getxregsize.c @@ -0,0 +1,30 @@ +/* Get the size of the extra state register set for this architecture. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_thr_getxregsize (const td_thrhandle_t *th, int *sizep) +{ + /* XXX This might be platform specific. */ + LOG ("td_thr_getxregsize"); + return TD_NOXREGS; +} diff --git a/libpthread/nptl_db/td_thr_set_event.c b/libpthread/nptl_db/td_thr_set_event.c new file mode 100644 index 000000000..6617147a8 --- /dev/null +++ b/libpthread/nptl_db/td_thr_set_event.c @@ -0,0 +1,77 @@ +/* Enable specific event for thread. + Copyright (C) 1999,2001,2002,2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <stddef.h> + +#include "thread_dbP.h" + + +td_err_e +td_thr_set_event (th, event) + const td_thrhandle_t *th; + td_thr_events_t *event; +{ + td_err_e err; + psaddr_t eventmask; + void *copy = NULL; + + LOG ("td_thr_set_event"); + + /* Fetch the old event mask from the inferior and modify it in place. */ + err = DB_GET_FIELD_ADDRESS (eventmask, th->th_ta_p, + th->th_unique, pthread, eventbuf_eventmask, 0); + if (err == TD_OK) + err = DB_GET_STRUCT (copy, th->th_ta_p, eventmask, td_thr_events_t); + if (err == TD_OK) + { + uint32_t idx; + for (idx = 0; idx < TD_EVENTSIZE; ++idx) + { + psaddr_t word; + uint32_t mask; + err = DB_GET_FIELD_LOCAL (word, th->th_ta_p, copy, + td_thr_events_t, event_bits, idx); + if (err != TD_OK) + break; + mask = (uintptr_t) word; + mask |= event->event_bits[idx]; + word = (psaddr_t) (uintptr_t) mask; + err = DB_PUT_FIELD_LOCAL (th->th_ta_p, copy, + td_thr_events_t, event_bits, idx, word); + if (err != TD_OK) + break; + } + if (err == TD_NOAPLIC) + { + err = TD_OK; + while (idx < TD_EVENTSIZE) + if (event->event_bits[idx++] != 0) + { + err = TD_NOEVENT; + break; + } + } + if (err == TD_OK) + /* Now write it back to the inferior. */ + err = DB_PUT_STRUCT (th->th_ta_p, eventmask, td_thr_events_t, copy); + } + + return err; +} diff --git a/libpthread/nptl_db/td_thr_setfpregs.c b/libpthread/nptl_db/td_thr_setfpregs.c new file mode 100644 index 000000000..01bdb5323 --- /dev/null +++ b/libpthread/nptl_db/td_thr_setfpregs.c @@ -0,0 +1,50 @@ +/* Set a thread's floating-point register set. + Copyright (C) 1999, 2001, 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_thr_setfpregs (const td_thrhandle_t *th, const prfpregset_t *fpregs) +{ + psaddr_t cancelhandling, tid; + td_err_e err; + + LOG ("td_thr_setfpregs"); + + /* We have to get the state and the PID for this thread. */ + err = DB_GET_FIELD (cancelhandling, th->th_ta_p, th->th_unique, pthread, + cancelhandling, 0); + if (err != TD_OK) + return err; + + /* Only set the registers if the thread hasn't yet terminated. */ + if ((((int) (uintptr_t) cancelhandling) & TERMINATED_BITMASK) == 0) + { + err = DB_GET_FIELD (tid, th->th_ta_p, th->th_unique, pthread, tid, 0); + if (err != TD_OK) + return err; + + if (ps_lsetfpregs (th->th_ta_p->ph, (uintptr_t) tid, fpregs) != PS_OK) + return TD_ERR; + } + + return TD_OK; +} diff --git a/libpthread/nptl_db/td_thr_setgregs.c b/libpthread/nptl_db/td_thr_setgregs.c new file mode 100644 index 000000000..2a9ce7e01 --- /dev/null +++ b/libpthread/nptl_db/td_thr_setgregs.c @@ -0,0 +1,50 @@ +/* Set a thread's general register set. + Copyright (C) 1999, 2001, 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_thr_setgregs (const td_thrhandle_t *th, prgregset_t gregs) +{ + psaddr_t cancelhandling, tid; + td_err_e err; + + LOG ("td_thr_setgregs"); + + /* We have to get the state and the PID for this thread. */ + err = DB_GET_FIELD (cancelhandling, th->th_ta_p, th->th_unique, pthread, + cancelhandling, 0); + if (err != TD_OK) + return err; + + /* Only set the registers if the thread hasn't yet terminated. */ + if ((((int) (uintptr_t) cancelhandling) & TERMINATED_BITMASK) == 0) + { + err = DB_GET_FIELD (tid, th->th_ta_p, th->th_unique, pthread, tid, 0); + if (err != TD_OK) + return err; + + if (ps_lsetregs (th->th_ta_p->ph, tid - (psaddr_t) 0, gregs) != PS_OK) + return TD_ERR; + } + + return TD_OK; +} diff --git a/libpthread/nptl_db/td_thr_setprio.c b/libpthread/nptl_db/td_thr_setprio.c new file mode 100644 index 000000000..6032b0ed4 --- /dev/null +++ b/libpthread/nptl_db/td_thr_setprio.c @@ -0,0 +1,30 @@ +/* Set a thread's priority. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_thr_setprio (const td_thrhandle_t *th, int prio) +{ + /* XXX We have to figure out what has to be done. */ + LOG ("td_thr_setprio"); + return TD_OK; +} diff --git a/libpthread/nptl_db/td_thr_setsigpending.c b/libpthread/nptl_db/td_thr_setsigpending.c new file mode 100644 index 000000000..e2c9d7ad2 --- /dev/null +++ b/libpthread/nptl_db/td_thr_setsigpending.c @@ -0,0 +1,31 @@ +/* Raise a signal for a thread. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_thr_setsigpending (const td_thrhandle_t *th, unsigned char n, + const sigset_t *ss) +{ + /* XXX We have to figure out what has to be done. */ + LOG ("td_thr_setsigpending"); + return TD_OK; +} diff --git a/libpthread/nptl_db/td_thr_setxregs.c b/libpthread/nptl_db/td_thr_setxregs.c new file mode 100644 index 000000000..f48877c78 --- /dev/null +++ b/libpthread/nptl_db/td_thr_setxregs.c @@ -0,0 +1,30 @@ +/* Set a thread's extra state register set. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_thr_setxregs (const td_thrhandle_t *ta, const void *addr) +{ + /* XXX This might have to be platform specific. */ + LOG ("td_thr_setxregs"); + return TD_NOXREGS; +} diff --git a/libpthread/nptl_db/td_thr_sigsetmask.c b/libpthread/nptl_db/td_thr_sigsetmask.c new file mode 100644 index 000000000..3a68aecd3 --- /dev/null +++ b/libpthread/nptl_db/td_thr_sigsetmask.c @@ -0,0 +1,30 @@ +/* Set a thread's signal mask. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_thr_sigsetmask (const td_thrhandle_t *th, const sigset_t *ss) +{ + /* XXX We have to figure out what has to be done. */ + LOG ("td_thr_sigsetmask"); + return TD_OK; +} diff --git a/libpthread/nptl_db/td_thr_tls_get_addr.c b/libpthread/nptl_db/td_thr_tls_get_addr.c new file mode 100644 index 000000000..e7d232272 --- /dev/null +++ b/libpthread/nptl_db/td_thr_tls_get_addr.c @@ -0,0 +1,43 @@ +/* Get address of thread local variable. + Copyright (C) 2002,2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <link.h> +#include "thread_dbP.h" + +td_err_e +td_thr_tls_get_addr (const td_thrhandle_t *th, + psaddr_t map_address, size_t offset, psaddr_t *address) +{ + td_err_e err; + psaddr_t modid; + + /* Get the TLS module ID from the `struct link_map' in the inferior. */ + err = DB_GET_FIELD (modid, th->th_ta_p, map_address, link_map, + l_tls_modid, 0); + if (err == TD_NOCAPAB) + return TD_NOAPLIC; + if (err == TD_OK) + { + err = td_thr_tlsbase (th, (uintptr_t) modid, address); + if (err == TD_OK) + *address += offset; + } + return err; +} diff --git a/libpthread/nptl_db/td_thr_tlsbase.c b/libpthread/nptl_db/td_thr_tlsbase.c new file mode 100644 index 000000000..aaeda6f3c --- /dev/null +++ b/libpthread/nptl_db/td_thr_tlsbase.c @@ -0,0 +1,55 @@ +/* Locate TLS data for a thread. + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + +td_err_e +td_thr_tlsbase (const td_thrhandle_t *th, + unsigned long int modid, + psaddr_t *base) +{ + td_err_e err; + psaddr_t dtv, dtvslot, dtvptr; + + if (modid < 1) + return TD_NOTLS; + + /* Get the DTV pointer from the thread descriptor. */ + err = DB_GET_FIELD (dtv, th->th_ta_p, th->th_unique, pthread, dtvp, 0); + if (err != TD_OK) + return err; + + /* Find the corresponding entry in the DTV. */ + err = DB_GET_FIELD_ADDRESS (dtvslot, th->th_ta_p, dtv, dtv, dtv, modid); + if (err != TD_OK) + return err; + + /* Extract the TLS block address from that DTV slot. */ + err = DB_GET_FIELD (dtvptr, th->th_ta_p, dtvslot, dtv_t, pointer_val, 0); + if (err != TD_OK) + return err; + + /* It could be that the memory for this module is not allocated for + the given thread. */ + if ((uintptr_t) dtvptr & 1) + return TD_TLSDEFER; + + *base = dtvptr; + return TD_OK; +} diff --git a/libpthread/nptl_db/td_thr_tsd.c b/libpthread/nptl_db/td_thr_tsd.c new file mode 100644 index 000000000..08f617b7d --- /dev/null +++ b/libpthread/nptl_db/td_thr_tsd.c @@ -0,0 +1,96 @@ +/* Get a thread-specific data pointer for a thread. + Copyright (C) 1999,2001,2002,2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_thr_tsd (const td_thrhandle_t *th, const thread_key_t tk, void **data) +{ + td_err_e err; + psaddr_t tk_seq, level1, level2, seq, value; + void *copy; + uint32_t pthread_key_2ndlevel_size, idx1st, idx2nd; + + LOG ("td_thr_tsd"); + + /* Get the key entry. */ + err = DB_GET_VALUE (tk_seq, th->th_ta_p, __pthread_keys, tk); + if (err == TD_NOAPLIC) + return TD_BADKEY; + if (err != TD_OK) + return err; + + /* Fail if this key is not at all used. */ + if (((uintptr_t) tk_seq & 1) == 0) + return TD_BADKEY; + + /* This makes sure we have the size information on hand. */ + err = DB_GET_FIELD_ADDRESS (level2, th->th_ta_p, 0, pthread_key_data_level2, + data, 1); + if (err != TD_OK) + return err; + + /* Compute the indeces. */ + pthread_key_2ndlevel_size + = DB_DESC_NELEM (th->th_ta_p->ta_field_pthread_key_data_level2_data); + idx1st = tk / pthread_key_2ndlevel_size; + idx2nd = tk % pthread_key_2ndlevel_size; + + /* Now fetch the first level pointer. */ + err = DB_GET_FIELD (level1, th->th_ta_p, th->th_unique, pthread, + specific, idx1st); + if (err == TD_NOAPLIC) + return TD_DBERR; + if (err != TD_OK) + return err; + + /* Check the pointer to the second level array. */ + if (level1 == 0) + return TD_NOTSD; + + /* Locate the element within the second level array. */ + err = DB_GET_FIELD_ADDRESS (level2, th->th_ta_p, + level1, pthread_key_data_level2, data, idx2nd); + if (err == TD_NOAPLIC) + return TD_DBERR; + if (err != TD_OK) + return err; + + /* Now copy in that whole structure. */ + err = DB_GET_STRUCT (copy, th->th_ta_p, level2, pthread_key_data); + if (err != TD_OK) + return err; + + /* Check whether the data is valid. */ + err = DB_GET_FIELD_LOCAL (seq, th->th_ta_p, copy, pthread_key_data, seq, 0); + if (err != TD_OK) + return err; + if (seq != tk_seq) + return TD_NOTSD; + + /* Finally, fetch the value. */ + err = DB_GET_FIELD_LOCAL (value, th->th_ta_p, copy, pthread_key_data, + data, 0); + if (err == TD_OK) + *data = value; + + return err; +} diff --git a/libpthread/nptl_db/td_thr_validate.c b/libpthread/nptl_db/td_thr_validate.c new file mode 100644 index 000000000..19ee940d6 --- /dev/null +++ b/libpthread/nptl_db/td_thr_validate.c @@ -0,0 +1,91 @@ +/* Validate a thread handle. + Copyright (C) 1999, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" +#include <stdbool.h> + +static td_err_e +check_thread_list (const td_thrhandle_t *th, psaddr_t head, bool *uninit) +{ + td_err_e err; + psaddr_t next, ofs; + + err = DB_GET_FIELD (next, th->th_ta_p, head, list_t, next, 0); + if (err == TD_OK) + { + if (next == 0) + { + *uninit = true; + return TD_NOTHR; + } + err = DB_GET_FIELD_ADDRESS (ofs, th->th_ta_p, 0, pthread, list, 0); + } + + while (err == TD_OK) + { + if (next == head) + return TD_NOTHR; + + if (next - (ofs - (psaddr_t) 0) == th->th_unique) + return TD_OK; + + err = DB_GET_FIELD (next, th->th_ta_p, next, list_t, next, 0); + } + + return err; +} + + +td_err_e +td_thr_validate (const td_thrhandle_t *th) +{ + td_err_e err; + psaddr_t list = NULL; + + LOG ("td_thr_validate"); + + /* First check the list with threads using user allocated stacks. */ + bool uninit = false; + err = DB_GET_SYMBOL (list, th->th_ta_p, __stack_user); + if (err == TD_OK) + err = check_thread_list (th, list, &uninit); + + /* If our thread is not on this list search the list with stack + using implementation allocated stacks. */ + if (err == TD_NOTHR) + { + err = DB_GET_SYMBOL (list, th->th_ta_p, stack_used); + if (err == TD_OK) + err = check_thread_list (th, list, &uninit); + + if (err == TD_NOTHR && uninit) + { + /* __pthread_initialize_minimal has not run yet. + But the main thread still has a valid ID. */ + td_thrhandle_t main_th; + err = td_ta_map_lwp2thr (th->th_ta_p, + ps_getpid (th->th_ta_p->ph), &main_th); + if (err == TD_OK && th->th_unique != main_th.th_unique) + err = TD_NOTHR; + } + } + + return err; +} diff --git a/libpthread/nptl_db/thread_db.h b/libpthread/nptl_db/thread_db.h new file mode 100644 index 000000000..433b54fd5 --- /dev/null +++ b/libpthread/nptl_db/thread_db.h @@ -0,0 +1,459 @@ +/* thread_db.h -- interface to libthread_db.so library for debugging -lpthread + Copyright (C) 1999,2001,2002,2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _THREAD_DB_H +#define _THREAD_DB_H 1 + +/* This is the debugger interface for the NPTL library. It is + modelled closely after the interface with same names in Solaris + with the goal to share the same code in the debugger. */ +#include <pthread.h> +#include <stdint.h> +#include <sys/types.h> +#include <sys/procfs.h> + + +/* Error codes of the library. */ +typedef enum +{ + TD_OK, /* No error. */ + TD_ERR, /* No further specified error. */ + TD_NOTHR, /* No matching thread found. */ + TD_NOSV, /* No matching synchronization handle found. */ + TD_NOLWP, /* No matching light-weighted process found. */ + TD_BADPH, /* Invalid process handle. */ + TD_BADTH, /* Invalid thread handle. */ + TD_BADSH, /* Invalid synchronization handle. */ + TD_BADTA, /* Invalid thread agent. */ + TD_BADKEY, /* Invalid key. */ + TD_NOMSG, /* No event available. */ + TD_NOFPREGS, /* No floating-point register content available. */ + TD_NOLIBTHREAD, /* Application not linked with thread library. */ + TD_NOEVENT, /* Requested event is not supported. */ + TD_NOCAPAB, /* Capability not available. */ + TD_DBERR, /* Internal debug library error. */ + TD_NOAPLIC, /* Operation is not applicable. */ + TD_NOTSD, /* No thread-specific data available. */ + TD_MALLOC, /* Out of memory. */ + TD_PARTIALREG, /* Not entire register set was read or written. */ + TD_NOXREGS, /* X register set not available for given thread. */ + TD_TLSDEFER, /* Thread has not yet allocated TLS for given module. */ + TD_NOTALLOC = TD_TLSDEFER, + TD_VERSION, /* Version if libpthread and libthread_db do not match. */ + TD_NOTLS /* There is no TLS segment in the given module. */ +} td_err_e; + + +/* Possible thread states. TD_THR_ANY_STATE is a pseudo-state used to + select threads regardless of state in td_ta_thr_iter(). */ +typedef enum +{ + TD_THR_ANY_STATE, + TD_THR_UNKNOWN, + TD_THR_STOPPED, + TD_THR_RUN, + TD_THR_ACTIVE, + TD_THR_ZOMBIE, + TD_THR_SLEEP, + TD_THR_STOPPED_ASLEEP +} td_thr_state_e; + +/* Thread type: user or system. TD_THR_ANY_TYPE is a pseudo-type used + to select threads regardless of type in td_ta_thr_iter(). */ +typedef enum +{ + TD_THR_ANY_TYPE, + TD_THR_USER, + TD_THR_SYSTEM +} td_thr_type_e; + + +/* Types of the debugging library. */ + +/* Handle for a process. This type is opaque. */ +typedef struct td_thragent td_thragent_t; + +/* The actual thread handle type. This is also opaque. */ +typedef struct td_thrhandle +{ + td_thragent_t *th_ta_p; + psaddr_t th_unique; +} td_thrhandle_t; + + +/* Forward declaration of a type defined by and for the dynamic linker. */ +struct link_map; + + +/* Flags for `td_ta_thr_iter'. */ +#define TD_THR_ANY_USER_FLAGS 0xffffffff +#define TD_THR_LOWEST_PRIORITY -20 +#define TD_SIGNO_MASK NULL + + +#define TD_EVENTSIZE 2 +#define BT_UISHIFT 5 /* log base 2 of BT_NBIPUI, to extract word index */ +#define BT_NBIPUI (1 << BT_UISHIFT) /* n bits per uint */ +#define BT_UIMASK (BT_NBIPUI - 1) /* to extract bit index */ + +/* Bitmask of enabled events. */ +typedef struct td_thr_events +{ + uint32_t event_bits[TD_EVENTSIZE]; +} td_thr_events_t; + +/* Event set manipulation macros. */ +#define __td_eventmask(n) \ + (UINT32_C (1) << (((n) - 1) & BT_UIMASK)) +#define __td_eventword(n) \ + ((UINT32_C ((n) - 1)) >> BT_UISHIFT) + +#define td_event_emptyset(setp) \ + do { \ + int __i; \ + for (__i = TD_EVENTSIZE; __i > 0; --__i) \ + (setp)->event_bits[__i - 1] = 0; \ + } while (0) + +#define td_event_fillset(setp) \ + do { \ + int __i; \ + for (__i = TD_EVENTSIZE; __i > 0; --__i) \ + (setp)->event_bits[__i - 1] = UINT32_C (0xffffffff); \ + } while (0) + +#define td_event_addset(setp, n) \ + (((setp)->event_bits[__td_eventword (n)]) |= __td_eventmask (n)) +#define td_event_delset(setp, n) \ + (((setp)->event_bits[__td_eventword (n)]) &= ~__td_eventmask (n)) +#define td_eventismember(setp, n) \ + (__td_eventmask (n) & ((setp)->event_bits[__td_eventword (n)])) +#if TD_EVENTSIZE == 2 +# define td_eventisempty(setp) \ + (!((setp)->event_bits[0]) && !((setp)->event_bits[1])) +#else +# error "td_eventisempty must be changed to match TD_EVENTSIZE" +#endif + +/* Events reportable by the thread implementation. */ +typedef enum +{ + TD_ALL_EVENTS, /* Pseudo-event number. */ + TD_EVENT_NONE = TD_ALL_EVENTS, /* Depends on context. */ + TD_READY, /* Is executable now. */ + TD_SLEEP, /* Blocked in a synchronization obj. */ + TD_SWITCHTO, /* Now assigned to a process. */ + TD_SWITCHFROM, /* Not anymore assigned to a process. */ + TD_LOCK_TRY, /* Trying to get an unavailable lock. */ + TD_CATCHSIG, /* Signal posted to the thread. */ + TD_IDLE, /* Process getting idle. */ + TD_CREATE, /* New thread created. */ + TD_DEATH, /* Thread terminated. */ + TD_PREEMPT, /* Preempted. */ + TD_PRI_INHERIT, /* Inherited elevated priority. */ + TD_REAP, /* Reaped. */ + TD_CONCURRENCY, /* Number of processes changing. */ + TD_TIMEOUT, /* Conditional variable wait timed out. */ + TD_MIN_EVENT_NUM = TD_READY, + TD_MAX_EVENT_NUM = TD_TIMEOUT, + TD_EVENTS_ENABLE = 31 /* Event reporting enabled. */ +} td_event_e; + +/* Values representing the different ways events are reported. */ +typedef enum +{ + NOTIFY_BPT, /* User must insert breakpoint at u.bptaddr. */ + NOTIFY_AUTOBPT, /* Breakpoint at u.bptaddr is automatically + inserted. */ + NOTIFY_SYSCALL /* System call u.syscallno will be invoked. */ +} td_notify_e; + +/* Description how event type is reported. */ +typedef struct td_notify +{ + td_notify_e type; /* Way the event is reported. */ + union + { + psaddr_t bptaddr; /* Address of breakpoint. */ + int syscallno; /* Number of system call used. */ + } u; +} td_notify_t; + +/* Structure used to report event. */ +typedef struct td_event_msg +{ + td_event_e event; /* Event type being reported. */ + const td_thrhandle_t *th_p; /* Thread reporting the event. */ + union + { +# if 0 + td_synchandle_t *sh; /* Handle of synchronization object. */ +#endif + uintptr_t data; /* Event specific data. */ + } msg; +} td_event_msg_t; + +/* Structure containing event data available in each thread structure. */ +typedef struct +{ + td_thr_events_t eventmask; /* Mask of enabled events. */ + td_event_e eventnum; /* Number of last event. */ + void *eventdata; /* Data associated with event. */ +} td_eventbuf_t; + + +/* Gathered statistics about the process. */ +typedef struct td_ta_stats +{ + int nthreads; /* Total number of threads in use. */ + int r_concurrency; /* Concurrency level requested by user. */ + int nrunnable_num; /* Average runnable threads, numerator. */ + int nrunnable_den; /* Average runnable threads, denominator. */ + int a_concurrency_num; /* Achieved concurrency level, numerator. */ + int a_concurrency_den; /* Achieved concurrency level, denominator. */ + int nlwps_num; /* Average number of processes in use, + numerator. */ + int nlwps_den; /* Average number of processes in use, + denominator. */ + int nidle_num; /* Average number of idling processes, + numerator. */ + int nidle_den; /* Average number of idling processes, + denominator. */ +} td_ta_stats_t; + + +/* Since Sun's library is based on Solaris threads we have to define a few + types to map them to POSIX threads. */ +typedef pthread_t thread_t; +typedef pthread_key_t thread_key_t; + + +/* Callback for iteration over threads. */ +typedef int td_thr_iter_f (const td_thrhandle_t *, void *); + +/* Callback for iteration over thread local data. */ +typedef int td_key_iter_f (thread_key_t, void (*) (void *), void *); + + + +/* Forward declaration. This has to be defined by the user. */ +struct ps_prochandle; + + +/* Information about the thread. */ +typedef struct td_thrinfo +{ + td_thragent_t *ti_ta_p; /* Process handle. */ + unsigned int ti_user_flags; /* Unused. */ + thread_t ti_tid; /* Thread ID returned by + pthread_create(). */ + char *ti_tls; /* Pointer to thread-local data. */ + psaddr_t ti_startfunc; /* Start function passed to + pthread_create(). */ + psaddr_t ti_stkbase; /* Base of thread's stack. */ + long int ti_stksize; /* Size of thread's stack. */ + psaddr_t ti_ro_area; /* Unused. */ + int ti_ro_size; /* Unused. */ + td_thr_state_e ti_state; /* Thread state. */ + unsigned char ti_db_suspended; /* Nonzero if suspended by debugger. */ + td_thr_type_e ti_type; /* Type of the thread (system vs + user thread). */ + intptr_t ti_pc; /* Unused. */ + intptr_t ti_sp; /* Unused. */ + short int ti_flags; /* Unused. */ + int ti_pri; /* Thread priority. */ + lwpid_t ti_lid; /* Kernel PID for this thread. */ + sigset_t ti_sigmask; /* Signal mask. */ + unsigned char ti_traceme; /* Nonzero if event reporting + enabled. */ + unsigned char ti_preemptflag; /* Unused. */ + unsigned char ti_pirecflag; /* Unused. */ + sigset_t ti_pending; /* Set of pending signals. */ + td_thr_events_t ti_events; /* Set of enabled events. */ +} td_thrinfo_t; + + + +/* Prototypes for exported library functions. */ + +/* Initialize the thread debug support library. */ +extern td_err_e td_init (void); + +/* Historical relict. Should not be used anymore. */ +extern td_err_e td_log (void); + +/* Return list of symbols the library can request. */ +extern const char **td_symbol_list (void); + +/* Generate new thread debug library handle for process PS. */ +extern td_err_e td_ta_new (struct ps_prochandle *__ps, td_thragent_t **__ta); + +/* Free resources allocated for TA. */ +extern td_err_e td_ta_delete (td_thragent_t *__ta); + +/* Get number of currently running threads in process associated with TA. */ +extern td_err_e td_ta_get_nthreads (const td_thragent_t *__ta, int *__np); + +/* Return process handle passed in `td_ta_new' for process associated with + TA. */ +extern td_err_e td_ta_get_ph (const td_thragent_t *__ta, + struct ps_prochandle **__ph); + +/* Map thread library handle PT to thread debug library handle for process + associated with TA and store result in *TH. */ +extern td_err_e td_ta_map_id2thr (const td_thragent_t *__ta, pthread_t __pt, + td_thrhandle_t *__th); + +/* Map process ID LWPID to thread debug library handle for process + associated with TA and store result in *TH. */ +extern td_err_e td_ta_map_lwp2thr (const td_thragent_t *__ta, lwpid_t __lwpid, + td_thrhandle_t *__th); + + +/* Call for each thread in a process associated with TA the callback function + CALLBACK. */ +extern td_err_e td_ta_thr_iter (const td_thragent_t *__ta, + td_thr_iter_f *__callback, void *__cbdata_p, + td_thr_state_e __state, int __ti_pri, + sigset_t *__ti_sigmask_p, + unsigned int __ti_user_flags); + +/* Call for each defined thread local data entry the callback function KI. */ +extern td_err_e td_ta_tsd_iter (const td_thragent_t *__ta, td_key_iter_f *__ki, + void *__p); + + +/* Get event address for EVENT. */ +extern td_err_e td_ta_event_addr (const td_thragent_t *__ta, + td_event_e __event, td_notify_t *__ptr); + +/* Enable EVENT in global mask. */ +extern td_err_e td_ta_set_event (const td_thragent_t *__ta, + td_thr_events_t *__event); + +/* Disable EVENT in global mask. */ +extern td_err_e td_ta_clear_event (const td_thragent_t *__ta, + td_thr_events_t *__event); + +/* Return information about last event. */ +extern td_err_e td_ta_event_getmsg (const td_thragent_t *__ta, + td_event_msg_t *__msg); + + +/* Set suggested concurrency level for process associated with TA. */ +extern td_err_e td_ta_setconcurrency (const td_thragent_t *__ta, int __level); + + +/* Enable collecting statistics for process associated with TA. */ +extern td_err_e td_ta_enable_stats (const td_thragent_t *__ta, int __enable); + +/* Reset statistics. */ +extern td_err_e td_ta_reset_stats (const td_thragent_t *__ta); + +/* Retrieve statistics from process associated with TA. */ +extern td_err_e td_ta_get_stats (const td_thragent_t *__ta, + td_ta_stats_t *__statsp); + + +/* Validate that TH is a thread handle. */ +extern td_err_e td_thr_validate (const td_thrhandle_t *__th); + +/* Return information about thread TH. */ +extern td_err_e td_thr_get_info (const td_thrhandle_t *__th, + td_thrinfo_t *__infop); + +/* Retrieve floating-point register contents of process running thread TH. */ +extern td_err_e td_thr_getfpregs (const td_thrhandle_t *__th, + prfpregset_t *__regset); + +/* Retrieve general register contents of process running thread TH. */ +extern td_err_e td_thr_getgregs (const td_thrhandle_t *__th, + prgregset_t __gregs); + +/* Retrieve extended register contents of process running thread TH. */ +extern td_err_e td_thr_getxregs (const td_thrhandle_t *__th, void *__xregs); + +/* Get size of extended register set of process running thread TH. */ +extern td_err_e td_thr_getxregsize (const td_thrhandle_t *__th, int *__sizep); + +/* Set floating-point register contents of process running thread TH. */ +extern td_err_e td_thr_setfpregs (const td_thrhandle_t *__th, + const prfpregset_t *__fpregs); + +/* Set general register contents of process running thread TH. */ +extern td_err_e td_thr_setgregs (const td_thrhandle_t *__th, + prgregset_t __gregs); + +/* Set extended register contents of process running thread TH. */ +extern td_err_e td_thr_setxregs (const td_thrhandle_t *__th, + const void *__addr); + + +/* Get address of the given module's TLS storage area for the given thread. */ +extern td_err_e td_thr_tlsbase (const td_thrhandle_t *__th, + unsigned long int __modid, + psaddr_t *__base); + +/* Get address of thread local variable. */ +extern td_err_e td_thr_tls_get_addr (const td_thrhandle_t *__th, + psaddr_t __map_address, size_t __offset, + psaddr_t *__address); + + +/* Enable reporting for EVENT for thread TH. */ +extern td_err_e td_thr_event_enable (const td_thrhandle_t *__th, int __event); + +/* Enable EVENT for thread TH. */ +extern td_err_e td_thr_set_event (const td_thrhandle_t *__th, + td_thr_events_t *__event); + +/* Disable EVENT for thread TH. */ +extern td_err_e td_thr_clear_event (const td_thrhandle_t *__th, + td_thr_events_t *__event); + +/* Get event message for thread TH. */ +extern td_err_e td_thr_event_getmsg (const td_thrhandle_t *__th, + td_event_msg_t *__msg); + + +/* Set priority of thread TH. */ +extern td_err_e td_thr_setprio (const td_thrhandle_t *__th, int __prio); + + +/* Set pending signals for thread TH. */ +extern td_err_e td_thr_setsigpending (const td_thrhandle_t *__th, + unsigned char __n, const sigset_t *__ss); + +/* Set signal mask for thread TH. */ +extern td_err_e td_thr_sigsetmask (const td_thrhandle_t *__th, + const sigset_t *__ss); + + +/* Return thread local data associated with key TK in thread TH. */ +extern td_err_e td_thr_tsd (const td_thrhandle_t *__th, + const thread_key_t __tk, void **__data); + + +/* Suspend execution of thread TH. */ +extern td_err_e td_thr_dbsuspend (const td_thrhandle_t *__th); + +/* Resume execution of thread TH. */ +extern td_err_e td_thr_dbresume (const td_thrhandle_t *__th); + +#endif /* thread_db.h */ diff --git a/libpthread/nptl_db/thread_dbP.h b/libpthread/nptl_db/thread_dbP.h new file mode 100644 index 000000000..c3d263b0c --- /dev/null +++ b/libpthread/nptl_db/thread_dbP.h @@ -0,0 +1,258 @@ +/* Private header for thread debug library + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _THREAD_DBP_H +#define _THREAD_DBP_H 1 + +#include <stdbool.h> +#include <stdint.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <assert.h> +#include "proc_service.h" +#include "thread_db.h" +#include "../nptl/pthreadP.h" /* This is for *_BITMASK only. */ + +#ifdef __UCLIBC__ +#define __alloca alloca +#endif + +/* Indeces for the symbol names. */ +enum + { +# define DB_STRUCT(type) SYM_SIZEOF_##type, +# define DB_STRUCT_FIELD(type, field) SYM_##type##_FIELD_##field, +# define DB_SYMBOL(name) SYM_##name, +# define DB_FUNCTION(name) SYM_##name, +# define DB_VARIABLE(name) SYM_##name, SYM_DESC_##name, +# include "structs.def" +# undef DB_STRUCT +# undef DB_STRUCT_FIELD +# undef DB_SYMBOL +# undef DB_FUNCTION +# undef DB_VARIABLE + + SYM_TH_UNIQUE_CONST_THREAD_AREA, + SYM_TH_UNIQUE_REGISTER64, + SYM_TH_UNIQUE_REGISTER32, + SYM_TH_UNIQUE_REGISTER64_THREAD_AREA, + SYM_TH_UNIQUE_REGISTER32_THREAD_AREA, + + SYM_NUM_MESSAGES + }; + + +/* Comment out the following for less verbose output. */ +#ifndef NDEBUG +# define LOG(c) if (__td_debug) write (2, c "\n", strlen (c "\n")) +extern int __td_debug attribute_hidden; +#else +# define LOG(c) +#endif + + +#define DB_DESC_SIZE(desc) ((desc)[0]) +#define DB_DESC_NELEM(desc) ((desc)[1]) +#define DB_DESC_OFFSET(desc) ((desc)[2]) +#define DB_SIZEOF_DESC (3 * sizeof (uint32_t)) +#define DB_DEFINE_DESC(name, size, nelem, offset) \ + const uint32_t name[3] = { (size), (nelem), (offset) } +typedef uint32_t db_desc_t[3]; + + +/* Handle for a process. This type is opaque. */ +struct td_thragent +{ + /* Chain on the list of all agent structures. */ + list_t list; + + /* Delivered by the debugger and we have to pass it back in the + proc callbacks. */ + struct ps_prochandle *ph; + + /* Cached values read from the inferior. */ +# define DB_STRUCT(type) \ + uint32_t ta_sizeof_##type; +# define DB_STRUCT_FIELD(type, field) \ + db_desc_t ta_field_##type##_##field; +# define DB_SYMBOL(name) \ + psaddr_t ta_addr_##name; +# define DB_FUNCTION(name) \ + psaddr_t ta_addr_##name; +# define DB_VARIABLE(name) \ + psaddr_t ta_addr_##name; \ + db_desc_t ta_var_##name; +# include "structs.def" +# undef DB_STRUCT +# undef DB_STRUCT_FIELD +# undef DB_FUNCTION +# undef DB_SYMBOL +# undef DB_VARIABLE + + /* The method of locating a thread's th_unique value. */ + enum + { + ta_howto_unknown, + ta_howto_reg, + ta_howto_reg_thread_area, + ta_howto_const_thread_area + } ta_howto; + union + { + uint32_t const_thread_area; /* Constant argument to ps_get_thread_area. */ + /* These are as if the descriptor of the field in prregset_t, + but DB_DESC_NELEM is overloaded as follows: */ + db_desc_t reg; /* Signed bias applied to register value. */ + db_desc_t reg_thread_area; /* Bits to scale down register value. */ + } ta_howto_data; +}; + + +/* List of all known descriptors. */ +extern list_t __td_agent_list attribute_hidden; + + +/* Function used to test for correct thread agent pointer. */ +static inline bool +ta_ok (const td_thragent_t *ta) +{ + list_t *runp; + + list_for_each (runp, &__td_agent_list) + if (list_entry (runp, td_thragent_t, list) == ta) + return true; + + return false; +} + + +/* Internal wrapper around ps_pglobal_lookup. */ +extern ps_err_e td_lookup (struct ps_prochandle *ps, + int idx, psaddr_t *sym_addr) attribute_hidden; + + + + +/* Store in psaddr_t VAR the address of inferior's symbol NAME. */ +#define DB_GET_SYMBOL(var, ta, name) \ + (((ta)->ta_addr_##name == 0 \ + && td_lookup ((ta)->ph, SYM_##name, &(ta)->ta_addr_##name) != PS_OK) \ + ? TD_ERR : ((var) = (ta)->ta_addr_##name, TD_OK)) + +/* Store in psaddr_t VAR the value of ((TYPE) PTR)->FIELD[IDX] in the inferior. + A target field smaller than psaddr_t is zero-extended. */ +#define DB_GET_FIELD(var, ta, ptr, type, field, idx) \ + _td_fetch_value ((ta), (ta)->ta_field_##type##_##field, \ + SYM_##type##_FIELD_##field, \ + (psaddr_t) 0 + (idx), (ptr), &(var)) + +#define DB_GET_FIELD_ADDRESS(var, ta, ptr, type, field, idx) \ + ((var) = (ptr), _td_locate_field ((ta), (ta)->ta_field_##type##_##field, \ + SYM_##type##_FIELD_##field, \ + (psaddr_t) 0 + (idx), &(var))) + +extern td_err_e _td_locate_field (td_thragent_t *ta, + db_desc_t desc, int descriptor_name, + psaddr_t idx, + psaddr_t *address) attribute_hidden; + + +/* Like DB_GET_FIELD, but PTR is a local pointer to a structure that + has already been copied in from the inferior. */ +#define DB_GET_FIELD_LOCAL(var, ta, ptr, type, field, idx) \ + _td_fetch_value_local ((ta), (ta)->ta_field_##type##_##field, \ + SYM_##type##_FIELD_##field, \ + (psaddr_t) 0 + (idx), (ptr), &(var)) + +/* Store in psaddr_t VAR the value of variable NAME[IDX] in the inferior. + A target value smaller than psaddr_t is zero-extended. */ +#define DB_GET_VALUE(var, ta, name, idx) \ + (((ta)->ta_addr_##name == 0 \ + && td_lookup ((ta)->ph, SYM_##name, &(ta)->ta_addr_##name) != PS_OK) \ + ? TD_ERR \ + : _td_fetch_value ((ta), (ta)->ta_var_##name, SYM_DESC_##name, \ + (psaddr_t) 0 + (idx), (ta)->ta_addr_##name, &(var))) + +/* Helper functions for those. */ +extern td_err_e _td_fetch_value (td_thragent_t *ta, + db_desc_t field, int descriptor_name, + psaddr_t idx, psaddr_t address, + psaddr_t *result) attribute_hidden; +extern td_err_e _td_fetch_value_local (td_thragent_t *ta, + db_desc_t field, + int descriptor_name, + psaddr_t idx, void *address, + psaddr_t *result) attribute_hidden; + +/* Store psaddr_t VALUE in ((TYPE) PTR)->FIELD[IDX] in the inferior. + A target field smaller than psaddr_t is zero-extended. */ +#define DB_PUT_FIELD(ta, ptr, type, field, idx, value) \ + _td_store_value ((ta), (ta)->ta_field_##type##_##field, \ + SYM_##type##_FIELD_##field, \ + (psaddr_t) 0 + (idx), (ptr), (value)) + +#define DB_PUT_FIELD_LOCAL(ta, ptr, type, field, idx, value) \ + _td_store_value_local ((ta), (ta)->ta_field_##type##_##field, \ + SYM_##type##_FIELD_##field, \ + (psaddr_t) 0 + (idx), (ptr), (value)) + +/* Store psaddr_t VALUE in variable NAME[IDX] in the inferior. + A target field smaller than psaddr_t is zero-extended. */ +#define DB_PUT_VALUE(ta, name, idx, value) \ + (((ta)->ta_addr_##name == 0 \ + && td_lookup ((ta)->ph, SYM_##name, &(ta)->ta_addr_##name) != PS_OK) \ + ? TD_ERR \ + : _td_store_value ((ta), (ta)->ta_var_##name, SYM_DESC_##name, \ + (psaddr_t) 0 + (idx), (ta)->ta_addr_##name, (value))) + +/* Helper functions for those. */ +extern td_err_e _td_store_value (td_thragent_t *ta, + db_desc_t field, int descriptor_name, + psaddr_t idx, psaddr_t address, + psaddr_t value) attribute_hidden; +extern td_err_e _td_store_value_local (td_thragent_t *ta, + db_desc_t field, int descriptor_name, + psaddr_t idx, void *address, + psaddr_t value) attribute_hidden; + +#define DB_GET_STRUCT(var, ta, ptr, type) \ + ({ td_err_e _err = TD_OK; \ + if ((ta)->ta_sizeof_##type == 0) \ + _err = _td_check_sizeof ((ta), &(ta)->ta_sizeof_##type, \ + SYM_SIZEOF_##type); \ + if (_err == TD_OK) \ + _err = ps_pdread ((ta)->ph, (ptr), \ + (var) = __alloca ((ta)->ta_sizeof_##type), \ + (ta)->ta_sizeof_##type) \ + == PS_OK ? TD_OK : TD_ERR; \ + else \ + (var) = NULL; \ + _err; \ + }) +#define DB_PUT_STRUCT(ta, ptr, type, copy) \ + ({ assert ((ta)->ta_sizeof_##type != 0); \ + ps_pdwrite ((ta)->ph, (ptr), (copy), (ta)->ta_sizeof_##type) \ + == PS_OK ? TD_OK : TD_ERR; \ + }) + +extern td_err_e _td_check_sizeof (td_thragent_t *ta, uint32_t *sizep, + int sizep_name) attribute_hidden; + +#endif /* thread_dbP.h */ |