diff options
author | Ulrich Drepper <drepper@redhat.com> | 2004-12-22 20:10:10 +0000 |
---|---|---|
committer | Ulrich Drepper <drepper@redhat.com> | 2004-12-22 20:10:10 +0000 |
commit | a334319f6530564d22e775935d9c91663623a1b4 (patch) | |
tree | b5877475619e4c938e98757d518bb1e9cbead751 /linuxthreads | |
parent | 0ecb606cb6cf65de1d9fc8a919bceb4be476c602 (diff) | |
download | glibc-a334319f6530564d22e775935d9c91663623a1b4.tar glibc-a334319f6530564d22e775935d9c91663623a1b4.tar.gz glibc-a334319f6530564d22e775935d9c91663623a1b4.tar.bz2 glibc-a334319f6530564d22e775935d9c91663623a1b4.zip |
(CFLAGS-tst-align.c): Add -mpreferred-stack-boundary=4.
Diffstat (limited to 'linuxthreads')
324 files changed, 42004 insertions, 0 deletions
diff --git a/linuxthreads/Banner b/linuxthreads/Banner new file mode 100644 index 0000000000..f0be105a5d --- /dev/null +++ b/linuxthreads/Banner @@ -0,0 +1 @@ +linuxthreads-0.10 by Xavier Leroy diff --git a/linuxthreads/ChangeLog b/linuxthreads/ChangeLog new file mode 100644 index 0000000000..beaad8c6c5 --- /dev/null +++ b/linuxthreads/ChangeLog @@ -0,0 +1,6468 @@ +2004-12-12 Ulrich Drepper <drepper@redhat.com> + + * internals.h: Include <stdbool.h> to match includes used in nptl. + +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. + * tst-clock1.c (do_test): Check for availability of CPU clock. + +2004-11-18 Daniel Jacobowitz <dan@codesourcery.com> + + * sysdeps/unix/sysv/linux/arm/sysdep-cancel.h: Update RETINSTR use. + * sysdeps/unix/sysv/linux/arm/vfork.S: Likewise. + +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): 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-05 Maciej W. Rozycki <macro@mips.com> + + * sysdeps/mips/pspinlock.c: Include <sgidefs.h>. Use _ABIO32, + _ABIN32 and _ABI64 for ABI selection throughout. + * sysdeps/mips/pt-machine.h: Use _ABIO32, _ABIN32 and _ABI64 for + ABI selection throughout. + +2004-10-18 Roland McGrath <roland@redhat.com> + + [BZ #406] + * Makefile (linuxthreads-CPPFLAGS): New variable; + adds -DIS_IN_linuxthreads=1. + * sysdeps/i386/tls.h: Protect "useldt.h" with + [!IS_IN_linuxthreads && !DO_MODIFY_LDT]. + * sysdeps/i386/i686/pt-machine.h: Revert last change. + +2004-10-14 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/pthread/errno-loc.c: Don't undef #errno + if RTLD_PRIVATE_ERRNO. + +2004-10-05 Dwayne Grant McConnell <dgm69@us.ibm.com> + + * pthread.c: Mask restart signal during cancel signal handler. + +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: Set _POSIX_CPUTIME + and _POSIX_THREAD_CPUTIME to zero. + * sysdeps/unix/sysv/linux/ia64/bits/posix_opt.h: Likewise. + + * sysdeps/unix/sysv/linux/bits/posix_opt.h: Define + _POSIX_THREAD_PROCESS_SHARED and _POSIX_CLOCK_SELECTION as -1. + * 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-09-25 Roland McGrath <roland@redhat.com> + + [BZ #406] + * sysdeps/i386/i686/pt-machine.h: Don't #include "../useldt.h" if + [_TLS_H], since sysdeps/i386/tls.h includes it after including us. + +2004-09-24 Roland McGrath <roland@redhat.com> + + [BZ #406] + * sysdeps/i386/tls.h: Move #include "useldt.h" outside + of [__ASSUME_LDT_WORKS > 0] test. + Reported by Carlos Velasco <carlos.velasco@newipnet.com>. + +2004-09-21 Roland McGrath <roland@redhat.com> + + * Versions: Add comment about linuxthreads' frozen ABI. + +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/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-12 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/pthread.h: Make rwlock prototypes available also + for __USE_XOPEN2K. + * sysdeps/pthread/bits/pthreadtypes.h: Define rwlock types also + for __USE_XOPEN2K. [BZ #320] + +2004-09-04 Jakub Jelinek <jakub@redhat.com> + + * tst-cancel4.c (tf_waitid): Use WEXITED flag bit if available. + +2004-09-07 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/pthread.h (pthread_once): Remove __THROW since + the initialization function might throw. + +2004-08-30 Roland McGrath <roland@frob.com> + + * Makefile (libpthread-abi-frozen): New variable. + +2004-08-26 Roland McGrath <roland@redhat.com> + + * configure.in: New file. If nptl add-on is also selected, barf if + explicit and elide ourselves if implicit. + * configure: Now generated. + +2004-08-25 Richard Sandiford <rsandifo@redhat.com> + + * sysdeps/unix/sysv/linux/mips/sysdep-cancel.h (CENABLE, CDISABLE, + __local_multiple_threads): Fix definitions for IS_IN_librt. + * sysdeps/unix/sysv/linux/mips/mips64/sysdep-cancel.h: Likewise. + +2004-08-22 Andreas Schwab <schwab@suse.de> + + * sysdeps/unix/sysv/linux/ia64/sysdep-cancel.h (PSEUDO) [IS_IN_librt]: + Save gp around CENABLE/CDISABLE calls. + +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> + + * libc-tsd.c: Move resolv.h include before the #if. + (__res_maybe_init): New function. Add libc_hidden_def. + +2004-08-02 Ulrich Drepper <drepper@redhat.com> + + * linuxthreads.texi (Cleanup Handlers): Fix typo. + Reported by Bjoern Engelmann <bjengelmann@gmx.de>. + +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-02 Roland McGrath <roland@redhat.com> + + * configure: Don't exit. + +2004-07-20 Alexandre Oliva <aoliva@redhat.com> + + * sysdeps/mips/pt-machine.h: Use standard names for ABI macros, + include sgidefs.h. + * sysdeps/mips/atomicity.h: Likewise. + +2004-07-19 Alexandre Oliva <aoliva@redhat.com> + + * sysdeps/unix/sysv/linux/mips/Makefile (CFLAGS-pt-initfini.s): + Remove redundant override that missed -g0. + +2004-07-14 Kaz Kojima <kkojima@rr.iij4u.or.jp> + + * sysdeps/unix/sysv/linux/sh/sysdep-cancel.h + (__local_multiple_threads): Define for librt. + (SINGLE_THREAD_P): Likewise. + +2004-07-07 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/pthread/getcpuclockid.c (pthread_getcpuclockid): Allow + using other thread's clock. + * ptclock_gettime.c (__pthread_clock_gettime): Likewise. + * ptclock_settime.c (__pthread_clock_settime): Likewise. + * internals.h (__pthread_clock_gettime, __pthread_clock_settime): + Remove prototypes. + Reported by Bernd Schmidt <bernds@redhat.com>. + * Makefile (librt-tests): Add tst-clock1. + * tst-clock1.c: New test. + + * sysdeps/x86_64/Versions: New file. + * sysdeps/unix/sysv/linux/ia64/bits/posix_opt.h: New file. + * sysdeps/unix/sysv/linux/x86_64/bits/posix_opt.h: New file. + +2004-04-16 Andreas Schwab <schwab@suse.de> + + * sysdeps/ia64/tls.h (INIT_SYSINFO): Cast dl_sysinfo to void*. + +2004-07-05 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/s390/pspinlock.c (__pthread_spin_lock, + __pthread_spin_trylock): Use constraint "m" instead of "0" for + futex. + * sysdeps/ia64/pt-machine.h (__compare_and_swap, + __compare_and_swap_with_release_semantic, testandset): Use + constraint "m" instead of "0" for futex. + +2004-06-29 Kaz Kojima <kkojima@rr.iij4u.or.jp> + + * sysdeps/unix/sysv/linux/sh/sysdep-cancel.h (CENABLE): Fix + branch offset for a PLT entry. + (CDISABLE): Likewise. + +2004-05-31 Andreas Jaeger <aj@suse.de> + + * sysdeps/unix/sysv/linux/mips/Makefile (CFLAGS-pt-initfini.s): + Set to -fno-unit-at-a-time. + Patch by Dan Kegel <dank@kegel.com>. + +2004-05-04 Jakub Jelinek <jakub@redhat.com> + + * tst-stack1.c: Don't include mcheck.h. + (do_test): Make sure user defined stacks aren't reused, + don't free them at the end. [BZ #110] + +2004-05-02 Jakub Jelinek <jakub@redhat.com> + + * manager.c: Include not-cancel.h. + (__pthread_manager): Use read_not_cancel instead of __libc_read. + (pthread_start_thread, __pthread_manager_sighandler): Use + write_not_cancel instead of __libc_write. + (pthread_reap_children): Use waitpid_not_cancel instead of + __libc_waitpid. + * pthread.c: Include not-cancel.h. + (__pthread_initialize_minimal, __pthread_create_2_1, + pthread_onexit_process, __pthread_message): Use + write_not_cancel instead of __libc_write. + (__pthread_initialize_manager): Likewise. Use close_not_cancel + instead of __libc_close. + (__pthread_reset_main_thread): Use close_not_cancel instead of + __libc_close. + * join.c: Include not-cancel.h. + (__pthread_do_exit, pthread_join, pthread_detach): Use + write_not_cancel instead of __libc_write. + * semaphore.c: Include not-cancel.h. + (__new_sem_post): Use write_not_cancel instead of __libc_write. + * specific.c: Include not-cancel.h. + (pthread_key_delete): Use write_not_cancel instead of __libc_write. + +2004-05-01 Jakub Jelinek <jakub@redhat.com> + + * Versions (libc): Add __on_exit and __libc_sigaction. + +2004-04-28 Jakub Jelinek <jakub@redhat.com> + + * semaphore.c (sem_timedwait): Return -1 and set errno instead of + returning error number [BZ #133]. Patch by <rmhaddad@yahoo.com>. + +2004-04-22 SUGIOKA Toshinobu <sugioka@itonet.co.jp> + + * sysdeps/unix/sysv/linux/sh/vfork.S: Fix wrong function pointer + reference in PIC case. + +2004-04-20 Jakub Jelinek <jakub@redhat.com> + + * oldsemaphore.c (SEM_VALUE_MAX): Remove. + +2004-04-19 Kaz Kojima <kkojima@rr.iij4u.or.jp> + + * sysdeps/unix/sysv/linux/sh/sysdep-cancel.h (CENABLE): Define + for librt. Save the return value to a safe register. + (CDISABLE): Define for librt. Set the function argument correctly. + +2004-04-18 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h + (PSEUDO_CANCEL): Define. + (PSEUDO): Use it. + * sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h (CENABLE, + CDISABLE): For librt, append @PLT. + +2004-04-17 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/x86_64/tls.h [!__ASSEMBLER__]: Include tcb-offsets.h. + + * 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. + + * sysdeps/unix/sysv/linux/mq_notify.c: Include stdlib.h. + +2004-04-17 Ulrich Drepper <drepper@redhat.com> + + * semaphore.h (SEM_VALUE_MAX): Just use a plain number. + +2004-04-16 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h: Fix last patch. + +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. + + * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h (CENABLE): Define + for librt. + (CDISABLE): Likewise. + +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. + +2004-04-10 Andreas Jaeger <aj@suse.de> + + * sysdeps/x86_64/pt-machine.h: Add used attribute to stack_pointer + to avoid warnings with GCC 3.5. + +2004-04-09 Steven Munroe <sjmunroe@us.ibm.com> + + * sysdeps/powerpc/tls.h (TLS_INIT_TP): Eliminate lvalue cast from + __thread_self assignment. + (THREAD_DTV): Replace __thread_register with __thread_self. + (INIT_THREAD_SELF): Eliminate lvalue cast from __thread_self + assignment. + +2004-04-08 Alexandre Oliva <aoliva@redhat.com> + + * signals.c (pthread_sigmask): Don't ever block or mask + __pthread_sig_debug. + +2004-03-11 Steven Munroe <sjmunroe@us.ibm.com> + + * sysdeps/powerpc/tls.h: Remove __powerpc64__ conditional. + +2004-03-23 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/ia64/pt-machine.h (BUSY_WAIT_NOP): Define. + * sysdeps/x86_64/pt-machine.h (BUSY_WAIT_NOP): Likewise. + +2004-03-12 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/bits/local_lim.h: Add 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-08 Andreas Jaeger <aj@suse.de> + + * sysdeps/i386/tls.h (TLS_DO_MODIFY_LDT_KERNEL_CHECK): + dl_osversion is readonly. + +2004-03-07 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/i386/tls.h (INIT_SYSINFO): _dl_sysinfo is now in + _rtlf_global_ro. + * sysdeps/ia64/tls.h (INIT_SYSINFO): Likewise. + +2004-02-20 Steven Munroe <sjmunroe@us.ibm.com> + + * sysdeps/unix/sysv/linux/powerpc/ptlongjmp.c [SHARED]: Code only + valid for SHARED case. Correct spelling of __vmx_longjmp. + + * sysdeps/powerpc/pspinlock.c: Move from here. + * sysdeps/powerpc/powerpc32/pspinlock.c: To here. + * sysdeps/powerpc/powerpc64/pspinlock.c: New file. + * sysdeps/powerpc/powerpc64/pt-machine.h: Define __compare_and_swap32 + and __compare_and_swap32_with_release_semantics. + +2004-02-20 Jakub Jelinek <jakub@redhat.com> + + * Makefile (generated): Remove tst-stack1.mtrace and tst-stack1-mem. + (tests): Remove $(objpfx)tst-stack1-mem. + (tst-stack1-ENV): Remove. + ($(objpfx)tst-stack1-mem): Remove. + + * 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/unix/sysv/linux/ia64/dl-sysdep.h (DL_ARGV_NOT_RELRO): Define. + +2004-02-10 Steven Munroe <sjmunroe@us.ibm.com> + + * Makefile (libpthread-routines): Add ptcleanup. + * ptlongjmp.c: Removed. + * ptcleanup.c: Copied __pthread_cleanup_upto to here. New file. + * sysdeps/pthread/ptlongjmp.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/ptlongjmp.c: New File. + +2004-01-22 Andreas Jaeger <aj@suse.de> + + * spinlock.c (__pthread_lock): Fix contraint to avoid warning. + (__pthread_release): Likewise. + +2004-01-16 Richard Henderson <rth@redhat.com> + + * attr.c: Include ldsodefs.h. + (pthread_getattr_np): Don't declare __libc_stack_end. + +2004-01-09 Steven Munroe <sjmunroe@us.ibm.com> + + * sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h + [!HAVE_TLS_SUPPORT]: Define SINGLE_THREAD_P using static + __lib*_multiple_threads. + * sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h + [!HAVE_TLS_SUPPORT]: Likewise. + +2004-01-13 Roland McGrath <roland@redhat.com> + + * sysdeps/powerpc/tcb-offsets.sym: Put -- separator line before any + conditionals. + +2004-01-10 Andreas Jaeger <aj@suse.de> + + * sysdeps/unix/sysv/linux/x86_64/vfork.S: Add cfi directives. + +2004-01-01 Andreas Jaeger <aj@suse.de> + + * Makefile (generated): Add missing files. + +2003-12-31 Ulrich Drepper <drepper@redhat.com> + + * attr.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> + + * sysdeps/ia64/tls.h: Include dl-sysdep.h. + (INIT_SYSINFO): Define. + (TLS_INIT_TP): Use it. + +2003-12-28 Carlos O'Donell <carlos@baldric.uwo.ca> + + * attr.c (pthread_getattr_np): Add _STACK_GROWS_UP case. + +2003-12-26 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/pthread/pthread.h (pthread_setcancelstate, + pthread_setcanceltype, pthread_cancel, pthread_testcancel): Remove + __THROW. + * semaphore.h (sem_wait, sem_timedwait): Likewise. + +2003-12-17 Jakub Jelinek <jakub@redhat.com> + + * manager.c (pthread_free): Call _dl_deallocate_tls even for + p_userstack threads. + * pthread.c (__pthread_initialize_manager): Call _dl_deallocate_tls + on error. + (pthread_onexit_process): Update comment. + * Makefile (tests): Add tst-stack1. Depend on $(objpfx)tst-stack1-mem. + (generated): Add tst-stack1.mtrace and tst-stack1-mem. + (tst-stack1-ENV): Set. + ($(objpfx)tst-stack1-mem): New. + * tst-stack1.c: New test. + +2003-12-16 Steven Munroe <sjmunroe@us.ibm.com> + + * sysdeps/powerpc/tcb-offsets.sym [!__powerpc64__]: Remove + conditional so MULTIPLE_THREADS_OFFSET is generated for both. + * sysdeps/powerpc/tls.h [!__powerpc64__]: Remove conditional + so TLS_MULTIPLE_THREADS_IN_TCB is generated for both. + * sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h: + Include tls.h. + +2003-12-04 Steven Munroe <sjmunroe@us.ibm.com> + + * sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h + (SINGLE_THREAD_P): Test using thread local p_multiple_threads field. + +2003-12-10 David Mosberger <davidm@hpl.hp.com> + + * sysdeps/unix/sysv/linux/ia64/pt-initfini.c: Update copyright + message. Add include of <stddef.h>. + (INIT_NEW_WAY): New macro. + (INIT_OLD_WAY): Likewise. + (_init): Add unwind directives. Invoke + __pthread_initialize_minimal() via INIT_NEW_WAY or INIT_OLD_WAY, + respectively. + (_init_EPILOG_BEGINS): Add unwind-directives. Drop unused .regstk + directive. + (_fini): Add unwind directives. Drop unnecessary .align 16 + directive (bundles are always 16-byte aligned). + (_fini_EPILOG_BEGINS): Add unwind-directives. + +2003-11-19 David Mosberger <davidm@hpl.hp.com> + + * sysdeps/unix/sysv/linux/ia64/dl-sysdep.h: New file. + +2003-12-10 Andreas Jaeger <aj@suse.de> + Ruediger Oertel <ro@suse.de> + + * sysdeps/alpha/elf/pt-initfini.c (__asm__): Remove extra .prologue. + +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-04 Jakub Jelinek <jakub@redhat.com> + + * signals.c (__pthread_sigaction): Set __sighandler[sig].old before + __libc_sigaction if it has been one of the special values before. + +2003-10-06 Carlos O'Donell <carlos@baldric.uwo.ca> + + * pthread.c (__pthread_self_stack): _STACK_GROWS_UP case added. + (__pthread_find_self): Likewise. + * manager.c (thread_segment): _STACK_GROWS_UP case added. + +2003-10-10 Carlos O'Donell <carlos@baldric.uwo.ca> + + * linuxthreads/sysdeps/unix/sysv/linux/hppa/malloc-machine.h: New file. + +2003-10-10 Carlos O'Donell <carlos@baldric.uwo.ca> + + * sysdeps/unix/sysv/linux/hppa/sysdep-cancel.h: New file. + +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-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-cancel8. + * tst-cancel8.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-10 Chris Demetriou <cgd@broadcom.com> + + * sysdeps/unix/sysv/linux/mips/mips64/sysdep-cancel.h: New file. + +2003-09-30 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/pthread/malloc-machine.h [!__libc_maybe_call2] (mutex_init, + mutex_lock, mutex_trylock, mutex_unlock): Remove. + +2003-09-27 Wolfram Gloger <wg@malloc.de> + + * sysdeps/pthread/malloc-machine.h: New file. + +2003-09-18 H.J. Lu <hongjiu.lu@intel.com> + + * attr.c (__pthread_attr_init_2_1): Double __guardsize size + if NEED_SEPARATE_REGISTER_STACK is defined. + +2003-09-22 Philip Blundell <philb@gnu.org> + + * forward.c: Add _pthread_cleanup_push, _pthread_cleanup_pop. + * sysdeps/pthread/pthread-functions.h (struct pthread_functions): + Likewise. + * pthread.c (__pthread_elements): Initialise these new elements. + * sysdeps/pthread/bits/libc-lock.h (__libc_cleanup_push): Use + __libc_maybe_call. + (__libc_cleanup_pop): Likewise. + +2003-09-22 Jakub Jelinek <jakub@redhat.com> + + * attr.c: Include stdlib.h. + +2003-09-18 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/pthread/pthread.h (pthread_getattr_np): Clarify usage. + + * tst-attr1.c: New test. + * Makefile (tests): Add tst-attr1. + +2003-09-17 Philip Blundell <philb@gnu.org> + + * sysdeps/unix/sysv/linux/arm/vfork.S: Branch to fork if + libpthread is loaded. Elide backwards compatibility code when not + required. + +2003-09-17 Jakub Jelinek <jakub@redhat.com> + + * descr.h (manager_thread): Rename to... + (__pthread_manager_threadp): ... this. + * pthread.c (manager_thread): Define to __pthread_manager_threadp. + (__pthread_manager_threadp): New variable. + * internals.h (__manager_thread): Define to + __pthread_manager_threadp if USE_TLS. + +2003-09-15 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/i386/Makefile (CFLAGS-cancel.c, CFLAGS-manager.c, + CFLAGS-pthread.c, CFLAGS-sighandler.c): Add + -mpreferred-stack-boundary=4. + +2003-09-16 Ulrich Drepper <drepper@redhat.com> + + * attr.c (pthread_getattr_np): Correctly fill in the stack-related + values for the initial thread. + +2003-09-17 Jakub Jelinek <jakub@redhat.com> + + * pthread.c (manager_thread): Remove static, add attribute_hidden. + (thread_self_stack): Rename to... + (__pthread_self_stack): ... this. Remove static. + (pthread_handle_sigcancel): Use check_thread_self (). + (pthread_handle_sigrestart): Likewise. + * sighandler.c (__pthread_sighandler, __pthread_sighandler_rt): + Likewise. + * descr.h (manager_thread): Declare. + * internals.h (__pthread_self_stack): New prototype. + (__manager_thread): Define. + (check_thread_self): New function. + +2003-09-15 Jakub Jelinek <jakub@redhat.com> + + * Makefile (CFLAGS-mutex.c): Add $(uses-callbacks). + (CFLAGS-sighandler.c): Change $(exceptions) into $(uses-callbacks). + +2003-09-12 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/s390/bits/typesizes.h: New. + (__SSIZE_T_TYPE): Define to __SWORD_TYPE for gcc 2.95.x and + __SLONGWORD_TYPE otherwise. + +2003-09-11 Steven Munroe <sjmunroe@us.ibm.com> + + * sysdeps/powerpc/powerpc64/pt-machine.h [MEMORY_BARRIER]: Use lwsync. + [READ_MEMORY_BARRIER]: Define. + [WRITE_MEMORY_BARRIER]: Define. + +2003-09-10 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/pthread/pthread-functions.h (struct pthread_functions): Move + ptr___pthread_cond_timedwait to the end of the structure to avoid + breaking Wine unnecessarily. + +2003-09-08 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/s390/bits/typesizes.h: Remove. + +2003-09-02 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/alpha/bits/local_lim.h: New file. + * sysdeps/unix/sysv/linux/alpha/Versions: New file. + * sysdeps/unix/sysv/linux/ia64/bits/local_lim.h: New file. + * sysdeps/unix/sysv/linux/ia64/Versions: New file. + * sysdeps/unix/sysv/linux/sparc/bits/local_lim.h: New file. + * sysdeps/unix/sysv/linux/sparc/Versions: New file. + * attr.c (__old_pthread_attr_setstacksize, + __old_pthread_attr_setstack): New functions. + (pthread_attr_setstacksize): If PTHREAD_STACK_MIN != 16384, export + as @@GLIBC_2.3.2 and also export compatibility @GLIBC_2.1. + (pthread_attr_setstack): If PTHREAD_STACK_MIN != 16384, export + as @@GLIBC_2.3.2 and also export compatibility @GLIBC_2.2. + * tststack.c: Include limits.h and sys/param.h. + (main): Set size to MAX (70 * 1024, PTHREAD_STACK_MIN). + + * barrier.c (__pthread_barrierattr_getpshared): Always + return PTHREAD_PROCESS_PRIVATE. + (pthread_barrierattr_setpshared): Return EINVAL if pshared + is neither PTHREAD_PROCESS_PRIVATE nor PTHREAD_PROCESS_SHARED. + +2003-09-02 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/dl-sysdep.h + (DL_SYSINFO_IMPLEMENTATION): Add CFI and make sure the code ends + up in .text. + + * barrier.c (pthread_barrierattr_setpshared): We don't handle + inter-process barriers. + +2003-09-01 Jakub Jelinek <jakub@redhat.com> + + * Makefile (tests): Add tst-tls1. + (module-names): Add tst-tls1mod{,a,b,c,d,e,f}. + ($(objpfx)tst-tls1mod{,a,b,c,d,e,f}.so-no-z-defs): Set to yes. + ($(objpfx)tst-tls1): New. + ($(objpfx)tst-tls2.out): Likewise. + (tests): Depend on $(objpfx)tst-tls2.out. + * tst-tls1.c: New test. + * tst-tls1.h: New. + * tst-tls1mod.c: New. + * tst-tls1moda.c: New. + * tst-tls1modb.c: New. + * tst-tls1modc.c: New. + * tst-tls1modd.c: New. + * tst-tls1mode.c: New. + * tst-tls1modf.c: New. + * tst-tls2.sh: New test. + + * internals.h (__pthread_cond_timedwait): New prototype. + * sysdeps/pthread/pthread-functions.h (struct pthread_functions): Add + ptr___pthread_cond_timedwait. + * pthread.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-08-27 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/pthread.h: Don't mark pthread_exit, + pthread_join, pthread_cond_wait, and pthread_cond_timedwait with + __THROW to match NPTL. + +2003-08-13 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/Makefile [subdir=rt] (CPPFLAGS): Add + -DBROKEN_THREAD_SIGNALS. + +2003-08-11 Steven Munroe <sjmunroe@us.ibm.com> + + * manager.c (pthread_start_thread) [!(USE_TLS && HAVE___THREAD)]: + Correct spelling of per thread resolver state. + +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). + * pthread.c (pthread_initialize): 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. + +2003-07-31 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/pthread/bits/typesizes.h (__SSIZE_T_TYPE): Define. + * sysdeps/unix/sysv/linux/alpha/bits/typesizes.h (__SSIZE_T_TYPE): + Likewise. + * sysdeps/unix/sysv/linux/sparc/bits/typesizes.h (__SSIZE_T_TYPE): + Likewise. + * sysdeps/unix/sysv/linux/s390/bits/typesizes.h: New file. + + * sysdeps/pthread/pthread.h (pthread_attr_setstackaddr, + pthread_attr_setstacksize): Change PTHREAD_STACK_SIZE to + PTHREAD_STACK_MIN in comments. + + * sysdeps/alpha/pt-machine.h (PT_EI): Add + __attribute__((always_inline)). + * sysdeps/arm/pt-machine.h (PT_EI): Likewise. + * sysdeps/cris/pt-machine.h (PT_EI): Likewise. + * sysdeps/hppa/pt-machine.h (PT_EI): Likewise. + * sysdeps/i386/i686/pt-machine.h (PT_EI): Likewise. + * sysdeps/i386/pt-machine.h (PT_EI): Likewise. + * sysdeps/ia64/pt-machine.h (PT_EI): Likewise. + * sysdeps/m68k/pt-machine.h (PT_EI): Likewise. + * sysdeps/mips/pt-machine.h (PT_EI): Likewise. + * sysdeps/powerpc/powerpc32/pt-machine.h (PT_EI): Likewise. + * sysdeps/powerpc/powerpc64/pt-machine.h (PT_EI): Likewise. + * sysdeps/s390/s390-32/pt-machine.h (PT_EI): Likewise. + * sysdeps/s390/s390-64/pt-machine.h (PT_EI): Likewise. + * sysdeps/sh/pt-machine.h (PT_EI): Likewise. + * sysdeps/sparc/sparc32/pt-machine.h (PT_EI): Likewise. + * sysdeps/sparc/sparc64/pt-machine.h (PT_EI): Likewise. + * sysdeps/x86_64/pt-machine.h (PT_EI): Likewise. + * spinlock.h (__pthread_set_own_extricate_if): Likewise. + * sysdeps/ia64/tls.h (TLS_INIT_TP): Cast tcbp to __typeof + (__thread_self). + * Examples/ex13.c (main): Change res type to void * to avoid + warnings. + * tst-cancel.c (cleanup, inner, tf1, tf2, tf3): Comment out. + +2003-07-30 Jakub Jelinek <jakub@redhat.com> + + * pthread.c (init_one_static_tls, __pthread_init_static_tls): New + functions. + (pthread_initialize): Initialize GL(dl_init_static_tls). + +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 Roland McGrath <roland@redhat.com> + + * manager.c (pthread_start_thread): Fix typo in last change. + +2003-07-14 Guido Guenther <agx@sigxcpu.org> + + * sysdeps/unix/sysv/linux/mips/sysdep-cancel.h: Add IS_IN_librt, + use L() for local labels. + +2003-07-22 Jakub Jelinek <jakub@redhat.com> + + * descr.h (struct _pthread_descr_struct): Provide p_res member + even if USE_TLS && HAVE___THREAD. + * sysdeps/pthread/res-state.c (__res_state): Return __resp + if USE___THREAD. + * manager.c: Include resolv.h. + (pthread_start_thread): Initialize __resp. + * libc-tls-loc.c (__res_state): Return __resp. + * Makefile (tests): Add tst-_res1. + (modules-names, extra-objs, test-extras, test-modules): Add support + for test modules. + ($(objpfx)tst-_res1mod2.so): Depend on $(objpfx)tst-_res1mod1.so. + ($(objpfx)tst-_res1): Depend on $(objpfx)tst-_res1mod2.so and + -lpthread. + * tst-_res1.c: New test. + * tst-_res1mod1.c: New test. + * tst-_res1mod2.c: New test. + +2003-07-20 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/bits/libc-lock.h: Define __libc_cleanup_push and + __libc_cleanup_pop. + + * tst-cancel-wrappers.sh: lseek and llseek are no cancellation points. + +2003-07-14 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/sparc/sparc32/sysdep-cancel.h: Fix typo + in test for compilation in libc. + +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. + +2003-06-20 Kaz Kojima <kkojima@rr.iij4u.or.jp> + + * sysdeps/unix/sysv/linux/sh/sysdep-cancel.h: Support cancellation + in librt. + +2003-06-21 Andreas Schwab <schwab@suse.de> + + * sysdeps/unix/sysv/linux/m68k/sysdep-cancel.h: Support cancellation + in librt. + +2003-06-20 Richard Henderson <rth@redhat.com> + + * sysdeps/unix/sysv/linux/alpha/Makefile (libpthread-routines): + Remove ptw-osf_sigprocmask. + +2003-06-18 Jakub Jelinek <jakub@redhat.com> + + * internals.h (__librt_multiple_threads, __librt_enable_asynccancel, + __librt_disable_asynccancel): Declare. + (LIBC_CANCEL_ASYNC, LIBC_CANCEL_RESET, LIBC_CANCEL_HANDLED): Define + for IS_IN_librt. + * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h: Support cancellation + in librt. + * sysdeps/unix/sysv/linux/ia64/sysdep-cancel.h: Likewise. + * sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h: Likewise. + * sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h: Likewise. + * sysdeps/unix/sysv/linux/sparc/sparc32/sysdep-cancel.h: Likewise. + * sysdeps/unix/sysv/linux/sparc/sparc64/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/x86_64/tcb-offsets.sym: New file. + * sysdeps/x86_64/Makefile: New file. + * sysdeps/x86_64/tls.h (tcbhead_t): Add multiple_threads. + * Versions (libc): Export __librt_enable_asynccancel, + __librt_disable_asynccancel and __librt_multiple_threads as + GLIBC_PRIVATE. + * libc-cancellation.c (__librt_multiple_threads, + __librt_enable_asynccancel, __librt_disable_asynccancel): New aliases. + +2003-06-12 Steven Munroe <sjmunroe@us.ibm.com> + + * sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h + (SINGLE_THREAD_P): Replace @ got notation with @toc. + +2003-06-11 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/powerpc/pspinlock.c (__pthread_spin_init): Fix + initializer [PR libc/5052]. + +2003-06-09 Andreas Schwab <schwab@suse.de> + + * Makefile: Move inclusion of ../Rules down after extra-objs is + fully known. + +2003-06-06 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/arm/sysdep-cancel.h: New sequences for + 5+ arg syscalls only needed for PIC. + Patch by Ralph Siemsen <ralphs@netwinder.org>. + +2003-06-05 Richard Henderson <rth@redhat.com> + + * sysdeps/unix/sysv/linux/alpha/sysdep-cancel.h (PSEUDO): Use + and require CFI assembler directives. + * sysdeps/unix/sysv/linux/alpha/vfork.S: Likewise. + +2003-05-30 Andreas Jaeger <aj@suse.de> + + * sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h + (SAVESTK_0): Add CFI directives. + (SAVESTK_3): Likewise. + (SAVESTK_5): Likewise. + (RESTSTK_0): Likewise. + (RESTSTK_3): Likewise. + (RESTSTK_5): Likewise. + +2003-05-05 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/i386/tls.h (TLS_DO_SET_THREAD_AREA): Add \n to error + messages. + +2003-05-04 Roland McGrath <roland@redhat.com> + + * Makefile ($(objpfx)../libc.so): New target. + +2003-04-26 Ulrich Drepper <drepper@redhat.com> + + * pthread.c (__pthread_initialize_manager): Remove one last + p_multiple_threads call. + +2003-04-22 Jakub Jelinek <jakub@redhat.com> + + * pthread.c (__pthread_initialize_manager): Subtract + TLS_PRE_TCB_SIZE bytes from tcbp to get to descr. + * manager.c (pthread_handle_create): Subtract or add TLS_PRE_TCB_SIZE + instead of sizeof (pthread_descr). + (pthread_free): Add TLS_PRE_TCB_SIZE instead of sizeof (pthread_descr). + * 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 + pthread_descr. + (TLS_PRE_TCB_SIZE): Increase to cover tcbhead_t preceeded by pad + to TLS_TCB_ALIGN. + (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. + +2003-04-22 Roland McGrath <roland@redhat.com> + + * Makeconfig (shared-thread-library): Reverse link order to work + around linker bug. + +2003-04-20 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/i386/useldt.h (DO_SET_THREAD_AREA): Make sure the + compiler knows we use the ldt_entry variable and that the syscall + modifies the memory. + + * internals.h: Split pthread_functions definition into... + * sysdeps/pthread/pthread-functions.h: ...new file. + + * sysdeps/i386/useldt.h: Include <sysdep.h>. + +2003-04-13 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h: Rename macros to + match changes in NPTL sysdep-cancel.h. + +2003-04-11 Roland McGrath <roland@redhat.com> + + * Makefile (multidir): Don't set the variable here with $(shell ...). + ($(objpfx)multidir.mk): New target, generated makefile; include that. + (generated): Append it. + +2003-04-10 Jakub Jelinek <jakub@redhat.com> + + * Makefile (multidir, crti-objs, crtn-objs): New variables. + (generated-dirs): Add pathname component of multidir. + (omit-deps, extra-objs): Include $(multidir)/crt? as well. + ($(objpfx)libpthread.so): Depend on $(multidir)/crt?.o as well. + ($(objpfx)$(multidir), $(objpfx)$(multidir)/crti.o, + $(objpfx)$(multidir)/crtn.o): New. + * sysdeps/unix/sysv/linux/sparc/Makefile: Removed. + * sysdeps/unix/sysv/linux/x86_64/Makefile (LDFLAGS-pthread.so, + before-compile, generated): Don't generate and use specs. + ($(objpfx)specs): Remove. + +2003-04-11 Martin Schwidefsky <schwidefsky@de.ibm.com> + + * sysdeps/s390/pspinlock.c (__pthread_spin_unlock): Fix asm contraints. + +2003-04-03 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/arm/sysdep-cancel.h (PSEUDO): Add + missing ; after ENTRY use [PR libc/4997]. + +2003-04-03 Jakub Jelinek <jakub@redhat.com> + + * pthread.c (pthread_initialize): Unblock __pthread_sig_cancel + in case the parent blocked it. + +2003-04-02 Jakub Jelinek <jakub@redhat.com> + + * Makefile (libpthread-routines): Add pthread_atfork. + (libpthread-static-only-routines): Add pthread_atfork. + +2003-04-01 Jakub Jelinek <jakub@redhat.com> + + * pthread.c (__pthread_wait_for_restart_signal): Use + __pthread_sigsuspend instead of sigsuspend. + * internals.h (__pthread_sigsuspend): New prototype. + * Makefile (libpthread-routines): Add pt-sigsuspend. + (tests): Add tst-cancel7. + * sysdeps/unix/sysv/linux/pt-sigsuspend.c: New file. + * sysdeps/unix/sysv/linux/alpha/pt-sigsuspend.S: New file. + * sysdeps/unix/sysv/linux/ia64/pt-sigsuspend.c: New file. + * sysdeps/unix/sysv/linux/s390/s390-64/pt-sigsuspend.c: New file. + * sysdeps/unix/sysv/linux/sparc/sparc64/pt-sigsuspend.c: New file. + * sysdeps/unix/sysv/linux/x86_64/pt-sigsuspend.c: New file. + * tst-cancel7.c: New test. + +2003-03-31 Alexandre Oliva <aoliva@redhat.com> + + * alloca_cutoff.c: Include internals.h. + * sysdeps/pthread/errno-loc.c: Include linuxthreads/internals.h. + * sysdeps/pthread/herrno-loc.c: Likewise. + * sysdeps/pthread/res-state.c: Likewise. + +2003-03-25 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/bits/typesizes.h: New file. + * sysdeps/unix/sysv/linux/alpha/bits/typesizes.h: New file. + * sysdeps/unix/sysv/linux/sparc/bits/typesizes.h: New file. + +2003-03-24 Daniel Jacobowitz <drow@mvista.com> + + * sysdeps/unix/sysv/linux/arm/sysdep-cancel.h + (DOARGS_5, DOARGS_6, DOARGS_7): Rewritten. + +2003-03-22 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/fork.c (__fork): Add libc_hidden_def. + +2003-03-21 Daniel Jacobowitz <drow@mvista.com> + + * sysdeps/unix/sysv/linux/arm/sysdep-cancel.h + (SINGLE_THREAD_P_PIC): Use "reg" instead of "lr". + +2003-03-21 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/i386/tls.h [__ASSUME_SET_THREAD_AREA_SYSCALL] + (TLS_SETUP_GS_SEGMENT): Fix a typo. + +2003-03-19 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/Makefile: Fix cut&paste error. + +2003-03-18 Roland McGrath <roland@redhat.com> + + * Versions (libpthread: GLIBC_2.2): Remove + pthread_barrierattr_getpshared, never really existed. + (libpthread: GLIBC_2.0): Move __pthread_initialize to ... + (libpthread: GLIBC_PRIVATE): ... here. + +2003-03-14 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/sparc/sparc64/Makefile: New file. + * sysdeps/unix/sysv/linux/sparc/Makefile ($(objpfx)specs): Use full + path for crt[in].o. + +2003-03-14 Alexandre Oliva <aoliva@redhat.com> + + * sysdeps/mips/pspinlock.c (__pthread_spin_lock): Don't .set + mips2 on new abi. + * sysdeps/mips/pt-machine.h (__compare_and_swap): Likewise. + Handle 64-bit longs on n64. + +2003-03-07 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/ia64/pspinlock.c (__pthread_spin_lock, + __pthread_spin_trylock): Rewritten. + +2003-03-06 Ulrich Drepper <drepper@redhat.com> + + * tst-cancel4.c (tf_sleep): Lower sleep time a bit to not upset + recent kernels. + +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. + +2003-03-01 Roland McGrath <roland@redhat.com> + + * sysdeps/powerpc/powerpc64/pt-machine.h + (THREAD_GETMEM, THREAD_GETMEM_NC, THREAD_SETMEM, THREAD_SETMEM_NC): + New macros. + * sysdeps/powerpc/tls.h: Don't define those here. + + * sysdeps/powerpc/tls.h [! USE_TLS && !__powerpc64__]: Define + tcbhead_t with multiple_threads member. + [USE_TLS] (tcbhead_t): Define minimal one-word version. + [USE_TLS && !__powerpc64__] (TLS_MULTIPLE_THREADS_IN_TCB): Define. + * sysdeps/powerpc/tcb-offsets.sym [USE_TLS]: Use tls.h macros to + derive thread register offset of p_multiple_threads member. + + * descr.h (struct _pthread_descr_struct) [!USE_TLS || !TLS_DTV_AT_TP]: + Conditionalize p_header member on this. + [TLS_MULTIPLE_THREADS_IN_TCB]: Add p_multiple_threads alternatively. + * sysdeps/ia64/tls.h [USE_TLS] (TLS_MULTIPLE_THREADS_IN_TCB): Define. + * sysdeps/sh/tls.h: Likewise. + * sysdeps/ia64/tcb-offsets.sym [USE_TLS]: Use p_multiple_threads. + * sysdeps/sh/tcb-offsets.sym: Likewise. + * sysdeps/unix/sysv/linux/sh/sysdep-cancel.h + (SINGLE_THREAD_P): Likewise. + * sysdeps/unix/sysv/linux/ia64/sysdep-cancel.h + (SINGLE_THREAD_P): Likewise. + * sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h + (SINGLE_THREAD_P): Likewise. + * pthread.c (__pthread_initialize_manager): Likewise. + * manager.c (pthread_handle_create): Likewise. + + * sysdeps/powerpc/tls.h [HAVE_TLS_SUPPORT]: Define USE_TLS and all + related macros. + +2003-01-31 Steven Munroe <sjmunroe@us.ibm.com> + + * sysdeps/unix/sysv/linux/powerpc/powerpc64/vfork.S [SHARED]: + Conditionalize .toc section magic on this. + +2003-02-21 Roland McGrath <roland@redhat.com> + + * cancel.c (__pthread_perform_cleanup): Call __libc_thread_freeres + instead of __rpc_thread_destroy. + +2003-02-21 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S (__vfork): Call + __fork instead of branching to it if BROKEN_SPARC_WDISP22. + * sysdeps/unix/sysv/linux/sparc/sparc64/sysdep-cancel.h (PSEUDO): + Fix typo. + * sysdeps/unix/sysv/linux/sparc/Makefile (specs): Add ./ prefix + to crti.o and crtn.o. + * sysdeps/unix/sysv/linux/x86_64/Makefile (specs): Likewise. + +2003-02-21 Roland McGrath <roland@redhat.com> + + * Makefile (install-lib-ldscripts): New variable. + +2003-02-20 Franz Sirl <Franz.Sirl-kernel@lauterbach.com> + + * sysdeps/unix/sysv/linux/powerpc/powerpc32/vfork.S: Avoid short + interprocedure branches. + +2003-02-19 Ulrich Drepper <drepper@redhat.com> + + * specific.c (pthread_key_delete_helper): Don't use GETMEM, we + need the target thread's lock. + +2003-02-17 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/bits/local_lim.h: Define TTY_NAME_MAX + and LOGIN_NAME_MAX. + +2003-02-17 Kevin B. Hendricks <kevin.hendricks@sympatico.ca> + Franz Sirl <Franz.Sirl-kernel@lauterbach.com> + + * sysdeps/powerpc/Makefile: Handle tcb-offsets.sym. + * sysdeps/powerpc/tcb-offsets.sym: New file. + * sysdeps/powerpc/tls.h: New file. + * sysdeps/powerpc/powerpc32/pt-machine.h (FLOATING_STACKS): Define. + (ARCH_STACK_MAX_SIZE): Define. + (THREAD_SELF): Define. + (INIT_THREAD_SELF): Define. + (THREAD_GETMEM): Define. + (THREAD_GETMEM_NC): Define. + (THREAD_SETMEM): Define. + (THREAD_SETMEM_NC): Define. + (__thread_self): Declare. + * sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h: Adjust + for thread register. + +2003-02-14 Steven Munroe <sjmunroe@us.ibm.com> + + * sysdeps/unix/sysv/linux/powerpc/powerpc64/vfork.S (__vfork): + Check pthread_create existance, not __pthread_fork. + +2003-02-12 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/Makefile: Define CFLAGS-confstr.c. + +2003-02-10 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/alpha/vfork.S (__vfork): Check + pthread_create existance, not __pthread_fork. + * sysdeps/unix/sysv/linux/i386/vfork.S (__vfork): Likewise. + * sysdeps/unix/sysv/linux/ia64/vfork.S (__vfork): Likewise. + * sysdeps/unix/sysv/linux/m68k/vfork.S (__vfork): Likewise. + * sysdeps/unix/sysv/linux/powerpc/powerpc32/vfork.S (__vfork): + Likewise. + * sysdeps/unix/sysv/linux/s390/s390-64/vfork.S (__vfork): Likewise. + * sysdeps/unix/sysv/linux/x86_64/vfork.S (__vfork): Likewise. + * sysdeps/unix/sysv/linux/sh/vfork.S (__vfork): Likewise. + Add .weak pthread_create. + * sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S (__vfork): Fix a typo. + Check pthread_create existance, not __pthread_fork. + * sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S (__vfork): Likewise. + * sysdeps/unix/sysv/linux/s390/s390-32/vfork.S (__vfork): Branch to + __fork whenever libpthread.so is loaded. + +2003-02-09 Andreas Jaeger <aj@suse.de> + + * sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h: + Rework: %r9 is destroyed by functions so don't use it as + temporary, align stack correctly, fix parameter for CDISABLE. + +2003-02-07 Kaz Kojima <kkojima@rr.iij4u.or.jp> + + * sysdeps/sh/Makefile: New file. + * sysdeps/sh/tcb-offsets.sym: Likewise. + * sysdeps/sh/tls.h: Don't include sysdep.h. Move include + of linuxthreads/descr.h after the definition of THREAD_SELF. + (tcbhead_t): Use IA64 type tcbhead_t for TLS case. + (TLS_TCB_SIZE): Set size of tcbhead_t. + (TLS_PRE_TCB_SIZE): Define. + (INSTALL_NEW_DTV): Set dtv of tcbhead_t structure instead of + a member of thread structure. + (THREAD_DTV): Likewise. + (TLS_INIT_TP_EXPENSIVE): Remove. + (TLS_INIT_TP): Set gbr register only. + (THREAD_SELF): New. + (INIT_THREAD_SELF): Likewise. + (NONTLS_INIT_TP): New. + * sysdeps/unix/sysv/linux/sh/pt-initfini.c (__fpscr_values): + Remove. + * sysdeps/unix/sysv/linux/sh/sysdep-cancel.h (PSEUDO): Add + SYSCALL_INST_PAD macro after DO_CALL. + (SINGLE_THREAD_P): Fix non-PIC and TLS case so to read the + correct variable. + * sysdeps/unix/sysv/linux/sh/vfork.S (__vfork): Branch to __fork + whenever libpthread.so is loaded. + +2003-02-08 Andreas Schwab <schwab@suse.de> + + * sysdeps/unix/sysv/linux/m68k/vfork.S: Branch to __fork whenever + libpthread.so is loaded. + +2003-02-07 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/vfork.S: Make sure + __ASSUME_VFORK_SYSCALL is not defined if the kernel headers have + no __NR_vfork definition. + +2003-02-07 Jakub Jelinek <jakub@redhat.com> + + * tst-popen2.c: New test. + * Makefile (tests): Add tst-popen2. + * sysdeps/unix/sysv/linux/alpha/vfork.S (__vfork): Branch to __fork + whenever libpthread.so is loaded. + * sysdeps/unix/sysv/linux/i386/vfork.S (__vfork): Likewise. + * sysdeps/unix/sysv/linux/ia64/vfork.S (__vfork): Likewise. + * 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/sparc/sparc32/vfork.S (__vfork): Likewise. + * sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S (__vfork): Likewise. + * sysdeps/unix/sysv/linux/x86_64/vfork.S (__vfork): Likewise. + +2003-02-05 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/bits/libc-lock.h (__libc_once): Set control + variable for non-libpthread case to the same value the + pthread_once function would use. + +2003-02-03 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S (__vfork): If + BROKEN_SPARC_WDISP22, handle SHARED the same way as non-SHARED. + +2003-02-04 Andreas Jaeger <aj@suse.de> + + * sysdeps/unix/sysv/linux/hppa/pt-initfini.c: Do not use + multi-line strings. + +2003-01-30 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/s390/tls.h (TLS_INIT_TP): Return NULL, not 0. + +2003-01-30 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/alpha/tls.h (THREAD_GETMEM, THREAD_GETMEM_NC, + THREAD_SETMEM, THREAD_SETMEM_NC): Avoid warnings about unused self + variable. + * sysdeps/ia64/pt-machine.h (THREAD_GETMEM, THREAD_GETMEM_NC, + THREAD_SETMEM, THREAD_SETMEM_NC): Likewise. + * sysdeps/s390/s390-32/pt-machine.h (THREAD_GETMEM, THREAD_GETMEM_NC, + THREAD_SETMEM, THREAD_SETMEM_NC): Likewise. + * sysdeps/s390/s390-64/pt-machine.h (THREAD_GETMEM, THREAD_GETMEM_NC, + THREAD_SETMEM, THREAD_SETMEM_NC): Likewise. + * sysdeps/sh/pt-machine.h (THREAD_GETMEM, THREAD_GETMEM_NC, + THREAD_SETMEM, THREAD_SETMEM_NC): Likewise. + * sysdeps/sparc/sparc32/pt-machine.h (THREAD_GETMEM, THREAD_GETMEM_NC, + THREAD_SETMEM, THREAD_SETMEM_NC): Likewise. + * sysdeps/sparc/sparc64/pt-machine.h (THREAD_GETMEM, THREAD_GETMEM_NC, + THREAD_SETMEM, THREAD_SETMEM_NC): Likewise. + +2003-01-27 Martin Schwidefsky <schwidefsky@de.ibm.com> + + * sysdeps/s390/s390-32/pt-machine.h (THREAD_SELF, INIT_THREAD_SELF): + Define TLS versions. + * sysdeps/s390/s390-64/pt-machine.h (THREAD_SELF, INIT_THREAD_SELF): + Likewise. + * sysdeps/s390/tls.h [HAVE_TLS_SUPPORT] (USE_TLS, TLS_INIT_TCB_SIZE, + TLS_INIT_TCB_ALIGN, TLS_TCB_SIZE, TLS_TCB_ALIGN, TLS_TCB_AT_TP, + INSTALL_DTV, INSTALL_NEW_DTV, GET_DTV, TLS_INIT_TP, THREAD_DTV): + Define. + * sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h (PSEUDO): Use + branch with 32 bit offset. + * sysdeps/unix/sysv/linux/s390/s390-64/vfork.S: Likewise. + +2003-01-24 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/sparc/sparc32/pt-machine.h (__thread_self): Change to %g7, + as required by TLS ABI. + * sysdeps/sparc/sparc64/pt-machine.h (__thread_self): Likewise. + * sysdeps/sparc/tls.h [HAVE_TLS_SUPPORT] (USE_TLS, TLS_INIT_TCB_SIZE, + TLS_INIT_TCB_ALIGN, TLS_TCB_SIZE, TLS_TCB_ALIGN, TLS_TCB_AT_TP, + INSTALL_DTV, INSTALL_NEW_DTV, GET_DTV, TLS_INIT_TP, THREAD_DTV): + Define. + [HAVE_TLS_SUPPORT]: Include descr.h and sysdep.h. + * sysdeps/unix/sysv/linux/sparc/sparc32/sysdep-cancel.h: Use %g7 + instead of %g6 for thread pointer. + * sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S: Likewise. + * sysdeps/unix/sysv/linux/sparc/sparc64/sysdep-cancel.h: Likewise. + * sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S: Likewise. + +2003-01-25 Guido Guenther <agx@sigxcpu.org> + + * sysdeps/unix/sysv/linux/mips/sysdep-cancel.h: New file. + * sysdeps/unix/sysv/linux/mips/Makefile: New file. + +2003-01-20 Martin Schwidefsky <schwidefsky@de.ibm.com> + + * sysdeps/unix/sysv/linux/s390/s390-32/vfork.S: Avoid non pc relative + reference to __fork. + +2003-01-17 Richard Henderson <rth@redhat.com> + + * sysdeps/alpha/tls.h (tcbhead_t): Clarify second member. + (TLS_TCB_SIZE, TLS_TCB_ALIGN): Set for tcbhead_t. + (TLS_PRE_TCB_SIZE): New. + (TLS_INIT_TP, THREAD_SELF, INIT_THREAD_SELF): Update for + new ia64-style thread pointer layout. + (THREAD_GETMEM, THREAD_GETMEM_NC): New. + (THREAD_SETMEM, THREAD_SETMEM_NC): New. + * sysdeps/unix/sysv/linux/alpha/vfork.S: Don't tail-call to __fork + if !SHARED. + +2003-01-15 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/ia64/tls.h (tcbhead_t): Use the TLS ABI required layout + if USE_TLS only. + (NONTLS_INIT_TP): Revert last change. + * sysdeps/ia64/tcb-offsets.sym (MULTIPLE_THREADS_OFFSET): Define to + offsetof (tcbhead_t, multiple_threads) if USE_TLS not defined. + +2003-01-16 Jakub Jelinek <jakub@redhat.com> + + * pthread.c (_pthread_initialize_minimal): Use + GL(dl_tls_dtv_slotinfo_list) != NULL to check whether TLS has + been already initialized. + +2003-01-16 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/i386/tls.h (INIT_SYSINFO): Initialize head->sysinfo even + if not SHARED. + +2003-01-15 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/pthread/bits/libc-lock.h (__libc_lock_init, + __libc_lock_init_recursive): Initialize fields directly. + +2003-01-15 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/alpha/vfork.S (__vfork): Allow + __fork to be far away from __vfork ifndef SHARED. + * sysdeps/unix/sysv/linux/powerpc/powerpc32/vfork.S (__vfork): + Likewise. + * sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S (__vfork): Likewise. + * sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S (__vfork): Likewise. + Add a missing instruction. + * sysdeps/unix/sysv/linux/arm/vfork.S (__vfork): Conditionally + branch to __fork even if __NR_vfork is not defined. + +2003-01-14 Ulrich Drepper <drepper@redhat.com> + + * tst-cancel-wrappers.sh: Allow .__*_asynccancel functions names + as well. + +2003-01-14 Steven Munroe <sjmunroe@us.ibm.com> + + * sysdeps/unix/sysv/linux/powerpc/powerpc64/vfork.S: New file. + +2003-01-14 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/ia64/vfork.S (JUMPTARGET): Remove. + +2003-01-13 Martin Schwidefsky <schwidefsky@de.ibm.com> + + * sysdeps/unix/sysv/linux/s390/s390-32/pt-initfini.c: Avoid + unterminated string literals. + * sysdeps/unix/sysv/linux/s390/s390-64/pt-initfini.c: Likewise. + +2003-01-13 Martin Schwidefsky <schwidefsky@de.ibm.com> + + * sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h + (PSEUDO): Code reordering. Move CENABLE and CDISABLE literals from + PSEUDO_END to PSEUDO. + (PSEUDO_END): Remove. + (SINGLE_THREAD_P): Save an instruction. + * sysdeps/unix/sysv/linux/s390/s390-32/vfork.S (__vfork): Add missing + parameter to SINGLE_THREAD_P call. + * sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h (PSEUDO): + Code reordering. + +2003-01-10 Andreas Schwab <schwab@suse.de> + + * sysdeps/unix/sysv/linux/m68k/vfork.S: New file. + +2003-01-10 Martin Schwidefsky <schwidefsky@de.ibm.com> + + * sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h (PSEUDO): Setup + backchain in pseudo_cancel. Minor code improvements. + * sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h (PSEUDO): + Likewise. + +2003-01-10 Martin Schwidefsky <schwidefsky@de.ibm.com> + + * sysdeps/unix/sysv/linux/s390/s390-32/vfork.S: New file. + * sysdeps/unix/sysv/linux/s390/s390-64/vfork.S: New file. + +2002-01-12 Franz Sirl <Franz.Sirl-kernel@lauterbach.com> + + * sysdeps/unix/sysv/linux/powerpc/powerpc32/vfork.S: New file. + +2002-01-09 Richard Henderson <rth@redhat.com> + + * sysdeps/unix/sysv/linux/alpha/sysdep-cancel.h: Assume only + ret follows pseudo, and thus avoid branch-to-branch in cancel + case. Use SYSCALL_ERROR_LABEL. + +2003-01-11 Philip Blundell <philb@gnu.org> + + * sysdeps/unix/sysv/linux/arm/vfork.S: New file. + * sysdeps/unix/sysv/linux/arm/sysdep-cancel.h (PSEUDO_RET): + Correctly unstack lr. + (UNDOARGS_5): Fix ordering of pushes and pops. + (SINGLE_THREAD_P_PIC): New. + (SINGLE_THREAD_P_INT): New. + (SINGLE_THREAD_P): Implement in terms of above. Restore lr if it + was stacked. + (PSEUDO): Use SINGLE_THREAD_P_INT. + +2003-01-11 Kaz Kojima <kkojima@rr.iij4u.or.jp> + + * sysdeps/unix/sysv/linux/sh/vfork.S: New file. + +2003-01-11 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/ia64/tls.h (tcbhead_t): Change into dtv_t *, void *. + [HAVE_TLS_SUPPORT] (USE_TLS, TLS_INIT_TCB_SIZE, TLS_INIT_TCB_ALIGN, + TLS_TCB_SIZE, TLS_PRE_TCB_SIZE, TLS_TCB_ALIGN, TLS_DTV_AT_TP, + INSTALL_DTV, INSTALL_NEW_DTV, GET_DTV, TLS_INIT_TP, THREAD_SELF, + INIT_THREAD_SELF): Define. + [HAVE_TLS_SUPPORT]: Include descr.h. + (NONTLS_INIT_TP): Point __thread_self at the end of dummy + struct _pthread_descr_struct. + * sysdeps/ia64/pt-machine.h (THREAD_GETMEM, THREAD_GETMEM_NC, + THREAD_SETMEM, THREAD_SETMEM_NC): Define using THREAD_SELF, + not __thread_self. + * sysdeps/ia64/tcb-offsets.sym (MULTIPLE_THREADS_OFFSET): Adjust + computation. + * pthread.c (__pthread_initialize_minimal): Use tcbp, not self + for TCB pointer. + (__pthread_initialize_manager): Rename tcb to mgr. + Use tcbp for TCB pointer, if TLS_DTV_AT_TP set mgr to sizeof (struct + _pthread_descr) below tcbp, otherwise to tcbp. + * manager.c (pthread_handle_create): If TLS_DTV_AT_TP, set + new_thread to be below _dl_allocate_tls (). Adjust new_thread back + before freeing. Fix clone arguments if report_events and USE_TLS. + (pthread_free): Adjust th back before freeing. + +2003-01-10 Steven Munroe <sjmunroe@us.ibm.com> + + * sysdeps/unix/sysv/linux/powerpc/powerpc32/Makefile: Moved to ... + * sysdeps/unix/sysv/linux/powerpc/Makefile: ...here. + * sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h: New File. + +2003-01-09 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/i386/vfork.S: New file. + * sysdeps/unix/sysv/linux/ia64/vfork.S: New file. + * sysdeps/unix/sysv/linux/ia64/sysdep-cancel.h + [__ASSEMBLER__] (SINGLE_THREAD_P): Remove trailing ;;. + * sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S: New file. + * sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S: New file. + * sysdeps/unix/sysv/linux/x86_64/vfork.S: New file. + * sysdeps/unix/sysv/linux/alpha/vfork.S: New file. + * tst-popen.c: New test. + * Makefile (tests): Add tst-popen. + +2003-01-06 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/sigwait.c (do_sigwait): Add + INTERNAL_SYSCALL_DECL, add err argument to INTERNAL_SYSCALL* macros. + +2003-01-06 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/alpha/sysdep-cancel.h (PSEUDO): Use + PSEUDO_PREPARE_ARGS. Fix branch condition after SINGLE_THREAD_P. + +2003-01-06 Philip Blundell <philb@gnu.org> + + * sysdeps/unix/sysv/linux/arm/sysdep-cancel.h: New file. + +2003-01-06 Jakub Jelinek <jakub@redhat.com> + + * internals.h (LIBC_CANCEL_HANDLED): Define. + * sysdeps/unix/sysv/linux/sigwait.c (LIBC_CANCEL_HANDLED): Add. + * signals.c (LIBC_CANCEL_HANDLED): Add. + * pt-system.c (LIBC_CANCEL_HANDLED): Add. + * tst-cancel-wrappers.sh: Remove all exceptions. + + * sysdeps/unix/sysv/linux/alpha/Makefile: New file. + +2003-01-05 Andreas Schwab <schwab@suse.de> + + * sysdeps/m68k/Makefile: New file, use -fPIC for nonshared + objects. + + * sysdeps/unix/sysv/linux/m68k/sysdep-cancel.h (SINGLE_THREAD_P): + Fix for PIC. + (CENABLE): Likewise. + (CDISABLE): Likewise. + +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>. + + * Makefile (libc.so-no-z-defs): Define to yes. + +2003-01-05 Kaz Kojima <kkojima@rr.iij4u.or.jp> + + * sysdeps/sh/tls.h: Include dl-sysdep.h and stdint.h. + (tcbhead_t): Add multiple_threads member. + (TLS_INIT_TP_EXPENSIVE): Define. + * sysdeps/unix/sysv/linux/sh/pt-initfini.c: Don't use multi-line + strings. Remove unused code. + * sysdeps/unix/sysv/linux/sh/sysdep-cancel.h: New file. + +2003-01-04 Franz Sirl <Franz.Sirl-kernel@lauterbach.com> + + * sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h: New file. + * sysdeps/unix/sysv/linux/powerpc/powerpc32/Makefile: New file. + +2003-01-04 Jakub Jelinek <jakub@redhat.com> + + * internals.h (LIBC_THREAD_GETMEM, LIBC_THREAD_SETMEM): Define + even if NOT_IN_libc is defined. + +2003-01-05 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h: New file. + * sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h: New file. + * sysdeps/s390/Makefile: New file. + * sysdeps/s390/tcb-offsets.sym: New file. + * sysdeps/s390/tls.h: New file. + +2003-01-03 Richard Henderson <rth@redhat.com> + + * sysdeps/unix/sysv/linux/alpha/sysdep-cancel.h: New file. + +2003-01-03 Andreas Jaeger <aj@suse.de> + + * sysdeps/pthread/bits/libc-tsd.h: Declare weak_extern functions. + +2003-01-03 Jakub Jelinek <jakub@redhat.com> + + * Makefile ($(objpfx)libpthread.so): Depend on ld.so. + +2003-01-02 Ulrich Drepper <drepper@redhat.com> + + * tst-cancel-wrappers.sh: Exclude sigwait.c as well, it does not have + cancellation tests. + +2003-01-02 Jakub Jelinek <jakub@redhat.com> + + * internals.h (struct pthread_functions): Rename + ptr_pthread_cond_* fields to ptr___pthread_cond_*. + * pthread.c (pthread_functions): Adjust. + * forward.c: Export both pthread_cond_*@@GLIBC_2.3.2 and + pthread_cond_*@GLIBC_2.0 compatibility symbols. + * Versions [libc] (GLIBC_2.3.2): Export pthread_cond_broadcast, + pthread_cond_destroy, pthread_cond_init, pthread_cond_signal + and pthread_cond_wait. + + * sysdeps/pthread/bits/pthreadtypes.h (__pthread_cond_align_t): New + type. + (pthread_cond_t): Add __align member, shorten __padding. + * sysdeps/pthread/pthread.h (PHTREAD_COND_INITIALIZER): Initialize + __padding and __align too. + + * sysdeps/pthread/bits/libc-lock.h (__libc_maybe_call2): Add + __builtin_expect. + * sysdeps/pthread/sigaction.c: New file. + * sysdeps/unix/sysv/linux/raise.c: New file. + * sysdeps/unix/sysv/linux/sigwait.c: New file. + * sysdeps/unix/sysv/linux/fork.c (__pthread_fork): Protect + weak_extern with #ifndef SHARED. + * sysdeps/unix/sysv/linux/jmp-unwind.c (__pthread_cleanup_upto): + Likewise. + * signals.c (__sigaction): Renamed to... + (__pthread_sigaction): ... this. + (__sigaction): New strong alias, #ifdef SHARED only. + (sigaction): Protect with #ifdef SHARED. + (sigwait): Renamed to... + (__pthread_sigwait): ... this. + (sigwait): New strong alias, #ifdef SHARED only. + (raise): Renamed to... + (__pthread_raise): ... this. + (raise): New strong alias, #ifdef SHARED only. + * internals.h (__pthread_sigaction, __pthread_sigwait, + __pthread_raise): New prototypes. + (struct pthread_functions): Add ptr_pthread_sigaction, + ptr_pthread_sigwait, ptr_pthread_raise. + * pthread.c (pthread_functions): Renamed to... + (__pthread_functions): ... this. No longer static, no longer + SHARED only. Initialize ptr_pthread_sigaction, ptr_pthread_sigwait + and ptr_pthread_raise. + [SHARED] (ptr_pthread_functions): Change to &__pthread_functions. + * libc-cancellation.c (__pthread_thread_self): Remove weak_extern. + * ptfork.c (__fork, __vfork): Protect with #ifdef SHARED. + * ptlongjmp.c (siglongjmp, longjmp): Protect with #ifdef SHARED. + + * Makefile (tests, tests-static): Add tst-cancel-static. + * tst-cancel-static.c: New test. + +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/pthread/bits/pthreadtypes.h (pthread_cond_t): Add padding. + * condvar.c: Add symbol versioning. The compatibility versions + are the same as the change in the interface does not effect this + implementation. + * Versions [libpthread]: Add definitions for new pthread_cond_* + interfaces for version GLIBC_2.3.2. + +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/i386/i686/pt-machine.h: Use __ASSEMBLER__ instead of + ASSEMBLER test macro. + * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h: Likewise. + * sysdeps/unix/sysv/linux/ia64/sysdep-cancel.h: Likewise. + * sysdeps/unix/sysv/linux/m68k/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/x86_64/sysdep-cancel.h: Likewise. + + * sysdeps/pthread/errno-loc.c (__errno_location): Add + libc_hidden_def. + * sysdeps/pthread/herrno-loc.c (__h_errno_location): Likewise. + * sysdeps/pthread/res-state.c (__res_state): Likewise. + * sysdeps/unix/sysv/linux/allocrtsig.c (__libc_current_sigrtmin, + __libc_current_sigrtmax): Likewise. + * Versions [libc] (GLIBC_PRIVATE): Remove __libc_internal_tsd_get, + __libc_internal_tsd_set, __libc_internal_tsd_address, + __libc_alloca_cutoff. + [libpthread] (GLIBC_PRIVATE): Remove __libc_internal_tsd_get, + __libc_internal_tsd_set, __libc_internal_tsd_address. + + * sysdeps/pthread/list.h: Remove assert.h include. + * sysdeps/unix/sysv/linux/fork.c: Include <fork.h>, not "fork.h". + + * sysdeps/pthread/list.h: New file. + * sysdeps/unix/sysv/linux/jmp-unwind.c: New file. + * sysdeps/unix/sysv/linux/fork.c: New file. + * sysdeps/unix/sysv/linux/fork.h: New file. + * sysdeps/unix/sysv/linux/ia64/fork.h: New file. + * sysdeps/unix/sysv/linux/sparc/fork.h: New file. + * sysdeps/unix/sysv/linux/register-atfork.c: New file. + * sysdeps/unix/sysv/linux/unregister-atfork.c: New file. + * sysdeps/unix/sysv/linux/Makefile: New file. + * sysdeps/unix/sysv/linux/Versions: New file. + * ptlongjmp.c (pthread_cleanup_upto): Rename to... + (__pthread_cleanup_upto): ...this. Add targetframe argument, + use it instead of currentframe. No longer static. + (siglongjmp, longjmp): Remove pthread_cleanup_upto calls. + * internals.h (__pthread_cleanup_upto, __pthread_fork): New prototypes. + (struct pthread_functions): Add ptr_pthread_fork, + ptr_pthread_cleanup_upto. + * pthread.c (pthread_functions): Initialize ptr_pthread_fork and + ptr_pthread_cleanup_upto. + * ptfork.c: Include fork.h. + (struct handler_list, struct handler_list_block): Remove. + (pthread_atfork_lock, pthread_atfork_prepare, pthread_atfork_parent, + pthread_atfork_child): Remove. + (pthread_insert_list, __pthread_atfork, pthread_call_handlers): Remove. + (__pthread_fork): New function. + (__fork, __vfork): Call __libc_fork. + * Makefile (libpthread-routines): Add old_pthread_atfork. + (libpthread-nonshared): Add pthread_atfork. + (others): Depend on $(objpfx)libpthread_nonshared.a. + ($(objpfx)libpthread_nonshared.a): New rule. + (install): Depend on $(inst_libdir)/libpthread.so. + ($(inst_libdir)/libpthread.so, $(inst_libdir)/libpthread_nonshared.a): + New rules. + (tests): Depend on libpthread_nonshared.a too. + * old_pthread_atfork.c: New file. + * pthread_atfork.c: New file. + * Makeconfig (shared-thread-library): Include libpthread_nonshared.a + too. + +2002-12-30 Jakub Jelinek <jakub@redhat.com> + + * forward.c: Make all functions available by default again. It + caused too much trouble. + * internals.h (struct pthread_functions): Rename ptr_pthread_exit + and ptr_pthread_attr_init_2_* to ptr___pthread_exit and + ptr___pthread_attr_init_2_*. + * pthread.c (pthread_functions): Adjust. + +2002-12-28 Jakub Jelinek <jakub@redhat.com> + + * libc_pthread_init.c (__libc_pthread_init): Remove + MULTIPLE_THREADS_OFFSET check. + * sysdeps/i386/tls.h: Include tcb-offsets.h in assembler. + (SYSINFO_OFFSET): Remove. + * sysdeps/i386/Makefile [csu] (gen-as-const-headers): Add + tcb-offsets.sym. + * sysdeps/i386/tcb-offsets.sym: New file. + * sysdeps/pthread/tcb-offsets.h: New file. + * sysdeps/sparc/sparc32/tls.h: Removed. + * sysdeps/sparc/sparc64/tls.h: Move... + * sysdeps/sparc/tls.h: ...here. Include tcb-offsets.h in assembler. + * sysdeps/sparc/Makefile: New file. + * sysdeps/sparc/tcb-offsets.sym: New file. + * sysdeps/ia64/tls.h: Include tcb-offsets.h in assembler. + * sysdeps/ia64/Makefile: New file. + * sysdeps/ia64/tcb-offsets.sym: New file. + * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h + (MULTIPLE_THREADS_OFFSET): Remove. + Replace defined MULTIPLE_THREADS_OFFSET + with defined FLOATING_STACKS && USE___THREAD. + * sysdeps/unix/sysv/linux/ia64/sysdep-cancel.h + (MULTIPLE_THREADS_OFFSET): Remove. + * sysdeps/unix/sysv/linux/sparc/sparc32/sysdep-cancel.h + (MULTIPLE_THREADS_OFFSET): Remove. + * sysdeps/unix/sysv/linux/sparc/sparc64/sysdep-cancel.h + (MULTIPLE_THREADS_OFFSET): Remove. + * pthread.c (__pthread_initialize_manager): Remove + MULTIPLE_THREADS_OFFSET cbeck. + + * tst-cancel-wrappers.sh: Add line continuations. + +2002-12-27 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/pthread/bits/libc-tsd.h: Include linuxthreads/descr.h + and bits/libc-lock.h. + (__libc_internal_tsd_get, __libc_internal_tsd_set, + __libc_internal_tsd_address): Remove. + (__pthread_internal_tsd_address, __pthread_internal_tsd_get, + __pthread_internal_tsd_set): New weak_externs. + (__libc_tsd_address, __libc_tsd_get, __libc_tsd_set): Define + using __libc_maybe_call2. + (__libc_tsd_key_t): Move to ... + * descr.h (__libc_tsd_key_t): ...here. + Remove bits/libc-tsd.h include. + * sysdeps/pthread/errno-loc.c: New file. + * sysdeps/pthread/herrno-loc.c: New file. + * sysdeps/pthread/res-state.c: New file. + * libc-cancellation.c (THREAD_GETMEM, THREAD_SETMEM): Remove. + (__libc_enable_asynccancel, __libc_disable_asynccancel): Use + thread_self unconditionally. Use LIBC_THREAD_[SG]ETMEM instead + of THREAD_[SG]ETMEM. + * specific.c (libc_internal_tsd_set): Renamed to... + __pthread_internal_tsd_set. Remove static. + (libc_internal_tsd_get): Renamed to... + __pthread_internal_tsd_get. Remove static. + (libc_internal_tsd_address): Renamed to... + __pthread_internal_tsd_address. Remove static. + (__libc_internal_tsd_set, __libc_internal_tsd_get, + __libc_internal_tsd_address, __libc_alloca_cutoff): Remove. + * internals.h [!NOT_IN_libc] (LIBC_THREAD_GETMEM, LIBC_THREAD_SETMEM): + Define. + (__pthread_internal_tsd_set, __pthread_internal_tsd_get, + __pthread_internal_tsd_address): New prototypes. + (struct pthread_functions): Add + ptr_pthread_internal_tsd_([sg]et|address) fields. + [!NOT_IN_libc && !FLOATING_STACKS] (thread_self): Define. + * pthread.c (pthread_functions) [!USE_TLS && !HAVE___THREAD]: + Initialize ptr_pthread_internal_tsd_([sg]et|address) fields. + * Versions (libpthread): Remove __libc_alloca_cutoff@GLIBC_PRIVATE. + * alloca_cutoff.c: New file. + * no-tsd.c: Removed. + * Makefile (routines): Remove no-tsd. Add alloca_cutoff. + * pt-system.c (system): Remove cancellation handling. + * tst-cancel-wrappers.sh: Allow pt-system.o* to not use the + cancellation routines. + + * sysdeps/i386/tls.h: Include dl-sysdep.h and stdint.h. + (tcbhead_t): Add sysinfo field. + (SYSINFO_OFFSET, INIT_SYSINFO): Define. + (TLS_INIT_TP): Use INIT_SYSINFO. + * sysdeps/unix/sysv/linux/i386/dl-sysdep.h: New file. + * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h + (MULTIPLE_THREADS_OFFSET): Adjust. + * sysdeps/unix/sysv/linux/ia64/sysdep-cancel.h + (MULTIPLE_THREADS_OFFSET): Likewise. + * sysdeps/unix/sysv/linux/sparc/sparc32/sysdep-cancel.h + (MULTIPLE_THREADS_OFFSET): Likewise. + * sysdeps/unix/sysv/linux/sparc/sparc64/sysdep-cancel.h + (MULTIPLE_THREADS_OFFSET): Likewise. + * descr.h: Include stdint.h. + (struct _pthread_descr_struct): Add p_header.data.sysinfo field. + +2002-12-22 Jakub Jelinek <jakub@redhat.com> + + * libc_pthread_init.c: Include stdlib.h. + * sysdeps/i386/tls.h (tcbhead_t): Add multiple_threads member. + (TLS_INIT_TP_EXPENSIVE): Define. + * sysdeps/pthread/bits/libc-lock.h (__libc_maybe_call, + __libc_maybe_call2): In _LIBC check SHARED define. + * sysdeps/ia64/tls.h: New file. + * sysdeps/unix/sysv/linux/ia64/sysdep-cancel.h: New file. + * sysdeps/unix/sysv/linux/ia64/Makefile: New file. + * sysdeps/x86_64/tls.h (TLS_INIT_TP_EXPENSIVE): Define. + * sysdeps/sparc/sparc32/tls.h: New file. + * sysdeps/sparc/sparc64/tls.h: New file. + * sysdeps/unix/sysv/linux/sparc/sparc32/sysdep-cancel.h: New file. + * sysdeps/unix/sysv/linux/sparc/sparc64/sysdep-cancel.h: New file. + * Makefile (tests): Add tst-cancel[1-6]. + (tests-reverse): Add tst-cancel5. + Link libc.so before libpthread.so for tests-reverse. + * tst-cancel1.c: New file. + * tst-cancel2.c: New file. + * tst-cancel3.c: New file. + * tst-cancel4.c: New file. + * tst-cancel5.c: New file. + * tst-cancel6.c: New file. + +2002-12-27 Andreas Schwab <schwab@suse.de> + + * sysdeps/unix/sysv/linux/m68k/sysdep-cancel.h: New file. + +2002-12-22 Roland McGrath <roland@redhat.com> + + * Makefile (omit-deps): Add $(unix-syscalls:%=ptw-%). + +2002-12-21 Ulrich Drepper <drepper@redhat.com> + + * pthread.c (init_rtsigs): Remove incomplete __builtin_expect. + Reported by Art Hass <ahaas@airmail.net>. + +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. + +2002-12-18 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/i386/useldt.h (FLOATING_STACKS, ARCH_STACK_MAX_SIZE): Only + define if __ASSUME_LDT_WORKS > 0. + * libc-cancellation.c (THREAD_GETMEM, THREAD_SETMEM): Redefine to + struct member access if !FLOATING_STACKS. + * sysdeps/pthread/flockfile.c (flockfile): Change into weak alias. + +2002-12-18 Jakub Jelinek <jakub@redhat.com> + + * internals.h (__pthread_thread_self): New prototype. + (struct pthread_functions): Add ptr_pthread_thread_self field. + * pthread.c (pthread_functions): Initialize ptr_pthread_thread_self. + (__pthread_thread_self): New function. + * libc-cancellation.c (__pthread_thread_self): Add weak_extern. + (__libc_enable_asynccancel, __libc_disable_asynccancel): Don't + use thread_self() directly if not FLOATING_STACKS. + +2002-12-18 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/x86_64/pt-machine.h: Guard most of the header + with #ifndef __ASSEMBLER__. + * pthread.c (pthread_functions): Use SHLIB_COMPAT around + pthread_attr_init_2_0 use. + +2002-12-17 Jakub Jelinek <jakub@redhat.com> + + * wrapsyscall.c: Removed. + * weaks.c: Removed. + * Makefile (distribute): Add tst-cancel-wrappers.sh. + (routines): Remove weaks. Add forward, + libc_pthread_init, libc-cancellation. + (shared-only-routines): Remove weaks. Add forward. + (libpthread-routines): Remove wrapsyscall. + Add 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-lseek64, + 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, pt-system, pt-allocrtsig. + (libpthread-shared-only-routines): Add pt-allocrtsig. + (tests): Depend on $(objpfx)tst-cancel-wrappers.out. + ($(objpfx)tst-cancel-wrappers.out): New rule. + * sysdeps/pthread/bits/libc-lock.h: Include linuxthreads/internals.h + if in libc. + (__libc_maybe_call): In libpthread.* don't check for existance + of the function. + (__libc_maybe_call2): Define. + (__libc_lock_init, __libc_lock_fini, __libc_lock_lock, + __libc_lock_trylock, __libc_lock_unlock): Use it. + * sysdeps/pthread/flockfile.c: New file. + * sysdeps/pthread/ftrylockfile.c: New file. + * sysdeps/pthread/funlockfile.c: New file. + * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h: New file. + * sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h: New file. + * sysdeps/unix/sysv/linux/allocrtsig.c: New file. + * libc-cancellation.c: New file. + * forward.c: New file. + * libc_pthread_init.c: New file. + * pt-system.c: New file. + * pthread.c: Remove locale.h. + (__pthread_manager_thread): Initialize multiple_threads. + (__pthread_multiple_threads): Declare. + (pthread_functions): New variable. + (__pthread_initialize_minimal): Remove __uselocale call. + Call __libc_pthread_init. + (__pthread_initialize_manager): Initialize __pthread_multiple_threads, + initial thread's multiple_threads and __libc_multiple_threads. + Check MULTIPLE_THREADS_OFFSET value. Initialize manager thread's + multiple_threads. + (pthread_setschedparam, pthread_getschedparam): Rename to __ + prefixed variants. Add strong_alias. + (current_rtmin, current_rtmax, __libc_current_sigrtmin, + __libc_current_sigrtmax, __libc_allocate_rtsig): Remove. + (init_rtsigs): Use __libc_current_sigrtmin_private. + (pthread_initialize): Only call init_rtsigs if + !__ASSUME_REALTIME_SIGNALS. + (__pthread_require_wrappers, __pthread_require_lockfile): Remove. + * internals.h (__pthread_attr_destroy, __pthread_attr_setdetachstate, + __pthread_attr_getdetachstate, __pthread_attr_setschedparam, + __pthread_attr_getschedparam, __pthread_attr_setschedpolicy, + __pthread_attr_getschedpolicy, __pthread_attr_setinheritsched, + __pthread_attr_getinheritsched, __pthread_attr_setscope, + __pthread_attr_getscope, __pthread_cond_init, + __pthread_cond_destroy, __pthread_cond_wait, + __pthread_cond_signal, __pthread_cond_broadcast, + __pthread_condattr_init, __pthread_condattr_destroy, + __pthread_equal, __pthread_getschedparam, + __pthread_setschedparam, __pthread_setcancelstate, + __pthread_setcanceltype, __pthread_enable_asynccancel, + __libc_enable_asynccancel, __libc_pthread_init): New prototype. + (__pthread_mutex_init, __pthread_mutex_destroy, + __pthread_mutex_lock, __pthread_mutex_unlock, + __pthread_mutex_trylock): Likewise. + Add hidden_proto. + (struct pthread_functions): New type. + (__libc_pthread_functions): New variable. + (LIBC_CANCEL_ASYNC, LIBC_CANCEL_RESET): Define. + * descr.h (struct _pthread_descr_struct): Add + p_header.data.multiple_threads field. + * manager.c (pthread_handle_create): Initialize multiple_threads. + * cancel.c (__pthread_enable_asynccancel, + __pthread_disable_asynccancel): New functions. + (__pthread_provide_wrappers): Remove. + (pthread_setcancelstate, pthread_setcanceltype): Rename to __ + prefixed variants. Add strong_alias. + * condvar.c (pthread_cond_init, pthread_cond_destroy, + pthread_cond_wait, pthread_cond_signal, pthread_cond_broadcast, + pthread_condattr_init, pthread_condattr_destroy): Likewise. + * join.c (pthread_exit): Likewise. + * attr.c (pthread_attr_destroy, pthread_attr_setdetachstate, + pthread_attr_getdetachstate, pthread_attr_setschedparam, + pthread_attr_getschedparam, pthread_attr_setschedpolicy, + pthread_attr_getschedpolicy, pthread_attr_setinheritsched, + pthread_attr_getinheritsched, pthread_attr_setscope, + pthread_attr_getscope): Likewise. + * mutex.c (__pthread_mutex_init, __pthread_mutex_destroy, + __pthread_mutex_lock, __pthread_mutex_unlock, + __pthread_mutex_trylock): Add hidden_def. + * Versions (libc): Add __libc_pthread_init, + __libc_current_sigrtmin_private, __libc_current_sigrtmax_private, + __libc_allocate_rtsig_private @@GLIBC_PRIVATE. + * lockfile.c: Remove some USE_IN_LIBIO guards. + (__pthread_provide_lockfile): Remove. + * pt-allocrtsig.c: New file. + * tst-cancel-wrappers.sh: New test. + +2002-12-15 Ulrich Drepper <drepper@redhat.com> + + * Versions [libpthread: GLIBC_2.3.2]: Remove creat, poll, pselect, + readv, select, sigpause, sigsuspend, sigwaitinfo, waitid, writev. + * wrapsyscall.c: Remove creat, poll, pselect, readv, select, + sigpause, sigsuspend, sigwaitinfo, waitid, and writev wrappers. + +2002-12-10 Ulrich Drepper <drepper@redhat.com> + + * wrapsyscall.c (CANCELABLE_SYSCALL): Don't define function as + weak. There is no reason for that. + (CANCELABLE_SYSCALL_VA): Likewise. + +2002-12-09 Ulrich Drepper <drepper@redhat.com> + + * wrapsyscall.c: Add wrappers for creat, poll, pselect, readv, select, + sigpause, __xpg_sigpause, sigsuspend, sigwaitinfo, waitid, and writev. + * Versions: Export creat, poll, pselect, readv, select, sigpause, + __xpg_sigpause, sigsuspend, sigwaitinfo, waitid, and writev from + libpthread in version GLIBC_2.3.2. + +2002-12-06 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/bits/libc-lock.h: Define __rtld_lock_* macros. + +2002-12-05 Roland McGrath <roland@redhat.com> + + * pthread.c (__pthread_initialize_minimal) + [USE_TLS && SHARED && !USE___THREAD]: Initialize TLS and set up the + TCB if the dynamic linker didn't do it at startup. + + * sysdeps/i386/tls.h (TLS_INIT_TP): Make it return zero or an error + string. + (TLS_DO_SET_THREAD_AREA, TLS_DO_MODIFY_LDT, TLS_SETUP_GS_SEGMENT): + Submacros updated. + * sysdeps/x86_64/tls.h (TLS_INIT_TP): Likewise. + * sysdeps/alpha/tls.h (TLS_INIT_TP): Likewise (always zero). + +2002-12-03 Roland McGrath <roland@redhat.com> + + * pthread.c (pthread_initialize) [SHARED]: Copy dl_error_tsd value + from dynamic linker internal cell to new libc cell. + +2002-11-28 Roland McGrath <roland@redhat.com> + + * tst-context.c: #define IS_IN_libpthread around #include <tls.h> + before other headers, so FLOATING_STACKS is not defined wrongly. + + * sysdeps/i386/tls.h [!IS_IN_libpthread]: Enable TLS support + even if [! FLOATING_STACKS]. + (TLS_DO_MODIFY_LDT_KERNEL_CHECK): New macro. + If not under [__ASSUME_LDT_WORKS > 0], then do a runtime check of + dl_osversion >= 2.3.99 and fatal if not. + (TLS_DO_MODIFY_LDT): Use it. + +2002-11-28 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/bits/posix_opt.h: Define macros which + require it to 200112L. Remove _POSIX_POLL and _POSIX_SELECT. + * sysdeps/unix/sysv/linux/i386/bits/posix_opt.h: Likewise. + +2002-11-19 Ulrich Drepper <drepper@redhat.com> + + * Versions (libc: GLIBC_2.0): Remove names of functions which are + not defined in libc. + * Makefile (shared-only-routines): Add weaks. + * weaks.c: Remove functions which are not exported from libc.so. + +2002-11-14 Roland McGrath <roland@redhat.com> + + * libc-tsd.c: New file. + * Makefile (distribute): Add it. + (libc-link.so): New variable. + ($(objpfx)libpthread.so): Depend on that instead of libc.so file name. + (libc-ok-for-link): New variable. + [$(versioning) = yes]: Include $(common-objpfx)tls.make and define + libc-ok-for-link to $(use-thread). + [$(libc-ok-for-link) = no] + (libc-link.so): Set to $(objpfx)libc.so, not $(common-objpfx)libc.so. + ($(objpfx)libc_pic_lite.a,$(objpfx)libc_pic_lite.os, $(objpfx)libc.so): + New targets. + (generated): Append them. + (extra-objs): Append libc-tsd.os. + + * libc-tls-loc.c: New file. + * Makefile (libpthread-routines): Add it. + +2002-11-14 Andreas Schwab <schwab@suse.de> + + * sysdeps/unix/sysv/linux/ia64/pt-initfini.c: Fix unterminated + string. + +2002-11-13 Roland McGrath <roland@redhat.com> + + * Examples/ex6.c (main): Improve error reporting. + +2002-11-04 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/i386/Makefile: Compile pthread.c and sighandler.c with + -fno-omit-frame-pointer. Patch by Andreas Steinmetz <ast@domdv.de>. + + * sysdeps/i386/useldt.h [PIC] (USETLS_LOAD_EBX): Use correct input + register number. + (DO_SET_THREAD_AREA): Mark asm output specifiers correctly. + +2002-10-22 Jakub Jelinek <jakub@redhat.com> + + * manager.c (pthread_start_thread): Call __uselocale even + if [! SHARED]. Patch by Leon Kanter <leon@geon.donetsk.ua>. + +2002-10-17 Roland McGrath <roland@redhat.com> + + * Makefile (unload): Don't link in libpthread.so. + ($(objpfx)unload.out): Do depend on it. + * unload.c (main): Improve error reporting. + +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) + (__libc_atfork): Use it. + + * pthread.c [SHARED] (__libc_dl_error_tsd): New function. + (pthread_initialize) [SHARED]: Set _dl_error_catch_tsd to that. + * Versions (libc: GLIBC_PRIVATE): Add __libc_dl_error_tsd. + (ld: GLIBC_PRIVATE): Set removed. + +2002-10-11 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/execve.c: New file. + +2002-10-09 Jakub Jelinek <jakub@redhat.com> + + * no-tsd.c: Include stdlib.h. + +2002-10-07 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/allocalim.h: New file. + * descr.h (struct _pthread_descr_struct): Add p_alloca_cutoff + field. + * manager.c (__pthread_allocate_stack): Add out_stacksize argument. + Pass stack size to caller. + (pthread_handle_create): Set p_alloca_cutoff. + * pthread.c (__pthread_initial_thread): Use C99 designated + initializers. Set p_alloca_cutoff. + (__pthread_manager_thread): Likewise. + (__pthread_initialize_minimal) [USE_TLS]: Set p_alloca_cutoff + for initial thread. + (__pthread_init_max_stacksize): Possibly decrease p_alloca_cutoff + for initial thread. + (__pthread_initialize_manager) [USE_TLS]: Set p_alloca_cutoff + for manager thread. + * specific.c (__libc_alloca_cutoff): New function. + * no-tsd.c (__libc_alloca_cutoff): New function. + * Versions: Export __libc_alloca_cutoff@@GLIBC_PRIVATE from libc + and libpthread. + +2002-10-02 Kaz Kojima <kkojima@rr.iij4u.or.jp> + + * sysdeps/sh/pt-machine.h: Make C code ifndef'ed with __ASSEMBLER__. + * sysdeps/sh/tls.h: Likewise. + * sysdeps/unix/sysv/linux/sh/smp.h: New file. + +2002-09-29 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/pthread/tst-timer.c (main): Clear + SIGEV2.sigev_notify_attributes. + +2002-09-29 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/i386/useldt.h (DO_SET_THREAD_AREA): Don't use + INLINE_SYSCALL for set_thread_area syscall. + +2002-09-28 Roland McGrath <roland@redhat.com> + + * pthread.c (__pthread_reset_main_thread) [FLOATING_STACKS]: + Don't call setrlimit, since we did no prior bogon we need to undo. + +2002-09-27 Roland McGrath <roland@redhat.com> + + * sysdeps/x86_64/tls.h [__ASSEMBLER__]: Don't include <pt-machine.h>. + +2002-09-24 Roland McGrath <roland@redhat.com> + + * sysdeps/x86_64/tls.h: New file. + +2002-09-23 Roland McGrath <roland@redhat.com> + + * Examples/ex13.c (dump_mut): int -> size_t for counter. + +2002-09-18 Bruno Haible <bruno@clisp.org> + + * Examples/ex10.c (thread): Fail if pthread_mutex_timedlock() returns + an unexpected error code. + + * internals.h (__pthread_message): Add const to first parameter type. + * pthread.c (__pthread_message): Likewise. + + * sysdeps/unix/sysv/linux/configure: Moved to ../sysdeps/pthread. + +2002-09-17 Roland McGrath <roland@redhat.com> + + * sysdeps/i386/tls.h (TLS_DO_MODIFY_LDT, TLS_DO_SET_THREAD_AREA): + Set the descriptor limit to the full 4GB, so %gs:OFFSET works for any + offset (positive or negative) relative to the thread struct. + * sysdeps/i386/useldt.h (DO_MODIFY_LDT, DO_SET_THREAD_AREA): Likewise. + +2002-09-12 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/sparc/sparc64/Makefile: Move... + * sysdeps/unix/sysv/linux/sparc/Makefile: ...here. + Replace /usr/lib/crt[in].o with crt[in].o too. + +2002-09-11 Steven Munroe <sjmunroe@us.ibm.com> + + * sysdeps/powerpc/powerpc64/pt-machine.h: New file. + +2002-09-04 Bruno Haible <bruno@clisp.org> + + * pthread.c: Include <sys/time.h>. + (is_smp_system): Move to sysdeps/unix/sysv/linux/smp.h. + * sysdeps/unix/sysv/linux/smp.h: New file, extracted from pthread.c. + * Makefile (distribute): Add smp.h to the list. + +2002-09-04 Bruno Haible <bruno@clisp.org> + + * sysdeps/alpha/pt-machine.h: Choose different include file location + on non-Linux platforms. + + * wrapsyscall.c (PROMOTE_INTEGRAL_TYPE): New macro. + (open, open64): Change va_arg argument type to the integral type to + which mode_t promotes. + + * sysdeps/pthread/tst-timer.c (main): Don't assume anything about + the structure of 'struct sigevent'. + + * errno.c (__errno_location, __h_errno_location, __res_state): + Use prototype function definitions. + +2002-07-29 Steven Munroe <sjmunroe@us.ibm.com> + + * shlib-versions: Set libpthread version to 2.3 for powerpc64. + * sysdeps/powerpc/pt-machine.h: moved to... + * sysdeps/powerpc/powerpc32/pt-machine.h: ...here + * sysdeps/powerpc/powerpc64/pt-machine.h: New file. + +2002-09-02 Roland McGrath <roland@redhat.com> + + * sysdeps/powerpc/Makefile (CFLAGS-pt-initfini.s): New variable. + +2002-09-01 Roland McGrath <roland@redhat.com> + + * sysdeps/pthread/bits/libc-tsd.h (enum __libc_tsd_key_t): Add new keys + CTYPE_B, CTYPE_TOLOWER, CTYPE_TOUPPER. + + * sysdeps/pthread/bits/libc-tsd.h (__libc_tsd_address): New macro. + (__libc_internal_tsd_address): Declare it. + * Versions (libc, ld, libpthread: GLIBC_PRIVATE): Add + __libc_internal_tsd_address. + * specific.c (libc_internal_tsd_address): New function. + (__libc_internal_tsd_address): New variable. + * no-tsd.c (__libc_internal_tsd_address): New variable. + +2002-08-31 Ulrich Drepper <drepper@redhat.com> + + * Makefile: Don't use rule for crt%.o, spell it out as rules for + crti.o and crtn.o. + +2002-08-30 Roland McGrath <roland@redhat.com> + + * Makefile (extra-objs, omit-deps): Add crtn. + ($(objpfx)libpthread.so): Depend on $(objpfx)crtn.o. + ($(objpfx)libpthread.so: +postinit): Append $(objpfx)crtn.o. + ($(objpfx)crtn.S): New target. + ($(objpfx)crt%.o): Pattern rule replaces crti.o target. + (generated): Add crtn.S. + + * sysdeps/unix/sysv/linux/x86_64/Makefile ($(objpfx)specs): Massage + crtn.o pathname too. + +2002-08-30 Jakub Jelinek <jakub@redhat.com> + + * pthread.c (__pthread_initialize_minimal): Call __uselocale even + if [! SHARED]. + +2002-08-30 Roland McGrath <roland@redhat.com> + + * tst-static-locale.c: New file. + * Makefile (tests, tests-static): Add it. + +2002-04-24 Steven Munroe <sjmunroe@us.ibm.com> + + * spinlock.c (__pthread_lock): Fix spurious wakeup + handling. Don't clear lowest bit of list pointer as sign the thread + is still on the wait list. Don't restart after spurious wakeup + with spinning to get the lock. + (__pthread_unlock): Take set lowest bit into account when handling + pointer to list elements. + Patch by Steve Munroe <sjmunroe@us.ibm.com>. + +2002-08-28 Roland McGrath <roland@redhat.com> + + * sysdeps/pthread/timer_routines.c (thread_func): Fix type in cast. + +2002-08-28 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/hppa/aio_cancel.c: New file. + * sysdeps/unix/sysv/linux/sparc/aio_cancel.c: New file. + * sysdeps/unix/sysv/linux/alpha/aio_cancel.c: New file. + +2002-08-28 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/timer_routines.c (thread_func): Change return + type to void and add casts in use to avoid warnings with all gcc + versions. + +2002-08-08 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/bits/local_lim.h (PTHREAD_THREADS_MAX): + Bump to 16384. + * manager.c (__pthread_handles): Remove. + * pthandles.c: New file. + * pthread.c (__pthread_initialize_minimal): Initialize + __pthread_handles[0] and __pthread_handles[1]. + * Makefile (libpthread-routines): Add pthandles (must be last). + +2002-08-26 Brian Youmans <3diff@gnu.org> + + * Examples/ex10.c: Corrected version number in Lesser GPL copying + permission notice from 2 to 2.1. + * Examples/ex11.c: Likewise. + * Examples/ex13.c: Likewise. + * Examples/ex8.c: Likewise. + * Examples/ex9.c: Likewise. + * barrier.c: Likewise. + * events.c: Likewise. + * lockfile.c: Likewise. + * no-tsd.c: Likewise. + * pt-machine.c: Likewise. + * ptclock_gettime.c: Likewise. + * ptclock_settime.c: Likewise. + * rwlock.c: Likewise. + * sysdeps/alpha/pspinlock.c: Likewise. + * sysdeps/alpha/pt-machine.h: Likewise. + * sysdeps/arm/pspinlock.c: Likewise. + * sysdeps/arm/pt-machine.h: Likewise. + * sysdeps/cris/pspinlock.c: Likewise. + * sysdeps/cris/pt-machine.h: Likewise. + * sysdeps/hppa/pspinlock.c: Likewise. + * sysdeps/hppa/pt-machine.h: Likewise. + * sysdeps/i386/i686/pt-machine.h: Likewise. + * sysdeps/i386/pspinlock.c: Likewise. + * sysdeps/i386/pt-machine.h: Likewise. + * sysdeps/i386/useldt.h: Likewise. + * sysdeps/ia64/pspinlock.c: Likewise. + * sysdeps/ia64/pt-machine.h: Likewise. + * sysdeps/m68k/pspinlock.c: Likewise. + * sysdeps/m68k/pt-machine.h: Likewise. + * sysdeps/mips/pspinlock.c: Likewise. + * sysdeps/mips/pt-machine.h: Likewise. + * sysdeps/powerpc/pspinlock.c: Likewise. + * sysdeps/powerpc/pt-machine.h: Likewise. + * sysdeps/pthread/bits/initspin.h: Likewise. + * sysdeps/pthread/bits/libc-lock.h: Likewise. + * sysdeps/pthread/bits/libc-tsd.h: Likewise. + * sysdeps/pthread/getcpuclockid.c: Likewise. + * sysdeps/pthread/posix-timer.h: Likewise. + * sysdeps/pthread/timer_create.c: Likewise. + * sysdeps/pthread/timer_delete.c: Likewise. + * sysdeps/pthread/timer_getoverr.c: Likewise. + * sysdeps/pthread/timer_gettime.c: Likewise. + * sysdeps/pthread/timer_routines.c: Likewise. + * sysdeps/pthread/timer_settime.c: Likewise. + * sysdeps/pthread/tst-timer.c: Likewise. + * sysdeps/s390/pspinlock.c: Likewise. + * sysdeps/s390/s390-32/pt-machine.h: Likewise. + * sysdeps/s390/s390-64/pt-machine.h: Likewise. + * sysdeps/sh/pspinlock.c: Likewise. + * sysdeps/sh/pt-machine.h: Likewise. + * sysdeps/sparc/sparc32/pspinlock.c: Likewise. + * sysdeps/sparc/sparc32/pt-machine.h: Likewise. + * sysdeps/sparc/sparc32/sparcv9/pspinlock.c: Likewise. + * sysdeps/sparc/sparc64/pspinlock.c: Likewise. + * sysdeps/sparc/sparc64/pt-machine.h: Likewise. + * sysdeps/unix/sysv/linux/bits/local_lim.h: Likewise. + * sysdeps/unix/sysv/linux/bits/posix_opt.h: Likewise. + * sysdeps/unix/sysv/linux/bits/sigthread.h: Likewise. + * sysdeps/unix/sysv/linux/hppa/bits/initspin.h: Likewise. + * sysdeps/unix/sysv/linux/i386/bits/posix_opt.h: Likewise. + * tststack.c: Likewise. + * unload.c: Likewise. + * weaks.c: Likewise. + * wrapsyscall.c: Likewise. + + * sysdeps/pthread/pt-initfini.c: Changed copying + permission notice to Lesser GPL from Library GPL, including the + references in the special exception. + * sysdeps/unix/sysv/linux/hppa/pt-initfini.c: Likewise. + * sysdeps/unix/sysv/linux/ia64/pt-initfini.c: Likewise. + * sysdeps/unix/sysv/linux/s390/s390-32/pt-initfini.c: + Likewise. + * sysdeps/unix/sysv/linux/s390/s390-64/pt-initfini.c: + Likewise. + * sysdeps/unix/sysv/linux/sh/pt-initfini.c: Likewise. + +2002-08-26 Ulrich Drepper <drepper@redhat.com> + + * Examples/ex10.c (thread): tv_nsec == 1000000000 is already + overflow [PR libc/4244]. + +2002-08-25 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/timer_routines.c (thread_func): Make the + compiler happy by adding a return statement which will never be + reached. + + * tst-context.c (main): Cast to long before casting to pointer. + + * Examples/ex17.c (main): Use correct format string. + + * Examples/ex9.c (thread): Remove incorrect return statement. + +2002-08-23 Ulrich Drepper <drepper@redhat.com> + + * pthread.c (__linuxthreads_version): New global constant. + +2002-08-23 Andreas Jaeger <aj@suse.de> + + * sysdeps/x86_64/pt-machine.h: Use %fs instead of %gs + as thread specific register. + (testandset): Fix inline asm. + (THREAD_GETMEM): Fix inline asm. + +2002-08-22 Roland McGrath <roland@redhat.com> + + * sysdeps/i386/useldt.h (INIT_THREAD_SELF): Remove [HAVE_TLS_SUPPORT] + conditional. + (INIT_THREAD_SELF): Pass second arg to DO_SET_THREAD_AREA. + (DO_SET_THREAD_AREA): Take second arg, pass to DO_SET_THREAD_AREA_REUSE + macro. That chooses whether to reuse %gs value or let kernel set it. + [USE_TLS] (DO_SET_THREAD_AREA_REUSE): New macro, always 1. + [!USE_TLS] (DO_SET_THREAD_AREA_REUSE): New macro, true if arg is + not constant 0. + +2002-08-21 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/i386/tls.h (TLS_SETUP_GS_SEGMENT): Add new parameter + also to the third definition of this macro. + +2002-06-17 Andreas Jaeger <aj@suse.de> + + * sysdeps/unix/sysv/linux/x86_64/Makefile (CFLAGS-pt-initfini.s): + Set it. + +2002-08-20 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/i386/useldt.h: Go back to using 16-bit instructions when + loading/reading segment registers. Some old hardware doesn't + handle the 32-bit instructions as expected. + * sysdeps/i386/tls.h: Likewise. + + * sysdeps/i386/tls.h (TLS_DO_SET_THREAD_AREA): Second parameter is + renamed to secondcall and use is negated. + (TLS_SETUP_GS_SEGMENT): Likewise. + (TLS_INIT_TP): Likewise. + * sysdeps/sh/tls.h (TLS_INIT_TP): Second parameter is renamed to + secondcall. + + * sysdeps/i386/tls.h: Use 32-bit operations when handling segment + registers. No need to mask upper 16 bits in this case. + * sysdeps/i386/useldt.h: Likewise. + (DO_SET_THREAD_AREA): We have to load %gs again even if the value + is the same since the GDT content changed. + + * sysdeps/i386/tls.h (TLS_INIT_TP): Add new parameter and pass it on + to TLS_SETUP_GS_SEGMENT. + (TLS_SETUP_GS_SEGMENT): Add new parameter and pass it on to + TLS_DO_SET_THREAD_AREA. + (TLS_DO_SET_THREAD_AREA): If new parameter is zero determine + entry number from %gs value. + * sysdeps/sh/tls.h (TLS_INIT_TP): Add new parameter and simply + ignore it. + + * manager.c (pthread_handle_create): Pass NULL to _dl_allocate_tls. + Pass true to _dl_deallocate_tls. + (pthread_free): Likewise. + * pthread.c (__pthread_initialize_manager): Likewise. + +2002-08-19 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/i386/useldt.h (DO_SET_THREAD_AREA): Use correct shift when + computing index from %gs value. + +2002-08-16 Roland McGrath <roland@redhat.com> + + * sysdeps/i386/tls.h (TLS_DO_SET_THREAD_AREA): Calculate segment + register value from entry number properly. + + * sysdeps/i386/tls.h (TLS_DO_MODIFY_LDT): Rewrite asm to use %ebx + optimally conditional on [__PIC__]. + (TLS_DO_SET_THREAD_AREA): New macro, implement inline syscall + without touching errno, and use latest modify_ldt-like interface. + (TLS_SETUP_GS_SEGMENT): Use that instead of INLINE_SYSCALL. + * sysdeps/i386/useldt.h (DO_MODIFY_LDT): Set %gs in this macro. + (DO_SET_THREAD_AREA): New macro, uses current syscall interface with + existing %gs value as the segment to set. + (INIT_THREAD_SELF): Rewritten using those. Use set_thread_area only + under [HAVE_TLS_SUPPORT] so we can rely on the initialization done + by the first thread's early TLS setup. + +2002-08-15 Roland McGrath <roland@redhat.com> + + * sysdeps/i386/tls.h (TLS_INIT_TP): Use statement expression and + return a value as callers now expect. + +2002-08-11 Roland McGrath <roland@redhat.com> + + * pthread.c (__pthread_initialize_manager): Initialize + p_header.data.tcb field of manager thread's descriptor. + (__pthread_initialize_minimal): Don't initialize p_header.data.self + field, already done by TLS_INIT_TP. + + * manager.c (pthread_handle_create): Move p_header field initializers + together. + +2002-08-08 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/i386/tls.h (TLS_DO_SET_THREAD_AREA): Removed. + +2002-08-07 Ulrich Drepper <drepper@redhat.com> + + * pthread.c (__linuxthreads_initial_report_events): New variable. + (__pthread_initialize_manager): Use it to initialize p_report_events + of initial thread. + [TLS]: Store pointer to descriptor of manager in __pthread_handles. + +2002-08-07 Roland McGrath <roland@redhat.com> + + * sysdeps/i386/tls.h (TLS_DO_MODIFY_LDT): Add an extra argument with + an "m" constraint to the asm so the compiler knows LDT_ENTRY was used. + +2002-08-02 Roland McGrath <roland@redhat.com> + + * sysdeps/pthread/bits/libc-tsd.h (enum __libc_tsd_key_t): + Add _LIBC_TSD_KEY_LOCALE. + * manager.c (pthread_start_thread) [!(USE_TLS && HAVE___THREAD)]: + Call __uselocale to initialize our per-thread locale pointer to + the global one. + * pthread.c (__pthread_initialize_minimal): Likewise. + + * sysdeps/i386/tls.h (TLS_DO_SET_THREAD_AREA): Add missing \s. + +2002-08-02 Ulrich Drepper <drepper@redhat.com> + + * pthread.c: Declare _errno, _h_errno, and _res unless we use TLS + internally. + + * cancel.c (__pthread_perform_cleanup) [USE_TLS && HAVE___THREAD]: + Don't use p_libc_specific element in thread descriptor. + +2002-07-30 Roland McGrath <roland@redhat.com> + + * sysdeps/pthread/bits/libc-tsd.h: Include <tls.h>. + [USE_TLS && HAVE___THREAD]: Just include the sysdeps/generic file, + which does the right thing when __thread support is available. + * descr.h (struct _pthread_descr_struct) [USE_TLS && HAVE___THREAD]: + Omit `p_libc_specific', `p_errnop', `p_errno', `p_h_errnop', + `p_h_errno', `p_resp', and `p_res' members. + * pthread.c (__pthread_initialize_minimal) [USE_TLS && HAVE___THREAD]: + Don't initialize `p_errnop' and `p_h_errnop' members. + (__pthread_reset_main_thread): Likewise. + (__pthread_initialize_manager): Likewise. + * manager.c (__pthread_manager, pthread_handle_create): Likewise. + * pthread.c (pthread_initialize) [USE_TLS && HAVE___THREAD]: + Don't initialize `p_resp' member. + (__pthread_reset_main_thread): Likewise. + * manager.c (pthread_handle_create): Likewise. + * specific.c (libc_internal_tsd_set, libc_internal_tsd_get): + Conditionalize these on [!(USE_TLS && HAVE___THREAD)]. + * no-tsd.c: Conditionalize contents on [!(USE_TLS && HAVE___THREAD)]. + * errno.c [USE_TLS && HAVE___THREAD] + (__h_errno_location, __res_state): Don't define these at all. + + * sysdeps/i386/tls.h (INSTALL_DTV): Add parens around arguments! + (INSTALL_NEW_DTV, GET_DTV): Likewise. + * sysdeps/sh/tls.h (INSTALL_DTV, INSTALL_NEW_DTV, GET_DTV): Likewise. + + * weaks.c: Don't include <errno.h> here. + +2002-08-01 Roland McGrath <roland@redhat.com> + + * sysdeps/i386/tls.h (TLS_DO_MODIFY_LDT): New macro, broken out of + TLS_INIT_TP. + (TLS_DO_SET_THREAD_AREA): New macro, uses thread_set_area syscall. + (TLS_SETUP_GS_SEGMENT): New macro, try one or the other or both. + (TLS_INIT_TP): Use that. + +2002-08-02 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/i386/useldt.h (DO_MODIFY_LDT): Move from INIT_THREAD_SELF. + (INIT_THREAD_SELF): Use sys_thread_area syscall instead if available. + (FREE_THREAD): Avoid modify_ldt if using GDT. + * sysdeps/i386/pspinlock.c (__have_no_set_thread_area): New variable. + +2002-07-25 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/i386/tls.h: Use __ASSEMBLER__ test macro not ASSEMBLER. + * sysdeps/i386/pt-machine.h: Likewise. + * sysdeps/i386/useldt.h: Likewise. + +2002-07-22 Ulrich Drepper <drepper@redhat.com> + + * pthread.c (__pthread_initialize_minimal): If !SHARED and TLS + call __libc_setup_tls first. + * Makefile: Actually create tst-signal.out file when running the test. + (tests): Add tststatic. + * Examples/tststatic.c: New file. + +2002-07-19 Ulrich Drepper <drepper@redhat.com> + + * errno.c (__errno_location): Don't define unless !USE_TLS + || !HAVE___THREAD. + * sysdeps/i386/pt-machine.c: Protect C code with #ifndef ASSEMBLER. + * sysdeps/i386/tls.h: Likewise. + * sysdeps/i386/useldt.h: Likewise. + * sysdeps/i386/i686/pt-machine.h: Likewise. + +2002-07-02 H.J. Lu <hjl@gnu.org> + + * sysdeps/mips/pspinlock.c: Don't include <sgidefs.h>. Always + use ll/sc. + * sysdeps/mips/pt-machine.h: Likewise. + +2002-07-14 Ulrich Drepper <drepper@redhat.com> + + * manager.c (pthread_handle_create): Initialize self-reference in + descriptor. + +2002-07-01 Jakub Jelinek <jakub@redhat.com> + + * Examples/ex9.c (main): Remove unused th variable. + +2002-07-10 Ulrich Drepper <drepper@redhat.com> + + * wrapsyscall.c: Add __nanosleep alias. + * Versions (GLIBC_2.2.6): Add __nanosleep. + * bug-sleep.c: New file. + * Makefile (tests): Add bug-sleep. + +2002-06-19 Steven Munroe <sjmunroe@vnet.ibm.com> + + * Examples/ex9.c (main): Use list of children and join them. + (thread): Do not call exit. + +2002-06-20 Ulrich Drepper <drepper@redhat.com> + + * spinlock.c (wait_node_alloc): We cannot use compare-and-exchange. + Unconditionally use the code using spinlock. Use __pthread_release + to free a spinlock. + (wait_node_free): Likewise. + (__pthread_acquire, __pthread_release): Unconditionally define. + +2002-06-07 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/ia64/pt-machine.h (MEMORY_BARRIER): Fix typo. + +2002-05-24 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/ia64/pt-machine.h (MEMORY_BARRIER): Use __sync_synchronize. + +2002-05-21 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/pthread.h (pthread_create): Rename first + parameter. + (pthread_cancel): Likewise. + * internals.h (__pthread_create_2_1): Likewise. + * sysdeps/unix/sysv/linux/bits/sigthread.h (pthread_kill): Likewise. + +2002-05-20 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/alpha/pt-machine.c (THREAD_SELF): Remove clobber. + Patch by Glen Nakamura <gen@flex.com>. + +2002-05-03 Ulrich Drepper <drepper@redhat.com> + + * signals.c: Move sighandler functions to... + * sighandler.c: ...here. New file. + * signals.c: Move signal handler related type definitions to... + * internals.h: ...here. Add prototypes for signal handlers. + * Makefile (libpthread-routines): Add sighandler. + (CFLAGS-sighandler.c): Add $(exceptions). + +2002-04-30 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/x86_64/Makefile: New file. + +2002-04-08 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/timer_getoverr.c: Return real overrun. + * sysdeps/pthread/posix-timer.h (struct timer_node): Add overrun_count. + * sysdeps/pthread/timer_routines.c (thread_func): Schedule next timeout + based on previous one and not on current time. Count overruns. + Patch by Eric F. Sorton <eric@cctcorp.com>. + + * sysdeps/unix/sysv/linux/bits/local_lim.h: Add DELAYTIMER_MAX. + +2002-04-08 kaz Kojima <kkojima@rr.iij4u.or.jp> + + * sysdeps/sh/pt-machine.h: Define _PT_MACHINE_H + if it isn't defined yet. + (FLOATING_STACKS, ARCH_STACK_MAX_SIZE): Defined. + (THREAD_GETMEM, THREAD_GETMEM_NC, THREAD_SETMEM, THREAD_SETMEM_NC): + Likewise. + * sysdeps/sh/tls.h: New file. + +2002-04-08 Jakub Jelinek <jakub@redhat.com> + + * manager.c (__pthread_manager_event): Use self instead of arg + for INIT_THREAD_SELF. + * sysdeps/i386/useldt.h (INIT_THREAD_SELF): Use sizeof (struct + _pthread_descr_struct) instead of sizeof (*descr). + +2002-04-05 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/ia64/pt-machine.h: Protect against multiple inclusion. + * sysdeps/alpha/pt-machine.h: Likewise. + * sysdeps/arm/pt-machine.h: Likewise. + * sysdeps/cris/pt-machine.h: Likewise. + * sysdeps/hppa/pt-machine.h: Likewise. + * sysdeps/m68k/pt-machine.h: Likewise. + * sysdeps/mips/pt-machine.h: Likewise. + * sysdeps/powerpc/pt-machine.h: Likewise. + * sysdeps/s390/s390-32/pt-machine.h: Likewise. + * sysdeps/s390/s390-64/pt-machine.h: Likewise. + * sysdeps/sh/pt-machine.h: Likewise. + * sysdeps/sparc/sparc32/pt-machine.h: Likewise. + * sysdeps/sparc/sparc64/pt-machine.h: Likewise. + * sysdeps/x86_64/pt-machine.h: Likewise. + +2002-04-05 Jakub Jelinek <jakub@redhat.com> + + * man/pthread_mutexattr_init.man (pthread_mutexattr_settype): Document + instead of pthread_mutexattr_setkind_np. + (pthread_mutexattr_gettype): Similarly. + * man/pthread_mutexattr_setkind_np.man: New. + * man/Makefile (SOURCES): Add pthread_mutexattr_setkind_np.man. + +2002-04-02 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/ia64/pt-machine.h (MEMORY_BARRIER): Define. + +2002-03-22 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/mips/pt-machine.h (MEMORY_BARRIER): Remove. + +2002-03-22 Ulrich Drepper <drepper@redhat.com> + + * internals.h (MEMORY_BARRIER): Define as asm with memory as clobber. + +2002-03-17 Andreas Jaeger <aj@suse.de> + + * sysdeps/i386/pt-machine.h: Add testandset and __compare_and_swap + prototpyes. + * sysdeps/alpha/pt-machine.h: Likewise. + * sysdeps/arm/pt-machine.h: Likewise. + * sysdeps/cris/pt-machine.h: Likewise. + * sysdeps/hppa/pt-machine.h: Likewise. + * sysdeps/i386/i686/pt-machine.h: Likewise. + * sysdeps/ia64/pt-machine.h: Likewise. + * sysdeps/m68k/pt-machine.h: Likewise. + * sysdeps/mips/pt-machine.h: Likewise. + * sysdeps/powerpc/pt-machine.h: Likewise. + * sysdeps/s390/s390-32/pt-machine.h: Likewise. + * sysdeps/s390/s390-64/pt-machine.h: Likewise. + * sysdeps/sh/pt-machine.h: Likewise. + * sysdeps/sparc/sparc32/pt-machine.h: Likewise. + * sysdeps/sparc/sparc64/pt-machine.h: Likewise. + * sysdeps/x86_64/pt-machine.h: Likewise. + + * internals.h: Move testandset and __compare_and_swap prototypes + to pt-machine.h. + +2002-03-03 Andreas Jaeger <aj@suse.de> + + * errno.c: Include resolv.h to avoid warning. + +2002-02-27 Ulrich Drepper <drepper@redhat.com> + + * pthread.c [USE_TLS] (thread_self_stack): Correct check for upper + stack limit. + +2002-02-23 Ulrich Drepper <drepper@redhat.com> + + * attr.c (pthread_getattr_np): Don't take thread descriptor size + into account if USE_TLS. + * manager.c (pthread_handle_create): Free TLS data structures if call + failed. Pass correct stack to clone if USE_TLS. + * sysdeps/i386/pt-machine.h: Handle multiple inclusion. + * sysdeps/i386/i686/pt-machine.h: Likewise. + * sysdeps/i386/tls.h: Unconditionally include <pt-machine.h>. + + * descr.h (struct _pthread_descr_struct): Update p_header for TLS. + Add p_stackaddr element #if USE_TLS. + * internals.c: Include <tls.h>. + * manager.c: Integrate creating and handling of thread descriptor + for TLS. + * pthread.c: Likewise. + * sysdeps/i386/tls.h (tcbhead_t): Add self pointer. + Include <linuxthreads/descr.h> only if TLS is really used. + (GET_DTV): New macro. + (TLS_INIT_TP): Initialize self pointer. + +2002-02-17 Andreas Schwab <schwab@suse.de> + + * signals.c (sigwait): Check for old sighandler being SIG_ERR, + not NULL. + +2002-02-12 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/i386/tls.c (INSTALL_NEW_DTV): Define. + (INSTALL_DTV): Adjust for being passed pointer to element with length. + +2002-02-08 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/i386/tls.h (TLS_INIT_TP): Also initialize %gs. + +2002-02-08 Richard Henderson <rth@redhat.com> + + * sysdeps/alpha/elf/pt-initfini.c: Use \n\ for multiline string. + +2002-02-08 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/i386/tls.h: TLS cannot be supported with FLOATING_STACKS + after all. + +2002-02-07 H.J. Lu <hjl@gnu.org> + + * sysdeps/mips/pspinlock.c (__pthread_spin_lock): Silence the + gcc warning. + (__pthread_spin_lock): Remove ".set noreorder". + * sysdeps/mips/pt-machine.h (__compare_and_swap): Liekwise. + +2002-02-05 H.J. Lu <hjl@gnu.org> + + * sysdeps/mips/pspinlock.c (__pthread_spin_lock): Not use + branch likely. + * sysdeps/mips/pt-machine.h (testandset): Likewise. + (__compare_and_swap): Likewise. + +2002-02-07 Ulrich Drepper <drepper@redhat.com> + + * internals.h: Move declarations/definitions of + __pthread_initial_thread_bos, __pthread_initial_thread, + __pthread_manager_thread_bos, __pthread_manager_thread_tos, + __pthread_manager_thread, __pthread_nonstandard_stacks, STACK_SIZE, + CURRENT_STACK_FRAME, __pthread_find_self, and thread_self... + * descr.h: ...here. + * sysdeps/i386/tls.h: Add TLS definitions also for !FLOATING_STACKS. + Define THREAD_GETMEM accordingly. + +2002-02-06 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/i386/tls.h: Include <stddef.h> for size_t. + + * sysdeps/i386/tls.h: Define THREAD_DTV. + +2002-02-04 Ulrich Drepper <drepper@redhat.com> + + * internals.h: Move thread descriptor definition... + * descr.h.: ...here. New file. + * sysdeps/i386/tls.h: New file. + +2002-02-01 H.J. Lu <hjl@gnu.org> + + * sysdeps/mips/pspinlock.c (__pthread_spin_lock): Use a + different register in the delayed slot. Use branch likely. + + * sysdeps/mips/pt-machine.h (testandset): Call _test_and_set. + (__compare_and_swap): Return 0 only when failed to compare. Use + branch likely. + +2002-02-01 Jakub Jelinek <jakub@redhat.com> + + * Versions (__libc_internal_tsd_get, __libc_internal_tsd_set, + __pthread_kill_other_threads_np): Move to GLIBC_PRIVATE. + * sysdeps/i386/i586/Versions: Move all symbols to GLIBC_PRIVATE. + * sysdeps/i386/i686/Versions: Move all symbols to GLIBC_PRIVATE. + * sysdeps/sparc/sparc32/sparcv9/Versions: New file. + * sysdeps/sparc/sparc64/Versions: New file. + * sysdeps/ia64/Versions: Move all symbols to GLIBC_PRIVATE. + +2002-01-31 Ulrich Drepper <drepper@redhat.com> + + * pthread.c: _dl_cpuclock_offset is not any longer a global variable + in SHARED code, use GL(dl_cpuclock_offset). + +2002-01-28 Andreas Jaeger <aj@suse.de> + + * sysdeps/mips/pspinlock.c (__pthread_spin_init): Clear *LOCK to + 0. Patch by Machida Hiroyuki <machida@sm.sony.co.jp>. + +2002-01-16 Martin Schwidefsky <schwidefsky@de.ibm.com> + + * sysdeps/s390/s390-32/pt-machine.h (MEMORY_BARRIER): Define. + (CURRENT_STACK_FRAME): Remove duplicate definition. + * sysdeps/s390/s390-64/pt-machine.h: Likewise. + +2002-01-14 Martin Schwidefsky <schwidefsky@de.ibm.com> + + * Makefile (CFLAGS-tst-cancel.c): Add -fno-inline-functions to prevent + automatic inline. + +2002-01-12 Andreas Schwab <schwab@suse.de> + + * Makefile (test-srcs): Add tst-signal. + (tests): Run tst-signal. + (distribute): Add tst-signal.sh. + * tst-signal.c, tst-signal.sh: New files. + +2002-01-14 Andreas Jaeger <aj@suse.de> + + * sysdeps/x86_64/pt-machine.h (INIT_THREAD_SELF): Avoid warning. + +2002-01-11 Andreas Schwab <schwab@suse.de> + + * signals.c (sighandler): Initialize all elements to SIG_ERR. + (__sigaction): Don't use value from sighandler if it is SIG_ERR. + +2002-01-06 Richard Henderson <rth@redhat.com> + + * sysdeps/alpha/elf/pt-initfini.c: New file. + +2001-12-29 Andreas Jaeger <aj@suse.de> + + * Examples/ex9.c: Add noreturn attribute for thread. + * Examples/ex10.c: Likewise. + * Examples/ex13.c (thread_start): Likewise. + * Examples/ex15.c (worker): Likewise. + + * Examples/ex18.c: Include unistd.h for prototype of sleep. + +2001-12-14 Ulrich Drepper <drepper@redhat.com> + + * man/pthread_atfork.man: Adjust description of mutex handling + after fork for current implementation. + * linuxthreads.texi: Likewise [PR libc/2519]. + +2001-12-13 Andreas Schwab <schwab@suse.de> + + * specific.c (pthread_key_delete): Don't contact the thread + manager if no threads have been created yet. + +2001-12-12 NIIBE Yutaka <gniibe@m17n.org> + + * sysdeps/sh/pt-machine.h (INIT_THREAD_SELF): Added __volatile__ + qualifier to be safe. + +2001-11-30 Andreas Schwab <schwab@suse.de> + + * pthread.c (pthread_handle_sigcancel) [THREAD_SELF]: Double check + that self is the manager thread, and initialize the thread + register if not. + (thread_self_stack) [THREAD_SELF]: New function to find self via + stack pointer. + * manager.c (pthread_handle_create): Don't block cancel signal any + more. + +2001-11-29 Andreas Jaeger <aj@suse.de> + + * sysdeps/x86_64/pt-machine.h: Use %gs as thread specific register. + (THREAD_SELF): New. + (INIT_THREAD_SELF): New. + (THREAD_GETMEM): New. + (THREAD_GETMEM_NC): + (THREAD_SETMEM): New. + (THREAD_SETMEM_NC): New. + (FLOATING_STACKS): Define. + (ARCH_STACK_MAX_SIZE): Define. + +2001-11-28 Kaz Kylheku <kaz@ashi.footprints.net> + + Bugfix to pthread_key_delete. It was iterating over the thread + manager's linked list of threads, behind the thread manager's + back causing a race. The fix is to have the manager iterate over + the threads instead, using a new request type for doing so. + * internals.h (struct pthread_request): New manager request type + REQ_FOR_EACH_THREAD. + * manager.c (pthread_for_each_thread): New function. + (__pthread_manager): Handle new REQ_FOR_EACH_THREAD request. + * specific.c (struct pthread_key_delete_helper_args): New type. + (pthread_key_delete_helper): New static function. + (pthread_key_delete): Use the new thread manager + REQ_FOR_EACH_THREAD function to iterate over the threads and set + the delete key slot to a null value in each thread. + * Examples/ex18.c: New test. + * Makefile (tests): Add ex18. + +2001-11-22 Wolfram Gloger <wg@malloc.de> + + * pthread.c (pthread_onexit_process): Don't call free + after threads have been asynchronously terminated. + + * manager.c (pthread_handle_exit): Surround cancellation + of threads with __flockfilelist()/__funlockfilelist(). + +2001-11-26 Andreas Schwab <schwab@suse.de> + + * manager.c (pthread_handle_create): Start the child thread with + the cancel signal blocked, so that it does not handle it before + the thread register is set up. Save errno from failed clone call. + +2001-11-15 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/i386/i686/Implies: Removed. + * sysdeps/i386/i686/Versions: New file. + +2001-10-31 Andreas Jaeger <aj@suse.de> + + * sysdeps/x86_64/Makefile: Remove, we do not need it anymore. + +2001-10-05 Kevin Buettner <kevinb@cygnus.com> + + * pthread.c (__linuxthread_pthread_sizeof_descr): Change name + to __linuxthreads_pthread_sizeof_descr to match name used by + symbol_list_arr[LINUXTHREADS_PTHREAD_SIZEOF_DESCR] in + linuxthreads_db/td_symbol_list.c. + +2001-09-22 Andreas Jaeger <aj@suse.de> + + * linuxthreads/tst-context.c: Avoid compile warning. + +2001-09-20 Andreas Jaeger <aj@suse.de> + + * shlib-versions: Add x86-64. + +2001-09-19 Andreas Jaeger <aj@suse.de> + + * sysdeps/x86_64/Makefile: New file. + * sysdeps/x86_64/pspinlock.c: New file. + * sysdeps/x86_64/pt-machine.h: New file. + +2001-09-12 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/pthread/timer_delete.c (timer_delete): Thread may be NULL + for SIGEV_NONE. + * sysdeps/pthread/timer_settime.c (timer_settime): Likewise. + +2001-09-11 Ulrich Drepper <drepper@redhat.com> + Wolfram Gloger <wg@malloc.de> + + * join.c: Protect all communications from and to manager with + TEMP_FAILURE_RETRY. + * manager.c: Likewise. + * pthread.c: Likewise. + * smeaphore.c: Likewise. + +2001-08-29 Ulrich Drepper <drepper@redhat.com> + + * spinlock.c (__pthread_lock): Top max_count value with + MAX_ADAPTIVE_SPIN_COUNT. + * internals.h (MAX_ADAPTIVE_SPIN_COUNT): Define if not already done. + + * sysdeps/i386/i686/pt-machine.h (BUSY_WAIT_NOP): New macro to + help P4. + +2001-08-27 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/pthread/bits/libc-lock.h (__libc_rwlock_t): Only define to + non-opaque type if __USE_UNIX98. + +2001-08-26 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/pthread/bits/libc-lock.h (__libc_lock_t): Define + non-opaque lock types also if _IO_MTSAFE_IO is defined. + +2001-08-23 Roland McGrath <roland@frob.com> + + * sysdeps/pthread/bits/libc-lock.h (__libc_cleanup_region_start): Take + new first argument, skip the cleanup handler if it's zero. + (_LIBC_LOCK_RECURSIVE_INITIALIZER): New macro. + (__libc_lock_define_initialized_recursive): Use it. + * sysdeps/pthread/bits/stdio-lock.h: File removed. + The sysdeps/generic file from the main tree now suffices. + +2001-08-22 Roland McGrath <roland@frob.com> + + * sysdeps/pthread/bits/stdio-lock.h: Include <bits/libc-lock.h> + instead of <pthread.h>. + (_IO_lock_t): Define this typedef using __libc_lock_define_recursive. + (_IO_lock_initializer): Add braces. + (_IO_lock_lock): Use __libc_lock_lock_recursive. + (_IO_lock_unlock): Use __libc_lock_unlock_recursive. + + * sysdeps/pthread/bits/libc-lock.h (__libc_lock_recursive_t): New type. + (__libc_lock_define_initialized_recursive): Use it. + (__libc_lock_init_recursive): Likewise. + (__libc_lock_fini_recursive): Likewise. + (__libc_lock_lock_recursive): Likewise. + (__libc_lock_trylock_recursive): Likewise. + (__libc_lock_unlock_recursive): Likewise. + (__libc_lock_define_recursive): New macro. + +2001-08-14 Jakub Jelinek <jakub@redhat.com> + + * lockfile.c (__pthread_provide_lockfile): New variable. + * pthread.c (__pthread_require_lockfile): New variable. + * cancel.c (__pthread_require_lockfile): New variable. + +2001-07-31 Ulrich Drepper <drepper@redhat.com> + + * tst-context.c (threadfct): Initialize context before calling + makecontext. + + * Examples/ex17.c: Make sure test thread is around long enough. + +2001-07-26 kaz Kojima <kkojima@rr.iij4u.or.jp> + + * sysdeps/sh/pt-machine.h (THREAD_SELF, INIT_THREAD_SELF): Defined. + +2001-07-24 Ulrich Drepper <drepper@redhat.com> + + * tst-context.c (main): Print explanation before bailing out + because context handling is not supported. + +2001-07-23 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add tst-context. + * tst-context.c: New file. + + * sysdeps/pthread/bits/stdio-lock.h: Define + _IO_cleanup_region_start_noarg. + +2001-07-23 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/alpha/pt-machine.h (FLOATING_STACKS): Define. + (ARCH_STACK_MAX_SIZE): Define. + * sysdeps/sparc/sparc32/pt-machine.h: Likewise. + * sysdeps/sparc/sparc64/pt-machine.h: Likewise. + +2001-07-19 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/i386/useldt.h: Fix typo in ARCH_STACK_MAX_SIZE comment. + + * sysdeps/ia64/pt-machine.h (FLOATING_STACKS): Define. + (ARCH_STACK_MAX_SIZE): Define. + * manager.c (pthread_allocate_stack): Handle FLOATING_STACKS with + NEED_SEPARATE_REGISTER_STACK. + +2001-07-16 Andreas Schwab <schwab@suse.de> + + * Makefile (before-compile): Don't add $(objpfx)crti.o. + (omit-deps): Add crti. + ($(objpfx)libpthread.so): Depend on $(objpfx)crti.o, but make sure + it is filtered out of the link command. + +2001-07-16 Ulrich Drepper <drepper@redhat.com> + + * pthread.c (pthread_initialize): For FLOATING_STACKS don't bother + to find the right value for __pthread_initial_thread_bos, it's not + used. If not FLOATING_STACKS first run + __pthread_init_max_stacksize. + +2001-06-16 H.J. Lu <hjl@gnu.org> + + * internals.h: Include <stackinfo.h>. + + * attr.c: Don't include <stackinfo.h> here. + * cancel.c: Likewise. + * manager.c: Likewise. + * pthread.c: Likewise. + * ptlongjmp.c: Likewise. + +2001-03-23 Matthew Wilcox <willy@ldl.fc.hp.com> + + * attr.c: Make _STACK_GROWS_UP work. + * internals.h: Likewise. + * manager.c: Likewise. + * pthread.c: Likewise. + +2001-06-15 H.J. Lu <hjl@gnu.org> + + * pthread.c (__pthread_reset_main_thread): Fix a typo. + +2001-02-02 John S. Marvin <jsm@udlkern.fc.hp.com> + + * semaphore.h: Use struct _pthread_fastlock as an element of + sem_t instead of an identical struct. + * rwlock.c: Remove casts. + * semaphore.c: Likewise. + +2001-04-30 Alan Modra <amodra@one.net.au> + + * sysdeps/unix/sysv/linux/hppa/pt-initfini.c: New. + +2001-05-25 Bruce Mitchener <bruce@cubik.org> + + * linuxthreads.texi: Spelling corrections. + +2001-05-25 Ulrich Drepper <drepper@redhat.com> + + * oldsemaphore.c (__old_sem_wait): Clear p_nextwaiting before + returning successfully. + Patch by Gene Cooperman <gene@ccs.neu.edu>. + +2001-05-24 Ulrich Drepper <drepper@redhat.com> + + * spinlock.c (__pthread_lock) [HAS_COMPARE_AND_SWAP]: Before doing any + serious work try once whether the lock is uncontested. + Remove duplicate reading of __status before loop. + Change suggested by Hans Boehm <hans_boehm@hp.com>. + + * spinlock.h (__pthread_trylock): Remove need for oldstatus variable. + (__pthread_alt_trylock): Likewise. + +2001-05-01 Kaz Kylheku <kaz@ashi.footprints.net> + + Memory barrier overhaul following line by line inspection. + * mutex.c (pthread_once): Missing memory barriers added. + * pthread.c (__pthread_wait_for_restart_signal, + __pthread_timedsuspend_new, __pthread_restart_new): Added + memory barriers ``just in case'' and for documentary value. + * spinlock.c (__pthread_release): New inline function for releasing + spinlock, to complement __pthread_acquire. Includes memory + barrier prior to assignment to spinlock, and __asm __volatile + dance to prevent reordering or optimization of the spinlock access. + * spinlock.c (__pthread_unlock, __pthread_alt_lock, + __pthread_alt_timedlock, __pthread_alt_unlock, + __pthread_compare_and_swap): Updated to use new __pthread_release + instead of updating spinlock directly. + * spinlock.c (__pthread_lock, __pthread_unlock, wait_node_alloc, + wait_node_free, wait_node_dequeue, __pthread_alt_lock, + __pthread_alt_timedlock, __pthread_alt_unlock, __pthread_acquire): + Memory barrier overhaul. Lots of missing memory barriers added, + a couple needless ones removed. + * spinlock.c (__pthread_compare_and_swap): testandset optimization + removed, just calls __pthread_acquire, which has the new read + barrier in it before its testandset. + +2001-05-20 Roland McGrath <roland@frob.com> + + * Makeconfig: New file, variables used to be in main libc Makeconfig. + +2001-05-09 Geoff Keating <geoffk@redhat.com> + + * sysdeps/powerpc/pt-machine.h + (HAS_COMPARE_AND_SWAP_WITH_RELEASE_SEMANTICS): Define. + (__compare_and_swap): Remove memory barriers. + (__compare_and_swap_with_release_semantics): New function. + +2001-04-24 Andreas Jaeger <aj@suse.de> + + * wrapsyscall.c: send* and recv* return ssize_t. + + * sysdeps/pthread/timer_getoverr.c (timer_getoverrun): Unlock the + mutex instead of double locking it. + Reported by Pierre Artaud <partaud@sodatec.com>. + +2001-04-23 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/getcpuclockid.c: Make function generic, test + using #ifdef whether the clock is available. + * sysdeps/unix/sysv/linux/i386/getcpuclockid.c: Removed. + + * sysdeps/ia64/Versions: New file. + + * sysdeps/unix/sysv/linux/ia64/pt-initfini.c (_init): We don't + have to call __gmon_start__ in the libpthread DSO. + * sysdeps/pthread/pt-initfini.c (_init): Likewise. + + * Makefile (libpthread-routines): Add ptclock_gettime and + ptclock_settime. + * internals.h: Don't use cpuclock-init.h definitions, use + hp-timing.h definitions. + * pthread.c: Likewise. + * manager.c: Likewise. + * ptclock_gettime.c: New file. + * ptclock_settime.c: New file. + * internals.h: Fix parameter type for __pthread_clock_gettime and + __pthread_clock_settime. + + * sysdeps/i386/i586/ptclock_gettime.c: Removed. + * sysdeps/i386/i586/ptclock_settime.c: Removed. + * sysdeps/i386/i586/Makefile: Removed. + +2001-04-22 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/bits/posix_opt.h: Define _POSIX_ASYNCH_IO. + * sysdeps/unix/sysv/linux/i386/bits/posix_opt.h: Likewise. + +2001-04-21 Andreas Jaeger <aj@suse.de> + + * sysdeps/pthread/timer_routines.c (thread_func): Add noreturn + attribute, remove statements that will never be executed. + (thread_func): Remove mutex_unlock call since it's never executed. + (thread_func): Fix comment as suggested by Jakub Jelinek. + + * manager.c (__pthread_manager): Add noreturn + attribute. + (pthread_start_thread): Likewise, remove return statement. + (pthread_start_thread_event): Likewise. + Add noreturn attribute for pthread_handle_exit. + * weaks.c: Add noreturn attribute for pthread_exit. + + * internals.h: Add __pthread_clock_gettime and + __pthread_clock_settime prototypes. + +2001-04-21 Ulrich Drepper <drepper@redhat.com> + + * internals.h: Include <cpuclock-init.h>. + (struct _pthread_descr_struct): Add p_cpuclock_offset field if + CPUCLOCK_VARDEF is defined. + * pthread.c (__pthread_initialize_minimal): Initialize + p_cpuclock_offset field for main thread if CPUCLOCK_INIT is defined. + * manager.c (pthread_start_thread): Set p_cpuclock_offset field + for new thread to current CPU clock value. + + * sysdeps/i386/useldt.h: Extend all the macros to handle 8-byte values. + + * sysdeps/i386/i586/Makefile: New file. + * sysdeps/i386/i586/Versions: New file. + * sysdeps/i386/i586/ptclock_gettime.c: New file. + * sysdeps/i386/i586/ptclock_settime.c: New file. + * sysdeps/i386/i686/Implies: New file. + +2001-04-18 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/sparc/sparc64/Makefile: Put specs into + $generated, not $postclean-generated. + +2001-04-18 Andreas Jaeger <aj@suse.de> + + * Makefile (otherlibs): Added. + +2001-04-18 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/sparc/sparc64/Makefile: New file. + +2001-04-16 Ulrich Drepper <drepper@redhat.com> + + * signals.c (sigwait): NSIG is no signal number. Block all + signals while in signal handler for signals in SET. + Patch by Manfred Spraul <manfred@colorfullife.com>. + +2001-04-12 Ulrich Drepper <drepper@redhat.com> + + * tst-cancel.c: Disable most tests. Add new test where all + cleanup handlers must run. + * Makefile (tests): Add tst-cancel again. + + * cancel.c (__pthread_perform_cleanup): Correct condition for + leaving cleanup loop early. + + * sysdeps/i386/Makefile: Make sure gcc uses a frame pointer for + all the files which use CURRENT_STACK_FRAME. + * sysdeps/i386/pt-machine.h (CURRENT_STACK_FRAME): Define using + __builtin_frame_address. + * sysdeps/i386/i686/pt-machine.h: Likewise. + +2001-04-11 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Comment out tst-cancel for now. + + * tst-cancel.c (main): Cleanup 4 is supposed to run. Create + temporary file in object directory. + * Makefile: Don't allow inlining when compiling tst-cancel.c. + Pass $(objpfx) to tst-cancel. + +2001-04-11 David S. Miller <davem@redhat.com> + + * sysdeps/sparc/sparc32/pt-machine.h (stack_pointer): Advance + up closer to user local variables so that new cleanup heuristics work. + * sysdeps/sparc/sparc64/pt-machine.h (stack_pointer): Likewise. + +2001-04-11 Ulrich Drepper <drepper@redhat.com> + + * cancel.c (_pthread_cleanup_push): Catch invalid __prev buffer + and remove it. + (_pthread_cleanup_push_defer): Likewise. + + * tst-cancel.c (main): Fix loop printing cleanup output. + +2001-04-10 kaz Kojima <kkojima@rr.iij4u.or.jp> + + * sysdeps/sh/pspinlock.c (__pthread_spin_lock): Fix a reverse + test. + (__pthread_spin_trylock): Likewise. + * sysdeps/sh/pt-machine.h (testandset): Likewise. + +2001-04-10 Ulrich Drepper <drepper@redhat.com> + + * join.c (pthread_exit): Move code to new function __pthread_do_exit + which takes an extra parameter with the current frame pointer. + Call new function with CURRENT_STACK_FRAME. + (__pthread_do_exit): New function. Call __pthread_perform_cleanup + with the new parameter. + (pthread_join): Call __pthread_do_exit instead of pthread_exit. + * cancel.c (__pthread_perform_cleanup): Takes extra parameter. Use + this parameter as the initial value the cleanup handler records are + compared against. No active cleanup handler record must have an + address lower than the previous one and the initial record must be + above (below on PA) the frame address passed in. + (pthread_setcancelstate): Call __pthread_do_exit instead of + pthread_exit. + (pthread_setcanceltype): Likewise. + (pthread_testcancel): Likewise. + (_pthread_cleanup_pop_restore): Likewise. + * condvar.c (pthread_cond_wait): Likewise. + (pthread_cond_timedwait_relative): Likewise. + * manager.c (pthread_start_thread): Likewise. + * oldsemaphore.c (__old_sem_wait): Likewise. + * pthread.c (pthread_handle_sigcancel): Likewise. + * semaphore.c (__new_sem_wait): Likewise. + (sem_timedwait): Likewise. + * ptlongjmp.c (pthread_cleanup_upto): Also use current stack frame + to limit the cleanup handlers which get run. + * internals.h: Add prototype for __pthread_do_exit. Adjust prototype + for __pthread_perform_cleanup. + + * Makefile (tests): Add tst-cancel. + * tst-cancel.c: New file. + +2001-04-08 Hans-Peter Nilsson <hp@axis.com> + + * sysdeps/cris/pt-machine.h: New file. + * sysdeps/cris/pspinlock.c: New file. + +2001-04-09 Hans-Peter Nilsson <hp@axis.com> + + * shlib-versions: Add case for Linux on CRIS. + +2001-03-26 Ulrich Drepper <drepper@redhat.com> + + * attr.c (pthread_getattr_np): Correct computation of stack size + for machiens with register stack. + + * Examples/ex17.c (main): Correct detection of failed mmap call. + +2001-03-21 Jakub Jelinek <jakub@redhat.com> + + * pthread.c (__pthread_initialize_manager): Fix a typo. + +2001-03-21 Jakub Jelinek <jakub@redhat.com> + + * attr.c (__pthread_attr_setstack): Fix alignment check. + (pthread_getattr_np): __stackaddr is top of stack, not bottom. + * Makefile (tests): Add ex17 test. + * Examples/ex17.c: New test. + +2001-03-20 Ulrich Drepper <drepper@redhat.com> + + * Makefile: Define -D_RPC_THREAD_SAFE_ for cancel.c. + * cancel.c (__pthread_perform_cleanup): Call __rpc_thread_destroy. + * sysdeps/pthread/bits/libc-tsd.h: Define _LIBC_TSD_KEY_VARS. + +2001-03-18 Ulrich Drepper <drepper@redhat.com> + + * Makefile: When generating DSO link with libc_nonshared.a. + +2001-02-26 Jakub Jelinek <jakub@redhat.com> + + * signals.c (pthread_sighandler): Use CALL_SIGHANDLER. + +2001-02-23 Jakub Jelinek <jakub@redhat.com> + + * internals.h (__pthread_init_max_stacksize): New prototype. + * attr.c (__pthread_attr_setstacksize): Call + __pthread_init_max_stacksize if not yet initialized. + * pthread.c (__pthread_init_max_stacksize): New function. + (__pthread_initialize_manager): Call it. + Patch by <dtc@cmucl.cons.org>. + +2001-03-16 Ulrich Drepper <drepper@redhat.com> + + * attr.c (pthread_getattr_np): Fix __stacksize computation for IA-64. + +2001-03-13 Martin Schwidefsky <schwidefsky@de.ibm.com> + + * shlib-versions: Add rule for Linux on 64 bit S/390. + * sysdeps/s390/s390-64/pt-machine.h: New file. + * sysdeps/unix/sysv/linux/s390/s390-64/pt-initfini.c: New file. + +2001-03-13 Martin Schwidefsky <schwidefsky@de.ibm.com> + + * sysdeps/s390/pt-machine.h: Move to... + * sysdeps/s390/s390-32/pt-machine.h: ...here. + Add defines for FLOATING_STACK and ARCH_STACK_MAX_SIZE. + +2001-03-15 Ulrich Drepper <drepper@redhat.com> + + * Versions [libpthread] (GLIBC_2.2.3): Add pthread_getattr_np. + * attr.c: Implement pthread_getattr_np. + * sysdeps/pthread/pthread.h: Add prototype for pthread_getattr_np. + * internals.h (struct _pthread_descr_struct): Add p_inheritsched. + * manager.c (pthread_handle_create): Initialize p_inheritsched. + +2001-03-09 Martin Schwidefsky <schwidefsky@de.ibm.com> + + * sysdeps/unix/sysv/linux/s390/pt-initfini.c: Use 0x07 padding for + code alignment. + +2001-02-20 Hans Boehm <hans_boehm@hp.com> + + * manager.c (manager_mask): Removed static vesion. Now always local + to __pthread_manager(). + (manager_mask_all): Removed completely. + (__pthread_manager): Remove manager_mask_all initialization. + (pthread_handle_create): Remove code to set and reset signal mask + around __clone2() calls. + +2001-02-17 Jakub Jelinek <jakub@redhat.com> + + * spinlock.c (__pthread_lock): Force lock->__status to be read from + memory on every spin. + +2001-02-10 Andreas Jaeger <aj@suse.de> + + * Makefile (extra-objs): New. + +2001-02-09 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/pthread/pt-initfini.c (call_initialize_minimal): Add + __pthread_initialize_minimal prototype. + +2001-02-08 kaz Kojima <kkojima@rr.iij4u.or.jp> + + * sysdeps/unix/sysv/linux/sh/pt-initfini.c: New file. + +2001-02-06 Martin Schwidefsky <schwidefsky@de.ibm.com> + + * sysdeps/unix/sysv/linux/s390/pt-initfini.c: New file. + +2001-02-06 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/ia64/pt-initfini.c: First attempt to fix the + broken code. Patch by Jes Sorensen. + +2001-02-06 Andreas Jaeger <aj@suse.de> + + * sysdeps/pthread/pthread.h: Move __pthread_initialize from here + to... + * internals.h: ...here. + +2001-02-05 Jes Sorensen <jes@linuxcare.com> + + * sysdeps/unix/sysv/linux/ia64/pt-initfini.c: New file. + +2001-02-02 Ulrich Drepper <drepper@redhat.com> + + * Versions: Remove __pthread_initialize_minimal. + +2001-02-01 Ulrich Drepper <drepper@redhat.com> + + * Makefile: Add rules to build crti.o and make it being used in + building libpthread.so. + * sysdeps/i386/Makefile: New file. + * sysdeps/pthread/pt-initfini.c: New file. + + * pthread.c: Cleanups. + +2001-01-28 Andreas Jaeger <aj@suse.de> + + * oldsemaphore.c (__old_sem_init): Adjust for last change. + * sysdeps/pthread/bits/libc-lock.h: Likewise. + * spinlock.c: Likewise. + +2001-01-28 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/bits/initspin.h: Make all names namespace clean. + * sysdeps/unix/sysv/linux/hppa/bits/initspin.h: Likewise. + * manager.c: Adjust for namespace cleanup in bits/initspin.h. + * pthread.c: Likewise. + * spinlock.h: Likewise. + * sysdeps/pthread/pthread.h: Likewise. + +2001-01-26 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/bits/pthreadtypes.h: Define pthread_attr_t also + as struct __pthread_attr_s. + + * semaphore.h (sem_t): Cleanup namespace, rename status and + spinlock elements. + +2001-01-13 Jakub Jelinek <jakub@redhat.com> + + * pthread.c (pthread_onexit_process): Clear + __pthread_manager_thread_bos after freeing it. + * Makefile (tests): Add ex16. + * Examples/ex16.c: New file. + +2001-01-11 Jakub Jelinek <jakub@redhat.com> + + * Makefile (CFLAGS-pthread.c): Pass -DHAVE_Z_NODELETE if ld supports + -z nodelete. + * pthread.c (pthread_exit_process): Rename to... + (pthread_onexit_process): ...this. + (pthread_atexit_process, pthread_atexit_retcode): New. + (pthread_initialize): Call __cxa_atexit instead of __cxa_on_exit + and only if HAVE_Z_NODELETE is not defined. + (__pthread_initialize_manager): Register pthread_atexit_retcode + with __cxa_atexit. + +2001-01-11 Ulrich Drepper <drepper@redhat.com> + + * pthread.c (pthread_initialize): Use __cxs_on_exit not __cxa_atexit. + +2001-01-11 Jakub Jelinek <jakub@redhat.com> + + * Makefile (tests): Add ex15. + * Examples/ex15.c: New test. + +2001-01-08 Ulrich Drepper <drepper@redhat.com> + + * pthread.c (pthread_exit_process): Free memory allocated for + manager stack. + +2000-12-31 Ulrich Drepper <drepper@redhat.com> + + * manager.c (pthread_alloca_stack): Remove MAP_FIXED from mmap calls. + (pthread_free): Always unmap the stack. It's safe now that we don't + use MAP_FIXED to allocate stacks. + +2000-12-31 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/powerpc/pspinlock.c: Don't include pt-machine.h here. + + * manager.c (pthread_allocate_stack): Prepare for removal of MAP_FIXED. + +2000-11-15 Wolfram Gloger <wg@malloc.de> + + * manager.c (pthread_free): [!FLOATING_STACKS]: Only remap the + stack to PROT_NONE, don't unmap it, avoiding collisions with malloc. + +2000-12-27 Andreas Jaeger <aj@suse.de> + + * Examples/ex13.c: Make local functions static. + * ecmutex.c: Likewise. + * joinrace.c: Likewise. + * Examples/ex14.c: Likewise. + + * Examples/ex2.c: Make local functions static; reformat. + * Examples/ex1.c: Likewise. + * Examples/ex4.c: Likewise. + * Examples/ex5.c: Likewise. + * Examples/ex7.c: Likewise. + + * oldsemaphore.c: Add prototypes to shut up GCC. + * pt-machine.c: Likewise. + + * weaks.c: Add prototype for pthread_exit. + + * internals.h: Add some prototypes, format prototypes and add + missing externs. + Move __libc_waitpid prototype to include/sys/wait.h. + + * rwlock.c: Include <bits/libc-lock.h> for prototypes. + * mutex.c: Likewise. + * specific.c: Likewise. + * ptfork.c: Likewise. + + * lockfile.c: Include internals.h to get prototypes. + * events.c: Likewise. + * sysdeps/alpha/pspinlock.c: Likewise. + * sysdeps/arm/pspinlock.c: Likewise. + * sysdeps/hppa/pspinlock.c: Likewise. + * sysdeps/i386/pspinlock.c: Likewise. + * sysdeps/ia64/pspinlock.c: Likewise. + * sysdeps/m68k/pspinlock.c: Likewise. + * sysdeps/mips/pspinlock.c: Likewise. + * sysdeps/powerpc/pspinlock.c: Likewise. + * sysdeps/s390/pspinlock.c: Likewise. + * sysdeps/sh/pspinlock.c: Likewise. + * sysdeps/sparc/sparc32/pspinlock.c: Likewise. + * sysdeps/sparc/sparc32/sparcv9/pspinlock.c: Likewise. + * sysdeps/sparc/sparc64/pspinlock.c: Likewise. + +2000-12-27 Ulrich Drepper <drepper@redhat.com> + + * attr.c (__pthread_attr_setstack): Fix setting of __stackaddr element. + (__pthread_attr_getstack): Return correct address. + Add warnings for using pthread_attr_getstackaddr and + pthread_attr_setstackaddr. + +2000-12-26 Ulrich Drepper <drepper@redhat.com> + + * Examples/ex6.c (test_thread): Make static. + * Examples/ex12.c (test_thread): Make static and add noreturn + attribute. + +2000-12-18 Jes Sorensen <jes@linuxcare.com> + + * linuxthreads/sysdeps/ia64/pt-machine.h: __compare_and_swap + and compare_and_swap_with_release_semantics returns int not long. + +2000-12-17 Andreas Jaeger <aj@suse.de> + + * sysdeps/s390/pt-machine.h (testandset): Use long int as return + value. + * sysdeps/arm/pt-machine.h (testandset): Likewise. + * sysdeps/hppa/pt-machine.h (testandset): Likewise. + * sysdeps/m68k/pt-machine.h (testandset): Likewise. + * sysdeps/sh/pt-machine.h (testandset): Likewise. + * sysdeps/sparc/sparc32/pt-machine.h (testandset): Likewise. + * sysdeps/sparc/sparc64/pt-machine.h (testandset): Likewise. + +2000-12-17 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/i386/pt-machine.h (testandset): Adjust for prototype change. + * sysdeps/i386/i686/pt-machine.h (testandset): Likewise. + +2000-12-17 Andreas Jaeger <aj@suse.de> + + * internals.h: Add prototypes for testandset and + __compare_and_swap to shut up gcc warnings. + +2000-12-06 Wolfram Gloger <wg@malloc.de> + + * join.c (pthread_detach): Allow case where the thread has already + terminated. + +2000-12-05 Andreas Jaeger <aj@suse.de> + + * sysdeps/mips/pspinlock.c (__pthread_spin_lock): Don't set mips2. + * sysdeps/mips/pt-machine.h (testandset): Likewise. + (__compare_and_swap): Likewise. + Patches by Maciej W. Rozycki <macro@ds2.pg.gda.pl>. + +2000-11-20 Jakub Jelinek <jakub@redhat.com> + + * Examples/ex3.c (main): Cast int to long before casting to void *. + (search): Cast void * to long, not int. + * Examples/ex8.c (main, thread): Similarly. + * Examples/ex11.c (main): Similarly. + * Examples/ex14.c (worker, do_test): Similarly. + * ecmutex.c (worker, do_test): Similarly. + (nlocks): Cast to int. + +2000-11-08 Bruce Mitchener <bruce@cubik.org> + + * linuxthreads.texi: Add documentation for pthreads attributes + guardsize, stackaddr, stacksize, and stack. Fix typo in previous + patch. Document pthread_[sg]etconcurrency(). Mark + pthread_mutexattr_[sg]ettype() as POSIX rather than GNU. + +2000-11-07 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/bits/posix_opt.h (_POSIX_MESSAGE_PASSING): + Don't define it. + * sysdeps/unix/sysv/linux/i386/bits/posix_opt.h: Likewise. + Reported by Christopher Yeoh <cyeoh@linuxcare.com.au>. + +2000-11-06 Ulrich Drepper <drepper@redhat.com> + + * cancel.c (pthread_cancel): Always set p_canceled, even if we are + not doing it right now. + Reported by Kaz Kylheku <kaz@ashi.footprints.net>. + +2000-10-30 Ulrich Drepper <drepper@redhat.com> + + * Examples/ex4.c (main): Don't use exit() to avoid warning with + broken compilers. + +2000-10-29 Ulrich Drepper <drepper@redhat.com> + + * attr.c (__pthread_attr_setguardsize): Don't round guardsize + here. Reported by Bruce Mitchener <bruce@cubik.org>. + + * linuxthreads.texi: Changes terminology to 'type' from 'kind' when + discussing mutexes. (As per the Unix98 name for the API.) + Changes documentation for pthread_mutexattr_setkind_np() and + pthread_mutexattr_getkind_np() over to the Unix98 APIs for the + same: pthread_mutexattr_settype() and pthread_mutexattr_gettype(). + Changes references to PTHREAD_MUTEXATTR_FAST_NP to + PTHREAD_MUTEXATTR_ADAPTIVE_NP. + Begins to introduce discussion of the ``timed'' mutex type. This + discussion is currently incomplete. + Patch by Bruce Mitchener <bruce@cubik.org>. + +2000-10-26 Kazumoto Kojima <kkojima@rr.iij4u.or.jp> + Yutaka Niibe <gniibe@chroot.org> + + * sysdeps/sh/pt-machine.h (testandset): Since the operand of TAS.B + has restrictions, use register. + +2000-10-23 Andreas Schwab <schwab@suse.de> + + * Examples/ex14.c (TIMEOUT): Override default timeout. + +2000-10-16 Ulrich Drepper <drepper@redhat.com> + + * specific.c: Protect tsd array modification in thread data + structures by getting the thread lock in pthread_key_delete and + __pthread_destroy_specifics. + Patch by Wolfram Gloger <Wolfram.Gloger@dent.med.uni-muenchen.de>. + +2000-10-12 Alan Modra <alan@linuxcare.com.au> + + * sysdeps/pthread/bits/initspin.h: New file. + * spinlock.h: Move LOCK_INITIALIZER definition to <bits/initspin.h>. + (__pthread_init_lock): Initialize lock with LT_SPINLOCK_INIT. + (__pthread_alt_init_lock): Likewise. + (__pthread_alt_trylock): Release lock with LT_SPINLOCK_INIT. + +2000-10-12 David Huggins-Daines <dhd@linuxcare.com> + + * oldsemaphore.c (__old_sem_init): Release lock with + LT_SPINLOCK_INIT, not zero. + * spinlock.c (__pthread_unlock): Likewise. + (__pthread_alt_lock): Likewise. + (__pthread_alt_timedlock): Likewise. + (__pthread_alt_unlock): Likewise. + * sysdeps/pthread/bits/libc-lock.h: Initialize locks with + LT_SPINLOCK_INIT if it is non-zero. Likewise for init-once flags. + * sysdeps/pthread/pthread.h: Include bits/initspin.h. Use + LT_SPINLOCK_INIT do initialize spinlocks not 0. + +2000-10-12 David Huggins-Daines <dhd@linuxcare.com> + + * shlib-versions: Add version definitions for hppa-linux. + +2000-10-12 Alan Modra <alan@linuxcare.com.au> + + * sysdeps/hppa/pspinlock.c: New file. + * sysdeps/hppa/pt-machine.h: New file. + * sysdeps/unix/sysv/linux/hppa/bits/initspin.h: New file. + +2000-10-05 Jakub Jelinek <jakub@redhat.com> + + * mutex.c (__pthread_mutex_destroy): Correct test of + busy mutex for mutexes using alternate fastlocks. + Patch by dtc@cmucl.cons.org. + +2000-09-28 Martin Schwidefsksy <schwidefsky@de.ibm.com> + + * sysdeps/s390/pt-machine.h: Make %a0 the thread register. + +2000-09-28 Ulrich Drepper <drepper@redhat.com> + + * mutex.c (__pthread_mutex_unlock): For PTHREAD_MUTEX_RECURSIVE_NP + test for owner first. + Patch by Kaz Kylheku <kaz@ashi.footprints.net>. + + * cancel.c (pthread_cancel): Don't do anything if cancelation is + disabled. + +2000-09-26 Ulrich Drepper <drepper@redhat.com> + + * spinlock.h (__pthread_set_own_extricate_if): Optimize a bit. + Patch by Kaz Kylheku <kaz@ashi.footprints.net>. + + * sysdeps/unix/sysv/linux/i386/bits/posix_opt.h: Remove + _POSIX_MONOTONIC_CLOCK. + + * spinlock.h (__pthread_set_own_extricate_if): Add back locking + and explain why. + +2000-09-20 Andreas Jaeger <aj@suse.de> + + * pthread.c [!__ASSUME_REALTIME_SIGNALS]: Make inclusion of + "testrtsig.h" conditional. + +2000-09-11 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/pthread.h: Declare pthread_attr_getstack and + pthread_attr_setstack. + * Versions [libpthread] (GLIBC_2.2): Export pthread_attr_getstack and + pthread_attr_setstack. + * attr.c (pthread_attr_getstack, pthread_attr_setstack): New functions. + +2000-09-05 Ulrich Drepper <drepper@redhat.com> + + * Examples/ex14.c: New file. + * Makefile (tests): Add ex14. + + * mutex.c (__pthread_mutex_unlock): Correct test for already unlocked + mutex. Patch by dtc@cmucl.cons.org. + + * ecmutex.c: New file. + * Makefile (tests): Add ecmutex. + +2000-09-04 H.J. Lu <hjl@gnu.org> + + * attr.c (__pthread_attr_setguardsize): Use page_roundup + instead of roundup to round up to the page size. + +2000-09-03 Mark Kettenis <kettenis@gnu.org> + + * manager.c (pthread_exited): Correctly report event as TD_REAP + instead of TD_DEATH. Fix comments. + +2000-09-03 Ulrich Drepper <drepper@redhat.com> + + * spinlock.h (testandset): Add cast to avoid warning. + Patch by Franz Sirl <Franz.Sirl-kernel@lauterbach.com>. + +2000-09-02 Andreas Jaeger <aj@suse.de> + + * sysdeps/pthread/timer_routines.c: Include stdlib.h for abort + prototype. + +2000-09-01 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/bits/stdio-lock.h (_IO_cleanup_region_start): + Fix typo in last patch (_mode -> _flags). + + * sysdeps/pthread/bits/stdio-lock.h (_IO_cleanup_region_start): + Provide definition which respects _IO_USER_LOCK flag. + +2000-08-30 Ulrich Drepper <drepper@redhat.com> + + * manager.c (pthread_allocate_stack): Clear descriptor only if not + mmaped. + +2000-08-25 Ulrich Drepper <drepper@redhat.com> + + * Makefile: Add rules to build and run unload. + * unload.c: New file. + + * pthread.c (pthread_exit_process): Move thread_self use inside `if'. + + * sysdeps/pthread/pthread.h + (PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP): Defined. + (PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP: Defined. + +2000-08-24 Andreas Jaeger <aj@suse.de> + + * Examples/ex13.c: Include <string.h> for strerror prototype and + <stdlib.h> for abort prototype. + (pthr_cond_signal_mutex): Rewrite to silence GCC. + (thread_start): Remove unused variable err. + (main): Silence GCC warnings. + +2000-08-22 Andreas Jaeger <aj@suse.de> + + * Examples/ex13.c: New test by Kurt Garloff <garloff@suse.de>. + + * Makefile (tests): Add ex13. + +2000-08-20 Ulrich Drepper <drepper@redhat.com> + + * semaphore.h: Add restrict where required by AGd4. + * sysdeps/pthread/pthread.h: Likewise. + * sysdeps/pthread/unix/sysv/linux/bits/sigthread.h: Likewise. + +2000-08-15 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add ex12. Add rule to build it. + * Examples/ex12.c: New file. + +2000-08-13 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/bits/posix_opt.h: Define _POSIX_SEMAPHORES + even though the implementation is not quite complete (but it reports + it). Define _POSIX_MESSAGE_PASSING to -1. + * sysdeps/unix/sysv/linux/i386/bits/posix_opt.h: Likewise. + +2000-08-12 Andreas Jaeger <aj@suse.de> + + * sysdeps/mips/pt-machine.h (testandset): Add .set mips2 for + assembler. + (__compare_and_swap): Likewise. + * sysdeps/mips/pspinlock.c (__pthread_spin_lock): Likewise. + +2000-08-10 Ulrich Drepper <drepper@redhat.com> + + * pthread.c (__pthread_initial_thread): Initialize p_errnop and + p_h_errnop correctly and not to NULL. + +2000-08-05 Ulrich Drepper <drepper@redhat.com> + + * Banner: Bump version number to 0.9. + +2000-08-04 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add tststack. Add rule to build the program. + * tststack.c: New file. + + * internals.h: Declare __pthread_max_stacksize. + * pthread.c (__pthread_max_stacksize): New variable. + (__pthread_initialize_manager): Determine __pthread_initialize_manager + value. + * manager.c (thread_segment): Return always NULL if FLOATING_STACKS. + (pthread_allocate_stack): Allow kernel to choose stack address if + FLOATING_STACKS. This also handles variable-sized stacks. + Always allocate stack and guardpage together. Use mprotect to + change guardpage access. + * sysdeps/i386/useldt.h: Define FLOATING_STACKS and + ARCH_STACK_MAX_SIZE. + + * attr.c (__pthread_attr_setstacksize): Also test value against + upper limit. + + * manager.c (__pthread_nonstandard_stacks): Define only if + THREAD_SELF is not defined. + (pthread_allocate_stack): Always initialize gardaddr to a correct + value. + (pthread_handle_create): Unmap thread with one call. + (pthread_free): Remove test for initial thread before removing stack. + Unmap stack with one call. + + * pthread.c (__pthread_initial_thread): Initialize p_userstack to + 1 to avoid removing the stack. + +2000-07-27 Jes Sorensen <jes@linuxcare.com> + + * sysdeps/ia64/pspinlock.c (__pthread_spin_lock): Add + load of spin lock to prime the cache before the atomic compare and + exchange operation (cmpxchg4). This avoids the spinning on the + cmpxchg4 instruction and reduces movement of the cache line back + and forth between the processors (explanation by Asis K. Mallick + from Intel). This basically makes the implementation operate the + same as the Linux kernel implementation. + + * shlib-versions: Use GLIBC_2_2 for Linux/ia64. + * sysdeps/ia64/pspinlock.c: New file. + +2000-08-03 Ulrich Drepper <drepper@redhat.com> + + * pthread.c: Move definition of __pthread_set_own_extricate_if... + * spinlock.h: ...here. Remove locking. + * internals.h: Remove __pthread_set_own_extricate_if prototype. + + * rwlock.c: Use THREAD_GETMEM And THREAD_SETMEM. + (rwlock_rd_extricate_func): Don't determine self, let + __pthread_lock do it. + (rwlock_wr_extricate_func): Likewise. + (rwlock_have_already): Optimize *pself handling a bit. + + * mutex.c: Use __builtin_expect. + * pthread.c: Likewise. + +2000-08-02 Andreas Jaeger <aj@suse.de> + + * sysdeps/s390/pspinlock.c: New file. + * sysdeps/s390/pt-machine.h: New file. + Patches by Martin Schwidefsky <schwidefsky@de.ibm.com>. + +2000-07-12 Maciej W. Rozycki <macro@ds2.pg.gda.pl> + + * sysdeps/mips/pspinlock.c (__pthread_spin_lock): Implement for + R3K. + * sysdeps/mips/pt-machine.h (testandset): Likewise. + +2000-07-26 Andreas Jaeger <aj@suse.de> + + * pthread.c: Initialize p_sem_avail. + +2000-07-25 Ulrich Drepper <drepper@redhat.com> + + * internals.h (struct __pthread_descr_struct): Add p_sem_avail. + * semaphore.c: Handle spurious wakeups. + + * sysdeps/pthread/pthread.h: Add back PTHREAD_MUTX_FAST_NP as an alias + for PTHREAD_MUTEX_ADAPTIVE_NP for source code compatibility. + + * pthread.c (__pthread_set_own_extricate): Use THREAD_GETMEM. + (__pthread_wait_for_restart): Likewise. + + * condvar.c (pthread_cond_wait): Also check whether thread is + cancelable before aborting loop. + (pthread_cond_timedwait): Likewise. + + * signals.c (pthread_sighandler): Remove special code to restrore + %gs on x86. + (pthread_sighandler_t): Likewise. + +2000-07-25 Mark Kettenis <kettenis@gnu.org> + + * internals.h (__RES_PTHREAD_INTERNAL): Remove define. + * pthread.c: Include <resolv.h>. + (_res): Undefine. Add extern declaration. + +2000-07-24 Ulrich Drepper <drepper@redhat.com> + + * pthread.c (__pthread_initial_thread): Update initializer. + (__pthread_manager_thread): Likewise. + (pthread_initialize): Move setrlimit call to... + (__pthread_initialize_manager): ...here. + (__pthread_reset_main_thread): Reset also soft limit on stack size. + + * condvar.c: Handle spurious wakeups. [PR libc/1749]. + * internals.h (struct _pthread_descr_struct): Add p_condvar_avail. + +2000-07-21 Ulrich Drepper <drepper@redhat.com> + + * spinlock.h: If IMPLEMENT_TAS_WITH_CAS is defined use + __compare_and_swap to define testandset. + * sysdeps/powerpc/pt-machine.h: Add volatile to asms. + Define IMPLEMENT_TAS_WITH_CAS. + +2000-07-20 Ulrich Drepper <drepper@redhat.com> + + * Makefile: Pass -z nodelete to linker for libpthread.so + generation if it understand this option. + +2000-07-18 Mark Kettenis <kettenis@gnu.org> + + * manager.c (pthread_handle_create): Remove initialization of + new_thread->p_res._sock. + +2000-07-19 Kaz Kylheku <kaz@ashi.footprints.net> + + Bugfixes to the variant of the code for machines with no compare + and swap. + + * spinlock.c (__pthread_alt_lock, __pthread_alt_timedlock): Wait + node was not being properly enqueued, due to failing to update + the lock->__status field. + + * spinlock.c (__pthread_alt_timedlock): The oldstatus variable was + being set inappropriately, causing the suspend function to be called + with a null self pointer and crash. + +2000-07-18 Ulrich Drepper <drepper@redhat.com> + + * spinlock.h (__pthread_alt_trylock): Fix code used if no + compare&swap is available. + + * spinlock.h (__pthread_trylock): Use __compare_and_swap, not + compare_and_swap. + + * pthread.c (pthread_initialize): Don't use sysconf to determine + whether the machine has more than one processor. + + * spinlock.c (__pthread_alt_timedlock): Add back one of the + removed thread_self calls. + +2000-07-18 Kaz Kylheku <kaz@ashi.footprints.net> + + * spinlock.c (__pthread_alt_lock, __pthread_alt_timedlock): Changed + __compare_and_swap to compare_and_swap in code which assumes + compare swap is available. + +2000-07-18 Kaz Kylheku <kaz@ashi.footprints.net> + + * spinlock.c (__pthread_alt_lock, __pthread_alt_timedlock): Fixed + bug whereby thr field of waitnode structure would not be correctly + set unless a null self pointer is passed to the functions. + Eliminated redundant calls to thread_self(). + +2000-07-18 Jakub Jelinek <jakub@redhat.com> + + * pthread.c (__pthread_initialize_manager): Lock + __pthread_manager_thread.p_lock before calling clone. + +2000-05-05 H.J. Lu <hjl@gnu.org> + + * sysdeps/ia64/pt-machine.h (__compare_and_swap): Change it to + have acquire semantics. + (__compare_and_swap_with_release_semantics): New inline + function. + (HAS_COMPARE_AND_SWAP_WITH_RELEASE_SEMANTICS): New macro. + +2000-01-28 Hans Boehm <hboehm@exch.hpl.hp.com> + + * manager.c: Fix the problem with signals at startup. + Change the way that thread stacks are allocated on IA64. + Clean up some of the guard page allocation stuff. + +1999-12-19 H.J. Lu <hjl@gnu.org> + + * internals.h (page_roundup): New. + * attr.c (__pthread_attr_setguardsize); Use page_roundup + instead of roundup. + * manager.c (pthread_allocate_stack): Make sure guardaddr is + page aligned with page_roundup if NEED_SEPARATE_REGISTER_STACK + is define. + +1999-12-17 Hans Boehm <hboehm@exch.hpl.hp.com> + + * manager.c (pthread_allocate_stack): Unmap the stack top + if failed to map the stack bottom. + Fix the guard page. + (pthread_free): Fix the guard page. + + * pthread.c (pthread_initialize): Set rlimit correctly for + NEED_SEPARATE_REGISTER_STACK. + +1999-12-16 H.J. Lu <hjl@gnu.org> + + * pthread.c (__pthread_initialize_manager): Pass + __pthread_manager_thread_bos instead of + __pthread_manager_thread_tos to __clone2. + +1999-12-16 H.J. Lu <hjl@gnu.org> + + * manager.c (pthread_allocate_stack): Correct the calculation + of "new_thread_bottom". Remove MAP_GROWSDOWN from mmap for + stack bottom. + +1999-12-13 H.J. Lu <hjl@gnu.org> + + * sysdeps/ia64/pt-machine.h (__compare_and_swap): Added a stop + bit after setting ar.ccv. + +1999-12-12 H.J. Lu <hjl@gnu.org> + + * manager.c (pthread_allocate_stack): Make the starting + address of the stack bottom page aligned. FIXME: it may + need changes in other places. + (pthread_handle_create): Likewise. + +1999-12-11 Hans Boehm <hboehm@exch.hpl.hp.com> + + * manager.c (pthread_allocate_stack): Handle + NEED_SEPARATE_REGISTER_STACK. + (pthread_handle_create): Likewise. + * pthread.c (__pthread_initialize_manager): Likewise. + + * sysdeps/ia64/pt-machine.h: Use r13 for thread pointer. + +1999-12-02 H.J. Lu <hjl@gnu.org> + + * sysdeps/ia64/pt-machine.h: New. + +2000-07-13 Ulrich Drepper <drepper@redhat.com> + + * wrapsyscall.c: Mark non-__ protected names as weak. + PR libc/1466. + +2000-07-12 Bruno Haible <haible@clisp.cons.org> + + * Examples/ex8.c: Include <sys/wait.h>, not <wait.h>. + +2000-07-12 Ulrich Drepper <drepper@redhat.com> + + * spinlock.c: Fix code for TEST_FOR_COMPARE_AND_SWAP being defined. + Add tests also to new alternative spinlock implementation. + * spinlock.h: Likewise. + Patch by Kaz Kylheku <kaz@ashi.footprints.net>. + +2000-07-06 Ulrich Drepper <drepper@redhat.com> + + * Version: Export __sigaction. + * signals.c: Define __sigaction alias. Use __libc_sigaction instead + of __sigaction. + * pthread.c: Use __libc_sigaction instead of __sigaction. + + * condvar.c: Implement pthread_condattr_getpshared and + pthread_condattr_setpshared. + * mutex.c: Implement pthread_mutexattr_getpshared and + pthread_mutexattr_setpshared. + * Versions: Export new functions. + * sysdeps/pthread/pthread.h: Add prototypes for new functions. + + * rwlock.c (pthread_rwlockattr_init): Use PTHREAD_PROCESS_PRIVATE. + (pthread_rwlockattr_setpshared): Fail if PTHREAD_PROCESS_PRIVATE + is not selected. + +2000-07-04 Greg McGary <greg@mcgary.org> + + * sysdeps/pthread/bits/libc-lock.h: Remove BP_SYM from + pragmas. Include bp-sym.h only if _LIBC. + +2000-07-04 Ulrich Drepper <drepper@redhat.com> + + * spinlock.c (__pthread_unlock): Properly place write barrier. + Patch by Kaz Kylheku <kaz@ashi.footprints.net>. + +2000-07-03 Ulrich Drepper <drepper@redhat.com> + + * spinlock.c: Replace fast spinlocks by adaptive spinlocks which are + faster on SMP systems. No more emulation of compare&swap for adaptive + spinlocks. + * spinlock.h: Likewise. + * sysdeps/pthread/pthread.h: Shuffle PTHREAD_MUTEX_* values around. + Replace fast with adaptive mutex. + * mutex.c: Rewrite for replacement of fast by adaptive mutex. + * condvar.c: Likewise. + * pthread.c: Define and initialize __pthread_smp_kernel variable. + * internals.h: Declare __pthread_smp_kernel. + * sysdeps/pthread/bits/pthreadtypes.h: Update comment of + _pthread_fastlock structure. + Patch by Kaz Kylheku <kaz@ashi.footprints.net>. + + * pthread.c: Remove initialization to zero from global variables. + +2000-06-29 Jakub Jelinek <jakub@redhat.com> + + * shlib-versions: Make sparc64 GLIBC_2.2+ only. + +2000-06-28 Greg McGary <greg@mcgary.org> + + * weaks.c: Wrap BP_SYM () around weak extern declarations of + pthread functions that have pointers in their return+arg signatures. + +2000-06-27 Greg McGary <greg@mcgary.org> + + * sysdeps/pthread/bits/libc-lock.h: Wrap BP_SYM () around weak + extern declarations of pthread functions that have pointers in + their return+arg signatures. + +2000-06-26 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add ex11. Add rules to build it. + * Examples/ex11.c: New file. + * rwlock.c: Fix complete braindamaged previous try to implement + timedout functions. + + * spinlock.c: Pretty print. + +2000-06-25 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add ex10. Add rules to build it. + * Versions [GLIBC_2.2] (libpthread): Add pthread_mutex_timedlock, + pthread_rwlock_timedrdlock, and pthread_rwlock_timedwrlock. + * condvar.c (pthread_cond_wait): Allow mutex of kind + PTHREAD_MUTEX_TIMED_NP. + (pthread_cond_timedwait_relative): Likewise. + * mutex.c (__pthread_mutex_init): Default is PTHREAD_MUTEX_TIMED_NP. + (__pthread_mutex_trylock): Use __pthread_alt_trylock for + PTHREAD_MUTEX_ERRORCHECK_NP. Handle PTHREAD_MUTEX_TIMED_NP. + (__pthread_mutex_lock): Use __pthread_alt_lock for + PTHREAD_MUTEX_ERRORCHECK_NP. Handle PTHREAD_MUTEX_TIMED_NP. + (__pthread_mutex_timedlock): New function. + (__pthread_mutex_unlock): Use __pthread_alt_unlock for + PTHREAD_MUTEX_ERRORCHECK_NP. Handle PTHREAD_MUTEX_TIMED_NP. + (__pthread_mutexattr_init): Use PTHREAD_MUTEX_TIMED_NP. + (__pthread_mutexattr_settype): Allow PTHREAD_MUTEX_TIMED_NP. + * spinlock.c: Implement alternate fastlocks. + * spinlock.h: Add prototypes. + * Examples/ex10.c: New file. + * sysdeps/pthread/pthread.h: Add prototypes for new functions. + Patch by Kaz Kylheku <kaz@ashi.footprints.net>. + + * rwlock.c (__pthread_rwlock_rdlock): Optimize loop a bit. + (__pthread_rwlock_timedrdlock): New function. + (__pthread_rwlock_timedwrlock): New function. + Use laternate fastlock function everywhere. + +2000-06-21 Andreas Jaeger <aj@suse.de> + + * sysdeps/pthread/timer_routines.c: Include <string.h> for memset + prototype. + + * join.c: Include <stdlib.h> for exit prototype. + +2000-06-20 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/i386/useldt.h: Include <stdlib.h>. + + * sysdeps/unix/sysv/linux/bits/posix_opt.h: Define _POSIX_BARRIERS. + * sysdeps/unix/sysv/linux/i386/bits/posix_opt.h: Likewise. + + * Makefile (libpthread-routines): Add barrier. + (tests): Add ex9. Add rule to build ex9. + * Versions: Export barrier functions. + * barrier.c: New file. + * Examples/ex9.c: New file. + * sysdeps/pthread/pthread.h: Add barrier data types and declarations. + * sysdeps/pthread/bits/pthreadtypes.h: Likewise. + Patch by Kaz Kylheku <kaz@ashi.footprints.net>. + +2000-06-19 H.J. Lu <hjl@gnu.org> + + * spinlock.h (HAS_COMPARE_AND_SWAP): Defined if + HAS_COMPARE_AND_SWAP_WITH_RELEASE_SEMANTICS is defined. + (compare_and_swap_with_release_semantics): New. Default to + compare_and_swap if HAS_COMPARE_AND_SWAP_WITH_RELEASE_SEMANTICS + is not defined. + + * spinlock.c (__pthread_unlock): Call + compare_and_swap_with_release_semantics () instead of + compare_and_swap (). + +2000-06-19 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/timer_create.c: Use _set_errno instead of assigning + to errno directly. + * sysdeps/pthread/timer_delete.c: Likewise. + * sysdeps/pthread/timer_getoverr.c: Likewise. + * sysdeps/pthread/timer_gettime.c: Likewise. + * sysdeps/pthread/timer_settime.c: Likewise. + +2000-06-13 Kaz Kylheku <kaz@ashi.footprints.net> + + Timer nodes are now reference counted, and can be marked + as deleted. This allows for the safe release of the global mutex + in the middle without losing the timer being operated on. + + * sysdeps/pthread/posix-timer.h (struct timer_node): The inuse + member is now an enum with three values, so that an intermediate + state can be represented (deleted but not free for reuse yet). + New refcount member added. + * sysdeps/pthread/timer_routines.c: Likewise. + + * sysdeps/pthread/posix-timer.h (timer_addref, timer_delref, + timer_valid): New inline functions added. + + * sysdeps/pthread/timer_gettime.c (timer_gettime): Function + restructured, recursive deadlock bug fixed. + + * sysdeps/pthread/timer_gettime.c (timer_gettime): Uses new + timer_addref to ensure that timer won't be deleted while mutex is not + held. Also uses timer_invalid to perform validation of timer handle. + * sysdeps/pthread/timer_settime.c (timer_settime): Likewise. + * sysdeps/pthread/timer_getoverr.c (timer_getoverrun): Likewise. + +2000-06-14 Ulrich Drepper <drepper@redhat.com> + + * shlib-versions: Add entry for SH. + Patch by Kaz Kojima <kkojima@rr.iij4u.or.jp>. + +2000-06-13 Kaz Kylheku <kaz@ashi.footprints.net> + + A few optimizations. Got rid of unnecessary wakeups of timer threads, + tightened up some critical regions and micro-optimized some list + manipulation code. + + * sysdeps/pthread/timer_routines.c (__timer_thread_queue_timer): + Returns int value now to indicate whether timer was queued at head. + * sysdeps/pthread/posix-timer.h: Likewise. + * sysdeps/pthread/timer_settime.c (timer_settime): Takes advantage of + new return value from __timer_thread_queue_timer to avoid waking + up timer thread unnecessarily. + + * sysdeps/pthread/posix-timer.h (timer_id2ptr): No longer checks + inuse flag, because this requires mutex to be held. Callers updated + to do the check when they have the mutex. + * sysdeps/pthread/timer_getoverr.c: Add check for inuse here. + + * sysdeps/pthread/timer_settime.c (timer_settime): Tighter critical + regions: avoids making system calls while holding timer mutex, and + a few computations were moved outside of the mutex as well. + * sysdeps/pthread/timer_gettime.c (timer_gettime): Likewise. + + * sysdeps/pthread/posix-timer.h (list_unlink_ip): Function name changed + to list_unlink_ip, meaning idempotent. Pointer manipulation + changed to get better better code out of gcc. + * sysdeps/pthread/timer_routines.c (list_unlink): Non-idempotent + version of list_unlink added here. + * sysdeps/pthread/timer_delete.c: Use appropriate list unlink + function in all places: idempotent one for timers, non-idempotent + one for thread nodes. + * sysdeps/pthread/timer_settime: Likewise. + * sysdeps/pthread/timer_routines.c: Likewise. + +2000-06-13 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/bits/posix_opt.h (_POSIX_TIMERS): Define. + * sysdeps/unix/sysv/linux/i386/bits/posix_opt.h: Likewise. + + * sysdeps/pthread/Makefile: Remove tests definition. + +2000-06-12 Kazumoto Kojima <kkojima@rr.iij4u.or.jp> + Yutaka Niibe <gniibe@chroot.org> + + * sysdeps/sh/pspinlock.c: New file. + * sysdeps/sh/pt-machine.h: New file. + +2000-06-12 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add joinrace. + + * Examples/ex6.c: Test return value of pthread_join. + +2000-06-11 Geoff Keating <geoffk@cygnus.com> + + * sysdeps/powerpc/pspinlock.c (__pthread_spin_lock): Implement. + (__pthread_spin_trylock): Implement. + (__pthread_spin_unlock): Implement. + (__pthread_spin_init): Implement. + (__pthread_spin_destroy): Implement. + +2000-06-10 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/timer_routines.c (list_append): Little fix to + really append the entry. + +2000-06-10 Andreas Jaeger <aj@suse.de> + + * lockfile.c (__fresetlockfiles): Remove unused variable fp. + +2000-06-10 Kaz Kylheku <kaz@ashi.footprints.net> + + * sysdeps/pthread/timer_create.c: Thread matching now done on + clock type as well as thread attributes. + There are individual global signal-delivering threads for + different clock types. + * sysdeps/pthread/posix-timer.h: Likewise. + * sysdeps/pthread/timer_routines.c: Likewise. + + * sysdeps/pthread/timer_routines.c: Thread allocation and + deallocation function now remembers to put thread on active + list and remove from active list. + Thus now the feature of binding multiple timers + to a single thread actually works. + +2000-06-10 Ulrich Drepper <drepper@redhat.com> + + * pthread.c (__pthread_create_2_1): Optimize a bit. + + * internals.h (invalid_handle): Also test for p_terminated != 0. + (nonexisting_handle): New function. Same as old invalid_handle. + * join.c (pthread_join): Use nonexisting_handle instead of + invalid_handle to test for acceptable thread handle. + * manager.c (pthread_handle_free): Likewise. + * joinrace.c: New file. + Reported by Permaine Cheung <pcheung@cygnus.com>. + +2000-06-08 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/timer_routines.c (__timer_thread_queue_timer): + Correct handling of matching variable. + + * sysdeps/pthread/tst-timer.c (main): Rewrite initializers to + avoid warnings. + + * sysdeps/pthread/timer_routines.c (__timer_thread_queue_timer): + Be prepared for empty timer list. + + * sysdeps/pthread/timer_create.c (timer_create): Correct names of + CPUTIME clock ID. Add support for thread clocks. + + * sysdeps/pthread/posix-timer.h (timer_ptr2id): Operands in + subtraction were switched. + + * sysdeps/pthread/timer_routines.c (init_module): Use + THREAD_MAXNODES threads. + + * sysdeps/pthread/posix-timer.h (struct timer_node): Add creator_pid. + * sysdeps/pthread/timer_create.c: Fill in creator_pid. + * sysdeps/pthread/timer_routines.c (thread_expire_timer): Send signal + with sigqueueinfo is this system call is available. + + * sysdeps/pthread/timer_create.c (timer_create): Allow + CLOCK_CPUTIME if _POSIX_CPUTIME is defined. + + * sysdeps/pthread/Makefile: New file. Add rules to build timer + functionality. + * sysdeps/unix/sysv/linux/bits/local_lim.h: Add TIMER_MAX. + +2000-06-04 Kaz Kylheku <kaz@ashi.footprints.net> + + * sysdeps/pthread/posix-timer.h: New file. + * sysdeps/pthread/timer_create.c: New file. + * sysdeps/pthread/timer_delete.c: New file. + * sysdeps/pthread/timer_getoverr.c: New file. + * sysdeps/pthread/timer_gettime.c: New file. + * sysdeps/pthread/timer_routines.c: New file. + * sysdeps/pthread/timer_settime.c: New file. + * sysdeps/pthread/tst-timer.c: New file. + +2000-06-08 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/bits/local_lim.h: Remove OPEN_MAX and + LINK_MAX definitions if necessary. + +2000-06-04 Kaz Kylheku <kaz@ashi.footprints.net> + + Added missing fork time handling of global libio lock. + + * lockfile.c (__fresetlockfiles): Now also resets the list lock, + not just the individual stream locks. Rewritten to use new + iterator interface provided by libio rather than accessing + global variable. + + * lockfile.c (__flockfilelist, _funlockfilelist): New functions + which lock and unlock the stream list using the new interface + provied by libio. + * internals.h: Likewise. + + * ptfork.c (__fork): Now calls __flockfilelist before fork, + and __funlockfilelist in the parent after the fork. + Child still calls __fresetlockfiles as before. + + * linuxthreads.texi: Now explains what happens to streams at + fork time. Also whole new section on forking and thread added. + Definition of pthread_atfork moved out of Miscellaneous Functions + to this new section. + +2000-06-04 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/sparc/sparc32/sparcv9/pspinlock.c (__pthread_spin_lock): + Add missing register. + * sysdeps/sparc/sparc64/pspinlock.c (__pthread_spin_lock): Likewise. + +2000-06-02 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/sparc/sparc32/pspinlock.c: Implement spinlocks. + * sysdeps/sparc/sparc32/sparcv9/pspinlock.c: New. + * sysdeps/sparc/sparc64/pspinlock.c: Implement spinlocks. + +2000-05-31 Andreas Jaeger <aj@suse.de> + + * sysdeps/mips/pspinlock.c: Implement spinlocks. + +2000-05-28 Ulrich Drepper <drepper@redhat.com> + + * spinlock.c (__pthread_lock): Remove ASSERT. + + * Makefile (tests): Add ex8. + * Examples/ex8.c: New file. + +2000-05-12 Kaz Kylheku <kaz@ashi.footprints.net> + + Bugfix: The pthread_atfork mechanism now takes care of its + own internal mutex at fork time. + + * ptfork.c (__fork): Revised so that the mutex is held across + the fork operation and while the handlers are called, and so that + the child resets the mutex. + + * linuxthreads.texi: Updated pthread_atfork documentation to make + it clear that fork and pthread_atfork can't be reentered from + atfork handlers, that pthread_atfork and fork are mutually atomic, + and that the handlers are inherited by the child process. + +2000-05-24 Ulrich Drepper <drepper@redhat.com> + + * Makefile (libpthread-routines): Add pspinlock. + * cancel.c: Rename __pthread_spin_unlock back to __pthread_unlock. + Use struct _pthread_fastlock instead of pthread_spinlock_t. + * condvar.c: Likewise. + * internals.h: Likewise. + * join.c: Likewise. + * manager.c: Likewise. + * mutex.c: Likewise. + * pthread.c: Likewise. + * rwlock.c: Likewise. + * semaphore.c: Likewise. + * signals.c: Likewise. + * spinlock.h: Likewise. + * spinlock.c: Likewise. Remove pthread_spin_lock functions. + * sysdeps/alpha/pspinlock.c: New file. + * sysdeps/arm/pspinlock.c: New file. + * sysdeps/i386/pspinlock.c: New file. + * sysdeps/m68k/pspinlock.c: New file. + * sysdeps/mips/pspinlock.c: New file. + * sysdeps/powerpc/pspinlock.c: New file. + * sysdeps/sparc/sparc32/pspinlock.c: New file. + * sysdeps/sparc/sparc64/pspinlock.c: New file. + * sysdeps/pthread/bits/pthreadtypes.h: Remove pthread_spinlock_t + back to _pthread_fastlock. Define new pthread_spinlock_t. + +2000-05-24 Andreas Jaeger <aj@suse.de> + + * sysdeps/i386/i686/pt-machine.h: Only use LDT on newer kernels. + +2000-05-21 Jakub Jelinek <jakub@redhat.com> + + * manager.c (pthread_handle_create): Initialize p_res._sock to -1. + +2000-05-13 Jakub Jelinek <jakub@redhat.com> + + * internals.h (__RES_PTHREAD_INTERNAL): Define. + +2000-05-06 Kaz Kylheku <kaz@ashi.footprints.net> + + * mutex.c (pthread_once): IN_PROGRESS state of pthread_once_t + object state is represented with additional bits which distinguish + whether that state was set up in the current process, or + in an ancestor process. If that state was set in an ancestor, + it means that a fork happened while thread was executing the init + function. In that case, the state is reset to NEVER. + * mutex.c (__pthread_once_fork_prepare): New function. + (__pthread_once_fork_child): Likewise + (__pthread_once_fork_parent): Likewise + (__pthread_reset_pthread_once): Removed. + * ptfork.c (__fork): Call new handlers in mutex.c. + * internals.h: Declarations of new mutex.c functions added. + Declaration of removed function deleted. + * linuxthreads.texi: Updated documentation about pthread_once + to clarify what happens under cancellation and forking. + +2000-05-06 Kaz Kylheku <kaz@ashi.footprints.net> + + * internals.h: New thread manager request type, REQ_KICK. + * join.c (pthread_exit): main thread now calls exit() instead + of _exit() in order to proper process cleanup. + * manager.c (__pthread_manager): Do not terminate manager + after unblocking main thread; wait for main thread's + REQ_PROCESS_EXIT request instead. + Also, added REQ_KICK case to handle new request; this just does + nothing. + * manager.c (pthread_exited): Do not terminate manager after + unblocking main thread. + * manager.c (__pthread_manager_sighandler): If the main thread + is waiting for all other threads to die, send a REQ_KICK into + the thread manager request pipe to get it to clean out the threads + and unblock the main thread as soon as possible. This fixes + the 2000 millisecond hang on shutdown bug. + * Examples/ex7.c: New file, tests shutdown behavior when all threads + including the main one call pthread_exit(), or implicitly do so. + * Makefile (tests): Add ex7. + +2000-05-05 Andreas Jaeger <aj@suse.de> + + * sysdeps/unix/sysv/linux/i386/getcpuclockid.c + (pthread_getcpuclockid): Correct test for ourselves. + +2000-05-05 Ulrich Drepper <drepper@redhat.com> + + * internals.h (struct _pthread_descr_struct): Reorganization. + Allocate room for 16 pointers at head of the structure for future + thread-local data handling. Move p_self member in this area. + * manager.c (pthread_handle_create): Adjust use of p_self. + * sysdeps/i386/useldt.h (THREAD_SELF): Likewise. + * pthread.c (__pthread_initial_thread): Adjust initialization. + (__pthread_manager_thread): Likewise. + +2000-04-29 Bruno Haible <haible@clisp.cons.org> + + * join.c (pthread_exit): Use THREAD_GETMEM_NC instead of THREAD_GETMEM + for eventmask larger than 1 word. + +2000-04-27 Ulrich Drepper <drepper@redhat.com> + + * Versions [libpthread] (GLIBC_2.2): Add __pthread_initialize_minimal. + * pthread.c (__pthread_initialize_minimal): New function. Perform + minimal initialization. + (pthread_initialize): Remove this code here. + * sysdeps/i386/i686/pt-machine.h: Include "../useldt.h" again. We + are working around the problem in glibc. + +2000-04-25 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/i386/i686/pt-machine.h: Do not use "../useldt.h" for + now. First gcc must be fixed (more concrete: libgcc). + +2000-04-24 Ulrich Drepper <drepper@redhat.com> + + * pthread.c: Remove special treatement for interrupt handlers on x86. + * manager.c (pthread_free): Use FREE_THREAD not FREE_THREAD_SELF. + * sysdeps/i386/useldt.h: Use "q" constraint instead of "r" where + necessary. + * sysdeps/i386/i686/pt-machine.h: Include "../useldt.h". + +2000-04-24 Mark Kettenis <kettenis@gnu.org> + + * join.c (pthread_exit): Set p_terminated after reporting the + termination event instead of before. + +2000-04-20 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/pthread/bits/libc-lock.h: Only declare __pthread_rwlock_* + if __USE_UNIX98. + +2000-04-18 Andreas Jaeger <aj@suse.de> + + * Versions: Use ld instead of ld.so. + +2000-04-18 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/sparc/bits/sigcontext.h (struct sigcontext): + Remove the typedef keyword. + +2000-04-18 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/sparc/sparc64/pt-machine.h (MEMORY_BARRIER): Use membar, + not stbar. + (READ_MEMORY_BARRIER): Define. + * spinlock.c (__pthread_spin_unlock): Use READ_MEMORY_BARRIER, not + MEMORY_BARRIER. + * internals.h (READ_MEMORY_BARRIER): Define if not defined in sysdep + headers. + +2000-04-17 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/getcpuclockid.c + (pthread_getcpuclockid): Don't compare thread_id with thread_self, + use thread_handle(). + +2000-04-16 Ulrich Drepper <drepper@redhat.com> + + * condvar.c (pthread_cond_timedwait_relative): Don't test for owner + if fast mutex is used. Don't initialize `already_canceled' twice. + Correctly test for return value of timedsuspend. + + * pthread.c: Correct long-time braino. We never set SA_SIGINFO and + therefore don't need the _rt versions of the signal handlers. + +2000-04-15 Ulrich Drepper <drepper@redhat.com> + + * pthread.c (pthread_yield): New function. + * sysdeps/pthread/pthread.h (pthread_yield): Add prototype. + * Versions [libpthread] (GLIBC_2.2): Add pthread_yield. + * internals.h: Declare __pthread_yield. + + * pthread.c (pthread_initialize): Avoid a bit more code if + realtime signals are known to exist. + + * pthread.c: Is __ASSUME_REALTIME_SIGNALS then avoid generating code + to dynamically detect RT signals and avoid generating compatibility + functions with old kernel. + * restart.h (restart) [__ASSUME_REALTIME_SIGNALS]: Use + __pthread_restart_new directly. + (suspend) [__ASSUME_REALTIME_SIGNALS]: Use + __pthread_wait_for_restart_signal directly. + (timedsuspend) [__ASSUME_REALTIME_SIGNALS]: Use + __pthread_timedsuspend_new directly. + +2000-04-15 Ulrich Drepper <drepper@redhat.com> + + * condvar.c: Remove all the special code to handle cond_timedwait. + Use timedsuspend instead. + * internals.h: Declare __pthread_timedsuspend_old, + __pthread_timedsuspend_new, and __pthread_timedsuspend. + Remove declaration of __pthread_init_condvar. + * pthread.c: Define __pthread_timedsuspend variable. + (__pthread_timedsuspend_old): New function. Timed suspension + implementation for old Linux kernels. + (__pthread_timedsuspend_new): New function. Timed suspension + implementation for new Linux kernels. + * restart.h (timedsuspend): New function. Call appropriate + suspension function through __pthread_timedsuspend. + * semaphore.c (sem_timedwait): Use timedsuspend, don't duplicate + the code. + Patch by Kaz Kylheku <kaz@ashi.footprints.net>. + + * internals.h (WRITE_MEMORY_BARRIER): Define as MEMORY_BARRIER if + undefined. + * spinlock.c: Use WRITE_MEMORY_BARRIER instead of MEMORY_BARRIER + where possible. + * sysdeps/alpha/pt-machine.h: Define WRITE_MEMORY_BARRIER. + * sysdeps/sparc/sparc64/pt-machine.h: Likewise. + + * sysdeps/unix/sysv/linux/bits/posix_opt.h: Add _POSIX_SPAWN. + * sysdeps/unix/sysv/linux/i386/bits/posix_opt.h: Likewise. + +2000-04-14 Andreas Jaeger <aj@suse.de> + + * weaks.c: Fix typo. + + * shlib-versions (mips.*-.*-linux.*): Support only GLIBC 2.0 and + 2.2 for linuxthreads. + +2000-04-13 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/getcpuclockid.c + (pthread_getcpuclockid): Fix typo. + +2000-04-12 Ulrich Drepper <drepper@redhat.com> + + * Makefile (libpthread-routines): Add getcpuclockid. + * Versions [libpthread] (GLIBC_2.2): Add pthread_getcpuclockid. + * sysdeps/pthread/getcpuclockid.c: New file. + * sysdeps/unix/sysv/linux/i386/getcpuclockid.c: New file. + * sysdeps/pthread/pthread.h: Add prototype for pthread_getcpuclockid. + + * sysdeps/unix/sysv/linux/bits/posix_opt.h (_POSIX_SPIN_LOCKS): + Defined. + * sysdeps/unix/sysv/linux/i386/bits/posix_opt.h: Likewise. + + * sysdeps/pthread/pthread.h: Add prototypes for pthread_spin_init, + pthread_spin_destroy, pthread_spin_lock, pthread_spin_trylock, + and pthread_spin_unlock. + * sysdeps/pthread/bits/pthreadtypes.h: Change struct _pthread_fastlock + into pthread_spinlock_t. Change all uses. + * spinlock.c: Implement pthread_spin_lock. + Rename __pthread_unlock to __pthread_spin_unlock and define weak + alias for real name. + Define pthread_spin_trylock, pthread_spin_init, and + pthread_spin_destroy. + Change all uses of _pthread_fastlock to pthread_spinlock_t. + * spinlock.h: Rename __pthread_unlock to __pthread_spin_unlock. + Change all uses of _pthread_fastlock to pthread_spinlock_t. + * Versions [libpthread] (GLIBC_2.2): Add pthread_spin_init, + pthread_spin_destroy, pthread_spin_lock, pthread_spin_trylock, + and pthread_spin_unlock. + * cancel.c: Use __pthread_spin_unlock instead of __pthread_unlock. + Change all uses of _pthread_fastlock to pthread_spinlock_t. + * condvar.c: Likewise. + * internals.h: Likewise. + * join.c: Likewise. + * manager.c: Likewise. + * mutex.c: Likewise. + * pthread.c: Likewise. + * rwlock.c: Likewise. + * semaphore.c: Likewise. + * signals.c: Likewise. + + * sysdeps/unix/sysv/linux/bits/posix_opt.h: Add various new POSIX + macros. + * sysdeps/unix/sysv/linux/i386/bits/posix_opt.h: New file. + +2000-04-11 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/bits/posix_opt.h: Add + _POSIX_SHARED_MEMORY_OBJECTS. + +2000-04-11 Andreas Jaeger <aj@suse.de> + + * sysdeps/mips/pt-machine.h (MEMORY_BARRIER): Define. + (__compare_and_swap): Mark as modifying memory. + +2000-04-11 Geoff Keating <geoffk@cygnus.com> + + * sysdeps/powerpc/pt-machine.h (MEMORY_BARRIER): Don't be + __volatile__. + (__compare_and_swap): Replace other 'sync' with MEMORY_BARRIER. + Don't have the 'asm' __volatile__. + +2000-04-11 Ulrich Drepper <drepper@redhat.com> + + * internals.h: Define MEMORY_BARRIER as empty if not defined already. + * spinlock.c (__pthread_lock): Add memory barriers. + (__pthread_unlock): Likewise. + * sysdeps/alpha/pt-machine.h (MEMORY_BARRIER): Define using mb + instruction. + (RELEASE): Not needed anymore. + (__compare_and_swap): Mark asm as modifying memory. + * sysdeps/powerpc/pt-machine.h (sync): Remove. Replace with definition + of MEMORY_BARRIER. + (__compare_and_swap): Use MEMORY_BARRIER instead of sync. + * sysdeps/sparc/sparc32/pt-machine.h (RELEASE): Not needed anymore. + (MEMORY_BARRIER): Define using stbar. + * sysdeps/sparc/sparc64/pt-machine.h (MEMORY_BARRIER): Define using + stbar. + (__compare_and_swap): Use MEMORY_BARRIER to ensure ordering. + Patch by Xavier Leroy <Xavier.Leroy@inria.fr> based on comments by + Mike Burrows <m3b@pa.dec.com>. + +2000-04-09 Ulrich Drepper <drepper@redhat.com> + + * signals.c (sigaction): Fix return value for the case SIG is one + of the signals the implementation uses. + Patch by Xavier.Leroy@inria.fr. + +2000-04-01 Andreas Jaeger <aj@suse.de> + + * attr.c: Use shlib-compat macros. + * oldsemaphore.c: Likewise. + * pthread.c: Likewise. + * weaks.c: Likewise. + +2000-03-26 Ulrich Drepper <drepper@redhat.com> + + * semaphore.c (sem_timedwait): New function. + Patch by Carl Mailloux <carlm@oricom.ca>. + * semaphore.h: Declare sem_timedwait. + * Versions [libpthread] (GLIBC_2.2): Add sem_timedwait. + +2000-03-26 Roland McGrath <roland@baalperazim.frob.com> + + * sysdeps/pthread/Makefile: File removed. + +2000-03-23 Ulrich Drepper <drepper@redhat.com> + + * mutex.c (__pthread_reset_pthread_once): Reset once_masterlock. + * internals.h (__pthread_reset_pthread_once): Add prototype. + * ptfork.c (__fork): Call __pthread_reset_pthread_once. + + * manager.c (pthread_handle_create): Store ID of new thread before + clone call. + +2000-03-21 Ulrich Drepper <drepper@redhat.com> + + * attr.c: Use new macros from shlib-compat.h to define versions. + * oldsemaphore.c: Likewise. + * semaphore.c: Likewise. + * weaks.c: Likewise. + + * pthread.c: Update for new SHLIB_COMPAT definition. + + * manager.c (__pthread_manager): Unmask debug signal. + + * pthread.c (pthread_initialize): Test for address of __dso_handle + being NULL, not value. Use __on_exit, not on_exit. + Patch by Andreas Jaeger <aj@suse.de>. + + * pthread.c: Use new macros from shlib-compat.h to define versions. + +2000-03-19 Ulrich Drepper <drepper@redhat.com> + + * pthread.c (pthread_initialize): Instead of on_exit use + __cxa_atexit if __dso_label is available to allow unloading the + libpthread shared library. + +2000-03-16 Ulrich Drepper <drepper@redhat.com> + + * condvar.c: Make tests for ownership of mutex less strict. + +2000-03-14 Ulrich Drepper <drepper@redhat.com> + + * condvar.c (pthread_cond_wait): Check whether mutex is owned by + current thread and return error if not. + (pthread_cond_timedwait_relative_old): Likewise. + (pthread_cond_timedwait_relative_new): Likewise. + + * mutex.c (__pthread_once): Handle cancelled init function correctly. + (pthread_once_cancelhandler): New function. + Patch by Kaz Kylheku <kaz@ashi.footprints.net>. + +2000-03-14 Andreas Jaeger <aj@suse.de> + + * pthread.c (pthread_handle_sigcancel_rt): GS has been renamed to + REG_GS. + (pthread_handle_sigrestart_rt): Likewise. + * signals.c (pthread_sighandler_rt): Likewise. + +2000-03-02 Andreas Jaeger <aj@suse.de> + + * sysdeps/pthread/bits/libc-lock.h: Fix typo. + Reported by Sean Chen <sean.chen@turbolinux.com>. + +2000-02-28 Andreas Jaeger <aj@suse.de> + + * rwlock.c: Fix typo. + +2000-02-27 Ulrich Drepper <drepper@redhat.com> + + * rwlock.c: Define __* variants of the functions and make old names + aliases. + * Versions [GLIBC_2.2]: Export the __pthread_rwlock_* functions. + * sysdeps/pthread/bits/libc-lock.h: Define __libc_rwlock_* macros. + +2000-02-25 Andreas Jaeger <aj@suse.de> + + * Versions: Export pread, __pread64, pread64, pwrite, __pwrite64, + pwrite64, lseek64, open64, and __open64 with version 2.2. + +2000-02-22 Ulrich Drepper <drepper@redhat.com> + + * semaphore.h (SEM_FAILED): Use 0 not NULL. + +2000-02-14 Ulrich Drepper <drepper@redhat.com> + + * condvar.c (pthread_cond_timedwait_relative_old): Tight loop with + nanosleep does not work either. Get absolute time inside the + loop. + (pthread_cond_timedwait_relative_new): Likewise. + Patch by Kaz Kylheku <kaz@ashi.footprints.net>. + +2000-02-13 Andreas Jaeger <aj@suse.de> + + * condvar.c (pthread_cond_timedwait_relative_new): Fix last patch. + (pthread_cond_timedwait_relative_old): Likewise. + +2000-02-13 Ulrich Drepper <drepper@redhat.com> + + * condvar.c (pthread_cond_timedwait_relative_old): Undo last patch + but keep the code around. A bug in the kernel prevent us from + using the code. + (pthread_cond_timedwait_relative_new): Likewise. + (PR libc/1597 and libc/1598). + +2000-02-01 Kaz Kylheku <kaz@ashi.footprints.net> + + * condvar.c (pthread_cond_timedwait_relative_old): Do tight + loop around nanosleep calls instead of around most of the function + (pthread_cond_timedwait_relative_new): Likewise. + body. Got rid of backwards goto and one local. + +2000-01-31 Ulrich Drepper <drepper@redhat.com> + + * condvar.c (pthread_cond_timedwait_relative_old): Recompute time + before every nanosleep call to account for time spent in the rest + of the function. + (pthread_cond_timedwait_relative_new): Likewise. + Patch by khendricks@ivey.uwo.ca (PR libc/1564). + +2000-01-29 Ulrich Drepper <drepper@redhat.com> + + * condvar.c (pthread_cond_timedwait_relative_old): Get remaining time + from nanosleep call so that in case we restart we only wait for the + remaining time. + (pthread_cond_timedwait_relative_new): Likewise. + Patch by khendricks@ivey.uwo.ca (PR libc/1561). + +2000-01-18 Ulrich Drepper <drepper@cygnus.com> + + * manager.c (pthread_allocate_stack): Compute guard page address + correctly. Patch by HJ Lu. + + * sysdeps/pthread/pthread.h: Define + PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP. + +2000-01-16 Ulrich Drepper <drepper@cygnus.com> + + * rwlock.c (pthread_rwlock_unlock): Correct one more problem with + preference handling. + (pthread_rwlockattr_setkind_np): Allow + PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP. + Patches by Kaz Kylheku <kaz@ashi.footprints.net>. + +2000-01-12 Ulrich Drepper <drepper@cygnus.com> + + * internals.h (pthread_readlock_info): New structure. + (_pthread_descr_struct): Add p_readlock_list, p_readlock_free, and + p_untracked_readlock_count. + * pthread.c (__pthread_initial_thread, pthread_manager_thread): + Add initializers for new fields. + * manager.c (pthread_free): Free read/write lock lists. + * queue.h (queue_is_empty): New function. + * rwlock.c: Implement requirements about when readers should get + locks assigned. + * sysdeps/pthread/pthread.h + (PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP): New definition. + * sysdeps/pthread/bits/pthreadtypes.h (struct _pthread_rwlock_t): + Define this name as well. + Patches by Kaz Kylheku <kaz@ashi.footprints.net>. + +2000-01-05 Ulrich Drepper <drepper@cygnus.com> + + * pthread.c (__pthread_initial_thread, pthread_manager_thread): + Adjust initializers for struct _pthread_descr_struct change. + * internals.h (struct _pthread_descr_struct): Move new elements to + the end. + +2000-01-03 Kaz Kylheku <kaz@ashi.footprints.net> + + Redesigned how cancellation unblocks a thread from internal + cancellation points (sem_wait, pthread_join, + pthread_cond_{wait,timedwait}). + Cancellation won't eat a signal in any of these functions + (*required* by POSIX and Single Unix Spec!). + * condvar.c: Spontaneous wakeup on pthread_cond_timedwait won't eat a + simultaneous condition variable signal (not required by POSIX + or Single Unix Spec, but nice). + * spinlock.c: __pthread_lock queues back any received restarts + that don't belong to it instead of assuming ownership of lock + upon any restart; fastlock can no longer be acquired by two threads + simultaneously. + * restart.h: Restarts queue even on kernels that don't have + queued real time signals (2.0, early 2.1), thanks to atomic counter, + avoiding a rare race condition in pthread_cond_timedwait. + +1999-12-31 Andreas Jaeger <aj@suse.de> + + * internals.h: Remove duplicate prototype declarations. + + * weaks.c: Remove __THROW from prototypes since the file is not + compiled by a C++ compiler. + * internals.h: Likewise. + +1999-12-30 Andreas Jaeger <aj@suse.de> + + * sysdeps/pthread/pthread.h: Move internal functions to... + * sysdeps/pthread/bits/libc-lock.h: ...here. + +1999-12-29 Andreas Jaeger <aj@suse.de> + + * sysdeps/pthread/pthread.h: Fix typos, reformat comments. + +1999-12-28 Ulrich Drepper <drepper@cygnus.com> + + * sysdeps/alpha/pt-machine.h: Move stack_pointer definition to the + beginning. + + * manager.c (__pthread_start): Add one more cast to prevent + warning on 64bit machines. + +1999-12-21 Ulrich Drepper <drepper@cygnus.com> + + * manager.c (pthread_handle_create): Set p_pid of new thread + before calling the callback function to report a new thread. + +1999-12-20 Andreas Jaeger <aj@suse.de> + + * pthread.c (pthread_initialize): Move getrlimit call after + setting of errno. + +1999-12-18 Ulrich Drepper <drepper@cygnus.com> + + * Versions: Export pread, __pread64, pread64, pwrite, __pwrite64, + pwrite64, lseek64, open64, and __open64. + * wrapsyscall.c: Define pread, __pread64, pread64, pwrite, __pwrite64, + pwrite64, lseek64, open64, and __open64. + + * manager.c (pthread_allocate_stack): Correct computation of + new_thread_bottom. Correct handling of stack size and when the + rlimit method to guard for stack growth is used. + * pthread.c (pthread_initialize): Stack limit must be STACK_SIZE + minus one pagesize (not two). + +1999-12-03 Andreas Jaeger <aj@suse.de> + + * Versions: Add __res_state with version GLIBC_2.2. + + * errno.c (__res_state): New function to return thread specific + resolver state. + + * pthread.c (pthread_initialize): Initialize p_resp. + (__pthread_reset_main_thread): Also set p_resp. + + * manager.c (pthread_handle_create): Initialize p_resp. + + * internals.h: Add thread specific resolver state. + Based on patches by Adam D. Bradley <artdodge@cs.bu.edu>. + +1999-12-01 Ulrich Drepper <drepper@cygnus.com> + + * sysdeps/i386/pt-machine.h: Move stack_pointer definition to the + beginning. + * sysdeps/i386/i686/pt-machine.h: Likewise. + Patches by Alan Modra <alan@SPRI.Levels.UniSA.Edu.Au>. + +1999-11-23 Ulrich Drepper <drepper@cygnus.com> + + * manager.c (pthread_start_thread_event): Initialize p_pid already + here. + +1999-11-22 Ulrich Drepper <drepper@cygnus.com> + + * internals.h: Add prototype for __pthread_manager_event. + * manager.c (__pthread_manager_event): New function. + (pthread_start_thread_event): Correct computation of self. + Use INIT_THREAD_SELF. + * pthread.c (__pthread_manager_thread): Initialize p_lock. + (__pthread_initialize_manager): Respect event flags also for creation + of the manager thread. + +1999-11-08 Ulrich Drepper <drepper@cygnus.com> + + * pthread.c (__pthread_initialize_manager): Initialize + __pthread_manager_thread.p_tid. + +1999-11-02 Ulrich Drepper <drepper@cygnus.com> + + * internals.h: Declare __pthread_last_event. + * manager.c: Define __pthread_last_event. + (pthread_handle_create): Set __pthread_last_event. + (pthread_exited): Likewise. + * join.c (pthread_exit): Likewise. + + * Makefile (libpthread-routines): Add events. + * events.c: New file. + * internals.h: Protect against multiple inclusion. + Include thread_dbP.h header. + (struct _pthread_descr_struct): Add new fields p_report_events and + p_eventbuf. + Declare event reporting functions. + * join.c (pthread_exit): Signal event if this is wanted. + * manager.c (__pthread_threads_events): New variable. + (pthread_handle_create): Take new parameters with event information. + Signal TD_CREATE event if wanted. + (__pthread_manager): Adjust pthread_handle_create call. + (pthread_start_thread_event): New function. Block until manager is + finished and then call pthread_start_thread. + (pthread_exited): Signal TD_REAP event if wanted. + +1999-10-26 Ulrich Drepper <drepper@cygnus.com> + + * restart.h (suspend_with_cancellation): Rewrite as a macro. + + * condvar.c (pthread_cond_timedwait_relative): Don't mark as inline. + +1999-10-25 Andreas Jaeger <aj@suse.de> + + * internals.h: Remove K&R compatibility. + * no-tsd.c: Likewise. + * semaphore.h: Likewise. + * signals.c: Likewise. + * sysdeps/pthread/bits/libc-tsd.h: Likewise. + * sysdeps/unix/sysv/linux/bits/sigthread.h: Likewise. + * weaks.c: Likewise. + +1999-10-21 Xavier Leroy <Xavier.Leroy@inria.fr> + + * pthread.c: For i386, wrap pthread_handle_sigrestart and + pthread_handle_sigcancel with functions that restore %gs from the + signal context. For each signal handling function, two wrappers + are required, one for a non-RT signal and one for a RT signal. + * signal.c: For i386, add code to restore %gs from the signal + context in pthread_sighandler and pthread_sighandler_rt. + +1999-10-17 Ulrich Drepper <drepper@cygnus.com> + + * internals.h (PTHREAD_START_ARGS_INITIALIZER): Add cast. + +1999-10-14 Ulrich Drepper <drepper@cygnus.com> + + * pthread.c (__pthread_initial_thread): Pass argument to + PTHREAD_START_ARGS_INITIALIZER. + (__pthread_manager_thread): Likewise. + + * internals.h (PTHREAD_START_ARGS_INITIALIZER): Add parameter to + initialize function. + + * manager.c (pthread_handle_create): Remove p_startfct initialization. + + * internals.h (_pthread_descr_struct): We don't need p_startfct field. + +1999-10-12 Ulrich Drepper <drepper@cygnus.com> + + * internals.h: Correct return types for __libc_read and __libc_write. + +1999-10-09 Andreas Jaeger <aj@suse.de> + + * internals.h: Add __new_sem_post to get prototype in + manager.c; include semaphore.h for needed types. + +1999-10-08 Ulrich Drepper <drepper@cygnus.com> + + * manager.c (__pthread_manager) [REQ_POST]: Use __new_sem_post + directly instead of calling sem_post which should not be necessary + but is faster and might help in some case to work around problems. + Patch by khendricks@ivey.uwo.ca [libc/1382]. + +1999-10-08 Andreas Schwab <schwab@suse.de> + + * sysdeps/pthread/Subdirs: New file. + * Implies: Removed. + +1999-10-07 Ulrich Drepper <drepper@cygnus.com> + + * Implies: New file. + * internals.h (struct _pthread_descr_struct): Add p_startfct. + * manager.c (pthread_handle_create): Initialize p_startfct. + * pthread.c: Define __linuxthread_pthread_sizeof_descr variable. + +1999-09-25 Ulrich Drepper <drepper@cygnus.com> + + * manager.c (__linuxthreads_pthread_threads_max): New variable. + * specific.c (__linuxthreads_pthread_keys_max): New variable. + (__linuxthreads_pthread_key_2ndlevel_size): New variable. + + * condvar.c (pthread_cond_timedwait_relative): Never return with + EINTR. Patch by Andreas Schwab. + +1999-09-19 Ulrich Drepper <drepper@cygnus.com> + + * signals.c (sigaction): Correct last patch. Don't select + pthread_sighandler_rt based on the signal number but instead of + the SA_SIGINFO flag. + +1999-09-23 Ulrich Drepper <drepper@cygnus.com> + + * specific.c: Move definitions of struct pthread_key_struct and + destr_function to ... + * internals.h: ...here. + +1999-09-18 Ulrich Drepper <drepper@cygnus.com> + + * pthread.c (pthread_handle_sigrestart_rt): New function. Use + this instead of pthread_handle_sigrestart if the signal is an RT + signal. + + * signals.c: Handle passing through of sighandler arguments also + for real-time signals. + +1999-09-03 Andreas Schwab <schwab@suse.de> + + * ptfork.c (__fork): Renamed from fork and use __libc_fork. Add + fork as weak alias. + (__vfork): New function, alias vfork. + * Versions: Export __fork, vfork, and __vfork in libpthread. + +1999-08-23 Andreas Schwab <schwab@suse.de> + + * signals.c (pthread_sighandler): Add SIGCONTEXT_EXTRA_ARGS to + call to signal handler. + +1999-08-20 Ulrich Drepper <drepper@cygnus.com> + + * pthread.c (__pthread_reset_main_thread): Undo last change. + (__pthread_kill_other_threads_np): Reset signal handlers for the + signals we used in the thread implementation here. + +1999-08-19 Ulrich Drepper <drepper@cygnus.com> + + * pthread.c (__pthread_reset_main_thread): Reset signal handlers + for the signals we used in the thread implementation [PR libc/1234]. + + * Versions: Export __pthread_kill_other_threads_np from libpthread + for GLIBC_2.1.2. + + * signals.c: Pass sigcontext through wrapper to the user function. + +1999-08-01 Ulrich Drepper <drepper@cygnus.com> + + * Versions [ld.so] (GLIBC_2.0): Export __libc_internal_tsd_get and + __libc_internal_tsd_set. + +1999-07-29 Andreas Jaeger <aj@arthur.rhein-neckar.de> + + * manager.c: Remove inclusion of <linux/tasks.h> since it's not + needed anymore. + +1999-07-16 Andreas Jaeger <aj@arthur.rhein-neckar.de> + + * internals.h: Align _pthread_descr_struct to 32 bytes. + Reported by Tim Hockin <thockin@cobaltnet.com>, close PR + libc/1206. + +1999-07-09 Ulrich Drepper <drepper@cygnus.com> + + * oldsemaphore.c (sem_compare_and_swap): Fix use of compare and + swap function. + +1999-07-09 Cristian Gafton <gafton@redhat.com> + + * Makefile (libpthread-routines): Add oldsemaphore routine. + * Versions: Add sem_destroy, sem_getvalue, sem_init, sem_post, + sem_trywait, and sem_wait to GLIBC_2.1. + * oldsemaphore.c: New file. + * semaphore.c: Add default_symbol_versions for the changed functions. + (__new_sem_init): Rename from sem_init. + (__new_sem_post): Rename from sem_post. + (__new_sem_wait): Rename from sem_wait. + (__new_sem_trywait): Rename from sem_trywait. + (__new_sem_getvalue): Rename from sem_getvalue. + (__new_sem_destroy): Rename from sem_destroy. + +1999-06-23 Robey Pointer <robey@netscape.com> + + * internals.h: Added p_nextlock entry to separate queueing for a + lock from queueing for a CV (sometimes a thread queues on a lock + to serialize removing itself from a CV queue). + * pthread.c: Added p_nextlock to initializers. + * spinlock.c: Changed to use p_nextlock instead of p_nextwaiting. + +1999-07-09 Ulrich Drepper <drepper@cygnus.com> + + * manager.c (pthread_handle_create): Free mmap region after stack + if clone failed. Patch by Kaz Kylheku <kaz@ashi.FootPrints.net>. + +1999-05-23 Andreas Jaeger <aj@arthur.rhein-neckar.de> + + * man/pthread_cond_init.man: Correct example. + Reported by Tomas Berndtsson <tomas@nocrew.org>. + + * linuxthreads.texi (Condition Variables): Likewise. + +1999-05-18 Jakub Jelinek <jj@ultra.linux.cz> + + * sysdeps/sparc/sparc64/pt-machine.h (__compare_and_swap): Use + casx not cas, also successful casx returns the old value in rd + and not the new value. + +1999-05-16 Xavier Leroy <Xavier.Leroy@inria.fr> + + * manager.c: If pthread_create() is given a NULL attribute + and the thread manager runs with a realtime policy, set the + scheduling policy of the newly created thread back to SCHED_OTHER. + * manager.c: If the PTHREAD_INHERIT_SCHED attribute is given, + initialize the schedpolicy field of new_thread->p_start_args + to that of the calling thread. + +1999-04-29 Ulrich Drepper <drepper@cygnus.com> + + * sysdeps/sparc/sparc64/pt-machine.h (__compare_and_swap): cas + instruction does not allow memory element to use offset. + +1999-04-28 Ulrich Drepper <drepper@cygnus.com> + + * manager.c (pthread_allocate_stack): Optimize initialization of new + thread descriptor. + + * sysdeps/pthread/bits/libc-lock.h (__libc_lock_define_initialized): + Don't use initializer since it is all zeroes. + (__libc_once_define): Likewise. + +1999-04-16 Andreas Jaeger <aj@arthur.rhein-neckar.de> + + * sysdeps/arm/Implies: Removed since cmpxchg/no-cmpxchg + doesn't exist anymore. + * sysdeps/i386/Implies: Likewise. + * sysdeps/m68k/Implies: Likewise. + * sysdeps/mips/Implies: Likewise. + * sysdeps/powerpc/Implies: Likewise. + * sysdeps/sparc/sparc32/Implies: Likewise. + * sysdeps/sparc/sparc64/Implies: Likewise. + +1999-04-15 Ulrich Drepper <drepper@cygnus.com> + + * sysdeps/alpha/bits/semaphore.h: Removed. + * sysdeps/powerpc/bits/semaphore.h: Removed. + * sysdeps/pthread/cmpxchg/bits/semaphore.h: Removed. + * sysdeps/pthread/no-cmpxchg/bits/semaphore.h: Removed. + * Makefile (headers): Remove bits/semaphore.h. + + * semaphore.h: Define _pthread_descr if necessary. + Don't include limits.h. Define SEM_VALUE_MAX directly. + Define SEM_FAILED. + (sem_t): Protect element names with leading __. + Add declarations for sem_close, sem_open, and sem_unlink. + * semaphore.c: Adjust all functions for new element names. + Define sem_close, sem_open, and sem_unlink. + * Versions (libthread): Add sem_close, sem_open, and sem_unlink for + GLIBC_2.1.1. + * sysdeps/pthread/bits/pthreadtypes.h: Define _pthread_descr only if + necessary. + +1999-03-16 H.J. Lu <hjl@gnu.org> + + * specific.c (pthread_key_delete): Check th->p_terminated to see + if the thread is running. + + * Versions (__libc_internal_tsd_get, __libc_internal_tsd_set): + Added to GLIBC_2.0 for libc.so. + +1999-02-12 H.J. Lu <hjl@gnu.org> + + * Versions (__libc_current_sigrtmin, __libc_current_sigrtmax, + __libc_allocate_rtsig): Added to GLIBC_2.1. + + * internals.h (DEFAULT_SIG_RESTART): Removed. + (DEFAULT_SIG_CANCEL): Removed. + + * pthread.c (init_rtsigs, __libc_current_sigrtmin, + __libc_current_sigrtmax, __libc_allocate_rtsig): New functions. + (__pthread_sig_restart, __pthread_sig_cancel, + __pthread_sig_debug): Initialized. + (pthread_initialize): Call init_rtsigs () to initialize + real-time signals. + +1999-02-03 H.J. Lu <hjl@gnu.org> + + * manager.c (__pthread_manager): Do block __pthread_sig_debug. + Don't restart the thread which sent REQ_DEBUG. + (pthread_start_thread): Check if __pthread_sig_debug > 0 + before debugging. + + * pthread.c (__pthread_initialize_manager): Suspend ourself + after sending __pthread_sig_debug to gdb instead of + __pthread_sig_cancel. + +1999-01-24 H.J. Lu <hjl@gnu.org> + + * manager.c (__pthread_manager): Delete __pthread_sig_debug + from mask if __pthread_sig_debug > 0. + (pthread_handle_create): Increment __pthread_handles_num. + + * manager.c (pthread_handle_create): Don't pass CLONE_PTRACE to clone. + * pthread.c (__pthread_initialize_manager): Likewise. + + * pthread.c (pthread_initialize): Use __libc_allocate_rtsig (1) + instead of __libc_allocate_rtsig (2). + (__pthread_initialize_manager): Send __pthread_sig_debug to gdb + instead of __pthread_sig_cancel. + (pthread_handle_sigdebug): Fix comments. + +1999-01-21 Ulrich Drepper <drepper@cygnus.com> + + * manager.c (pthread_allocate_stack): Set + __pthread_nonstandard_stacks if user-specified stack is used. + +1999-01-16 Ulrich Drepper <drepper@cygnus.com> + + * sysdeps/unix/sysv/linux/bits/posix_opt.h: Add _LFS_ASYNCHRONOUS_IO, + _LFS_LARGEFILE, _LFS64_LARGEFILE, and _LFS64_STDIO from Unix98. + +1999-01-07 Xavier Leroy <Xavier.Leroy@inria.fr> + + * pthread.c: Use a third signal __pthread_sig_debug distinct + from __pthread_sig_cancel to notify gdb when a thread is + created + * manager.c: Likewise. + * internals.h: Likewise. + * signals.c: The implementation of sigwait(s) assumed that + all signals in s have signal handlers already attached. + This is not required by the standard, so make it work + also if some of the signals have no handlers. + +1999-01-05 Andreas Schwab <schwab@issan.cs.uni-dortmund.de> + + * linuxthreads.texi: Remove pointers from first @node. Move old + @node spec inside comment. + +1998-12-31 Ulrich Drepper <drepper@cygnus.com> + + * sysdeps/pthread/bits/stdio-lock.h: Define _IO_lock_lock and + _IO_lock_unlock. + +1998-12-29 Ulrich Drepper <drepper@cygnus.com> + + * semaphore.c (sem_trywait): Don't forget to unlock the semaphore + lock. Patch by Bernd Schmidt <crux@pool.informatik.rwth-aachen.de>. + +1998-12-21 Ulrich Drepper <drepper@cygnus.com> + + * manager.c: Threads now send __pthread_sig_cancel on termination. + Change clone call and signal masks. + * thread.c (pthread_handle_sigrestart): Remove special code for + manager. + (pthread_handle_sigcancel): In manager thread call + __pthread_manager_sighandler. + * sysdeps/i386/pt-machine.h (__compare_and_swap): Add memory clobber. + * sysdeps/i386/i686/pt-machine.h: Likewise. + Patches by Xavier Leroy. + +1998-12-14 Ulrich Drepper <drepper@cygnus.com> + + * spinlock.c (__pthread_unlock): Don't crash if called for an + untaken mutex. Reported by Ruslan V. Brushkoff <rus@Snif.Te.Net.UA>. + + * Examples/ex6.c: Unbuffer stdout and reduce sleep time to reduce + overall runtime. + +1998-12-13 Ulrich Drepper <drepper@cygnus.com> + + * Examples/ex3.c: Wait until all threads are started before + searching for the number to avoid race condition on very fast + systems. + +1998-12-08 Andreas Jaeger <aj@arthur.rhein-neckar.de> + + * sysdeps/pthread/pthread.h: Remove __pthread_setcanceltype + declaration since it's not needed. + + * sysdeps/pthread/pthread.h: Move internal functions to ... + * internals.h: ...here. + +1998-12-02 H.J. Lu <hjl@gnu.org> + + * pthread.c (__pthread_sig_restart): Initiliaze to 0 if + SIGRTMIN is defined. + (__pthread_sig_cancel): Likewise. + +1998-12-01 Andreas Jaeger <aj@arthur.rhein-neckar.de> + + * wrapsyscall.c: Include <sys/mman.h> for msync, + <stdlib.h> for system and <termios.h> for tcdrain prototype. + Correct msync declaration. + +1998-11-29 Roland McGrath <roland@baalperazim.frob.com> + + * sysdeps/pthread/bits/libc-tsd.h (__libc_tsd_define, __libc_tsd_get, + __libc_tsd_set): New macros for new interface. + * no-tsd.c: New file, provide uninitialized defns of + __libc_internal_tsd_get and __libc_internal_tsd_set. + * Makefile (routines): Add no-tsd. + +1998-10-12 Roland McGrath <roland@baalperazim.frob.com> + + * internals.h: Include <bits/libc-tsd.h>, not <bits/libc-lock.h>. + * sysdeps/pthread/bits/libc-lock.h (__libc_internal_tsd_get, + __libc_internal_tsd_set): Move decls to ... + * sysdeps/pthread/bits/libc-tsd.h: New file for __libc_internal_tsd_* + declarations. + + * sysdeps/pthread/bits/libc-lock.h (__libc_internal_tsd_get, + __libc_internal_tsd_set): Make these pointers to functions, not + functions; remove #pragma weak decls for them. + * specific.c (__libc_internal_tsd_get, __libc_internal_tsd_set): + Define static functions and initialized pointers to them. + +1998-11-18 Ulrich Drepper <drepper@cygnus.com> + + * Makefile (CFLAGS-mutex.c): Define as -D__NO_WEAK_PTHREAD_ALIASES. + (CFLAGS-specific.c): Likewise. + (CFLAGS-pthread.c): Likewise. + (CFLAGS-ptfork.c): Likewise. + (CFLAGS-cancel.c): Likewise. + * sysdeps/pthread/bits/libc-lock.h: Don't mark __pthread_* functions + as weak references if __NO_WEAK_PTHREAD_ALIASES is defined. + + * mutex.c (pthread_mutex_init): Define as strong symbol. + (pthread_mutex_destroy): Likewise. + (pthread_mutex_trylock): Likewise. + (pthread_mutex_lock): Likewise. + (pthread_mutex_unlock): Likewise. + (pthread_mutexattr_init): Likewise. + (pthread_mutexattr_destroy): Likewise. + (pthread_once): Likewise. + * ptfork.c (pthread_atfork): Likewise. + * specific.c (pthread_key_create): Likewise. + (pthread_setspecific): Likewise. + (pthread_getspecific): Likewise. + +1998-11-15 Andreas Schwab <schwab@issan.cs.uni-dortmund.de> + + * linuxthreads.texi: Fix punctuation after xref. + +1998-11-10 H.J. Lu <hjl@gnu.org> + + * sysdeps/unix/sysv/linux/bits/local_lim.h: Undefine NR_OPEN + if it is defined in <linux/limits.h>. + +1998-10-29 14:28 Ulrich Drepper <drepper@cygnus.com> + + * spinlock.h (__pthread_trylock): Define inline. + (__pthread_lock): Add extra parameter to declaration. Declare + using internal_function. + (__pthread_unlock): Declare using internal_function. + * spinlock.c (__pthread_lock): Add new parameter. Use it instead + of local variable self. Avoid recomputing self. Define using + internal_function. + (__pthread_trylock): Remove. + (__pthread_unlock): Define using internal_function. + * cancel.c: Adjust for __pthread_lock interface change. Use already + computed self value is possible. + * condvar.c: Likewise. + * join.c: Likewise. + * manager.c: Likewise. + * mutex.c: Likewise. + * pthread.c: Likewise. + * rwlock.c: Likewise. + * semaphore.c: Likewise. + * signals.c: Likewise. + +1998-10-27 13:46 Ulrich Drepper <drepper@cygnus.com> + + * sysdeps/pthread/pthread.h (struct _pthread_cleanup_buffer): Prepend + __ to field names of the struct. + * sysdeps/pthread/bits/pthreadtypes.h (struct _pthread_fastlock): + Likewise. + (pthread_attr_t): Likewise. + (pthread_cond_t): Likewise. + (pthread_condattr_t): Likewise. + (pthread_mutex_t): Likewise. + (pthread_mutexattr_t): Likewise. + (pthread_rwlock_t): Likewise. + (pthread_rwlockattr_t): Likewise. + * attr.c: Adjust for pthread.h and pthreadtypes.h change. + * cancel.c: Likewise. + * condvar.c: Likewise. + * manager.c: Likewise. + * mutex.c: Likewise. + * pthread.c: Likewise. + * ptlongjmp.c: Likewise. + * rwlock.c: Likewise. + * spinlock.c: Likewise. + +1998-10-09 Ulrich Drepper <drepper@cygnus.com> + + * sysdeps/i386/pt-machine.h (get_eflags, set_eflags): Mark these + also with PT_EI. + + * sysdeps/i386/i686/pt-machine.h: Remove unused inline + definitions. + + * Makefile (libpthread-routines): Add pt-machine. + * pt-machine.c: New file. + * sysdeps/alpha/pt-machine.h: Define PT_EI as extern inline is not + yet defined. Use PT_EI in extern inline definitions. + * sysdeps/arm/pt-machine.h: Likewise. + * sysdeps/i386/pt-machine.h: Likewise. + * sysdeps/i386/i686/pt-machine.h: Likewise. + * sysdeps/m68k/pt-machine.h: Likewise. + * sysdeps/mips/pt-machine.h: Likewise. + * sysdeps/powerpc/pt-machine.h: Likewise. + * sysdeps/sparc/sparc32/pt-machine.h: Likewise. + * sysdeps/sparc/sparc64/pt-machine.h: Likewise. + +1998-10-02 Andreas Jaeger <aj@arthur.rhein-neckar.de> + + * semaphore.h: Include <sys/types.h> so that _pthread_descr + is declared. + +1998-09-15 David S. Miller <davem@pierdol.cobaltmicro.com> + + * sysdeps/sparc/sparc32/pt-machine.h (INIT_THREAD_SELF): Add nr + argument. + * sysdeps/sparc/sparc64/pt-machine.h (INIT_THREAD_SELF): Likewise. + +1998-09-12 14:24 -0400 Zack Weinberg <zack@rabi.phys.columbia.edu> + + * sysdeps/unix/sysv/linux/bits/sigthread.h: Add multiple inclusion + guard. + +1998-09-02 11:08 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> + + * signals.c (sigaction): Check that sig is less than NSIG to avoid + array index overflow. + +1998-09-06 10:56 Ulrich Drepper <drepper@cygnus.com> + + * sysdeps/pthread/semaphore.h: New file. + +1998-09-06 09:08 Ulrich Drepper <drepper@cygnus.com> + + * sysdeps/pthread/bits/libc-lock.h (enum __libc_tsd_key_t): Add + _LIBC_TSD_KEY_DL_ERROR. + +1998-08-31 Ulrich Drepper <drepper@cygnus.com> + + * sysdeps/i386/i686/pt-machine.h (testandset): Add memory clobber. + * sysdeps/i386/pt-machine.h: Likewise. + Suggested by Roland McGrath. + +1998-08-28 13:58 Ulrich Drepper <drepper@cygnus.com> + + * internals.h: Also define THREAD_GETMEM_NC and THREAD_SETMEM_NC to + access thread data with non-constant offsets. + * specific.c: Use THREAD_GETMEM_NC and THREAD_SETMEM_NC where + necessary. + + * sysdeps/i386/useldt.h: Fix typo. Add THREAD_GETMEM_NC and + THREAD_SETMEM_NC definitions. + + * sysdeps/sparc/sparc32/pt-machine.h: Define THREAD_GETMEM_NC and + THREAD_SETMEM_NC. + * sysdeps/sparc/sparc64/pt-machine.h: Likewise. + +1998-08-26 15:46 Ulrich Drepper <drepper@cygnus.com> + + * internals.h: Define THREAD_GETMEM and THREAD_SETMEM to default if + not already defined. + (struct _pthread_descr_struct): Add p_self and p_nr field. + * manager.c (__pthread_handles): Define second element to point + to manager thread. + (__pthread_handles_num): Initialize to 2. + (__pthread_manager): Use INIT_THREAD_SELF with two arguments. + (pthread_start_thread): Likewise. + (pthread_handle_create): Start search for free slot at entry 2. + Initialize new fields p_self and p_nr. + Call __clone with CLONE_PTRACE if available. + (pthread_free): Call FREE_THREAD_SELF if available. + * pthread.c (__pthread_initial_thread): Initialize new fields. + (__pthread_manager_thread): Likewise. + (__pthread_initialize_manager): Call __clone with CLONE_PTRACE. + + * cancel.c: Use THREAD_GETMEM and THREAD_SETMEM to access the + elements of the thread descriptor. + * condvar.c: Likewise. + * errno.c: Likewise. + * join.c: Likewise. + * manager.c: Likewise. + * pthread.c: Likewise. + * ptlongjmp.c: Likewise. + * semaphore.c: Likewise. + * signals.c: Likewise. + * specific.c: Likewise. + * spinlock.c: Likewise. + + * sysdeps/alpha/pt-machine.h (INIT_THREAD_SELF): Add extra parameter. + + * sysdeps/i386/useldt.h: New file. + * sysdeps/i386/i686/pt-machine.h: Show how to use this file. + + * sysdeps/sparc/sparc32/pt-machine.h: Define THREAD_GETMEM and + THREAD_SETMEM using __thread_self. + * sysdeps/sparc/sparc64/pt-machine.h: Likewise. + +1998-08-24 Geoff Keating <geoffk@ozemail.com.au> + + * spinlock.c (__pthread_lock): Reset p_nextwaiting to NULL if it + turned out that we didn't need to queue after all. + +1998-08-22 Geoff Keating <geoffk@ozemail.com.au> + + * sysdeps/powerpc/pt-machine.h: Remove testandset, it's not used + and wastes space; correct types. + +1998-08-08 11:18 H.J. Lu <hjl@gnu.org> + + * signals.c (sigaction): Handle NULL argument. + +1998-08-04 Ulrich Drepper <drepper@cygnus.com> + + * sysdeps/unix/sysv/linux/bits/sigthread.h: Use __sigset_t instead + of sigset_t. + +1998-08-02 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> + + * Makefile (linuxthreads-version): Extract correct number from + Banner. + +1998-07-29 Xavier Leroy <Xavier.Leroy@inria.fr> + + * Banner: Bump version number to 0.8 + * FAQ.html: Many updates, in particular w.r.t. debugging. + * manager.c: Support for non-default stacksize for + LinuxThreads-allocated stacks; + don't use guard pages for stacks with default size, rely on + rlimit(RLIMIT_STACK) instead (it's cheaper). + * attr.c: Likewise. + * cancel.c: Use __pthread_sig_cancel and __pthread_sig_restart + everywhere instead of PTHREAD_SIG_CANCEL and PTHREAD_SIG_RESTART. + * condvar.c: Likewise. + * internals.h: Likewise. + * restart.h: Likewise. + * signals.c: Likewise. + * pthread.c: Likewise; set rlimit(RLIMIT_STACK) as we need it. + +1998-07-23 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> + + * weaks.c: Define pthread_mutexattr_[sg]ettype instead of + __pthread_mutexattr_[sg]ettype. Add more weak aliases. + * Versions: Put __pthread_mutexattr_settype under version + GLIBC_2.0. Don't export __pthread_mutexattr_setkind_np and + __pthread_mutexattr_gettype. + +1998-07-23 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> + + * sysdeps/pthread/bits/libc-lock.h: Make + __pthread_mutexattr_settype weak. Don't make + __pthread_mutexattr_setkind_np weak. + +1998-07-16 10:52 Ulrich Drepper <drepper@cygnus.com> + + * manager.c (pthread_handle_create): Check whether sched_setscheduler + call can succeed here. + + * mutex.c: Define __pthread_mutexattr_settype and make + __pthread_mutexattr_setkind_np an alias. + Likewise for __pthread_mutexattr_gettype. + +1998-07-15 11:00 -0400 Zack Weinberg <zack@rabi.phys.columbia.edu> + + * attr.c (pthread_attr_setschedpolicy): Don't check whether caller + is root. + +1998-07-14 19:38 Ulrich Drepper <drepper@cygnus.com> + + * sysdeps/pthread/bits/libc-lock.h: Define __libc_cleanup_end. + +1998-07-11 Andreas Jaeger <aj@arthur.rhein-neckar.de> + + * Examples/ex6.c: Include <unistd.h> for usleep. + +1998-06-13 11:04 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> + + * Examples/ex4.c (main): Use exit, not pthread_exit. + +1998-07-09 13:39 Ulrich Drepper <drepper@cygnus.com> + + * Versions: Add __pthread_mutexattr_gettype and + __pthread_mutexattr_settype. + * lockfile.c: Use __pthread_mutexattr_settype instead of + __pthread_mutexattr_setkind_np. + * mutex.c: Define __pthread_mutexattr_gettype and + __pthread_mutexattr_settype. + * weak.c: Likewise. + * sysdeps/pthread/pthread.h: Declare __pthread_mutexattr_gettype and + __pthread_mutexattr_settype. + * sysdeps/pthread/bits/libc-lock.h (__libc_lock_init_recursive): + Use __pthread_mutexattr_settype. + +1998-07-08 22:26 Ulrich Drepper <drepper@cygnus.com> + + * Versions: Add pthread_mutexattr_gettype, pthread_mutexattr_settype. + * mutex.c: Define weak alias pthread_mutexattr_gettype and + pthread_mutexattr_settype. + * sysdeps/pthread/pthread.h: Declare these functions. + Move pthread_sigmask and pthread_kill declaration in separate header. + * sysdeps/unix/sysv/linux/bits/sigthread.h: New file. + +1998-07-07 15:20 Ulrich Drepper <drepper@cygnus.com> + + * Makefile: Add rules to compile and run tests. + * Examples/ex1.c: Little changes to fix warnings. + * Examples/ex2.c: Likewise. + * Examples/ex3.c: Likewise. + * Examples/ex4.c: Likewise. + * Examples/ex5.c: Likewise. + * Examples/ex6.c: New file. + +1998-07-05 11:54 Ulrich Drepper <drepper@cygnus.com> + + * Versions: Add pthread_attr_init to GLIBC_2.1 version in libc. + +1998-07-01 Andreas Jaeger <aj@arthur.rhein-neckar.de> + + * attr.c: Include <string.h>. + +1998-06-30 11:47 Ulrich Drepper <drepper@cygnus.com> + + * attr.c: Include errno.h. Use memcpy to copy sched_param. + * internals.h: Include limits.h. + * manager.c: Use memcpy to copy sched_param. + * ptfork.c: Include errno.h. + * pthread.c: Likewise. + * semaphore.c: Likewise. + * specific.c: Likewise. + * spinlock.h: Likewise. + * sysdeps/pthread/pthread.h: Include only allowed headers. Move + type definition to ... + * sysdeps/pthread/bits/pthreadtypes.h: ...here. New file. + +1998-06-29 12:34 Ulrich Drepper <drepper@cygnus.com> + + * sysdeps/pthread/pthread.h: Use __PMT not __P for function pointers. + + * sysdeps/pthread/pthread.h: Define various PTHREAD_* symbols also + as macros as demanded in POSIX.1, Annex C. + +1998-06-29 12:29 Ulrich Drepper <drepper@cygnus.com> + + * internals.h (struct pthread_request): For free use pthread_t + instead of pthread_descr. + * join.c (pthread_join): Pass thread_id, not th to manager. + (pthread_detach): Likewise. + * manager.c (__pthread_manager): Except thread ID in FREE_REQ case. + (pthread_exited): Remove detached queue code. + (pthread_handle_free): Expect thread ID parameter and use it to + validate the thread decsriptor. Don't use detached queue. + Patches by Xavier Leroy. + +1998-06-27 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> + + * libpthread.map: Export accept, longjmp, sigaction, siglongjmp, + _IO_flockfile, _IO_ftrylockfile, _IO_funlockfile, + __pthread_atfork, __pthread_key_create, __pthread_once. + * internals.h: Doc fix. + * pthread.c (__pthread_initialize): Define again. + +1998-06-26 Ulrich Drepper <drepper@cygnus.com> + + * manager.c (pthread_exited): If thread is not detached put it on + special list. + (pthread_handle_free): If thread is not on list with living threads + search on list with detached threads. + + * sysdeps/pthread/pthread.h (PTHREAD_RWLOCK_INITIALIZER): Correct + for new definition of pthread_rwlock_t. + + * spinlock.c: Correct test whether to compile + __pthread_compare_and_swap or not. + +1998-06-25 19:27 Ulrich Drepper <drepper@cygnus.com> + + * attr.c: Finish user stack support. Change locking code to be safe + in situations with different priorities. + * cancel.c: Likewise. + * condvar.c: Likewise. + * internals.h: Likewise. + * join.c: Likewise. + * manager.c: Likewise. + * mutex.c: Likewise. + * pthread.c: Likewise. + * ptlongjmp.c: Likewise. + * queue.h: Likewise. + * rwlock.c: Likewise. + * semaphore.c: Likewise. + * semaphore.h: Likewise. + * signals.c: Likewise. + * spinlock.c: Likewise. + * spinlock.h: Likewise. + * sysdeps/pthread/pthread.h: Likewise. + Patches by Xavier Leroy. + + * sysdeps/i386/i686/pt-machine.h: New file. + +1998-06-25 Ulrich Drepper <drepper@cygnus.com> + + * sysdeps/pthread/pthread.h: Make [sg]et_stacksize and + [sg]et_stackaddr prototypes always available. + + * sysdeps/unix/sysv/linux/bits/posix_opt.h: Define + _POSIX_THREAD_ATTR_STACKSIZE and _POSIX_THREAD_ATTR_STACKADDR. + +1998-06-24 Ulrich Drepper <drepper@cygnus.com> + + * manager.c (pthread_free): Undo patch from 980430. + Reported by David Wragg <dpw@doc.ic.ac.uk>. + +1998-06-09 15:07 Ulrich Drepper <drepper@cygnus.com> + + * manager.c: Define __pthread_manager_adjust_prio and use it to + increase priority when needed. + * internals.h: Add prototype for __pthread_manager_adjust_prio. + * mutex.c: Optimize mutexes to wake up only one thread. + * pthread.c: Move PID of manager for global variable in structure + element. + Patches by Xavier Leroy. + +1998-06-07 13:47 Ulrich Drepper <drepper@cygnus.com> + + * sysdeps/pthread/bits/libc-lock.h: Optimize cleanup handlers a bit. + +1998-06-03 Andreas Jaeger <aj@arthur.rhein-neckar.de> + + * attr.c: Correct typo. + +1998-05-01 Ulrich Drepper <drepper@cygnus.com> + + * manager.c (pthread_free): Unmap guard before the stack. + Patch by Matthias Urlichs. + +1998-04-30 Ulrich Drepper <drepper@cygnus.com> + + * manager.c (pthread_free): Detect already free child. + Patch by Xavier Leroy, reported by Matthias Urlichs. + +1998-04-23 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> + + * Makefile (linuxthreads-version): Renamed back from + libpthread-version. + +1998-04-21 Ulrich Drepper <drepper@cygnus.com> + + * ptlongjmp.c: Add prototypes for __libc_siglongjmp and + __libc_longjmp. + +1998-04-20 14:55 Ulrich Drepper <drepper@cygnus.com> + + * Makefile (libpthread-routines): Add ptlongjmp and spinlock. + * internals.h: Add definitions for new spinlock implementation. + * ptlongjmp.c: New file. + * spinlock.c: New file. + * spinlock.h (acquire): Don't reschedule using __sched_yield, use + new function __pthread_acquire to prevent deadlocks with thread + with different priorities. + Patches by Xavier Leroy <Xavier.Leroy@inria.fr>. + +1998-03-16 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> + + * manager.c (__pthread_manager): Reduce first argument to select + to include just the needed file descriptor. + +1998-03-17 00:06 Ulrich Drepper <drepper@cygnus.com> + + * manager.c: Fix last patch which caused core dumps. + + * pthread.c: Correctly handle missing SIGRTMIN. + +1998-03-15 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> + + * libpthread.map: Add __libc_internal_tsd_get and + __libc_internal_tsd_set. Add missing cancelable functions. Export + libc internal versions of the cancelable functions. + +1998-03-13 16:51 Ulrich Drepper <drepper@cygnus.com> + + * weaks.c: Define pthread_attr_init as GLIBC_2.0 and GLIBC_2.1. + +1998-03-13 00:46 Ulrich Drepper <drepper@cygnus.com> + + * attr.c: Implement pthread_attr_[gs]etguardsize, + pthread_attr_[gs]setstackaddr, pthread_attr_[gs]etstacksize. + Change pthread_attr_init to have two interfaces. + * internals.h (struct _pthread_descr_struct): Add new fields for + above functions. + * libpthread.map: Add names in GLIBC_2.1 section. + * manager.c (pthread_handle_create): Implement guardsize and + user stack. + (pthread_free): Likewise. + * pthread.c (pthread_create): Add new interface for changed + pthread_attr_t. + * sysdeps/pthread/pthread.h: Add prototypes for new functions. + * sysdeps/unix/sysv/linux/bits/local_lim.h: Add definition of + PTHREAD_STACK_MIN. + +1998-03-11 00:42 Wolfram Gloger <wmglo@dent.med.uni-muenchen.de> + + * manager.c: Enable resetting of the thread scheduling policy + to SCHED_OTHER when the parent thread has a different one. + +1998-02-01 13:51 Ulrich Drepper <drepper@cygnus.com> + + * sysdeps/unix/sysv/linux/bits/posix_opt.h: Define + _POSIX_ASYNCHRONOUS_IO. + + * sysdeps/pthread/pthread.h: Define bits for Unix98 variants of + mutexes. + * mutex.c: Implement new mutex types. + + * internals.h: Include <signal.h>. + + * libpthread.map: Add __erno_location and __h_errno_location. + + * errno.c: Return pointer to variable actually in use. This might + not be the one in the thread structure. + * internals.h (struct _pthread_descr_struct): Add new fields p_errnop + and p_h_errnop. + * manager.c (__pthread_manager): Set p_errnop and p_h_errnop member + of manager thread structure. + (pthread_handle_create): Set p_errnop and p_h_errnop members for new + thread. + * pthread.c: Adapt initializer for thread structures. + (__pthread_initial_thread): Set p_errnop and p_h_errnop member. + (__pthread_reset_main_thread): Reset p_errnop and p_h_errnop of + current thread to global variables. + +1998-01-31 17:27 Ulrich Drepper <drepper@cygnus.com> + + * rwlock.c: New file. + * Makefile (libpthread-routines): Add rwlock. + * sysdeps/pthread/pthread.h: Define data structures and declare + functions. + * libpthread.map: Add new functions. + +1997-12-18 13:50 Philip Blundell <pb@nexus.co.uk> + + * sysdeps/arm/pt-machine.h: New file; add ARM support. + * sysdeps/arm/Implies: likewise. + * README: Document it. + +1997-12-13 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> + + * signals.c: Remove unneeded initializer for sigwaited, saving a + warning. + +1997-04-11 01:18 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> + + * semaphore.c (sem_init): Set sem_spinlock only if available. + +1997-12-04 01:48 Ulrich Drepper <drepper@cygnus.com> + + * mutex.c: Implement PTHREAD_MUTEX_CHECKERROR. + * sysdeps/pthread/pthread.h: Define PTHREAD_MUTEX_CHECKERROR. + + * Makefile: Update from LinuxThreads 0.7. + * internals.h. Likewise. + * manager.c: Likewise. + * mutex.c: Likewise. + * pthread.c: Likewise. + * signals.c: Likewise. + * specific.c: Likewise. + * Examples/ex3.c: Likewise. + +1997-11-20 18:13 Ulrich Drepper <drepper@cygnus.com> + + * pthread.c (__pthread_reset_main_thread): Close pipe only if still + open. + +1997-10-29 05:38 Ulrich Drepper <drepper@cygnus.com> + + * wrapsyscall.c: Add socket functions which are also cancelation + points. + +1997-10-19 21:40 Wolfram Gloger <wg@wolfram.dent.med.uni-muenchen.de> + + * specific.c (__libc_internal_tsd_set, __libc_internal_tsd_get): + New functions for fast thread specific data within libc. + + * internals.h: Add new array p_libc_specific to struct + _pthread_descr_struct. + + * sysdeps/pthread/bits/libc-lock.h: Declare new functions. + +1997-10-13 05:39 Ulrich Drepper <drepper@cygnus.com> + + * semaphore.h: Add __BEGIN_DECLS/__END_DECLS. + Reported by Ralf Corsepius <corsepiu@faw.uni-ulm.de>. + +1997-08-29 03:05 Ulrich Drepper <drepper@cygnus.com> + + * internals.h (struct _pthread_descr_struct): Add definitions for + two-level specific key handling. + * manager.c (pthread_handle_create): Initialize specific memory array. + * specific.c: Implement two-level key handling. + * weaks.c: Don't provide dummy key handling. + * sysdeps/pthread/bits/libc-lock.h: Typedef __libc_lock_t (no #define). + Add definition of __libc_key_t. + * sysdeps/unix/sysv/linux/bits/local_lim.h: Define PTHREAD_KEYS_MAX + as 1024. + Add definition of _POSIX_THREAD_DESTRUCTOR_ITERATIONS and + PTHREAD_DESTRUCTOR_ITERATIONS. + + * manager.c (pthread_handle_create): Compare mmap result with + MAP_FAILED. + + * ptfork.c: Rename to __pthread_atfork and make old name a weak alias. + * sysdeps/pthread/bits/pthread.h: Add prototype for __pthread_atfork. + +1997-08-22 19:04 Richard Henderson <rth@cygnus.com> + + sysdeps/sparc -> sysdeps/sparc/sparc32 + sysdeps/sparc64 -> sysdeps/sparc/sparc64 + + * internals.h: Change definition of THREAD_SELF to be an expression, + not a statement that did a return. + * sysdeps/alpha/pt-machine.h (THREAD_SELF): Update accordingly. + * sysdeps/sparc/sparc32/pt-machine.h (THREAD_SELF, INIT_THREAD_SELF): + Follow Solaris and use a "system reserved" register (%g6) to hold + the thread descriptor. + * sysdeps/sparc/sparc64/pt-machine.h: Likewise. + +1997-08-03 00:09 Ulrich Drepper <drepper@cygnus.com> + + * mutex.c: Correct pthread_once. Patch by Xavier Leroy. + * sysdeps/pthread/pthread.h: Add prototype for __pthread_once. + * sysdeps/pthread/bits/pthread.h: Add macros for __libc_once. + + * semaphore.c: Include spinlock.h only when needed. + + * specific.c (__pthread_setsepcific, __pthread_getspecific): Reject + keys for entries not in use. + + * weaks.c: Implement key handling functions for real. + +1997-06-29 01:04 Richard Henderson <richard@gnu.ai.mit.edu> + + Initial sparc64-linux support: + * sysdeps/sparc64/Implies: New file. + * sysdeps/sparc64/pt-machine.h: Likewise. + +1997-06-29 00:48 Ulrich Drepper <drepper@cygnus.com> + + * semaphore.c: Include spinlock.h at correct place. + Patch by HJ Lu. + +1997-06-13 10:06 Richard Henderson <rth@tamu.edu> + + The Great Bit File Move: + * sysdeps/alpha/semaphorebits.h: -> .../bits/semaphore.h. + * sysdeps/powerpc/semaphorebits.h: Likewise. + * sysdeps/pthread/cmpxchg/semaphorebits.h: Likewise. + * sysdeps/pthread/no-cmpxchg/semaphorebits.h: Likewise. + * sysdeps/pthread/libc-lock.h: -> bits/ + * sysdeps/pthread/stdio-lock.h: Likewise. + * sysdeps/unix/sysv/linux/local_lim.h: Likewise. + * sysdeps/unix/sysv/linux/posix_opt.h: Likewise. + * semaphore.h: Likewise. + * sysdeps/pthread/pthread.h: Likewise. + + * lockfile.c: <foo.h> -> <bits/foo.h>. + * semaphore.h: Likewise. + + * Makefile: (headers): foo.h -> bits/foo.h. + * sysdeps/pthread/Makefile: Likewise. + +1997-04-11 01:18 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> + + * semaphore.c (sem_init): Set sem_spinlock only if available. + + * sysdeps/m68k/pt-machine.h (testandset, __compare_and_swap): Fix + asm constraints. + +1997-04-09 03:00 Ulrich Drepper <drepper@cygnus.com> + + Update from LinuxThreads 0.6. + + * attr.c (pthread_attr_getdetachstate): Use __sched_get_priority_max + and __sched_get_priority_min instead of names without `__'. + + * manager.c: Rewrite large parts to implement opaque pthread_t. + + * cancel.c: Adapt for opaque pthread_t type. + * condvar.c: Likewise. + * errno.c: Likewise. + * join.c: Likewise. + * mutex.c: Likewise. + * pthread.c: Likewise. + * signals.c: Likewise. + * specific.c: Likewise. + * restart.h: Likewise. + * queue.h: Likewise. + * Examples/ex3.c: Likewise. + * Examples/ex4.c: Likewise. + * sysdeps/pthread/pthread.h: Likewise. + + * pthread.c: Accumulate time for all threads in thread manager. + + * semaphore.c: Implement fallback implementation for architectures + sometimes missing compare-exchange operations. + + * cancel.c (pthread_cancel): Validate handle argument. + * join.c (pthread_join): Likewise. + (pthread_detach): Likewise. + * signals.c (pthread_kill): Likewise. + + * spinlock.h (acquire): Use __sched_yield not sched_yield. + + * queue.h (enqueue): Enqueue thread according to priority. + + * internals.c (struct pthread_start_args): New struct for passing + args to cloning function. + (struct _pthread): Rename to _pthread_descr_struct and adapt for + opaque pthread_t. + + * Examples/Makefile (clean): Pass -f option to rm. + + * sysdeps/i386/pt-machine.h: Add check for compare-exchange instruction + and define TEST_FOR_COMPARE_AND_SWAP. + * sysdeps/i386/i486/pt-machine.h: Removed. + + * sysdeps/unix/sysv/linux/local_lim.h (PTHREAD_THREADS_MAX): Increase + to 1024. + +1997-04-04 16:38 Ulrich Drepper <drepper@cygnus.com> + + * restart.h (suspend): Clear p_signal before suspending. + (suspend_with_cancellation): Likewise. + Patch by Xavier Leroy <Xavier.Leroy@inria.fr>. + + * weaks.c: Make __pthread_key_create return 1. + * sysdeps/pthread/libc-lock.h: Define __libc_key_create, + __libc_getspecific, __libc_setspecific, and __libc_key_t. + * sysdeps/pthread/stdio-lock.h: Don't care for implementation not + using libio. + +1997-03-19 15:13 Miguel de Icaza <miguel@nuclecu.unam.mx> + + * sysdeps/sparc/pt-machine (RELEASE): Fix. + +1997-03-01 07:55 Geoff Keating <geoffk@ozemail.com.au> + + * sysdeps/powerpc/Implies: Added. + * sysdeps/powerpc/pt-machine.h: Added. + * sysdeps/powerpc/semaphorebits.h: Added. + +1997-01-22 01:22 Ulrich Drepper <drepper@cygnus.com> + + * pthread.c (__pthread_initial_thread): Correct + initializer. + (__pthread_manager_thread): Likewise. + Reported by Andreas Jaeger. + +1997-01-18 22:15 Richard Henderson <rth@tamu.edu> + + Since sigset_t no longer fits in a register, we can't pass in the + thread's initial mask so easily. Take this opportunity to simplify + the clone implementation by only accepting a single void* argument. + + * manager.c (__pthread_manager): Put thread vitals in the thread + struct instead of as arguments through clone. + (pthread_start_thread): Look for them there. + * internals.h (struct _pthread): Add p_initial_fn, + p_initial_fn_arg, p_initial_mask. Fix __pthread_manager proto. + * pthread.c (pthread_initialize_manager): Revise clone invocation. diff --git a/linuxthreads/Changes b/linuxthreads/Changes new file mode 100644 index 0000000000..b213f36c57 --- /dev/null +++ b/linuxthreads/Changes @@ -0,0 +1,85 @@ +Release 0.9: +- more ports (SH, IA-64, s390) +- many bug fixes +- timed sync object wait functions +- barrier implementation +- spinlocks implementation +- thread register on x86 +- variable stack size and position on some platforms + +Release 0.8: +(ehmm, forgot to update, don't know anymore) + +Release 0.7: +- Destructors for thread-specific data now conform to the POSIX semantics + (call destructors again if non-NULL TSD remains after a round of + destruction). +- Implemented thread-specific data as a sparse array, allows more TSD keys + and smaller thread descriptors (Ulrich Drepper). +- Added "error checking" mutexes. +- Protect against multiple sigwait() on the same signals. +- Simplified implementation of semaphores when compare_and_swap is + not available. +- Fixed bug in fork() where stdin was closed if fork() was called before + the first pthread_create(). +- Fixed bug in the gethostby*_r functions (bad result if null bytes + in addresses). +- Typos in manual pages corrected. +- First cut at a PowerPC port (not working yet, runs into problems + with gcc and with the C library). + +Release 0.6: +- Validation of thread identifiers: no more crashes when operating on + a thread that has exited (based on Pavel Krauz's ideas). +- Added fallback implementation of semaphores for the 386 and the + Sparc. +- Fixed a bug in signal handling causing false restarts of suspended + threads. +- Fixed a bug in realtime scheduling causing all threads to have + default scheduling on Ix86 with libc5. +- With realtime scheduling, unlocking a mutex now restarts the + highest priority thread waiting on the mutex, not the + first-suspended thread (Richard Neitzel). +- Timing a process now returns cumulative times for all threads, not + just times for the initial thread (suggested by Wolfram Gloger). +- Cleaned up name space (internal defs prefixed by __, weak aliases + for non-portable extensions). +- MIPS port (contributed by Ralf Baechle). + +Release 0.5: +- Signal-safe semaphores a la POSIX 1003.1b added. +- Locking bug in pthread_mutex_trylock over recursive mutexes fixed. +- Race conditions in thread cancellation fixed. +- Sparc port (contributed by Miguel de Icaza). +- Support for getpwnam_r and getpwuid_r. +- Added pthread_kill_other_threads_np to be used in conjunction with + exec*(). + +Release 0.4: +- Manual pages for all functions. +- Synchronization bug causing accumulation of zombie processes fixed. +- Race condition in pthread_cond_timedwait fixed. +- Recursive mutexes are back by popular demand. +- Partial support for realtime scheduling (initiated by Richard Neitzel). +- pthread.h cleaned up a lot: now C++ compatible, added missing "const" + qualifiers, added short documentation, put to GNU libc standards + for name space pollution (Ulrich Drepper). +- Motorola 68k port (contributed by Andreas Schwab). +- Interaction with fork(2) cleaned up a lot. + +Release 0.3: +- Thread creation and reclaimation now performed by a centralized + "thread manager" thread. +- Removed recursive mutexes to make regular mutexes more efficient. +- Now available as a shared library (contributed by Richard Henderson). +- Alpha port (contributed by Richard Henderson). +- Fixed many small discrepancies with Posix 1003.1c. +- Put under the LGPL instead of the GPL. + +Release 0.2: +- Reentrant libc functions (adapted from libc 5.3.9 by Peeter Joot) +- pthread_cond_wait did not reacquire the mutex correctly on return +- More efficient pthread_cond_broadcast + +Release 0.1: +- First public release diff --git a/linuxthreads/Examples/Makefile b/linuxthreads/Examples/Makefile new file mode 100644 index 0000000000..c68b3676a4 --- /dev/null +++ b/linuxthreads/Examples/Makefile @@ -0,0 +1,15 @@ +CC=gcc +CFLAGS=-g -O -Wall -I.. -D_REENTRANT +LIBPTHREAD=../libpthread.a + +PROGS=ex1 ex2 ex3 ex4 ex5 proxy + +all: $(PROGS) + +.c: + $(CC) $(CFLAGS) -o $* $*.c $(LIBPTHREAD) + +$(PROGS): + +clean: + rm -f $(PROGS) diff --git a/linuxthreads/Examples/ex1.c b/linuxthreads/Examples/ex1.c new file mode 100644 index 0000000000..29138cf761 --- /dev/null +++ b/linuxthreads/Examples/ex1.c @@ -0,0 +1,42 @@ +/* Creates two threads, one printing 10000 "a"s, the other printing + 10000 "b"s. + Illustrates: thread creation, thread joining. */ + +#include <stddef.h> +#include <stdio.h> +#include <unistd.h> +#include "pthread.h" + +static void * +process (void *arg) +{ + int i; + fprintf (stderr, "Starting process %s\n", (char *) arg); + for (i = 0; i < 10000; i++) + { + write (1, (char *) arg, 1); + } + return NULL; +} + +int +main (void) +{ + int retcode; + pthread_t th_a, th_b; + void *retval; + + retcode = pthread_create (&th_a, NULL, process, (void *) "a"); + if (retcode != 0) + fprintf (stderr, "create a failed %d\n", retcode); + retcode = pthread_create (&th_b, NULL, process, (void *) "b"); + if (retcode != 0) + fprintf (stderr, "create b failed %d\n", retcode); + retcode = pthread_join (th_a, &retval); + if (retcode != 0) + fprintf (stderr, "join a failed %d\n", retcode); + retcode = pthread_join (th_b, &retval); + if (retcode != 0) + fprintf (stderr, "join b failed %d\n", retcode); + return 0; +} diff --git a/linuxthreads/Examples/ex10.c b/linuxthreads/Examples/ex10.c new file mode 100644 index 0000000000..f3ad517283 --- /dev/null +++ b/linuxthreads/Examples/ex10.c @@ -0,0 +1,108 @@ +/* Tests for pthread_mutex_timedlock function. + Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc. + Contributed by Kaz Kylheku <kaz@ashi.footprints.net>, 2000. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <errno.h> +#include <error.h> +#include <stdio.h> +#include <stdlib.h> +#include <pthread.h> +#include <time.h> + +#define NUM_THREADS 10 +#define NUM_ITERS 50 +#define TIMEOUT_NS 100000000L + +static void *thread (void *) __attribute__ ((__noreturn__)); +static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + +int +main (void) +{ + pthread_t th; + int i; + + for (i = 0; i < NUM_THREADS; i++) + { + if (pthread_create (&th, NULL, thread, NULL) != 0) + error (EXIT_FAILURE, 0, "cannot create thread"); + } + + (void) thread (NULL); + /* notreached */ + return 0; +} + + +static void * +thread (void *arg) +{ + int i; + pthread_t self = pthread_self (); + static int linecount; /* protected by flockfile(stdout) */ + + for (i = 0; i < NUM_ITERS; i++) + { + struct timespec ts; + + for (;;) + { + int err; + + clock_gettime (CLOCK_REALTIME, &ts); + + ts.tv_nsec += TIMEOUT_NS; + + if (ts.tv_nsec >= 1000000000L) { + ts.tv_sec++; + ts.tv_nsec -= 1000000000L; + } + + switch ((err = pthread_mutex_timedlock (&mutex, &ts))) + { + case 0: + flockfile (stdout); + printf ("%04d: thread %lu got mutex\n", ++linecount, + (unsigned long) self); + funlockfile (stdout); + break; + case ETIMEDOUT: + flockfile (stdout); + printf ("%04d: thread %lu timed out on mutex\n", ++linecount, + (unsigned long) self); + funlockfile (stdout); + continue; + default: + error (EXIT_FAILURE, err, "pthread_mutex_timedlock failure"); + } + break; + } + + ts.tv_sec = 0; + ts.tv_nsec = TIMEOUT_NS; + nanosleep (&ts, NULL); + + flockfile (stdout); + printf ("%04d: thread %lu releasing mutex\n", ++linecount, + (unsigned long) self); + funlockfile (stdout); + pthread_mutex_unlock (&mutex); + } + + pthread_exit (NULL); +} diff --git a/linuxthreads/Examples/ex11.c b/linuxthreads/Examples/ex11.c new file mode 100644 index 0000000000..abb5b5385a --- /dev/null +++ b/linuxthreads/Examples/ex11.c @@ -0,0 +1,154 @@ +/* Test program for timedout read/write lock functions. + Copyright (C) 2000 Free Software Foundation, Inc. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2000. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <errno.h> +#include <error.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <unistd.h> + + +#define NWRITERS 15 +#define WRITETRIES 10 +#define NREADERS 15 +#define READTRIES 15 + +#define TIMEOUT 1000000 +#define DELAY 1000000 + +static pthread_rwlock_t lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP; + + +static void * +writer_thread (void *nr) +{ + struct timespec ts; + struct timespec delay; + int n; + + ts.tv_sec = 0; + ts.tv_nsec = TIMEOUT; + + delay.tv_sec = 0; + delay.tv_nsec = DELAY; + + for (n = 0; n < WRITETRIES; ++n) + { + do + { + clock_gettime (CLOCK_REALTIME, &ts); + + ts.tv_nsec += 2 * TIMEOUT; + + printf ("writer thread %ld tries again\n", (long int) nr); + } + //while (pthread_rwlock_wrlock (&lock), 0); + while (pthread_rwlock_timedwrlock (&lock, &ts) == ETIMEDOUT); + + printf ("writer thread %ld succeeded\n", (long int) nr); + + nanosleep (&delay, NULL); + + pthread_rwlock_unlock (&lock); + + printf ("writer thread %ld released\n", (long int) nr); + } + + return NULL; +} + + +static void * +reader_thread (void *nr) +{ + struct timespec ts; + struct timespec delay; + int n; + + delay.tv_sec = 0; + delay.tv_nsec = DELAY; + + for (n = 0; n < READTRIES; ++n) + { + do + { + clock_gettime (CLOCK_REALTIME, &ts); + + ts.tv_nsec += TIMEOUT; + + printf ("reader thread %ld tries again\n", (long int) nr); + } + //while (pthread_rwlock_rdlock (&lock), 0); + while (pthread_rwlock_timedrdlock (&lock, &ts) == ETIMEDOUT); + + printf ("reader thread %ld succeeded\n", (long int) nr); + + nanosleep (&delay, NULL); + + pthread_rwlock_unlock (&lock); + + printf ("reader thread %ld released\n", (long int) nr); + } + + return NULL; +} + + +int +main (void) +{ + pthread_t thwr[NWRITERS]; + pthread_t thrd[NREADERS]; + int n; + void *res; + + /* Make standard error the same as standard output. */ + dup2 (1, 2); + + /* Make sure we see all message, even those on stdout. */ + setvbuf (stdout, NULL, _IONBF, 0); + + for (n = 0; n < NWRITERS; ++n) + { + int err = pthread_create (&thwr[n], NULL, writer_thread, + (void *) (long int) n); + + if (err != 0) + error (EXIT_FAILURE, err, "cannot create writer thread"); + } + + for (n = 0; n < NREADERS; ++n) + { + int err = pthread_create (&thrd[n], NULL, reader_thread, + (void *) (long int) n); + + if (err != 0) + error (EXIT_FAILURE, err, "cannot create reader thread"); + } + + /* Wait for all the threads. */ + for (n = 0; n < NWRITERS; ++n) + pthread_join (thwr[n], &res); + for (n = 0; n < NREADERS; ++n) + pthread_join (thrd[n], &res); + + return 0; +} diff --git a/linuxthreads/Examples/ex12.c b/linuxthreads/Examples/ex12.c new file mode 100644 index 0000000000..e986fec97f --- /dev/null +++ b/linuxthreads/Examples/ex12.c @@ -0,0 +1,47 @@ +/* Variant of ex6, but this time we use pthread_exit (). */ +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <pthread.h> +#include <unistd.h> + +static void * +__attribute__ ((noreturn)) +test_thread (void *v_param) +{ + pthread_exit (NULL); +} + +int +main (void) +{ + unsigned long count; + + setvbuf (stdout, NULL, _IONBF, 0); + + for (count = 0; count < 2000; ++count) + { + pthread_t thread; + int status; + + status = pthread_create (&thread, NULL, test_thread, NULL); + if (status != 0) + { + printf ("status = %d, count = %lu: %s\n", status, count, + strerror (errno)); + return 1; + } + else + { + printf ("count = %lu\n", count); + } + /* pthread_detach (thread); */ + if (pthread_join (thread, NULL) != 0) + { + printf ("join failed, count %lu\n", count); + return 2; + } + usleep (10); + } + return 0; +} diff --git a/linuxthreads/Examples/ex13.c b/linuxthreads/Examples/ex13.c new file mode 100644 index 0000000000..14add6c773 --- /dev/null +++ b/linuxthreads/Examples/ex13.c @@ -0,0 +1,112 @@ +/* Test for Pthreads/mutexes. + Copyright (C) 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Kurt Garloff <garloff@suse.de>, 2000. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +static void *thread_start (void *ptr) __attribute__ ((__noreturn__)); + + +struct thr_ctrl +{ + pthread_mutex_t mutex; + pthread_cond_t cond; + int retval; +}; + +static void +dump_mut (pthread_mutex_t * mut) +{ + size_t i; + for (i = 0; i < sizeof (*mut); i++) + printf (" %02x", *((unsigned char *) mut + i)); + printf ("\n"); +}; + +/* Helper, the opposite of pthread_cond_wait (cond, mut). */ +static void +pthr_cond_signal_mutex (pthread_cond_t * cond, pthread_mutex_t * mut) +{ + int err; + err = pthread_mutex_lock (mut); + if (err) + printf ("mutex_lock : %s\n", strerror (err)); + err = pthread_cond_signal (cond); + if (err) + printf ("cond_signal : %s\n", strerror (err)); + err = pthread_mutex_unlock (mut); + if (err) + printf ("mutex_unlock: %s\n", strerror (err)); +} + +static void * +thread_start (void *ptr) +{ + struct thr_ctrl *tc = ptr; + /* Do initialization. */ + /* ... */ + /* Signal that we are ready. */ + pthr_cond_signal_mutex (&tc->cond, &tc->mutex); + sleep (2); + pthr_cond_signal_mutex (&tc->cond, &tc->mutex); + tc->retval = 0; + pthread_exit (&tc->retval); +} + +int +main (void) +{ + struct thr_ctrl threadctrl; + pthread_t thread; + int err; + void *res = &threadctrl.retval; + pthread_mutexattr_t mutattr; + pthread_mutexattr_init (&mutattr); + pthread_mutex_init (&threadctrl.mutex, &mutattr); + pthread_cond_init (&threadctrl.cond, NULL); + err = pthread_mutex_lock (&threadctrl.mutex); + if (err) + printf ("mutex_lock : %s\n", strerror (err)); + dump_mut (&threadctrl.mutex); + pthread_create (&thread, NULL, thread_start, &threadctrl); + /* Wait until it's ready. */ + err = pthread_cond_wait (&threadctrl.cond, &threadctrl.mutex); + if (err) + printf ("cond_wait : %s\n", strerror (err)); + /* Now, we should have acquired the mutex again! */ + dump_mut (&threadctrl.mutex); + sleep (1); + dump_mut (&threadctrl.mutex); + err = pthread_cond_wait (&threadctrl.cond, &threadctrl.mutex); + if (err) + { + printf ("cond_wait : %s\n", strerror (err)); + printf ("ERROR\n"); + abort (); + }; + dump_mut (&threadctrl.mutex); + pthread_join (thread, &res); + printf ("OK\n"); + return 0; +} diff --git a/linuxthreads/Examples/ex14.c b/linuxthreads/Examples/ex14.c new file mode 100644 index 0000000000..406e03f346 --- /dev/null +++ b/linuxthreads/Examples/ex14.c @@ -0,0 +1,133 @@ +/* Test of POSIX barriers. */ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define NTHREADS 20 + +#define ROUNDS 20 + +static pthread_barrier_t barriers[NTHREADS]; + +static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; +static int counters[NTHREADS]; +static int serial[NTHREADS]; + +static void * +worker (void *arg) +{ + void *result = NULL; + int nr = (long int) arg; + int i; + + for (i = 0; i < ROUNDS; ++i) + { + int j; + int retval; + + if (nr == 0) + { + memset (counters, '\0', sizeof (counters)); + memset (serial, '\0', sizeof (serial)); + } + + retval = pthread_barrier_wait (&barriers[NTHREADS - 1]); + if (retval != 0 && retval != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("thread %d failed to wait for all the others\n", nr); + result = (void *) 1; + } + + for (j = nr; j < NTHREADS; ++j) + { + /* Increment the counter for this round. */ + pthread_mutex_lock (&lock); + ++counters[j]; + pthread_mutex_unlock (&lock); + + /* Wait for the rest. */ + retval = pthread_barrier_wait (&barriers[j]); + + /* Test the result. */ + if (nr == 0 && counters[j] != j + 1) + { + printf ("barrier in round %d released but count is %d\n", + j, counters[j]); + result = (void *) 1; + } + + if (retval != 0) + { + if (retval != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("thread %d in round %d has nonzero return value != PTHREAD_BARRIER_SERIAL_THREAD\n", + nr, j); + result = (void *) 1; + } + else + { + pthread_mutex_lock (&lock); + ++serial[j]; + pthread_mutex_unlock (&lock); + } + } + + /* Wait for the rest again. */ + retval = pthread_barrier_wait (&barriers[j]); + + /* Now we can check whether exactly one thread was serializing. */ + if (nr == 0 && serial[j] != 1) + { + printf ("not exactly one serial thread in round %d\n", j); + result = (void *) 1; + } + } + } + + return result; +} + + +#define TEST_FUNCTION do_test () +#define TIMEOUT 60 +static int +do_test (void) +{ + pthread_t threads[NTHREADS]; + int i; + void *res; + int result = 0; + + /* Initialized the barrier variables. */ + for (i = 0; i < NTHREADS; ++i) + if (pthread_barrier_init (&barriers[i], NULL, i + 1) != 0) + { + printf ("Failed to initialize barrier %d\n", i); + exit (1); + } + + /* Start the threads. */ + for (i = 0; i < NTHREADS; ++i) + if (pthread_create (&threads[i], NULL, worker, (void *) (long int) i) != 0) + { + printf ("Failed to start thread %d\n", i); + exit (1); + } + + /* And wait for them. */ + for (i = 0; i < NTHREADS; ++i) + if (pthread_join (threads[i], &res) != 0 || res != NULL) + { + printf ("thread %d returned a failure\n", i); + result = 1; + } + + if (result == 0) + puts ("all OK"); + + return result; +} + +#include "../test-skeleton.c" diff --git a/linuxthreads/Examples/ex15.c b/linuxthreads/Examples/ex15.c new file mode 100644 index 0000000000..e953b231d7 --- /dev/null +++ b/linuxthreads/Examples/ex15.c @@ -0,0 +1,58 @@ +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <pthread.h> +#include <unistd.h> + +static void *worker (void *dummy) __attribute__ ((__noreturn__)); + +static void * +worker (void *dummy) +{ + exit (26); +} + +#define TEST_FUNCTION do_test () +#define TIMEOUT 10 +static int +do_test (void) +{ + pthread_t th; + pid_t pid; + int status; + + switch ((pid = fork ())) + { + case -1: + puts ("Could not fork"); + exit (1); + case 0: + if (pthread_create(&th, NULL, worker, NULL) != 0) + { + puts ("Failed to start thread"); + exit (1); + } + for (;;); + exit (1); + default: + break; + } + + if (waitpid (pid, &status, 0) != pid) + { + puts ("waitpid failed"); + exit (1); + } + + if (!WIFEXITED (status) || WEXITSTATUS (status) != 26) + { + printf ("Wrong exit code %d\n", status); + exit (1); + } + + puts ("All OK"); + return 0; +} + +#include "../../test-skeleton.c" diff --git a/linuxthreads/Examples/ex16.c b/linuxthreads/Examples/ex16.c new file mode 100644 index 0000000000..6509ae4515 --- /dev/null +++ b/linuxthreads/Examples/ex16.c @@ -0,0 +1,26 @@ +/* Tst case by Jakub Jelinek <jakub@redhat.com>. */ +#include <stdlib.h> +#include <unistd.h> +#include <pthread.h> + +static void * +task (void *p) +{ + sleep (30); + return NULL; +} + +int +main (void) +{ + pthread_t t; + int status; + + status = pthread_create (&t, NULL, task, NULL); + if (status) + exit (status); + + status = pthread_detach (t); + pthread_kill_other_threads_np (); + return status; +} diff --git a/linuxthreads/Examples/ex17.c b/linuxthreads/Examples/ex17.c new file mode 100644 index 0000000000..1bc09a5bda --- /dev/null +++ b/linuxthreads/Examples/ex17.c @@ -0,0 +1,112 @@ +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <pthread.h> +#include <unistd.h> +#include <limits.h> +#include <sys/mman.h> + +static pthread_mutex_t synch = PTHREAD_MUTEX_INITIALIZER; + +static void * +test_thread (void *v_param) +{ + pthread_mutex_lock (&synch); + return NULL; +} + +#define STACKSIZE 0x100000 + +int +main (void) +{ + pthread_t thread; + pthread_attr_t attr; + int status; + void *stack, *stack2; + size_t stacksize; + + pthread_attr_init (&attr); + stack = mmap (NULL, STACKSIZE, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + + if (stack == MAP_FAILED) + { + perror ("mmap failed"); + return 1; + } + + status = pthread_attr_setstack (&attr, stack, STACKSIZE); + if (status != 0) + { + printf ("pthread_attr_setstack failed: %s\n", strerror (status)); + return 1; + } + + status = pthread_attr_getstack (&attr, &stack2, &stacksize); + if (status != 0) + { + printf ("pthread_attr_getstack failed: %s\n", strerror (status)); + return 1; + } + + if (stack2 != stack || stacksize != STACKSIZE) + { + printf ("first pthread_attr_getstack returned different stack (%p,%zx)\n" + "than was set by setstack (%p,%x)\n", + stack2, stacksize, stack, STACKSIZE); + return 2; + } + + status = pthread_mutex_lock (&synch); + if (status != 0) + { + printf ("cannot get lock: %s\n", strerror (status)); + return 1; + } + + status = pthread_create (&thread, &attr, test_thread, NULL); + if (status != 0) + { + printf ("pthread_create failed: %s\n", strerror (status)); + return 1; + } + + status = pthread_getattr_np (thread, &attr); + if (status != 0) + { + printf ("pthread_getattr_np failed: %s\n", strerror (status)); + return 1; + } + + status = pthread_attr_getstack (&attr, &stack2, &stacksize); + if (status != 0) + { + printf ("pthread_attr_getstack failed: %s\n", strerror (status)); + return 1; + } + + if (stack2 != stack || stacksize != STACKSIZE) + { + printf ("second pthread_attr_getstack returned different stack (%p,%zx)\n" + "than was set by setstack (%p,%x)\n", + stack2, stacksize, stack, STACKSIZE); + return 3; + } + + status = pthread_mutex_unlock (&synch); + if (status != 0) + { + printf ("cannot release lock: %s\n", strerror (status)); + return 1; + } + + /* pthread_detach (thread); */ + if (pthread_join (thread, NULL) != 0) + { + printf ("join failed\n"); + return 1; + } + return 0; +} diff --git a/linuxthreads/Examples/ex18.c b/linuxthreads/Examples/ex18.c new file mode 100644 index 0000000000..283396bede --- /dev/null +++ b/linuxthreads/Examples/ex18.c @@ -0,0 +1,113 @@ +/* + * Beat up the pthread_key_create and pthread_key_delete + * functions. + */ + +#if 0 +#define CHATTY +#endif + +#include <stdio.h> +#include <errno.h> +#include <stdlib.h> +#include <pthread.h> +#include <unistd.h> + +const int beatup_iterations = 10000; +const int num_threads = 30; +const int max_keys = 500; + +struct key_list { + struct key_list *next; + pthread_key_t key; +}; + +struct key_list *key_list; +pthread_mutex_t key_lock = PTHREAD_MUTEX_INITIALIZER; + +/* + * Create a new key and put it at the tail of a linked list. + * If the linked list grows to a certain length, delete a key from the + * head of * the list. + */ + +static void +beat_up(void) +{ + struct key_list *new = malloc(sizeof *new); + struct key_list **iter, *old_key = 0; + int key_count = 0; + + if (new == 0) { + fprintf(stderr, "malloc failed\n"); + abort(); + } + + new->next = 0; + + if (pthread_key_create(&new->key, 0) != 0) { + fprintf(stderr, "pthread_key_create failed\n"); + abort(); + } + + if (pthread_getspecific(new->key) != 0) { + fprintf(stderr, "new pthread_key_t resolves to non-null value\n"); + abort(); + } + + pthread_setspecific(new->key, (void *) 1); + +#ifdef CHATTY + printf("created key\n"); +#endif + + pthread_mutex_lock(&key_lock); + + for (iter = &key_list; *iter != 0; iter = &(*iter)->next) + key_count++; + + *iter = new; + + if (key_count > max_keys) { + old_key = key_list; + key_list = key_list->next; + } + + pthread_mutex_unlock(&key_lock); + + if (old_key != 0) { +#ifdef CHATTY + printf("deleting key\n"); +#endif + pthread_key_delete(old_key->key); + } +} + +static void * +thread(void *arg) +{ + int i; + for (i = 0; i < beatup_iterations; i++) + beat_up(); + return 0; +} + +int +main(void) +{ + int i; + pthread_attr_t detached_thread; + + pthread_attr_init(&detached_thread); + pthread_attr_setdetachstate(&detached_thread, PTHREAD_CREATE_DETACHED); + + for (i = 0; i < num_threads; i++) { + pthread_t thread_id; + while (pthread_create(&thread_id, &detached_thread, thread, 0) == EAGAIN) { + /* let some threads die, so system can breathe. :) */ + sleep(1); + } + } + + pthread_exit(0); +} diff --git a/linuxthreads/Examples/ex2.c b/linuxthreads/Examples/ex2.c new file mode 100644 index 0000000000..f2556a4206 --- /dev/null +++ b/linuxthreads/Examples/ex2.c @@ -0,0 +1,124 @@ +/* The classic producer-consumer example. + Illustrates mutexes and conditions. + All integers between 0 and 9999 should be printed exactly twice, + once to the right of the arrow and once to the left. */ + +#include <stdio.h> +#include "pthread.h" + +#define BUFFER_SIZE 16 + +/* Circular buffer of integers. */ + +struct prodcons +{ + int buffer[BUFFER_SIZE]; /* the actual data */ + pthread_mutex_t lock; /* mutex ensuring exclusive access to buffer */ + int readpos, writepos; /* positions for reading and writing */ + pthread_cond_t notempty; /* signaled when buffer is not empty */ + pthread_cond_t notfull; /* signaled when buffer is not full */ +}; + +/* Initialize a buffer */ +static void +init (struct prodcons *b) +{ + pthread_mutex_init (&b->lock, NULL); + pthread_cond_init (&b->notempty, NULL); + pthread_cond_init (&b->notfull, NULL); + b->readpos = 0; + b->writepos = 0; +} + +/* Store an integer in the buffer */ +static void +put (struct prodcons *b, int data) +{ + pthread_mutex_lock (&b->lock); + /* Wait until buffer is not full */ + while ((b->writepos + 1) % BUFFER_SIZE == b->readpos) + { + pthread_cond_wait (&b->notfull, &b->lock); + /* pthread_cond_wait reacquired b->lock before returning */ + } + /* Write the data and advance write pointer */ + b->buffer[b->writepos] = data; + b->writepos++; + if (b->writepos >= BUFFER_SIZE) + b->writepos = 0; + /* Signal that the buffer is now not empty */ + pthread_cond_signal (&b->notempty); + pthread_mutex_unlock (&b->lock); +} + +/* Read and remove an integer from the buffer */ +static int +get (struct prodcons *b) +{ + int data; + pthread_mutex_lock (&b->lock); + /* Wait until buffer is not empty */ + while (b->writepos == b->readpos) + { + pthread_cond_wait (&b->notempty, &b->lock); + } + /* Read the data and advance read pointer */ + data = b->buffer[b->readpos]; + b->readpos++; + if (b->readpos >= BUFFER_SIZE) + b->readpos = 0; + /* Signal that the buffer is now not full */ + pthread_cond_signal (&b->notfull); + pthread_mutex_unlock (&b->lock); + return data; +} + +/* A test program: one thread inserts integers from 1 to 10000, + the other reads them and prints them. */ + +#define OVER (-1) + +struct prodcons buffer; + +static void * +producer (void *data) +{ + int n; + for (n = 0; n < 10000; n++) + { + printf ("%d --->\n", n); + put (&buffer, n); + } + put (&buffer, OVER); + return NULL; +} + +static void * +consumer (void *data) +{ + int d; + while (1) + { + d = get (&buffer); + if (d == OVER) + break; + printf ("---> %d\n", d); + } + return NULL; +} + +int +main (void) +{ + pthread_t th_a, th_b; + void *retval; + + init (&buffer); + /* Create the threads */ + pthread_create (&th_a, NULL, producer, 0); + pthread_create (&th_b, NULL, consumer, 0); + /* Wait until producer and consumer finish. */ + pthread_join (th_a, &retval); + pthread_join (th_b, &retval); + return 0; +} diff --git a/linuxthreads/Examples/ex3.c b/linuxthreads/Examples/ex3.c new file mode 100644 index 0000000000..b80b323a33 --- /dev/null +++ b/linuxthreads/Examples/ex3.c @@ -0,0 +1,152 @@ +/* Multi-thread searching. + Illustrates: thread cancellation, cleanup handlers. */ + +#include <errno.h> +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <sys/types.h> +#include <pthread.h> + +/* Defines the number of searching threads */ +#define NUM_THREADS 5 + +/* Function prototypes */ +void *search(void *); +void print_it(void *); + +/* Global variables */ +pthread_t threads[NUM_THREADS]; +pthread_mutex_t lock; +int tries; +volatile int started; + +int main(int argc, char ** argv) +{ + int i; + int pid; + + /* create a number to search for */ + pid = getpid(); + printf("Searching for the number = %d...\n", pid); + + /* Initialize the mutex lock */ + pthread_mutex_init(&lock, NULL); + + /* Create the searching threads */ + for (started=0; started<NUM_THREADS; started++) + pthread_create(&threads[started], NULL, search, (void *) (long int) pid); + + /* Wait for (join) all the searching threads */ + for (i=0; i<NUM_THREADS; i++) + pthread_join(threads[i], NULL); + + printf("It took %d tries to find the number.\n", tries); + + /* Exit the program */ + return 0; +} + +/* This is the cleanup function that is called + when the threads are cancelled */ + +void print_it(void *arg) +{ + int *try = (int *) arg; + pthread_t tid; + + /* Get the calling thread's ID */ + tid = pthread_self(); + + /* Print where the thread was in its search when it was cancelled */ + printf("Thread %lx was canceled on its %d try.\n", tid, *try); +} + +/* This is the search routine that is executed in each thread */ + +void *search(void *arg) +{ + int num = (long int) arg; + int i, j, ntries; + pthread_t tid; + + /* get the calling thread ID */ + tid = pthread_self(); + + /* use the thread ID to set the seed for the random number generator */ + /* Since srand and rand are not thread-safe, serialize with lock */ + + /* Try to lock the mutex lock -- + if locked, check to see if the thread has been cancelled + if not locked then continue */ + while (pthread_mutex_trylock(&lock) == EBUSY) + pthread_testcancel(); + + srand((int)tid); + i = rand() & 0xFFFFFF; + pthread_mutex_unlock(&lock); + ntries = 0; + + /* Set the cancellation parameters -- + - Enable thread cancellation + - Defer the action of the cancellation */ + + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); + pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL); + + while (started < NUM_THREADS) + sched_yield (); + + /* Push the cleanup routine (print_it) onto the thread + cleanup stack. This routine will be called when the + thread is cancelled. Also note that the pthread_cleanup_push + call must have a matching pthread_cleanup_pop call. The + push and pop calls MUST be at the same lexical level + within the code */ + + /* Pass address of `ntries' since the current value of `ntries' is not + the one we want to use in the cleanup function */ + + pthread_cleanup_push(print_it, (void *)&ntries); + + /* Loop forever */ + while (1) { + i = (i + 1) & 0xFFFFFF; + ntries++; + + /* Does the random number match the target number? */ + if (num == i) { + /* Try to lock the mutex lock -- + if locked, check to see if the thread has been cancelled + if not locked then continue */ + while (pthread_mutex_trylock(&lock) == EBUSY) + pthread_testcancel(); + + /* Set the global variable for the number of tries */ + tries = ntries; + printf("Thread %lx found the number!\n", tid); + + /* Cancel all the other threads */ + for (j=0; j<NUM_THREADS; j++) + if (threads[j] != tid) pthread_cancel(threads[j]); + + /* Break out of the while loop */ + break; + } + + /* Every 100 tries check to see if the thread has been cancelled. */ + if (ntries % 100 == 0) { + pthread_testcancel(); + } + } + + /* The only way we can get here is when the thread breaks out + of the while loop. In this case the thread that makes it here + has found the number we are looking for and does not need to run + the thread cleanup function. This is why the pthread_cleanup_pop + function is called with a 0 argument; this will pop the cleanup + function off the stack without executing it */ + + pthread_cleanup_pop(0); + return((void *)0); +} diff --git a/linuxthreads/Examples/ex4.c b/linuxthreads/Examples/ex4.c new file mode 100644 index 0000000000..5c8b929e22 --- /dev/null +++ b/linuxthreads/Examples/ex4.c @@ -0,0 +1,115 @@ +/* Making a library function that uses static variables thread-safe. + Illustrates: thread-specific data, pthread_once(). */ + +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <pthread.h> + +/* This is a typical example of a library function that uses + static variables to accumulate results between calls. + Here, it just returns the concatenation of all string arguments + that were given to it. */ + +#if 0 + +char * +str_accumulate (char *s) +{ + static char accu[1024] = { 0 }; + strcat (accu, s); + return accu; +} + +#endif + +/* Of course, this cannot be used in a multi-threaded program + because all threads store "accu" at the same location. + So, we'll use thread-specific data to have a different "accu" + for each thread. */ + +/* Key identifying the thread-specific data */ +static pthread_key_t str_key; +/* "Once" variable ensuring that the key for str_alloc will be allocated + exactly once. */ +static pthread_once_t str_alloc_key_once = PTHREAD_ONCE_INIT; + +/* Forward functions */ +static void str_alloc_key (void); +static void str_alloc_destroy_accu (void *accu); + +/* Thread-safe version of str_accumulate */ + +static char * +str_accumulate (const char *s) +{ + char *accu; + + /* Make sure the key is allocated */ + pthread_once (&str_alloc_key_once, str_alloc_key); + /* Get the thread-specific data associated with the key */ + accu = (char *) pthread_getspecific (str_key); + /* It's initially NULL, meaning that we must allocate the buffer first. */ + if (accu == NULL) + { + accu = malloc (1024); + if (accu == NULL) + return NULL; + accu[0] = 0; + /* Store the buffer pointer in the thread-specific data. */ + pthread_setspecific (str_key, (void *) accu); + printf ("Thread %lx: allocating buffer at %p\n", pthread_self (), accu); + } + /* Now we can use accu just as in the non thread-safe code. */ + strcat (accu, s); + return accu; +} + +/* Function to allocate the key for str_alloc thread-specific data. */ + +static void +str_alloc_key (void) +{ + pthread_key_create (&str_key, str_alloc_destroy_accu); + printf ("Thread %lx: allocated key %d\n", pthread_self (), str_key); +} + +/* Function to free the buffer when the thread exits. */ +/* Called only when the thread-specific data is not NULL. */ + +static void +str_alloc_destroy_accu (void *accu) +{ + printf ("Thread %lx: freeing buffer at %p\n", pthread_self (), accu); + free (accu); +} + +/* Test program */ + +static void * +process (void *arg) +{ + char *res; + res = str_accumulate ("Result of "); + res = str_accumulate ((char *) arg); + res = str_accumulate (" thread"); + printf ("Thread %lx: \"%s\"\n", pthread_self (), res); + return NULL; +} + +int +main (int argc, char **argv) +{ + char *res; + pthread_t th1, th2; + + res = str_accumulate ("Result of "); + pthread_create (&th1, NULL, process, (void *) "first"); + pthread_create (&th2, NULL, process, (void *) "second"); + res = str_accumulate ("initial thread"); + printf ("Thread %lx: \"%s\"\n", pthread_self (), res); + pthread_join (th1, NULL); + pthread_join (th2, NULL); + return 0; +} diff --git a/linuxthreads/Examples/ex5.c b/linuxthreads/Examples/ex5.c new file mode 100644 index 0000000000..d39d487603 --- /dev/null +++ b/linuxthreads/Examples/ex5.c @@ -0,0 +1,114 @@ +/* The classic producer-consumer example, implemented with semaphores. + All integers between 0 and 9999 should be printed exactly twice, + once to the right of the arrow and once to the left. */ + +#include <stdio.h> +#include "pthread.h" +#include "semaphore.h" + +#define BUFFER_SIZE 16 + +/* Circular buffer of integers. */ + +struct prodcons +{ + int buffer[BUFFER_SIZE]; /* the actual data */ + int readpos, writepos; /* positions for reading and writing */ + sem_t sem_read; /* number of elements available for reading */ + sem_t sem_write; /* number of locations available for writing */ +}; + +/* Initialize a buffer */ + +static void +init (struct prodcons *b) +{ + sem_init (&b->sem_write, 0, BUFFER_SIZE - 1); + sem_init (&b->sem_read, 0, 0); + b->readpos = 0; + b->writepos = 0; +} + +/* Store an integer in the buffer */ + +static void +put (struct prodcons *b, int data) +{ + /* Wait until buffer is not full */ + sem_wait (&b->sem_write); + /* Write the data and advance write pointer */ + b->buffer[b->writepos] = data; + b->writepos++; + if (b->writepos >= BUFFER_SIZE) + b->writepos = 0; + /* Signal that the buffer contains one more element for reading */ + sem_post (&b->sem_read); +} + +/* Read and remove an integer from the buffer */ + +static int +get (struct prodcons *b) +{ + int data; + /* Wait until buffer is not empty */ + sem_wait (&b->sem_read); + /* Read the data and advance read pointer */ + data = b->buffer[b->readpos]; + b->readpos++; + if (b->readpos >= BUFFER_SIZE) + b->readpos = 0; + /* Signal that the buffer has now one more location for writing */ + sem_post (&b->sem_write); + return data; +} + +/* A test program: one thread inserts integers from 1 to 10000, + the other reads them and prints them. */ + +#define OVER (-1) + +struct prodcons buffer; + +static void * +producer (void *data) +{ + int n; + for (n = 0; n < 10000; n++) + { + printf ("%d --->\n", n); + put (&buffer, n); + } + put (&buffer, OVER); + return NULL; +} + +static void * +consumer (void *data) +{ + int d; + while (1) + { + d = get (&buffer); + if (d == OVER) + break; + printf ("---> %d\n", d); + } + return NULL; +} + +int +main (void) +{ + pthread_t th_a, th_b; + void *retval; + + init (&buffer); + /* Create the threads */ + pthread_create (&th_a, NULL, producer, 0); + pthread_create (&th_b, NULL, consumer, 0); + /* Wait until producer and consumer finish. */ + pthread_join (th_a, &retval); + pthread_join (th_b, &retval); + return 0; +} diff --git a/linuxthreads/Examples/ex6.c b/linuxthreads/Examples/ex6.c new file mode 100644 index 0000000000..9a0266828b --- /dev/null +++ b/linuxthreads/Examples/ex6.c @@ -0,0 +1,46 @@ +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <pthread.h> +#include <unistd.h> + +static void * +test_thread (void *v_param) +{ + return NULL; +} + +int +main (void) +{ + unsigned long count; + + setvbuf (stdout, NULL, _IONBF, 0); + + for (count = 0; count < 2000; ++count) + { + pthread_t thread; + int status; + + status = pthread_create (&thread, NULL, test_thread, NULL); + if (status != 0) + { + printf ("status = %d, count = %lu: %s\n", status, count, + strerror (errno)); + return 1; + } + else + { + printf ("count = %lu\n", count); + } + /* pthread_detach (thread); */ + int err = pthread_join (thread, NULL); + if (err != 0) + { + printf ("join failed (%s), count %lu\n", strerror (err), count); + return 2; + } + usleep (10); + } + return 0; +} diff --git a/linuxthreads/Examples/ex7.c b/linuxthreads/Examples/ex7.c new file mode 100644 index 0000000000..d9db33c5cd --- /dev/null +++ b/linuxthreads/Examples/ex7.c @@ -0,0 +1,45 @@ +/* This is a test of the special shutdown that occurs + when all threads, including the main one, call + pthread_exit(). It demonstrates that atexit + handlers are properly called, and that the + output is properly flushed even when stdout is + redirected to a file, and therefore fully buffered. */ + +#include <stdio.h> +#include <stdlib.h> +#include <pthread.h> + +#define NTHREADS 20 /* number of threads */ + +static void * +thread (void *arg) +{ + printf ("thread terminating\n"); + return 0; +} + +static void +cleanup (void) +{ + printf ("atexit handler called\n"); +} + +int +main (void) +{ + int i; + + atexit (cleanup); + + for (i = 0; i < NTHREADS; i++) + { + pthread_t id; + if (pthread_create (&id, 0, thread, 0) != 0) + { + fprintf (stderr, "pthread_create failed\n"); + abort (); + } + } + + pthread_exit (0); +} diff --git a/linuxthreads/Examples/ex8.c b/linuxthreads/Examples/ex8.c new file mode 100644 index 0000000000..bda81b9c61 --- /dev/null +++ b/linuxthreads/Examples/ex8.c @@ -0,0 +1,101 @@ +/* Tests for fork in multi-threaded environment. + Copyright (C) 2000 Free Software Foundation, Inc. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 2000. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <errno.h> +#include <error.h> +#include <stdlib.h> +#include <pthread.h> +#include <unistd.h> +#include <sys/wait.h> + +enum +{ + PREPARE_BIT = 1, + PARENT_BIT = 2, + CHILD_BIT = 4 +}; + +static int var; + +static void +prepare (void) +{ + var |= PREPARE_BIT; +} + +static void +parent (void) +{ + var |= PARENT_BIT; +} + +static void +child (void) +{ + var |= CHILD_BIT; +} + + +static void *thread (void *arg); + + +int +main (void) +{ + pthread_t th; + void *res; + + pthread_atfork (prepare, parent, child); + + if (pthread_create (&th, NULL, thread, NULL) != 0) + error (EXIT_FAILURE, 0, "cannot create thread"); + + pthread_join (th, &res); + + return (int) (long int) res; +} + + +static void * +thread (void *arg) +{ + int status; + pid_t pid; + + pid = fork (); + if (pid == 0) + { + /* We check whether the `prepare' and `child' function ran. */ + exit (var != (PREPARE_BIT | CHILD_BIT)); + } + else if (pid == (pid_t) -1) + error (EXIT_FAILURE, errno, "cannot fork"); + + if (waitpid (pid, &status, 0) != pid) + error (EXIT_FAILURE, errno, "wrong child"); + + if (WTERMSIG (status) != 0) + error (EXIT_FAILURE, 0, "Child terminated incorrectly"); + status = WEXITSTATUS (status); + + if (status == 0) + status = var != (PREPARE_BIT | PARENT_BIT); + + return (void *) (long int) status; +} diff --git a/linuxthreads/Examples/ex9.c b/linuxthreads/Examples/ex9.c new file mode 100644 index 0000000000..3c8b8142e1 --- /dev/null +++ b/linuxthreads/Examples/ex9.c @@ -0,0 +1,98 @@ +/* Tests for pthread_barrier_* functions. + Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc. + Contributed by Kaz Kylheku <kaz@ashi.footprints.net>, 2000. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <errno.h> +#include <error.h> +#include <stdio.h> +#include <stdlib.h> +#include <pthread.h> + +#define NUM_THREADS 10 +#define NUM_ITERS 500 + +static void *thread (void *) __attribute__ ((__noreturn__)); +static pthread_barrier_t barrier; + +int +main (void) +{ + pthread_t thread_list[NUM_THREADS]; + int i; + + if (pthread_barrier_init (&barrier, NULL, NUM_THREADS + 1) != 0) + error (EXIT_FAILURE, 0, "cannot initialize barrier"); + + for (i = 0; i < NUM_THREADS; i++) + { + if (pthread_create (&thread_list[i], NULL, thread, NULL) != 0) + error (EXIT_FAILURE, 0, "cannot create thread"); + } + + (void) thread (NULL); + + for (i = 0; i < NUM_THREADS; i++) + { + pthread_join(thread_list[i], NULL); + } + + return 0; +} + + +static void * +thread (void *arg) +{ + int i; + pthread_t self = pthread_self (); + static pthread_t last_serial_thread; + static int linecount; /* protected by flockfile(stdout) */ + + for (i = 0; i < NUM_ITERS; i++) + { + switch (pthread_barrier_wait (&barrier)) + { + case 0: + flockfile (stdout); + printf ("%04d: non-serial thread %lu\n", ++linecount, + (unsigned long) self); + funlockfile (stdout); + break; + case PTHREAD_BARRIER_SERIAL_THREAD: + flockfile (stdout); + printf ("%04d: serial thread %lu\n", ++linecount, + (unsigned long) self); + funlockfile (stdout); + last_serial_thread = self; + break; + default: + /* Huh? */ + error (EXIT_FAILURE, 0, "unexpected return value from barrier wait"); + } + } + + if (pthread_equal (self, last_serial_thread)) + { + flockfile (stdout); + printf ("%04d: last serial thread %lu terminating process\n", + ++linecount, (unsigned long) self); + funlockfile (stdout); + } + + pthread_exit(NULL); +} diff --git a/linuxthreads/Examples/tststatic.c b/linuxthreads/Examples/tststatic.c new file mode 100644 index 0000000000..421011a3c4 --- /dev/null +++ b/linuxthreads/Examples/tststatic.c @@ -0,0 +1 @@ +#include "ex1.c" diff --git a/linuxthreads/FAQ.html b/linuxthreads/FAQ.html new file mode 100644 index 0000000000..21be33ec4c --- /dev/null +++ b/linuxthreads/FAQ.html @@ -0,0 +1,1039 @@ +<HTML> +<HEAD> +<TITLE>LinuxThreads Frequently Asked Questions</TITLE> +</HEAD> +<BODY> +<H1 ALIGN=center>LinuxThreads Frequently Asked Questions <BR> + (with answers)</H1> +<H2 ALIGN=center>[For LinuxThreads version 0.8]</H2> + +<HR><P> + +<A HREF="#A">A. The big picture</A><BR> +<A HREF="#B">B. Getting more information</A><BR> +<A HREF="#C">C. Issues related to the C library</A><BR> +<A HREF="#D">D. Problems, weird behaviors, potential bugs</A><BR> +<A HREF="#E">E. Missing functions, wrong types, etc</A><BR> +<A HREF="#F">F. C++ issues</A><BR> +<A HREF="#G">G. Debugging LinuxThreads programs</A><BR> +<A HREF="#H">H. Compiling multithreaded code; errno madness</A><BR> +<A HREF="#I">I. X-Windows and other libraries</A><BR> +<A HREF="#J">J. Signals and threads</A><BR> +<A HREF="#K">K. Internals of LinuxThreads</A><P> + +<HR> +<P> + +<H2><A NAME="A">A. The big picture</A></H2> + +<H4><A NAME="A.1">A.1: What is LinuxThreads?</A></H4> + +LinuxThreads is a Linux library for multi-threaded programming. +It implements the Posix 1003.1c API (Application Programming +Interface) for threads. It runs on any Linux system with kernel 2.0.0 +or more recent, and a suitable C library (see section <A HREF="C">C</A>). +<P> + +<H4><A NAME="A.2">A.2: What are threads?</A></H4> + +A thread is a sequential flow of control through a program. +Multi-threaded programming is, thus, a form of parallel programming +where several threads of control are executing concurrently in the +program. All threads execute in the same memory space, and can +therefore work concurrently on shared data.<P> + +Multi-threaded programming differs from Unix-style multi-processing in +that all threads share the same memory space (and a few other system +resources, such as file descriptors), instead of running in their own +memory space as is the case with Unix processes.<P> + +Threads are useful for two reasons. First, they allow a program to +exploit multi-processor machines: the threads can run in parallel on +several processors, allowing a single program to divide its work +between several processors, thus running faster than a single-threaded +program, which runs on only one processor at a time. Second, some +programs are best expressed as several threads of control that +communicate together, rather than as one big monolithic sequential +program. Examples include server programs, overlapping asynchronous +I/O, and graphical user interfaces.<P> + +<H4><A NAME="A.3">A.3: What is POSIX 1003.1c?</A></H4> + +It's an API for multi-threaded programming standardized by IEEE as +part of the POSIX standards. Most Unix vendors have endorsed the +POSIX 1003.1c standard. Implementations of the 1003.1c API are +already available under Sun Solaris 2.5, Digital Unix 4.0, +Silicon Graphics IRIX 6, and should soon be available from other +vendors such as IBM and HP. More generally, the 1003.1c API is +replacing relatively quickly the proprietary threads library that were +developed previously under Unix, such as Mach cthreads, Solaris +threads, and IRIX sprocs. Thus, multithreaded programs using the +1003.1c API are likely to run unchanged on a wide variety of Unix +platforms.<P> + +<H4><A NAME="A.4">A.4: What is the status of LinuxThreads?</A></H4> + +LinuxThreads implements almost all of Posix 1003.1c, as well as a few +extensions. The only part of LinuxThreads that does not conform yet +to Posix is signal handling (see section <A HREF="#J">J</A>). Apart +from the signal stuff, all the Posix 1003.1c base functionality, +as well as a number of optional extensions, are provided and conform +to the standard (to the best of my knowledge). +The signal stuff is hard to get right, at least without special kernel +support, and while I'm definitely looking at ways to implement the +Posix behavior for signals, this might take a long time before it's +completed.<P> + +<H4><A NAME="A.5">A.5: How stable is LinuxThreads?</A></H4> + +The basic functionality (thread creation and termination, mutexes, +conditions, semaphores) is very stable. Several industrial-strength +programs, such as the AOL multithreaded Web server, use LinuxThreads +and seem quite happy about it. There used to be some rough edges in +the LinuxThreads / C library interface with libc 5, but glibc 2 +fixes all of those problems and is now the standard C library on major +Linux distributions (see section <A HREF="#C">C</A>). <P> + +<HR> +<P> + +<H2><A NAME="B">B. Getting more information</A></H2> + +<H4><A NAME="B.1">B.1: What are good books and other sources of +information on POSIX threads?</A></H4> + +The FAQ for comp.programming.threads lists several books: +<A HREF="http://www.serpentine.com/~bos/threads-faq/">http://www.serpentine.com/~bos/threads-faq/</A>.<P> + +There are also some online tutorials. Follow the links from the +LinuxThreads web page: +<A HREF="http://pauillac.inria.fr/~xleroy/linuxthreads">http://pauillac.inria.fr/~xleroy/linuxthreads</A>.<P> + +<H4><A NAME="B.2">B.2: I'd like to be informed of future developments on +LinuxThreads. Is there a mailing list for this purpose?</A></H4> + +I post LinuxThreads-related announcements on the newsgroup +<A HREF="news:comp.os.linux.announce">comp.os.linux.announce</A>, +and also on the mailing list +<code>linux-threads@magenet.com</code>. +You can subscribe to the latter by writing +<A HREF="mailto:majordomo@magenet.com">majordomo@magenet.com</A>.<P> + +<H4><A NAME="B.3">B.3: What are good places for discussing +LinuxThreads?</A></H4> + +For questions about programming with POSIX threads in general, use +the newsgroup +<A HREF="news:comp.programming.threads">comp.programming.threads</A>. +Be sure you read the +<A HREF="http://www.serpentine.com/~bos/threads-faq/">FAQ</A> +for this group before you post.<P> + +For Linux-specific questions, use +<A +HREF="news:comp.os.linux.development.apps">comp.os.linux.development.apps</A> +and <A +HREF="news:comp.os.linux.development.kernel">comp.os.linux.development.kernel</A>. +The latter is especially appropriate for questions relative to the +interface between the kernel and LinuxThreads.<P> + +<H4><A NAME="B.4">B.4: How should I report a possible bug in +LinuxThreads?</A></H4> + +If you're using glibc 2, the best way by far is to use the +<code>glibcbug</code> script to mail a bug report to the glibc +maintainers. <P> + +If you're using an older libc, or don't have the <code>glibcbug</code> +script on your machine, then e-mail me directly +(<code>Xavier.Leroy@inria.fr</code>). <P> + +In both cases, before sending the bug report, make sure that it is not +addressed already in this FAQ. Also, try to send a short program that +reproduces the weird behavior you observed. <P> + +<H4><A NAME="B.5">B.5: I'd like to read the POSIX 1003.1c standard. Is +it available online?</A></H4> + +Unfortunately, no. POSIX standards are copyrighted by IEEE, and +IEEE does not distribute them freely. You can buy paper copies from +IEEE, but the price is fairly high ($120 or so). If you disagree with +this policy and you're an IEEE member, be sure to let them know.<P> + +On the other hand, you probably don't want to read the standard. It's +very hard to read, written in standard-ese, and targeted to +implementors who already know threads inside-out. A good book on +POSIX threads provides the same information in a much more readable form. +I can personally recommend Dave Butenhof's book, <CITE>Programming +with POSIX threads</CITE> (Addison-Wesley). Butenhof was part of the +POSIX committee and also designed the Digital Unix implementations of +POSIX threads, and it shows.<P> + +Another good source of information is the X/Open Group Single Unix +specification which is available both +<A HREF="http://www.rdg.opengroup.org/onlinepubs/7908799/index.html">on-line</A> +and as a +<A HREF="http://www.UNIX-systems.org/gosolo2/">book and CD/ROM</A>. +That specification includes pretty much all the POSIX standards, +including 1003.1c, with some extensions and clarifications.<P> + +<HR> +<P> + +<H2><A NAME="C">C. Issues related to the C library</A></H2> + +<H4><A NAME="C.1">C.1: Which version of the C library should I use +with LinuxThreads?</A></H4> + +The best choice by far is glibc 2, a.k.a. libc 6. It offers very good +support for multi-threading, and LinuxThreads has been closely +integrated with glibc 2. The glibc 2 distribution contains the +sources of a specially adapted version of LinuxThreads.<P> + +glibc 2 comes preinstalled as the default C library on several Linux +distributions, such as RedHat 5 and up, and Debian 2. +Those distributions include the version of LinuxThreads matching +glibc 2.<P> + +<H4><A NAME="C.2">C.2: My system has libc 5 preinstalled, not glibc +2. Can I still use LinuxThreads?</H4> + +Yes, but you're likely to run into some problems, as libc 5 only +offers minimal support for threads and contains some bugs that affect +multithreaded programs. <P> + +The versions of libc 5 that work best with LinuxThreads are +libc 5.2.18 on the one hand, and libc 5.4.12 or later on the other hand. +Avoid 5.3.12 and 5.4.7: these have problems with the per-thread errno +variable. <P> + +<H4><A NAME="C.3">C.3: So, should I switch to glibc 2, or stay with a +recent libc 5?</A></H4> + +I'd recommend you switch to glibc 2. Even for single-threaded +programs, glibc 2 is more solid and more standard-conformant than libc +5. And the shortcomings of libc 5 almost preclude any serious +multi-threaded programming.<P> + +Switching an already installed +system from libc 5 to glibc 2 is not completely straightforward. +See the <A HREF="http://sunsite.unc.edu/LDP/HOWTO/Glibc2-HOWTO.html">Glibc2 +HOWTO</A> for more information. Much easier is (re-)installing a +Linux distribution based on glibc 2, such as RedHat 6.<P> + +<H4><A NAME="C.4">C.4: Where can I find glibc 2 and the version of +LinuxThreads that goes with it?</A></H4> + +On <code>prep.ai.mit.edu</code> and its many, many mirrors around the world. +See <A +HREF="http://www.gnu.org/order/ftp.html">http://www.gnu.org/order/ftp.html</A> +for a list of mirrors.<P> + +<H4><A NAME="C.5">C.5: Where can I find libc 5 and the version of +LinuxThreads that goes with it?</A></H4> + +For libc 5, see <A HREF="ftp://sunsite.unc.edu/pub/Linux/devel/GCC/"><code>ftp://sunsite.unc.edu/pub/Linux/devel/GCC/</code></A>.<P> + +For the libc 5 version of LinuxThreads, see +<A HREF="ftp://ftp.inria.fr/INRIA/Projects/cristal/Xavier.Leroy/linuxthreads/">ftp://ftp.inria.fr/INRIA/Projects/cristal/Xavier.Leroy/linuxthreads/</A>.<P> + +<H4><A NAME="C.6">C.6: How can I recompile the glibc 2 version of the +LinuxThreads sources?</A></H4> + +You must transfer the whole glibc sources, then drop the LinuxThreads +sources in the <code>linuxthreads/</code> subdirectory, then recompile +glibc as a whole. There are now too many inter-dependencies between +LinuxThreads and glibc 2 to allow separate re-compilation of LinuxThreads. +<P> + +<H4><A NAME="C.7">C.7: What is the correspondence between LinuxThreads +version numbers, libc version numbers, and RedHat version +numbers?</A></H4> + +Here is a summary. (Information on Linux distributions other than +RedHat are welcome.)<P> + +<TABLE> +<TR><TD>LinuxThreads </TD> <TD>C library</TD> <TD>RedHat</TD></TR> +<TR><TD>0.7, 0.71 (for libc 5)</TD> <TD>libc 5.x</TD> <TD>RH 4.2</TD></TR> +<TR><TD>0.7, 0.71 (for glibc 2)</TD> <TD>glibc 2.0.x</TD> <TD>RH 5.x</TD></TR> +<TR><TD>0.8</TD> <TD>glibc 2.1.1</TD> <TD>RH 6.0</TD></TR> +<TR><TD>0.8</TD> <TD>glibc 2.1.2</TD> <TD>not yet released</TD></TR> +</TABLE> +<P> + +<HR> +<P> + +<H2><A NAME="D">D. Problems, weird behaviors, potential bugs</A></H2> + +<H4><A NAME="D.1">D.1: When I compile LinuxThreads, I run into problems in +file <code>libc_r/dirent.c</code></A></H4> + +You probably mean: +<PRE> + libc_r/dirent.c:94: structure has no member named `dd_lock' +</PRE> +I haven't actually seen this problem, but several users reported it. +My understanding is that something is wrong in the include files of +your Linux installation (<code>/usr/include/*</code>). Make sure +you're using a supported version of the libc 5 library. (See question <A +HREF="#C.2">C.2</A>).<P> + +<H4><A NAME="D.2">D.2: When I compile LinuxThreads, I run into problems with +<CODE>/usr/include/sched.h</CODE>: there are several occurrences of +<CODE>_p</CODE> that the C compiler does not understand</A></H4> + +Yes, <CODE>/usr/include/sched.h</CODE> that comes with libc 5.3.12 is broken. +Replace it with the <code>sched.h</code> file contained in the +LinuxThreads distribution. But really you should not be using libc +5.3.12 with LinuxThreads! (See question <A HREF="#C.2">C.1</A>.)<P> + +<H4><A NAME="D.3">D.3: My program does <CODE>fdopen()</CODE> on a file +descriptor opened on a pipe. When I link it with LinuxThreads, +<CODE>fdopen()</CODE> always returns NULL!</A></H4> + +You're using one of the buggy versions of libc (5.3.12, 5.4.7., etc). +See question <A HREF="#C.1">C.1</A> above.<P> + +<H4><A NAME="D.4">D.4: My program creates a lot of threads, and after +a while <CODE>pthread_create()</CODE> no longer returns!</A></H4> + +This is known bug in the version of LinuxThreads that comes with glibc +2.1.1. An upgrade to 2.1.2 is recommended. <P> + +<H4><A NAME="D.5">D.5: When I'm running a program that creates N +threads, <code>top</code> or <code>ps</code> +display N+2 processes that are running my program. What do all these +processes correspond to?</A></H4> + +Due to the general "one process per thread" model, there's one process +for the initial thread and N processes for the threads it created +using <CODE>pthread_create</CODE>. That leaves one process +unaccounted for. That extra process corresponds to the "thread +manager" thread, a thread created internally by LinuxThreads to handle +thread creation and thread termination. This extra thread is asleep +most of the time. + +<H4><A NAME="D.6">D.6: Scheduling seems to be very unfair when there +is strong contention on a mutex: instead of giving the mutex to each +thread in turn, it seems that it's almost always the same thread that +gets the mutex. Isn't this completely broken behavior?</A></H4> + +That behavior has mostly disappeared in recent releases of +LinuxThreads (version 0.8 and up). It was fairly common in older +releases, though. + +What happens in LinuxThreads 0.7 and before is the following: when a +thread unlocks a mutex, all other threads that were waiting on the +mutex are sent a signal which makes them runnable. However, the +kernel scheduler may or may not restart them immediately. If the +thread that unlocked the mutex tries to lock it again immediately +afterwards, it is likely that it will succeed, because the threads +haven't yet restarted. This results in an apparently very unfair +behavior, when the same thread repeatedly locks and unlocks the mutex, +while other threads can't lock the mutex.<P> + +In LinuxThreads 0.8 and up, <code>pthread_unlock</code> restarts only +one waiting thread, and pre-assign the mutex to that thread. Hence, +if the thread that unlocked the mutex tries to lock it again +immediately, it will block until other waiting threads have had a +chance to lock and unlock the mutex. This results in much fairer +scheduling.<P> + +Notice however that even the old "unfair" behavior is perfectly +acceptable with respect to the POSIX standard: for the default +scheduling policy, POSIX makes no guarantees of fairness, such as "the +thread waiting for the mutex for the longest time always acquires it +first". Properly written multithreaded code avoids that kind of heavy +contention on mutexes, and does not run into fairness problems. If +you need scheduling guarantees, you should consider using the +real-time scheduling policies <code>SCHED_RR</code> and +<code>SCHED_FIFO</code>, which have precisely defined scheduling +behaviors. <P> + +<H4><A NAME="D.7">D.7: I have a simple test program with two threads +that do nothing but <CODE>printf()</CODE> in tight loops, and from the +printout it seems that only one thread is running, the other doesn't +print anything!</A></H4> + +Again, this behavior is characteristic of old releases of LinuxThreads +(0.7 and before); more recent versions (0.8 and up) should not exhibit +this behavior.<P> + +The reason for this behavior is explained in +question <A HREF="#D.6">D.6</A> above: <CODE>printf()</CODE> performs +locking on <CODE>stdout</CODE>, and thus your two threads contend very +heavily for the mutex associated with <CODE>stdout</CODE>. But if you +do some real work between two calls to <CODE>printf()</CODE>, you'll +see that scheduling becomes much smoother.<P> + +<H4><A NAME="D.8">D.8: I've looked at <code><pthread.h></code> +and there seems to be a gross error in the <code>pthread_cleanup_push</code> +macro: it opens a block with <code>{</code> but does not close it! +Surely you forgot a <code>}</code> at the end of the macro, right? +</A></H4> + +Nope. That's the way it should be. The closing brace is provided by +the <code>pthread_cleanup_pop</code> macro. The POSIX standard +requires <code>pthread_cleanup_push</code> and +<code>pthread_cleanup_pop</code> to be used in matching pairs, at the +same level of brace nesting. This allows +<code>pthread_cleanup_push</code> to open a block in order to +stack-allocate some data structure, and +<code>pthread_cleanup_pop</code> to close that block. It's ugly, but +it's the standard way of implementing cleanup handlers.<P> + +<H4><A NAME="D.9">D.9: I tried to use real-time threads and my program +loops like crazy and freezes the whole machine!</A></H4> + +Versions of LinuxThreads prior to 0.8 are susceptible to ``livelocks'' +(one thread loops, consuming 100% of the CPU time) in conjunction with +real-time scheduling. Since real-time threads and processes have +higher priority than normal Linux processes, all other processes on +the machine, including the shell, the X server, etc, cannot run and +the machine appears frozen.<P> + +The problem is fixed in LinuxThreads 0.8.<P> + +<H4><A NAME="D.10">D.10: My application needs to create thousands of +threads, or maybe even more. Can I do this with +LinuxThreads?</A></H4> + +No. You're going to run into several hard limits: +<UL> +<LI>Each thread, from the kernel's standpoint, is one process. Stock +Linux kernels are limited to at most 512 processes for the super-user, +and half this number for regular users. This can be changed by +changing <code>NR_TASKS</code> in <code>include/linux/tasks.h</code> +and recompiling the kernel. On the x86 processors at least, +architectural constraints seem to limit <code>NR_TASKS</code> to 4090 +at most. +<LI>LinuxThreads contains a table of all active threads. This table +has room for 1024 threads at most. To increase this limit, you must +change <code>PTHREAD_THREADS_MAX</code> in the LinuxThreads sources +and recompile. +<LI>By default, each thread reserves 2M of virtual memory space for +its stack. This space is just reserved; actual memory is allocated +for the stack on demand. But still, on a 32-bit processor, the total +virtual memory space available for the stacks is on the order of 1G, +meaning that more than 500 threads will have a hard time fitting in. +You can overcome this limitation by moving to a 64-bit platform, or by +allocating smaller stacks yourself using the <code>setstackaddr</code> +attribute. +<LI>Finally, the Linux kernel contains many algorithms that run in +time proportional to the number of process table entries. Increasing +this number drastically will slow down the kernel operations +noticeably. +</UL> +(Other POSIX threads libraries have similar limitations, by the way.) +For all those reasons, you'd better restructure your application so +that it doesn't need more than, say, 100 threads. For instance, +in the case of a multithreaded server, instead of creating a new +thread for each connection, maintain a fixed-size pool of worker +threads that pick incoming connection requests from a queue.<P> + +<HR> +<P> + +<H2><A NAME="E">E. Missing functions, wrong types, etc</A></H2> + +<H4><A NAME="E.1">E.1: Where is <CODE>pthread_yield()</CODE> ? How +comes LinuxThreads does not implement it?</A></H4> + +Because it's not part of the (final) POSIX 1003.1c standard. +Several drafts of the standard contained <CODE>pthread_yield()</CODE>, +but then the POSIX guys discovered it was redundant with +<CODE>sched_yield()</CODE> and dropped it. So, just use +<CODE>sched_yield()</CODE> instead. + +<H4><A NAME="E.2">E.2: I've found some type errors in +<code><pthread.h></code>. +For instance, the second argument to <CODE>pthread_create()</CODE> +should be a <CODE>pthread_attr_t</CODE>, not a +<CODE>pthread_attr_t *</CODE>. Also, didn't you forget to declare +<CODE>pthread_attr_default</CODE>?</A></H4> + +No, I didn't. What you're describing is draft 4 of the POSIX +standard, which is used in OSF DCE threads. LinuxThreads conforms to the +final standard. Even though the functions have the same names as in +draft 4 and DCE, their calling conventions are slightly different. In +particular, attributes are passed by reference, not by value, and +default attributes are denoted by the NULL pointer. Since draft 4/DCE +will eventually disappear, you'd better port your program to use the +standard interface.<P> + +<H4><A NAME="E.3">E.3: I'm porting an application from Solaris and I +have to rename all thread functions from <code>thr_blah</code> to +<CODE>pthread_blah</CODE>. This is very annoying. Why did you change +all the function names?</A></H4> + +POSIX did it. The <code>thr_*</code> functions correspond to Solaris +threads, an older thread interface that you'll find only under +Solaris. The <CODE>pthread_*</CODE> functions correspond to POSIX +threads, an international standard available for many, many platforms. +Even Solaris 2.5 and later support the POSIX threads interface. So, +do yourself a favor and rewrite your code to use POSIX threads: this +way, it will run unchanged under Linux, Solaris, and quite a lot of +other platforms.<P> + +<H4><A NAME="E.4">E.4: How can I suspend and resume a thread from +another thread? Solaris has the <CODE>thr_suspend()</CODE> and +<CODE>thr_resume()</CODE> functions to do that; why don't you?</A></H4> + +The POSIX standard provides <B>no</B> mechanism by which a thread A can +suspend the execution of another thread B, without cooperation from B. +The only way to implement a suspend/restart mechanism is to have B +check periodically some global variable for a suspend request +and then suspend itself on a condition variable, which another thread +can signal later to restart B.<P> + +Notice that <CODE>thr_suspend()</CODE> is inherently dangerous and +prone to race conditions. For one thing, there is no control on where +the target thread stops: it can very well be stopped in the middle of +a critical section, while holding mutexes. Also, there is no +guarantee on when the target thread will actually stop. For these +reasons, you'd be much better off using mutexes and conditions +instead. The only situations that really require the ability to +suspend a thread are debuggers and some kind of garbage collectors.<P> + +If you really must suspend a thread in LinuxThreads, you can send it a +<CODE>SIGSTOP</CODE> signal with <CODE>pthread_kill</CODE>. Send +<CODE>SIGCONT</CODE> for restarting it. +Beware, this is specific to LinuxThreads and entirely non-portable. +Indeed, a truly conforming POSIX threads implementation will stop all +threads when one thread receives the <CODE>SIGSTOP</CODE> signal! +One day, LinuxThreads will implement that behavior, and the +non-portable hack with <CODE>SIGSTOP</CODE> won't work anymore.<P> + +<H4><A NAME="E.5">E.5: Does LinuxThreads implement +<CODE>pthread_attr_setstacksize()</CODE> and +<CODE>pthread_attr_setstackaddr()</CODE>?</A></H4> + +These optional functions are provided in recent versions of +LinuxThreads (0.8 and up). Earlier releases did not provide these +optional components of the POSIX standard.<P> + +Even if <CODE>pthread_attr_setstacksize()</CODE> and +<CODE>pthread_attr_setstackaddr()</CODE> are now provided, we still +recommend that you do not use them unless you really have strong +reasons for doing so. The default stack allocation strategy for +LinuxThreads is nearly optimal: stacks start small (4k) and +automatically grow on demand to a fairly large limit (2M). +Moreover, there is no portable way to estimate the stack requirements +of a thread, so setting the stack size yourself makes your program +less reliable and non-portable.<P> + +<H4><A NAME="E.6">E.6: LinuxThreads does not support the +<CODE>PTHREAD_SCOPE_PROCESS</CODE> value of the "contentionscope" +attribute. Why? </A></H4> + +With a "one-to-one" model, as in LinuxThreads (one kernel execution +context per thread), there is only one scheduler for all processes and +all threads on the system. So, there is no way to obtain the behavior of +<CODE>PTHREAD_SCOPE_PROCESS</CODE>. + +<H4><A NAME="E.7">E.7: LinuxThreads does not implement process-shared +mutexes, conditions, and semaphores. Why?</A></H4> + +This is another optional component of the POSIX standard. Portable +applications should test <CODE>_POSIX_THREAD_PROCESS_SHARED</CODE> +before using this facility. +<P> +The goal of this extension is to allow different processes (with +different address spaces) to synchronize through mutexes, conditions +or semaphores allocated in shared memory (either SVR4 shared memory +segments or <CODE>mmap()</CODE>ed files). +<P> +The reason why this does not work in LinuxThreads is that mutexes, +conditions, and semaphores are not self-contained: their waiting +queues contain pointers to linked lists of thread descriptors, and +these pointers are meaningful only in one address space. +<P> +Matt Messier and I spent a significant amount of time trying to design a +suitable mechanism for sharing waiting queues between processes. We +came up with several solutions that combined two of the following +three desirable features, but none that combines all three: +<UL> +<LI>allow sharing between processes having different UIDs +<LI>supports cancellation +<LI>supports <CODE>pthread_cond_timedwait</CODE> +</UL> +We concluded that kernel support is required to share mutexes, +conditions and semaphores between processes. That's one place where +Linus Torvalds's intuition that "all we need in the kernel is +<CODE>clone()</CODE>" fails. +<P> +Until suitable kernel support is available, you'd better use +traditional interprocess communications to synchronize different +processes: System V semaphores and message queues, or pipes, or sockets. +<P> + +<HR> +<P> + +<H2><A NAME="F">F. C++ issues</A></H2> + +<H4><A NAME="F.1">F.1: Are there C++ wrappers for LinuxThreads?</A></H4> + +Douglas Schmidt's ACE library contains, among a lot of other +things, C++ wrappers for LinuxThreads and quite a number of other +thread libraries. Check out +<A HREF="http://www.cs.wustl.edu/~schmidt/ACE.html">http://www.cs.wustl.edu/~schmidt/ACE.html</A><P> + +<H4><A NAME="F.2">F.2: I'm trying to use LinuxThreads from a C++ +program, and the compiler complains about the third argument to +<CODE>pthread_create()</CODE> !</A></H4> + +You're probably trying to pass a class member function or some +other C++ thing as third argument to <CODE>pthread_create()</CODE>. +Recall that <CODE>pthread_create()</CODE> is a C function, and it must +be passed a C function as third argument.<P> + +<H4><A NAME="F.3">F.3: I'm trying to use LinuxThreads in conjunction +with libg++, and I'm having all sorts of trouble.</A></H4> + +>From what I understand, thread support in libg++ is completely broken, +especially with respect to locking of iostreams. H.J.Lu wrote: +<BLOCKQUOTE> +If you want to use thread, I can only suggest egcs and glibc. You +can find egcs at +<A HREF="http://www.cygnus.com/egcs">http://www.cygnus.com/egcs</A>. +egcs has libsdtc++, which is MT safe under glibc 2. If you really +want to use the libg++, I have a libg++ add-on for egcs. +</BLOCKQUOTE> +<HR> +<P> + +<H2><A NAME="G">G. Debugging LinuxThreads programs</A></H2> + +<H4><A NAME="G.1">G.1: Can I debug LinuxThreads program using gdb?</A></H4> + +Yes, but not with the stock gdb 4.17. You need a specially patched +version of gdb 4.17 developed by Eric Paire and colleages at The Open +Group, Grenoble. The patches against gdb 4.17 are available at +<A HREF="http://www.gr.opengroup.org/java/jdk/linux/debug.htm"><code>http://www.gr.opengroup.org/java/jdk/linux/debug.htm</code></A>. +Precompiled binaries of the patched gdb are available in RedHat's RPM +format at <A +HREF="http://odin.appliedtheory.com/"><code>http://odin.appliedtheory.com/</code></A>.<P> + +Some Linux distributions provide an already-patched version of gdb; +others don't. For instance, the gdb in RedHat 5.2 is thread-aware, +but apparently not the one in RedHat 6.0. Just ask (politely) the +makers of your Linux distributions to please make sure that they apply +the correct patches to gdb.<P> + +<H4><A NAME="G.2">G.2: Does it work with post-mortem debugging?</A></H4> + +Not very well. Generally, the core file does not correspond to the +thread that crashed. The reason is that the kernel will not dump core +for a process that shares its memory with other processes, such as the +other threads of your program. So, the thread that crashes silently +disappears without generating a core file. Then, all other threads of +your program die on the same signal that killed the crashing thread. +(This is required behavior according to the POSIX standard.) The last +one that dies is no longer sharing its memory with anyone else, so the +kernel generates a core file for that thread. Unfortunately, that's +not the thread you are interested in. + +<H4><A NAME="G.3">G.3: Any other ways to debug multithreaded programs, then?</A></H4> + +Assertions and <CODE>printf()</CODE> are your best friends. Try to debug +sequential parts in a single-threaded program first. Then, put +<CODE>printf()</CODE> statements all over the place to get execution traces. +Also, check invariants often with the <CODE>assert()</CODE> macro. In truth, +there is no other effective way (save for a full formal proof of your +program) to track down concurrency bugs. Debuggers are not really +effective for subtle concurrency problems, because they disrupt +program execution too much.<P> + +<HR> +<P> + +<H2><A NAME="H">H. Compiling multithreaded code; errno madness</A></H2> + +<H4><A NAME="H.1">H.1: You say all multithreaded code must be compiled +with <CODE>_REENTRANT</CODE> defined. What difference does it make?</A></H4> + +It affects include files in three ways: +<UL> +<LI> The include files define prototypes for the reentrant variants of +some of the standard library functions, +e.g. <CODE>gethostbyname_r()</CODE> as a reentrant equivalent to +<CODE>gethostbyname()</CODE>.<P> + +<LI> If <CODE>_REENTRANT</CODE> is defined, some +<code><stdio.h></code> functions are no longer defined as macros, +e.g. <CODE>getc()</CODE> and <CODE>putc()</CODE>. In a multithreaded +program, stdio functions require additional locking, which the macros +don't perform, so we must call functions instead.<P> + +<LI> More importantly, <code><errno.h></code> redefines errno when +<CODE>_REENTRANT</CODE> is +defined, so that errno refers to the thread-specific errno location +rather than the global errno variable. This is achieved by the +following <code>#define</code> in <code><errno.h></code>: +<PRE> + #define errno (*(__errno_location())) +</PRE> +which causes each reference to errno to call the +<CODE>__errno_location()</CODE> function for obtaining the location +where error codes are stored. libc provides a default definition of +<CODE>__errno_location()</CODE> that always returns +<code>&errno</code> (the address of the global errno variable). Thus, +for programs not linked with LinuxThreads, defining +<CODE>_REENTRANT</CODE> makes no difference w.r.t. errno processing. +But LinuxThreads redefines <CODE>__errno_location()</CODE> to return a +location in the thread descriptor reserved for holding the current +value of errno for the calling thread. Thus, each thread operates on +a different errno location. +</UL> +<P> + +<H4><A NAME="H.2">H.2: Why is it so important that each thread has its +own errno variable? </A></H4> + +If all threads were to store error codes in the same, global errno +variable, then the value of errno after a system call or library +function returns would be unpredictable: between the time a system +call stores its error code in the global errno and your code inspects +errno to see which error occurred, another thread might have stored +another error code in the same errno location. <P> + +<H4><A NAME="H.3">H.3: What happens if I link LinuxThreads with code +not compiled with <CODE>-D_REENTRANT</CODE>?</A></H4> + +Lots of trouble. If the code uses <CODE>getc()</CODE> or +<CODE>putc()</CODE>, it will perform I/O without proper interlocking +of the stdio buffers; this can cause lost output, duplicate output, or +just crash other stdio functions. If the code consults errno, it will +get back the wrong error code. The following code fragment is a +typical example: +<PRE> + do { + r = read(fd, buf, n); + if (r == -1) { + if (errno == EINTR) /* an error we can handle */ + continue; + else { /* other errors are fatal */ + perror("read failed"); + exit(100); + } + } + } while (...); +</PRE> +Assume this code is not compiled with <CODE>-D_REENTRANT</CODE>, and +linked with LinuxThreads. At run-time, <CODE>read()</CODE> is +interrupted. Since the C library was compiled with +<CODE>-D_REENTRANT</CODE>, <CODE>read()</CODE> stores its error code +in the location pointed to by <CODE>__errno_location()</CODE>, which +is the thread-local errno variable. Then, the code above sees that +<CODE>read()</CODE> returns -1 and looks up errno. Since +<CODE>_REENTRANT</CODE> is not defined, the reference to errno +accesses the global errno variable, which is most likely 0. Hence the +code concludes that it cannot handle the error and stops.<P> + +<H4><A NAME="H.4">H.4: With LinuxThreads, I can no longer use the signals +<code>SIGUSR1</code> and <code>SIGUSR2</code> in my programs! Why? </A></H4> + +The short answer is: because the Linux kernel you're using does not +support realtime signals. <P> + +LinuxThreads needs two signals for its internal operation. +One is used to suspend and restart threads blocked on mutex, condition +or semaphore operations. The other is used for thread +cancellation.<P> + +On ``old'' kernels (2.0 and early 2.1 kernels), there are only 32 +signals available and the kernel reserves all of them but two: +<code>SIGUSR1</code> and <code>SIGUSR2</code>. So, LinuxThreads has +no choice but use those two signals.<P> + +On recent kernels (2.2 and up), more than 32 signals are provided in +the form of realtime signals. When run on one of those kernels, +LinuxThreads uses two reserved realtime signals for its internal +operation, thus leaving <code>SIGUSR1</code> and <code>SIGUSR2</code> +free for user code. (This works only with glibc, not with libc 5.) <P> + +<H4><A NAME="H.5">H.5: Is the stack of one thread visible from the +other threads? Can I pass a pointer into my stack to other threads? +</A></H4> + +Yes, you can -- if you're very careful. The stacks are indeed visible +from all threads in the system. Some non-POSIX thread libraries seem +to map the stacks for all threads at the same virtual addresses and +change the memory mapping when they switch from one thread to +another. But this is not the case for LinuxThreads, as it would make +context switching between threads more expensive, and at any rate +might not conform to the POSIX standard.<P> + +So, you can take the address of an "auto" variable and pass it to +other threads via shared data structures. However, you need to make +absolutely sure that the function doing this will not return as long +as other threads need to access this address. It's the usual mistake +of returning the address of an "auto" variable, only made much worse +because of concurrency. It's much, much safer to systematically +heap-allocate all shared data structures. <P> + +<HR> +<P> + +<H2><A NAME="I">I. X-Windows and other libraries</A></H2> + +<H4><A NAME="I.1">I.1: My program uses both Xlib and LinuxThreads. +It stops very early with an "Xlib: unknown 0 error" message. What +does this mean? </A></H4> + +That's a prime example of the errno problem described in question <A +HREF="#H.2">H.2</A>. The binaries for Xlib you're using have not been +compiled with <CODE>-D_REENTRANT</CODE>. It happens Xlib contains a +piece of code very much like the one in question <A +HREF="#H.2">H.2</A>. So, your Xlib fetches the error code from the +wrong errno location and concludes that an error it cannot handle +occurred.<P> + +<H4><A NAME="I.2">I.2: So, what can I do to build a multithreaded X +Windows client? </A></H4> + +The best solution is to use X libraries that have been compiled with +multithreading options set. Linux distributions that come with glibc +2 as the main C library generally provide thread-safe X libraries. +At least, that seems to be the case for RedHat 5 and later.<P> + +You can try to recompile yourself the X libraries with multithreading +options set. They contain optional support for multithreading; it's +just that the binaries provided by your Linux distribution were built +without this support. See the file <code>README.Xfree3.3</code> in +the LinuxThreads distribution for patches and info on how to compile +thread-safe X libraries from the Xfree3.3 distribution. The Xfree3.3 +sources are readily available in most Linux distributions, e.g. as a +source RPM for RedHat. Be warned, however, that X Windows is a huge +system, and recompiling even just the libraries takes a lot of time +and disk space.<P> + +Another, less involving solution is to call X functions only from the +main thread of your program. Even if all threads have their own errno +location, the main thread uses the global errno variable for its errno +location. Thus, code not compiled with <code>-D_REENTRANT</code> +still "sees" the right error values if it executes in the main thread +only. <P> + +<H4><A NAME="I.2">This is a lot of work. Don't you have precompiled +thread-safe X libraries that you could distribute?</A></H4> + +No, I don't. Sorry. But consider installing a Linux distribution +that comes with thread-safe X libraries, such as RedHat 6.<P> + +<H4><A NAME="I.3">I.3: Can I use library FOO in a multithreaded +program?</A></H4> + +Most libraries cannot be used "as is" in a multithreaded program. +For one thing, they are not necessarily thread-safe: calling +simultaneously two functions of the library from two threads might not +work, due to internal use of global variables and the like. Second, +the libraries must have been compiled with <CODE>-D_REENTRANT</CODE> to avoid +the errno problems explained in question <A HREF="#H.2">H.2</A>. +<P> + +<H4><A NAME="I.4">I.4: What if I make sure that only one thread calls +functions in these libraries?</A></H4> + +This avoids problems with the library not being thread-safe. But +you're still vulnerable to errno problems. At the very least, a +recompile of the library with <CODE>-D_REENTRANT</CODE> is needed. +<P> + +<H4><A NAME="I.5">I.5: What if I make sure that only the main thread +calls functions in these libraries?</A></H4> + +That might actually work. As explained in question <A HREF="#I.1">I.1</A>, +the main thread uses the global errno variable, and can therefore +execute code not compiled with <CODE>-D_REENTRANT</CODE>.<P> + +<H4><A NAME="I.6">I.6: SVGAlib doesn't work with LinuxThreads. Why? +</A></H4> + +Because both LinuxThreads and SVGAlib use the signals +<code>SIGUSR1</code> and <code>SIGUSR2</code>. See question <A +HREF="#H.4">H.4</A>. +<P> + + +<HR> +<P> + +<H2><A NAME="J">J. Signals and threads</A></H2> + +<H4><A NAME="J.1">J.1: When it comes to signals, what is shared +between threads and what isn't?</A></H4> + +Signal handlers are shared between all threads: when a thread calls +<CODE>sigaction()</CODE>, it sets how the signal is handled not only +for itself, but for all other threads in the program as well.<P> + +On the other hand, signal masks are per-thread: each thread chooses +which signals it blocks independently of others. At thread creation +time, the newly created thread inherits the signal mask of the thread +calling <CODE>pthread_create()</CODE>. But afterwards, the new thread +can modify its signal mask independently of its creator thread.<P> + +<H4><A NAME="J.2">J.2: When I send a <CODE>SIGKILL</CODE> to a +particular thread using <CODE>pthread_kill</CODE>, all my threads are +killed!</A></H4> + +That's how it should be. The POSIX standard mandates that all threads +should terminate when the process (i.e. the collection of all threads +running the program) receives a signal whose effect is to +terminate the process (such as <CODE>SIGKILL</CODE> or <CODE>SIGINT</CODE> +when no handler is installed on that signal). This behavior makes a +lot of sense: when you type "ctrl-C" at the keyboard, or when a thread +crashes on a division by zero or a segmentation fault, you really want +all threads to stop immediately, not just the one that caused the +segmentation violation or that got the <CODE>SIGINT</CODE> signal. +(This assumes default behavior for those signals; see question +<A HREF="#J.3">J.3</A> if you install handlers for those signals.)<P> + +If you're trying to terminate a thread without bringing the whole +process down, use <code>pthread_cancel()</code>.<P> + +<H4><A NAME="J.3">J.3: I've installed a handler on a signal. Which +thread executes the handler when the signal is received?</A></H4> + +If the signal is generated by a thread during its execution (e.g. a +thread executes a division by zero and thus generates a +<CODE>SIGFPE</CODE> signal), then the handler is executed by that +thread. This also applies to signals generated by +<CODE>raise()</CODE>.<P> + +If the signal is sent to a particular thread using +<CODE>pthread_kill()</CODE>, then that thread executes the handler.<P> + +If the signal is sent via <CODE>kill()</CODE> or the tty interface +(e.g. by pressing ctrl-C), then the POSIX specs say that the handler +is executed by any thread in the process that does not currently block +the signal. In other terms, POSIX considers that the signal is sent +to the process (the collection of all threads) as a whole, and any +thread that is not blocking this signal can then handle it.<P> + +The latter case is where LinuxThreads departs from the POSIX specs. +In LinuxThreads, there is no real notion of ``the process as a whole'': +in the kernel, each thread is really a distinct process with a +distinct PID, and signals sent to the PID of a thread can only be +handled by that thread. As long as no thread is blocking the signal, +the behavior conforms to the standard: one (unspecified) thread of the +program handles the signal. But if the thread to which PID the signal +is sent blocks the signal, and some other thread does not block the +signal, then LinuxThreads will simply queue in +that thread and execute the handler only when that thread unblocks +the signal, instead of executing the handler immediately in the other +thread that does not block the signal.<P> + +This is to be viewed as a LinuxThreads bug, but I currently don't see +any way to implement the POSIX behavior without kernel support.<P> + +<H4><A NAME="J.3">J.3: How shall I go about mixing signals and threads +in my program? </A></H4> + +The less you mix them, the better. Notice that all +<CODE>pthread_*</CODE> functions are not async-signal safe, meaning +that you should not call them from signal handlers. This +recommendation is not to be taken lightly: your program can deadlock +if you call a <CODE>pthread_*</CODE> function from a signal handler! +<P> + +The only sensible things you can do from a signal handler is set a +global flag, or call <CODE>sem_post</CODE> on a semaphore, to record +the delivery of the signal. The remainder of the program can then +either poll the global flag, or use <CODE>sem_wait()</CODE> and +<CODE>sem_trywait()</CODE> on the semaphore.<P> + +Another option is to do nothing in the signal handler, and dedicate +one thread (preferably the initial thread) to wait synchronously for +signals, using <CODE>sigwait()</CODE>, and send messages to the other +threads accordingly. + +<H4><A NAME="J.4">J.4: When one thread is blocked in +<CODE>sigwait()</CODE>, other threads no longer receive the signals +<CODE>sigwait()</CODE> is waiting for! What happens? </A></H4> + +It's an unfortunate consequence of how LinuxThreads implements +<CODE>sigwait()</CODE>. Basically, it installs signal handlers on all +signals waited for, in order to record which signal was received. +Since signal handlers are shared with the other threads, this +temporarily deactivates any signal handlers you might have previously +installed on these signals.<P> + +Though surprising, this behavior actually seems to conform to the +POSIX standard. According to POSIX, <CODE>sigwait()</CODE> is +guaranteed to work as expected only if all other threads in the +program block the signals waited for (otherwise, the signals could be +delivered to other threads than the one doing <CODE>sigwait()</CODE>, +which would make <CODE>sigwait()</CODE> useless). In this particular +case, the problem described in this question does not appear.<P> + +One day, <CODE>sigwait()</CODE> will be implemented in the kernel, +along with others POSIX 1003.1b extensions, and <CODE>sigwait()</CODE> +will have a more natural behavior (as well as better performances).<P> + +<HR> +<P> + +<H2><A NAME="K">K. Internals of LinuxThreads</A></H2> + +<H4><A NAME="K.1">K.1: What is the implementation model for +LinuxThreads?</A></H4> + +LinuxThreads follows the so-called "one-to-one" model: each thread is +actually a separate process in the kernel. The kernel scheduler takes +care of scheduling the threads, just like it schedules regular +processes. The threads are created with the Linux +<code>clone()</code> system call, which is a generalization of +<code>fork()</code> allowing the new process to share the memory +space, file descriptors, and signal handlers of the parent.<P> + +Advantages of the "one-to-one" model include: +<UL> +<LI> minimal overhead on CPU-intensive multiprocessing (with +about one thread per processor); +<LI> minimal overhead on I/O operations; +<LI> a simple and robust implementation (the kernel scheduler does +most of the hard work for us). +</UL> +The main disadvantage is more expensive context switches on mutex and +condition operations, which must go through the kernel. This is +mitigated by the fact that context switches in the Linux kernel are +pretty efficient.<P> + +<H4><A NAME="K.2">K.2: Have you considered other implementation +models?</A></H4> + +There are basically two other models. The "many-to-one" model +relies on a user-level scheduler that context-switches between the +threads entirely in user code; viewed from the kernel, there is only +one process running. This model is completely out of the question for +me, since it does not take advantage of multiprocessors, and require +unholy magic to handle blocking I/O operations properly. There are +several user-level thread libraries available for Linux, but I found +all of them deficient in functionality, performance, and/or robustness. +<P> + +The "many-to-many" model combines both kernel-level and user-level +scheduling: several kernel-level threads run concurrently, each +executing a user-level scheduler that selects between user threads. +Most commercial Unix systems (Solaris, Digital Unix, IRIX) implement +POSIX threads this way. This model combines the advantages of both +the "many-to-one" and the "one-to-one" model, and is attractive +because it avoids the worst-case behaviors of both models -- +especially on kernels where context switches are expensive, such as +Digital Unix. Unfortunately, it is pretty complex to implement, and +requires kernel support which Linux does not provide. Linus Torvalds +and other Linux kernel developers have always been pushing the +"one-to-one" model in the name of overall simplicity, and are doing a +pretty good job of making kernel-level context switches between +threads efficient. LinuxThreads is just following the general +direction they set.<P> + +<HR> +<ADDRESS>Xavier.Leroy@inria.fr</ADDRESS> +</BODY> +</HTML> diff --git a/linuxthreads/LICENSE b/linuxthreads/LICENSE new file mode 100644 index 0000000000..7bcca60504 --- /dev/null +++ b/linuxthreads/LICENSE @@ -0,0 +1,501 @@ +GNU LIBRARY GENERAL PUBLIC LICENSE +********************************** + + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 59 Temple Place -- Suite 330, Boston, MA 02111-1307, USA + + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + [This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + +Preamble +======== + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it in +new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License, which was designed for utility +programs. This license, the GNU Library General Public License, +applies to certain designated libraries. This license is quite +different from the ordinary one; be sure to read it in full, and don't +assume that anything in it is the same as in the ordinary license. + + The reason we have a separate public license for some libraries is +that they blur the distinction we usually make between modifying or +adding to a program and simply using it. Linking a program with a +library, without changing the library, is in some sense simply using +the library, and is analogous to running a utility program or +application program. However, in a textual and legal sense, the linked +executable is a combined work, a derivative of the original library, +and the ordinary General Public License treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended +to permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to +achieve this as regards changes in header files, but we have achieved +it as regards changes in the actual functions of the Library.) The +hope is that this will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which + contains a notice placed by the copyright holder or other + authorized party saying it may be distributed under the terms of + this Library General Public License (also called "this License"). + Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data + prepared so as to be conveniently linked with application programs + (which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work + which has been distributed under these terms. A "work based on the + Library" means either the Library or any derivative work under + copyright law: that is to say, a work containing the Library or a + portion of it, either verbatim or with modifications and/or + translated straightforwardly into another language. (Hereinafter, + translation is included without limitation in the term + "modification".) + + "Source code" for a work means the preferred form of the work for + making modifications to it. For a library, complete source code + means all the source code for all modules it contains, plus any + associated interface definition files, plus the scripts used to + control compilation and installation of the library. + + Activities other than copying, distribution and modification are + not covered by this License; they are outside its scope. The act + of running a program using the Library is not restricted, and + output from such a program is covered only if its contents + constitute a work based on the Library (independent of the use of + the Library in a tool for writing it). Whether that is true + depends on what the Library does and what the program that uses + the Library does. + + 1. You may copy and distribute verbatim copies of the Library's + complete source code as you receive it, in any medium, provided + that you conspicuously and appropriately publish on each copy an + appropriate copyright notice and disclaimer of warranty; keep + intact all the notices that refer to this License and to the + absence of any warranty; and distribute a copy of this License + along with the Library. + + You may charge a fee for the physical act of transferring a copy, + and you may at your option offer warranty protection in exchange + for a fee. + + 2. You may modify your copy or copies of the Library or any portion + of it, thus forming a work based on the Library, and copy and + distribute such modifications or work under the terms of Section 1 + above, provided that you also meet all of these conditions: + + a. The modified work must itself be a software library. + + b. You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c. You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d. If a facility in the modified Library refers to a function or + a table of data to be supplied by an application program that + uses the facility, other than as an argument passed when the + facility is invoked, then you must make a good faith effort + to ensure that, in the event an application does not supply + such function or table, the facility still operates, and + performs whatever part of its purpose remains meaningful. + + (For example, a function in a library to compute square roots + has a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function + must be optional: if the application does not supply it, the + square root function must still compute square roots.) + + These requirements apply to the modified work as a whole. If + identifiable sections of that work are not derived from the + Library, and can be reasonably considered independent and separate + works in themselves, then this License, and its terms, do not + apply to those sections when you distribute them as separate + works. But when you distribute the same sections as part of a + whole which is a work based on the Library, the distribution of + the whole must be on the terms of this License, whose permissions + for other licensees extend to the entire whole, and thus to each + and every part regardless of who wrote it. + + Thus, it is not the intent of this section to claim rights or + contest your rights to work written entirely by you; rather, the + intent is to exercise the right to control the distribution of + derivative or collective works based on the Library. + + In addition, mere aggregation of another work not based on the + Library with the Library (or with a work based on the Library) on + a volume of a storage or distribution medium does not bring the + other work under the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public + License instead of this License to a given copy of the Library. + To do this, you must alter all the notices that refer to this + License, so that they refer to the ordinary GNU General Public + License, version 2, instead of to this License. (If a newer + version than version 2 of the ordinary GNU General Public License + has appeared, then you can specify that version instead if you + wish.) Do not make any other change in these notices. + + Once this change is made in a given copy, it is irreversible for + that copy, so the ordinary GNU General Public License applies to + all subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of + the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or + derivative of it, under Section 2) in object code or executable + form under the terms of Sections 1 and 2 above provided that you + accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software + interchange. + + If distribution of object code is made by offering access to copy + from a designated place, then offering equivalent access to copy + the source code from the same place satisfies the requirement to + distribute the source code, even though third parties are not + compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the + Library, but is designed to work with the Library by being + compiled or linked with it, is called a "work that uses the + Library". Such a work, in isolation, is not a derivative work of + the Library, and therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library + creates an executable that is a derivative of the Library (because + it contains portions of the Library), rather than a "work that + uses the library". The executable is therefore covered by this + License. Section 6 states terms for distribution of such + executables. + + When a "work that uses the Library" uses material from a header + file that is part of the Library, the object code for the work may + be a derivative work of the Library even though the source code is + not. Whether this is true is especially significant if the work + can be linked without the Library, or if the work is itself a + library. The threshold for this to be true is not precisely + defined by law. + + If such an object file uses only numerical parameters, data + structure layouts and accessors, and small macros and small inline + functions (ten lines or less in length), then the use of the object + file is unrestricted, regardless of whether it is legally a + derivative work. (Executables containing this object code plus + portions of the Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may + distribute the object code for the work under the terms of Section + 6. Any executables containing that work also fall under Section 6, + whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or + link a "work that uses the Library" with the Library to produce a + work containing portions of the Library, and distribute that work + under terms of your choice, provided that the terms permit + modification of the work for the customer's own use and reverse + engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the + Library is used in it and that the Library and its use are covered + by this License. You must supply a copy of this License. If the + work during execution displays copyright notices, you must include + the copyright notice for the Library among them, as well as a + reference directing the user to the copy of this License. Also, + you must do one of these things: + + a. Accompany the work with the complete corresponding + machine-readable source code for the Library including + whatever changes were used in the work (which must be + distributed under Sections 1 and 2 above); and, if the work + is an executable linked with the Library, with the complete + machine-readable "work that uses the Library", as object code + and/or source code, so that the user can modify the Library + and then relink to produce a modified executable containing + the modified Library. (It is understood that the user who + changes the contents of definitions files in the Library will + not necessarily be able to recompile the application to use + the modified definitions.) + + b. Accompany the work with a written offer, valid for at least + three years, to give the same user the materials specified in + Subsection 6a, above, for a charge no more than the cost of + performing this distribution. + + c. If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the + above specified materials from the same place. + + d. Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the + Library" must include any data and utility programs needed for + reproducing the executable from it. However, as a special + exception, the source code distributed need not include anything + that is normally distributed (in either source or binary form) + with the major components (compiler, kernel, and so on) of the + operating system on which the executable runs, unless that + component itself accompanies the executable. + + It may happen that this requirement contradicts the license + restrictions of other proprietary libraries that do not normally + accompany the operating system. Such a contradiction means you + cannot use both them and the Library together in an executable + that you distribute. + + 7. You may place library facilities that are a work based on the + Library side-by-side in a single library together with other + library facilities not covered by this License, and distribute + such a combined library, provided that the separate distribution + of the work based on the Library and of the other library + facilities is otherwise permitted, and provided that you do these + two things: + + a. Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b. Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same + work. + + 8. You may not copy, modify, sublicense, link with, or distribute the + Library except as expressly provided under this License. Any + attempt otherwise to copy, modify, sublicense, link with, or + distribute the Library is void, and will automatically terminate + your rights under this License. However, parties who have + received copies, or rights, from you under this License will not + have their licenses terminated so long as such parties remain in + full compliance. + + 9. You are not required to accept this License, since you have not + signed it. However, nothing else grants you permission to modify + or distribute the Library or its derivative works. These actions + are prohibited by law if you do not accept this License. + Therefore, by modifying or distributing the Library (or any work + based on the Library), you indicate your acceptance of this + License to do so, and all its terms and conditions for copying, + distributing or modifying the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the + Library), the recipient automatically receives a license from the + original licensor to copy, distribute, link with or modify the + Library subject to these terms and conditions. You may not impose + any further restrictions on the recipients' exercise of the rights + granted herein. You are not responsible for enforcing compliance + by third parties to this License. + + 11. If, as a consequence of a court judgment or allegation of patent + infringement or for any other reason (not limited to patent + issues), conditions are imposed on you (whether by court order, + agreement or otherwise) that contradict the conditions of this + License, they do not excuse you from the conditions of this + License. If you cannot distribute so as to satisfy simultaneously + your obligations under this License and any other pertinent + obligations, then as a consequence you may not distribute the + Library at all. For example, if a patent license would not permit + royalty-free redistribution of the Library by all those who + receive copies directly or indirectly through you, then the only + way you could satisfy both it and this License would be to refrain + entirely from distribution of the Library. + + If any portion of this section is held invalid or unenforceable + under any particular circumstance, the balance of the section is + intended to apply, and the section as a whole is intended to apply + in other circumstances. + + It is not the purpose of this section to induce you to infringe any + patents or other property right claims or to contest validity of + any such claims; this section has the sole purpose of protecting + the integrity of the free software distribution system which is + implemented by public license practices. Many people have made + generous contributions to the wide range of software distributed + through that system in reliance on consistent application of that + system; it is up to the author/donor to decide if he or she is + willing to distribute software through any other system and a + licensee cannot impose that choice. + + This section is intended to make thoroughly clear what is believed + to be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in + certain countries either by patents or by copyrighted interfaces, + the original copyright holder who places the Library under this + License may add an explicit geographical distribution limitation + excluding those countries, so that distribution is permitted only + in or among countries not thus excluded. In such case, this + License incorporates the limitation as if written in the body of + this License. + + 13. The Free Software Foundation may publish revised and/or new + versions of the Library General Public License from time to time. + Such new versions will be similar in spirit to the present version, + but may differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the + Library specifies a version number of this License which applies + to it and "any later version", you have the option of following + the terms and conditions either of that version or of any later + version published by the Free Software Foundation. If the Library + does not specify a license version number, you may choose any + version ever published by the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free + programs whose distribution conditions are incompatible with these, + write to the author to ask for permission. For software which is + copyrighted by the Free Software Foundation, write to the Free + Software Foundation; we sometimes make exceptions for this. Our + decision will be guided by the two goals of preserving the free + status of all derivatives of our free software and of promoting + the sharing and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO + WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE + LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT + HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT + WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT + NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE + QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE + LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY + SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN + WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY + MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE + LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, + INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR + INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF + DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU + OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY + OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + +How to Apply These Terms to Your New Libraries +============================================== + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of +the ordinary General Public License). + + To apply these terms, attach the following notices to the library. +It is safest to attach them to the start of each source file to most +effectively convey the exclusion of warranty; and each file should have +at least the "copyright" line and a pointer to where the full notice is +found. + + ONE LINE TO GIVE THE LIBRARY'S NAME AND AN IDEA OF WHAT IT DOES. + Copyright (C) YEAR NAME OF AUTHOR + + This 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. + + This library is distributed in the hope that 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 General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + + Also add information on how to contact you by electronic and paper +mail. + + You should also get your employer (if you work as a programmer) or +your school, if any, to sign a "copyright disclaimer" for the library, +if necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the library + `Frob' (a library for tweaking knobs) written by James Random Hacker. + + SIGNATURE OF TY COON, 1 April 1990 + Ty Coon, President of Vice + + That's all there is to it! + diff --git a/linuxthreads/Makeconfig b/linuxthreads/Makeconfig new file mode 100644 index 0000000000..5470c22b97 --- /dev/null +++ b/linuxthreads/Makeconfig @@ -0,0 +1,11 @@ +# Makeconfig fragment for linuxthreads add-on. +# This gets included at the end of the main glibc Makeconfig. + +have-thread-library = yes + +shared-thread-library = $(common-objpfx)linuxthreads/libpthread_nonshared.a \ + $(common-objpfx)linuxthreads/libpthread.so +static-thread-library = $(common-objpfx)linuxthreads/libpthread.a +bounded-thread-library = $(common-objpfx)linuxthreads/libpthread_b.a + +rpath-dirs += linuxthreads diff --git a/linuxthreads/Makefile b/linuxthreads/Makefile new file mode 100644 index 0000000000..3f06c41276 --- /dev/null +++ b/linuxthreads/Makefile @@ -0,0 +1,345 @@ +# Copyright (C) 1996-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. + +# +# Sub-makefile for linuxthreads portion of the library. +# +subdir := linuxthreads + +all: # Make this the default target; it will be defined in Rules. + +linuxthreads-version := $(shell sed -n 's/^.*$(subdir)-\([0-9.]*\).*$$/\1/p' \ + Banner) +libpthread-abi-frozen := GLIBC_2.3.2 + +headers := pthread.h semaphore.h +distribute := internals.h queue.h restart.h spinlock.h smp.h tst-signal.sh \ + tst-cancel-wrappers.sh libc-tsd.c + +routines := forward alloca_cutoff libc-cancellation libc_pthread_init +shared-only-routines = forward + +extra-libs := libpthread +extra-libs-others := $(extra-libs) +install-lib-ldscripts := libpthread.so + +libpthread-routines := attr cancel condvar join manager mutex ptfork \ + ptlongjmp pthread pt-sigsuspend signals specific errno \ + lockfile semaphore spinlock rwlock pt-machine \ + oldsemaphore events getcpuclockid pspinlock barrier \ + ptclock_gettime ptclock_settime sighandler \ + pthandles libc-tls-loc pt-allocrtsig \ + 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-lseek64 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 pt-system old_pthread_atfork pthread_atfork \ + ptcleanup +# pthread_setuid pthread_seteuid pthread_setreuid \ +# pthread_setresuid \ +# pthread_setgid pthread_setegid pthread_setregid \ +# pthread_setresgid + +# Don't generate deps for calls with no sources. See sysdeps/unix/Makefile. +omit-deps = $(unix-syscalls:%=ptw-%) + +libpthread-shared-only-routines = pt-allocrtsig +libpthread-static-only-routines = pthread_atfork + +linuxthreads-CPPFLAGS = -DIS_IN_linuxthreads=1 + +CFLAGS-pthread_atfork.c = -DNOT_IN_libc + +nodelete-yes = -Wl,--enable-new-dtags,-z,nodelete +initfirst-yes = -Wl,--enable-new-dtags,-z,initfirst +LDFLAGS-pthread.so = $(nodelete-$(have-z-nodelete)) \ + $(initfirst-$(have-z-initfirst)) + +vpath %.c Examples + +tst-cancel-ARGS = "$(objpfx)" +CFLAGS-tst-cancel.c = -fno-inline -fno-inline-functions + +include ../Makeconfig + +ifeq ($(build-shared),yes) + +# Set the `multidir' variable by grabbing the variable from the compiler. +# We do it once and save the result in a generated makefile. +-include $(objpfx)multidir.mk +$(objpfx)multidir.mk: $(common-objpfx)config.make + $(make-target-directory) + dir=`$(CC) $(CFLAGS) $(CPPFLAGS) -print-multi-directory`; \ + echo "multidir := $$dir" > $@T + mv -f $@T $@ +generated += multidir.mk + +crti-objs := crti.o +crtn-objs := crtn.o +ifneq (,$(patsubst .,,$(multidir))) +generated-dirs := $(firstword $(subst /, , $(multidir))) +crti-objs += $(multidir)/crti.o +crtn-objs += $(multidir)/crtn.o +omit-deps += $(multidir)/crti $(multidir)/crtn +endif +extra-objs += $(crti-objs) $(crtn-objs) +omit-deps += crti crtn + +CFLAGS-pt-initfini.s = -g0 -fPIC -fno-inline-functions $(fno-unit-at-a-time) +endif + +librt-tests = ex10 ex11 tst-clock1 +tests = ex1 ex2 ex3 ex4 ex5 ex6 ex7 ex8 ex9 $(librt-tests) ex12 ex13 joinrace \ + tststack $(tests-nodelete-$(have-z-nodelete)) ecmutex ex14 ex15 ex16 \ + ex17 ex18 tst-cancel tst-context bug-sleep \ + tst-cancel1 tst-cancel2 tst-cancel3 tst-cancel4 tst-cancel5 \ + tst-cancel6 tst-cancel7 tst-cancel8 tst-popen tst-popen2 tst-attr1 \ + tst-stack1 +test-srcs = tst-signal +# These tests are linked with libc before libpthread +tests-reverse += tst-cancel5 + +ifeq ($(build-static),yes) +tests += tststatic tst-static-locale tst-cancel-static +tests-static += tststatic tst-static-locale tst-cancel-static +endif + +ifeq (yes,$(build-shared)) +tests-nodelete-yes = unload +tests += tst-tls1 tst-_res1 +endif + +modules-names = tst-_res1mod1 tst-_res1mod2 \ + tst-tls1mod tst-tls1moda tst-tls1modb tst-tls1modc \ + tst-tls1modd tst-tls1mode tst-tls1modf +extra-objs += $(addsuffix .os,$(strip $(modules-names))) +generated += $(addsuffix .so,$(strip $(modules-names))) +test-extras += $(modules-names) +test-modules = $(addprefix $(objpfx),$(addsuffix .so,$(modules-names))) + +tst-tls1mod.so-no-z-defs = yes +tst-tls1moda.so-no-z-defs = yes +tst-tls1modb.so-no-z-defs = yes +tst-tls1modc.so-no-z-defs = yes +tst-tls1modd.so-no-z-defs = yes +tst-tls1mode.so-no-z-defs = yes +tst-tls1modf.so-no-z-defs = yes + +$(test-modules): $(objpfx)%.so: $(objpfx)%.os $(common-objpfx)shlib.lds + $(build-module) + +ifeq ($(build-shared),yes) +# Build all the modules even when not actually running test programs. +tests: $(test-modules) +endif + +# What we install as libpthread.so for programs to link against is in fact a +# link script. It contains references for the various libraries we need. +# The libpthread.so object is not complete since some functions are only defined +# in libpthread_nonshared.a. +# We need to use absolute paths since otherwise local copies (if they exist) +# of the files are taken by the linker. +install: $(inst_libdir)/libpthread.so +$(inst_libdir)/libpthread.so: $(common-objpfx)format.lds \ + $(objpfx)libpthread.so$(libpthread.so-version) \ + $(inst_libdir)/$(patsubst %,$(libtype.oS),\ + $(libprefix)pthread) \ + $(+force) + (echo '/* GNU ld script';\ + echo ' Use the shared library, but some functions are only in';\ + echo ' the static library, so try that secondarily. */';\ + cat $<; \ + echo 'GROUP ( $(slibdir)/libpthread.so$(libpthread.so-version)' \ + '$(libdir)/$(patsubst %,$(libtype.oS),$(libprefix)pthread)'\ + ')' \ + ) > $@.new + mv -f $@.new $@ + + +extra-B-pthread.so = -B$(common-objpfx)linuxthreads/ +$(objpfx)libpthread.so: $(addprefix $(objpfx),$(crti-objs) $(crtn-objs)) +$(objpfx)libpthread.so: +preinit += $(addprefix $(objpfx),$(crti-objs)) +$(objpfx)libpthread.so: +postinit += $(addprefix $(objpfx),$(crtn-objs)) + +znodelete-yes = -DHAVE_Z_NODELETE +CFLAGS-mutex.c += -D__NO_WEAK_PTHREAD_ALIASES +CFLAGS-specific.c += -D__NO_WEAK_PTHREAD_ALIASES +CFLAGS-pthread.c += -D__NO_WEAK_PTHREAD_ALIASES $(znodelete-$(have-z-nodelete)) +CFLAGS-ptfork.c += -D__NO_WEAK_PTHREAD_ALIASES +CFLAGS-cancel.c += -D__NO_WEAK_PTHREAD_ALIASES -D_RPC_THREAD_SAFE_ +CFLAGS-unload.c += -DPREFIX=\"$(objpfx)\" +CFLAGS-mutex.c += $(uses-callbacks) +CFLAGS-sighandler.c += $(uses-callbacks) + +ifeq (yes,$(versioning)) +-include $(common-objpfx)tls.make +libc-ok-for-link = $(use-thread) +else +libc-ok-for-link = yes +endif + +ifeq (no,$(libc-ok-for-link)) +# These hacks are necessary to let us link against a libc.so that exports +# the symbols _errno, _h_errno, and _res. Those symbols are accessible +# in libc at runtime (dynamic linkable), but are not exported at link time +# so that applications cannot link against them. However, libpthread.so +# needs to link against them for its __errno_location et al functions to +# find the locations that libc's symbols resolve to. We cannot do this +# with aliases in libc.so(GLIBC_PRIVATE), because we need to refer to an +# executable's symbols when it defines them with copy relocs. +libc-link.so = $(objpfx)libc.so + +$(objpfx)libc_pic_lite.a: $(common-objpfx)libc_pic.a + cp $< $@T + $(AR) d $@T errno.os herrno.os res_libc.os + mv -f $@T $@ + +extra-objs += libc-tsd.os +$(objpfx)libc_pic_lite.os: $(objpfx)libc_pic_lite.a $(objpfx)libc-tsd.os + $(LINK.o) -nostdlib -nostartfiles -r -o $@ \ + $(LDFLAGS-c_pic.os) -Wl,-d -Wl,--whole-archive $^ + +# This trick leaves errno and h_errno undefined. +libc.so-no-z-defs = yes + +$(objpfx)libc.so: $(elfobjdir)/soinit.os \ + $(objpfx)libc_pic_lite.os \ + $(elfobjdir)/sofini.os \ + $(elfobjdir)/interp.os $(elfobjdir)/ld.so + $(build-shlib) + +generated += libc_pic_lite.a libc_pic_lite.os libc.so libc-tsd.os +else +libc-link.so = $(common-objpfx)libc.so +endif + +include ../Rules + +# Depend on libc.so so a DT_NEEDED is generated in the shared objects. +# This ensures they will load libc.so for needed symbols if loaded by +# a statically-linked program that hasn't already loaded it. +# Depend on ld.so too to get proper versions of ld.so symbols. +$(objpfx)libpthread.so: $(libc-link.so) $(common-objpfx)libc_nonshared.a \ + $(if $(filter yes,$(elf)), $(elfobjdir)/ld.so) + +# Make sure we link with the thread library. +ifeq ($(build-shared),yes) +$(addprefix $(objpfx), \ + $(filter-out $(tests-static) $(tests-reverse) unload, \ + $(tests) $(test-srcs))): $(objpfx)libpthread.so \ + $(objpfx)libpthread_nonshared.a +# $(objpfx)../libc.so is used instead of $(common-objpfx)libc.so, +# since otherwise libpthread.so comes before libc.so when linking. +$(addprefix $(objpfx), $(tests-reverse)): \ + $(objpfx)../libc.so $(objpfx)libpthread.so \ + $(objpfx)libpthread_nonshared.a +$(objpfx)../libc.so: $(common-objpfx)libc.so ; +$(addprefix $(objpfx),$(librt-tests)): $(common-objpfx)rt/librt.so +$(objpfx)unload: $(common-objpfx)dlfcn/libdl.so +$(objpfx)unload.out: $(objpfx)libpthread.so $(objpfx)libpthread_nonshared.a +else +$(addprefix $(objpfx),$(tests) $(test-srcs)): $(objpfx)libpthread.a +$(addprefix $(objpfx),$(librt-tests)): $(common-objpfx)rt/librt.a +endif +ifeq ($(build-bounded),yes) +$(tests:%=$(objpfx)%-bp): $(objpfx)libpthread_b.a +$(librt-tests:%=$(objpfx)%-bp): $(common-objpfx)rt/librt_b.a +endif + +ifeq ($(build-static),yes) +$(addprefix $(objpfx), $(tests-static)): $(objpfx)libpthread.a +endif + +ifeq ($(build-shared),yes) +vpath pt-initfini.c $(full_config_sysdirs) + +$(objpfx)pt-initfini.s: pt-initfini.c + $(compile.c) -S $(CFLAGS-pt-initfini.s) -finhibit-size-directive \ + $(patsubst -f%,-fno-%,$(exceptions)) -o $@ + +# We only have one kind of startup code files. Static binaries and +# shared libraries are build using the PIC version. +$(objpfx)crti.S: $(objpfx)pt-initfini.s + sed -n -e '1,/@HEADER_ENDS/p' \ + -e '/@_.*_PROLOG_BEGINS/,/@_.*_PROLOG_ENDS/p' \ + -e '/@TRAILER_BEGINS/,$$p' $< > $@ +$(objpfx)crtn.S: $(objpfx)pt-initfini.s + sed -n -e '1,/@HEADER_ENDS/p' \ + -e '/@_.*_EPILOG_BEGINS/,/@_.*_EPILOG_ENDS/p' \ + -e '/@TRAILER_BEGINS/,$$p' $< > $@ + +$(objpfx)defs.h: $(objpfx)pt-initfini.s + sed -n -e '/@TESTS_BEGIN/,/@TESTS_END/p' $< | \ + $(AWK) -f ../csu/defs.awk > $@ + +$(objpfx)crti.o: $(objpfx)crti.S $(objpfx)defs.h + $(compile.S) -g0 $(ASFLAGS-.os) -o $@ + +$(objpfx)crtn.o: $(objpfx)crtn.S $(objpfx)defs.h + $(compile.S) -g0 $(ASFLAGS-.os) -o $@ + +ifneq ($(multidir),.) +$(objpfx)$(multidir): + @mkdir -p $(objpfx)$(multidir) + +$(objpfx)$(multidir)/crti.o: $(objpfx)crti.o $(objpfx)$(multidir) + ln -f $< $@ + +$(objpfx)$(multidir)/crtn.o: $(objpfx)crtn.o $(objpfx)$(multidir) + ln -f $< $@ +endif + +generated += crti.S crtn.S defs.h pt-initfini.s libpthread_nonshared.a +endif + +ifeq (yes,$(build-static-nss)) +otherlibs += $(nssobjdir)/libnss_files.a $(resolvobjdir)/libnss_dns.a \ + $(resolvobjdir)/libresolv.a +endif + +ifeq (yes,$(build-shared)) +$(objpfx)tst-_res1mod2.so: $(objpfx)tst-_res1mod1.so +$(objpfx)tst-_res1: $(objpfx)tst-_res1mod2.so $(shared-thread-library) + +$(objpfx)tst-tls1: $(objpfx)tst-tls1mod.so $(shared-thread-library) + +tests: $(objpfx)tst-tls2.out +$(objpfx)tst-tls2.out: tst-tls2.sh $(objpfx)tst-tls1 \ + $(objpfx)tst-tls1moda.so $(objpfx)tst-tls1modb.so \ + $(objpfx)tst-tls1modc.so $(objpfx)tst-tls1modd.so \ + $(objpfx)tst-tls1mode.so $(objpfx)tst-tls1modf.so + $(SHELL) -e tst-tls2.sh $(common-objpfx) $(elf-objpfx) \ + $(rtld-installed-name) +generated += tst-tls2.out +endif + +ifeq (no,$(cross-compiling)) +ifeq (yes,$(build-shared)) +tests: $(objpfx)tst-signal.out $(objpfx)tst-cancel-wrappers.out +$(objpfx)tst-signal.out: tst-signal.sh $(objpfx)tst-signal + $(SHELL) -e $< $(common-objpfx) > $@ +$(objpfx)tst-cancel-wrappers.out: tst-cancel-wrappers.sh + $(SHELL) $< $(common-objpfx)/libc_pic.a \ + $(common-objpfx)/libc.a \ + $(objpfx)/libpthread_pic.a \ + $(objpfx)/libpthread.a > $@ +generated += tst-signal.out tst-cancel-wrappers.out +endif +endif diff --git a/linuxthreads/README b/linuxthreads/README new file mode 100644 index 0000000000..955bd59e7a --- /dev/null +++ b/linuxthreads/README @@ -0,0 +1,166 @@ + Linuxthreads - POSIX 1003.1c kernel threads for Linux + + Copyright 1996, 1997 Xavier Leroy (Xavier.Leroy@inria.fr) + + +DESCRIPTION: + +This is release 0.7 (late beta) of LinuxThreads, a BiCapitalized +implementation of the Posix 1003.1c "pthread" interface for Linux. + +LinuxThreads provides kernel-level threads: each thread is a separate +Unix process, sharing its address space with the other threads through +the new system call clone(). Scheduling between threads is handled by +the kernel scheduler, just like scheduling between Unix processes. + + +REQUIREMENTS: + +- Linux version 2.0 and up (requires the new clone() system call + and the new realtime scheduler). + +- For Intel platforms: libc 5.2.18 or later is required. + 5.2.18 or 5.4.12 or later are recommended; + 5.3.12 and 5.4.7 have problems (see the FAQ.html file for more info). + +- Also supports glibc 2 (a.k.a. libc 6), which actually comes with + a specially-adapted version of this library. + +- Currently supports Intel, Alpha, Sparc, Motorola 68k, ARM and MIPS + platforms. + +- Multiprocessors are supported. + + +INSTALLATION: + +- Edit the Makefile, set the variables in the "Configuration" section. + +- Do "make". + +- Do "make install". + + +USING LINUXTHREADS: + + gcc -D_REENTRANT ... -lpthread + +A complete set of manual pages is included. Also see the subdirectory +Examples/ for some sample programs. + + +STATUS: + +- All functions in the Posix 1003.1c base interface implemented. + Also supports priority scheduling. + +- For users of libc 5 (H.J.Lu's libc), a number of C library functions + are reimplemented or wrapped to make them thread-safe, including: + * malloc functions + * stdio functions (define _REENTRANT before including <stdio.h>) + * per-thread errno variable (define _REENTRANT before including <errno.h>) + * directory reading functions (opendir(), etc) + * sleep() + * gmtime(), localtime() + + New library functions provided: + * flockfile(), funlockfile(), ftrylockfile() + * reentrant versions of network database functions (gethostbyname_r(), etc) + and password functions (getpwnam_r(), etc). + +- libc 6 (glibc 2) provides much better thread support than libc 5, + and comes with a specially-adapted version of LinuxThreads. + For serious multithreaded programming, you should consider switching + to glibc 2. It is available from ftp.gnu.org:/pub/gnu and its mirrors. + + +WARNING: + +Many existing libraries are not compatible with LinuxThreads, +either because they are not inherently thread-safe, or because they +have not been compiled with the -D_REENTRANT. For more info, see the +FAQ.html file in this directory. + +A prime example of the latter is Xlib. If you link it with +LinuxThreads, you'll probably get an "unknown 0 error" very +early. This is just a consequence of the Xlib binaries using the +global variable "errno" to fetch error codes, while LinuxThreads and +the C library use the per-thread "errno" location. + +See the file README.Xfree3.3 for info on how to compile the Xfree 3.3 +libraries to make them compatible with LinuxThreads. + + +KNOWN BUGS AND LIMITATIONS: + +- Threads share pretty much everything they should share according + to the standard: memory space, file descriptors, signal handlers, + current working directory, etc. One thing that they do not share + is their pid's and parent pid's. According to the standard, they + should have the same, but that's one thing we cannot achieve + in this implementation (until the CLONE_PID flag to clone() becomes + usable). + +- The current implementation uses the two signals SIGUSR1 and SIGUSR2, + so user-level code cannot employ them. Ideally, there should be two + signals reserved for this library. One signal is used for restarting + threads blocked on mutexes or conditions; the other is for thread + cancellation. + + *** This is not anymore true when the application runs on a kernel + newer than approximately 2.1.60. + +- The stacks for the threads are allocated high in the memory space, + below the stack of the initial process, and spaced 2M apart. + Stacks are allocated with the "grow on demand" flag, so they don't + use much virtual space initially (4k, currently), but can grow + up to 2M if needed. + + Reserving such a large address space for each thread means that, + on a 32-bit architecture, no more than about 1000 threads can + coexist (assuming a 2Gb address space for user processes), + but this is reasonable, since each thread uses up one entry in the + kernel's process table, which is usually limited to 512 processes. + + Another potential problem of the "grow on demand" scheme is that + nothing prevents the user from mmap'ing something in the 2M address + window reserved for a thread stack, possibly causing later extensions of + that stack to fail. Mapping at fixed addresses should be avoided + when using this library. + +- Signal handling does not fully conform to the Posix standard, + due to the fact that threads are here distinct processes that can be + sent signals individually, so there's no notion of sending a signal + to "the" process (the collection of all threads). + More precisely, here is a summary of the standard requirements + and how they are met by the implementation: + + 1- Synchronous signals (generated by the thread execution, e.g. SIGFPE) + are delivered to the thread that raised them. + (OK.) + + 2- A fatal asynchronous signal terminates all threads in the process. + (OK. The thread manager notices when a thread dies on a signal + and kills all other threads with the same signal.) + + 3- An asynchronous signal will be delivered to one of the threads + of the program which does not block the signal (it is unspecified + which). + (No, the signal is delivered to the thread it's been sent to, + based on the pid of the thread. If that thread is currently + blocking the signal, the signal remains pending.) + + 4- The signal will be delivered to at most one thread. + (OK, except for signals generated from the terminal or sent to + the process group, which will be delivered to all threads.) + +- The current implementation of the MIPS support assumes a MIPS ISA II + processor or better. These processors support atomic operations by + ll/sc instructions. Older R2000/R3000 series processors are not + supported yet; support for these will have higher overhead. + +- The current implementation of the ARM support assumes that the SWP + (atomic swap register with memory) instruction is available. This is + the case for all processors except for the ARM1 and ARM2. On StrongARM, + the SWP instruction does not bypass the cache, so multi-processor support + will be more troublesome. diff --git a/linuxthreads/README.Xfree3.2 b/linuxthreads/README.Xfree3.2 new file mode 100644 index 0000000000..ac08e15832 --- /dev/null +++ b/linuxthreads/README.Xfree3.2 @@ -0,0 +1,352 @@ +This file describes how to make a threaded X11R6. + +You need the source-code of XFree-3.2. I used the sources of X11R6.1 +(files: xc-1.tar.gz xc-2.tar.gz xc-3.tar.gz) and the patches to +XFree-3.2 (files: README.X11.patch R6.1pl1-3.2.diff.gz cfont32.tgz). + +Untar the xc-?.tar.gz files in a directory called XF3.2 and apply +the XFree-3.2 patches as described in README.X11.patch or use the +whole XFree86 source. + +Now apply the thread patch with + +patch -p0 < XF3.2.xc.diff + +Go to the XF3.2/xc directory and make the whole thing: +nice make World >& world.log & +tail -f world.log + +Wait a few hours or interrupt the process after the shared libs +are made. The shared libs are: + +XF3.2/xc/lib/ICE/libICE.so.6.0* +XF3.2/xc/lib/PEX5/libPEX5.so.6.0* +XF3.2/xc/lib/SM/libSM.so.6.0* +XF3.2/xc/lib/X11/libX11.so.6.1* +XF3.2/xc/lib/XIE/libXIE.so.6.0* +XF3.2/xc/lib/XThrStub/libXThrStub.so.6.0* +XF3.2/xc/lib/Xaw/libXaw.so.6.1* +XF3.2/xc/lib/Xext/libXext.so.6.1* +XF3.2/xc/lib/Xi/libXi.so.6.0* +XF3.2/xc/lib/Xmu/libXmu.so.6.0* +XF3.2/xc/lib/Xt/libXt.so.6.0* +XF3.2/xc/lib/Xtst/libXtst.so.6.1* + +(The Program dga didn't compile, but I have not check out why.) + +Now you can copy the resulting libs + +cp XF3.2/xc/lib/*/*.so.?.? /usr/X11R6/lib/ + +and create some links + +cd /usr/X11R6/lib/ +ln -s libXThrStub.so.6.0 libXThrStub.so.6 +ln -s libXThrStub.so.6 libXThrStub.so + +or use make install (not tested, and needs new configuration). + +It is possible with the libXThrSub to compile X11 programs without linking +libpthread to them and not necessary to recompile already installed +unthreaded X11 programs, because libXThrSub keeps the dynamic linker quit. +On the other hand you can link libpthread to a X11 program to use threads. + +I used linux 2.0.23 and libc 5.4.7 . + +Hans-Helmut Bühmann hans@expmech.ing.tu-bs.de + +---------------------------------------------------------------------------- + +XF3.2.xc.diff: +----------------------------------------------------------------------------- +diff -u --recursive XF3.2.orig/xc/config/cf/linux.cf XF3.2/xc/config/cf/linux.cf +--- XF3.2.orig/xc/config/cf/linux.cf Sun Nov 10 17:05:30 1996 ++++ XF3.2/xc/config/cf/linux.cf Sun Nov 10 16:30:55 1996 +@@ -61,6 +61,14 @@ + #define HasSnprintf YES + #endif + ++#define HasPosixThreads YES ++#define ThreadedX YES ++#define BuildThreadStubLibrary YES ++#define NeedUIThrStubs YES ++#define HasThreadSafeAPI NO ++#define SystemMTDefines -D_REENTRANT ++#define ThreadsLibraries -lpthread ++ + #define AvoidNullMakeCommand YES + #define StripInstalledPrograms YES + #define CompressAllFonts YES +@@ -158,7 +166,7 @@ + #define LdPostLib /* Never needed */ + + #ifdef i386Architecture +-#define OptimizedCDebugFlags DefaultGcc2i386Opt -m486 ++#define OptimizedCDebugFlags DefaultGcc2i386Opt -m486 -pipe + #define StandardDefines -Dlinux -D__i386__ -D_POSIX_SOURCE \ + -D_BSD_SOURCE -D_SVID_SOURCE -DX_LOCALE + #define XawI18nDefines -DUSE_XWCHAR_STRING -DUSE_XMBTOWC +diff -u --recursive XF3.2.orig/xc/config/cf/lnxLib.tmpl XF3.2/xc/config/cf/lnxLib.tmpl +--- XF3.2.orig/xc/config/cf/lnxLib.tmpl Sun Nov 10 17:05:30 1996 ++++ XF3.2/xc/config/cf/lnxLib.tmpl Sat Nov 9 14:52:39 1996 +@@ -19,7 +19,7 @@ + + #define CplusplusLibC + +-#define SharedX11Reqs ++#define SharedX11Reqs -L$(BUILDLIBDIR) -lXThrStub + #define SharedOldXReqs $(LDPRELIB) $(XLIBONLY) + #define SharedXtReqs $(LDPRELIB) $(XLIBONLY) $(SMLIB) $(ICELIB) + #define SharedXawReqs $(LDPRELIB) $(XMULIB) $(XTOOLLIB) $(XLIB) +diff -u --recursive XF3.2.orig/xc/include/Xthreads.h XF3.2/xc/include/Xthreads.h +--- XF3.2.orig/xc/include/Xthreads.h Thu Dec 7 02:19:09 1995 ++++ XF3.2/xc/include/Xthreads.h Sat Nov 9 01:04:55 1996 +@@ -229,12 +229,12 @@ + #define xcondition_wait(c,m) pthread_cond_wait(c,m) + #define xcondition_signal(c) pthread_cond_signal(c) + #define xcondition_broadcast(c) pthread_cond_broadcast(c) +-#ifdef _DECTHREADS_ ++#if defined(_DECTHREADS_) || defined(linux) + static xthread_t _X_no_thread_id; + #define xthread_have_id(id) !pthread_equal(id, _X_no_thread_id) + #define xthread_clear_id(id) id = _X_no_thread_id + #define xthread_equal(id1,id2) pthread_equal(id1, id2) +-#endif /* _DECTHREADS_ */ ++#endif /* _DECTHREADS_ || linux */ + #if _CMA_VENDOR_ == _CMA__IBM + #ifdef DEBUG /* too much of a hack to enable normally */ + /* see also cma__obj_set_name() */ +diff -u --recursive XF3.2.orig/xc/lib/X11/util/makekeys.c XF3.2/xc/lib/X11/util/makekeys.c +--- XF3.2.orig/xc/lib/X11/util/makekeys.c Mon Apr 18 02:22:22 1994 ++++ XF3.2/xc/lib/X11/util/makekeys.c Sat Nov 9 00:44:14 1996 +@@ -73,7 +73,7 @@ + register char c; + int first; + int best_max_rehash; +- int best_z; ++ int best_z = 0; + int num_found; + KeySym val; + +diff -u --recursive XF3.2.orig/xc/lib/XThrStub/Imakefile XF3.2/xc/lib/XThrStub/Imakefile +--- XF3.2.orig/xc/lib/XThrStub/Imakefile Sun Nov 10 17:08:12 1996 ++++ XF3.2/xc/lib/XThrStub/Imakefile Sat Nov 9 19:04:51 1996 +@@ -25,7 +25,7 @@ + DEFINES = $(ALLOC_DEFINES) + INCLUDES = + SRCS = $(STUBSRCS) +- OBJS = $(STUBOBJS ++ OBJS = $(STUBOBJS) + LINTLIBS = $(LINTXLIB) + + #include <Library.tmpl> +diff -u --recursive XF3.2.orig/xc/lib/XThrStub/UIThrStubs.c XF3.2/xc/lib/XThrStub/UIThrStubs.c +--- XF3.2.orig/xc/lib/XThrStub/UIThrStubs.c Sun Nov 10 17:08:12 1996 ++++ XF3.2/xc/lib/XThrStub/UIThrStubs.c Sun Nov 10 15:14:55 1996 +@@ -37,16 +37,43 @@ + * specificies the thread library on the link line. + */ + ++#if defined(linux) ++#include <pthread.h> ++#else + #include <thread.h> + #include <synch.h> ++#endif + ++#if defined(linux) ++static pthread_t no_thread_id; ++#endif /* defined(linux) */ ++ ++#if defined(linux) ++#pragma weak pthread_self = _Xthr_self_stub_ ++pthread_t ++_Xthr_self_stub_() ++{ ++ return(no_thread_id); ++} ++#else /* defined(linux) */ + #pragma weak thr_self = _Xthr_self_stub_ + thread_t + _Xthr_self_stub_() + { + return((thread_t)0); + } ++#endif /* defined(linux) */ + ++#if defined(linux) ++#pragma weak pthread_mutex_init = _Xmutex_init_stub_ ++int ++_Xmutex_init_stub_(m, a) ++ pthread_mutex_t *m; ++ __const pthread_mutexattr_t *a; ++{ ++ return(0); ++} ++#else /* defined(linux) */ + #pragma weak mutex_init = _Xmutex_init_stub_ + int + _Xmutex_init_stub_(m, t, a) +@@ -56,7 +83,17 @@ + { + return(0); + } ++#endif /* defined(linux) */ + ++#if defined(linux) ++#pragma weak pthread_mutex_destroy = _Xmutex_destroy_stub_ ++int ++_Xmutex_destroy_stub_(m) ++ pthread_mutex_t *m; ++{ ++ return(0); ++} ++#else /* defined(linux) */ + #pragma weak mutex_destroy = _Xmutex_destroy_stub_ + int + _Xmutex_destroy_stub_(m) +@@ -64,7 +101,17 @@ + { + return(0); + } ++#endif /* defined(linux) */ + ++#if defined(linux) ++#pragma weak pthread_mutex_lock = _Xmutex_lock_stub_ ++int ++_Xmutex_lock_stub_(m) ++ pthread_mutex_t *m; ++{ ++ return(0); ++} ++#else /* defined(linux) */ + #pragma weak mutex_lock = _Xmutex_lock_stub_ + int + _Xmutex_lock_stub_(m) +@@ -72,7 +119,17 @@ + { + return(0); + } ++#endif /* defined(linux) */ + ++#if defined(linux) ++#pragma weak pthread_mutex_unlock = _Xmutex_unlock_stub_ ++int ++_Xmutex_unlock_stub_(m) ++ pthread_mutex_t *m; ++{ ++ return(0); ++} ++#else /* defined(linux) */ + #pragma weak mutex_unlock = _Xmutex_unlock_stub_ + int + _Xmutex_unlock_stub_(m) +@@ -80,7 +137,18 @@ + { + return(0); + } ++#endif /* defined(linux) */ + ++#if defined(linux) ++#pragma weak pthread_cond_init = _Xcond_init_stub_ ++int ++_Xcond_init_stub_(c, a) ++ pthread_cond_t *c; ++ __const pthread_condattr_t *a; ++{ ++ return(0); ++} ++#else /* defined(linux) */ + #pragma weak cond_init = _Xcond_init_stub_ + int + _Xcond_init_stub_(c, t, a) +@@ -90,7 +158,17 @@ + { + return(0); + } ++#endif /* defined(linux) */ + ++#if defined(linux) ++#pragma weak pthread_cond_destroy = _Xcond_destroy_stub_ ++int ++_Xcond_destroy_stub_(c) ++ pthread_cond_t *c; ++{ ++ return(0); ++} ++#else /* defined(linux) */ + #pragma weak cond_destroy = _Xcond_destroy_stub_ + int + _Xcond_destroy_stub_(c) +@@ -98,7 +176,18 @@ + { + return(0); + } ++#endif /* defined(linux) */ + ++#if defined(linux) ++#pragma weak pthread_cond_wait = _Xcond_wait_stub_ ++int ++_Xcond_wait_stub_(c,m) ++ pthread_cond_t *c; ++ pthread_mutex_t *m; ++{ ++ return(0); ++} ++#else /* defined(linux) */ + #pragma weak cond_wait = _Xcond_wait_stub_ + int + _Xcond_wait_stub_(c,m) +@@ -107,7 +196,17 @@ + { + return(0); + } ++#endif /* defined(linux) */ + ++#if defined(linux) ++#pragma weak pthread_cond_signal = _Xcond_signal_stub_ ++int ++_Xcond_signal_stub_(c) ++ pthread_cond_t *c; ++{ ++ return(0); ++} ++#else /* defined(linux) */ + #pragma weak cond_signal = _Xcond_signal_stub_ + int + _Xcond_signal_stub_(c) +@@ -115,7 +214,17 @@ + { + return(0); + } ++#endif /* defined(linux) */ + ++#if defined(linux) ++#pragma weak pthread_cond_broadcast = _Xcond_broadcast_stub_ ++int ++_Xcond_broadcast_stub_(c) ++ pthread_cond_t *c; ++{ ++ return(0); ++} ++#else /* defined(linux) */ + #pragma weak cond_broadcast = _Xcond_broadcast_stub_ + int + _Xcond_broadcast_stub_(c) +@@ -123,3 +232,15 @@ + { + return(0); + } ++#endif /* defined(linux) */ ++ ++#if defined(linux) ++#pragma weak pthread_equal = _Xthr_equal_stub_ ++int ++_Xthr_equal_stub_(t1, t2) ++ pthread_t t1; ++ pthread_t t2; ++{ ++ return(1); ++} ++#endif /* defined(linux) */ +------------------------------------------------------------------------- diff --git a/linuxthreads/Versions b/linuxthreads/Versions new file mode 100644 index 0000000000..615a132e54 --- /dev/null +++ b/linuxthreads/Versions @@ -0,0 +1,188 @@ +libc { + GLIBC_2.0 { + pthread_attr_destroy; pthread_attr_getdetachstate; + pthread_attr_getinheritsched; pthread_attr_getschedparam; + pthread_attr_getschedpolicy; pthread_attr_getscope; pthread_attr_init; + pthread_attr_setdetachstate; pthread_attr_setinheritsched; + pthread_attr_setschedparam; pthread_attr_setschedpolicy; + pthread_attr_setscope; pthread_cond_broadcast; pthread_cond_destroy; + pthread_cond_init; pthread_cond_signal; pthread_cond_wait; + pthread_cond_timedwait; + pthread_condattr_destroy; pthread_condattr_init; pthread_equal; + pthread_exit; pthread_getschedparam; pthread_mutex_destroy; + pthread_mutex_init; pthread_mutex_lock; pthread_mutex_unlock; + pthread_self; pthread_setcancelstate; pthread_setcanceltype; + pthread_setschedparam; + } + GLIBC_2.1 { + pthread_attr_init; + } + GLIBC_2.3.2 { + # Changed pthread_cond_t. + pthread_cond_init; pthread_cond_destroy; + pthread_cond_wait; pthread_cond_signal; + pthread_cond_broadcast; pthread_cond_timedwait; + } + GLIBC_PRIVATE { + # Internal libc interface to libpthread + __libc_dl_error_tsd; + + __libc_pthread_init; __libc_current_sigrtmin_private; + __libc_current_sigrtmax_private; __libc_allocate_rtsig_private; + + __libc_creat; __libc_poll; __libc_pselect; __libc_select; + __libc_sigpause; __libc_sigsuspend; __libc_sigwait; __libc_sigwaitinfo; + __libc_waitid; __libc___xpg_sigpause; __librt_enable_asynccancel; + __librt_disable_asynccancel; __librt_multiple_threads; + + __libc_sigaction; __on_exit; + } +} + +libpthread { + GLIBC_2.0 { + # Hidden entry point (through macros). + _pthread_cleanup_pop; _pthread_cleanup_pop_restore; _pthread_cleanup_push; + _pthread_cleanup_push_defer; + + # Overwritten libc functions. + accept; close; connect; fcntl; fork; fsync; longjmp; lseek; msync; + nanosleep; open; pause; raise; read; recv; recvfrom; recvmsg; send; + sendmsg; sendto; sigaction; siglongjmp; system; tcdrain; wait; + waitpid; write; + __close; __connect; __fcntl; __lseek; __open; __read; __send; __wait; + __write; + _IO_flockfile; _IO_ftrylockfile; _IO_funlockfile; + vfork; __fork; + + # POSIX.1c extensions to libc. + flockfile; funlockfile; ftrylockfile; + + # Non-standard POSIX1.x functions. + pthread_kill_other_threads_np; pthread_mutexattr_getkind_np; + pthread_mutexattr_setkind_np; + + # Real POSIX.1c functions. + pthread_atfork; pthread_attr_destroy; pthread_attr_getdetachstate; + pthread_attr_getinheritsched; pthread_attr_getschedparam; + pthread_attr_getschedpolicy; pthread_attr_getscope; pthread_attr_init; + pthread_attr_setdetachstate; pthread_attr_setinheritsched; + pthread_attr_setschedparam; pthread_attr_setschedpolicy; + pthread_attr_setscope; pthread_cancel; pthread_cond_broadcast; + pthread_cond_destroy; pthread_cond_init; pthread_cond_signal; + pthread_cond_timedwait; pthread_cond_wait; pthread_condattr_destroy; + pthread_condattr_init; pthread_create; pthread_detach; pthread_equal; + pthread_exit; pthread_getschedparam; pthread_getspecific; pthread_join; + pthread_key_create; pthread_key_delete; pthread_kill; + pthread_mutex_destroy; pthread_mutex_init; pthread_mutex_lock; + pthread_mutex_trylock; pthread_mutex_unlock; pthread_mutexattr_destroy; + pthread_mutexattr_init; pthread_once; pthread_self; pthread_setcancelstate; + pthread_setcanceltype; pthread_setschedparam; pthread_setspecific; + pthread_sigmask; pthread_testcancel; + + sem_destroy; sem_getvalue; sem_init; sem_post; sem_trywait; sem_wait; + sigwait; + + # Protected names for functions used in other shared objects. + __pthread_atfork; __pthread_getspecific; + __pthread_key_create; __pthread_mutex_destroy; __pthread_mutex_init; + __pthread_mutex_lock; __pthread_mutex_trylock; __pthread_mutex_unlock; + __pthread_mutexattr_destroy; __pthread_mutexattr_init; + __pthread_mutexattr_settype; __pthread_once; __pthread_setspecific; + + # The error functions. + __errno_location; __h_errno_location; + + # Must be preemptible + __sigaction; + } + GLIBC_2.1 { + # Functions with changed interface. + pthread_attr_init; pthread_create; + + # Unix98 extensions. + pthread_rwlock_init; pthread_rwlock_destroy; pthread_rwlock_rdlock; + pthread_rwlock_tryrdlock; pthread_rwlock_wrlock; 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_attr_getguardsize; pthread_attr_setguardsize; + pthread_attr_getstackaddr; pthread_attr_setstackaddr; + pthread_attr_getstacksize; pthread_attr_setstacksize; + + pthread_getconcurrency; pthread_setconcurrency; + + pthread_mutexattr_gettype; pthread_mutexattr_settype; + + sem_destroy; sem_getvalue; sem_init; sem_post; sem_trywait; sem_wait; + + # helper functions + __libc_current_sigrtmin; __libc_current_sigrtmax; + __libc_allocate_rtsig; + } + GLIBC_2.1.1 { + sem_close; sem_open; sem_unlink; + } + GLIBC_2.1.2 { + __vfork; + } + GLIBC_2.2 { + # For the cancelation wrappers. + pread; __pread64; pread64; pwrite; __pwrite64; pwrite64; lseek64; + open64; __open64; + + __res_state; + + # Names used internally. + __pthread_rwlock_init; __pthread_rwlock_destroy; __pthread_rwlock_rdlock; + __pthread_rwlock_tryrdlock; __pthread_rwlock_wrlock; + __pthread_rwlock_trywrlock; __pthread_rwlock_unlock; + + # No really implemented. + pthread_condattr_getpshared; pthread_condattr_setpshared; + pthread_mutexattr_getpshared; pthread_mutexattr_setpshared; + + # New functions from IEEE Std. 1003.1-200x. + sem_timedwait; + pthread_attr_getstack; pthread_attr_setstack; + pthread_spin_destroy; pthread_spin_init; pthread_spin_lock; + pthread_spin_trylock; pthread_spin_unlock; + pthread_getcpuclockid; + pthread_barrier_destroy; pthread_barrier_init; pthread_barrier_wait; + pthread_barrierattr_destroy; pthread_barrierattr_init; + pthread_barrierattr_setpshared; + pthread_mutex_timedlock; + pthread_rwlock_timedrdlock; pthread_rwlock_timedwrlock; + + # Extensions. + pthread_yield; + } + GLIBC_2.2.3 { + # Extensions. + pthread_getattr_np; + } + GLIBC_2.2.6 { + # Cancellation wrapper + __nanosleep; + } + GLIBC_2.3.2 { + # Changed pthread_cond_t. + pthread_cond_init; pthread_cond_destroy; + pthread_cond_wait; pthread_cond_timedwait; + pthread_cond_signal; pthread_cond_broadcast; + } + + # Hey you!! Yes, YOU! Do not add new symbols here! + # The linuxthreads libpthread ABI froze at GLIBC_2.3.2 and lacks + # numerous additions that NPTL's libpthread has. We can't go adding + # any new symbols here unless we support all the new symbols in NPTL, + # and we don't want to do that. Linuxthreads is only alive for + # compatibility with old binaries using old interfaces. + + GLIBC_PRIVATE { + # Internal libc interface to libpthread + __pthread_initialize; + __pthread_kill_other_threads_np; + } +} diff --git a/linuxthreads/alloca_cutoff.c b/linuxthreads/alloca_cutoff.c new file mode 100644 index 0000000000..ca064b3bb6 --- /dev/null +++ b/linuxthreads/alloca_cutoff.c @@ -0,0 +1,36 @@ +/* Determine whether block of given size can be allocated on the stack or not. + 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; 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 "internals.h" +#include <sysdep-cancel.h> + +int +__libc_alloca_cutoff (size_t size) +{ + if (! SINGLE_THREAD_P) + { + pthread_descr self = thread_self (); + return size <= LIBC_THREAD_GETMEM (self, p_alloca_cutoff); + } + + return size <= __MAX_ALLOCA_CUTOFF; +} diff --git a/linuxthreads/attr.c b/linuxthreads/attr.c new file mode 100644 index 0000000000..2adc7ccd7a --- /dev/null +++ b/linuxthreads/attr.c @@ -0,0 +1,485 @@ +/* Linuxthreads - a simple clone()-based implementation of Posix */ +/* threads for Linux. */ +/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ +/* */ +/* This program is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public License */ +/* as published by the Free Software Foundation; either version 2 */ +/* of the License, or (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Library General Public License for more details. */ + +/* Handling of thread attributes */ + +#include <errno.h> +#include <inttypes.h> +#include <stdio.h> +#include <stdio_ext.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/param.h> +#include <sys/resource.h> +#include "pthread.h" +#include "internals.h" +#include <shlib-compat.h> +#include <ldsodefs.h> + + +int __pthread_attr_init_2_1(pthread_attr_t *attr) +{ + size_t ps = __getpagesize (); + + attr->__detachstate = PTHREAD_CREATE_JOINABLE; + attr->__schedpolicy = SCHED_OTHER; + attr->__schedparam.sched_priority = 0; + attr->__inheritsched = PTHREAD_EXPLICIT_SCHED; + attr->__scope = PTHREAD_SCOPE_SYSTEM; +#ifdef NEED_SEPARATE_REGISTER_STACK + attr->__guardsize = ps + ps; +#else + attr->__guardsize = ps; +#endif + attr->__stackaddr = NULL; + attr->__stackaddr_set = 0; + attr->__stacksize = STACK_SIZE - ps; + return 0; +} + +versioned_symbol (libpthread, __pthread_attr_init_2_1, pthread_attr_init, + GLIBC_2_1); + +#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_1) +int __pthread_attr_init_2_0(pthread_attr_t *attr) +{ + attr->__detachstate = PTHREAD_CREATE_JOINABLE; + attr->__schedpolicy = SCHED_OTHER; + attr->__schedparam.sched_priority = 0; + attr->__inheritsched = PTHREAD_EXPLICIT_SCHED; + attr->__scope = PTHREAD_SCOPE_SYSTEM; + return 0; +} +compat_symbol (libpthread, __pthread_attr_init_2_0, pthread_attr_init, + GLIBC_2_0); +#endif + +int __pthread_attr_destroy(pthread_attr_t *attr) +{ + return 0; +} +strong_alias (__pthread_attr_destroy, pthread_attr_destroy); + +int __pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate) +{ + if (detachstate < PTHREAD_CREATE_JOINABLE || + detachstate > PTHREAD_CREATE_DETACHED) + return EINVAL; + attr->__detachstate = detachstate; + return 0; +} +strong_alias (__pthread_attr_setdetachstate, pthread_attr_setdetachstate); + +int __pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate) +{ + *detachstate = attr->__detachstate; + return 0; +} +strong_alias (__pthread_attr_getdetachstate, pthread_attr_getdetachstate); + +int __pthread_attr_setschedparam(pthread_attr_t *attr, + const struct sched_param *param) +{ + int max_prio = __sched_get_priority_max(attr->__schedpolicy); + int min_prio = __sched_get_priority_min(attr->__schedpolicy); + + if (param->sched_priority < min_prio || param->sched_priority > max_prio) + return EINVAL; + memcpy (&attr->__schedparam, param, sizeof (struct sched_param)); + return 0; +} +strong_alias (__pthread_attr_setschedparam, pthread_attr_setschedparam); + +int __pthread_attr_getschedparam(const pthread_attr_t *attr, + struct sched_param *param) +{ + memcpy (param, &attr->__schedparam, sizeof (struct sched_param)); + return 0; +} +strong_alias (__pthread_attr_getschedparam, pthread_attr_getschedparam); + +int __pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy) +{ + if (policy != SCHED_OTHER && policy != SCHED_FIFO && policy != SCHED_RR) + return EINVAL; + attr->__schedpolicy = policy; + return 0; +} +strong_alias (__pthread_attr_setschedpolicy, pthread_attr_setschedpolicy); + +int __pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy) +{ + *policy = attr->__schedpolicy; + return 0; +} +strong_alias (__pthread_attr_getschedpolicy, pthread_attr_getschedpolicy); + +int __pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit) +{ + if (inherit != PTHREAD_INHERIT_SCHED && inherit != PTHREAD_EXPLICIT_SCHED) + return EINVAL; + attr->__inheritsched = inherit; + return 0; +} +strong_alias (__pthread_attr_setinheritsched, pthread_attr_setinheritsched); + +int __pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inherit) +{ + *inherit = attr->__inheritsched; + return 0; +} +strong_alias (__pthread_attr_getinheritsched, pthread_attr_getinheritsched); + +int __pthread_attr_setscope(pthread_attr_t *attr, int scope) +{ + switch (scope) { + case PTHREAD_SCOPE_SYSTEM: + attr->__scope = scope; + return 0; + case PTHREAD_SCOPE_PROCESS: + return ENOTSUP; + default: + return EINVAL; + } +} +strong_alias (__pthread_attr_setscope, pthread_attr_setscope); + +int __pthread_attr_getscope(const pthread_attr_t *attr, int *scope) +{ + *scope = attr->__scope; + return 0; +} +strong_alias (__pthread_attr_getscope, pthread_attr_getscope); + +int __pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize) +{ + /* The guard size must not be larger than the stack itself */ + if (guardsize >= attr->__stacksize) return EINVAL; + + attr->__guardsize = guardsize; + + return 0; +} +weak_alias (__pthread_attr_setguardsize, pthread_attr_setguardsize) + +int __pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize) +{ + *guardsize = attr->__guardsize; + return 0; +} +weak_alias (__pthread_attr_getguardsize, pthread_attr_getguardsize) + +int __pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr) +{ + attr->__stackaddr = stackaddr; + attr->__stackaddr_set = 1; + return 0; +} +weak_alias (__pthread_attr_setstackaddr, pthread_attr_setstackaddr) + +link_warning (pthread_attr_setstackaddr, + "the use of `pthread_attr_setstackaddr' is deprecated, use `pthread_attr_setstack'") + +int __pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackaddr) +{ + /* XXX This function has a stupid definition. The standard specifies + no error value but what is if no stack address was set? We simply + return the value we have in the member. */ + *stackaddr = attr->__stackaddr; + return 0; +} +weak_alias (__pthread_attr_getstackaddr, pthread_attr_getstackaddr) + +link_warning (pthread_attr_getstackaddr, + "the use of `pthread_attr_getstackaddr' is deprecated, use `pthread_attr_getstack'") + + +int __pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize) +{ +#ifdef FLOATING_STACKS + /* We have to check against the maximum allowed stack size. This is no + problem if the manager is already started and we determined it. If + this hasn't happened, we have to find the limit outself. */ + if (__pthread_max_stacksize == 0) + __pthread_init_max_stacksize (); + + if (stacksize > __pthread_max_stacksize) + return EINVAL; +#else + /* We have a fixed size limit. */ + if (stacksize > STACK_SIZE) + return EINVAL; +#endif + + /* We don't accept value smaller than PTHREAD_STACK_MIN. */ + if (stacksize < PTHREAD_STACK_MIN) + return EINVAL; + + attr->__stacksize = stacksize; + return 0; +} + +#if PTHREAD_STACK_MIN == 16384 +weak_alias (__pthread_attr_setstacksize, pthread_attr_setstacksize) +#else +versioned_symbol (libpthread, __pthread_attr_setstacksize, + pthread_attr_setstacksize, GLIBC_2_3_3); + +# if SHLIB_COMPAT(libpthread, GLIBC_2_1, GLIBC_2_3_3) + +int __old_pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize) +{ +# ifdef FLOATING_STACKS + /* We have to check against the maximum allowed stack size. This is no + problem if the manager is already started and we determined it. If + this hasn't happened, we have to find the limit outself. */ + if (__pthread_max_stacksize == 0) + __pthread_init_max_stacksize (); + + if (stacksize > __pthread_max_stacksize) + return EINVAL; +# else + /* We have a fixed size limit. */ + if (stacksize > STACK_SIZE) + return EINVAL; +# endif + + /* We don't accept value smaller than old PTHREAD_STACK_MIN. */ + if (stacksize < 16384) + return EINVAL; + + attr->__stacksize = stacksize; + return 0; +} +compat_symbol (libpthread, __old_pthread_attr_setstacksize, + pthread_attr_setstacksize, GLIBC_2_1); +# endif +#endif + + +int __pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize) +{ + *stacksize = attr->__stacksize; + return 0; +} +weak_alias (__pthread_attr_getstacksize, pthread_attr_getstacksize) + +int __pthread_attr_setstack (pthread_attr_t *attr, void *stackaddr, + size_t stacksize) +{ + int err; + + if ((((uintptr_t) stackaddr) + & (__alignof__ (struct _pthread_descr_struct) - 1)) != 0) + err = EINVAL; + else + err = __pthread_attr_setstacksize (attr, stacksize); + if (err == 0) + { +#ifndef _STACK_GROWS_UP + attr->__stackaddr = (char *) stackaddr + stacksize; +#else + attr->__stackaddr = stackaddr; +#endif + attr->__stackaddr_set = 1; + } + + return err; +} + +#if PTHREAD_STACK_MIN == 16384 +weak_alias (__pthread_attr_setstack, pthread_attr_setstack) +#else +versioned_symbol (libpthread, __pthread_attr_setstack, pthread_attr_setstack, + GLIBC_2_3_3); +# if SHLIB_COMPAT(libpthread, GLIBC_2_2, GLIBC_2_3_3) +int __old_pthread_attr_setstack (pthread_attr_t *attr, void *stackaddr, + size_t stacksize) +{ + int err; + + if ((((uintptr_t) stackaddr) + & (__alignof__ (struct _pthread_descr_struct) - 1)) != 0) + err = EINVAL; + else + err = __old_pthread_attr_setstacksize (attr, stacksize); + if (err == 0) + { +# ifndef _STACK_GROWS_UP + attr->__stackaddr = (char *) stackaddr + stacksize; +# else + attr->__stackaddr = stackaddr; +# endif + attr->__stackaddr_set = 1; + } + + return err; +} + +compat_symbol (libpthread, __old_pthread_attr_setstack, pthread_attr_setstack, + GLIBC_2_2); + +# endif +#endif + +int __pthread_attr_getstack (const pthread_attr_t *attr, void **stackaddr, + size_t *stacksize) +{ + /* XXX This function has a stupid definition. The standard specifies + no error value but what is if no stack address was set? We simply + return the value we have in the member. */ +#ifndef _STACK_GROWS_UP + *stackaddr = (char *) attr->__stackaddr - attr->__stacksize; +#else + *stackaddr = attr->__stackaddr; +#endif + *stacksize = attr->__stacksize; + return 0; +} +weak_alias (__pthread_attr_getstack, pthread_attr_getstack) + +int pthread_getattr_np (pthread_t thread, pthread_attr_t *attr) +{ + pthread_handle handle = thread_handle (thread); + pthread_descr descr; + int ret = 0; + + if (handle == NULL) + return ENOENT; + + descr = handle->h_descr; + + attr->__detachstate = (descr->p_detached + ? PTHREAD_CREATE_DETACHED + : PTHREAD_CREATE_JOINABLE); + + attr->__schedpolicy = __sched_getscheduler (descr->p_pid); + if (attr->__schedpolicy == -1) + return errno; + + if (__sched_getparam (descr->p_pid, + (struct sched_param *) &attr->__schedparam) != 0) + return errno; + + attr->__inheritsched = descr->p_inheritsched; + attr->__scope = PTHREAD_SCOPE_SYSTEM; + +#ifdef _STACK_GROWS_DOWN +# ifdef USE_TLS + attr->__stacksize = descr->p_stackaddr - (char *)descr->p_guardaddr + - descr->p_guardsize; +# else + attr->__stacksize = (char *)(descr + 1) - (char *)descr->p_guardaddr + - descr->p_guardsize; +# endif +#else +# ifdef USE_TLS + attr->__stacksize = (char *)descr->p_guardaddr - descr->p_stackaddr; +# else + attr->__stacksize = (char *)descr->p_guardaddr - (char *)descr; +# endif +#endif + attr->__guardsize = descr->p_guardsize; + attr->__stackaddr_set = descr->p_userstack; +#ifdef NEED_SEPARATE_REGISTER_STACK + if (descr->p_userstack == 0) + attr->__stacksize *= 2; + /* XXX This is awkward. The guard pages are in the middle of the + two stacks. We must count the guard size in the stack size since + otherwise the range of the stack area cannot be computed. */ + attr->__stacksize += attr->__guardsize; +#endif +#ifdef USE_TLS + attr->__stackaddr = descr->p_stackaddr; +#else +# ifndef _STACK_GROWS_UP + attr->__stackaddr = (char *)(descr + 1); +# else + attr->__stackaddr = (char *)descr; +# endif +#endif + +#ifdef USE_TLS + if (attr->__stackaddr == NULL) +#else + if (descr == &__pthread_initial_thread) +#endif + { + /* 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. */ + attr->__stacksize = rl.rlim_cur; +#ifdef _STACK_GROWS_UP + /* Don't check to enforce a limit on the __stacksize */ + attr->__stackaddr = (void *) from; +#else + attr->__stackaddr = (void *) to; + + /* The limit might be too high. */ + if ((size_t) attr->__stacksize + > (size_t) attr->__stackaddr - last_to) + attr->__stacksize = (size_t) attr->__stackaddr - last_to; +#endif + + /* We succeed and no need to look further. */ + ret = 0; + break; + } + last_to = to; + } + + fclose (fp); + free (line); + } + } + + return 0; + +} diff --git a/linuxthreads/barrier.c b/linuxthreads/barrier.c new file mode 100644 index 0000000000..37d997cfc1 --- /dev/null +++ b/linuxthreads/barrier.c @@ -0,0 +1,128 @@ +/* POSIX barrier implementation for LinuxThreads. + Copyright (C) 2000, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Kaz Kylheku <kaz@ashi.footprints.net>, 2000. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <errno.h> +#include "pthread.h" +#include "internals.h" +#include "spinlock.h" +#include "queue.h" +#include "restart.h" + +int +pthread_barrier_wait(pthread_barrier_t *barrier) +{ + pthread_descr self = thread_self(); + pthread_descr temp_wake_queue, th; + int result = 0; + + __pthread_lock(&barrier->__ba_lock, self); + + /* If the required number of threads have achieved rendezvous... */ + if (barrier->__ba_present >= barrier->__ba_required - 1) + { + /* ... then this last caller shall be the serial thread */ + result = PTHREAD_BARRIER_SERIAL_THREAD; + /* Copy and clear wait queue and reset barrier. */ + temp_wake_queue = barrier->__ba_waiting; + barrier->__ba_waiting = NULL; + barrier->__ba_present = 0; + } + else + { + result = 0; + barrier->__ba_present++; + enqueue(&barrier->__ba_waiting, self); + } + + __pthread_unlock(&barrier->__ba_lock); + + if (result == 0) + { + /* Non-serial threads have to suspend */ + suspend(self); + /* We don't bother dealing with cancellation because the POSIX + spec for barriers doesn't mention that pthread_barrier_wait + is a cancellation point. */ + } + else + { + /* Serial thread wakes up all others. */ + while ((th = dequeue(&temp_wake_queue)) != NULL) + restart(th); + } + + return result; +} + +int +pthread_barrier_init(pthread_barrier_t *barrier, + const pthread_barrierattr_t *attr, + unsigned int count) +{ + if (count == 0) + return EINVAL; + + __pthread_init_lock(&barrier->__ba_lock); + barrier->__ba_required = count; + barrier->__ba_present = 0; + barrier->__ba_waiting = NULL; + return 0; +} + +int +pthread_barrier_destroy(pthread_barrier_t *barrier) +{ + if (barrier->__ba_waiting != NULL) return EBUSY; + return 0; +} + +int +pthread_barrierattr_init(pthread_barrierattr_t *attr) +{ + attr->__pshared = PTHREAD_PROCESS_PRIVATE; + return 0; +} + +int +pthread_barrierattr_destroy(pthread_barrierattr_t *attr) +{ + return 0; +} + +int +__pthread_barrierattr_getpshared(const pthread_barrierattr_t *attr, + int *pshared) +{ + *pshared = PTHREAD_PROCESS_PRIVATE; + return 0; +} + +int +pthread_barrierattr_setpshared(pthread_barrierattr_t *attr, int pshared) +{ + if (pshared != PTHREAD_PROCESS_PRIVATE && pshared != PTHREAD_PROCESS_SHARED) + return EINVAL; + + /* For now it is not possible to shared a conditional variable. */ + if (pshared != PTHREAD_PROCESS_PRIVATE) + return ENOSYS; + + return 0; +} diff --git a/linuxthreads/bug-sleep.c b/linuxthreads/bug-sleep.c new file mode 100644 index 0000000000..f29a6b73c0 --- /dev/null +++ b/linuxthreads/bug-sleep.c @@ -0,0 +1,34 @@ +/* PR libc/4005 */ +#include <pthread.h> +#include <stdio.h> +#include <unistd.h> +#include <time.h> + +void * +run_thread (void *a) +{ + while (1) + { + sleep (10); + } + return 0; +} + +int +main (void) +{ + pthread_t thr; + void *result; + alarm (4); + printf ("Starting thread.\n"); + pthread_create (&thr, 0, run_thread, 0); + sleep (2); + printf ("Canceling thread.\n"); + pthread_cancel (thr); + pthread_join (thr, &result); + if (result == PTHREAD_CANCELED) + printf ("Thread canceled.\n"); + else + printf ("Thread exited.\n"); + return 0; +} diff --git a/linuxthreads/cancel.c b/linuxthreads/cancel.c new file mode 100644 index 0000000000..d8053ca899 --- /dev/null +++ b/linuxthreads/cancel.c @@ -0,0 +1,234 @@ +/* Linuxthreads - a simple clone()-based implementation of Posix */ +/* threads for Linux. */ +/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ +/* */ +/* This program is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public License */ +/* as published by the Free Software Foundation; either version 2 */ +/* of the License, or (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Library General Public License for more details. */ + +/* Thread cancellation */ + +#include <errno.h> +#include <libc-internal.h> +#include "pthread.h" +#include "internals.h" +#include "spinlock.h" +#include "restart.h" + +#ifdef _STACK_GROWS_DOWN +# define FRAME_LEFT(frame, other) ((char *) frame >= (char *) other) +#elif _STACK_GROWS_UP +# define FRAME_LEFT(frame, other) ((char *) frame <= (char *) other) +#else +# error "Define either _STACK_GROWS_DOWN or _STACK_GROWS_UP" +#endif + + +int __pthread_setcancelstate(int state, int * oldstate) +{ + pthread_descr self = thread_self(); + if (state < PTHREAD_CANCEL_ENABLE || state > PTHREAD_CANCEL_DISABLE) + return EINVAL; + if (oldstate != NULL) *oldstate = THREAD_GETMEM(self, p_cancelstate); + THREAD_SETMEM(self, p_cancelstate, state); + if (THREAD_GETMEM(self, p_canceled) && + THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE && + THREAD_GETMEM(self, p_canceltype) == PTHREAD_CANCEL_ASYNCHRONOUS) + __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME); + return 0; +} +strong_alias (__pthread_setcancelstate, pthread_setcancelstate); + +int __pthread_setcanceltype(int type, int * oldtype) +{ + pthread_descr self = thread_self(); + if (type < PTHREAD_CANCEL_DEFERRED || type > PTHREAD_CANCEL_ASYNCHRONOUS) + return EINVAL; + if (oldtype != NULL) *oldtype = THREAD_GETMEM(self, p_canceltype); + THREAD_SETMEM(self, p_canceltype, type); + if (THREAD_GETMEM(self, p_canceled) && + THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE && + THREAD_GETMEM(self, p_canceltype) == PTHREAD_CANCEL_ASYNCHRONOUS) + __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME); + return 0; +} +strong_alias (__pthread_setcanceltype, pthread_setcanceltype); + + +/* 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) +{ + pthread_descr self = thread_self(); + int oldtype = THREAD_GETMEM(self, p_canceltype); + THREAD_SETMEM(self, p_canceltype, PTHREAD_CANCEL_ASYNCHRONOUS); + if (__builtin_expect (THREAD_GETMEM(self, p_canceled), 0) && + THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) + __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME); + return oldtype; +} + +void +internal_function attribute_hidden +__pthread_disable_asynccancel (int oldtype) +{ + pthread_descr self = thread_self(); + THREAD_SETMEM(self, p_canceltype, oldtype); +} + + +int pthread_cancel(pthread_t thread) +{ + pthread_handle handle = thread_handle(thread); + int pid; + int dorestart = 0; + pthread_descr th; + pthread_extricate_if *pextricate; + int already_canceled; + + __pthread_lock(&handle->h_lock, NULL); + if (invalid_handle(handle, thread)) { + __pthread_unlock(&handle->h_lock); + return ESRCH; + } + + th = handle->h_descr; + + already_canceled = th->p_canceled; + th->p_canceled = 1; + + if (th->p_cancelstate == PTHREAD_CANCEL_DISABLE || already_canceled) { + __pthread_unlock(&handle->h_lock); + return 0; + } + + pextricate = th->p_extricate; + pid = th->p_pid; + + /* If the thread has registered an extrication interface, then + invoke the interface. If it returns 1, then we succeeded in + dequeuing the thread from whatever waiting object it was enqueued + with. In that case, it is our responsibility to wake it up. + And also to set the p_woken_by_cancel flag so the woken thread + can tell that it was woken by cancellation. */ + + if (pextricate != NULL) { + dorestart = pextricate->pu_extricate_func(pextricate->pu_object, th); + th->p_woken_by_cancel = dorestart; + } + + __pthread_unlock(&handle->h_lock); + + /* If the thread has suspended or is about to, then we unblock it by + issuing a restart, instead of a cancel signal. Otherwise we send + the cancel signal to unblock the thread from a cancellation point, + or to initiate asynchronous cancellation. The restart is needed so + we have proper accounting of restarts; suspend decrements the thread's + resume count, and restart() increments it. This also means that suspend's + handling of the cancel signal is obsolete. */ + + if (dorestart) + restart(th); + else + kill(pid, __pthread_sig_cancel); + + return 0; +} + +void pthread_testcancel(void) +{ + pthread_descr self = thread_self(); + if (THREAD_GETMEM(self, p_canceled) + && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) + __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME); +} + +void _pthread_cleanup_push(struct _pthread_cleanup_buffer * buffer, + void (*routine)(void *), void * arg) +{ + pthread_descr self = thread_self(); + buffer->__routine = routine; + buffer->__arg = arg; + buffer->__prev = THREAD_GETMEM(self, p_cleanup); + if (buffer->__prev != NULL && FRAME_LEFT (buffer, buffer->__prev)) + buffer->__prev = NULL; + THREAD_SETMEM(self, p_cleanup, buffer); +} + +void _pthread_cleanup_pop(struct _pthread_cleanup_buffer * buffer, + int execute) +{ + pthread_descr self = thread_self(); + if (execute) buffer->__routine(buffer->__arg); + THREAD_SETMEM(self, p_cleanup, buffer->__prev); +} + +void _pthread_cleanup_push_defer(struct _pthread_cleanup_buffer * buffer, + void (*routine)(void *), void * arg) +{ + pthread_descr self = thread_self(); + buffer->__routine = routine; + buffer->__arg = arg; + buffer->__canceltype = THREAD_GETMEM(self, p_canceltype); + buffer->__prev = THREAD_GETMEM(self, p_cleanup); + if (buffer->__prev != NULL && FRAME_LEFT (buffer, buffer->__prev)) + buffer->__prev = NULL; + THREAD_SETMEM(self, p_canceltype, PTHREAD_CANCEL_DEFERRED); + THREAD_SETMEM(self, p_cleanup, buffer); +} + +void _pthread_cleanup_pop_restore(struct _pthread_cleanup_buffer * buffer, + int execute) +{ + pthread_descr self = thread_self(); + if (execute) buffer->__routine(buffer->__arg); + THREAD_SETMEM(self, p_cleanup, buffer->__prev); + THREAD_SETMEM(self, p_canceltype, buffer->__canceltype); + if (THREAD_GETMEM(self, p_canceled) && + THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE && + THREAD_GETMEM(self, p_canceltype) == PTHREAD_CANCEL_ASYNCHRONOUS) + __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME); +} + +void __pthread_perform_cleanup(char *currentframe) +{ + pthread_descr self = thread_self(); + struct _pthread_cleanup_buffer *c = THREAD_GETMEM(self, p_cleanup); + struct _pthread_cleanup_buffer *last; + + if (c != NULL) + while (FRAME_LEFT (currentframe, c)) + { + last = c; + c = c->__prev; + + if (c == NULL || FRAME_LEFT (last, c)) + { + c = NULL; + break; + } + } + + while (c != NULL) + { + c->__routine(c->__arg); + + last = c; + c = c->__prev; + + if (FRAME_LEFT (last, c)) + break; + } + + /* And the TSD which needs special help. */ + __libc_thread_freeres (); +} diff --git a/linuxthreads/condvar.c b/linuxthreads/condvar.c new file mode 100644 index 0000000000..6ab95b88ae --- /dev/null +++ b/linuxthreads/condvar.c @@ -0,0 +1,341 @@ +/* Linuxthreads - a simple clone()-based implementation of Posix */ +/* threads for Linux. */ +/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ +/* and Pavel Krauz (krauz@fsid.cvut.cz). */ +/* */ +/* This program is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public License */ +/* as published by the Free Software Foundation; either version 2 */ +/* of the License, or (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Library General Public License for more details. */ + +/* Condition variables */ + +#include <errno.h> +#include <sched.h> +#include <stddef.h> +#include <sys/time.h> +#include "pthread.h" +#include "internals.h" +#include "spinlock.h" +#include "queue.h" +#include "restart.h" +#include <shlib-compat.h> + +int __pthread_cond_init(pthread_cond_t *cond, + const pthread_condattr_t *cond_attr) +{ + __pthread_init_lock(&cond->__c_lock); + cond->__c_waiting = NULL; + return 0; +} +versioned_symbol (libpthread, __pthread_cond_init, pthread_cond_init, + GLIBC_2_3_2); +#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_3_2) +strong_alias (__pthread_cond_init, __old_pthread_cond_init) +compat_symbol (libpthread, __old_pthread_cond_init, pthread_cond_init, + GLIBC_2_0); +#endif + +int __pthread_cond_destroy(pthread_cond_t *cond) +{ + if (cond->__c_waiting != NULL) return EBUSY; + return 0; +} +versioned_symbol (libpthread, __pthread_cond_destroy, pthread_cond_destroy, + GLIBC_2_3_2); +#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_3_2) +strong_alias (__pthread_cond_destroy, __old_pthread_cond_destroy) +compat_symbol (libpthread, __old_pthread_cond_destroy, pthread_cond_destroy, + GLIBC_2_0); +#endif + +/* Function called by pthread_cancel to remove the thread from + waiting on a condition variable queue. */ + +static int cond_extricate_func(void *obj, pthread_descr th) +{ + volatile pthread_descr self = thread_self(); + pthread_cond_t *cond = obj; + int did_remove = 0; + + __pthread_lock(&cond->__c_lock, self); + did_remove = remove_from_queue(&cond->__c_waiting, th); + __pthread_unlock(&cond->__c_lock); + + return did_remove; +} + +int __pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) +{ + volatile pthread_descr self = thread_self(); + pthread_extricate_if extr; + int already_canceled = 0; + int spurious_wakeup_count; + + /* Check whether the mutex is locked and owned by this thread. */ + if (mutex->__m_kind != PTHREAD_MUTEX_TIMED_NP + && mutex->__m_kind != PTHREAD_MUTEX_ADAPTIVE_NP + && mutex->__m_owner != self) + return EINVAL; + + /* Set up extrication interface */ + extr.pu_object = cond; + extr.pu_extricate_func = cond_extricate_func; + + /* Register extrication interface */ + THREAD_SETMEM(self, p_condvar_avail, 0); + __pthread_set_own_extricate_if(self, &extr); + + /* Atomically enqueue thread for waiting, but only if it is not + canceled. If the thread is canceled, then it will fall through the + suspend call below, and then call pthread_exit without + having to worry about whether it is still on the condition variable queue. + This depends on pthread_cancel setting p_canceled before calling the + extricate function. */ + + __pthread_lock(&cond->__c_lock, self); + if (!(THREAD_GETMEM(self, p_canceled) + && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE)) + enqueue(&cond->__c_waiting, self); + else + already_canceled = 1; + __pthread_unlock(&cond->__c_lock); + + if (already_canceled) { + __pthread_set_own_extricate_if(self, 0); + __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME); + } + + pthread_mutex_unlock(mutex); + + spurious_wakeup_count = 0; + while (1) + { + suspend(self); + if (THREAD_GETMEM(self, p_condvar_avail) == 0 + && (THREAD_GETMEM(self, p_woken_by_cancel) == 0 + || THREAD_GETMEM(self, p_cancelstate) != PTHREAD_CANCEL_ENABLE)) + { + /* Count resumes that don't belong to us. */ + spurious_wakeup_count++; + continue; + } + break; + } + + __pthread_set_own_extricate_if(self, 0); + + /* Check for cancellation again, to provide correct cancellation + point behavior */ + + if (THREAD_GETMEM(self, p_woken_by_cancel) + && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) { + THREAD_SETMEM(self, p_woken_by_cancel, 0); + pthread_mutex_lock(mutex); + __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME); + } + + /* Put back any resumes we caught that don't belong to us. */ + while (spurious_wakeup_count--) + restart(self); + + pthread_mutex_lock(mutex); + return 0; +} +versioned_symbol (libpthread, __pthread_cond_wait, pthread_cond_wait, + GLIBC_2_3_2); +#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_3_2) +strong_alias (__pthread_cond_wait, __old_pthread_cond_wait) +compat_symbol (libpthread, __old_pthread_cond_wait, pthread_cond_wait, + GLIBC_2_0); +#endif + +static int +pthread_cond_timedwait_relative(pthread_cond_t *cond, + pthread_mutex_t *mutex, + const struct timespec * abstime) +{ + volatile pthread_descr self = thread_self(); + int already_canceled = 0; + pthread_extricate_if extr; + int spurious_wakeup_count; + + /* Check whether the mutex is locked and owned by this thread. */ + if (mutex->__m_kind != PTHREAD_MUTEX_TIMED_NP + && mutex->__m_kind != PTHREAD_MUTEX_ADAPTIVE_NP + && mutex->__m_owner != self) + return EINVAL; + + /* Set up extrication interface */ + extr.pu_object = cond; + extr.pu_extricate_func = cond_extricate_func; + + /* Register extrication interface */ + THREAD_SETMEM(self, p_condvar_avail, 0); + __pthread_set_own_extricate_if(self, &extr); + + /* Enqueue to wait on the condition and check for cancellation. */ + __pthread_lock(&cond->__c_lock, self); + if (!(THREAD_GETMEM(self, p_canceled) + && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE)) + enqueue(&cond->__c_waiting, self); + else + already_canceled = 1; + __pthread_unlock(&cond->__c_lock); + + if (already_canceled) { + __pthread_set_own_extricate_if(self, 0); + __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME); + } + + pthread_mutex_unlock(mutex); + + spurious_wakeup_count = 0; + while (1) + { + if (!timedsuspend(self, abstime)) { + int was_on_queue; + + /* __pthread_lock will queue back any spurious restarts that + may happen to it. */ + + __pthread_lock(&cond->__c_lock, self); + was_on_queue = remove_from_queue(&cond->__c_waiting, self); + __pthread_unlock(&cond->__c_lock); + + if (was_on_queue) { + __pthread_set_own_extricate_if(self, 0); + pthread_mutex_lock(mutex); + return ETIMEDOUT; + } + + /* Eat the outstanding restart() from the signaller */ + suspend(self); + } + + if (THREAD_GETMEM(self, p_condvar_avail) == 0 + && (THREAD_GETMEM(self, p_woken_by_cancel) == 0 + || THREAD_GETMEM(self, p_cancelstate) != PTHREAD_CANCEL_ENABLE)) + { + /* Count resumes that don't belong to us. */ + spurious_wakeup_count++; + continue; + } + break; + } + + __pthread_set_own_extricate_if(self, 0); + + /* The remaining logic is the same as in other cancellable waits, + such as pthread_join sem_wait or pthread_cond wait. */ + + if (THREAD_GETMEM(self, p_woken_by_cancel) + && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) { + THREAD_SETMEM(self, p_woken_by_cancel, 0); + pthread_mutex_lock(mutex); + __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME); + } + + /* Put back any resumes we caught that don't belong to us. */ + while (spurious_wakeup_count--) + restart(self); + + pthread_mutex_lock(mutex); + return 0; +} + +int __pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, + const struct timespec * abstime) +{ + /* Indirect call through pointer! */ + return pthread_cond_timedwait_relative(cond, mutex, abstime); +} +versioned_symbol (libpthread, __pthread_cond_timedwait, pthread_cond_timedwait, + GLIBC_2_3_2); +#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_3_2) +strong_alias (__pthread_cond_timedwait, __old_pthread_cond_timedwait) +compat_symbol (libpthread, __old_pthread_cond_timedwait, + pthread_cond_timedwait, GLIBC_2_0); +#endif + +int __pthread_cond_signal(pthread_cond_t *cond) +{ + pthread_descr th; + + __pthread_lock(&cond->__c_lock, NULL); + th = dequeue(&cond->__c_waiting); + __pthread_unlock(&cond->__c_lock); + if (th != NULL) { + th->p_condvar_avail = 1; + WRITE_MEMORY_BARRIER(); + restart(th); + } + return 0; +} +versioned_symbol (libpthread, __pthread_cond_signal, pthread_cond_signal, + GLIBC_2_3_2); +#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_3_2) +strong_alias (__pthread_cond_signal, __old_pthread_cond_signal) +compat_symbol (libpthread, __old_pthread_cond_signal, pthread_cond_signal, + GLIBC_2_0); +#endif + +int __pthread_cond_broadcast(pthread_cond_t *cond) +{ + pthread_descr tosignal, th; + + __pthread_lock(&cond->__c_lock, NULL); + /* Copy the current state of the waiting queue and empty it */ + tosignal = cond->__c_waiting; + cond->__c_waiting = NULL; + __pthread_unlock(&cond->__c_lock); + /* Now signal each process in the queue */ + while ((th = dequeue(&tosignal)) != NULL) { + th->p_condvar_avail = 1; + WRITE_MEMORY_BARRIER(); + restart(th); + } + return 0; +} +versioned_symbol (libpthread, __pthread_cond_broadcast, pthread_cond_broadcast, + GLIBC_2_3_2); +#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_3_2) +strong_alias (__pthread_cond_broadcast, __old_pthread_cond_broadcast) +compat_symbol (libpthread, __old_pthread_cond_broadcast, + pthread_cond_broadcast, GLIBC_2_0); +#endif + +int __pthread_condattr_init(pthread_condattr_t *attr) +{ + return 0; +} +strong_alias (__pthread_condattr_init, pthread_condattr_init) + +int __pthread_condattr_destroy(pthread_condattr_t *attr) +{ + return 0; +} +strong_alias (__pthread_condattr_destroy, pthread_condattr_destroy) + +int pthread_condattr_getpshared (const pthread_condattr_t *attr, int *pshared) +{ + *pshared = PTHREAD_PROCESS_PRIVATE; + return 0; +} + +int pthread_condattr_setpshared (pthread_condattr_t *attr, int pshared) +{ + if (pshared != PTHREAD_PROCESS_PRIVATE && pshared != PTHREAD_PROCESS_SHARED) + return EINVAL; + + /* For now it is not possible to shared a conditional variable. */ + if (pshared != PTHREAD_PROCESS_PRIVATE) + return ENOSYS; + + return 0; +} diff --git a/linuxthreads/configure b/linuxthreads/configure new file mode 100755 index 0000000000..2624f9ec5a --- /dev/null +++ b/linuxthreads/configure @@ -0,0 +1,17 @@ +# This file is generated from configure.in by Autoconf. DO NOT EDIT! + +# LinuxThreads fragment for GNU C library configure mechanism. +# This is a shell script fragment sourced by the main configure script. + +for other in $add_ons; do + test $other = nptl || continue + if test $add_ons_automatic = yes; then + echo "$as_me:$LINENO: result: $libc_add_on disabled because $other add-on is also in use" >&5 +echo "${ECHO_T}$libc_add_on disabled because $other add-on is also in use" >&6 + libc_add_on= + else + { { echo "$as_me:$LINENO: error: cannot use both $libc_add_on and $other add-ons in one build" >&5 +echo "$as_me: error: cannot use both $libc_add_on and $other add-ons in one build" >&2;} + { (exit 1); exit 1; }; } + fi +done diff --git a/linuxthreads/configure.in b/linuxthreads/configure.in new file mode 100644 index 0000000000..3f9904a411 --- /dev/null +++ b/linuxthreads/configure.in @@ -0,0 +1,14 @@ +GLIBC_PROVIDES dnl See top-level configure.in. + +# LinuxThreads fragment for GNU C library configure mechanism. +# This is a shell script fragment sourced by the main configure script. + +for other in $add_ons; do + test $other = nptl || continue + if test $add_ons_automatic = yes; then + AC_MSG_RESULT($libc_add_on disabled because $other add-on is also in use) + libc_add_on= + else + AC_MSG_ERROR(cannot use both $libc_add_on and $other add-ons in one build) + fi +done diff --git a/linuxthreads/descr.h b/linuxthreads/descr.h new file mode 100644 index 0000000000..bea8b912f7 --- /dev/null +++ b/linuxthreads/descr.h @@ -0,0 +1,267 @@ +/* Linuxthreads - a simple clone()-based implementation of Posix */ +/* threads for Linux. */ +/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ +/* */ +/* This program is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public License */ +/* as published by the Free Software Foundation; either version 2 */ +/* of the License, or (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Library General Public License for more details. */ + +#ifndef _DESCR_H +#define _DESCR_H 1 + +#define __need_res_state +#include <resolv.h> +#include <sched.h> +#include <setjmp.h> +#include <signal.h> +#include <stdint.h> +#include <sys/types.h> +#include <hp-timing.h> +#include <tls.h> + +/* Fast thread-specific data internal to libc. */ +enum __libc_tsd_key_t { _LIBC_TSD_KEY_MALLOC = 0, + _LIBC_TSD_KEY_DL_ERROR, + _LIBC_TSD_KEY_RPC_VARS, + _LIBC_TSD_KEY_LOCALE, + _LIBC_TSD_KEY_CTYPE_B, + _LIBC_TSD_KEY_CTYPE_TOLOWER, + _LIBC_TSD_KEY_CTYPE_TOUPPER, + _LIBC_TSD_KEY_N }; + +/* The type of thread descriptors */ +typedef struct _pthread_descr_struct *pthread_descr; + + +/* Some more includes. */ +#include <pt-machine.h> +#include <linuxthreads_db/thread_dbP.h> + + +/* Arguments passed to thread creation routine */ +struct pthread_start_args { + void *(*start_routine)(void *); /* function to run */ + void *arg; /* its argument */ + sigset_t mask; /* initial signal mask for thread */ + int schedpolicy; /* initial scheduling policy (if any) */ + struct sched_param schedparam; /* initial scheduling parameters (if any) */ +}; + + +/* Callback interface for removing the thread from waiting on an + object if it is cancelled while waiting or about to wait. + This hold a pointer to the object, and a pointer to a function + which ``extricates'' the thread from its enqueued state. + The function takes two arguments: pointer to the wait object, + and a pointer to the thread. It returns 1 if an extrication + actually occured, and hence the thread must also be signalled. + It returns 0 if the thread had already been extricated. */ +typedef struct _pthread_extricate_struct { + void *pu_object; + int (*pu_extricate_func)(void *, pthread_descr); +} pthread_extricate_if; + + +/* Atomic counter made possible by compare_and_swap */ +struct pthread_atomic { + long p_count; + int p_spinlock; +}; + + +/* Context info for read write locks. The pthread_rwlock_info structure + is information about a lock that has been read-locked by the thread + in whose list this structure appears. The pthread_rwlock_context + is embedded in the thread context and contains a pointer to the + head of the list of lock info structures, as well as a count of + read locks that are untracked, because no info structure could be + allocated for them. */ +struct _pthread_rwlock_t; +typedef struct _pthread_rwlock_info { + struct _pthread_rwlock_info *pr_next; + struct _pthread_rwlock_t *pr_lock; + int pr_lock_count; +} pthread_readlock_info; + + +/* 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) + + +union dtv; + +struct _pthread_descr_struct +{ +#if !defined USE_TLS || !TLS_DTV_AT_TP + /* This overlaps tcbhead_t (see tls.h), as used for TLS without threads. */ + union + { + struct + { + void *tcb; /* Pointer to the TCB. This is not always + the address of this thread descriptor. */ + union dtv *dtvp; + pthread_descr self; /* Pointer to this structure */ + int multiple_threads; +# ifdef NEED_DL_SYSINFO + uintptr_t sysinfo; +# endif + } data; + void *__padding[16]; + } p_header; +# define p_multiple_threads p_header.data.multiple_threads +#elif TLS_MULTIPLE_THREADS_IN_TCB + int p_multiple_threads; +#endif + + pthread_descr p_nextlive, p_prevlive; + /* Double chaining of active threads */ + pthread_descr p_nextwaiting; /* Next element in the queue holding the thr */ + pthread_descr p_nextlock; /* can be on a queue and waiting on a lock */ + pthread_t p_tid; /* Thread identifier */ + int p_pid; /* PID of Unix process */ + int p_priority; /* Thread priority (== 0 if not realtime) */ + struct _pthread_fastlock * p_lock; /* Spinlock for synchronized accesses */ + int p_signal; /* last signal received */ + sigjmp_buf * p_signal_jmp; /* where to siglongjmp on a signal or NULL */ + sigjmp_buf * p_cancel_jmp; /* where to siglongjmp on a cancel or NULL */ + char p_terminated; /* true if terminated e.g. by pthread_exit */ + char p_detached; /* true if detached */ + char p_exited; /* true if the assoc. process terminated */ + void * p_retval; /* placeholder for return value */ + int p_retcode; /* placeholder for return code */ + pthread_descr p_joining; /* thread joining on that thread or NULL */ + struct _pthread_cleanup_buffer * p_cleanup; /* cleanup functions */ + char p_cancelstate; /* cancellation state */ + char p_canceltype; /* cancellation type (deferred/async) */ + char p_canceled; /* cancellation request pending */ + char * p_in_sighandler; /* stack address of sighandler, or NULL */ + char p_sigwaiting; /* true if a sigwait() is in progress */ + struct pthread_start_args p_start_args; /* arguments for thread creation */ + void ** p_specific[PTHREAD_KEY_1STLEVEL_SIZE]; /* thread-specific data */ +#if !(USE_TLS && HAVE___THREAD) + void * p_libc_specific[_LIBC_TSD_KEY_N]; /* thread-specific data for libc */ + int * p_errnop; /* pointer to used errno variable */ + int p_errno; /* error returned by last system call */ + int * p_h_errnop; /* pointer to used h_errno variable */ + int p_h_errno; /* error returned by last netdb function */ + struct __res_state *p_resp; /* Pointer to resolver state */ +#endif + struct __res_state p_res; /* per-thread resolver state */ + int p_userstack; /* nonzero if the user provided the stack */ + void *p_guardaddr; /* address of guard area or NULL */ + size_t p_guardsize; /* size of guard area */ + int p_nr; /* Index of descriptor in __pthread_handles */ + int p_report_events; /* Nonzero if events must be reported. */ + td_eventbuf_t p_eventbuf; /* Data for event. */ + struct pthread_atomic p_resume_count; /* number of times restart() was + called on thread */ + char p_woken_by_cancel; /* cancellation performed wakeup */ + char p_condvar_avail; /* flag if conditional variable became avail */ + char p_sem_avail; /* flag if semaphore became available */ + pthread_extricate_if *p_extricate; /* See above */ + pthread_readlock_info *p_readlock_list; /* List of readlock info structs */ + pthread_readlock_info *p_readlock_free; /* Free list of structs */ + int p_untracked_readlock_count; /* Readlocks not tracked by list */ + int p_inheritsched; /* copied from the thread attribute */ +#if HP_TIMING_AVAIL + hp_timing_t p_cpuclock_offset; /* Initial CPU clock for thread. */ +#endif +#ifdef USE_TLS + char *p_stackaddr; /* Stack address. */ +#endif + size_t p_alloca_cutoff; /* Maximum size which should be allocated + using alloca() instead of malloc(). */ + /* New elements must be added at the end. */ +} __attribute__ ((aligned(32))); /* We need to align the structure so that + doubles are aligned properly. This is 8 + bytes on MIPS and 16 bytes on MIPS64. + 32 bytes might give better cache + utilization. */ + + + +/* Limit between the stack of the initial thread (above) and the + stacks of other threads (below). Aligned on a STACK_SIZE boundary. + Initially 0, meaning that the current thread is (by definition) + the initial thread. */ + +extern char *__pthread_initial_thread_bos; + +/* Descriptor of the initial thread */ + +extern struct _pthread_descr_struct __pthread_initial_thread; + +/* Limits of the thread manager stack. */ + +extern char *__pthread_manager_thread_bos; +extern char *__pthread_manager_thread_tos; + +/* Descriptor of the manager thread */ + +extern struct _pthread_descr_struct __pthread_manager_thread; +extern pthread_descr __pthread_manager_threadp attribute_hidden; + +/* Indicate whether at least one thread has a user-defined stack (if 1), + or all threads have stacks supplied by LinuxThreads (if 0). */ + +extern int __pthread_nonstandard_stacks; + +/* The max size of the thread stack segments. If the default + THREAD_SELF implementation is used, this must be a power of two and + a multiple of PAGE_SIZE. */ +#ifndef STACK_SIZE +#define STACK_SIZE (2 * 1024 * 1024) +#endif + +/* Get some notion of the current stack. Need not be exactly the top + of the stack, just something somewhere in the current frame. */ +#ifndef CURRENT_STACK_FRAME +#define CURRENT_STACK_FRAME ({ char __csf; &__csf; }) +#endif + +/* Recover thread descriptor for the current thread */ + +extern pthread_descr __pthread_find_self (void) __attribute__ ((const)); + +static inline pthread_descr thread_self (void) __attribute__ ((const)); +static inline pthread_descr thread_self (void) +{ +#ifdef THREAD_SELF + return THREAD_SELF; +#else + char *sp = CURRENT_STACK_FRAME; + if (sp >= __pthread_initial_thread_bos) + return &__pthread_initial_thread; + else if (sp >= __pthread_manager_thread_bos + && sp < __pthread_manager_thread_tos) + return &__pthread_manager_thread; + else if (__pthread_nonstandard_stacks) + return __pthread_find_self(); + else +#ifdef _STACK_GROWS_DOWN + return (pthread_descr)(((unsigned long)sp | (STACK_SIZE-1))+1) - 1; +#else + return (pthread_descr)((unsigned long)sp &~ (STACK_SIZE-1)); +#endif +#endif +} + +#endif /* descr.h */ diff --git a/linuxthreads/ecmutex.c b/linuxthreads/ecmutex.c new file mode 100644 index 0000000000..ce54ddf331 --- /dev/null +++ b/linuxthreads/ecmutex.c @@ -0,0 +1,157 @@ +/* Test of the error checking mutex and incidently also barriers. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> + + +static pthread_mutex_t locks[] = +{ + PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP, + PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP, + PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP, + PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP, + PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP +}; +#define nlocks ((int) (sizeof (locks) / sizeof (locks[0]))) + +static pthread_barrier_t barrier; +#define SYNC pthread_barrier_wait (&barrier) + +#define NTHREADS nlocks + +#define ROUNDS 20 + + +static void * +worker (void *arg) +{ + /* We are locking the and unlocked the locks and check the errors. + Since we are using the error-checking variant the implementation + should report them. */ + int nr = (long int) arg; + int i; + void *result = NULL; + int retval; + + for (i = 0; i < ROUNDS; ++i) + { + /* Skip the rounds which would make other == own. */ + if (i % nlocks == 0) + continue; + + /* Get the "own" mutex. */ + if (pthread_mutex_trylock (&locks[nr]) != 0) + { + printf ("thread %d failed getting own mutex\n", nr); + result = (void *) 1; + } + + /* Try locking "own" mutex again. */ + retval = pthread_mutex_lock (&locks[nr]); + if (retval != EDEADLK) + { + printf ("thread %d failed getting own mutex\n", nr); + result = (void *) 1; + } + + /* Try to get a different semaphore. */ + SYNC; + retval = pthread_mutex_trylock (&locks[(nr + i) % nlocks]); + if (retval != EBUSY) + { + printf ("thread %d didn't deadlock on getting %d's lock\n", + nr, (nr + i) % nlocks); + result = (void *) 1; + } + + /* Try unlocking other's lock. */ + retval = pthread_mutex_unlock (&locks[(nr + i) % nlocks]); + if (retval != EPERM) + { + printf ("thread %d managed releasing mutex %d\n", + nr, (nr + i) % nlocks); + result = (void *) 1; + } + + /* All lock one mutex now. */ + SYNC; + retval = pthread_mutex_lock (&locks[i % nlocks]); + if (nr == (i % nlocks)) + { + if (retval != EDEADLK) + { + printf ("thread %d didn't deadlock on getting %d's lock\n", + nr, (nr + i) % nlocks); + result = (void *) 1; + } + if (pthread_mutex_unlock (&locks[i % nlocks]) != 0) + { + printf ("thread %d failed releasing own mutex\n", nr); + result = (void *) 1; + } + } + else + { + if (retval != 0) + { + printf ("thread %d failed acquiring mutex %d\n", + nr, i % nlocks); + result = (void *) 1; + } + else if (pthread_mutex_unlock (&locks[i % nlocks]) != 0) + { + printf ("thread %d failed releasing mutex %d\n", + nr, i % nlocks); + result = (void *) 1; + } + } + + /* Unlock the own lock. */ + SYNC; + if (nr != (i % nlocks) && pthread_mutex_unlock (&locks[nr]) != 0) + { + printf ("thread %d failed releasing own mutex\n", nr); + result = (void *) 1; + } + + /* Try unlocking again. */ + retval = pthread_mutex_unlock (&locks[nr]); + if (retval == 0) + { + printf ("thread %d managed releasing own mutex twice\n", nr); + result = (void *) 1; + } + } + + return result; +} + + +#define TEST_FUNCTION do_test () +static int +do_test (void) +{ + pthread_t threads[NTHREADS]; + int i; + void *res; + int result = 0; + + pthread_barrier_init (&barrier, NULL, NTHREADS); + + for (i = 0; i < NTHREADS; ++i) + if (pthread_create (&threads[i], NULL, worker, (void *) (long int) i) != 0) + { + printf ("failed to create thread %d: %m\n", i); + exit (1); + } + + for (i = 0; i < NTHREADS; ++i) + if (pthread_join (threads[i], &res) != 0 || res != NULL) + result = 1; + + return result; +} + +#include "../test-skeleton.c" diff --git a/linuxthreads/errno.c b/linuxthreads/errno.c new file mode 100644 index 0000000000..5c0e8767a1 --- /dev/null +++ b/linuxthreads/errno.c @@ -0,0 +1,47 @@ +/* Linuxthreads - a simple clone()-based implementation of Posix */ +/* threads for Linux. */ +/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ +/* */ +/* This program is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public License */ +/* as published by the Free Software Foundation; either version 2 */ +/* of the License, or (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Library General Public License for more details. */ + +/* Define the location of errno for the remainder of the C library */ + +#include <errno.h> +#include <netdb.h> +#include <resolv.h> +#include <tls.h> +#include "pthread.h" +#include "internals.h" + +#if !USE_TLS || !HAVE___THREAD +/* The definition in libc is sufficient if we use TLS. */ +int * +__errno_location (void) +{ + pthread_descr self = thread_self(); + return THREAD_GETMEM (self, p_errnop); +} + +int * +__h_errno_location (void) +{ + pthread_descr self = thread_self(); + return THREAD_GETMEM (self, p_h_errnop); +} + +/* Return thread specific resolver state. */ +struct __res_state * +__res_state (void) +{ + pthread_descr self = thread_self(); + return THREAD_GETMEM (self, p_resp); +} +#endif diff --git a/linuxthreads/events.c b/linuxthreads/events.c new file mode 100644 index 0000000000..b4ca3846e8 --- /dev/null +++ b/linuxthreads/events.c @@ -0,0 +1,37 @@ +/* Event functions used while debugging. + 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; 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 "internals.h" + +void +__linuxthreads_create_event (void) +{ +} + +void +__linuxthreads_death_event (void) +{ +} + +void +__linuxthreads_reap_event (void) +{ +} diff --git a/linuxthreads/forward.c b/linuxthreads/forward.c new file mode 100644 index 0000000000..b2a36d7d60 --- /dev/null +++ b/linuxthreads/forward.c @@ -0,0 +1,179 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <dlfcn.h> +#include "internals.h" +#include <stdlib.h> + +#include <shlib-compat.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) + +#if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_1) +FORWARD (__pthread_attr_init_2_0, (pthread_attr_t *attr), (attr), 0) +compat_symbol (libc, __pthread_attr_init_2_0, pthread_attr_init, GLIBC_2_0); +#endif + +FORWARD (__pthread_attr_init_2_1, (pthread_attr_t *attr), (attr), 0) +versioned_symbol (libc, __pthread_attr_init_2_1, pthread_attr_init, GLIBC_2_1); + +FORWARD (pthread_attr_getdetachstate, + (const pthread_attr_t *attr, int *detachstate), (attr, detachstate), + 0) +FORWARD (pthread_attr_setdetachstate, (pthread_attr_t *attr, int detachstate), + (attr, detachstate), 0) + +FORWARD (pthread_attr_getinheritsched, + (const pthread_attr_t *attr, int *inherit), (attr, inherit), 0) +FORWARD (pthread_attr_setinheritsched, (pthread_attr_t *attr, int inherit), + (attr, inherit), 0) + +FORWARD (pthread_attr_getschedparam, + (const pthread_attr_t *attr, struct sched_param *param), + (attr, param), 0) +FORWARD (pthread_attr_setschedparam, + (pthread_attr_t *attr, const struct sched_param *param), + (attr, param), 0) + +FORWARD (pthread_attr_getschedpolicy, + (const pthread_attr_t *attr, int *policy), (attr, policy), 0) +FORWARD (pthread_attr_setschedpolicy, (pthread_attr_t *attr, int policy), + (attr, policy), 0) + +FORWARD (pthread_attr_getscope, + (const pthread_attr_t *attr, int *scope), (attr, scope), 0) +FORWARD (pthread_attr_setscope, (pthread_attr_t *attr, int scope), + (attr, scope), 0) + + +FORWARD (pthread_condattr_destroy, (pthread_condattr_t *attr), (attr), 0) +FORWARD (pthread_condattr_init, (pthread_condattr_t *attr), (attr), 0) + + +FORWARD (__pthread_cond_broadcast, (pthread_cond_t *cond), (cond), 0) +#if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_3_2) +strong_alias (__pthread_cond_broadcast, __pthread_cond_broadcast_2_0) +compat_symbol (libc, __pthread_cond_broadcast_2_0, pthread_cond_broadcast, + GLIBC_2_0); +#endif +versioned_symbol (libc, __pthread_cond_broadcast, pthread_cond_broadcast, + GLIBC_2_3_2); + +FORWARD (__pthread_cond_destroy, (pthread_cond_t *cond), (cond), 0) +#if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_3_2) +strong_alias (__pthread_cond_destroy, __pthread_cond_destroy_2_0) +compat_symbol (libc, __pthread_cond_destroy_2_0, pthread_cond_destroy, + GLIBC_2_0); +#endif +versioned_symbol (libc, __pthread_cond_destroy, pthread_cond_destroy, + GLIBC_2_3_2); + +FORWARD (__pthread_cond_init, + (pthread_cond_t *cond, const pthread_condattr_t *cond_attr), + (cond, cond_attr), 0) +#if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_3_2) +strong_alias (__pthread_cond_init, __pthread_cond_init_2_0) +compat_symbol (libc, __pthread_cond_init_2_0, pthread_cond_init, GLIBC_2_0); +#endif +versioned_symbol (libc, __pthread_cond_init, pthread_cond_init, GLIBC_2_3_2); + +FORWARD (__pthread_cond_signal, (pthread_cond_t *cond), (cond), 0) +#if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_3_2) +strong_alias (__pthread_cond_signal, __pthread_cond_signal_2_0) +compat_symbol (libc, __pthread_cond_signal_2_0, pthread_cond_signal, + GLIBC_2_0); +#endif +versioned_symbol (libc, __pthread_cond_signal, pthread_cond_signal, + GLIBC_2_3_2); + +FORWARD (__pthread_cond_wait, (pthread_cond_t *cond, pthread_mutex_t *mutex), + (cond, mutex), 0) +#if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_3_2) +strong_alias (__pthread_cond_wait, __pthread_cond_wait_2_0) +compat_symbol (libc, __pthread_cond_wait_2_0, pthread_cond_wait, GLIBC_2_0); +#endif +versioned_symbol (libc, __pthread_cond_wait, pthread_cond_wait, GLIBC_2_3_2); + +FORWARD (__pthread_cond_timedwait, + (pthread_cond_t *cond, pthread_mutex_t *mutex, + const struct timespec *abstime), (cond, mutex, abstime), 0) +#if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_3_2) +strong_alias (__pthread_cond_timedwait, __pthread_cond_timedwait_2_0) +compat_symbol (libc, __pthread_cond_timedwait_2_0, pthread_cond_timedwait, GLIBC_2_0); +#endif +versioned_symbol (libc, __pthread_cond_timedwait, pthread_cond_timedwait, GLIBC_2_3_2); + + +FORWARD (pthread_equal, (pthread_t thread1, pthread_t thread2), + (thread1, thread2), 1) + + +/* Use an alias to avoid warning, as pthread_exit is declared noreturn. */ +FORWARD2 (__pthread_exit, void, (void *retval), (retval), exit (EXIT_SUCCESS)) +strong_alias (__pthread_exit, pthread_exit); + + +FORWARD (pthread_getschedparam, + (pthread_t target_thread, int *policy, struct sched_param *param), + (target_thread, policy, param), 0) +FORWARD (pthread_setschedparam, + (pthread_t target_thread, int policy, + const struct sched_param *param), (target_thread, policy, param), 0) + + +FORWARD (pthread_mutex_destroy, (pthread_mutex_t *mutex), (mutex), 0) + +FORWARD (pthread_mutex_init, + (pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr), + (mutex, mutexattr), 0) + +FORWARD (pthread_mutex_lock, (pthread_mutex_t *mutex), (mutex), 0) + +FORWARD (pthread_mutex_unlock, (pthread_mutex_t *mutex), (mutex), 0) + + +FORWARD2 (pthread_self, pthread_t, (void), (), return 0) + + +FORWARD (pthread_setcancelstate, (int state, int *oldstate), (state, oldstate), + 0) + +FORWARD (pthread_setcanceltype, (int type, int *oldtype), (type, oldtype), 0) + +FORWARD2 (_pthread_cleanup_push, void, (struct _pthread_cleanup_buffer * buffer, void (*routine)(void *), void * arg), (buffer, routine, arg), return) + +FORWARD2 (_pthread_cleanup_pop, void, (struct _pthread_cleanup_buffer * buffer, int execute), (buffer, execute), return) diff --git a/linuxthreads/internals.h b/linuxthreads/internals.h new file mode 100644 index 0000000000..605021766c --- /dev/null +++ b/linuxthreads/internals.h @@ -0,0 +1,550 @@ +/* Linuxthreads - a simple clone()-based implementation of Posix */ +/* threads for Linux. */ +/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ +/* */ +/* This program is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public License */ +/* as published by the Free Software Foundation; either version 2 */ +/* of the License, or (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Library General Public License for more details. */ + +#ifndef _INTERNALS_H +#define _INTERNALS_H 1 + +/* Internal data structures */ + +/* Includes */ + +#include <limits.h> +#include <signal.h> +#include <stdbool.h> +#include <unistd.h> +#include <stackinfo.h> +#include <sigcontextinfo.h> + +#include <tls.h> +#include "descr.h" + +#include "semaphore.h" +#include <pthread-functions.h> + +#ifndef THREAD_GETMEM +# define THREAD_GETMEM(descr, member) descr->member +#endif +#ifndef THREAD_GETMEM_NC +# define THREAD_GETMEM_NC(descr, member) descr->member +#endif +#ifndef THREAD_SETMEM +# define THREAD_SETMEM(descr, member, value) descr->member = (value) +#endif +#ifndef THREAD_SETMEM_NC +# define THREAD_SETMEM_NC(descr, member, value) descr->member = (value) +#endif + +#if !defined NOT_IN_libc && defined FLOATING_STACKS +# define LIBC_THREAD_GETMEM(descr, member) THREAD_GETMEM (descr, member) +# define LIBC_THREAD_SETMEM(descr, member, value) \ + THREAD_SETMEM (descr, member, value) +#else +# define LIBC_THREAD_GETMEM(descr, member) descr->member +# define LIBC_THREAD_SETMEM(descr, member, value) descr->member = (value) +#endif + +typedef void (*destr_function)(void *); + +struct pthread_key_struct { + int in_use; /* already allocated? */ + destr_function destr; /* destruction routine */ +}; + + +#define PTHREAD_START_ARGS_INITIALIZER(fct) \ + { (void *(*) (void *)) fct, NULL, {{0, }}, 0, { 0 } } + + +/* The type of thread handles. */ + +typedef struct pthread_handle_struct * pthread_handle; + +struct pthread_handle_struct { + struct _pthread_fastlock h_lock; /* Fast lock for sychronized access */ + pthread_descr h_descr; /* Thread descriptor or NULL if invalid */ + char * h_bottom; /* Lowest address in the stack thread */ +}; + +/* The type of messages sent to the thread manager thread */ + +struct pthread_request { + pthread_descr req_thread; /* Thread doing the request */ + enum { /* Request kind */ + REQ_CREATE, REQ_FREE, REQ_PROCESS_EXIT, REQ_MAIN_THREAD_EXIT, + REQ_POST, REQ_DEBUG, REQ_KICK, REQ_FOR_EACH_THREAD + } req_kind; + union { /* Arguments for request */ + struct { /* For REQ_CREATE: */ + const pthread_attr_t * attr; /* thread attributes */ + void * (*fn)(void *); /* start function */ + void * arg; /* argument to start function */ + sigset_t mask; /* signal mask */ + } create; + struct { /* For REQ_FREE: */ + pthread_t thread_id; /* identifier of thread to free */ + } free; + struct { /* For REQ_PROCESS_EXIT: */ + int code; /* exit status */ + } exit; + void * post; /* For REQ_POST: the semaphore */ + struct { /* For REQ_FOR_EACH_THREAD: callback */ + void (*fn)(void *, pthread_descr); + void *arg; + } for_each; + } req_args; +}; + + + +typedef void (*arch_sighandler_t) (int, SIGCONTEXT); +union sighandler +{ + arch_sighandler_t old; + void (*rt) (int, struct siginfo *, struct ucontext *); +}; +extern union sighandler __sighandler[NSIG]; + + +/* Signals used for suspend/restart and for cancellation notification. */ + +extern int __pthread_sig_restart; +extern int __pthread_sig_cancel; + +/* Signal used for interfacing with gdb */ + +extern int __pthread_sig_debug; + +/* Global array of thread handles, used for validating a thread id + and retrieving the corresponding thread descriptor. Also used for + mapping the available stack segments. */ + +extern struct pthread_handle_struct __pthread_handles[PTHREAD_THREADS_MAX]; + +/* Descriptor of the main thread */ + +extern pthread_descr __pthread_main_thread; + +/* File descriptor for sending requests to the thread manager. + Initially -1, meaning that __pthread_initialize_manager must be called. */ + +extern int __pthread_manager_request; + +/* Other end of the pipe for sending requests to the thread manager. */ + +extern int __pthread_manager_reader; + +#ifdef FLOATING_STACKS +/* Maximum stack size. */ +extern size_t __pthread_max_stacksize; +#endif + +/* Pending request for a process-wide exit */ + +extern int __pthread_exit_requested, __pthread_exit_code; + +/* Set to 1 by gdb if we're debugging */ + +extern volatile int __pthread_threads_debug; + +/* Globally enabled events. */ +extern volatile td_thr_events_t __pthread_threads_events; + +/* Pointer to descriptor of thread with last event. */ +extern volatile pthread_descr __pthread_last_event; + +/* Flag which tells whether we are executing on SMP kernel. */ +extern int __pthread_smp_kernel; + +/* Return the handle corresponding to a thread id */ + +static inline pthread_handle thread_handle(pthread_t id) +{ + return &__pthread_handles[id % PTHREAD_THREADS_MAX]; +} + +/* Validate a thread handle. Must have acquired h->h_spinlock before. */ + +static inline int invalid_handle(pthread_handle h, pthread_t id) +{ + return h->h_descr == NULL || h->h_descr->p_tid != id || h->h_descr->p_terminated; +} + +static inline int nonexisting_handle(pthread_handle h, pthread_t id) +{ + return h->h_descr == NULL || h->h_descr->p_tid != id; +} + +/* Fill in defaults left unspecified by pt-machine.h. */ + +/* We round up a value with page size. */ +#ifndef page_roundup +#define page_roundup(v,p) ((((size_t) (v)) + (p) - 1) & ~((p) - 1)) +#endif + +/* The page size we can get from the system. This should likely not be + changed by the machine file but, you never know. */ +#ifndef PAGE_SIZE +#define PAGE_SIZE (sysconf (_SC_PAGE_SIZE)) +#endif + +/* The initial size of the thread stack. Must be a multiple of PAGE_SIZE. */ +#ifndef INITIAL_STACK_SIZE +#define INITIAL_STACK_SIZE (4 * PAGE_SIZE) +#endif + +/* Size of the thread manager stack. The "- 32" avoids wasting space + with some malloc() implementations. */ +#ifndef THREAD_MANAGER_STACK_SIZE +#define THREAD_MANAGER_STACK_SIZE (2 * PAGE_SIZE - 32) +#endif + +/* The base of the "array" of thread stacks. The array will grow down from + here. Defaults to the calculated bottom of the initial application + stack. */ +#ifndef THREAD_STACK_START_ADDRESS +#define THREAD_STACK_START_ADDRESS __pthread_initial_thread_bos +#endif + +/* If MEMORY_BARRIER isn't defined in pt-machine.h, assume the + architecture doesn't need a memory barrier instruction (e.g. Intel + x86). Still we need the compiler to respect the barrier and emit + all outstanding operations which modify memory. Some architectures + distinguish between full, read and write barriers. */ + +#ifndef MEMORY_BARRIER +#define MEMORY_BARRIER() asm ("" : : : "memory") +#endif +#ifndef READ_MEMORY_BARRIER +#define READ_MEMORY_BARRIER() MEMORY_BARRIER() +#endif +#ifndef WRITE_MEMORY_BARRIER +#define WRITE_MEMORY_BARRIER() MEMORY_BARRIER() +#endif + +/* Max number of times we must spin on a spinlock calling sched_yield(). + After MAX_SPIN_COUNT iterations, we put the calling thread to sleep. */ + +#ifndef MAX_SPIN_COUNT +#define MAX_SPIN_COUNT 50 +#endif + +/* Max number of times the spinlock in the adaptive mutex implementation + spins actively on SMP systems. */ + +#ifndef MAX_ADAPTIVE_SPIN_COUNT +#define MAX_ADAPTIVE_SPIN_COUNT 100 +#endif + +/* Duration of sleep (in nanoseconds) when we can't acquire a spinlock + after MAX_SPIN_COUNT iterations of sched_yield(). + With the 2.0 and 2.1 kernels, this MUST BE > 2ms. + (Otherwise the kernel does busy-waiting for realtime threads, + giving other threads no chance to run.) */ + +#ifndef SPIN_SLEEP_DURATION +#define SPIN_SLEEP_DURATION 2000001 +#endif + +/* Defined and used in libc.so. */ +extern int __libc_multiple_threads attribute_hidden; +extern int __librt_multiple_threads; + +/* Debugging */ + +#ifdef DEBUG +#include <assert.h> +#define ASSERT assert +#define MSG __pthread_message +#else +#define ASSERT(x) +#define MSG(msg,arg...) +#endif + +/* Internal global functions */ + +extern void __pthread_do_exit (void *retval, char *currentframe) + __attribute__ ((__noreturn__)); +extern void __pthread_destroy_specifics (void); +extern void __pthread_perform_cleanup (char *currentframe); +extern void __pthread_init_max_stacksize (void); +extern int __pthread_initialize_manager (void); +extern void __pthread_message (const char * fmt, ...); +extern int __pthread_manager (void *reqfd); +extern int __pthread_manager_event (void *reqfd); +extern void __pthread_manager_sighandler (int sig); +extern void __pthread_reset_main_thread (void); +extern void __pthread_once_fork_prepare (void); +extern void __pthread_once_fork_parent (void); +extern void __pthread_once_fork_child (void); +extern void __flockfilelist (void); +extern void __funlockfilelist (void); +extern void __fresetlockfiles (void); +extern void __pthread_manager_adjust_prio (int thread_prio); +extern void __pthread_initialize_minimal (void); + +extern int __pthread_attr_setguardsize (pthread_attr_t *__attr, + size_t __guardsize); +extern int __pthread_attr_getguardsize (const pthread_attr_t *__attr, + size_t *__guardsize); +extern int __pthread_attr_setstackaddr (pthread_attr_t *__attr, + void *__stackaddr); +extern int __pthread_attr_getstackaddr (const pthread_attr_t *__attr, + void **__stackaddr); +extern int __pthread_attr_setstacksize (pthread_attr_t *__attr, + size_t __stacksize); +extern int __pthread_attr_getstacksize (const pthread_attr_t *__attr, + size_t *__stacksize); +extern int __pthread_attr_setstack (pthread_attr_t *__attr, void *__stackaddr, + size_t __stacksize); +extern int __pthread_attr_getstack (const pthread_attr_t *__attr, void **__stackaddr, + size_t *__stacksize); +extern int __pthread_attr_destroy (pthread_attr_t *attr); +extern int __pthread_attr_setdetachstate (pthread_attr_t *attr, + int detachstate); +extern int __pthread_attr_getdetachstate (const pthread_attr_t *attr, + int *detachstate); +extern int __pthread_attr_setschedparam (pthread_attr_t *attr, + const struct sched_param *param); +extern int __pthread_attr_getschedparam (const pthread_attr_t *attr, + struct sched_param *param); +extern int __pthread_attr_setschedpolicy (pthread_attr_t *attr, int policy); +extern int __pthread_attr_getschedpolicy (const pthread_attr_t *attr, + int *policy); +extern int __pthread_attr_setinheritsched (pthread_attr_t *attr, int inherit); +extern int __pthread_attr_getinheritsched (const pthread_attr_t *attr, + int *inherit); +extern int __pthread_attr_setscope (pthread_attr_t *attr, int scope); +extern int __pthread_attr_getscope (const pthread_attr_t *attr, int *scope); + +extern int __pthread_getconcurrency (void); +extern int __pthread_setconcurrency (int __level); +extern int __pthread_mutex_timedlock (pthread_mutex_t *__mutex, + const struct timespec *__abstime); +extern int __pthread_mutexattr_getpshared (const pthread_mutexattr_t *__attr, + int *__pshared); +extern int __pthread_mutexattr_setpshared (pthread_mutexattr_t *__attr, + int __pshared); +extern int __pthread_mutexattr_gettype (const pthread_mutexattr_t *__attr, + int *__kind); +extern void __pthread_kill_other_threads_np (void); +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_lock (pthread_mutex_t *__mutex); +extern int __pthread_mutex_trylock (pthread_mutex_t *__mutex); +extern int __pthread_mutex_unlock (pthread_mutex_t *__mutex); +#if defined NOT_IN_libc && defined IS_IN_libpthread +hidden_proto (__pthread_mutex_init) +hidden_proto (__pthread_mutex_destroy) +hidden_proto (__pthread_mutex_lock) +hidden_proto (__pthread_mutex_trylock) +hidden_proto (__pthread_mutex_unlock) +#endif +extern int __pthread_cond_init (pthread_cond_t *cond, + const pthread_condattr_t *cond_attr); +extern int __pthread_cond_destroy (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_cond_signal (pthread_cond_t *cond); +extern int __pthread_cond_broadcast (pthread_cond_t *cond); +extern int __pthread_condattr_init (pthread_condattr_t *attr); +extern int __pthread_condattr_destroy (pthread_condattr_t *attr); +extern pthread_t __pthread_self (void); +extern pthread_descr __pthread_thread_self (void); +extern pthread_descr __pthread_self_stack (void) attribute_hidden; +extern int __pthread_equal (pthread_t thread1, pthread_t thread2); +extern void __pthread_exit (void *retval); +extern int __pthread_getschedparam (pthread_t thread, int *policy, + struct sched_param *param); +extern int __pthread_setschedparam (pthread_t thread, int policy, + const struct sched_param *param); +extern int __pthread_setcancelstate (int state, int * oldstate); +extern int __pthread_setcanceltype (int type, int * oldtype); + +extern void __pthread_restart_old(pthread_descr th); +extern void __pthread_suspend_old(pthread_descr self); +extern int __pthread_timedsuspend_old(pthread_descr self, const struct timespec *abs); + +extern void __pthread_restart_new(pthread_descr th); +extern void __pthread_suspend_new(pthread_descr self); +extern int __pthread_timedsuspend_new(pthread_descr self, const struct timespec *abs); + +extern void __pthread_wait_for_restart_signal(pthread_descr self); + +extern void __pthread_sigsuspend (const sigset_t *mask) attribute_hidden; + +extern int __pthread_yield (void); + +extern int __pthread_rwlock_timedrdlock (pthread_rwlock_t *__restrict __rwlock, + __const struct timespec *__restrict + __abstime); +extern int __pthread_rwlock_timedwrlock (pthread_rwlock_t *__restrict __rwlock, + __const struct timespec *__restrict + __abstime); +extern int __pthread_rwlockattr_destroy (pthread_rwlockattr_t *__attr); + +extern int __pthread_barrierattr_getpshared (__const pthread_barrierattr_t * + __restrict __attr, + int *__restrict __pshared); + +extern int __pthread_spin_lock (pthread_spinlock_t *__lock); +extern int __pthread_spin_trylock (pthread_spinlock_t *__lock); +extern int __pthread_spin_unlock (pthread_spinlock_t *__lock); +extern int __pthread_spin_init (pthread_spinlock_t *__lock, int __pshared); +extern int __pthread_spin_destroy (pthread_spinlock_t *__lock); + +/* Global pointers to old or new suspend functions */ + +extern void (*__pthread_restart)(pthread_descr); +extern void (*__pthread_suspend)(pthread_descr); +extern int (*__pthread_timedsuspend)(pthread_descr, const struct timespec *); + +/* Prototypes for the function without cancelation support when the + normal version has it. */ +extern int __libc_close (int fd); +extern int __libc_nanosleep (const struct timespec *requested_time, + struct timespec *remaining); +/* Prototypes for some of the new semaphore functions. */ +extern int __new_sem_post (sem_t * sem); +extern int __new_sem_init (sem_t *__sem, int __pshared, unsigned int __value); +extern int __new_sem_wait (sem_t *__sem); +extern int __new_sem_trywait (sem_t *__sem); +extern int __new_sem_getvalue (sem_t *__restrict __sem, int *__restrict __sval); +extern int __new_sem_destroy (sem_t *__sem); + +/* Prototypes for compatibility functions. */ +extern int __pthread_attr_init_2_1 (pthread_attr_t *__attr); +extern int __pthread_attr_init_2_0 (pthread_attr_t *__attr); +extern int __pthread_create_2_1 (pthread_t *__restrict __threadp, + const pthread_attr_t *__attr, + void *(*__start_routine) (void *), + void *__restrict __arg); +extern int __pthread_create_2_0 (pthread_t *__restrict thread, + const pthread_attr_t *__attr, + void *(*__start_routine) (void *), + void *__restrict arg); + +/* The functions called the signal events. */ +extern void __linuxthreads_create_event (void); +extern void __linuxthreads_death_event (void); +extern void __linuxthreads_reap_event (void); + +/* This function is called to initialize the pthread library. */ +extern void __pthread_initialize (void); + +/* TSD. */ +extern int __pthread_internal_tsd_set (int key, const void * pointer); +extern void * __pthread_internal_tsd_get (int key); +extern void ** __attribute__ ((__const__)) + __pthread_internal_tsd_address (int key); + +/* Sighandler wrappers. */ +extern void __pthread_sighandler(int signo, SIGCONTEXT ctx); +extern void __pthread_sighandler_rt(int signo, struct siginfo *si, + struct ucontext *uc); +extern void __pthread_null_sighandler(int sig); +extern int __pthread_sigaction (int sig, const struct sigaction *act, + struct sigaction *oact); +extern int __pthread_sigwait (const sigset_t *set, int *sig); +extern int __pthread_raise (int sig); + +/* Cancellation. */ +extern int __pthread_enable_asynccancel (void) attribute_hidden; +extern void __pthread_disable_asynccancel (int oldtype) + internal_function attribute_hidden; + +/* 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 libc.so and are exported. */ +extern int __librt_enable_asynccancel (void); +extern void __librt_disable_asynccancel (int oldtype) internal_function; + +extern void __pthread_cleanup_upto (__jmp_buf target, + char *targetframe) attribute_hidden; +extern pid_t __pthread_fork (struct fork_block *b) attribute_hidden; + +#if !defined NOT_IN_libc +# define LIBC_CANCEL_ASYNC() \ + __libc_enable_asynccancel () +# define LIBC_CANCEL_RESET(oldtype) \ + __libc_disable_asynccancel (oldtype) +# define LIBC_CANCEL_HANDLED() \ + __asm (".globl " __SYMBOL_PREFIX "__libc_enable_asynccancel"); \ + __asm (".globl " __SYMBOL_PREFIX "__libc_disable_asynccancel") +#elif defined IS_IN_libpthread +# define LIBC_CANCEL_ASYNC() \ + __pthread_enable_asynccancel () +# define LIBC_CANCEL_RESET(oldtype) \ + __pthread_disable_asynccancel (oldtype) +# define LIBC_CANCEL_HANDLED() \ + __asm (".globl " __SYMBOL_PREFIX "__pthread_enable_asynccancel"); \ + __asm (".globl " __SYMBOL_PREFIX "__pthread_disable_asynccancel") +#elif defined IS_IN_librt +# define LIBC_CANCEL_ASYNC() \ + __librt_enable_asynccancel () +# define LIBC_CANCEL_RESET(oldtype) \ + __librt_disable_asynccancel (oldtype) +# define LIBC_CANCEL_HANDLED() \ + __asm (".globl " __SYMBOL_PREFIX "__librt_enable_asynccancel"); \ + __asm (".globl " __SYMBOL_PREFIX "__librt_disable_asynccancel") +#else +# define LIBC_CANCEL_ASYNC() 0 /* Just a dummy value. */ +# define LIBC_CANCEL_RESET(val) ((void)(val)) /* Nothing, but evaluate it. */ +# define LIBC_CANCEL_HANDLED() /* Nothing. */ +#endif + +extern int * __libc_pthread_init (const struct pthread_functions *functions); + +#if !defined NOT_IN_libc && !defined FLOATING_STACKS +# ifdef SHARED +# define thread_self() \ + (*__libc_pthread_functions.ptr_pthread_thread_self) () +# else +weak_extern (__pthread_thread_self) +# define thread_self() __pthread_thread_self () +# endif +#endif + +#ifndef USE_TLS +# define __manager_thread (&__pthread_manager_thread) +#else +# define __manager_thread __pthread_manager_threadp +#endif + +extern inline __attribute__((always_inline)) pthread_descr +check_thread_self (void) +{ + pthread_descr self = thread_self (); +#if defined THREAD_SELF && defined INIT_THREAD_SELF + if (self == __manager_thread) + { + /* A new thread might get a cancel signal before it is fully + initialized, so that the thread register might still point to the + manager thread. Double check that this is really the manager + thread. */ + self = __pthread_self_stack(); + if (self != __manager_thread) + /* Oops, thread_self() isn't working yet.. */ + INIT_THREAD_SELF(self, self->p_nr); + } +#endif + return self; +} + +#endif /* internals.h */ diff --git a/linuxthreads/join.c b/linuxthreads/join.c new file mode 100644 index 0000000000..148f222319 --- /dev/null +++ b/linuxthreads/join.c @@ -0,0 +1,220 @@ +/* Linuxthreads - a simple clone()-based implementation of Posix */ +/* threads for Linux. */ +/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ +/* */ +/* This program is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public License */ +/* as published by the Free Software Foundation; either version 2 */ +/* of the License, or (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Library General Public License for more details. */ + +/* Thread termination and joining */ + +#include <errno.h> +#include <sched.h> +#include <stdlib.h> +#include <unistd.h> +#include "pthread.h" +#include "internals.h" +#include "spinlock.h" +#include "restart.h" +#include <not-cancel.h> + +void __pthread_exit(void * retval) +{ + __pthread_do_exit (retval, CURRENT_STACK_FRAME); +} +strong_alias (__pthread_exit, pthread_exit); + +void __pthread_do_exit(void *retval, char *currentframe) +{ + pthread_descr self = thread_self(); + pthread_descr joining; + struct pthread_request request; + + /* Reset the cancellation flag to avoid looping if the cleanup handlers + contain cancellation points */ + THREAD_SETMEM(self, p_canceled, 0); + /* Call cleanup functions and destroy the thread-specific data */ + __pthread_perform_cleanup(currentframe); + __pthread_destroy_specifics(); + /* Store return value */ + __pthread_lock(THREAD_GETMEM(self, p_lock), self); + THREAD_SETMEM(self, p_retval, retval); + /* See whether we have to signal the death. */ + if (THREAD_GETMEM(self, p_report_events)) + { + /* See whether TD_DEATH is in any of the mask. */ + int idx = __td_eventword (TD_DEATH); + uint32_t mask = __td_eventmask (TD_DEATH); + + if ((mask & (__pthread_threads_events.event_bits[idx] + | THREAD_GETMEM_NC(self, + p_eventbuf.eventmask.event_bits[idx]))) + != 0) + { + /* Yep, we have to signal the death. */ + THREAD_SETMEM(self, p_eventbuf.eventnum, TD_DEATH); + THREAD_SETMEM(self, p_eventbuf.eventdata, self); + __pthread_last_event = self; + + /* Now call the function to signal the event. */ + __linuxthreads_death_event(); + } + } + /* Say that we've terminated */ + THREAD_SETMEM(self, p_terminated, 1); + /* See if someone is joining on us */ + joining = THREAD_GETMEM(self, p_joining); + __pthread_unlock(THREAD_GETMEM(self, p_lock)); + /* Restart joining thread if any */ + if (joining != NULL) restart(joining); + /* If this is the initial thread, block until all threads have terminated. + If another thread calls exit, we'll be terminated from our signal + handler. */ + if (self == __pthread_main_thread && __pthread_manager_request >= 0) { + request.req_thread = self; + request.req_kind = REQ_MAIN_THREAD_EXIT; + TEMP_FAILURE_RETRY(write_not_cancel(__pthread_manager_request, + (char *)&request, sizeof(request))); + suspend(self); + /* Main thread flushes stdio streams and runs atexit functions. + It also calls a handler within LinuxThreads which sends a process exit + request to the thread manager. */ + exit(0); + } + /* Threads other than the main one terminate without flushing stdio streams + or running atexit functions. */ + _exit(0); +} + +/* Function called by pthread_cancel to remove the thread from + waiting on a condition variable queue. */ + +static int join_extricate_func(void *obj, pthread_descr th) +{ + volatile pthread_descr self = thread_self(); + pthread_handle handle = obj; + pthread_descr jo; + int did_remove = 0; + + __pthread_lock(&handle->h_lock, self); + jo = handle->h_descr; + did_remove = jo->p_joining != NULL; + jo->p_joining = NULL; + __pthread_unlock(&handle->h_lock); + + return did_remove; +} + +int pthread_join(pthread_t thread_id, void ** thread_return) +{ + volatile pthread_descr self = thread_self(); + struct pthread_request request; + pthread_handle handle = thread_handle(thread_id); + pthread_descr th; + pthread_extricate_if extr; + int already_canceled = 0; + + /* Set up extrication interface */ + extr.pu_object = handle; + extr.pu_extricate_func = join_extricate_func; + + __pthread_lock(&handle->h_lock, self); + if (nonexisting_handle(handle, thread_id)) { + __pthread_unlock(&handle->h_lock); + return ESRCH; + } + th = handle->h_descr; + if (th == self) { + __pthread_unlock(&handle->h_lock); + return EDEADLK; + } + /* If detached or already joined, error */ + if (th->p_detached || th->p_joining != NULL) { + __pthread_unlock(&handle->h_lock); + return EINVAL; + } + /* If not terminated yet, suspend ourselves. */ + if (! th->p_terminated) { + /* Register extrication interface */ + __pthread_set_own_extricate_if(self, &extr); + if (!(THREAD_GETMEM(self, p_canceled) + && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE)) + th->p_joining = self; + else + already_canceled = 1; + __pthread_unlock(&handle->h_lock); + + if (already_canceled) { + __pthread_set_own_extricate_if(self, 0); + __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME); + } + + suspend(self); + /* Deregister extrication interface */ + __pthread_set_own_extricate_if(self, 0); + + /* This is a cancellation point */ + if (THREAD_GETMEM(self, p_woken_by_cancel) + && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) { + THREAD_SETMEM(self, p_woken_by_cancel, 0); + __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME); + } + __pthread_lock(&handle->h_lock, self); + } + /* Get return value */ + if (thread_return != NULL) *thread_return = th->p_retval; + __pthread_unlock(&handle->h_lock); + /* Send notification to thread manager */ + if (__pthread_manager_request >= 0) { + request.req_thread = self; + request.req_kind = REQ_FREE; + request.req_args.free.thread_id = thread_id; + TEMP_FAILURE_RETRY(write_not_cancel(__pthread_manager_request, + (char *) &request, sizeof(request))); + } + return 0; +} + +int pthread_detach(pthread_t thread_id) +{ + int terminated; + struct pthread_request request; + pthread_handle handle = thread_handle(thread_id); + pthread_descr th; + + __pthread_lock(&handle->h_lock, NULL); + if (nonexisting_handle(handle, thread_id)) { + __pthread_unlock(&handle->h_lock); + return ESRCH; + } + th = handle->h_descr; + /* If already detached, error */ + if (th->p_detached) { + __pthread_unlock(&handle->h_lock); + return EINVAL; + } + /* If already joining, don't do anything. */ + if (th->p_joining != NULL) { + __pthread_unlock(&handle->h_lock); + return 0; + } + /* Mark as detached */ + th->p_detached = 1; + terminated = th->p_terminated; + __pthread_unlock(&handle->h_lock); + /* If already terminated, notify thread manager to reclaim resources */ + if (terminated && __pthread_manager_request >= 0) { + request.req_thread = thread_self(); + request.req_kind = REQ_FREE; + request.req_args.free.thread_id = thread_id; + TEMP_FAILURE_RETRY(write_not_cancel(__pthread_manager_request, + (char *) &request, sizeof(request))); + } + return 0; +} diff --git a/linuxthreads/joinrace.c b/linuxthreads/joinrace.c new file mode 100644 index 0000000000..8e1064c984 --- /dev/null +++ b/linuxthreads/joinrace.c @@ -0,0 +1,48 @@ +/* Test case by Permaine Cheung <pcheung@cygnus.com>. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> + +static void * +sub1 (void *arg) +{ + /* Nothing. */ + return NULL; +} + +int +main (void) +{ + int istatus; + int policy; + int cnt; + pthread_t thread1; + struct sched_param spresult1, sp1; + + for (cnt = 0; cnt < 100; ++cnt) + { + printf ("Round %d\n", cnt); + + pthread_create (&thread1, NULL, &sub1, NULL); + pthread_join (thread1, NULL); + + istatus = pthread_getschedparam (thread1, &policy, &spresult1); + if (istatus != ESRCH) + { + printf ("pthread_getschedparam returns: %d\n", istatus); + return 1; + } + + sp1.sched_priority = 0; + istatus = pthread_setschedparam (thread1, SCHED_OTHER, &sp1); + if (istatus != ESRCH) + { + printf ("pthread_setschedparam returns: %d\n", istatus); + return 2; + } + } + + return 0; +} diff --git a/linuxthreads/libc-cancellation.c b/linuxthreads/libc-cancellation.c new file mode 100644 index 0000000000..c28920feb3 --- /dev/null +++ b/linuxthreads/libc-cancellation.c @@ -0,0 +1,64 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <rpc/rpc.h> +#include "pthread.h" +#include "internals.h" +#include "spinlock.h" +#include "restart.h" +#include <bits/libc-lock.h> + +#if !defined NOT_IN_libc + +# ifndef SHARED +weak_extern (__pthread_do_exit) +# endif + +int __libc_multiple_threads attribute_hidden __attribute__((nocommon)); +strong_alias (__libc_multiple_threads, __librt_multiple_threads); + +/* 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) +{ + pthread_descr self = thread_self(); + int oldtype = LIBC_THREAD_GETMEM(self, p_canceltype); + LIBC_THREAD_SETMEM(self, p_canceltype, PTHREAD_CANCEL_ASYNCHRONOUS); + if (__builtin_expect (LIBC_THREAD_GETMEM(self, p_canceled), 0) && + LIBC_THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) + __libc_maybe_call2 (pthread_do_exit, + (PTHREAD_CANCELED, CURRENT_STACK_FRAME), 0); + return oldtype; +} +strong_alias (__libc_enable_asynccancel, __librt_enable_asynccancel) + +void +internal_function attribute_hidden +__libc_disable_asynccancel (int oldtype) +{ + pthread_descr self = thread_self(); + LIBC_THREAD_SETMEM(self, p_canceltype, oldtype); +} +strong_alias (__libc_disable_asynccancel, __librt_disable_asynccancel) + +#endif diff --git a/linuxthreads/libc-tls-loc.c b/linuxthreads/libc-tls-loc.c new file mode 100644 index 0000000000..a0a4b1b07d --- /dev/null +++ b/linuxthreads/libc-tls-loc.c @@ -0,0 +1,49 @@ +/* Special definitions for libc's own exposed thread-specific variables. + 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 <tls.h> + +#if USE___THREAD +# include <errno.h> +# include <netdb.h> +# include <resolv.h> + +/* These functions have identical definitions in libc. But the versioned + dependencies in executables bind them to libpthread.so definitions, + so we must have some here. */ + +int * +__errno_location (void) +{ + return &errno; +} + +int * +__h_errno_location (void) +{ + return &h_errno; +} + +struct __res_state * +__res_state (void) +{ + return __resp; +} + +#endif diff --git a/linuxthreads/libc-tsd.c b/linuxthreads/libc-tsd.c new file mode 100644 index 0000000000..353ffb380a --- /dev/null +++ b/linuxthreads/libc-tsd.c @@ -0,0 +1,41 @@ +/* Special hack used to build link-time libc.so object for linking libpthread. + 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; 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 <tls.h> +#include <resolv.h> + +#if ! USE___THREAD + +/* Special hack used to build link-time libc.so object for linking libpthread. + See Makefile comments near libc_pic_lite.os rule for what this is for. */ + +# undef _res + +int _errno; +int _h_errno; +struct __res_state _res; + +#endif + +int +__res_maybe_init (res_state resp, int preinit) +{ + return -1; +} +libc_hidden_def (__res_maybe_init) diff --git a/linuxthreads/libc_pthread_init.c b/linuxthreads/libc_pthread_init.c new file mode 100644 index 0000000000..99213a2ff0 --- /dev/null +++ b/linuxthreads/libc_pthread_init.c @@ -0,0 +1,46 @@ +/* Copyright (C) 2002 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 <locale.h> +#include <stdlib.h> +#include <string.h> +#include <tls.h> +#include "internals.h" +#include <sysdep-cancel.h> + +int * +__libc_pthread_init (functions) + const struct pthread_functions *functions; +{ +#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 + +#if !(USE_TLS && HAVE___THREAD) + /* Initialize thread-locale current locale to point to the global one. + With __thread support, the variable's initializer takes care of this. */ + __uselocale (LC_GLOBAL_LOCALE); +#endif + + return &__libc_multiple_threads; +} diff --git a/linuxthreads/linuxthreads.texi b/linuxthreads/linuxthreads.texi new file mode 100644 index 0000000000..795fb70977 --- /dev/null +++ b/linuxthreads/linuxthreads.texi @@ -0,0 +1,1627 @@ +@node POSIX Threads +@c @node POSIX Threads, , Top, Top +@chapter POSIX Threads +@c %MENU% The standard threads library + +@c This chapter needs more work bigtime. -zw + +This chapter describes the pthreads (POSIX threads) library. This +library provides support functions for multithreaded programs: thread +primitives, synchronization objects, and so forth. It also implements +POSIX 1003.1b semaphores (not to be confused with System V semaphores). + +The threads operations (@samp{pthread_*}) do not use @var{errno}. +Instead they return an error code directly. The semaphore operations do +use @var{errno}. + +@menu +* Basic Thread Operations:: Creating, terminating, and waiting for threads. +* Thread Attributes:: Tuning thread scheduling. +* Cancellation:: Stopping a thread before it's done. +* Cleanup Handlers:: Deallocating resources when a thread is + canceled. +* Mutexes:: One way to synchronize threads. +* Condition Variables:: Another way. +* POSIX Semaphores:: And a third way. +* Thread-Specific Data:: Variables with different values in + different threads. +* Threads and Signal Handling:: Why you should avoid mixing the two, and + how to do it if you must. +* Threads and Fork:: Interactions between threads and the + @code{fork} function. +* Streams and Fork:: Interactions between stdio streams and + @code{fork}. +* Miscellaneous Thread Functions:: A grab bag of utility routines. +@end menu + +@node Basic Thread Operations +@section Basic Thread Operations + +These functions are the thread equivalents of @code{fork}, @code{exit}, +and @code{wait}. + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_create (pthread_t * @var{thread}, pthread_attr_t * @var{attr}, void * (*@var{start_routine})(void *), void * @var{arg}) +@code{pthread_create} creates a new thread of control that executes +concurrently with the calling thread. The new thread calls the +function @var{start_routine}, passing it @var{arg} as first argument. The +new thread terminates either explicitly, by calling @code{pthread_exit}, +or implicitly, by returning from the @var{start_routine} function. The +latter case is equivalent to calling @code{pthread_exit} with the result +returned by @var{start_routine} as exit code. + +The @var{attr} argument specifies thread attributes to be applied to the +new thread. @xref{Thread Attributes}, for details. The @var{attr} +argument can also be @code{NULL}, in which case default attributes are +used: the created thread is joinable (not detached) and has an ordinary +(not realtime) scheduling policy. + +On success, the identifier of the newly created thread is stored in the +location pointed by the @var{thread} argument, and a 0 is returned. On +error, a non-zero error code is returned. + +This function may return the following errors: +@table @code +@item EAGAIN +Not enough system resources to create a process for the new thread, +or more than @code{PTHREAD_THREADS_MAX} threads are already active. +@end table +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun void pthread_exit (void *@var{retval}) +@code{pthread_exit} terminates the execution of the calling thread. All +cleanup handlers (@pxref{Cleanup Handlers}) that have been set for the +calling thread with @code{pthread_cleanup_push} are executed in reverse +order (the most recently pushed handler is executed first). Finalization +functions for thread-specific data are then called for all keys that +have non-@code{NULL} values associated with them in the calling thread +(@pxref{Thread-Specific Data}). Finally, execution of the calling +thread is stopped. + +The @var{retval} argument is the return value of the thread. It can be +retrieved from another thread using @code{pthread_join}. + +The @code{pthread_exit} function never returns. +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_cancel (pthread_t @var{thread}) + +@code{pthread_cancel} sends a cancellation request to the thread denoted +by the @var{thread} argument. If there is no such thread, +@code{pthread_cancel} fails and returns @code{ESRCH}. Otherwise it +returns 0. @xref{Cancellation}, for details. +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_join (pthread_t @var{th}, void **thread_@var{return}) +@code{pthread_join} suspends the execution of the calling thread until +the thread identified by @var{th} terminates, either by calling +@code{pthread_exit} or by being canceled. + +If @var{thread_return} is not @code{NULL}, the return value of @var{th} +is stored in the location pointed to by @var{thread_return}. The return +value of @var{th} is either the argument it gave to @code{pthread_exit}, +or @code{PTHREAD_CANCELED} if @var{th} was canceled. + +The joined thread @code{th} must be in the joinable state: it must not +have been detached using @code{pthread_detach} or the +@code{PTHREAD_CREATE_DETACHED} attribute to @code{pthread_create}. + +When a joinable thread terminates, its memory resources (thread +descriptor and stack) are not deallocated until another thread performs +@code{pthread_join} on it. Therefore, @code{pthread_join} must be called +once for each joinable thread created to avoid memory leaks. + +At most one thread can wait for the termination of a given +thread. Calling @code{pthread_join} on a thread @var{th} on which +another thread is already waiting for termination returns an error. + +@code{pthread_join} is a cancellation point. If a thread is canceled +while suspended in @code{pthread_join}, the thread execution resumes +immediately and the cancellation is executed without waiting for the +@var{th} thread to terminate. If cancellation occurs during +@code{pthread_join}, the @var{th} thread remains not joined. + +On success, the return value of @var{th} is stored in the location +pointed to by @var{thread_return}, and 0 is returned. On error, one of +the following values is returned: +@table @code +@item ESRCH +No thread could be found corresponding to that specified by @var{th}. +@item EINVAL +The @var{th} thread has been detached, or another thread is already +waiting on termination of @var{th}. +@item EDEADLK +The @var{th} argument refers to the calling thread. +@end table +@end deftypefun + +@node Thread Attributes +@section Thread Attributes + +@comment pthread.h +@comment POSIX + +Threads have a number of attributes that may be set at creation time. +This is done by filling a thread attribute object @var{attr} of type +@code{pthread_attr_t}, then passing it as second argument to +@code{pthread_create}. Passing @code{NULL} is equivalent to passing a +thread attribute object with all attributes set to their default values. + +Attribute objects are consulted only when creating a new thread. The +same attribute object can be used for creating several threads. +Modifying an attribute object after a call to @code{pthread_create} does +not change the attributes of the thread previously created. + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_attr_init (pthread_attr_t *@var{attr}) +@code{pthread_attr_init} initializes the thread attribute object +@var{attr} and fills it with default values for the attributes. (The +default values are listed below for each attribute.) + +Each attribute @var{attrname} (see below for a list of all attributes) +can be individually set using the function +@code{pthread_attr_set@var{attrname}} and retrieved using the function +@code{pthread_attr_get@var{attrname}}. +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_attr_destroy (pthread_attr_t *@var{attr}) +@code{pthread_attr_destroy} destroys the attribute object pointed to by +@var{attr} releasing any resources associated with it. @var{attr} is +left in an undefined state, and you must not use it again in a call to +any pthreads function until it has been reinitialized. +@end deftypefun + +@findex pthread_attr_setdetachstate +@findex pthread_attr_setguardsize +@findex pthread_attr_setinheritsched +@findex pthread_attr_setschedparam +@findex pthread_attr_setschedpolicy +@findex pthread_attr_setscope +@findex pthread_attr_setstack +@findex pthread_attr_setstackaddr +@findex pthread_attr_setstacksize +@comment pthread.h +@comment POSIX +@deftypefun int pthread_attr_setattr (pthread_attr_t *@var{obj}, int @var{value}) +Set attribute @var{attr} to @var{value} in the attribute object pointed +to by @var{obj}. See below for a list of possible attributes and the +values they can take. + +On success, these functions return 0. If @var{value} is not meaningful +for the @var{attr} being modified, they will return the error code +@code{EINVAL}. Some of the functions have other failure modes; see +below. +@end deftypefun + +@findex pthread_attr_getdetachstate +@findex pthread_attr_getguardsize +@findex pthread_attr_getinheritsched +@findex pthread_attr_getschedparam +@findex pthread_attr_getschedpolicy +@findex pthread_attr_getscope +@findex pthread_attr_getstack +@findex pthread_attr_getstackaddr +@findex pthread_attr_getstacksize +@comment pthread.h +@comment POSIX +@deftypefun int pthread_attr_getattr (const pthread_attr_t *@var{obj}, int *@var{value}) +Store the current setting of @var{attr} in @var{obj} into the variable +pointed to by @var{value}. + +These functions always return 0. +@end deftypefun + +The following thread attributes are supported: +@table @samp +@item detachstate +Choose whether the thread is created in the joinable state (value +@code{PTHREAD_CREATE_JOINABLE}) or in the detached state +(@code{PTHREAD_CREATE_DETACHED}). The default is +@code{PTHREAD_CREATE_JOINABLE}. + +In the joinable state, another thread can synchronize on the thread +termination and recover its termination code using @code{pthread_join}, +but some of the thread resources are kept allocated after the thread +terminates, and reclaimed only when another thread performs +@code{pthread_join} on that thread. + +In the detached state, the thread resources are immediately freed when +it terminates, but @code{pthread_join} cannot be used to synchronize on +the thread termination. + +A thread created in the joinable state can later be put in the detached +thread using @code{pthread_detach}. + +@item schedpolicy +Select the scheduling policy for the thread: one of @code{SCHED_OTHER} +(regular, non-realtime scheduling), @code{SCHED_RR} (realtime, +round-robin) or @code{SCHED_FIFO} (realtime, first-in first-out). +The default is @code{SCHED_OTHER}. +@c Not doc'd in our manual: FIXME. +@c See @code{sched_setpolicy} for more information on scheduling policies. + +The realtime scheduling policies @code{SCHED_RR} and @code{SCHED_FIFO} +are available only to processes with superuser privileges. +@code{pthread_attr_setschedparam} will fail and return @code{ENOTSUP} if +you try to set a realtime policy when you are unprivileged. + +The scheduling policy of a thread can be changed after creation with +@code{pthread_setschedparam}. + +@item schedparam +Change the scheduling parameter (the scheduling priority) +for the thread. The default is 0. + +This attribute is not significant if the scheduling policy is +@code{SCHED_OTHER}; it only matters for the realtime policies +@code{SCHED_RR} and @code{SCHED_FIFO}. + +The scheduling priority of a thread can be changed after creation with +@code{pthread_setschedparam}. + +@item inheritsched +Choose whether the scheduling policy and scheduling parameter for the +newly created thread are determined by the values of the +@var{schedpolicy} and @var{schedparam} attributes (value +@code{PTHREAD_EXPLICIT_SCHED}) or are inherited from the parent thread +(value @code{PTHREAD_INHERIT_SCHED}). The default is +@code{PTHREAD_EXPLICIT_SCHED}. + +@item scope +Choose the scheduling contention scope for the created thread. The +default is @code{PTHREAD_SCOPE_SYSTEM}, meaning that the threads contend +for CPU time with all processes running on the machine. In particular, +thread priorities are interpreted relative to the priorities of all +other processes on the machine. The other possibility, +@code{PTHREAD_SCOPE_PROCESS}, means that scheduling contention occurs +only between the threads of the running process: thread priorities are +interpreted relative to the priorities of the other threads of the +process, regardless of the priorities of other processes. + +@code{PTHREAD_SCOPE_PROCESS} is not supported in LinuxThreads. If you +try to set the scope to this value, @code{pthread_attr_setscope} will +fail and return @code{ENOTSUP}. + +@item stackaddr +Provide an address for an application managed stack. The size of the +stack must be at least @code{PTHREAD_STACK_MIN}. + +@item stacksize +Change the size of the stack created for the thread. The value defines +the minimum stack size, in bytes. + +If the value exceeds the system's maximum stack size, or is smaller +than @code{PTHREAD_STACK_MIN}, @code{pthread_attr_setstacksize} will +fail and return @code{EINVAL}. + +@item stack +Provide both the address and size of an application managed stack to +use for the new thread. The base of the memory area is @var{stackaddr} +with the size of the memory area, @var{stacksize}, measured in bytes. + +If the value of @var{stacksize} is less than @code{PTHREAD_STACK_MIN}, +or greater than the system's maximum stack size, or if the value of +@var{stackaddr} lacks the proper alignment, @code{pthread_attr_setstack} +will fail and return @code{EINVAL}. + +@item guardsize +Change the minimum size in bytes of the guard area for the thread's +stack. The default size is a single page. If this value is set, it +will be rounded up to the nearest page size. If the value is set to 0, +a guard area will not be created for this thread. The space allocated +for the guard area is used to catch stack overflow. Therefore, when +allocating large structures on the stack, a larger guard area may be +required to catch a stack overflow. + +If the caller is managing their own stacks (if the @code{stackaddr} +attribute has been set), then the @code{guardsize} attribute is ignored. + +If the value exceeds the @code{stacksize}, @code{pthread_atrr_setguardsize} +will fail and return @code{EINVAL}. +@end table + +@node Cancellation +@section Cancellation + +Cancellation is the mechanism by which a thread can terminate the +execution of another thread. More precisely, a thread can send a +cancellation request to another thread. Depending on its settings, the +target thread can then either ignore the request, honor it immediately, +or defer it till it reaches a cancellation point. When threads are +first created by @code{pthread_create}, they always defer cancellation +requests. + +When a thread eventually honors a cancellation request, it behaves as if +@code{pthread_exit(PTHREAD_CANCELED)} was called. All cleanup handlers +are executed in reverse order, finalization functions for +thread-specific data are called, and finally the thread stops executing. +If the canceled thread was joinable, the return value +@code{PTHREAD_CANCELED} is provided to whichever thread calls +@var{pthread_join} on it. See @code{pthread_exit} for more information. + +Cancellation points are the points where the thread checks for pending +cancellation requests and performs them. The POSIX threads functions +@code{pthread_join}, @code{pthread_cond_wait}, +@code{pthread_cond_timedwait}, @code{pthread_testcancel}, +@code{sem_wait}, and @code{sigwait} are cancellation points. In +addition, these system calls are cancellation points: + +@multitable @columnfractions .33 .33 .33 +@item @t{accept} @tab @t{open} @tab @t{sendmsg} +@item @t{close} @tab @t{pause} @tab @t{sendto} +@item @t{connect} @tab @t{read} @tab @t{system} +@item @t{fcntl} @tab @t{recv} @tab @t{tcdrain} +@item @t{fsync} @tab @t{recvfrom} @tab @t{wait} +@item @t{lseek} @tab @t{recvmsg} @tab @t{waitpid} +@item @t{msync} @tab @t{send} @tab @t{write} +@item @t{nanosleep} +@end multitable + +@noindent +All library functions that call these functions (such as +@code{printf}) are also cancellation points. + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_setcancelstate (int @var{state}, int *@var{oldstate}) +@code{pthread_setcancelstate} changes the cancellation state for the +calling thread -- that is, whether cancellation requests are ignored or +not. The @var{state} argument is the new cancellation state: either +@code{PTHREAD_CANCEL_ENABLE} to enable cancellation, or +@code{PTHREAD_CANCEL_DISABLE} to disable cancellation (cancellation +requests are ignored). + +If @var{oldstate} is not @code{NULL}, the previous cancellation state is +stored in the location pointed to by @var{oldstate}, and can thus be +restored later by another call to @code{pthread_setcancelstate}. + +If the @var{state} argument is not @code{PTHREAD_CANCEL_ENABLE} or +@code{PTHREAD_CANCEL_DISABLE}, @code{pthread_setcancelstate} fails and +returns @code{EINVAL}. Otherwise it returns 0. +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_setcanceltype (int @var{type}, int *@var{oldtype}) +@code{pthread_setcanceltype} changes the type of responses to +cancellation requests for the calling thread: asynchronous (immediate) +or deferred. The @var{type} argument is the new cancellation type: +either @code{PTHREAD_CANCEL_ASYNCHRONOUS} to cancel the calling thread +as soon as the cancellation request is received, or +@code{PTHREAD_CANCEL_DEFERRED} to keep the cancellation request pending +until the next cancellation point. If @var{oldtype} is not @code{NULL}, +the previous cancellation state is stored in the location pointed to by +@var{oldtype}, and can thus be restored later by another call to +@code{pthread_setcanceltype}. + +If the @var{type} argument is not @code{PTHREAD_CANCEL_DEFERRED} or +@code{PTHREAD_CANCEL_ASYNCHRONOUS}, @code{pthread_setcanceltype} fails +and returns @code{EINVAL}. Otherwise it returns 0. +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun void pthread_testcancel (@var{void}) +@code{pthread_testcancel} does nothing except testing for pending +cancellation and executing it. Its purpose is to introduce explicit +checks for cancellation in long sequences of code that do not call +cancellation point functions otherwise. +@end deftypefun + +@node Cleanup Handlers +@section Cleanup Handlers + +Cleanup handlers are functions that get called when a thread terminates, +either by calling @code{pthread_exit} or because of +cancellation. Cleanup handlers are installed and removed following a +stack-like discipline. + +The purpose of cleanup handlers is to free the resources that a thread +may hold at the time it terminates. In particular, if a thread exits or +is canceled while it owns a locked mutex, the mutex will remain locked +forever and prevent other threads from executing normally. The best way +to avoid this is, just before locking the mutex, to install a cleanup +handler whose effect is to unlock the mutex. Cleanup handlers can be +used similarly to free blocks allocated with @code{malloc} or close file +descriptors on thread termination. + +Here is how to lock a mutex @var{mut} in such a way that it will be +unlocked if the thread is canceled while @var{mut} is locked: + +@smallexample +pthread_cleanup_push(pthread_mutex_unlock, (void *) &mut); +pthread_mutex_lock(&mut); +/* do some work */ +pthread_mutex_unlock(&mut); +pthread_cleanup_pop(0); +@end smallexample + +Equivalently, the last two lines can be replaced by + +@smallexample +pthread_cleanup_pop(1); +@end smallexample + +Notice that the code above is safe only in deferred cancellation mode +(see @code{pthread_setcanceltype}). In asynchronous cancellation mode, a +cancellation can occur between @code{pthread_cleanup_push} and +@code{pthread_mutex_lock}, or between @code{pthread_mutex_unlock} and +@code{pthread_cleanup_pop}, resulting in both cases in the thread trying +to unlock a mutex not locked by the current thread. This is the main +reason why asynchronous cancellation is difficult to use. + +If the code above must also work in asynchronous cancellation mode, +then it must switch to deferred mode for locking and unlocking the +mutex: + +@smallexample +pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldtype); +pthread_cleanup_push(pthread_mutex_unlock, (void *) &mut); +pthread_mutex_lock(&mut); +/* do some work */ +pthread_cleanup_pop(1); +pthread_setcanceltype(oldtype, NULL); +@end smallexample + +The code above can be rewritten in a more compact and efficient way, +using the non-portable functions @code{pthread_cleanup_push_defer_np} +and @code{pthread_cleanup_pop_restore_np}: + +@smallexample +pthread_cleanup_push_defer_np(pthread_mutex_unlock, (void *) &mut); +pthread_mutex_lock(&mut); +/* do some work */ +pthread_cleanup_pop_restore_np(1); +@end smallexample + +@comment pthread.h +@comment POSIX +@deftypefun void pthread_cleanup_push (void (*@var{routine}) (void *), void *@var{arg}) + +@code{pthread_cleanup_push} installs the @var{routine} function with +argument @var{arg} as a cleanup handler. From this point on to the +matching @code{pthread_cleanup_pop}, the function @var{routine} will be +called with arguments @var{arg} when the thread terminates, either +through @code{pthread_exit} or by cancellation. If several cleanup +handlers are active at that point, they are called in LIFO order: the +most recently installed handler is called first. +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun void pthread_cleanup_pop (int @var{execute}) +@code{pthread_cleanup_pop} removes the most recently installed cleanup +handler. If the @var{execute} argument is not 0, it also executes the +handler, by calling the @var{routine} function with arguments +@var{arg}. If the @var{execute} argument is 0, the handler is only +removed but not executed. +@end deftypefun + +Matching pairs of @code{pthread_cleanup_push} and +@code{pthread_cleanup_pop} must occur in the same function, at the same +level of block nesting. Actually, @code{pthread_cleanup_push} and +@code{pthread_cleanup_pop} are macros, and the expansion of +@code{pthread_cleanup_push} introduces an open brace @code{@{} with the +matching closing brace @code{@}} being introduced by the expansion of the +matching @code{pthread_cleanup_pop}. + +@comment pthread.h +@comment GNU +@deftypefun void pthread_cleanup_push_defer_np (void (*@var{routine}) (void *), void *@var{arg}) +@code{pthread_cleanup_push_defer_np} is a non-portable extension that +combines @code{pthread_cleanup_push} and @code{pthread_setcanceltype}. +It pushes a cleanup handler just as @code{pthread_cleanup_push} does, +but also saves the current cancellation type and sets it to deferred +cancellation. This ensures that the cleanup mechanism is effective even +if the thread was initially in asynchronous cancellation mode. +@end deftypefun + +@comment pthread.h +@comment GNU +@deftypefun void pthread_cleanup_pop_restore_np (int @var{execute}) +@code{pthread_cleanup_pop_restore_np} pops a cleanup handler introduced +by @code{pthread_cleanup_push_defer_np}, and restores the cancellation +type to its value at the time @code{pthread_cleanup_push_defer_np} was +called. +@end deftypefun + +@code{pthread_cleanup_push_defer_np} and +@code{pthread_cleanup_pop_restore_np} must occur in matching pairs, at +the same level of block nesting. + +The sequence + +@smallexample +pthread_cleanup_push_defer_np(routine, arg); +... +pthread_cleanup_pop_restore_np(execute); +@end smallexample + +@noindent +is functionally equivalent to (but more compact and efficient than) + +@smallexample +@{ + int oldtype; + pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldtype); + pthread_cleanup_push(routine, arg); + ... + pthread_cleanup_pop(execute); + pthread_setcanceltype(oldtype, NULL); +@} +@end smallexample + + +@node Mutexes +@section Mutexes + +A mutex is a MUTual EXclusion device, and is useful for protecting +shared data structures from concurrent modifications, and implementing +critical sections and monitors. + +A mutex has two possible states: unlocked (not owned by any thread), +and locked (owned by one thread). A mutex can never be owned by two +different threads simultaneously. A thread attempting to lock a mutex +that is already locked by another thread is suspended until the owning +thread unlocks the mutex first. + +None of the mutex functions is a cancellation point, not even +@code{pthread_mutex_lock}, in spite of the fact that it can suspend a +thread for arbitrary durations. This way, the status of mutexes at +cancellation points is predictable, allowing cancellation handlers to +unlock precisely those mutexes that need to be unlocked before the +thread stops executing. Consequently, threads using deferred +cancellation should never hold a mutex for extended periods of time. + +It is not safe to call mutex functions from a signal handler. In +particular, calling @code{pthread_mutex_lock} or +@code{pthread_mutex_unlock} from a signal handler may deadlock the +calling thread. + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_mutex_init (pthread_mutex_t *@var{mutex}, const pthread_mutexattr_t *@var{mutexattr}) + +@code{pthread_mutex_init} initializes the mutex object pointed to by +@var{mutex} according to the mutex attributes specified in @var{mutexattr}. +If @var{mutexattr} is @code{NULL}, default attributes are used instead. + +The LinuxThreads implementation supports only one mutex attribute, +the @var{mutex type}, which is either ``fast'', ``recursive'', or +``error checking''. The type of a mutex determines whether +it can be locked again by a thread that already owns it. +The default type is ``fast''. + +Variables of type @code{pthread_mutex_t} can also be initialized +statically, using the constants @code{PTHREAD_MUTEX_INITIALIZER} (for +timed mutexes), @code{PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP} (for +recursive mutexes), @code{PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP} +(for fast mutexes(, and @code{PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP} +(for error checking mutexes). + +@code{pthread_mutex_init} always returns 0. +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_mutex_lock (pthread_mutex_t *mutex)) +@code{pthread_mutex_lock} locks the given mutex. If the mutex is +currently unlocked, it becomes locked and owned by the calling thread, +and @code{pthread_mutex_lock} returns immediately. If the mutex is +already locked by another thread, @code{pthread_mutex_lock} suspends the +calling thread until the mutex is unlocked. + +If the mutex is already locked by the calling thread, the behavior of +@code{pthread_mutex_lock} depends on the type of the mutex. If the mutex +is of the ``fast'' type, the calling thread is suspended. It will +remain suspended forever, because no other thread can unlock the mutex. +If the mutex is of the ``error checking'' type, @code{pthread_mutex_lock} +returns immediately with the error code @code{EDEADLK}. If the mutex is +of the ``recursive'' type, @code{pthread_mutex_lock} succeeds and +returns immediately, recording the number of times the calling thread +has locked the mutex. An equal number of @code{pthread_mutex_unlock} +operations must be performed before the mutex returns to the unlocked +state. +@c This doesn't discuss PTHREAD_MUTEX_TIMED_NP mutex attributes. FIXME +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_mutex_trylock (pthread_mutex_t *@var{mutex}) +@code{pthread_mutex_trylock} behaves identically to +@code{pthread_mutex_lock}, except that it does not block the calling +thread if the mutex is already locked by another thread (or by the +calling thread in the case of a ``fast'' mutex). Instead, +@code{pthread_mutex_trylock} returns immediately with the error code +@code{EBUSY}. +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_mutex_timedlock (pthread_mutex_t *@var{mutex}, const struct timespec *@var{abstime}) +The @code{pthread_mutex_timedlock} is similar to the +@code{pthread_mutex_lock} function but instead of blocking for in +indefinite time if the mutex is locked by another thread, it returns +when the time specified in @var{abstime} is reached. + +This function can only be used on standard (``timed'') and ``error +checking'' mutexes. It behaves just like @code{pthread_mutex_lock} for +all other types. + +If the mutex is successfully locked, the function returns zero. If the +time specified in @var{abstime} is reached without the mutex being locked, +@code{ETIMEDOUT} is returned. + +This function was introduced in the POSIX.1d revision of the POSIX standard. +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_mutex_unlock (pthread_mutex_t *@var{mutex}) +@code{pthread_mutex_unlock} unlocks the given mutex. The mutex is +assumed to be locked and owned by the calling thread on entrance to +@code{pthread_mutex_unlock}. If the mutex is of the ``fast'' type, +@code{pthread_mutex_unlock} always returns it to the unlocked state. If +it is of the ``recursive'' type, it decrements the locking count of the +mutex (number of @code{pthread_mutex_lock} operations performed on it by +the calling thread), and only when this count reaches zero is the mutex +actually unlocked. + +On ``error checking'' mutexes, @code{pthread_mutex_unlock} actually +checks at run-time that the mutex is locked on entrance, and that it was +locked by the same thread that is now calling +@code{pthread_mutex_unlock}. If these conditions are not met, +@code{pthread_mutex_unlock} returns @code{EPERM}, and the mutex remains +unchanged. ``Fast'' and ``recursive'' mutexes perform no such checks, +thus allowing a locked mutex to be unlocked by a thread other than its +owner. This is non-portable behavior and must not be relied upon. +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_mutex_destroy (pthread_mutex_t *@var{mutex}) +@code{pthread_mutex_destroy} destroys a mutex object, freeing the +resources it might hold. The mutex must be unlocked on entrance. In the +LinuxThreads implementation, no resources are associated with mutex +objects, thus @code{pthread_mutex_destroy} actually does nothing except +checking that the mutex is unlocked. + +If the mutex is locked by some thread, @code{pthread_mutex_destroy} +returns @code{EBUSY}. Otherwise it returns 0. +@end deftypefun + +If any of the above functions (except @code{pthread_mutex_init}) +is applied to an uninitialized mutex, they will simply return +@code{EINVAL} and do nothing. + +A shared global variable @var{x} can be protected by a mutex as follows: + +@smallexample +int x; +pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; +@end smallexample + +All accesses and modifications to @var{x} should be bracketed by calls to +@code{pthread_mutex_lock} and @code{pthread_mutex_unlock} as follows: + +@smallexample +pthread_mutex_lock(&mut); +/* operate on x */ +pthread_mutex_unlock(&mut); +@end smallexample + +Mutex attributes can be specified at mutex creation time, by passing a +mutex attribute object as second argument to @code{pthread_mutex_init}. +Passing @code{NULL} is equivalent to passing a mutex attribute object +with all attributes set to their default values. + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_mutexattr_init (pthread_mutexattr_t *@var{attr}) +@code{pthread_mutexattr_init} initializes the mutex attribute object +@var{attr} and fills it with default values for the attributes. + +This function always returns 0. +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_mutexattr_destroy (pthread_mutexattr_t *@var{attr}) +@code{pthread_mutexattr_destroy} destroys a mutex attribute object, +which must not be reused until it is +reinitialized. @code{pthread_mutexattr_destroy} does nothing in the +LinuxThreads implementation. + +This function always returns 0. +@end deftypefun + +LinuxThreads supports only one mutex attribute: the mutex type, which is +either @code{PTHREAD_MUTEX_ADAPTIVE_NP} for ``fast'' mutexes, +@code{PTHREAD_MUTEX_RECURSIVE_NP} for ``recursive'' mutexes, +@code{PTHREAD_MUTEX_TIMED_NP} for ``timed'' mutexes, or +@code{PTHREAD_MUTEX_ERRORCHECK_NP} for ``error checking'' mutexes. As +the @code{NP} suffix indicates, this is a non-portable extension to the +POSIX standard and should not be employed in portable programs. + +The mutex type determines what happens if a thread attempts to lock a +mutex it already owns with @code{pthread_mutex_lock}. If the mutex is of +the ``fast'' type, @code{pthread_mutex_lock} simply suspends the calling +thread forever. If the mutex is of the ``error checking'' type, +@code{pthread_mutex_lock} returns immediately with the error code +@code{EDEADLK}. If the mutex is of the ``recursive'' type, the call to +@code{pthread_mutex_lock} returns immediately with a success return +code. The number of times the thread owning the mutex has locked it is +recorded in the mutex. The owning thread must call +@code{pthread_mutex_unlock} the same number of times before the mutex +returns to the unlocked state. + +The default mutex type is ``timed'', that is, @code{PTHREAD_MUTEX_TIMED_NP}. +@c This doesn't describe how a ``timed'' mutex behaves. FIXME + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_mutexattr_settype (pthread_mutexattr_t *@var{attr}, int @var{type}) +@code{pthread_mutexattr_settype} sets the mutex type attribute in +@var{attr} to the value specified by @var{type}. + +If @var{type} is not @code{PTHREAD_MUTEX_ADAPTIVE_NP}, +@code{PTHREAD_MUTEX_RECURSIVE_NP}, @code{PTHREAD_MUTEX_TIMED_NP}, or +@code{PTHREAD_MUTEX_ERRORCHECK_NP}, this function will return +@code{EINVAL} and leave @var{attr} unchanged. + +The standard Unix98 identifiers @code{PTHREAD_MUTEX_DEFAULT}, +@code{PTHREAD_MUTEX_NORMAL}, @code{PTHREAD_MUTEX_RECURSIVE}, +and @code{PTHREAD_MUTEX_ERRORCHECK} are also permitted. + +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_mutexattr_gettype (const pthread_mutexattr_t *@var{attr}, int *@var{type}) +@code{pthread_mutexattr_gettype} retrieves the current value of the +mutex type attribute in @var{attr} and stores it in the location pointed +to by @var{type}. + +This function always returns 0. +@end deftypefun + +@node Condition Variables +@section Condition Variables + +A condition (short for ``condition variable'') is a synchronization +device that allows threads to suspend execution until some predicate on +shared data is satisfied. The basic operations on conditions are: signal +the condition (when the predicate becomes true), and wait for the +condition, suspending the thread execution until another thread signals +the condition. + +A condition variable must always be associated with a mutex, to avoid +the race condition where a thread prepares to wait on a condition +variable and another thread signals the condition just before the first +thread actually waits on it. + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_cond_init (pthread_cond_t *@var{cond}, pthread_condattr_t *cond_@var{attr}) + +@code{pthread_cond_init} initializes the condition variable @var{cond}, +using the condition attributes specified in @var{cond_attr}, or default +attributes if @var{cond_attr} is @code{NULL}. The LinuxThreads +implementation supports no attributes for conditions, hence the +@var{cond_attr} parameter is actually ignored. + +Variables of type @code{pthread_cond_t} can also be initialized +statically, using the constant @code{PTHREAD_COND_INITIALIZER}. + +This function always returns 0. +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_cond_signal (pthread_cond_t *@var{cond}) +@code{pthread_cond_signal} restarts one of the threads that are waiting +on the condition variable @var{cond}. If no threads are waiting on +@var{cond}, nothing happens. If several threads are waiting on +@var{cond}, exactly one is restarted, but it is not specified which. + +This function always returns 0. +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_cond_broadcast (pthread_cond_t *@var{cond}) +@code{pthread_cond_broadcast} restarts all the threads that are waiting +on the condition variable @var{cond}. Nothing happens if no threads are +waiting on @var{cond}. + +This function always returns 0. +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_cond_wait (pthread_cond_t *@var{cond}, pthread_mutex_t *@var{mutex}) +@code{pthread_cond_wait} atomically unlocks the @var{mutex} (as per +@code{pthread_unlock_mutex}) and waits for the condition variable +@var{cond} to be signaled. The thread execution is suspended and does +not consume any CPU time until the condition variable is signaled. The +@var{mutex} must be locked by the calling thread on entrance to +@code{pthread_cond_wait}. Before returning to the calling thread, +@code{pthread_cond_wait} re-acquires @var{mutex} (as per +@code{pthread_lock_mutex}). + +Unlocking the mutex and suspending on the condition variable is done +atomically. Thus, if all threads always acquire the mutex before +signaling the condition, this guarantees that the condition cannot be +signaled (and thus ignored) between the time a thread locks the mutex +and the time it waits on the condition variable. + +This function always returns 0. +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_cond_timedwait (pthread_cond_t *@var{cond}, pthread_mutex_t *@var{mutex}, const struct timespec *@var{abstime}) +@code{pthread_cond_timedwait} atomically unlocks @var{mutex} and waits +on @var{cond}, as @code{pthread_cond_wait} does, but it also bounds the +duration of the wait. If @var{cond} has not been signaled before time +@var{abstime}, the mutex @var{mutex} is re-acquired and +@code{pthread_cond_timedwait} returns the error code @code{ETIMEDOUT}. +The wait can also be interrupted by a signal; in that case +@code{pthread_cond_timedwait} returns @code{EINTR}. + +The @var{abstime} parameter specifies an absolute time, with the same +origin as @code{time} and @code{gettimeofday}: an @var{abstime} of 0 +corresponds to 00:00:00 GMT, January 1, 1970. +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_cond_destroy (pthread_cond_t *@var{cond}) +@code{pthread_cond_destroy} destroys the condition variable @var{cond}, +freeing the resources it might hold. If any threads are waiting on the +condition variable, @code{pthread_cond_destroy} leaves @var{cond} +untouched and returns @code{EBUSY}. Otherwise it returns 0, and +@var{cond} must not be used again until it is reinitialized. + +In the LinuxThreads implementation, no resources are associated with +condition variables, so @code{pthread_cond_destroy} actually does +nothing. +@end deftypefun + +@code{pthread_cond_wait} and @code{pthread_cond_timedwait} are +cancellation points. If a thread is canceled while suspended in one of +these functions, the thread immediately resumes execution, relocks the +mutex specified by @var{mutex}, and finally executes the cancellation. +Consequently, cleanup handlers are assured that @var{mutex} is locked +when they are called. + +It is not safe to call the condition variable functions from a signal +handler. In particular, calling @code{pthread_cond_signal} or +@code{pthread_cond_broadcast} from a signal handler may deadlock the +calling thread. + +Consider two shared variables @var{x} and @var{y}, protected by the +mutex @var{mut}, and a condition variable @var{cond} that is to be +signaled whenever @var{x} becomes greater than @var{y}. + +@smallexample +int x,y; +pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; +pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +@end smallexample + +Waiting until @var{x} is greater than @var{y} is performed as follows: + +@smallexample +pthread_mutex_lock(&mut); +while (x <= y) @{ + pthread_cond_wait(&cond, &mut); +@} +/* operate on x and y */ +pthread_mutex_unlock(&mut); +@end smallexample + +Modifications on @var{x} and @var{y} that may cause @var{x} to become greater than +@var{y} should signal the condition if needed: + +@smallexample +pthread_mutex_lock(&mut); +/* modify x and y */ +if (x > y) pthread_cond_broadcast(&cond); +pthread_mutex_unlock(&mut); +@end smallexample + +If it can be proved that at most one waiting thread needs to be waken +up (for instance, if there are only two threads communicating through +@var{x} and @var{y}), @code{pthread_cond_signal} can be used as a slightly more +efficient alternative to @code{pthread_cond_broadcast}. In doubt, use +@code{pthread_cond_broadcast}. + +To wait for @var{x} to becomes greater than @var{y} with a timeout of 5 +seconds, do: + +@smallexample +struct timeval now; +struct timespec timeout; +int retcode; + +pthread_mutex_lock(&mut); +gettimeofday(&now); +timeout.tv_sec = now.tv_sec + 5; +timeout.tv_nsec = now.tv_usec * 1000; +retcode = 0; +while (x <= y && retcode != ETIMEDOUT) @{ + retcode = pthread_cond_timedwait(&cond, &mut, &timeout); +@} +if (retcode == ETIMEDOUT) @{ + /* timeout occurred */ +@} else @{ + /* operate on x and y */ +@} +pthread_mutex_unlock(&mut); +@end smallexample + +Condition attributes can be specified at condition creation time, by +passing a condition attribute object as second argument to +@code{pthread_cond_init}. Passing @code{NULL} is equivalent to passing +a condition attribute object with all attributes set to their default +values. + +The LinuxThreads implementation supports no attributes for +conditions. The functions on condition attributes are included only for +compliance with the POSIX standard. + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_condattr_init (pthread_condattr_t *@var{attr}) +@deftypefunx int pthread_condattr_destroy (pthread_condattr_t *@var{attr}) +@code{pthread_condattr_init} initializes the condition attribute object +@var{attr} and fills it with default values for the attributes. +@code{pthread_condattr_destroy} destroys the condition attribute object +@var{attr}. + +Both functions do nothing in the LinuxThreads implementation. + +@code{pthread_condattr_init} and @code{pthread_condattr_destroy} always +return 0. +@end deftypefun + +@node POSIX Semaphores +@section POSIX Semaphores + +@vindex SEM_VALUE_MAX +Semaphores are counters for resources shared between threads. The +basic operations on semaphores are: increment the counter atomically, +and wait until the counter is non-null and decrement it atomically. + +Semaphores have a maximum value past which they cannot be incremented. +The macro @code{SEM_VALUE_MAX} is defined to be this maximum value. In +the GNU C library, @code{SEM_VALUE_MAX} is equal to @code{INT_MAX} +(@pxref{Range of Type}), but it may be much smaller on other systems. + +The pthreads library implements POSIX 1003.1b semaphores. These should +not be confused with System V semaphores (@code{ipc}, @code{semctl} and +@code{semop}). +@c !!! SysV IPC is not doc'd at all in our manual + +All the semaphore functions and macros are defined in @file{semaphore.h}. + +@comment semaphore.h +@comment POSIX +@deftypefun int sem_init (sem_t *@var{sem}, int @var{pshared}, unsigned int @var{value}) +@code{sem_init} initializes the semaphore object pointed to by +@var{sem}. The count associated with the semaphore is set initially to +@var{value}. The @var{pshared} argument indicates whether the semaphore +is local to the current process (@var{pshared} is zero) or is to be +shared between several processes (@var{pshared} is not zero). + +On success @code{sem_init} returns 0. On failure it returns -1 and sets +@var{errno} to one of the following values: + +@table @code +@item EINVAL +@var{value} exceeds the maximal counter value @code{SEM_VALUE_MAX} + +@item ENOSYS +@var{pshared} is not zero. LinuxThreads currently does not support +process-shared semaphores. (This will eventually change.) +@end table +@end deftypefun + +@comment semaphore.h +@comment POSIX +@deftypefun int sem_destroy (sem_t * @var{sem}) +@code{sem_destroy} destroys a semaphore object, freeing the resources it +might hold. If any threads are waiting on the semaphore when +@code{sem_destroy} is called, it fails and sets @var{errno} to +@code{EBUSY}. + +In the LinuxThreads implementation, no resources are associated with +semaphore objects, thus @code{sem_destroy} actually does nothing except +checking that no thread is waiting on the semaphore. This will change +when process-shared semaphores are implemented. +@end deftypefun + +@comment semaphore.h +@comment POSIX +@deftypefun int sem_wait (sem_t * @var{sem}) +@code{sem_wait} suspends the calling thread until the semaphore pointed +to by @var{sem} has non-zero count. It then atomically decreases the +semaphore count. + +@code{sem_wait} is a cancellation point. It always returns 0. +@end deftypefun + +@comment semaphore.h +@comment POSIX +@deftypefun int sem_trywait (sem_t * @var{sem}) +@code{sem_trywait} is a non-blocking variant of @code{sem_wait}. If the +semaphore pointed to by @var{sem} has non-zero count, the count is +atomically decreased and @code{sem_trywait} immediately returns 0. If +the semaphore count is zero, @code{sem_trywait} immediately returns -1 +and sets errno to @code{EAGAIN}. +@end deftypefun + +@comment semaphore.h +@comment POSIX +@deftypefun int sem_post (sem_t * @var{sem}) +@code{sem_post} atomically increases the count of the semaphore pointed to +by @var{sem}. This function never blocks. + +@c !!! This para appears not to agree with the code. +On processors supporting atomic compare-and-swap (Intel 486, Pentium and +later, Alpha, PowerPC, MIPS II, Motorola 68k, Ultrasparc), the +@code{sem_post} function is can safely be called from signal handlers. +This is the only thread synchronization function provided by POSIX +threads that is async-signal safe. On the Intel 386 and earlier Sparc +chips, the current LinuxThreads implementation of @code{sem_post} is not +async-signal safe, because the hardware does not support the required +atomic operations. + +@code{sem_post} always succeeds and returns 0, unless the semaphore +count would exceed @code{SEM_VALUE_MAX} after being incremented. In +that case @code{sem_post} returns -1 and sets @var{errno} to +@code{EINVAL}. The semaphore count is left unchanged. +@end deftypefun + +@comment semaphore.h +@comment POSIX +@deftypefun int sem_getvalue (sem_t * @var{sem}, int * @var{sval}) +@code{sem_getvalue} stores in the location pointed to by @var{sval} the +current count of the semaphore @var{sem}. It always returns 0. +@end deftypefun + +@node Thread-Specific Data +@section Thread-Specific Data + +Programs often need global or static variables that have different +values in different threads. Since threads share one memory space, this +cannot be achieved with regular variables. Thread-specific data is the +POSIX threads answer to this need. + +Each thread possesses a private memory block, the thread-specific data +area, or TSD area for short. This area is indexed by TSD keys. The TSD +area associates values of type @code{void *} to TSD keys. TSD keys are +common to all threads, but the value associated with a given TSD key can +be different in each thread. + +For concreteness, the TSD areas can be viewed as arrays of @code{void *} +pointers, TSD keys as integer indices into these arrays, and the value +of a TSD key as the value of the corresponding array element in the +calling thread. + +When a thread is created, its TSD area initially associates @code{NULL} +with all keys. + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_key_create (pthread_key_t *@var{key}, void (*destr_function) (void *)) +@code{pthread_key_create} allocates a new TSD key. The key is stored in +the location pointed to by @var{key}. There is a limit of +@code{PTHREAD_KEYS_MAX} on the number of keys allocated at a given +time. The value initially associated with the returned key is +@code{NULL} in all currently executing threads. + +The @var{destr_function} argument, if not @code{NULL}, specifies a +destructor function associated with the key. When a thread terminates +via @code{pthread_exit} or by cancellation, @var{destr_function} is +called on the value associated with the key in that thread. The +@var{destr_function} is not called if a key is deleted with +@code{pthread_key_delete} or a value is changed with +@code{pthread_setspecific}. The order in which destructor functions are +called at thread termination time is unspecified. + +Before the destructor function is called, the @code{NULL} value is +associated with the key in the current thread. A destructor function +might, however, re-associate non-@code{NULL} values to that key or some +other key. To deal with this, if after all the destructors have been +called for all non-@code{NULL} values, there are still some +non-@code{NULL} values with associated destructors, then the process is +repeated. The LinuxThreads implementation stops the process after +@code{PTHREAD_DESTRUCTOR_ITERATIONS} iterations, even if some +non-@code{NULL} values with associated descriptors remain. Other +implementations may loop indefinitely. + +@code{pthread_key_create} returns 0 unless @code{PTHREAD_KEYS_MAX} keys +have already been allocated, in which case it fails and returns +@code{EAGAIN}. +@end deftypefun + + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_key_delete (pthread_key_t @var{key}) +@code{pthread_key_delete} deallocates a TSD key. It does not check +whether non-@code{NULL} values are associated with that key in the +currently executing threads, nor call the destructor function associated +with the key. + +If there is no such key @var{key}, it returns @code{EINVAL}. Otherwise +it returns 0. +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_setspecific (pthread_key_t @var{key}, const void *@var{pointer}) +@code{pthread_setspecific} changes the value associated with @var{key} +in the calling thread, storing the given @var{pointer} instead. + +If there is no such key @var{key}, it returns @code{EINVAL}. Otherwise +it returns 0. +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun {void *} pthread_getspecific (pthread_key_t @var{key}) +@code{pthread_getspecific} returns the value currently associated with +@var{key} in the calling thread. + +If there is no such key @var{key}, it returns @code{NULL}. +@end deftypefun + +The following code fragment allocates a thread-specific array of 100 +characters, with automatic reclaimation at thread exit: + +@smallexample +/* Key for the thread-specific buffer */ +static pthread_key_t buffer_key; + +/* Once-only initialisation of the key */ +static pthread_once_t buffer_key_once = PTHREAD_ONCE_INIT; + +/* Allocate the thread-specific buffer */ +void buffer_alloc(void) +@{ + pthread_once(&buffer_key_once, buffer_key_alloc); + pthread_setspecific(buffer_key, malloc(100)); +@} + +/* Return the thread-specific buffer */ +char * get_buffer(void) +@{ + return (char *) pthread_getspecific(buffer_key); +@} + +/* Allocate the key */ +static void buffer_key_alloc() +@{ + pthread_key_create(&buffer_key, buffer_destroy); +@} + +/* Free the thread-specific buffer */ +static void buffer_destroy(void * buf) +@{ + free(buf); +@} +@end smallexample + +@node Threads and Signal Handling +@section Threads and Signal Handling + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_sigmask (int @var{how}, const sigset_t *@var{newmask}, sigset_t *@var{oldmask}) +@code{pthread_sigmask} changes the signal mask for the calling thread as +described by the @var{how} and @var{newmask} arguments. If @var{oldmask} +is not @code{NULL}, the previous signal mask is stored in the location +pointed to by @var{oldmask}. + +The meaning of the @var{how} and @var{newmask} arguments is the same as +for @code{sigprocmask}. If @var{how} is @code{SIG_SETMASK}, the signal +mask is set to @var{newmask}. If @var{how} is @code{SIG_BLOCK}, the +signals specified to @var{newmask} are added to the current signal mask. +If @var{how} is @code{SIG_UNBLOCK}, the signals specified to +@var{newmask} are removed from the current signal mask. + +Recall that signal masks are set on a per-thread basis, but signal +actions and signal handlers, as set with @code{sigaction}, are shared +between all threads. + +The @code{pthread_sigmask} function returns 0 on success, and one of the +following error codes on error: +@table @code +@item EINVAL +@var{how} is not one of @code{SIG_SETMASK}, @code{SIG_BLOCK}, or @code{SIG_UNBLOCK} + +@item EFAULT +@var{newmask} or @var{oldmask} point to invalid addresses +@end table +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_kill (pthread_t @var{thread}, int @var{signo}) +@code{pthread_kill} sends signal number @var{signo} to the thread +@var{thread}. The signal is delivered and handled as described in +@ref{Signal Handling}. + +@code{pthread_kill} returns 0 on success, one of the following error codes +on error: +@table @code +@item EINVAL +@var{signo} is not a valid signal number + +@item ESRCH +The thread @var{thread} does not exist (e.g. it has already terminated) +@end table +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun int sigwait (const sigset_t *@var{set}, int *@var{sig}) +@code{sigwait} suspends the calling thread until one of the signals in +@var{set} is delivered to the calling thread. It then stores the number +of the signal received in the location pointed to by @var{sig} and +returns. The signals in @var{set} must be blocked and not ignored on +entrance to @code{sigwait}. If the delivered signal has a signal handler +function attached, that function is @emph{not} called. + +@code{sigwait} is a cancellation point. It always returns 0. +@end deftypefun + +For @code{sigwait} to work reliably, the signals being waited for must be +blocked in all threads, not only in the calling thread, since +otherwise the POSIX semantics for signal delivery do not guarantee +that it's the thread doing the @code{sigwait} that will receive the signal. +The best way to achieve this is block those signals before any threads +are created, and never unblock them in the program other than by +calling @code{sigwait}. + +Signal handling in LinuxThreads departs significantly from the POSIX +standard. According to the standard, ``asynchronous'' (external) signals +are addressed to the whole process (the collection of all threads), +which then delivers them to one particular thread. The thread that +actually receives the signal is any thread that does not currently block +the signal. + +In LinuxThreads, each thread is actually a kernel process with its own +PID, so external signals are always directed to one particular thread. +If, for instance, another thread is blocked in @code{sigwait} on that +signal, it will not be restarted. + +The LinuxThreads implementation of @code{sigwait} installs dummy signal +handlers for the signals in @var{set} for the duration of the +wait. Since signal handlers are shared between all threads, other +threads must not attach their own signal handlers to these signals, or +alternatively they should all block these signals (which is recommended +anyway). + +@node Threads and Fork +@section Threads and Fork + +It's not intuitively obvious what should happen when a multi-threaded POSIX +process calls @code{fork}. Not only are the semantics tricky, but you may +need to write code that does the right thing at fork time even if that code +doesn't use the @code{fork} function. Moreover, you need to be aware of +interaction between @code{fork} and some library features like +@code{pthread_once} and stdio streams. + +When @code{fork} is called by one of the threads of a process, it creates a new +process which is copy of the calling process. Effectively, in addition to +copying certain system objects, the function takes a snapshot of the memory +areas of the parent process, and creates identical areas in the child. +To make matters more complicated, with threads it's possible for two or more +threads to concurrently call fork to create two or more child processes. + +The child process has a copy of the address space of the parent, but it does +not inherit any of its threads. Execution of the child process is carried out +by a new thread which returns from @code{fork} function with a return value of +zero; it is the only thread in the child process. Because threads are not +inherited across fork, issues arise. At the time of the call to @code{fork}, +threads in the parent process other than the one calling @code{fork} may have +been executing critical regions of code. As a result, the child process may +get a copy of objects that are not in a well-defined state. This potential +problem affects all components of the program. + +Any program component which will continue being used in a child process must +correctly handle its state during @code{fork}. For this purpose, the POSIX +interface provides the special function @code{pthread_atfork} for installing +pointers to handler functions which are called from within @code{fork}. + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_atfork (void (*@var{prepare})(void), void (*@var{parent})(void), void (*@var{child})(void)) + +@code{pthread_atfork} registers handler functions to be called just +before and just after a new process is created with @code{fork}. The +@var{prepare} handler will be called from the parent process, just +before the new process is created. The @var{parent} handler will be +called from the parent process, just before @code{fork} returns. The +@var{child} handler will be called from the child process, just before +@code{fork} returns. + +@code{pthread_atfork} returns 0 on success and a non-zero error code on +error. + +One or more of the three handlers @var{prepare}, @var{parent} and +@var{child} can be given as @code{NULL}, meaning that no handler needs +to be called at the corresponding point. + +@code{pthread_atfork} can be called several times to install several +sets of handlers. At @code{fork} time, the @var{prepare} handlers are +called in LIFO order (last added with @code{pthread_atfork}, first +called before @code{fork}), while the @var{parent} and @var{child} +handlers are called in FIFO order (first added, first called). + +If there is insufficient memory available to register the handlers, +@code{pthread_atfork} fails and returns @code{ENOMEM}. Otherwise it +returns 0. + +The functions @code{fork} and @code{pthread_atfork} must not be regarded as +reentrant from the context of the handlers. That is to say, if a +@code{pthread_atfork} handler invoked from within @code{fork} calls +@code{pthread_atfork} or @code{fork}, the behavior is undefined. + +Registering a triplet of handlers is an atomic operation with respect to fork. +If new handlers are registered at about the same time as a fork occurs, either +all three handlers will be called, or none of them will be called. + +The handlers are inherited by the child process, and there is no +way to remove them, short of using @code{exec} to load a new +pocess image. + +@end deftypefun + +To understand the purpose of @code{pthread_atfork}, recall that +@code{fork} duplicates the whole memory space, including mutexes in +their current locking state, but only the calling thread: other threads +are not running in the child process. The mutexes are not usable after +the @code{fork} and must be initialized with @code{pthread_mutex_init} +in the child process. This is a limitation of the current +implementation and might or might not be present in future versions. + +To avoid this, install handlers with @code{pthread_atfork} as follows: have the +@var{prepare} handler lock the mutexes (in locking order), and the +@var{parent} handler unlock the mutexes. The @var{child} handler should reset +the mutexes using @code{pthread_mutex_init}, as well as any other +synchronization objects such as condition variables. + +Locking the global mutexes before the fork ensures that all other threads are +locked out of the critical regions of code protected by those mutexes. Thus +when @code{fork} takes a snapshot of the parent's address space, that snapshot +will copy valid, stable data. Resetting the synchronization objects in the +child process will ensure they are properly cleansed of any artifacts from the +threading subsystem of the parent process. For example, a mutex may inherit +a wait queue of threads waiting for the lock; this wait queue makes no sense +in the child process. Initializing the mutex takes care of this. + +@node Streams and Fork +@section Streams and Fork + +The GNU standard I/O library has an internal mutex which guards the internal +linked list of all standard C FILE objects. This mutex is properly taken care +of during @code{fork} so that the child receives an intact copy of the list. +This allows the @code{fopen} function, and related stream-creating functions, +to work correctly in the child process, since these functions need to insert +into the list. + +However, the individual stream locks are not completely taken care of. Thus +unless the multithreaded application takes special precautions in its use of +@code{fork}, the child process might not be able to safely use the streams that +it inherited from the parent. In general, for any given open stream in the +parent that is to be used by the child process, the application must ensure +that that stream is not in use by another thread when @code{fork} is called. +Otherwise an inconsistent copy of the stream object be produced. An easy way to +ensure this is to use @code{flockfile} to lock the stream prior to calling +@code{fork} and then unlock it with @code{funlockfile} inside the parent +process, provided that the parent's threads properly honor these locks. +Nothing special needs to be done in the child process, since the library +internally resets all stream locks. + +Note that the stream locks are not shared between the parent and child. +For example, even if you ensure that, say, the stream @code{stdout} is properly +treated and can be safely used in the child, the stream locks do not provide +an exclusion mechanism between the parent and child. If both processes write +to @code{stdout}, strangely interleaved output may result regardless of +the explicit use of @code{flockfile} or implicit locks. + +Also note that these provisions are a GNU extension; other systems might not +provide any way for streams to be used in the child of a multithreaded process. +POSIX requires that such a child process confines itself to calling only +asynchronous safe functions, which excludes much of the library, including +standard I/O. + +@node Miscellaneous Thread Functions +@section Miscellaneous Thread Functions + +@comment pthread.h +@comment POSIX +@deftypefun {pthread_t} pthread_self (@var{void}) +@code{pthread_self} returns the thread identifier for the calling thread. +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_equal (pthread_t thread1, pthread_t thread2) +@code{pthread_equal} determines if two thread identifiers refer to the same +thread. + +A non-zero value is returned if @var{thread1} and @var{thread2} refer to +the same thread. Otherwise, 0 is returned. +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_detach (pthread_t @var{th}) +@code{pthread_detach} puts the thread @var{th} in the detached +state. This guarantees that the memory resources consumed by @var{th} +will be freed immediately when @var{th} terminates. However, this +prevents other threads from synchronizing on the termination of @var{th} +using @code{pthread_join}. + +A thread can be created initially in the detached state, using the +@code{detachstate} attribute to @code{pthread_create}. In contrast, +@code{pthread_detach} applies to threads created in the joinable state, +and which need to be put in the detached state later. + +After @code{pthread_detach} completes, subsequent attempts to perform +@code{pthread_join} on @var{th} will fail. If another thread is already +joining the thread @var{th} at the time @code{pthread_detach} is called, +@code{pthread_detach} does nothing and leaves @var{th} in the joinable +state. + +On success, 0 is returned. On error, one of the following codes is +returned: +@table @code +@item ESRCH +No thread could be found corresponding to that specified by @var{th} +@item EINVAL +The thread @var{th} is already in the detached state +@end table +@end deftypefun + +@comment pthread.h +@comment GNU +@deftypefun void pthread_kill_other_threads_np (@var{void}) +@code{pthread_kill_other_threads_np} is a non-portable LinuxThreads extension. +It causes all threads in the program to terminate immediately, except +the calling thread which proceeds normally. It is intended to be +called just before a thread calls one of the @code{exec} functions, +e.g. @code{execve}. + +Termination of the other threads is not performed through +@code{pthread_cancel} and completely bypasses the cancellation +mechanism. Hence, the current settings for cancellation state and +cancellation type are ignored, and the cleanup handlers are not +executed in the terminated threads. + +According to POSIX 1003.1c, a successful @code{exec*} in one of the +threads should automatically terminate all other threads in the program. +This behavior is not yet implemented in LinuxThreads. Calling +@code{pthread_kill_other_threads_np} before @code{exec*} achieves much +of the same behavior, except that if @code{exec*} ultimately fails, then +all other threads are already killed. +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_once (pthread_once_t *once_@var{control}, void (*@var{init_routine}) (void)) + +The purpose of @code{pthread_once} is to ensure that a piece of +initialization code is executed at most once. The @var{once_control} +argument points to a static or extern variable statically initialized +to @code{PTHREAD_ONCE_INIT}. + +The first time @code{pthread_once} is called with a given +@var{once_control} argument, it calls @var{init_routine} with no +argument and changes the value of the @var{once_control} variable to +record that initialization has been performed. Subsequent calls to +@code{pthread_once} with the same @code{once_control} argument do +nothing. + +If a thread is cancelled while executing @var{init_routine} +the state of the @var{once_control} variable is reset so that +a future call to @code{pthread_once} will call the routine again. + +If the process forks while one or more threads are executing +@code{pthread_once} initialization routines, the states of their respective +@var{once_control} variables will appear to be reset in the child process so +that if the child calls @code{pthread_once}, the routines will be executed. + +@code{pthread_once} always returns 0. +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_setschedparam (pthread_t target_@var{thread}, int @var{policy}, const struct sched_param *@var{param}) + +@code{pthread_setschedparam} sets the scheduling parameters for the +thread @var{target_thread} as indicated by @var{policy} and +@var{param}. @var{policy} can be either @code{SCHED_OTHER} (regular, +non-realtime scheduling), @code{SCHED_RR} (realtime, round-robin) or +@code{SCHED_FIFO} (realtime, first-in first-out). @var{param} specifies +the scheduling priority for the two realtime policies. See +@code{sched_setpolicy} for more information on scheduling policies. + +The realtime scheduling policies @code{SCHED_RR} and @code{SCHED_FIFO} +are available only to processes with superuser privileges. + +On success, @code{pthread_setschedparam} returns 0. On error it returns +one of the following codes: +@table @code +@item EINVAL +@var{policy} is not one of @code{SCHED_OTHER}, @code{SCHED_RR}, +@code{SCHED_FIFO}, or the priority value specified by @var{param} is not +valid for the specified policy + +@item EPERM +Realtime scheduling was requested but the calling process does not have +sufficient privileges. + +@item ESRCH +The @var{target_thread} is invalid or has already terminated + +@item EFAULT +@var{param} points outside the process memory space +@end table +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_getschedparam (pthread_t target_@var{thread}, int *@var{policy}, struct sched_param *@var{param}) + +@code{pthread_getschedparam} retrieves the scheduling policy and +scheduling parameters for the thread @var{target_thread} and stores them +in the locations pointed to by @var{policy} and @var{param}, +respectively. + +@code{pthread_getschedparam} returns 0 on success, or one of the +following error codes on failure: +@table @code +@item ESRCH +The @var{target_thread} is invalid or has already terminated. + +@item EFAULT +@var{policy} or @var{param} point outside the process memory space. + +@end table +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_setconcurrency (int @var{level}) +@code{pthread_setconcurrency} is unused in LinuxThreads due to the lack +of a mapping of user threads to kernel threads. It exists for source +compatibility. It does store the value @var{level} so that it can be +returned by a subsequent call to @code{pthread_getconcurrency}. It takes +no other action however. +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_getconcurrency () +@code{pthread_getconcurrency} is unused in LinuxThreads due to the lack +of a mapping of user threads to kernel threads. It exists for source +compatibility. However, it will return the value that was set by the +last call to @code{pthread_setconcurrency}. +@end deftypefun diff --git a/linuxthreads/lockfile.c b/linuxthreads/lockfile.c new file mode 100644 index 0000000000..34055e4115 --- /dev/null +++ b/linuxthreads/lockfile.c @@ -0,0 +1,82 @@ +/* lockfile - Handle locking and unlocking of stream. + Copyright (C) 1996, 1998, 2000 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; 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 <bits/libc-lock.h> +#include <stdio.h> +#include <pthread.h> +#include "internals.h" +#include "../libio/libioP.h" + +void +__flockfile (FILE *stream) +{ + __pthread_mutex_lock (stream->_lock); +} +#undef _IO_flockfile +strong_alias (__flockfile, _IO_flockfile) +weak_alias (__flockfile, flockfile); + + +void +__funlockfile (FILE *stream) +{ + __pthread_mutex_unlock (stream->_lock); +} +#undef _IO_funlockfile +strong_alias (__funlockfile, _IO_funlockfile) +weak_alias (__funlockfile, funlockfile); + + +int +__ftrylockfile (FILE *stream) +{ + return __pthread_mutex_trylock (stream->_lock); +} +strong_alias (__ftrylockfile, _IO_ftrylockfile) +weak_alias (__ftrylockfile, ftrylockfile); + +void +__flockfilelist(void) +{ + _IO_list_lock(); +} + +void +__funlockfilelist(void) +{ + _IO_list_unlock(); +} + +void +__fresetlockfiles (void) +{ + _IO_ITER i; + + pthread_mutexattr_t attr; + + __pthread_mutexattr_init (&attr); + __pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE_NP); + + for (i = _IO_iter_begin(); i != _IO_iter_end(); i = _IO_iter_next(i)) + __pthread_mutex_init (_IO_iter_file(i)->_lock, &attr); + + __pthread_mutexattr_destroy (&attr); + + _IO_list_resetlock(); +} diff --git a/linuxthreads/man/Makefile b/linuxthreads/man/Makefile new file mode 100644 index 0000000000..4afd2ee15d --- /dev/null +++ b/linuxthreads/man/Makefile @@ -0,0 +1,31 @@ +SOURCES=pthread_atfork.man pthread_attr_init.man pthread_cancel.man \ + pthread_cleanup_push.man pthread_cond_init.man \ + pthread_condattr_init.man pthread_create.man pthread_detach.man \ + pthread_equal.man pthread_exit.man pthread_join.man \ + pthread_key_create.man pthread_mutex_init.man \ + pthread_mutexattr_init.man pthread_once.man pthread_self.man \ + pthread_setschedparam.man pthread_sigmask.man sem_init.man \ + pthread_kill_other_threads_np.man pthread_mutexattr_setkind_np.man + +MANPAGES=$(SOURCES:.man=.3thr) + +PREPRO=perl troffprepro + +MANDIR=/usr/man/man3 + +all: $(MANPAGES) + +.SUFFIXES: .man .3thr + +.man.3thr: + $(PREPRO) $*.man $*.3thr + +$(MANPAGES): troffprepro + +clean: + rm -f *.3thr + rm -f *~ + +install: + install *.3thr $(MANDIR) + @echo "*** Remember to run /usr/sbin/makewhatis `dirname $(MANDIR)` at some point" diff --git a/linuxthreads/man/pthread_atfork.man b/linuxthreads/man/pthread_atfork.man new file mode 100644 index 0000000000..b682bed3ac --- /dev/null +++ b/linuxthreads/man/pthread_atfork.man @@ -0,0 +1,53 @@ +.TH PTHREAD_ATFORK 3 LinuxThreads + +.SH NAME +pthread_atfork \- register handlers to be called at fork(2) time + +.SH SYNOPSIS +#include <pthread.h> + +int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void)); + +.SH DESCRIPTION + +!pthread_atfork! registers handler functions to be called just before +and just after a new process is created with !fork!(2). The |prepare| +handler will be called from the parent process, just before the new +process is created. The |parent| handler will be called from the parent +process, just before !fork!(2) returns. The |child| handler will be +called from the child process, just before !fork!(2) returns. + +One or several of the three handlers |prepare|, |parent| and |child| +can be given as !NULL!, meaning that no handler needs to be called at +the corresponding point. + +!pthread_atfork! can be called several times to install several sets +of handlers. At !fork!(2) time, the |prepare| handlers are called in +LIFO order (last added with !pthread_atfork!, first called before !fork!), +while the |parent| and |child| handlers are called in FIFO order +(first added, first called). + +To understand the purpose of !pthread_atfork!, recall that !fork!(2) +duplicates the whole memory space, including mutexes in their current +locking state, but only the calling thread: other threads are not +running in the child process. The mutexes are not usable after the +!fork! and must be initialized with |pthread_mutex_init| in the child +process. This is a limitation of the current implementation and might +or might not be present in future versions. + +.SH "RETURN VALUE" + +!pthread_atfork! returns 0 on success and a non-zero error code on error. + +.SH ERRORS +.TP +!ENOMEM! +insufficient memory available to register the handlers. + +.SH AUTHOR +Xavier Leroy <Xavier.Leroy@inria.fr> + +.SH "SEE ALSO" +!fork!(2), +!pthread_mutex_lock!(3), +!pthread_mutex_unlock!(3). diff --git a/linuxthreads/man/pthread_attr_init.man b/linuxthreads/man/pthread_attr_init.man new file mode 100644 index 0000000000..bd5a169242 --- /dev/null +++ b/linuxthreads/man/pthread_attr_init.man @@ -0,0 +1,221 @@ +.TH PTHREAD_ATTR_INIT 3 LinuxThreads + +.XREF pthread_attr_destroy +.XREF pthread_attr_setdetachstate +.XREF pthread_attr_getdetachstate +.XREF pthread_attr_setschedparam +.XREF pthread_attr_getschedparam +.XREF pthread_attr_setschedpolicy +.XREF pthread_attr_getschedpolicy +.XREF pthread_attr_setinheritsched +.XREF pthread_attr_getinheritsched +.XREF pthread_attr_setscope +.XREF pthread_attr_getscope + +.SH NAME +pthread_attr_init, pthread_attr_destroy, pthread_attr_setdetachstate, pthread_attr_getdetachstate, pthread_attr_setschedparam, pthread_attr_getschedparam, pthread_attr_setschedpolicy, pthread_attr_getschedpolicy, pthread_attr_setinheritsched, pthread_attr_getinheritsched, pthread_attr_setscope, pthread_attr_getscope \- thread creation attributes + +.SH SYNOPSIS +#include <pthread.h> + +int pthread_attr_init(pthread_attr_t *attr); + +int pthread_attr_destroy(pthread_attr_t *attr); + +int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate); + +int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate); + +int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy); + +int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy); + +int pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *param); + +int pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param *param); + +int pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit); + +int pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inherit); + +int pthread_attr_setscope(pthread_attr_t *attr, int scope); + +int pthread_attr_getscope(const pthread_attr_t *attr, int *scope); + +.SH DESCRIPTION + +Setting attributes for threads is achieved by filling a +thread attribute object |attr| of type !pthread_attr_t!, then passing it as +second argument to !pthread_create!(3). Passing !NULL! is equivalent to +passing a thread attribute object with all attributes set to their +default values. + +!pthread_attr_init! initializes the thread attribute object |attr| and +fills it with default values for the attributes. (The default values +are listed below for each attribute.) + +Each attribute |attrname| (see below for a list of all attributes) can +be individually set using the function !pthread_attr_set!|attrname| +and retrieved using the function !pthread_attr_get!|attrname|. + +!pthread_attr_destroy! destroys a thread attribute object, which +must not be reused until it is reinitialized. !pthread_attr_destroy! +does nothing in the LinuxThreads implementation. + +Attribute objects are consulted only when creating a new thread. The +same attribute object can be used for creating several +threads. Modifying an attribute object after a call to +!pthread_create! does not change the attributes of the thread +previously created. + +The following thread attributes are supported: + +.SS detachstate + +Control whether the thread is created in the joinable state (value +!PTHREAD_CREATE_JOINABLE!) or in the detached state +(!PTHREAD_CREATE_DETACHED!). + +Default value: !PTHREAD_CREATE_JOINABLE!. + +In the joinable state, another thread can synchronize on the thread +termination and recover its termination code using !pthread_join!(3), +but some of the thread resources are kept allocated after the thread +terminates, and reclaimed only when another thread performs +!pthread_join!(3) on that thread. + +In the detached state, the thread resources are immediately freed when +it terminates, but !pthread_join!(3) cannot be used to synchronize on +the thread termination. + +A thread created in the joinable state can later be put in the +detached thread using !pthread_detach!(3). + +.SS schedpolicy + +Select the scheduling policy for the thread: one of +!SCHED_OTHER! (regular, non-realtime scheduling), +!SCHED_RR! (realtime, round-robin) or +!SCHED_FIFO! (realtime, first-in first-out). See +!sched_setpolicy!(2) for more information on scheduling policies. + +Default value: !SCHED_OTHER!. + +The realtime scheduling policies !SCHED_RR! and !SCHED_FIFO! are +available only to processes with superuser privileges. + +The scheduling policy of a thread can be changed after creation with +!pthread_setschedparam!(3). + +.SS schedparam + +Contain the scheduling parameters (essentially, the scheduling +priority) for the thread. See !sched_setparam!(2) for more information +on scheduling parameters. + +Default value: priority is 0. + +This attribute is not significant if the scheduling policy is !SCHED_OTHER!; +it only matters for the realtime policies !SCHED_RR! and !SCHED_FIFO!. + +The scheduling priority of a thread can be changed after creation with +!pthread_setschedparam!(3). + +.SS inheritsched + +Indicate whether the scheduling policy and scheduling parameters for +the newly created thread are determined by the values of the +|schedpolicy| and |schedparam| attributes (value +!PTHREAD_EXPLICIT_SCHED!) or are inherited from the parent thread +(value !PTHREAD_INHERIT_SCHED!). + +Default value: !PTHREAD_EXPLICIT_SCHED!. + +.SS scope + +Define the scheduling contention scope for the created thread. The +only value supported in the LinuxThreads implementation is +!PTHREAD_SCOPE_SYSTEM!, meaning that the threads contend for CPU time +with all processes running on the machine. In particular, thread +priorities are interpreted relative to the priorities of all other +processes on the machine. The other value specified by the standard, +!PTHREAD_SCOPE_PROCESS!, means that scheduling contention occurs only +between the threads of the running process: thread priorities are +interpreted relative to the priorities of the other threads of the +process, regardless of the priorities of other processes. +!PTHREAD_SCOPE_PROCESS! is not supported in LinuxThreads. + +Default value: !PTHREAD_SCOPE_SYSTEM!. + +.SH "RETURN VALUE" + +All functions return 0 on success and a non-zero error code on error. +On success, the !pthread_attr_get!|attrname| functions also store the +current value of the attribute |attrname| in the location pointed to +by their second argument. + +.SH ERRORS + +The !pthread_attr_setdetachstate! function returns the following error +codes on error: +.RS +.TP +!EINVAL! +the specified |detachstate| is not one of !PTHREAD_CREATE_JOINABLE! or +!PTHREAD_CREATE_DETACHED!. +.RE + +The !pthread_attr_setschedparam! function returns the following error +codes on error: +.RS +.TP +!EINVAL! +the priority specified in |param| is outside the range of allowed +priorities for the scheduling policy currently in |attr| +(1 to 99 for !SCHED_FIFO! and !SCHED_RR!; 0 for !SCHED_OTHER!). +.RE + +The !pthread_attr_setschedpolicy! function returns the following error +codes on error: +.RS +.TP +!EINVAL! +the specified |policy| is not one of !SCHED_OTHER!, !SCHED_FIFO!, or +!SCHED_RR!. + +.TP +!ENOTSUP! +|policy| is !SCHED_FIFO! or !SCHED_RR!, and the effective user of the +calling process is not super-user. +.RE + +The !pthread_attr_setinheritsched! function returns the following error +codes on error: +.RS +.TP +!EINVAL! +the specified |inherit| is not one of !PTHREAD_INHERIT_SCHED! or +!PTHREAD_EXPLICIT_SCHED!. +.RE + +The !pthread_attr_setscope! function returns the following error +codes on error: +.RS +.TP +!EINVAL! +the specified |scope| is not one of !PTHREAD_SCOPE_SYSTEM! or +!PTHREAD_SCOPE_PROCESS!. + +.TP +!ENOTSUP! +the specified |scope| is !PTHREAD_SCOPE_PROCESS! (not supported). +.RE + +.SH AUTHOR +Xavier Leroy <Xavier.Leroy@inria.fr> + +.SH "SEE ALSO" +!pthread_create!(3), +!pthread_join!(3), +!pthread_detach!(3), +!pthread_setschedparam!(3). diff --git a/linuxthreads/man/pthread_cancel.man b/linuxthreads/man/pthread_cancel.man new file mode 100644 index 0000000000..202d5c9b26 --- /dev/null +++ b/linuxthreads/man/pthread_cancel.man @@ -0,0 +1,155 @@ +.TH PTHREAD_CANCEL 3 LinuxThreads + +.XREF pthread_setcancelstate +.XREF pthread_setcanceltype +.XREF pthread_testcancel + +.SH NAME +pthread_cancel, pthread_setcancelstate, pthread_setcanceltype, pthread_testcancel \- thread cancellation + +.SH SYNOPSIS +#include <pthread.h> + +int pthread_cancel(pthread_t thread); + +int pthread_setcancelstate(int state, int *oldstate); + +int pthread_setcanceltype(int type, int *oldtype); + +void pthread_testcancel(void); + +.SH DESCRIPTION + +Cancellation is the mechanism by which a thread can terminate the +execution of another thread. More precisely, a thread can send a +cancellation request to another thread. Depending on its settings, the +target thread can then either ignore the request, honor it +immediately, or defer it till it reaches a cancellation point. + +When a thread eventually honors a cancellation request, it performs as +if !pthread_exit(PTHREAD_CANCELED)! has been called at that point: +all cleanup handlers are executed in reverse order, finalization +functions for thread-specific data are called, and finally the thread +stops executing with the return value !PTHREAD_CANCELED!. See +!pthread_exit!(3) for more information. + +!pthread_cancel! sends a cancellation request to the thread denoted +by the |thread| argument. + +!pthread_setcancelstate! changes the cancellation state for the +calling thread -- that is, whether cancellation requests are ignored +or not. The |state| argument is the new cancellation state: either +!PTHREAD_CANCEL_ENABLE! to enable cancellation, or +!PTHREAD_CANCEL_DISABLE! to disable cancellation (cancellation +requests are ignored). If |oldstate| is not !NULL!, the previous +cancellation state is stored in the location pointed to by |oldstate|, +and can thus be restored later by another call to +!pthread_setcancelstate!. + +!pthread_setcanceltype! changes the type of responses to cancellation +requests for the calling thread: asynchronous (immediate) or deferred. +The |type| argument is the new cancellation type: either +!PTHREAD_CANCEL_ASYNCHRONOUS! to cancel the calling thread as soon as +the cancellation request is received, or !PTHREAD_CANCEL_DEFERRED! to +keep the cancellation request pending until the next cancellation +point. If |oldtype| is not !NULL!, the previous +cancellation state is stored in the location pointed to by |oldtype|, +and can thus be restored later by another call to +!pthread_setcanceltype!. + +Threads are always created by !pthread_create!(3) with cancellation +enabled and deferred. That is, the initial cancellation state is +!PTHREAD_CANCEL_ENABLE! and the initial type is +!PTHREAD_CANCEL_DEFERRED!. + +Cancellation points are those points in the program execution where a +test for pending cancellation requests is performed and cancellation +is executed if positive. The following POSIX threads functions +are cancellation points: + +!pthread_join!(3) +.br +!pthread_cond_wait!(3) +.br +!pthread_cond_timedwait!(3) +.br +!pthread_testcancel!(3) +.br +!sem_wait!(3) +.br +!sigwait!(3) + +All other POSIX threads functions are guaranteed not to be +cancellation points. That is, they never perform cancellation in +deferred cancellation mode. + +!pthread_testcancel! does nothing except testing for pending +cancellation and executing it. Its purpose is to introduce explicit +checks for cancellation in long sequences of code that do not call +cancellation point functions otherwise. + +.SH "RETURN VALUE" + +!pthread_cancel!, !pthread_setcancelstate! and +!pthread_setcanceltype! return 0 on success and a non-zero error code +on error. + +.SH ERRORS +!pthread_cancel! returns the following error code on error: +.RS +.TP +!ESRCH! +no thread could be found corresponding to that specified by the |thread| ID. +.RE + +!pthread_setcancelstate! returns the following error code on error: +.RS +.TP +!EINVAL! +the |state| argument is not !PTHREAD_CANCEL_ENABLE! nor +!PTHREAD_CANCEL_DISABLE! +.RE + +!pthread_setcanceltype! returns the following error code on error: +.RS +.TP +!EINVAL! +the |type| argument is not !PTHREAD_CANCEL_DEFERRED! nor +!PTHREAD_CANCEL_ASYNCHRONOUS! +.RE + +.SH AUTHOR +Xavier Leroy <Xavier.Leroy@inria.fr> + +.SH "SEE ALSO" +!pthread_exit!(3), +!pthread_cleanup_push!(3), +!pthread_cleanup_pop!(3). + +.SH BUGS + +POSIX specifies that a number of system calls (basically, all +system calls that may block, such as !read!(2), !write!(2), !wait!(2), +etc.) and library functions that may call these system calls (e.g. +!fprintf!(3)) are cancellation points. LinuxThreads is not yet +integrated enough with the C library to implement this, and thus none +of the C library functions is a cancellation point. + +For system calls at least, there is a workaround. Cancellation +requests are transmitted to the target thread by sending it a +signal. That signal will interrupt all blocking system calls, causing +them to return immediately with the !EINTR! error. So, checking for +cancellation during a !read! system call, for instance, can be +achieved as follows: + +.RS +.ft 3 +.nf +.sp +pthread_testcancel(); +retcode = read(fd, buffer, length); +pthread_testcancel(); +.ft +.LP +.RE +.fi diff --git a/linuxthreads/man/pthread_cleanup_push.man b/linuxthreads/man/pthread_cleanup_push.man new file mode 100644 index 0000000000..1591431c9c --- /dev/null +++ b/linuxthreads/man/pthread_cleanup_push.man @@ -0,0 +1,194 @@ +.TH PTHREAD_CLEANUP 3 LinuxThreads + +.XREF pthread_cleanup_pop +.XREF pthread_cleanup_push_defer_np +.XREF pthread_cleanup_pop_restore_np + +.SH NAME +pthread_cleanup_push, pthread_cleanup_pop, pthread_cleanup_push_defer_np, pthread_cleanup_pop_restore_np \- install and remove cleanup handlers + +.SH SYNOPSIS +#include <pthread.h> + +void pthread_cleanup_push(void (*routine) (void *), void *arg); + +void pthread_cleanup_pop(int execute); + +void pthread_cleanup_push_defer_np(void (*routine) (void *), void *arg); + +void pthread_cleanup_pop_restore_np(int execute); + +.SH DESCRIPTION + +Cleanup handlers are functions that get called when a thread +terminates, either by calling !pthread_exit!(3) or because of +cancellation. Cleanup handlers are installed and removed following a +stack-like discipline. + +The purpose of cleanup handlers is to free the resources that a thread +may hold at the time it terminates. In particular, if a thread +exits or is cancelled while it owns a locked mutex, the mutex will +remain locked forever and prevent other threads from executing +normally. The best way to avoid this is, just before locking the +mutex, to install a cleanup handler whose effect is to unlock the +mutex. Cleanup handlers can be used similarly to free blocks allocated +with !malloc!(3) or close file descriptors on thread termination. + +!pthread_cleanup_push! installs the |routine| function with argument +|arg| as a cleanup handler. From this point on to the matching +!pthread_cleanup_pop!, the function |routine| will be called with +arguments |arg| when the thread terminates, either through !pthread_exit!(3) +or by cancellation. If several cleanup handlers are active at that +point, they are called in LIFO order: the most recently installed +handler is called first. + +!pthread_cleanup_pop! removes the most recently installed cleanup +handler. If the |execute| argument is not 0, it also executes the +handler, by calling the |routine| function with arguments |arg|. If +the |execute| argument is 0, the handler is only removed but not +executed. + +Matching pairs of !pthread_cleanup_push! and !pthread_cleanup_pop! +must occur in the same function, at the same level of block nesting. +Actually, !pthread_cleanup_push! and !pthread_cleanup_pop! are macros, +and the expansion of !pthread_cleanup_push! introduces an open brace !{! +with the matching closing brace !}! being introduced by the expansion +of the matching !pthread_cleanup_pop!. + +!pthread_cleanup_push_defer_np! is a non-portable extension that +combines !pthread_cleanup_push! and !pthread_setcanceltype!(3). +It pushes a cleanup handler just as !pthread_cleanup_push! does, but +also saves the current cancellation type and sets it to deferred +cancellation. This ensures that the cleanup mechanism is effective +even if the thread was initially in asynchronous cancellation mode. + +!pthread_cleanup_pop_restore_np! pops a cleanup handler introduced by +!pthread_cleanup_push_defer_np!, and restores the cancellation type to +its value at the time !pthread_cleanup_push_defer_np! was called. + +!pthread_cleanup_push_defer_np! and !pthread_cleanup_pop_restore_np! +must occur in matching pairs, at the same level of block nesting. + +The following sequence + +.RS +.ft 3 +.nf +.sp +pthread_cleanup_push_defer_np(routine, arg); +... +pthread_cleanup_pop_defer_np(execute); +.ft +.LP +.RE +.fi + +is functionally equivalent to (but more compact and more efficient than) + +.RS +.ft 3 +.nf +.sp +{ int oldtype; + pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldtype); + pthread_cleanup_push(routine, arg); + ... + pthread_cleanup_pop(execute); + pthread_setcanceltype(oldtype, NULL); +} +.ft +.LP +.RE +.fi + +.SH "RETURN VALUE" + +None. + +.SH ERRORS + +None. + +.SH AUTHOR +Xavier Leroy <Xavier.Leroy@inria.fr> + +.SH "SEE ALSO" +!pthread_exit!(3), +!pthread_cancel!(3), +!pthread_setcanceltype!(3). + +.SH EXAMPLE + +Here is how to lock a mutex |mut| in such a way that it will be +unlocked if the thread is canceled while |mut| is locked: + +.RS +.ft 3 +.nf +.sp +pthread_cleanup_push(pthread_mutex_unlock, (void *) &mut); +pthread_mutex_lock(&mut); +/* do some work */ +pthread_mutex_unlock(&mut); +pthread_cleanup_pop(0); +.ft +.LP +.RE +.fi + +Equivalently, the last two lines can be replaced by + +.RS +.ft 3 +.nf +.sp +pthread_cleanup_pop(1); +.ft +.LP +.RE +.fi + +Notice that the code above is safe only in deferred cancellation mode +(see !pthread_setcanceltype!(3)). In asynchronous cancellation mode, +a cancellation can occur between !pthread_cleanup_push! and +!pthread_mutex_lock!, or between !pthread_mutex_unlock! and +!pthread_cleanup_pop!, resulting in both cases in the thread trying to +unlock a mutex not locked by the current thread. This is the main +reason why asynchronous cancellation is difficult to use. + +If the code above must also work in asynchronous cancellation mode, +then it must switch to deferred mode for locking and unlocking the +mutex: + +.RS +.ft 3 +.nf +.sp +pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldtype); +pthread_cleanup_push(pthread_mutex_unlock, (void *) &mut); +pthread_mutex_lock(&mut); +/* do some work */ +pthread_cleanup_pop(1); +pthread_setcanceltype(oldtype, NULL); +.ft +.LP +.RE +.fi + +The code above can be rewritten in a more compact and more +efficient way, using the non-portable functions +!pthread_cleanup_push_defer_np! and !pthread_cleanup_pop_restore_np!: + +.RS +.ft 3 +.nf +.sp +pthread_cleanup_push_restore_np(pthread_mutex_unlock, (void *) &mut); +pthread_mutex_lock(&mut); +/* do some work */ +pthread_cleanup_pop_restore_np(1); +.ft +.LP +.RE +.fi + diff --git a/linuxthreads/man/pthread_cond_init.man b/linuxthreads/man/pthread_cond_init.man new file mode 100644 index 0000000000..4913062fd2 --- /dev/null +++ b/linuxthreads/man/pthread_cond_init.man @@ -0,0 +1,234 @@ +.TH PTHREAD_COND 3 LinuxThreads + +.XREF pthread_cond_signal +.XREF pthread_cond_broadcast +.XREF pthread_cond_wait +.XREF pthread_cond_timedwait +.XREF pthread_cond_destroy + +.SH NAME +pthread_cond_init, pthread_cond_destroy, pthread_cond_signal, pthread_cond_broadcast, pthread_cond_wait, pthread_cond_timedwait \- operations on conditions + +.SH SYNOPSIS +#include <pthread.h> + +pthread_cond_t cond = PTHREAD_COND_INITIALIZER; + +int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr); + +int pthread_cond_signal(pthread_cond_t *cond); + +int pthread_cond_broadcast(pthread_cond_t *cond); + +int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); + +int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime); + +int pthread_cond_destroy(pthread_cond_t *cond); + +.SH DESCRIPTION + +A condition (short for ``condition variable'') is a synchronization +device that allows threads to suspend execution and relinquish the +processors until some predicate on shared data is satisfied. The basic +operations on conditions are: signal the condition (when the +predicate becomes true), and wait for the condition, suspending the +thread execution until another thread signals the condition. + +A condition variable must always be associated with a mutex, to avoid +the race condition where a thread prepares to wait on a condition +variable and another thread signals the condition just before the +first thread actually waits on it. + +!pthread_cond_init! initializes the condition variable |cond|, using the +condition attributes specified in |cond_attr|, or default attributes +if |cond_attr| is !NULL!. The LinuxThreads implementation supports no +attributes for conditions, hence the |cond_attr| parameter is actually +ignored. + +Variables of type !pthread_cond_t! can also be initialized +statically, using the constant !PTHREAD_COND_INITIALIZER!. + +!pthread_cond_signal! restarts one of the threads that are waiting on +the condition variable |cond|. If no threads are waiting on |cond|, +nothing happens. If several threads are waiting on |cond|, exactly one +is restarted, but it is not specified which. + +!pthread_cond_broadcast! restarts all the threads that are waiting on +the condition variable |cond|. Nothing happens if no threads are +waiting on |cond|. + +!pthread_cond_wait! atomically unlocks the |mutex| (as per +!pthread_unlock_mutex!) and waits for the condition variable |cond| to +be signaled. The thread execution is suspended and does not consume +any CPU time until the condition variable is signaled. The |mutex| +must be locked by the calling thread on entrance to +!pthread_cond_wait!. Before returning to the calling thread, +!pthread_cond_wait! re-acquires |mutex| (as per !pthread_lock_mutex!). + +Unlocking the mutex and suspending on the condition variable is done +atomically. Thus, if all threads always acquire the mutex before +signaling the condition, this guarantees that the condition cannot be +signaled (and thus ignored) between the time a thread locks the mutex +and the time it waits on the condition variable. + +!pthread_cond_timedwait! atomically unlocks |mutex| and waits on +|cond|, as !pthread_cond_wait! does, but it also bounds the duration +of the wait. If |cond| has not been signaled within the amount of time +specified by |abstime|, the mutex |mutex| is re-acquired and +!pthread_cond_timedwait! returns the error !ETIMEDOUT!. +The |abstime| parameter specifies an absolute time, with the same +origin as !time!(2) and !gettimeofday!(2): an |abstime| of 0 +corresponds to 00:00:00 GMT, January 1, 1970. + +!pthread_cond_destroy! destroys a condition variable, freeing the +resources it might hold. No threads must be waiting on the condition +variable on entrance to !pthread_cond_destroy!. In the LinuxThreads +implementation, no resources are associated with condition variables, +thus !pthread_cond_destroy! actually does nothing except checking that +the condition has no waiting threads. + +.SH CANCELLATION + +!pthread_cond_wait! and !pthread_cond_timedwait! are cancellation +points. If a thread is cancelled while suspended in one of these +functions, the thread immediately resumes execution, then locks again +the |mutex| argument to !pthread_cond_wait! and +!pthread_cond_timedwait!, and finally executes the cancellation. +Consequently, cleanup handlers are assured that |mutex| is locked when +they are called. + +.SH "ASYNC-SIGNAL SAFETY" + +The condition functions are not async-signal safe, and should not be +called from a signal handler. In particular, calling +!pthread_cond_signal! or !pthread_cond_broadcast! from a signal +handler may deadlock the calling thread. + +.SH "RETURN VALUE" + +All condition variable functions return 0 on success and a non-zero +error code on error. + +.SH ERRORS + +!pthread_cond_init!, !pthread_cond_signal!, !pthread_cond_broadcast!, +and !pthread_cond_wait! never return an error code. + +The !pthread_cond_timedwait! function returns the following error codes +on error: +.RS +.TP +!ETIMEDOUT! +the condition variable was not signaled until the timeout specified by +|abstime| + +.TP +!EINTR! +!pthread_cond_timedwait! was interrupted by a signal +.RE + +The !pthread_cond_destroy! function returns the following error code +on error: +.RS +.TP +!EBUSY! +some threads are currently waiting on |cond|. +.RE + +.SH AUTHOR +Xavier Leroy <Xavier.Leroy@inria.fr> + +.SH "SEE ALSO" +!pthread_condattr_init!(3), +!pthread_mutex_lock!(3), +!pthread_mutex_unlock!(3), +!gettimeofday!(2), +!nanosleep!(2). + +.SH EXAMPLE + +Consider two shared variables |x| and |y|, protected by the mutex |mut|, +and a condition variable |cond| that is to be signaled whenever |x| +becomes greater than |y|. + +.RS +.ft 3 +.nf +.sp +int x,y; +pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; +pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +.ft +.LP +.RE +.fi + +Waiting until |x| is greater than |y| is performed as follows: + +.RS +.ft 3 +.nf +.sp +pthread_mutex_lock(&mut); +while (x <= y) { + pthread_cond_wait(&cond, &mut); +} +/* operate on x and y */ +pthread_mutex_unlock(&mut); +.ft +.LP +.RE +.fi + +Modifications on |x| and |y| that may cause |x| to become greater than +|y| should signal the condition if needed: + +.RS +.ft 3 +.nf +.sp +pthread_mutex_lock(&mut); +/* modify x and y */ +if (x > y) pthread_cond_broadcast(&cond); +pthread_mutex_unlock(&mut); +.ft +.LP +.RE +.fi + +If it can be proved that at most one waiting thread needs to be waken +up (for instance, if there are only two threads communicating through +|x| and |y|), !pthread_cond_signal! can be used as a slightly more +efficient alternative to !pthread_cond_broadcast!. In doubt, use +!pthread_cond_broadcast!. + +To wait for |x| to becomes greater than |y| with a timeout of 5 +seconds, do: + +.RS +.ft 3 +.nf +.sp +struct timeval now; +struct timespec timeout; +int retcode; + +pthread_mutex_lock(&mut); +gettimeofday(&now); +timeout.tv_sec = now.tv_sec + 5; +timeout.tv_nsec = now.tv_usec * 1000; +retcode = 0; +while (x <= y && retcode != ETIMEDOUT) { + retcode = pthread_cond_timedwait(&cond, &mut, &timeout); +} +if (retcode == ETIMEDOUT) { + /* timeout occurred */ +} else { + /* operate on x and y */ +} +pthread_mutex_unlock(&mut); +.ft +.LP +.RE +.fi diff --git a/linuxthreads/man/pthread_condattr_init.man b/linuxthreads/man/pthread_condattr_init.man new file mode 100644 index 0000000000..f491cbedbe --- /dev/null +++ b/linuxthreads/man/pthread_condattr_init.man @@ -0,0 +1,39 @@ +.TH PTHREAD_CONDATTR 3 LinuxThreads + +.XREF pthread_condattr_destroy + +.SH NAME +pthread_condattr_init, pthread_condattr_destroy \- condition creation attributes + +.SH SYNOPSIS +#include <pthread.h> + +int pthread_condattr_init(pthread_condattr_t *attr); + +int pthread_condattr_destroy(pthread_condattr_t *attr); + +.SH DESCRIPTION + +Condition attributes can be specified at condition creation time, by passing a +condition attribute object as second argument to !pthread_cond_init!(3). +Passing !NULL! is equivalent to passing a condition attribute object with +all attributes set to their default values. + +The LinuxThreads implementation supports no attributes for +conditions. The functions on condition attributes are included only +for compliance with the POSIX standard. + +!pthread_condattr_init! initializes the condition attribute object +|attr| and fills it with default values for the attributes. +!pthread_condattr_destroy! destroys a condition attribute object, +which must not be reused until it is reinitialized. Both functions do +nothing in the LinuxThreads implementation. + +.SH "RETURN VALUE" +!pthread_condattr_init! and !pthread_condattr_destroy! always return 0. + +.SH AUTHOR +Xavier Leroy <Xavier.Leroy@inria.fr> + +.SH "SEE ALSO" +!pthread_cond_init!(3). diff --git a/linuxthreads/man/pthread_create.man b/linuxthreads/man/pthread_create.man new file mode 100644 index 0000000000..a94004767a --- /dev/null +++ b/linuxthreads/man/pthread_create.man @@ -0,0 +1,46 @@ +.TH PTHREAD_CREATE 3 LinuxThreads + +.SH NAME +pthread_create \- create a new thread + +.SH SYNOPSIS +#include <pthread.h> + +int pthread_create(pthread_t * thread, pthread_attr_t * attr, void * (*start_routine)(void *), void * arg); + +.SH DESCRIPTION +!pthread_create! creates a new thread of control that executes +concurrently with the calling thread. The new thread applies the +function |start_routine| passing it |arg| as first argument. The new +thread terminates either explicitly, by calling !pthread_exit!(3), +or implicitly, by returning from the |start_routine| function. The +latter case is equivalent to calling !pthread_exit!(3) with the result +returned by |start_routine| as exit code. + +The |attr| argument specifies thread attributes to be applied to the +new thread. See !pthread_attr_init!(3) for a complete list of thread +attributes. The |attr| argument can also be !NULL!, in which case +default attributes are used: the created thread is joinable (not +detached) and has default (non real-time) scheduling policy. + +.SH "RETURN VALUE" +On success, the identifier of the newly created thread is stored in +the location pointed by the |thread| argument, and a 0 is returned. On +error, a non-zero error code is returned. + +.SH ERRORS +.TP +!EAGAIN! +not enough system resources to create a process for the new thread. +.TP +!EAGAIN! +more than !PTHREAD_THREADS_MAX! threads are already active. + +.SH AUTHOR +Xavier Leroy <Xavier.Leroy@inria.fr> + +.SH "SEE ALSO" +!pthread_exit!(3), +!pthread_join!(3), +!pthread_detach!(3), +!pthread_attr_init!(3). diff --git a/linuxthreads/man/pthread_detach.man b/linuxthreads/man/pthread_detach.man new file mode 100644 index 0000000000..7b43f45faa --- /dev/null +++ b/linuxthreads/man/pthread_detach.man @@ -0,0 +1,44 @@ +.TH PTHREAD_DETACH 3 LinuxThreads + +.SH NAME +pthread_detach \- put a running thread in the detached state + +.SH SYNOPSIS +#include <pthread.h> + +int pthread_detach(pthread_t th); + +.SH DESCRIPTION +!pthread_detach! put the thread |th| in the detached state. This +guarantees that the memory resources consumed by |th| will be freed +immediately when |th| terminates. However, this prevents other threads +from synchronizing on the termination of |th| using !pthread_join!. + +A thread can be created initially in the detached state, using the +!detachstate! attribute to !pthread_create!(3). In contrast, +!pthread_detach! applies to threads created in the joinable state, and +which need to be put in the detached state later. + +After !pthread_detach! completes, subsequent attempts to perform +!pthread_join! on |th| will fail. If another thread is already joining +the thread |th| at the time !pthread_detach! is called, +!pthread_detach! does nothing and leaves |th| in the joinable state. + +.SH "RETURN VALUE" +On success, 0 is returned. On error, a non-zero error code is returned. + +.SH ERRORS +.TP +!ESRCH! +No thread could be found corresponding to that specified by |th| +.TP +!EINVAL! +the thread |th| is already in the detached state + +.SH AUTHOR +Xavier Leroy <Xavier.Leroy@inria.fr> + +.SH "SEE ALSO" +!pthread_create!(3), +!pthread_join!(3), +!pthread_attr_setdetachstate!(3).
\ No newline at end of file diff --git a/linuxthreads/man/pthread_equal.man b/linuxthreads/man/pthread_equal.man new file mode 100644 index 0000000000..1a0396515a --- /dev/null +++ b/linuxthreads/man/pthread_equal.man @@ -0,0 +1,23 @@ +.TH PTHREAD_EQUAL 3 LinuxThreads + +.SH NAME +pthread_equal \- compare two thread identifiers + +.SH SYNOPSIS +#include <pthread.h> + +int pthread_equal(pthread_t thread1, pthread_t thread2); + +.SH DESCRIPTION +!pthread_equal! determines if two thread identifiers refer to the same +thread. + +.SH "RETURN VALUE" +A non-zero value is returned if |thread1| and |thread2| refer to the +same thread. Otherwise, 0 is returned. + +.SH AUTHOR +Xavier Leroy <Xavier.Leroy@inria.fr> + +.SH "SEE ALSO" +!pthread_self!(3). diff --git a/linuxthreads/man/pthread_exit.man b/linuxthreads/man/pthread_exit.man new file mode 100644 index 0000000000..54751e9d05 --- /dev/null +++ b/linuxthreads/man/pthread_exit.man @@ -0,0 +1,32 @@ +.TH PTHREAD_EXIT 3 LinuxThreads + +.SH NAME +pthread_exit \- terminate the calling thread + +.SH SYNOPSIS +#include <pthread.h> + +void pthread_exit(void *retval); + +.SH DESCRIPTION +!pthread_exit! terminates the execution of the calling thread. +All cleanup handlers that have been set for the calling thread with +!pthread_cleanup_push!(3) are executed in reverse order (the most +recently pushed handler is executed first). Finalization functions for +thread-specific data are then called for all keys that have non-!NULL! +values associated with them in the calling thread (see +!pthread_key_create!(3)). Finally, execution of the calling thread is +stopped. + +The |retval| argument is the return value of the thread. It can be +consulted from another thread using !pthread_join!(3). + +.SH "RETURN VALUE" +The !pthread_exit! function never returns. + +.SH AUTHOR +Xavier Leroy <Xavier.Leroy@inria.fr> + +.SH "SEE ALSO" +!pthread_create!(3), +!pthread_join!(3). diff --git a/linuxthreads/man/pthread_join.man b/linuxthreads/man/pthread_join.man new file mode 100644 index 0000000000..d587093841 --- /dev/null +++ b/linuxthreads/man/pthread_join.man @@ -0,0 +1,70 @@ +.TH PTHREAD_JOIN 3 LinuxThreads + +.SH NAME +pthread_join \- wait for termination of another thread + +.SH SYNOPSIS +#include <pthread.h> + +int pthread_join(pthread_t th, void **thread_return); + +.SH DESCRIPTION +!pthread_join! suspends the execution of the calling thread until the +thread identified by |th| terminates, either by calling !pthread_exit!(3) +or by being cancelled. + +If |thread_return| is not !NULL!, the return value of |th| is stored +in the location pointed to by |thread_return|. The return value of +|th| is either the argument it gave to !pthread_exit!(3), or +!PTHREAD_CANCELED! if |th| was cancelled. + +The joined thread !th! must be in the joinable state: it must not have +been detached using !pthread_detach!(3) or the +!PTHREAD_CREATE_DETACHED! attribute to !pthread_create!(3). + +When a joinable thread terminates, its memory resources (thread +descriptor and stack) are not deallocated until another thread +performs !pthread_join! on it. Therefore, !pthread_join! must be +called once for each joinable thread created to avoid memory leaks. + +At most one thread can wait for the termination of a given +thread. Calling !pthread_join! on a thread |th| on which another +thread is already waiting for termination returns an error. + +.SH CANCELLATION + +!pthread_join! is a cancellation point. If a thread is canceled while +suspended in !pthread_join!, the thread execution resumes immediately +and the cancellation is executed without waiting for the |th| thread +to terminate. If cancellation occurs during !pthread_join!, the |th| +thread remains not joined. + +.SH "RETURN VALUE" +On success, the return value of |th| is stored in the location pointed +to by |thread_return|, and 0 is returned. On error, a non-zero error +code is returned. + +.SH ERRORS +.TP +!ESRCH! +No thread could be found corresponding to that specified by |th|. +.TP +!EINVAL! +The |th| thread has been detached. +.TP +!EINVAL! +Another thread is already waiting on termination of |th|. +.TP +!EDEADLK! +The |th| argument refers to the calling thread. + +.SH AUTHOR +Xavier Leroy <Xavier.Leroy@inria.fr> + +.SH "SEE ALSO" +!pthread_exit!(3), +!pthread_detach!(3), +!pthread_create!(3), +!pthread_attr_setdetachstate!(3), +!pthread_cleanup_push!(3), +!pthread_key_create!(3). diff --git a/linuxthreads/man/pthread_key_create.man b/linuxthreads/man/pthread_key_create.man new file mode 100644 index 0000000000..6823e304c9 --- /dev/null +++ b/linuxthreads/man/pthread_key_create.man @@ -0,0 +1,151 @@ +.TH PTHREAD_SPECIFIC 3 LinuxThreads + +.SH NAME +pthread_key_create, pthread_key_delete, pthread_setspecific, pthread_getspecific \- management of thread-specific data + +.SH SYNOPSIS +#include <pthread.h> + +int pthread_key_create(pthread_key_t *key, void (*destr_function) (void *)); + +int pthread_key_delete(pthread_key_t key); + +int pthread_setspecific(pthread_key_t key, const void *pointer); + +void * pthread_getspecific(pthread_key_t key); + +.SH DESCRIPTION + +Programs often need global or static variables that have different +values in different threads. Since threads share one memory space, +this cannot be achieved with regular variables. Thread-specific data +is the POSIX threads answer to this need. + +Each thread possesses a private memory block, the thread-specific data +area, or TSD area for short. This area is indexed by TSD keys. The TSD +area associates values of type !void *! to TSD keys. TSD keys are +common to all threads, but the value associated with a given TSD key +can be different in each thread. + +For concreteness, the TSD areas can be viewed as arrays of !void *! +pointers, TSD keys as integer indices into these arrays, and the value +of a TSD key as the value of the corresponding array element in the +calling thread. + +When a thread is created, its TSD area initially associates !NULL! +with all keys. + +!pthread_key_create! allocates a new TSD key. The key is stored in the +location pointed to by |key|. There is a limit of !PTHREAD_KEYS_MAX! +on the number of keys allocated at a given time. The value initially +associated with the returned key is !NULL! in all currently executing +threads. + +The |destr_function| argument, if not !NULL!, specifies a destructor +function associated with the key. When a thread terminates via +!pthread_exit! or by cancellation, |destr_function| is called with +arguments the value associated with the key in that thread. The +|destr_function| is not called if that value is !NULL!. The order in +which destructor functions are called at thread termination time is +unspecified. + +Before the destructor function is called, the !NULL! value is +associated with the key in the current thread. A destructor function +might, however, re-associate non-!NULL! values to that key or some +other key. To deal with this, if after all the destructors have been +called for all non-!NULL! values, there are still some non-!NULL! +values with associated destructors, then the process is repeated. The +LinuxThreads implementation stops the process after +!PTHREAD_DESTRUCTOR_ITERATIONS! iterations, even if some non-!NULL! +values with associated descriptors remain. Other implementations may +loop indefinitely. + +!pthread_key_delete! deallocates a TSD key. It does not check whether +non-!NULL! values are associated with that key in the currently +executing threads, nor call the destructor function associated with +the key. + +!pthread_setspecific! changes the value associated with |key| in the +calling thread, storing the given |pointer| instead. + +!pthread_getspecific! returns the value currently associated with +|key| in the calling thread. + +.SH "RETURN VALUE" + +!pthread_key_create!, !pthread_key_delete!, and !pthread_setspecific! +return 0 on success and a non-zero error code on failure. If +successful, !pthread_key_create! stores the newly allocated key in the +location pointed to by its |key| argument. + +!pthread_getspecific! returns the value associated with |key| on +success, and !NULL! on error. + +.SH ERRORS +!pthread_key_create! returns the following error code on error: +.RS +.TP +!EAGAIN! +!PTHREAD_KEYS_MAX! keys are already allocated +.RE + +!pthread_key_delete! and !pthread_setspecific! return the following +error code on error: +.RS +.TP +!EINVAL! +|key| is not a valid, allocated TSD key +.RE + +!pthread_getspecific! returns !NULL! if |key| is not a valid, +allocated TSD key. + +.SH AUTHOR +Xavier Leroy <Xavier.Leroy@inria.fr> + +.SH "SEE ALSO" +pthread_create(3), pthread_exit(3), pthread_testcancel(3). + +.SH EXAMPLE + +The following code fragment allocates a thread-specific array of 100 +characters, with automatic reclaimation at thread exit: + +.RS +.ft 3 +.nf +.sp +/* Key for the thread-specific buffer */ +static pthread_key_t buffer_key; + +/* Once-only initialisation of the key */ +static pthread_once_t buffer_key_once = PTHREAD_ONCE_INIT; + +/* Allocate the thread-specific buffer */ +void buffer_alloc(void) +{ + pthread_once(&buffer_key_once, buffer_key_alloc); + pthread_setspecific(buffer_key, malloc(100)); +} + +/* Return the thread-specific buffer */ +char * get_buffer(void) +{ + return (char *) pthread_getspecific(buffer_key); +} + +/* Allocate the key */ +static void buffer_key_alloc() +{ + pthread_key_create(&buffer_key, buffer_destroy); +} + +/* Free the thread-specific buffer */ +static void buffer_destroy(void * buf) +{ + free(buf); +} +.ft +.LP +.RE +.fi diff --git a/linuxthreads/man/pthread_kill_other_threads_np.man b/linuxthreads/man/pthread_kill_other_threads_np.man new file mode 100644 index 0000000000..0de42d52d5 --- /dev/null +++ b/linuxthreads/man/pthread_kill_other_threads_np.man @@ -0,0 +1,40 @@ +.TH PTHREAD_KILL_OTHER_THREADS_NP 3 LinuxThreads + +.SH NAME +pthread_kill_other_threads_np \- terminate all threads in program except calling thread + +.SH SYNOPSIS +#include <pthread.h> + +void pthread_kill_other_threads_np(void); + +.SH DESCRIPTION +!pthread_kill_other_threads_np! is a non-portable LinuxThreads extension. +It causes all threads in the program to terminate immediately, except +the calling thread which proceeds normally. It is intended to be +called just before a thread calls one of the !exec! functions, +e.g. !execve!(2). + +Termination of the other threads is not performed through +!pthread_cancel!(3) and completely bypasses the cancellation +mechanism. Hence, the current settings for cancellation state and +cancellation type are ignored, and the cleanup handlers are not +executed in the terminated threads. + +.SH AUTHOR +Xavier Leroy <Xavier.Leroy@inria.fr> + +.SH "SEE ALSO" +!execve!(2), +!pthread_setcancelstate!(3), +!pthread_setcanceltype!(3), +!pthread_cancel!(3). + +.SH BUGS + +According to POSIX 1003.1c, a successful !exec*! in one of the threads +should terminate automatically all other threads in the program. +This behavior is not yet implemented in LinuxThreads. +Calling !pthread_kill_other_threads_np! before !exec*! achieves much +of the same behavior, except that if !exec*! ultimately fails, then +all other threads are already killed. diff --git a/linuxthreads/man/pthread_mutex_init.man b/linuxthreads/man/pthread_mutex_init.man new file mode 100644 index 0000000000..643b007aec --- /dev/null +++ b/linuxthreads/man/pthread_mutex_init.man @@ -0,0 +1,213 @@ +.TH PTHREAD_MUTEX 3 LinuxThreads + +.XREF pthread_mutex_lock +.XREF pthread_mutex_unlock +.XREF pthread_mutex_trylock +.XREF pthread_mutex_destroy + +.SH NAME +pthread_mutex_init, pthread_mutex_lock, pthread_mutex_trylock, pthread_mutex_unlock, pthread_mutex_destroy \- operations on mutexes + +.SH SYNOPSIS +#include <pthread.h> + +pthread_mutex_t fastmutex = PTHREAD_MUTEX_INITIALIZER; + +pthread_mutex_t recmutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; + +pthread_mutex_t errchkmutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP; + +int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr); + +int pthread_mutex_lock(pthread_mutex_t *mutex); + +int pthread_mutex_trylock(pthread_mutex_t *mutex); + +int pthread_mutex_unlock(pthread_mutex_t *mutex); + +int pthread_mutex_destroy(pthread_mutex_t *mutex); + +.SH DESCRIPTION +A mutex is a MUTual EXclusion device, and is useful for protecting +shared data structures from concurrent modifications, and implementing +critical sections and monitors. + +A mutex has two possible states: unlocked (not owned by any thread), +and locked (owned by one thread). A mutex can never be owned by two +different threads simultaneously. A thread attempting to lock a mutex +that is already locked by another thread is suspended until the owning +thread unlocks the mutex first. + +!pthread_mutex_init! initializes the mutex object pointed to by +|mutex| according to the mutex attributes specified in |mutexattr|. +If |mutexattr| is !NULL!, default attributes are used instead. + +The LinuxThreads implementation supports only one mutex attributes, +the |mutex kind|, which is either ``fast'', ``recursive'', or +``error checking''. The kind of a mutex determines whether +it can be locked again by a thread that already owns it. +The default kind is ``fast''. See !pthread_mutexattr_init!(3) for more +information on mutex attributes. + +Variables of type !pthread_mutex_t! can also be initialized +statically, using the constants !PTHREAD_MUTEX_INITIALIZER! (for fast +mutexes), !PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP! (for recursive +mutexes), and !PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP! (for error checking +mutexes). + +!pthread_mutex_lock! locks the given mutex. If the mutex is currently +unlocked, it becomes locked and owned by the calling thread, and +!pthread_mutex_lock! returns immediately. If the mutex is already +locked by another thread, !pthread_mutex_lock! suspends the calling +thread until the mutex is unlocked. + +If the mutex is already locked by the calling thread, the behavior of +!pthread_mutex_lock! depends on the kind of the mutex. If the mutex is +of the ``fast'' kind, the calling thread is suspended until the mutex +is unlocked, thus effectively causing the calling thread to +deadlock. If the mutex is of the ``error checking'' kind, +!pthread_mutex_lock! returns immediately with the error code !EDEADLK!. +If the mutex is of the ``recursive'' kind, !pthread_mutex_lock! +succeeds and returns immediately, recording the number of times the +calling thread has locked the mutex. An equal number of +!pthread_mutex_unlock! operations must be performed before the mutex +returns to the unlocked state. + +!pthread_mutex_trylock! behaves identically to !pthread_mutex_lock!, +except that it does not block the calling thread if the mutex is +already locked by another thread (or by the calling thread in the case +of a ``fast'' mutex). Instead, !pthread_mutex_trylock! returns +immediately with the error code !EBUSY!. + +!pthread_mutex_unlock! unlocks the given mutex. The mutex is assumed +to be locked and owned by the calling thread on entrance to +!pthread_mutex_unlock!. If the mutex is of the ``fast'' kind, +!pthread_mutex_unlock! always returns it to the unlocked state. If it +is of the ``recursive'' kind, it decrements the locking count of the +mutex (number of !pthread_mutex_lock! operations performed on it by +the calling thread), and only when this count reaches zero is the +mutex actually unlocked. + +On ``error checking'' mutexes, !pthread_mutex_unlock! actually checks +at run-time that the mutex is locked on entrance, and that it was +locked by the same thread that is now calling !pthread_mutex_unlock!. +If these conditions are not met, an error code is returned and the +mutex remains unchanged. ``Fast'' and ``recursive'' mutexes perform +no such checks, thus allowing a locked mutex to be unlocked by a +thread other than its owner. This is non-portable behavior and must +not be relied upon. + +!pthread_mutex_destroy! destroys a mutex object, freeing the resources +it might hold. The mutex must be unlocked on entrance. In the +LinuxThreads implementation, no resources are associated with mutex +objects, thus !pthread_mutex_destroy! actually does nothing except +checking that the mutex is unlocked. + +.SH CANCELLATION + +None of the mutex functions is a cancellation point, not even +!pthread_mutex_lock!, in spite of the fact that it can suspend a +thread for arbitrary durations. This way, the status of mutexes at +cancellation points is predictable, allowing cancellation handlers to +unlock precisely those mutexes that need to be unlocked before the +thread stops executing. Consequently, threads using deferred +cancellation should never hold a mutex for extended periods of time. + +.SH "ASYNC-SIGNAL SAFETY" + +The mutex functions are not async-signal safe. What this means is that +they should not be called from a signal handler. In particular, +calling !pthread_mutex_lock! or !pthread_mutex_unlock! from a signal +handler may deadlock the calling thread. + +.SH "RETURN VALUE" + +!pthread_mutex_init! always returns 0. The other mutex functions +return 0 on success and a non-zero error code on error. + +.SH ERRORS + +The !pthread_mutex_lock! function returns the following error code +on error: +.RS +.TP +!EINVAL! +the mutex has not been properly initialized. + +.TP +!EDEADLK! +the mutex is already locked by the calling thread +(``error checking'' mutexes only). +.RE + +The !pthread_mutex_trylock! function returns the following error codes +on error: +.RS +.TP +!EBUSY! +the mutex could not be acquired because it was currently locked. + +.TP +!EINVAL! +the mutex has not been properly initialized. +.RE + +The !pthread_mutex_unlock! function returns the following error code +on error: +.RS +.TP +!EINVAL! +the mutex has not been properly initialized. + +.TP +!EPERM! +the calling thread does not own the mutex (``error checking'' mutexes only). +.RE + +The !pthread_mutex_destroy! function returns the following error code +on error: +.RS +.TP +!EBUSY! +the mutex is currently locked. +.RE + +.SH AUTHOR +Xavier Leroy <Xavier.Leroy@inria.fr> + +.SH "SEE ALSO" +!pthread_mutexattr_init!(3), +!pthread_mutexattr_setkind_np!(3), +!pthread_cancel!(3). + +.SH EXAMPLE + +A shared global variable |x| can be protected by a mutex as follows: + +.RS +.ft 3 +.nf +.sp +int x; +pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; +.ft +.LP +.RE +.fi + +All accesses and modifications to |x| should be bracketed by calls to +!pthread_mutex_lock! and !pthread_mutex_unlock! as follows: + +.RS +.ft 3 +.nf +.sp +pthread_mutex_lock(&mut); +/* operate on x */ +pthread_mutex_unlock(&mut); +.ft +.LP +.RE +.fi + + diff --git a/linuxthreads/man/pthread_mutexattr_init.man b/linuxthreads/man/pthread_mutexattr_init.man new file mode 100644 index 0000000000..b838948904 --- /dev/null +++ b/linuxthreads/man/pthread_mutexattr_init.man @@ -0,0 +1,84 @@ +.TH PTHREAD_MUTEXATTR 3 LinuxThreads + +.XREF pthread_mutexattr_destroy +.XREF pthread_mutexattr_settype +.XREF pthread_mutexattr_gettype + +.SH NAME +pthread_mutexattr_init, pthread_mutexattr_destroy, pthread_mutexattr_settype, pthread_mutexattr_gettype \- mutex creation attributes + +.SH SYNOPSIS +#include <pthread.h> + +int pthread_mutexattr_init(pthread_mutexattr_t *attr); + +int pthread_mutexattr_destroy(pthread_mutexattr_t *attr); + +int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int kind); + +int pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *kind); + +.SH DESCRIPTION + +Mutex attributes can be specified at mutex creation time, by passing a +mutex attribute object as second argument to !pthread_mutex_init!(3). +Passing !NULL! is equivalent to passing a mutex attribute object with +all attributes set to their default values. + +!pthread_mutexattr_init! initializes the mutex attribute object |attr| +and fills it with default values for the attributes. + +!pthread_mutexattr_destroy! destroys a mutex attribute object, which +must not be reused until it is reinitialized. !pthread_mutexattr_destroy! +does nothing in the LinuxThreads implementation. + +LinuxThreads supports only one mutex attribute: the mutex kind, which +is either !PTHREAD_MUTEX_FAST_NP! for ``fast'' mutexes, +!PTHREAD_MUTEX_RECURSIVE_NP! for ``recursive'' mutexes, +or !PTHREAD_MUTEX_ERRORCHECK_NP! for ``error checking'' mutexes. +As the !NP! suffix indicates, this is a non-portable extension to the +POSIX standard and should not be employed in portable programs. + +The mutex kind determines what happens if a thread attempts to lock a +mutex it already owns with !pthread_mutex_lock!(3). If the mutex is of +the ``fast'' kind, !pthread_mutex_lock!(3) simply suspends the calling +thread forever. If the mutex is of the ``error checking'' kind, +!pthread_mutex_lock!(3) returns immediately with the error code +!EDEADLK!. If the mutex is of the ``recursive'' kind, the call to +!pthread_mutex_lock!(3) returns immediately with a success return +code. The number of times the thread owning the mutex has locked it is +recorded in the mutex. The owning thread must call +!pthread_mutex_unlock!(3) the same number of times before the mutex +returns to the unlocked state. + +The default mutex kind is ``fast'', that is, !PTHREAD_MUTEX_FAST_NP!. + +!pthread_mutexattr_settype! sets the mutex kind attribute in |attr| +to the value specified by |kind|. + +!pthread_mutexattr_gettype! retrieves the current value of the +mutex kind attribute in |attr| and stores it in the location pointed +to by |kind|. + +.SH "RETURN VALUE" +!pthread_mutexattr_init!, !pthread_mutexattr_destroy! and +!pthread_mutexattr_gettype! always return 0. + +!pthread_mutexattr_settype! returns 0 on success and a non-zero +error code on error. + +.SH ERRORS + +On error, !pthread_mutexattr_settype! returns the following error code: +.TP +!EINVAL! +|kind| is neither !PTHREAD_MUTEX_FAST_NP! nor !PTHREAD_MUTEX_RECURSIVE_NP! +nor !PTHREAD_MUTEX_ERRORCHECK_NP! + +.SH AUTHOR +Xavier Leroy <Xavier.Leroy@inria.fr> + +.SH "SEE ALSO" +!pthread_mutex_init!(3), +!pthread_mutex_lock!(3), +!pthread_mutex_unlock!(3). diff --git a/linuxthreads/man/pthread_mutexattr_setkind_np.man b/linuxthreads/man/pthread_mutexattr_setkind_np.man new file mode 100644 index 0000000000..e10f47d0e5 --- /dev/null +++ b/linuxthreads/man/pthread_mutexattr_setkind_np.man @@ -0,0 +1,39 @@ +.TH PTHREAD_MUTEXATTR_SETKIND_NP 3 LinuxThreads + +.XREF pthread_mutexattr_getkind_np + +.SH NAME +pthread_mutexattr_setkind_np, pthread_mutexattr_getkind_np \- deprecated mutex creation attributes + +.SH SYNOPSIS +#include <pthread.h> + +int pthread_mutexattr_setkind_np(pthread_mutexattr_t *attr, int kind); + +int pthread_mutexattr_getkind_np(const pthread_mutexattr_t *attr, int *kind); + +.SH DESCRIPTION + +These functions are deprecated, use !pthread_mutexattr_settype!(3) +and !pthread_mutexattr_gettype!(3) instead. + +.SH "RETURN VALUE" +!pthread_mutexattr_getkind_np! always returns 0. + +!pthread_mutexattr_setkind_np! returns 0 on success and a non-zero +error code on error. + +.SH ERRORS + +On error, !pthread_mutexattr_setkind_np! returns the following error code: +.TP +!EINVAL! +|kind| is neither !PTHREAD_MUTEX_FAST_NP! nor !PTHREAD_MUTEX_RECURSIVE_NP! +nor !PTHREAD_MUTEX_ERRORCHECK_NP! + +.SH AUTHOR +Xavier Leroy <Xavier.Leroy@inria.fr> + +.SH "SEE ALSO" +!pthread_mutexattr_settype!(3), +!pthread_mutexattr_gettype!(3). diff --git a/linuxthreads/man/pthread_once.man b/linuxthreads/man/pthread_once.man new file mode 100644 index 0000000000..e9d117b656 --- /dev/null +++ b/linuxthreads/man/pthread_once.man @@ -0,0 +1,34 @@ +.TH PTHREAD_ONCE 3 LinuxThreads + +.SH NAME +pthread_once \- once-only initialization + +.SH SYNOPSIS +#include <pthread.h> + +pthread_once_t once_control = PTHREAD_ONCE_INIT; + +int pthread_once(pthread_once_t *once_control, void (*init_routine) (void)); + +.SH DESCRIPTION + +The purpose of !pthread_once! is to ensure that a piece of +initialization code is executed at most once. The |once_control| +argument points to a static or extern variable statically initialized +to !PTHREAD_ONCE_INIT!. + +The first time !pthread_once! is called with a given |once_control| +argument, it calls |init_routine| with no argument and changes the +value of the |once_control| variable to record that initialization has +been performed. Subsequent calls to !pthread_once! with the same +!once_control! argument do nothing. + +.SH "RETURN VALUE" +!pthread_once! always returns 0. + +.SH ERRORS +None. + +.SH AUTHOR +Xavier Leroy <Xavier.Leroy@inria.fr> + diff --git a/linuxthreads/man/pthread_self.man b/linuxthreads/man/pthread_self.man new file mode 100644 index 0000000000..3aa4a0021e --- /dev/null +++ b/linuxthreads/man/pthread_self.man @@ -0,0 +1,23 @@ +.TH PTHREAD_SELF 3 LinuxThreads + +.SH NAME +pthread_self \- return identifier of current thread + +.SH SYNOPSIS +#include <pthread.h> + +pthread_t pthread_self(void); + +.SH DESCRIPTION +!pthread_self! return the thread identifier for the calling thread. + +.SH AUTHOR +Xavier Leroy <Xavier.Leroy@inria.fr> + +.SH "SEE ALSO" +!pthread_equal!(3), +!pthread_join!(3), +!pthread_detach!(3), +!pthread_setschedparam!(3), +!pthread_getschedparam!(3). + diff --git a/linuxthreads/man/pthread_setschedparam.man b/linuxthreads/man/pthread_setschedparam.man new file mode 100644 index 0000000000..3992927837 --- /dev/null +++ b/linuxthreads/man/pthread_setschedparam.man @@ -0,0 +1,79 @@ +.TH PTHREAD_SETSCHEDPARAM 3 LinuxThreads + +.XREF pthread_getschedparam + +.SH NAME +pthread_setschedparam, pthread_getschedparam \- control thread scheduling parameters + +.SH SYNOPSIS +#include <pthread.h> + +int pthread_setschedparam(pthread_t target_thread, int policy, const struct sched_param *param); + +int pthread_getschedparam(pthread_t target_thread, int *policy, struct sched_param *param); + +.SH DESCRIPTION + +!pthread_setschedparam! sets the scheduling parameters for the thread +|target_thread| as indicated by |policy| and |param|. |policy| can be +either !SCHED_OTHER! (regular, non-realtime scheduling), !SCHED_RR! +(realtime, round-robin) or !SCHED_FIFO! (realtime, first-in +first-out). |param| specifies the scheduling priority for the two +realtime policies. See !sched_setpolicy!(2) for more information on +scheduling policies. + +The realtime scheduling policies !SCHED_RR! and !SCHED_FIFO! are +available only to processes with superuser privileges. + +!pthread_getschedparam! retrieves the scheduling policy and scheduling +parameters for the thread |target_thread| and store them in the +locations pointed to by |policy| and |param|, respectively. + +.SH "RETURN VALUE" +!pthread_setschedparam! and !pthread_getschedparam! return 0 on +success and a non-zero error code on error. + +.SH ERRORS +On error, !pthread_setschedparam! returns the following error codes: +.RS +.TP +!EINVAL! +|policy| is not one of !SCHED_OTHER!, !SCHED_RR!, !SCHED_FIFO! + +.TP +!EINVAL! +the priority value specified by |param| is not valid for the specified policy + +.TP +!EPERM! +the calling process does not have superuser permissions + +.TP +!ESRCH! +the |target_thread| is invalid or has already terminated + +.TP +!EFAULT! +|param| points outside the process memory space +.RE + +On error, !pthread_getschedparam! returns the following error codes: +.RS +.TP +!ESRCH! +the |target_thread| is invalid or has already terminated + +.TP +!EFAULT! +|policy| or |param| point outside the process memory space +.RE + +.SH AUTHOR +Xavier Leroy <Xavier.Leroy@inria.fr> + +.SH "SEE ALSO" +!sched_setscheduler!(2), +!sched_getscheduler!(2), +!sched_getparam!(2), +!pthread_attr_setschedpolicy!(3), +!pthread_attr_setschedparam!(3). diff --git a/linuxthreads/man/pthread_sigmask.man b/linuxthreads/man/pthread_sigmask.man new file mode 100644 index 0000000000..784161da2b --- /dev/null +++ b/linuxthreads/man/pthread_sigmask.man @@ -0,0 +1,123 @@ +.TH PTHREAD_SIGNAL 3 LinuxThreads + +.XREF pthread_kill +.XREF sigwait + +.SH NAME +pthread_sigmask, pthread_kill, sigwait \- handling of signals in threads + +.SH SYNOPSIS +#include <pthread.h> +.br +#include <signal.h> + +int pthread_sigmask(int how, const sigset_t *newmask, sigset_t *oldmask); + +int pthread_kill(pthread_t thread, int signo); + +int sigwait(const sigset_t *set, int *sig); + +.SH DESCRIPTION + +!pthread_sigmask! changes the signal mask for the calling thread as +described by the |how| and |newmask| arguments. If |oldmask| is not +!NULL!, the previous signal mask is stored in the location pointed to +by |oldmask|. + +The meaning of the |how| and |newmask| arguments is the same as for +!sigprocmask!(2). If |how| is !SIG_SETMASK!, the signal mask is set to +|newmask|. If |how| is !SIG_BLOCK!, the signals specified to |newmask| +are added to the current signal mask. If |how| is !SIG_UNBLOCK!, the +signals specified to |newmask| are removed from the current signal +mask. + +Recall that signal masks are set on a per-thread basis, but signal +actions and signal handlers, as set with !sigaction!(2), are shared +between all threads. + +!pthread_kill! send signal number |signo| to the thread +|thread|. The signal is delivered and handled as described in +!kill!(2). + +!sigwait! suspends the calling thread until one of the signals +in |set| is delivered to the calling thread. It then stores the number +of the signal received in the location pointed to by |sig| and +returns. The signals in |set| must be blocked and not ignored on +entrance to !sigwait!. If the delivered signal has a signal handler +function attached, that function is |not| called. + +.SH CANCELLATION + +!sigwait! is a cancellation point. + +.SH "RETURN VALUE" + +On success, 0 is returned. On failure, a non-zero error code is returned. + +.SH ERRORS + +The !pthread_sigmask! function returns the following error codes +on error: +.RS +.TP +!EINVAL! +|how| is not one of !SIG_SETMASK!, !SIG_BLOCK!, or !SIG_UNBLOCK! + +.TP +!EFAULT! +|newmask| or |oldmask| point to invalid addresses +.RE + +The !pthread_kill! function returns the following error codes +on error: +.RS +.TP +!EINVAL! +|signo| is not a valid signal number + +.TP +!ESRCH! +the thread |thread| does not exist (e.g. it has already terminated) +.RE + +The !sigwait! function never returns an error. + +.SH AUTHOR +Xavier Leroy <Xavier.Leroy@inria.fr> + +.SH "SEE ALSO" +!sigprocmask!(2), +!kill!(2), +!sigaction!(2), +!sigsuspend!(2). + +.SH NOTES + +For !sigwait! to work reliably, the signals being waited for must be +blocked in all threads, not only in the calling thread, since +otherwise the POSIX semantics for signal delivery do not guarantee +that it's the thread doing the !sigwait! that will receive the signal. +The best way to achieve this is block those signals before any threads +are created, and never unblock them in the program other than by +calling !sigwait!. + +.SH BUGS + +Signal handling in LinuxThreads departs significantly from the POSIX +standard. According to the standard, ``asynchronous'' (external) +signals are addressed to the whole process (the collection of all +threads), which then delivers them to one particular thread. The +thread that actually receives the signal is any thread that does +not currently block the signal. + +In LinuxThreads, each thread is actually a kernel process with its own +PID, so external signals are always directed to one particular thread. +If, for instance, another thread is blocked in !sigwait! on that +signal, it will not be restarted. + +The LinuxThreads implementation of !sigwait! installs dummy signal +handlers for the signals in |set| for the duration of the wait. Since +signal handlers are shared between all threads, other threads must not +attach their own signal handlers to these signals, or alternatively +they should all block these signals (which is recommended anyway -- +see the Notes section). diff --git a/linuxthreads/man/sem_init.man b/linuxthreads/man/sem_init.man new file mode 100644 index 0000000000..e3a1a63e36 --- /dev/null +++ b/linuxthreads/man/sem_init.man @@ -0,0 +1,132 @@ +.TH SEMAPHORES 3 LinuxThreads + +.XREF sem_wait +.XREF sem_trywait +.XREF sem_post +.XREF sem_getvalue +.XREF sem_destroy + +.SH NAME +sem_init, sem_wait, sem_trywait, sem_post, sem_getvalue, sem_destroy \- operations on semaphores + +.SH SYNOPSIS +#include <semaphore.h> + +int sem_init(sem_t *sem, int pshared, unsigned int value); + +int sem_wait(sem_t * sem); + +int sem_trywait(sem_t * sem); + +int sem_post(sem_t * sem); + +int sem_getvalue(sem_t * sem, int * sval); + +int sem_destroy(sem_t * sem); + +.SH DESCRIPTION +This manual page documents POSIX 1003.1b semaphores, not to be +confused with SystemV semaphores as described in !ipc!(5), !semctl!(2) +and !semop!(2). + +Semaphores are counters for resources shared between threads. The +basic operations on semaphores are: increment the counter atomically, +and wait until the counter is non-null and decrement it atomically. + +!sem_init! initializes the semaphore object pointed to by |sem|. The +count associated with the semaphore is set initially to |value|. The +|pshared| argument indicates whether the semaphore is local to the +current process (|pshared| is zero) or is to be shared between several +processes (|pshared| is not zero). LinuxThreads currently does not +support process-shared semaphores, thus !sem_init! always returns with +error !ENOSYS! if |pshared| is not zero. + +!sem_wait! suspends the calling thread until the semaphore pointed to +by |sem| has non-zero count. It then atomically decreases the +semaphore count. + +!sem_trywait! is a non-blocking variant of !sem_wait!. If the +semaphore pointed to by |sem| has non-zero count, the count is +atomically decreased and !sem_trywait! immediately returns 0. +If the semaphore count is zero, !sem_trywait! immediately returns with +error !EAGAIN!. + +!sem_post! atomically increases the count of the semaphore pointed to +by |sem|. This function never blocks and can safely be used in +asynchronous signal handlers. + +!sem_getvalue! stores in the location pointed to by |sval| the current +count of the semaphore |sem|. + +!sem_destroy! destroys a semaphore object, freeing the resources it +might hold. No threads should be waiting on the semaphore at the time +!sem_destroy! is called. In the LinuxThreads implementation, no +resources are associated with semaphore objects, thus !sem_destroy! +actually does nothing except checking that no thread is waiting on the +semaphore. + +.SH CANCELLATION + +!sem_wait! is a cancellation point. + +.SH "ASYNC-SIGNAL SAFETY" + +On processors supporting atomic compare-and-swap (Intel 486, Pentium +and later, Alpha, PowerPC, MIPS II, Motorola 68k), the !sem_post! +function is async-signal safe and can therefore be +called from signal handlers. This is the only thread synchronization +function provided by POSIX threads that is async-signal safe. + +On the Intel 386 and the Sparc, the current LinuxThreads +implementation of !sem_post! is not async-signal safe by lack of the +required atomic operations. + +.SH "RETURN VALUE" + +The !sem_wait! and !sem_getvalue! functions always return 0. +All other semaphore functions return 0 on success and -1 on error, in +addition to writing an error code in !errno!. + +.SH ERRORS + +The !sem_init! function sets !errno! to the following codes on error: +.RS +.TP +!EINVAL! +|value| exceeds the maximal counter value !SEM_VALUE_MAX! +.TP +!ENOSYS! +|pshared| is not zero +.RE + +The !sem_trywait! function sets !errno! to the following error code on error: +.RS +.TP +!EAGAIN! +the semaphore count is currently 0 +.RE + +The !sem_post! function sets !errno! to the following error code on error: +.RS +.TP +!ERANGE! +after incrementation, the semaphore value would exceed !SEM_VALUE_MAX! +(the semaphore count is left unchanged in this case) +.RE + +The !sem_destroy! function sets !errno! to the following error code on error: +.RS +.TP +!EBUSY! +some threads are currently blocked waiting on the semaphore. +.RE + +.SH AUTHOR +Xavier Leroy <Xavier.Leroy@inria.fr> + +.SH "SEE ALSO" +!pthread_mutex_init!(3), +!pthread_cond_init!(3), +!pthread_cancel!(3), +!ipc!(5). + diff --git a/linuxthreads/man/troffprepro b/linuxthreads/man/troffprepro new file mode 100755 index 0000000000..ba564fefbe --- /dev/null +++ b/linuxthreads/man/troffprepro @@ -0,0 +1,68 @@ +#!/usr/local/bin/perl + +$insynopsis = 0; + +open(INPUT, $ARGV[0]) || die("cannot open $ARGV[0]"); +open(OUTPUT, "> $ARGV[1]") || die("cannot create $ARGV[1]"); + +select(OUTPUT); + +line: +while(<INPUT>) { + if (/^\.XREF (.*)$/) { + $xref = $1; + $_ = $ARGV[1]; + m/^.*\.(([1-8]).*)$/; + $suffix = $1; + $extension = $2; + open(XREF, "> $xref.$suffix"); + print XREF ".so man$extension/$ARGV[1]\n"; + close(XREF); + next line; + } + if (/^\.SH/) { + $insynopsis = /SYNOPSIS/; + print $_; + next; + } + if ($insynopsis) { + if (/^#/) { + print ".B ", $_; + } + elsif (/^[a-z]/) { + chop; +# if (m/^([a-zA-Z][a-zA-Z0-9_]*\s+[a-zA-Z][a-zA-Z0-9_]*)\(/) { +# print ".B \"", $1, "\"\n"; +# $_ = '(' . $'; +# } +# s/([a-zA-Z][a-zA-Z0-9_]*)(\s*[,()=])/" \1 "\2/g; + s/([ *])([a-zA-Z][a-zA-Z0-9_]*)(\s*[,)=])/\1" \2 "\3/g; + print ".BI \"", $_, "\"\n"; + } + else { + print $_; + } + next; + } + chop; + s/!([^!]+)!\|([^|]+)\|([^\s]*)\s*/\n.BI "\1" "\2\3"\n/g; + s/([!|])([^!|]+)\1([^\s]*)\s*/do subst($1,$2,$3)/eg; + s/^\n+//; + s/\n+$//; + s/\n\n+/\n/g; + print $_, "\n"; +} + +close(INPUT); +close(OUTPUT); + +sub subst { + local ($a, $b, $c) = @_; + if ($c) { + "\n" . ($a eq "!" ? ".BR " : ".IR ") . "\"$b\" $c\n" + } else { + "\n" . ($a eq "!" ? ".B " : ".I ") . "\"$b\"\n" + } +} + + diff --git a/linuxthreads/manager.c b/linuxthreads/manager.c new file mode 100644 index 0000000000..f21a6def6f --- /dev/null +++ b/linuxthreads/manager.c @@ -0,0 +1,1112 @@ +/* Linuxthreads - a simple clone()-based implementation of Posix */ +/* threads for Linux. */ +/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ +/* */ +/* This program is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public License */ +/* as published by the Free Software Foundation; either version 2 */ +/* of the License, or (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Library General Public License for more details. */ + +/* The "thread manager" thread: manages creation and termination of threads */ + +#include <assert.h> +#include <errno.h> +#include <sched.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/poll.h> /* for poll */ +#include <sys/mman.h> /* for mmap */ +#include <sys/param.h> +#include <sys/time.h> +#include <sys/wait.h> /* for waitpid macros */ +#include <locale.h> /* for __uselocale */ +#include <resolv.h> /* for __resp */ + +#include <ldsodefs.h> +#include "pthread.h" +#include "internals.h" +#include "spinlock.h" +#include "restart.h" +#include "semaphore.h" +#include <not-cancel.h> + +/* For debugging purposes put the maximum number of threads in a variable. */ +const int __linuxthreads_pthread_threads_max = PTHREAD_THREADS_MAX; + +#ifndef THREAD_SELF +/* Indicate whether at least one thread has a user-defined stack (if 1), + or if all threads have stacks supplied by LinuxThreads (if 0). */ +int __pthread_nonstandard_stacks; +#endif + +/* Number of active entries in __pthread_handles (used by gdb) */ +volatile int __pthread_handles_num = 2; + +/* Whether to use debugger additional actions for thread creation + (set to 1 by gdb) */ +volatile int __pthread_threads_debug; + +/* Globally enabled events. */ +volatile td_thr_events_t __pthread_threads_events; + +/* Pointer to thread descriptor with last event. */ +volatile pthread_descr __pthread_last_event; + +static pthread_descr manager_thread; + +/* Mapping from stack segment to thread descriptor. */ +/* Stack segment numbers are also indices into the __pthread_handles array. */ +/* Stack segment number 0 is reserved for the initial thread. */ + +#if FLOATING_STACKS +# define thread_segment(seq) NULL +#else +static inline pthread_descr thread_segment(int seg) +{ +# ifdef _STACK_GROWS_UP + return (pthread_descr)(THREAD_STACK_START_ADDRESS + (seg - 1) * STACK_SIZE) + + 1; +# else + return (pthread_descr)(THREAD_STACK_START_ADDRESS - (seg - 1) * STACK_SIZE) + - 1; +# endif +} +#endif + +/* Flag set in signal handler to record child termination */ + +static volatile int terminated_children; + +/* Flag set when the initial thread is blocked on pthread_exit waiting + for all other threads to terminate */ + +static int main_thread_exiting; + +/* Counter used to generate unique thread identifier. + Thread identifier is pthread_threads_counter + segment. */ + +static pthread_t pthread_threads_counter; + +/* Forward declarations */ + +static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr, + void * (*start_routine)(void *), void *arg, + sigset_t *mask, int father_pid, + int report_events, + td_thr_events_t *event_maskp); +static void pthread_handle_free(pthread_t th_id); +static void pthread_handle_exit(pthread_descr issuing_thread, int exitcode) + __attribute__ ((noreturn)); +static void pthread_reap_children(void); +static void pthread_kill_all_threads(int sig, int main_thread_also); +static void pthread_for_each_thread(void *arg, + void (*fn)(void *, pthread_descr)); + +/* The server thread managing requests for thread creation and termination */ + +int +__attribute__ ((noreturn)) +__pthread_manager(void *arg) +{ + pthread_descr self = manager_thread = arg; + int reqfd = __pthread_manager_reader; + struct pollfd ufd; + sigset_t manager_mask; + int n; + struct pthread_request request; + + /* If we have special thread_self processing, initialize it. */ +#ifdef INIT_THREAD_SELF + INIT_THREAD_SELF(self, 1); +#endif +#if !(USE_TLS && HAVE___THREAD) + /* Set the error variable. */ + self->p_errnop = &self->p_errno; + self->p_h_errnop = &self->p_h_errno; +#endif + /* Block all signals except __pthread_sig_cancel and SIGTRAP */ + sigfillset(&manager_mask); + sigdelset(&manager_mask, __pthread_sig_cancel); /* for thread termination */ + sigdelset(&manager_mask, SIGTRAP); /* for debugging purposes */ + if (__pthread_threads_debug && __pthread_sig_debug > 0) + sigdelset(&manager_mask, __pthread_sig_debug); + sigprocmask(SIG_SETMASK, &manager_mask, NULL); + /* Raise our priority to match that of main thread */ + __pthread_manager_adjust_prio(__pthread_main_thread->p_priority); + /* Synchronize debugging of the thread manager */ + n = TEMP_FAILURE_RETRY(read_not_cancel(reqfd, (char *)&request, + sizeof(request))); + ASSERT(n == sizeof(request) && request.req_kind == REQ_DEBUG); + ufd.fd = reqfd; + ufd.events = POLLIN; + /* Enter server loop */ + while(1) { + n = __poll(&ufd, 1, 2000); + + /* Check for termination of the main thread */ + if (getppid() == 1) { + pthread_kill_all_threads(SIGKILL, 0); + _exit(0); + } + /* Check for dead children */ + if (terminated_children) { + terminated_children = 0; + pthread_reap_children(); + } + /* Read and execute request */ + if (n == 1 && (ufd.revents & POLLIN)) { + n = TEMP_FAILURE_RETRY(read_not_cancel(reqfd, (char *)&request, + sizeof(request))); +#ifdef DEBUG + if (n < 0) { + char d[64]; + write(STDERR_FILENO, d, snprintf(d, sizeof(d), "*** read err %m\n")); + } else if (n != sizeof(request)) { + write(STDERR_FILENO, "*** short read in manager\n", 26); + } +#endif + + switch(request.req_kind) { + case REQ_CREATE: + request.req_thread->p_retcode = + pthread_handle_create((pthread_t *) &request.req_thread->p_retval, + request.req_args.create.attr, + request.req_args.create.fn, + request.req_args.create.arg, + &request.req_args.create.mask, + request.req_thread->p_pid, + request.req_thread->p_report_events, + &request.req_thread->p_eventbuf.eventmask); + restart(request.req_thread); + break; + case REQ_FREE: + pthread_handle_free(request.req_args.free.thread_id); + break; + case REQ_PROCESS_EXIT: + pthread_handle_exit(request.req_thread, + request.req_args.exit.code); + /* NOTREACHED */ + break; + case REQ_MAIN_THREAD_EXIT: + main_thread_exiting = 1; + /* Reap children in case all other threads died and the signal handler + went off before we set main_thread_exiting to 1, and therefore did + not do REQ_KICK. */ + pthread_reap_children(); + + if (__pthread_main_thread->p_nextlive == __pthread_main_thread) { + restart(__pthread_main_thread); + /* The main thread will now call exit() which will trigger an + __on_exit handler, which in turn will send REQ_PROCESS_EXIT + to the thread manager. In case you are wondering how the + manager terminates from its loop here. */ + } + break; + case REQ_POST: + __new_sem_post(request.req_args.post); + break; + case REQ_DEBUG: + /* Make gdb aware of new thread and gdb will restart the + new thread when it is ready to handle the new thread. */ + if (__pthread_threads_debug && __pthread_sig_debug > 0) + raise(__pthread_sig_debug); + break; + case REQ_KICK: + /* This is just a prod to get the manager to reap some + threads right away, avoiding a potential delay at shutdown. */ + break; + case REQ_FOR_EACH_THREAD: + pthread_for_each_thread(request.req_args.for_each.arg, + request.req_args.for_each.fn); + restart(request.req_thread); + break; + } + } + } +} + +int __pthread_manager_event(void *arg) +{ + pthread_descr self = arg; + /* If we have special thread_self processing, initialize it. */ +#ifdef INIT_THREAD_SELF + INIT_THREAD_SELF(self, 1); +#endif + + /* Get the lock the manager will free once all is correctly set up. */ + __pthread_lock (THREAD_GETMEM(self, p_lock), NULL); + /* Free it immediately. */ + __pthread_unlock (THREAD_GETMEM(self, p_lock)); + + return __pthread_manager(arg); +} + +/* Process creation */ + +static int +__attribute__ ((noreturn)) +pthread_start_thread(void *arg) +{ + pthread_descr self = (pthread_descr) arg; + struct pthread_request request; + void * outcome; +#if HP_TIMING_AVAIL + hp_timing_t tmpclock; +#endif + /* Initialize special thread_self processing, if any. */ +#ifdef INIT_THREAD_SELF + INIT_THREAD_SELF(self, self->p_nr); +#endif +#if HP_TIMING_AVAIL + HP_TIMING_NOW (tmpclock); + THREAD_SETMEM (self, p_cpuclock_offset, tmpclock); +#endif + /* Make sure our pid field is initialized, just in case we get there + before our father has initialized it. */ + THREAD_SETMEM(self, p_pid, __getpid()); + /* Initial signal mask is that of the creating thread. (Otherwise, + we'd just inherit the mask of the thread manager.) */ + sigprocmask(SIG_SETMASK, &self->p_start_args.mask, NULL); + /* Set the scheduling policy and priority for the new thread, if needed */ + if (THREAD_GETMEM(self, p_start_args.schedpolicy) >= 0) + /* Explicit scheduling attributes were provided: apply them */ + __sched_setscheduler(THREAD_GETMEM(self, p_pid), + THREAD_GETMEM(self, p_start_args.schedpolicy), + &self->p_start_args.schedparam); + else if (manager_thread->p_priority > 0) + /* Default scheduling required, but thread manager runs in realtime + scheduling: switch new thread to SCHED_OTHER policy */ + { + struct sched_param default_params; + default_params.sched_priority = 0; + __sched_setscheduler(THREAD_GETMEM(self, p_pid), + SCHED_OTHER, &default_params); + } +#if !(USE_TLS && HAVE___THREAD) + /* Initialize thread-locale current locale to point to the global one. + With __thread support, the variable's initializer takes care of this. */ + __uselocale (LC_GLOBAL_LOCALE); +#else + /* Initialize __resp. */ + __resp = &self->p_res; +#endif + /* Make gdb aware of new thread */ + if (__pthread_threads_debug && __pthread_sig_debug > 0) { + request.req_thread = self; + request.req_kind = REQ_DEBUG; + TEMP_FAILURE_RETRY(write_not_cancel(__pthread_manager_request, + (char *) &request, sizeof(request))); + suspend(self); + } + /* Run the thread code */ + outcome = self->p_start_args.start_routine(THREAD_GETMEM(self, + p_start_args.arg)); + /* Exit with the given return value */ + __pthread_do_exit(outcome, CURRENT_STACK_FRAME); +} + +static int +__attribute__ ((noreturn)) +pthread_start_thread_event(void *arg) +{ + pthread_descr self = (pthread_descr) arg; + +#ifdef INIT_THREAD_SELF + INIT_THREAD_SELF(self, self->p_nr); +#endif + /* Make sure our pid field is initialized, just in case we get there + before our father has initialized it. */ + THREAD_SETMEM(self, p_pid, __getpid()); + /* Get the lock the manager will free once all is correctly set up. */ + __pthread_lock (THREAD_GETMEM(self, p_lock), NULL); + /* Free it immediately. */ + __pthread_unlock (THREAD_GETMEM(self, p_lock)); + + /* Continue with the real function. */ + pthread_start_thread (arg); +} + +#if defined USE_TLS && !FLOATING_STACKS +# error "TLS can only work with floating stacks" +#endif + +static int pthread_allocate_stack(const pthread_attr_t *attr, + pthread_descr default_new_thread, + int pagesize, + char ** out_new_thread, + char ** out_new_thread_bottom, + char ** out_guardaddr, + size_t * out_guardsize, + size_t * out_stacksize) +{ + pthread_descr new_thread; + char * new_thread_bottom; + char * guardaddr; + size_t stacksize, guardsize; + +#ifdef USE_TLS + /* TLS cannot work with fixed thread descriptor addresses. */ + assert (default_new_thread == NULL); +#endif + + if (attr != NULL && attr->__stackaddr_set) + { +#ifdef _STACK_GROWS_UP + /* The user provided a stack. */ +# ifdef USE_TLS + /* This value is not needed. */ + new_thread = (pthread_descr) attr->__stackaddr; + new_thread_bottom = (char *) new_thread; +# else + new_thread = (pthread_descr) attr->__stackaddr; + new_thread_bottom = (char *) (new_thread + 1); +# endif + guardaddr = attr->__stackaddr + attr->__stacksize; + guardsize = 0; +#else + /* The user provided a stack. For now we interpret the supplied + address as 1 + the highest addr. in the stack segment. If a + separate register stack is needed, we place it at the low end + of the segment, relying on the associated stacksize to + determine the low end of the segment. This differs from many + (but not all) other pthreads implementations. The intent is + that on machines with a single stack growing toward higher + addresses, stackaddr would be the lowest address in the stack + segment, so that it is consistently close to the initial sp + value. */ +# ifdef USE_TLS + new_thread = (pthread_descr) attr->__stackaddr; +# else + new_thread = + (pthread_descr) ((long)(attr->__stackaddr) & -sizeof(void *)) - 1; +# endif + new_thread_bottom = (char *) attr->__stackaddr - attr->__stacksize; + guardaddr = new_thread_bottom; + guardsize = 0; +#endif +#ifndef THREAD_SELF + __pthread_nonstandard_stacks = 1; +#endif +#ifndef USE_TLS + /* Clear the thread data structure. */ + memset (new_thread, '\0', sizeof (*new_thread)); +#endif + stacksize = attr->__stacksize; + } + else + { +#ifdef NEED_SEPARATE_REGISTER_STACK + const size_t granularity = 2 * pagesize; + /* Try to make stacksize/2 a multiple of pagesize */ +#else + const size_t granularity = pagesize; +#endif + void *map_addr; + + /* Allocate space for stack and thread descriptor at default address */ +#if FLOATING_STACKS + if (attr != NULL) + { + guardsize = page_roundup (attr->__guardsize, granularity); + stacksize = __pthread_max_stacksize - guardsize; + stacksize = MIN (stacksize, + page_roundup (attr->__stacksize, granularity)); + } + else + { + guardsize = granularity; + stacksize = __pthread_max_stacksize - guardsize; + } + + map_addr = mmap(NULL, stacksize + guardsize, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (map_addr == MAP_FAILED) + /* No more memory available. */ + return -1; + +# ifdef NEED_SEPARATE_REGISTER_STACK + guardaddr = map_addr + stacksize / 2; + if (guardsize > 0) + mprotect (guardaddr, guardsize, PROT_NONE); + + new_thread_bottom = (char *) map_addr; +# ifdef USE_TLS + new_thread = ((pthread_descr) (new_thread_bottom + stacksize + + guardsize)); +# else + new_thread = ((pthread_descr) (new_thread_bottom + stacksize + + guardsize)) - 1; +# endif +# elif _STACK_GROWS_DOWN + guardaddr = map_addr; + if (guardsize > 0) + mprotect (guardaddr, guardsize, PROT_NONE); + + new_thread_bottom = (char *) map_addr + guardsize; +# ifdef USE_TLS + new_thread = ((pthread_descr) (new_thread_bottom + stacksize)); +# else + new_thread = ((pthread_descr) (new_thread_bottom + stacksize)) - 1; +# endif +# elif _STACK_GROWS_UP + guardaddr = map_addr + stacksize; + if (guardsize > 0) + mprotect (guardaddr, guardsize, PROT_NONE); + + new_thread = (pthread_descr) map_addr; +# ifdef USE_TLS + new_thread_bottom = (char *) new_thread; +# else + new_thread_bottom = (char *) (new_thread + 1); +# endif +# else +# error You must define a stack direction +# endif /* Stack direction */ +#else /* !FLOATING_STACKS */ + void *res_addr; + + if (attr != NULL) + { + guardsize = page_roundup (attr->__guardsize, granularity); + stacksize = STACK_SIZE - guardsize; + stacksize = MIN (stacksize, + page_roundup (attr->__stacksize, granularity)); + } + else + { + guardsize = granularity; + stacksize = STACK_SIZE - granularity; + } + +# ifdef NEED_SEPARATE_REGISTER_STACK + new_thread = default_new_thread; + new_thread_bottom = (char *) (new_thread + 1) - stacksize - guardsize; + /* Includes guard area, unlike the normal case. Use the bottom + end of the segment as backing store for the register stack. + Needed on IA64. In this case, we also map the entire stack at + once. According to David Mosberger, that's cheaper. It also + avoids the risk of intermittent failures due to other mappings + in the same region. The cost is that we might be able to map + slightly fewer stacks. */ + + /* First the main stack: */ + map_addr = (caddr_t)((char *)(new_thread + 1) - stacksize / 2); + res_addr = mmap(map_addr, stacksize / 2, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (res_addr != map_addr) + { + /* Bad luck, this segment is already mapped. */ + if (res_addr != MAP_FAILED) + munmap(res_addr, stacksize / 2); + return -1; + } + /* Then the register stack: */ + map_addr = (caddr_t)new_thread_bottom; + res_addr = mmap(map_addr, stacksize/2, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (res_addr != map_addr) + { + if (res_addr != MAP_FAILED) + munmap(res_addr, stacksize / 2); + munmap((caddr_t)((char *)(new_thread + 1) - stacksize/2), + stacksize/2); + return -1; + } + + guardaddr = new_thread_bottom + stacksize/2; + /* We leave the guard area in the middle unmapped. */ +# else /* !NEED_SEPARATE_REGISTER_STACK */ +# ifdef _STACK_GROWS_DOWN + new_thread = default_new_thread; + new_thread_bottom = (char *) (new_thread + 1) - stacksize; + map_addr = new_thread_bottom - guardsize; + res_addr = mmap(map_addr, stacksize + guardsize, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (res_addr != map_addr) + { + /* Bad luck, this segment is already mapped. */ + if (res_addr != MAP_FAILED) + munmap (res_addr, stacksize + guardsize); + return -1; + } + + /* We manage to get a stack. Protect the guard area pages if + necessary. */ + guardaddr = map_addr; + if (guardsize > 0) + mprotect (guardaddr, guardsize, PROT_NONE); +# else + /* The thread description goes at the bottom of this area, and + * the stack starts directly above it. + */ + new_thread = (pthread_descr)((unsigned long)default_new_thread &~ (STACK_SIZE - 1)); + map_addr = mmap(new_thread, stacksize + guardsize, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (map_addr == MAP_FAILED) + return -1; + + new_thread_bottom = map_addr + sizeof(*new_thread); + guardaddr = map_addr + stacksize; + if (guardsize > 0) + mprotect (guardaddr, guardsize, PROT_NONE); + +# endif /* stack direction */ +# endif /* !NEED_SEPARATE_REGISTER_STACK */ +#endif /* !FLOATING_STACKS */ + } + *out_new_thread = (char *) new_thread; + *out_new_thread_bottom = new_thread_bottom; + *out_guardaddr = guardaddr; + *out_guardsize = guardsize; +#ifdef NEED_SEPARATE_REGISTER_STACK + *out_stacksize = stacksize / 2; +#else + *out_stacksize = stacksize; +#endif + return 0; +} + +static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr, + void * (*start_routine)(void *), void *arg, + sigset_t * mask, int father_pid, + int report_events, + td_thr_events_t *event_maskp) +{ + size_t sseg; + int pid; + pthread_descr new_thread; + char *stack_addr; + char * new_thread_bottom; + pthread_t new_thread_id; + char *guardaddr = NULL; + size_t guardsize = 0, stksize = 0; + int pagesize = __getpagesize(); + int saved_errno = 0; + +#ifdef USE_TLS + new_thread = _dl_allocate_tls (NULL); + if (new_thread == NULL) + return EAGAIN; +# if TLS_DTV_AT_TP + /* pthread_descr is below TP. */ + new_thread = (pthread_descr) ((char *) new_thread - TLS_PRE_TCB_SIZE); +# endif +#else + /* Prevent warnings. */ + new_thread = NULL; +#endif + + /* First check whether we have to change the policy and if yes, whether + we can do this. Normally this should be done by examining the + return value of the __sched_setscheduler call in pthread_start_thread + but this is hard to implement. FIXME */ + if (attr != NULL && attr->__schedpolicy != SCHED_OTHER && geteuid () != 0) + return EPERM; + /* Find a free segment for the thread, and allocate a stack if needed */ + for (sseg = 2; ; sseg++) + { + if (sseg >= PTHREAD_THREADS_MAX) + { +#ifdef USE_TLS +# if TLS_DTV_AT_TP + new_thread = (pthread_descr) ((char *) new_thread + TLS_PRE_TCB_SIZE); +# endif + _dl_deallocate_tls (new_thread, true); +#endif + return EAGAIN; + } + if (__pthread_handles[sseg].h_descr != NULL) + continue; + if (pthread_allocate_stack(attr, thread_segment(sseg), + pagesize, &stack_addr, &new_thread_bottom, + &guardaddr, &guardsize, &stksize) == 0) + { +#ifdef USE_TLS + new_thread->p_stackaddr = stack_addr; +#else + new_thread = (pthread_descr) stack_addr; +#endif + break; + } + } + __pthread_handles_num++; + /* Allocate new thread identifier */ + pthread_threads_counter += PTHREAD_THREADS_MAX; + new_thread_id = sseg + pthread_threads_counter; + /* Initialize the thread descriptor. Elements which have to be + initialized to zero already have this value. */ +#if !defined USE_TLS || !TLS_DTV_AT_TP + new_thread->p_header.data.tcb = new_thread; + new_thread->p_header.data.self = new_thread; +#endif +#if TLS_MULTIPLE_THREADS_IN_TCB || !defined USE_TLS || !TLS_DTV_AT_TP + new_thread->p_multiple_threads = 1; +#endif + new_thread->p_tid = new_thread_id; + new_thread->p_lock = &(__pthread_handles[sseg].h_lock); + new_thread->p_cancelstate = PTHREAD_CANCEL_ENABLE; + new_thread->p_canceltype = PTHREAD_CANCEL_DEFERRED; +#if !(USE_TLS && HAVE___THREAD) + new_thread->p_errnop = &new_thread->p_errno; + new_thread->p_h_errnop = &new_thread->p_h_errno; + new_thread->p_resp = &new_thread->p_res; +#endif + new_thread->p_guardaddr = guardaddr; + new_thread->p_guardsize = guardsize; + new_thread->p_nr = sseg; + new_thread->p_inheritsched = attr ? attr->__inheritsched : 0; + new_thread->p_alloca_cutoff = stksize / 4 > __MAX_ALLOCA_CUTOFF + ? __MAX_ALLOCA_CUTOFF : stksize / 4; + /* Initialize the thread handle */ + __pthread_init_lock(&__pthread_handles[sseg].h_lock); + __pthread_handles[sseg].h_descr = new_thread; + __pthread_handles[sseg].h_bottom = new_thread_bottom; + /* Determine scheduling parameters for the thread */ + new_thread->p_start_args.schedpolicy = -1; + if (attr != NULL) { + new_thread->p_detached = attr->__detachstate; + new_thread->p_userstack = attr->__stackaddr_set; + + switch(attr->__inheritsched) { + case PTHREAD_EXPLICIT_SCHED: + new_thread->p_start_args.schedpolicy = attr->__schedpolicy; + memcpy (&new_thread->p_start_args.schedparam, &attr->__schedparam, + sizeof (struct sched_param)); + break; + case PTHREAD_INHERIT_SCHED: + new_thread->p_start_args.schedpolicy = __sched_getscheduler(father_pid); + __sched_getparam(father_pid, &new_thread->p_start_args.schedparam); + break; + } + new_thread->p_priority = + new_thread->p_start_args.schedparam.sched_priority; + } + /* Finish setting up arguments to pthread_start_thread */ + new_thread->p_start_args.start_routine = start_routine; + new_thread->p_start_args.arg = arg; + new_thread->p_start_args.mask = *mask; + /* Make the new thread ID available already now. If any of the later + functions fail we return an error value and the caller must not use + the stored thread ID. */ + *thread = new_thread_id; + /* Raise priority of thread manager if needed */ + __pthread_manager_adjust_prio(new_thread->p_priority); + /* Do the cloning. We have to use two different functions depending + on whether we are debugging or not. */ + pid = 0; /* Note that the thread never can have PID zero. */ + if (report_events) + { + /* See whether the TD_CREATE event bit is set in any of the + masks. */ + int idx = __td_eventword (TD_CREATE); + uint32_t mask = __td_eventmask (TD_CREATE); + + if ((mask & (__pthread_threads_events.event_bits[idx] + | event_maskp->event_bits[idx])) != 0) + { + /* Lock the mutex the child will use now so that it will stop. */ + __pthread_lock(new_thread->p_lock, NULL); + + /* We have to report this event. */ +#ifdef NEED_SEPARATE_REGISTER_STACK + /* Perhaps this version should be used on all platforms. But + this requires that __clone2 be uniformly supported + everywhere. + + And there is some argument for changing the __clone2 + interface to pass sp and bsp instead, making it more IA64 + specific, but allowing stacks to grow outward from each + other, to get less paging and fewer mmaps. */ + pid = __clone2(pthread_start_thread_event, + (void **)new_thread_bottom, + (char *)stack_addr - new_thread_bottom, + CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | + __pthread_sig_cancel, new_thread); +#elif _STACK_GROWS_UP + pid = __clone(pthread_start_thread_event, (void *) new_thread_bottom, + CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | + __pthread_sig_cancel, new_thread); +#else + pid = __clone(pthread_start_thread_event, stack_addr, + CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | + __pthread_sig_cancel, new_thread); +#endif + saved_errno = errno; + if (pid != -1) + { + /* 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. */ + new_thread->p_eventbuf.eventdata = new_thread; + new_thread->p_eventbuf.eventnum = TD_CREATE; + __pthread_last_event = new_thread; + + /* We have to set the PID here since the callback function + in the debug library will need it and we cannot guarantee + the child got scheduled before the debugger. */ + new_thread->p_pid = pid; + + /* Now call the function which signals the event. */ + __linuxthreads_create_event (); + + /* Now restart the thread. */ + __pthread_unlock(new_thread->p_lock); + } + } + } + if (pid == 0) + { +#ifdef NEED_SEPARATE_REGISTER_STACK + pid = __clone2(pthread_start_thread, + (void **)new_thread_bottom, + (char *)stack_addr - new_thread_bottom, + CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | + __pthread_sig_cancel, new_thread); +#elif _STACK_GROWS_UP + pid = __clone(pthread_start_thread, (void *) new_thread_bottom, + CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | + __pthread_sig_cancel, new_thread); +#else + pid = __clone(pthread_start_thread, stack_addr, + CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | + __pthread_sig_cancel, new_thread); +#endif /* !NEED_SEPARATE_REGISTER_STACK */ + saved_errno = errno; + } + /* Check if cloning succeeded */ + if (pid == -1) { + /* Free the stack if we allocated it */ + if (attr == NULL || !attr->__stackaddr_set) + { +#ifdef NEED_SEPARATE_REGISTER_STACK + size_t stacksize = ((char *)(new_thread->p_guardaddr) + - new_thread_bottom); + munmap((caddr_t)new_thread_bottom, + 2 * stacksize + new_thread->p_guardsize); +#elif _STACK_GROWS_UP +# ifdef USE_TLS + size_t stacksize = guardaddr - stack_addr; + munmap(stack_addr, stacksize + guardsize); +# else + size_t stacksize = guardaddr - (char *)new_thread; + munmap(new_thread, stacksize + guardsize); +# endif +#else +# ifdef USE_TLS + size_t stacksize = stack_addr - new_thread_bottom; +# else + size_t stacksize = (char *)(new_thread+1) - new_thread_bottom; +# endif + munmap(new_thread_bottom - guardsize, guardsize + stacksize); +#endif + } +#ifdef USE_TLS +# if TLS_DTV_AT_TP + new_thread = (pthread_descr) ((char *) new_thread + TLS_PRE_TCB_SIZE); +# endif + _dl_deallocate_tls (new_thread, true); +#endif + __pthread_handles[sseg].h_descr = NULL; + __pthread_handles[sseg].h_bottom = NULL; + __pthread_handles_num--; + return saved_errno; + } + /* Insert new thread in doubly linked list of active threads */ + new_thread->p_prevlive = __pthread_main_thread; + new_thread->p_nextlive = __pthread_main_thread->p_nextlive; + __pthread_main_thread->p_nextlive->p_prevlive = new_thread; + __pthread_main_thread->p_nextlive = new_thread; + /* Set pid field of the new thread, in case we get there before the + child starts. */ + new_thread->p_pid = pid; + return 0; +} + + +/* Try to free the resources of a thread when requested by pthread_join + or pthread_detach on a terminated thread. */ + +static void pthread_free(pthread_descr th) +{ + pthread_handle handle; + pthread_readlock_info *iter, *next; + + ASSERT(th->p_exited); + /* Make the handle invalid */ + handle = thread_handle(th->p_tid); + __pthread_lock(&handle->h_lock, NULL); + handle->h_descr = NULL; + handle->h_bottom = (char *)(-1L); + __pthread_unlock(&handle->h_lock); +#ifdef FREE_THREAD + FREE_THREAD(th, th->p_nr); +#endif + /* One fewer threads in __pthread_handles */ + __pthread_handles_num--; + + /* Destroy read lock list, and list of free read lock structures. + If the former is not empty, it means the thread exited while + holding read locks! */ + + for (iter = th->p_readlock_list; iter != NULL; iter = next) + { + next = iter->pr_next; + free(iter); + } + + for (iter = th->p_readlock_free; iter != NULL; iter = next) + { + next = iter->pr_next; + free(iter); + } + + /* If initial thread, nothing to free */ + if (!th->p_userstack) + { + size_t guardsize = th->p_guardsize; + /* Free the stack and thread descriptor area */ + char *guardaddr = th->p_guardaddr; +#ifdef _STACK_GROWS_UP +# ifdef USE_TLS + size_t stacksize = guardaddr - th->p_stackaddr; +# else + size_t stacksize = guardaddr - (char *)th; +# endif + guardaddr = (char *)th; +#else + /* Guardaddr is always set, even if guardsize is 0. This allows + us to compute everything else. */ +# ifdef USE_TLS + size_t stacksize = th->p_stackaddr - guardaddr - guardsize; +# else + size_t stacksize = (char *)(th+1) - guardaddr - guardsize; +# endif +# ifdef NEED_SEPARATE_REGISTER_STACK + /* Take account of the register stack, which is below guardaddr. */ + guardaddr -= stacksize; + stacksize *= 2; +# endif +#endif + /* Unmap the stack. */ + munmap(guardaddr, stacksize + guardsize); + + } + +#ifdef USE_TLS +# if TLS_DTV_AT_TP + th = (pthread_descr) ((char *) th + TLS_PRE_TCB_SIZE); +# endif + _dl_deallocate_tls (th, true); +#endif +} + +/* Handle threads that have exited */ + +static void pthread_exited(pid_t pid) +{ + pthread_descr th; + int detached; + /* Find thread with that pid */ + for (th = __pthread_main_thread->p_nextlive; + th != __pthread_main_thread; + th = th->p_nextlive) { + if (th->p_pid == pid) { + /* Remove thread from list of active threads */ + th->p_nextlive->p_prevlive = th->p_prevlive; + th->p_prevlive->p_nextlive = th->p_nextlive; + /* Mark thread as exited, and if detached, free its resources */ + __pthread_lock(th->p_lock, NULL); + th->p_exited = 1; + /* If we have to signal this event do it now. */ + if (th->p_report_events) + { + /* See whether TD_REAP is in any of the mask. */ + int idx = __td_eventword (TD_REAP); + uint32_t mask = __td_eventmask (TD_REAP); + + if ((mask & (__pthread_threads_events.event_bits[idx] + | th->p_eventbuf.eventmask.event_bits[idx])) != 0) + { + /* Yep, we have to signal the reapage. */ + th->p_eventbuf.eventnum = TD_REAP; + th->p_eventbuf.eventdata = th; + __pthread_last_event = th; + + /* Now call the function to signal the event. */ + __linuxthreads_reap_event(); + } + } + detached = th->p_detached; + __pthread_unlock(th->p_lock); + if (detached) + pthread_free(th); + break; + } + } + /* If all threads have exited and the main thread is pending on a + pthread_exit, wake up the main thread and terminate ourselves. */ + if (main_thread_exiting && + __pthread_main_thread->p_nextlive == __pthread_main_thread) { + restart(__pthread_main_thread); + /* Same logic as REQ_MAIN_THREAD_EXIT. */ + } +} + +static void pthread_reap_children(void) +{ + pid_t pid; + int status; + + while ((pid = waitpid_not_cancel(-1, &status, WNOHANG | __WCLONE)) > 0) { + pthread_exited(pid); + if (WIFSIGNALED(status)) { + /* If a thread died due to a signal, send the same signal to + all other threads, including the main thread. */ + pthread_kill_all_threads(WTERMSIG(status), 1); + _exit(0); + } + } +} + +/* Try to free the resources of a thread when requested by pthread_join + or pthread_detach on a terminated thread. */ + +static void pthread_handle_free(pthread_t th_id) +{ + pthread_handle handle = thread_handle(th_id); + pthread_descr th; + + __pthread_lock(&handle->h_lock, NULL); + if (nonexisting_handle(handle, th_id)) { + /* pthread_reap_children has deallocated the thread already, + nothing needs to be done */ + __pthread_unlock(&handle->h_lock); + return; + } + th = handle->h_descr; + if (th->p_exited) { + __pthread_unlock(&handle->h_lock); + pthread_free(th); + } else { + /* The Unix process of the thread is still running. + Mark the thread as detached so that the thread manager will + deallocate its resources when the Unix process exits. */ + th->p_detached = 1; + __pthread_unlock(&handle->h_lock); + } +} + +/* Send a signal to all running threads */ + +static void pthread_kill_all_threads(int sig, int main_thread_also) +{ + pthread_descr th; + for (th = __pthread_main_thread->p_nextlive; + th != __pthread_main_thread; + th = th->p_nextlive) { + kill(th->p_pid, sig); + } + if (main_thread_also) { + kill(__pthread_main_thread->p_pid, sig); + } +} + +static void pthread_for_each_thread(void *arg, + void (*fn)(void *, pthread_descr)) +{ + pthread_descr th; + + for (th = __pthread_main_thread->p_nextlive; + th != __pthread_main_thread; + th = th->p_nextlive) { + fn(arg, th); + } + + fn(arg, __pthread_main_thread); +} + +/* Process-wide exit() */ + +static void pthread_handle_exit(pthread_descr issuing_thread, int exitcode) +{ + pthread_descr th; + __pthread_exit_requested = 1; + __pthread_exit_code = exitcode; + /* A forced asynchronous cancellation follows. Make sure we won't + get stuck later in the main thread with a system lock being held + by one of the cancelled threads. Ideally one would use the same + code as in pthread_atfork(), but we can't distinguish system and + user handlers there. */ + __flockfilelist(); + /* Send the CANCEL signal to all running threads, including the main + thread, but excluding the thread from which the exit request originated + (that thread must complete the exit, e.g. calling atexit functions + and flushing stdio buffers). */ + for (th = issuing_thread->p_nextlive; + th != issuing_thread; + th = th->p_nextlive) { + kill(th->p_pid, __pthread_sig_cancel); + } + /* Now, wait for all these threads, so that they don't become zombies + and their times are properly added to the thread manager's times. */ + for (th = issuing_thread->p_nextlive; + th != issuing_thread; + th = th->p_nextlive) { + waitpid(th->p_pid, NULL, __WCLONE); + } + __fresetlockfiles(); + restart(issuing_thread); + _exit(0); +} + +/* Handler for __pthread_sig_cancel in thread manager thread */ + +void __pthread_manager_sighandler(int sig) +{ + int kick_manager = terminated_children == 0 && main_thread_exiting; + terminated_children = 1; + + /* If the main thread is terminating, kick the thread manager loop + each time some threads terminate. This eliminates a two second + shutdown delay caused by the thread manager sleeping in the + call to __poll(). Instead, the thread manager is kicked into + action, reaps the outstanding threads and resumes the main thread + so that it can complete the shutdown. */ + + if (kick_manager) { + struct pthread_request request; + request.req_thread = 0; + request.req_kind = REQ_KICK; + TEMP_FAILURE_RETRY(write_not_cancel(__pthread_manager_request, + (char *) &request, sizeof(request))); + } +} + +/* Adjust priority of thread manager so that it always run at a priority + higher than all threads */ + +void __pthread_manager_adjust_prio(int thread_prio) +{ + struct sched_param param; + + if (thread_prio <= manager_thread->p_priority) return; + param.sched_priority = + thread_prio < __sched_get_priority_max(SCHED_FIFO) + ? thread_prio + 1 : thread_prio; + __sched_setscheduler(manager_thread->p_pid, SCHED_FIFO, ¶m); + manager_thread->p_priority = thread_prio; +} diff --git a/linuxthreads/mutex.c b/linuxthreads/mutex.c new file mode 100644 index 0000000000..d5f7a335cc --- /dev/null +++ b/linuxthreads/mutex.c @@ -0,0 +1,362 @@ +/* Linuxthreads - a simple clone()-based implementation of Posix */ +/* threads for Linux. */ +/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ +/* */ +/* This program is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public License */ +/* as published by the Free Software Foundation; either version 2 */ +/* of the License, or (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Library General Public License for more details. */ + +/* Mutexes */ + +#include <bits/libc-lock.h> +#include <errno.h> +#include <sched.h> +#include <stddef.h> +#include <limits.h> +#include "pthread.h" +#include "internals.h" +#include "spinlock.h" +#include "queue.h" +#include "restart.h" + +int __pthread_mutex_init(pthread_mutex_t * mutex, + const pthread_mutexattr_t * mutex_attr) +{ + __pthread_init_lock(&mutex->__m_lock); + mutex->__m_kind = + mutex_attr == NULL ? PTHREAD_MUTEX_TIMED_NP : mutex_attr->__mutexkind; + mutex->__m_count = 0; + mutex->__m_owner = NULL; + return 0; +} +strong_alias (__pthread_mutex_init, pthread_mutex_init) +hidden_def (__pthread_mutex_init) + +int __pthread_mutex_destroy(pthread_mutex_t * mutex) +{ + switch (mutex->__m_kind) { + case PTHREAD_MUTEX_ADAPTIVE_NP: + case PTHREAD_MUTEX_RECURSIVE_NP: + if ((mutex->__m_lock.__status & 1) != 0) + return EBUSY; + return 0; + case PTHREAD_MUTEX_ERRORCHECK_NP: + case PTHREAD_MUTEX_TIMED_NP: + if (mutex->__m_lock.__status != 0) + return EBUSY; + return 0; + default: + return EINVAL; + } +} +strong_alias (__pthread_mutex_destroy, pthread_mutex_destroy) +hidden_def (__pthread_mutex_destroy) + +int __pthread_mutex_trylock(pthread_mutex_t * mutex) +{ + pthread_descr self; + int retcode; + + switch(mutex->__m_kind) { + case PTHREAD_MUTEX_ADAPTIVE_NP: + retcode = __pthread_trylock(&mutex->__m_lock); + return retcode; + case PTHREAD_MUTEX_RECURSIVE_NP: + self = thread_self(); + if (mutex->__m_owner == self) { + mutex->__m_count++; + return 0; + } + retcode = __pthread_trylock(&mutex->__m_lock); + if (retcode == 0) { + mutex->__m_owner = self; + mutex->__m_count = 0; + } + return retcode; + case PTHREAD_MUTEX_ERRORCHECK_NP: + retcode = __pthread_alt_trylock(&mutex->__m_lock); + if (retcode == 0) { + mutex->__m_owner = thread_self(); + } + return retcode; + case PTHREAD_MUTEX_TIMED_NP: + retcode = __pthread_alt_trylock(&mutex->__m_lock); + return retcode; + default: + return EINVAL; + } +} +strong_alias (__pthread_mutex_trylock, pthread_mutex_trylock) +hidden_def (__pthread_mutex_trylock) + +int __pthread_mutex_lock(pthread_mutex_t * mutex) +{ + pthread_descr self; + + switch(mutex->__m_kind) { + case PTHREAD_MUTEX_ADAPTIVE_NP: + __pthread_lock(&mutex->__m_lock, NULL); + return 0; + case PTHREAD_MUTEX_RECURSIVE_NP: + self = thread_self(); + if (mutex->__m_owner == self) { + mutex->__m_count++; + return 0; + } + __pthread_lock(&mutex->__m_lock, self); + mutex->__m_owner = self; + mutex->__m_count = 0; + return 0; + case PTHREAD_MUTEX_ERRORCHECK_NP: + self = thread_self(); + if (mutex->__m_owner == self) return EDEADLK; + __pthread_alt_lock(&mutex->__m_lock, self); + mutex->__m_owner = self; + return 0; + case PTHREAD_MUTEX_TIMED_NP: + __pthread_alt_lock(&mutex->__m_lock, NULL); + return 0; + default: + return EINVAL; + } +} +strong_alias (__pthread_mutex_lock, pthread_mutex_lock) +hidden_def (__pthread_mutex_lock) + +int __pthread_mutex_timedlock (pthread_mutex_t *mutex, + const struct timespec *abstime) +{ + pthread_descr self; + int res; + + if (__builtin_expect (abstime->tv_nsec, 0) < 0 + || __builtin_expect (abstime->tv_nsec, 0) >= 1000000000) + return EINVAL; + + switch(mutex->__m_kind) { + case PTHREAD_MUTEX_ADAPTIVE_NP: + __pthread_lock(&mutex->__m_lock, NULL); + return 0; + case PTHREAD_MUTEX_RECURSIVE_NP: + self = thread_self(); + if (mutex->__m_owner == self) { + mutex->__m_count++; + return 0; + } + __pthread_lock(&mutex->__m_lock, self); + mutex->__m_owner = self; + mutex->__m_count = 0; + return 0; + case PTHREAD_MUTEX_ERRORCHECK_NP: + self = thread_self(); + if (mutex->__m_owner == self) return EDEADLK; + res = __pthread_alt_timedlock(&mutex->__m_lock, self, abstime); + if (res != 0) + { + mutex->__m_owner = self; + return 0; + } + return ETIMEDOUT; + case PTHREAD_MUTEX_TIMED_NP: + /* Only this type supports timed out lock. */ + return (__pthread_alt_timedlock(&mutex->__m_lock, NULL, abstime) + ? 0 : ETIMEDOUT); + default: + return EINVAL; + } +} +strong_alias (__pthread_mutex_timedlock, pthread_mutex_timedlock) + +int __pthread_mutex_unlock(pthread_mutex_t * mutex) +{ + switch (mutex->__m_kind) { + case PTHREAD_MUTEX_ADAPTIVE_NP: + __pthread_unlock(&mutex->__m_lock); + return 0; + case PTHREAD_MUTEX_RECURSIVE_NP: + if (mutex->__m_owner != thread_self()) + return EPERM; + if (mutex->__m_count > 0) { + mutex->__m_count--; + return 0; + } + mutex->__m_owner = NULL; + __pthread_unlock(&mutex->__m_lock); + return 0; + case PTHREAD_MUTEX_ERRORCHECK_NP: + if (mutex->__m_owner != thread_self() || mutex->__m_lock.__status == 0) + return EPERM; + mutex->__m_owner = NULL; + __pthread_alt_unlock(&mutex->__m_lock); + return 0; + case PTHREAD_MUTEX_TIMED_NP: + __pthread_alt_unlock(&mutex->__m_lock); + return 0; + default: + return EINVAL; + } +} +strong_alias (__pthread_mutex_unlock, pthread_mutex_unlock) +hidden_def (__pthread_mutex_unlock) + +int __pthread_mutexattr_init(pthread_mutexattr_t *attr) +{ + attr->__mutexkind = PTHREAD_MUTEX_TIMED_NP; + return 0; +} +strong_alias (__pthread_mutexattr_init, pthread_mutexattr_init) + +int __pthread_mutexattr_destroy(pthread_mutexattr_t *attr) +{ + return 0; +} +strong_alias (__pthread_mutexattr_destroy, pthread_mutexattr_destroy) + +int __pthread_mutexattr_settype(pthread_mutexattr_t *attr, int kind) +{ + if (kind != PTHREAD_MUTEX_ADAPTIVE_NP + && kind != PTHREAD_MUTEX_RECURSIVE_NP + && kind != PTHREAD_MUTEX_ERRORCHECK_NP + && kind != PTHREAD_MUTEX_TIMED_NP) + return EINVAL; + attr->__mutexkind = kind; + return 0; +} +weak_alias (__pthread_mutexattr_settype, pthread_mutexattr_settype) +strong_alias ( __pthread_mutexattr_settype, __pthread_mutexattr_setkind_np) +weak_alias (__pthread_mutexattr_setkind_np, pthread_mutexattr_setkind_np) + +int __pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *kind) +{ + *kind = attr->__mutexkind; + return 0; +} +weak_alias (__pthread_mutexattr_gettype, pthread_mutexattr_gettype) +strong_alias (__pthread_mutexattr_gettype, __pthread_mutexattr_getkind_np) +weak_alias (__pthread_mutexattr_getkind_np, pthread_mutexattr_getkind_np) + +int __pthread_mutexattr_getpshared (const pthread_mutexattr_t *attr, + int *pshared) +{ + *pshared = PTHREAD_PROCESS_PRIVATE; + return 0; +} +weak_alias (__pthread_mutexattr_getpshared, pthread_mutexattr_getpshared) + +int __pthread_mutexattr_setpshared (pthread_mutexattr_t *attr, int pshared) +{ + if (pshared != PTHREAD_PROCESS_PRIVATE && pshared != PTHREAD_PROCESS_SHARED) + return EINVAL; + + /* For now it is not possible to shared a conditional variable. */ + if (pshared != PTHREAD_PROCESS_PRIVATE) + return ENOSYS; + + return 0; +} +weak_alias (__pthread_mutexattr_setpshared, pthread_mutexattr_setpshared) + +/* Once-only execution */ + +static pthread_mutex_t once_masterlock = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t once_finished = PTHREAD_COND_INITIALIZER; +static int fork_generation = 0; /* Child process increments this after fork. */ + +enum { NEVER = 0, IN_PROGRESS = 1, DONE = 2 }; + +/* If a thread is canceled while calling the init_routine out of + pthread once, this handler will reset the once_control variable + to the NEVER state. */ + +static void pthread_once_cancelhandler(void *arg) +{ + pthread_once_t *once_control = arg; + + pthread_mutex_lock(&once_masterlock); + *once_control = NEVER; + pthread_mutex_unlock(&once_masterlock); + pthread_cond_broadcast(&once_finished); +} + +int __pthread_once(pthread_once_t * once_control, void (*init_routine)(void)) +{ + /* flag for doing the condition broadcast outside of mutex */ + int state_changed; + + /* Test without locking first for speed */ + if (*once_control == DONE) { + READ_MEMORY_BARRIER(); + return 0; + } + /* Lock and test again */ + + state_changed = 0; + + pthread_mutex_lock(&once_masterlock); + + /* If this object was left in an IN_PROGRESS state in a parent + process (indicated by stale generation field), reset it to NEVER. */ + if ((*once_control & 3) == IN_PROGRESS && (*once_control & ~3) != fork_generation) + *once_control = NEVER; + + /* If init_routine is being called from another routine, wait until + it completes. */ + while ((*once_control & 3) == IN_PROGRESS) { + pthread_cond_wait(&once_finished, &once_masterlock); + } + /* Here *once_control is stable and either NEVER or DONE. */ + if (*once_control == NEVER) { + *once_control = IN_PROGRESS | fork_generation; + pthread_mutex_unlock(&once_masterlock); + pthread_cleanup_push(pthread_once_cancelhandler, once_control); + init_routine(); + pthread_cleanup_pop(0); + pthread_mutex_lock(&once_masterlock); + WRITE_MEMORY_BARRIER(); + *once_control = DONE; + state_changed = 1; + } + pthread_mutex_unlock(&once_masterlock); + + if (state_changed) + pthread_cond_broadcast(&once_finished); + + return 0; +} +strong_alias (__pthread_once, pthread_once) + +/* + * Handle the state of the pthread_once mechanism across forks. The + * once_masterlock is acquired in the parent process prior to a fork to ensure + * that no thread is in the critical region protected by the lock. After the + * fork, the lock is released. In the child, the lock and the condition + * variable are simply reset. The child also increments its generation + * counter which lets pthread_once calls detect stale IN_PROGRESS states + * and reset them back to NEVER. + */ + +void __pthread_once_fork_prepare(void) +{ + pthread_mutex_lock(&once_masterlock); +} + +void __pthread_once_fork_parent(void) +{ + pthread_mutex_unlock(&once_masterlock); +} + +void __pthread_once_fork_child(void) +{ + pthread_mutex_init(&once_masterlock, NULL); + pthread_cond_init(&once_finished, NULL); + if (fork_generation <= INT_MAX - 4) + fork_generation += 4; /* leave least significant two bits zero */ + else + fork_generation = 0; +} diff --git a/linuxthreads/old_pthread_atfork.c b/linuxthreads/old_pthread_atfork.c new file mode 100644 index 0000000000..768e6876c4 --- /dev/null +++ b/linuxthreads/old_pthread_atfork.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 <shlib-compat.h> + +#if SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_3) +# define __pthread_atfork __dyn_pthread_atfork +# include "pthread_atfork.c" +# undef __pthread_atfork +compat_symbol (libpthread, __dyn_pthread_atfork, pthread_atfork, GLIBC_2_0); +#endif diff --git a/linuxthreads/oldsemaphore.c b/linuxthreads/oldsemaphore.c new file mode 100644 index 0000000000..d35683b98b --- /dev/null +++ b/linuxthreads/oldsemaphore.c @@ -0,0 +1,241 @@ +/* + * This file contains the old semaphore code that we need to + * preserve for glibc-2.0 backwards compatibility. Port to glibc 2.1 + * done by Cristian Gafton. + */ + +/* Linuxthreads - a simple clone()-based implementation of Posix */ +/* threads for Linux. */ +/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ +/* */ +/* This program is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public License */ +/* as published by the Free Software Foundation; either version 2 */ +/* of the License, or (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Library General Public License for more details. */ + +/* Semaphores a la POSIX 1003.1b */ +#include <shlib-compat.h> +#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_1) + +#include <errno.h> +#include "pthread.h" +#include "internals.h" +#include "spinlock.h" +#include "restart.h" +#include "queue.h" + +typedef struct { + long int sem_status; + int sem_spinlock; +} old_sem_t; + +extern int __old_sem_init (old_sem_t *__sem, int __pshared, unsigned int __value); +extern int __old_sem_wait (old_sem_t *__sem); +extern int __old_sem_trywait (old_sem_t *__sem); +extern int __old_sem_post (old_sem_t *__sem); +extern int __old_sem_getvalue (old_sem_t *__sem, int *__sval); +extern int __old_sem_destroy (old_sem_t *__sem); + +static inline int sem_compare_and_swap(old_sem_t *sem, long oldval, long newval) +{ + return compare_and_swap(&sem->sem_status, oldval, newval, &sem->sem_spinlock); +} + +/* The state of a semaphore is represented by a long int encoding + either the semaphore count if >= 0 and no thread is waiting on it, + or the head of the list of threads waiting for the semaphore. + To distinguish the two cases, we encode the semaphore count N + as 2N+1, so that it has the lowest bit set. + + A sequence of sem_wait operations on a semaphore initialized to N + result in the following successive states: + 2N+1, 2N-1, ..., 3, 1, &first_waiting_thread, &second_waiting_thread, ... +*/ + +static void sem_restart_list(pthread_descr waiting); + +int __old_sem_init(old_sem_t *sem, int pshared, unsigned int value) +{ + if (value > SEM_VALUE_MAX) { + errno = EINVAL; + return -1; + } + if (pshared) { + errno = ENOSYS; + return -1; + } + sem->sem_spinlock = __LT_SPINLOCK_INIT; + sem->sem_status = ((long)value << 1) + 1; + return 0; +} + +/* Function called by pthread_cancel to remove the thread from + waiting inside __old_sem_wait. Here we simply unconditionally + indicate that the thread is to be woken, by returning 1. */ + +static int old_sem_extricate_func(void *obj, pthread_descr th) +{ + return 1; +} + +int __old_sem_wait(old_sem_t * sem) +{ + long oldstatus, newstatus; + volatile pthread_descr self = thread_self(); + pthread_descr * th; + pthread_extricate_if extr; + + /* Set up extrication interface */ + extr.pu_object = 0; + extr.pu_extricate_func = old_sem_extricate_func; + + while (1) { + /* Register extrication interface */ + __pthread_set_own_extricate_if(self, &extr); + do { + oldstatus = sem->sem_status; + if ((oldstatus & 1) && (oldstatus != 1)) + newstatus = oldstatus - 2; + else { + newstatus = (long) self; + self->p_nextwaiting = (pthread_descr) oldstatus; + } + } + while (! sem_compare_and_swap(sem, oldstatus, newstatus)); + if (newstatus & 1) { + /* We got the semaphore. */ + __pthread_set_own_extricate_if(self, 0); + self->p_nextwaiting = NULL; + return 0; + } + /* Wait for sem_post or cancellation */ + suspend(self); + __pthread_set_own_extricate_if(self, 0); + + /* This is a cancellation point */ + if (self->p_canceled && self->p_cancelstate == PTHREAD_CANCEL_ENABLE) { + /* Remove ourselves from the waiting list if we're still on it */ + /* First check if we're at the head of the list. */ + do { + oldstatus = sem->sem_status; + if (oldstatus != (long) self) break; + newstatus = (long) self->p_nextwaiting; + } + while (! sem_compare_and_swap(sem, oldstatus, newstatus)); + /* Now, check if we're somewhere in the list. + There's a race condition with sem_post here, but it does not matter: + the net result is that at the time pthread_exit is called, + self is no longer reachable from sem->sem_status. */ + if (oldstatus != (long) self && (oldstatus & 1) == 0) { + for (th = &(((pthread_descr) oldstatus)->p_nextwaiting); + *th != NULL && *th != (pthread_descr) 1; + th = &((*th)->p_nextwaiting)) { + if (*th == self) { + *th = self->p_nextwaiting; + break; + } + } + } + __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME); + } + } +} + +int __old_sem_trywait(old_sem_t * sem) +{ + long oldstatus, newstatus; + + do { + oldstatus = sem->sem_status; + if ((oldstatus & 1) == 0 || (oldstatus == 1)) { + errno = EAGAIN; + return -1; + } + newstatus = oldstatus - 2; + } + while (! sem_compare_and_swap(sem, oldstatus, newstatus)); + return 0; +} + +int __old_sem_post(old_sem_t * sem) +{ + long oldstatus, newstatus; + + do { + oldstatus = sem->sem_status; + if ((oldstatus & 1) == 0) + newstatus = 3; + else { + if (oldstatus >= SEM_VALUE_MAX) { + /* Overflow */ + errno = ERANGE; + return -1; + } + newstatus = oldstatus + 2; + } + } + while (! sem_compare_and_swap(sem, oldstatus, newstatus)); + if ((oldstatus & 1) == 0) + sem_restart_list((pthread_descr) oldstatus); + return 0; +} + +int __old_sem_getvalue(old_sem_t * sem, int * sval) +{ + long status = sem->sem_status; + if (status & 1) + *sval = (int)((unsigned long) status >> 1); + else + *sval = 0; + return 0; +} + +int __old_sem_destroy(old_sem_t * sem) +{ + if ((sem->sem_status & 1) == 0) { + errno = EBUSY; + return -1; + } + return 0; +} + +/* Auxiliary function for restarting all threads on a waiting list, + in priority order. */ + +static void sem_restart_list(pthread_descr waiting) +{ + pthread_descr th, towake, *p; + + /* Sort list of waiting threads by decreasing priority (insertion sort) */ + towake = NULL; + while (waiting != (pthread_descr) 1) { + th = waiting; + waiting = waiting->p_nextwaiting; + p = &towake; + while (*p != NULL && th->p_priority < (*p)->p_priority) + p = &((*p)->p_nextwaiting); + th->p_nextwaiting = *p; + *p = th; + } + /* Wake up threads in priority order */ + while (towake != NULL) { + th = towake; + towake = towake->p_nextwaiting; + th->p_nextwaiting = NULL; + restart(th); + } +} + +compat_symbol (libpthread, __old_sem_init, sem_init, GLIBC_2_0); +compat_symbol (libpthread, __old_sem_wait, sem_wait, GLIBC_2_0); +compat_symbol (libpthread, __old_sem_trywait, sem_trywait, GLIBC_2_0); +compat_symbol (libpthread, __old_sem_post, sem_post, GLIBC_2_0); +compat_symbol (libpthread, __old_sem_getvalue, sem_getvalue, GLIBC_2_0); +compat_symbol (libpthread, __old_sem_destroy, sem_destroy, GLIBC_2_0); + +#endif diff --git a/linuxthreads/pt-allocrtsig.c b/linuxthreads/pt-allocrtsig.c new file mode 100644 index 0000000000..3598dbb49f --- /dev/null +++ b/linuxthreads/pt-allocrtsig.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 <signal.h> + + +/* These are defined in libc. We want to have only one definition + so we "forward" the calls. */ +extern int __libc_current_sigrtmin_private (void); +extern int __libc_current_sigrtmax_private (void); +extern int __libc_allocate_rtsig_private (int high); + + +/* We reserve __SIGRTMIN for use as the cancelation signal. This + signal is used internally. */ +int +__libc_current_sigrtmin (void) +{ + return __libc_current_sigrtmin_private (); +} + + +int +__libc_current_sigrtmax (void) +{ + return __libc_current_sigrtmax_private (); +} + + +int +__libc_allocate_rtsig (int high) +{ + return __libc_allocate_rtsig_private (high); +} diff --git a/linuxthreads/pt-machine.c b/linuxthreads/pt-machine.c new file mode 100644 index 0000000000..5cd477ce97 --- /dev/null +++ b/linuxthreads/pt-machine.c @@ -0,0 +1,25 @@ +/* "Instantiation of machine-dependent pthreads inline functions. + Copyright (C) 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#define PT_EI + +extern long int testandset (int *spinlock); +extern int __compare_and_swap (long int *p, long int oldval, long int newval); + +#include <pt-machine.h> diff --git a/linuxthreads/pt-system.c b/linuxthreads/pt-system.c new file mode 100644 index 0000000000..c3ed676f51 --- /dev/null +++ b/linuxthreads/pt-system.c @@ -0,0 +1,32 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <stdlib.h> +#include <sysdep-cancel.h> + + +int +system (const char *line) +{ + return __libc_system (line); +} + +/* __libc_system in libc.so handles cancellation. */ +LIBC_CANCEL_HANDLED (); diff --git a/linuxthreads/ptcleanup.c b/linuxthreads/ptcleanup.c new file mode 100644 index 0000000000..9fde2555b1 --- /dev/null +++ b/linuxthreads/ptcleanup.c @@ -0,0 +1,52 @@ +/* Linuxthreads - a simple clone()-based implementation of Posix */ +/* threads for Linux. */ +/* Copyright (C) 1998, 2004 Xavier Leroy (Xavier.Leroy@inria.fr) */ +/* */ +/* This program is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public License */ +/* as published by the Free Software Foundation; either version 2 */ +/* of the License, or (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Library General Public License for more details. */ + +/* Redefine siglongjmp and longjmp so that they interact correctly + with cleanup handlers */ + +#include <setjmp.h> +#include "pthread.h" +#include "internals.h" + +void __pthread_cleanup_upto (__jmp_buf target, char *targetframe) +{ + pthread_descr self = thread_self(); + struct _pthread_cleanup_buffer * c; + + for (c = THREAD_GETMEM(self, p_cleanup); + c != NULL && _JMPBUF_UNWINDS(target, c); + c = c->__prev) + { +#if _STACK_GROWS_DOWN + if ((char *) c <= targetframe) + { + c = NULL; + break; + } +#elif _STACK_GROWS_UP + if ((char *) c >= targetframe) + { + c = NULL; + break; + } +#else +# error "Define either _STACK_GROWS_DOWN or _STACK_GROWS_UP" +#endif + c->__routine(c->__arg); + } + THREAD_SETMEM(self, p_cleanup, c); + if (THREAD_GETMEM(self, p_in_sighandler) + && _JMPBUF_UNWINDS(target, THREAD_GETMEM(self, p_in_sighandler))) + THREAD_SETMEM(self, p_in_sighandler, NULL); +} diff --git a/linuxthreads/ptclock_gettime.c b/linuxthreads/ptclock_gettime.c new file mode 100644 index 0000000000..755f83d101 --- /dev/null +++ b/linuxthreads/ptclock_gettime.c @@ -0,0 +1,69 @@ +/* Copyright (C) 2001, 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. */ + +#include <errno.h> +#include <time.h> +#include <libc-internal.h> +#include "internals.h" +#include "spinlock.h" + + +#if HP_TIMING_AVAIL +int +__pthread_clock_gettime (clockid_t clock_id, hp_timing_t freq, + struct timespec *tp) +{ + hp_timing_t tsc, cpuclock_offset; + pthread_descr self = thread_self (); + pthread_t thread = ((unsigned int) clock_id) >> CLOCK_IDFIELD_SIZE; + const unsigned int mask = ~0U >> CLOCK_IDFIELD_SIZE; + + if (thread == 0 || (THREAD_GETMEM (self, p_tid) & mask) == thread) + cpuclock_offset = THREAD_GETMEM (self, p_cpuclock_offset); + else + { + pthread_descr th; + pthread_handle handle = thread_handle (thread); + __pthread_lock (&handle->h_lock, NULL); + th = handle->h_descr; + if (th == NULL || (th->p_tid & mask) != thread || th->p_terminated) + { + __pthread_unlock (&handle->h_lock); + __set_errno (EINVAL); + return -1; + } + cpuclock_offset = th->p_cpuclock_offset; + __pthread_unlock (&handle->h_lock); + } + + /* Get the current counter. */ + HP_TIMING_NOW (tsc); + + /* Compute the offset since the start time of the process. */ + tsc -= 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/linuxthreads/ptclock_settime.c b/linuxthreads/ptclock_settime.c new file mode 100644 index 0000000000..a4f218c771 --- /dev/null +++ b/linuxthreads/ptclock_settime.c @@ -0,0 +1,55 @@ +/* Copyright (C) 2001, 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. */ + +#include <errno.h> +#include <time.h> +#include <libc-internal.h> +#include "internals.h" +#include "spinlock.h" + + +#if HP_TIMING_AVAIL +int +__pthread_clock_settime (clockid_t clock_id, hp_timing_t offset) +{ + pthread_descr self = thread_self (); + pthread_t thread = ((unsigned int) clock_id) >> CLOCK_IDFIELD_SIZE; + const unsigned int mask = ~0U >> CLOCK_IDFIELD_SIZE; + + if (thread == 0 || (THREAD_GETMEM (self, p_tid) & mask) == thread) + /* Our own clock. */ + THREAD_SETMEM (self, p_cpuclock_offset, offset); + else + { + pthread_descr th; + pthread_handle handle = thread_handle (thread); + __pthread_lock (&handle->h_lock, NULL); + th = handle->h_descr; + if (th == NULL || (th->p_tid & mask) != thread || th->p_terminated) + { + __pthread_unlock (&handle->h_lock); + __set_errno (EINVAL); + return -1; + } + th->p_cpuclock_offset = offset; + __pthread_unlock (&handle->h_lock); + } + + return 0; +} +#endif diff --git a/linuxthreads/ptfork.c b/linuxthreads/ptfork.c new file mode 100644 index 0000000000..9cdbb54361 --- /dev/null +++ b/linuxthreads/ptfork.c @@ -0,0 +1,93 @@ +/* Linuxthreads - a simple clone()-based implementation of Posix */ +/* threads for Linux. */ +/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ +/* */ +/* This program is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public License */ +/* as published by the Free Software Foundation; either version 2 */ +/* of the License, or (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Library General Public License for more details. */ + +/* The "atfork" stuff */ + +#include <errno.h> +#include <stddef.h> +#include <stdlib.h> +#include <unistd.h> +#include "pthread.h" +#include "internals.h" +#include <bits/libc-lock.h> +#include "fork.h" + +extern int __libc_fork (void); + +pid_t __pthread_fork (struct fork_block *b) +{ + pid_t pid; + list_t *runp; + + __libc_lock_lock (b->lock); + + /* Run all the registered preparation handlers. In reverse order. */ + list_for_each_prev (runp, &b->prepare_list) + { + struct fork_handler *curp; + curp = list_entry (runp, struct fork_handler, list); + curp->handler (); + } + + __pthread_once_fork_prepare(); + __flockfilelist(); + + pid = ARCH_FORK (); + + if (pid == 0) { + __pthread_reset_main_thread(); + + __fresetlockfiles(); + __pthread_once_fork_child(); + + /* Run the handlers registered for the child. */ + list_for_each (runp, &b->child_list) + { + struct fork_handler *curp; + curp = list_entry (runp, struct fork_handler, list); + curp->handler (); + } + + __libc_lock_init (b->lock); + } else { + __funlockfilelist(); + __pthread_once_fork_parent(); + + /* Run the handlers registered for the parent. */ + list_for_each (runp, &b->parent_list) + { + struct fork_handler *curp; + curp = list_entry (runp, struct fork_handler, list); + curp->handler (); + } + + __libc_lock_unlock (b->lock); + } + + return pid; +} + +#ifdef SHARED +pid_t __fork (void) +{ + return __libc_fork (); +} +weak_alias (__fork, fork); + +pid_t __vfork(void) +{ + return __libc_fork (); +} +weak_alias (__vfork, vfork); +#endif diff --git a/linuxthreads/pthandles.c b/linuxthreads/pthandles.c new file mode 100644 index 0000000000..4d2ac1940d --- /dev/null +++ b/linuxthreads/pthandles.c @@ -0,0 +1,6 @@ +#include <ldsodefs.h> +#include "pthread.h" +#include "internals.h" + +/* Array of active threads. Entry 0 is reserved for the initial thread. */ +struct pthread_handle_struct __pthread_handles[PTHREAD_THREADS_MAX]; diff --git a/linuxthreads/pthread.c b/linuxthreads/pthread.c new file mode 100644 index 0000000000..24f0eb02b0 --- /dev/null +++ b/linuxthreads/pthread.c @@ -0,0 +1,1407 @@ + +/* Linuxthreads - a simple clone()-based implementation of Posix */ +/* threads for Linux. */ +/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ +/* */ +/* This program is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public License */ +/* as published by the Free Software Foundation; either version 2 */ +/* of the License, or (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Library General Public License for more details. */ + +/* Thread creation, initialization, and basic low-level routines */ + +#include <errno.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/wait.h> +#include <sys/resource.h> +#include <sys/time.h> +#include <shlib-compat.h> +#include "pthread.h" +#include "internals.h" +#include "spinlock.h" +#include "restart.h" +#include "smp.h" +#include <ldsodefs.h> +#include <tls.h> +#include <version.h> +#include <not-cancel.h> + +/* Sanity check. */ +#if !defined __SIGRTMIN || (__SIGRTMAX - __SIGRTMIN) < 3 +# error "This must not happen" +#endif + +#if !(USE_TLS && HAVE___THREAD) +/* These variables are used by the setup code. */ +extern int _errno; +extern int _h_errno; + +/* We need the global/static resolver state here. */ +# include <resolv.h> +# undef _res + +extern struct __res_state _res; +#endif + +#ifdef USE_TLS + +/* We need only a few variables. */ +#define manager_thread __pthread_manager_threadp +pthread_descr __pthread_manager_threadp attribute_hidden; + +#else + +/* Descriptor of the initial thread */ + +struct _pthread_descr_struct __pthread_initial_thread = { + .p_header.data.self = &__pthread_initial_thread, + .p_nextlive = &__pthread_initial_thread, + .p_prevlive = &__pthread_initial_thread, + .p_tid = PTHREAD_THREADS_MAX, + .p_lock = &__pthread_handles[0].h_lock, + .p_start_args = PTHREAD_START_ARGS_INITIALIZER(NULL), +#if !(USE_TLS && HAVE___THREAD) + .p_errnop = &_errno, + .p_h_errnop = &_h_errno, + .p_resp = &_res, +#endif + .p_userstack = 1, + .p_resume_count = __ATOMIC_INITIALIZER, + .p_alloca_cutoff = __MAX_ALLOCA_CUTOFF +}; + +/* Descriptor of the manager thread; none of this is used but the error + variables, the p_pid and p_priority fields, + and the address for identification. */ + +#define manager_thread (&__pthread_manager_thread) +struct _pthread_descr_struct __pthread_manager_thread = { + .p_header.data.self = &__pthread_manager_thread, + .p_header.data.multiple_threads = 1, + .p_lock = &__pthread_handles[1].h_lock, + .p_start_args = PTHREAD_START_ARGS_INITIALIZER(__pthread_manager), +#if !(USE_TLS && HAVE___THREAD) + .p_errnop = &__pthread_manager_thread.p_errno, +#endif + .p_nr = 1, + .p_resume_count = __ATOMIC_INITIALIZER, + .p_alloca_cutoff = PTHREAD_STACK_MIN / 4 +}; +#endif + +/* Pointer to the main thread (the father of the thread manager thread) */ +/* Originally, this is the initial thread, but this changes after fork() */ + +#ifdef USE_TLS +pthread_descr __pthread_main_thread; +#else +pthread_descr __pthread_main_thread = &__pthread_initial_thread; +#endif + +/* Limit between the stack of the initial thread (above) and the + stacks of other threads (below). Aligned on a STACK_SIZE boundary. */ + +char *__pthread_initial_thread_bos; + +/* File descriptor for sending requests to the thread manager. */ +/* Initially -1, meaning that the thread manager is not running. */ + +int __pthread_manager_request = -1; + +int __pthread_multiple_threads attribute_hidden; + +/* Other end of the pipe for sending requests to the thread manager. */ + +int __pthread_manager_reader; + +/* Limits of the thread manager stack */ + +char *__pthread_manager_thread_bos; +char *__pthread_manager_thread_tos; + +/* For process-wide exit() */ + +int __pthread_exit_requested; +int __pthread_exit_code; + +/* Maximum stack size. */ +size_t __pthread_max_stacksize; + +/* Nozero if the machine has more than one processor. */ +int __pthread_smp_kernel; + + +#if !__ASSUME_REALTIME_SIGNALS +/* Pointers that select new or old suspend/resume functions + based on availability of rt signals. */ + +void (*__pthread_restart)(pthread_descr) = __pthread_restart_old; +void (*__pthread_suspend)(pthread_descr) = __pthread_suspend_old; +int (*__pthread_timedsuspend)(pthread_descr, const struct timespec *) = __pthread_timedsuspend_old; +#endif /* __ASSUME_REALTIME_SIGNALS */ + +/* Communicate relevant LinuxThreads constants to gdb */ + +const int __pthread_threads_max = PTHREAD_THREADS_MAX; +const int __pthread_sizeof_handle = sizeof(struct pthread_handle_struct); +const int __pthread_offsetof_descr = offsetof(struct pthread_handle_struct, + h_descr); +const int __pthread_offsetof_pid = offsetof(struct _pthread_descr_struct, + p_pid); +const int __linuxthreads_pthread_sizeof_descr + = sizeof(struct _pthread_descr_struct); + +const int __linuxthreads_initial_report_events; + +const char __linuxthreads_version[] = VERSION; + +/* Forward declarations */ + +static void pthread_onexit_process(int retcode, void *arg); +#ifndef HAVE_Z_NODELETE +static void pthread_atexit_process(void *arg, int retcode); +static void pthread_atexit_retcode(void *arg, int retcode); +#endif +static void pthread_handle_sigcancel(int sig); +static void pthread_handle_sigrestart(int sig); +static void pthread_handle_sigdebug(int sig); + +/* Signal numbers used for the communication. + In these variables we keep track of the used variables. If the + platform does not support any real-time signals we will define the + values to some unreasonable value which will signal failing of all + the functions below. */ +int __pthread_sig_restart = __SIGRTMIN; +int __pthread_sig_cancel = __SIGRTMIN + 1; +int __pthread_sig_debug = __SIGRTMIN + 2; + +extern int __libc_current_sigrtmin_private (void); + +#if !__ASSUME_REALTIME_SIGNALS +static int rtsigs_initialized; + +static void +init_rtsigs (void) +{ + if (rtsigs_initialized) + return; + + if (__libc_current_sigrtmin_private () == -1) + { + __pthread_sig_restart = SIGUSR1; + __pthread_sig_cancel = SIGUSR2; + __pthread_sig_debug = 0; + } + else + { + __pthread_restart = __pthread_restart_new; + __pthread_suspend = __pthread_wait_for_restart_signal; + __pthread_timedsuspend = __pthread_timedsuspend_new; + } + + rtsigs_initialized = 1; +} +#endif + + +/* Initialize the pthread library. + Initialization is split in two functions: + - a constructor function that blocks the __pthread_sig_restart signal + (must do this very early, since the program could capture the signal + mask with e.g. sigsetjmp before creating the first thread); + - a regular function called from pthread_create when needed. */ + +static void pthread_initialize(void) __attribute__((constructor)); + +#ifndef HAVE_Z_NODELETE +extern void *__dso_handle __attribute__ ((weak)); +#endif + + +#if defined USE_TLS && !defined SHARED +extern void __libc_setup_tls (size_t tcbsize, size_t tcbalign); +#endif + +struct pthread_functions __pthread_functions = + { +#if !(USE_TLS && HAVE___THREAD) + .ptr_pthread_internal_tsd_set = __pthread_internal_tsd_set, + .ptr_pthread_internal_tsd_get = __pthread_internal_tsd_get, + .ptr_pthread_internal_tsd_address = __pthread_internal_tsd_address, +#endif + .ptr_pthread_fork = __pthread_fork, + .ptr_pthread_attr_destroy = __pthread_attr_destroy, +#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_1) + .ptr___pthread_attr_init_2_0 = __pthread_attr_init_2_0, +#endif + .ptr___pthread_attr_init_2_1 = __pthread_attr_init_2_1, + .ptr_pthread_attr_getdetachstate = __pthread_attr_getdetachstate, + .ptr_pthread_attr_setdetachstate = __pthread_attr_setdetachstate, + .ptr_pthread_attr_getinheritsched = __pthread_attr_getinheritsched, + .ptr_pthread_attr_setinheritsched = __pthread_attr_setinheritsched, + .ptr_pthread_attr_getschedparam = __pthread_attr_getschedparam, + .ptr_pthread_attr_setschedparam = __pthread_attr_setschedparam, + .ptr_pthread_attr_getschedpolicy = __pthread_attr_getschedpolicy, + .ptr_pthread_attr_setschedpolicy = __pthread_attr_setschedpolicy, + .ptr_pthread_attr_getscope = __pthread_attr_getscope, + .ptr_pthread_attr_setscope = __pthread_attr_setscope, + .ptr_pthread_condattr_destroy = __pthread_condattr_destroy, + .ptr_pthread_condattr_init = __pthread_condattr_init, + .ptr___pthread_cond_broadcast = __pthread_cond_broadcast, + .ptr___pthread_cond_destroy = __pthread_cond_destroy, + .ptr___pthread_cond_init = __pthread_cond_init, + .ptr___pthread_cond_signal = __pthread_cond_signal, + .ptr___pthread_cond_wait = __pthread_cond_wait, + .ptr___pthread_cond_timedwait = __pthread_cond_timedwait, + .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_trylock = __pthread_mutex_trylock, + .ptr_pthread_mutex_unlock = __pthread_mutex_unlock, + .ptr_pthread_self = __pthread_self, + .ptr_pthread_setcancelstate = __pthread_setcancelstate, + .ptr_pthread_setcanceltype = __pthread_setcanceltype, + .ptr_pthread_do_exit = __pthread_do_exit, + .ptr_pthread_thread_self = __pthread_thread_self, + .ptr_pthread_cleanup_upto = __pthread_cleanup_upto, + .ptr_pthread_sigaction = __pthread_sigaction, + .ptr_pthread_sigwait = __pthread_sigwait, + .ptr_pthread_raise = __pthread_raise, + .ptr__pthread_cleanup_push = _pthread_cleanup_push, + .ptr__pthread_cleanup_pop = _pthread_cleanup_pop + }; +#ifdef SHARED +# define ptr_pthread_functions &__pthread_functions +#else +# define ptr_pthread_functions NULL +#endif + +static int *__libc_multiple_threads_ptr; + +/* Do some minimal initialization which has to be done during the + startup of the C library. */ +void +__pthread_initialize_minimal(void) +{ +#ifdef USE_TLS + pthread_descr self; + + /* First of all init __pthread_handles[0] and [1] if needed. */ +# if __LT_SPINLOCK_INIT != 0 + __pthread_handles[0].h_lock = __LOCK_INITIALIZER; + __pthread_handles[1].h_lock = __LOCK_INITIALIZER; +# endif +# ifndef SHARED + /* Unlike in the dynamically linked case the dynamic linker has not + taken care of initializing the TLS data structures. */ + __libc_setup_tls (TLS_TCB_SIZE, TLS_TCB_ALIGN); +# elif !USE___THREAD + if (__builtin_expect (GL(dl_tls_dtv_slotinfo_list) == NULL, 0)) + { + tcbhead_t *tcbp; + + /* There is no actual TLS being used, so the thread register + was not initialized in the dynamic linker. */ + + /* We need to install special hooks so that the malloc and memalign + calls in _dl_tls_setup and _dl_allocate_tls won't cause full + malloc initialization that will try to set up its thread state. */ + + extern void __libc_malloc_pthread_startup (bool first_time); + __libc_malloc_pthread_startup (true); + + if (__builtin_expect (_dl_tls_setup (), 0) + || __builtin_expect ((tcbp = _dl_allocate_tls (NULL)) == NULL, 0)) + { + static const char msg[] = "\ +cannot allocate TLS data structures for initial thread\n"; + TEMP_FAILURE_RETRY (write_not_cancel (STDERR_FILENO, + msg, sizeof msg - 1)); + abort (); + } + const char *lossage = TLS_INIT_TP (tcbp, 0); + if (__builtin_expect (lossage != NULL, 0)) + { + static const char msg[] = "cannot set up thread-local storage: "; + const char nl = '\n'; + TEMP_FAILURE_RETRY (write_not_cancel (STDERR_FILENO, + msg, sizeof msg - 1)); + TEMP_FAILURE_RETRY (write_not_cancel (STDERR_FILENO, + lossage, strlen (lossage))); + TEMP_FAILURE_RETRY (write_not_cancel (STDERR_FILENO, &nl, 1)); + } + + /* Though it was allocated with libc's malloc, that was done without + the user's __malloc_hook installed. A later realloc that uses + the hooks might not work with that block from the plain malloc. + So we record this block as unfreeable just as the dynamic linker + does when it allocates the DTV before the libc malloc exists. */ + GL(dl_initial_dtv) = GET_DTV (tcbp); + + __libc_malloc_pthread_startup (false); + } +# endif + + self = THREAD_SELF; + + /* The memory for the thread descriptor was allocated elsewhere as + part of the TLS allocation. We have to initialize the data + structure by hand. This initialization must mirror the struct + definition above. */ + self->p_nextlive = self->p_prevlive = self; + self->p_tid = PTHREAD_THREADS_MAX; + self->p_lock = &__pthread_handles[0].h_lock; +# ifndef HAVE___THREAD + self->p_errnop = &_errno; + self->p_h_errnop = &_h_errno; +# endif + /* self->p_start_args need not be initialized, it's all zero. */ + self->p_userstack = 1; +# if __LT_SPINLOCK_INIT != 0 + self->p_resume_count = (struct pthread_atomic) __ATOMIC_INITIALIZER; +# endif + self->p_alloca_cutoff = __MAX_ALLOCA_CUTOFF; + + /* Another variable which points to the thread descriptor. */ + __pthread_main_thread = self; + + /* And fill in the pointer the the thread __pthread_handles array. */ + __pthread_handles[0].h_descr = self; + +#else /* USE_TLS */ + + /* First of all init __pthread_handles[0] and [1]. */ +# if __LT_SPINLOCK_INIT != 0 + __pthread_handles[0].h_lock = __LOCK_INITIALIZER; + __pthread_handles[1].h_lock = __LOCK_INITIALIZER; +# endif + __pthread_handles[0].h_descr = &__pthread_initial_thread; + __pthread_handles[1].h_descr = &__pthread_manager_thread; + + /* If we have special thread_self processing, initialize that for the + main thread now. */ +# ifdef INIT_THREAD_SELF + INIT_THREAD_SELF(&__pthread_initial_thread, 0); +# endif +#endif + +#if HP_TIMING_AVAIL +# ifdef USE_TLS + self->p_cpuclock_offset = GL(dl_cpuclock_offset); +# else + __pthread_initial_thread.p_cpuclock_offset = GL(dl_cpuclock_offset); +# endif +#endif + + __libc_multiple_threads_ptr = __libc_pthread_init (ptr_pthread_functions); +} + + +void +__pthread_init_max_stacksize(void) +{ + struct rlimit limit; + size_t max_stack; + + getrlimit(RLIMIT_STACK, &limit); +#ifdef FLOATING_STACKS + if (limit.rlim_cur == RLIM_INFINITY) + limit.rlim_cur = ARCH_STACK_MAX_SIZE; +# ifdef NEED_SEPARATE_REGISTER_STACK + max_stack = limit.rlim_cur / 2; +# else + max_stack = limit.rlim_cur; +# endif +#else + /* Play with the stack size limit to make sure that no stack ever grows + beyond STACK_SIZE minus one page (to act as a guard page). */ +# ifdef NEED_SEPARATE_REGISTER_STACK + /* STACK_SIZE bytes hold both the main stack and register backing + store. The rlimit value applies to each individually. */ + max_stack = STACK_SIZE/2 - __getpagesize (); +# else + max_stack = STACK_SIZE - __getpagesize(); +# endif + if (limit.rlim_cur > max_stack) { + limit.rlim_cur = max_stack; + setrlimit(RLIMIT_STACK, &limit); + } +#endif + __pthread_max_stacksize = max_stack; + if (max_stack / 4 < __MAX_ALLOCA_CUTOFF) + { +#ifdef USE_TLS + pthread_descr self = THREAD_SELF; + self->p_alloca_cutoff = max_stack / 4; +#else + __pthread_initial_thread.p_alloca_cutoff = max_stack / 4; +#endif + } +} + +#ifdef SHARED +# if USE___THREAD +/* 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)); +# else +static void ** __attribute__ ((const)) +__libc_dl_error_tsd (void) +{ + return &thread_self ()->p_libc_specific[_LIBC_TSD_KEY_DL_ERROR]; +} +# endif +#endif + +#ifdef USE_TLS +static inline void __attribute__((always_inline)) +init_one_static_tls (pthread_descr descr, struct link_map *map) +{ +# if TLS_TCB_AT_TP + dtv_t *dtv = GET_DTV (descr); + void *dest = (char *) descr - map->l_tls_offset; +# elif TLS_DTV_AT_TP + dtv_t *dtv = GET_DTV ((pthread_descr) ((char *) descr + TLS_PRE_TCB_SIZE)); + void *dest = (char *) descr + 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 = dest; + + /* 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); +} + +static void +__pthread_init_static_tls (struct link_map *map) +{ + size_t i; + + for (i = 0; i < PTHREAD_THREADS_MAX; ++i) + if (__pthread_handles[i].h_descr != NULL && i != 1) + { + __pthread_lock (&__pthread_handles[i].h_lock, NULL); + if (__pthread_handles[i].h_descr != NULL) + init_one_static_tls (__pthread_handles[i].h_descr, map); + __pthread_unlock (&__pthread_handles[i].h_lock); + } +} +#endif + +static void pthread_initialize(void) +{ + struct sigaction sa; + sigset_t mask; + + /* If already done (e.g. by a constructor called earlier!), bail out */ + if (__pthread_initial_thread_bos != NULL) return; +#ifdef TEST_FOR_COMPARE_AND_SWAP + /* Test if compare-and-swap is available */ + __pthread_has_cas = compare_and_swap_is_available(); +#endif +#ifdef FLOATING_STACKS + /* We don't need to know the bottom of the stack. Give the pointer some + value to signal that initialization happened. */ + __pthread_initial_thread_bos = (void *) -1l; +#else + /* Determine stack size limits . */ + __pthread_init_max_stacksize (); +# ifdef _STACK_GROWS_UP + /* The initial thread already has all the stack it needs */ + __pthread_initial_thread_bos = (char *) + ((long)CURRENT_STACK_FRAME &~ (STACK_SIZE - 1)); +# else + /* For the initial stack, reserve at least STACK_SIZE bytes of stack + below the current stack address, and align that on a + STACK_SIZE boundary. */ + __pthread_initial_thread_bos = + (char *)(((long)CURRENT_STACK_FRAME - 2 * STACK_SIZE) & ~(STACK_SIZE - 1)); +# endif +#endif +#ifdef USE_TLS + /* Update the descriptor for the initial thread. */ + THREAD_SETMEM (((pthread_descr) NULL), p_pid, __getpid()); +# ifndef HAVE___THREAD + /* Likewise for the resolver state _res. */ + THREAD_SETMEM (((pthread_descr) NULL), p_resp, &_res); +# endif +#else + /* Update the descriptor for the initial thread. */ + __pthread_initial_thread.p_pid = __getpid(); + /* Likewise for the resolver state _res. */ + __pthread_initial_thread.p_resp = &_res; +#endif +#if !__ASSUME_REALTIME_SIGNALS + /* Initialize real-time signals. */ + init_rtsigs (); +#endif + /* Setup signal handlers for the initial thread. + Since signal handlers are shared between threads, these settings + will be inherited by all other threads. */ + sa.sa_handler = pthread_handle_sigrestart; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + __libc_sigaction(__pthread_sig_restart, &sa, NULL); + sa.sa_handler = pthread_handle_sigcancel; + sigaddset(&sa.sa_mask, __pthread_sig_restart); + // sa.sa_flags = 0; + __libc_sigaction(__pthread_sig_cancel, &sa, NULL); + if (__pthread_sig_debug > 0) { + sa.sa_handler = pthread_handle_sigdebug; + sigemptyset(&sa.sa_mask); + // sa.sa_flags = 0; + __libc_sigaction(__pthread_sig_debug, &sa, NULL); + } + /* Initially, block __pthread_sig_restart. Will be unblocked on demand. */ + sigemptyset(&mask); + sigaddset(&mask, __pthread_sig_restart); + sigprocmask(SIG_BLOCK, &mask, NULL); + /* And unblock __pthread_sig_cancel if it has been blocked. */ + sigdelset(&mask, __pthread_sig_restart); + sigaddset(&mask, __pthread_sig_cancel); + sigprocmask(SIG_UNBLOCK, &mask, NULL); + /* Register an exit function to kill all other threads. */ + /* Do it early so that user-registered atexit functions are called + before pthread_*exit_process. */ +#ifndef HAVE_Z_NODELETE + if (__builtin_expect (&__dso_handle != NULL, 1)) + __cxa_atexit ((void (*) (void *)) pthread_atexit_process, NULL, + __dso_handle); + else +#endif + __on_exit (pthread_onexit_process, NULL); + /* How many processors. */ + __pthread_smp_kernel = is_smp_system (); + +#ifdef SHARED + /* Transfer the old value from the dynamic linker's internal location. */ + *__libc_dl_error_tsd () = *(*GL(dl_error_catch_tsd)) (); + GL(dl_error_catch_tsd) = &__libc_dl_error_tsd; + + /* Make __rtld_lock_{,un}lock_recursive use pthread_mutex_{,un}lock, + keep the lock count from the ld.so implementation. */ + GL(dl_rtld_lock_recursive) = (void *) __pthread_mutex_lock; + GL(dl_rtld_unlock_recursive) = (void *) __pthread_mutex_unlock; + unsigned int rtld_lock_count = GL(dl_load_lock).mutex.__m_count; + GL(dl_load_lock).mutex.__m_count = 0; + while (rtld_lock_count-- > 0) + __pthread_mutex_lock (&GL(dl_load_lock).mutex); +#endif + +#ifdef USE_TLS + GL(dl_init_static_tls) = &__pthread_init_static_tls; +#endif +} + +void __pthread_initialize(void) +{ + pthread_initialize(); +} + +int __pthread_initialize_manager(void) +{ + int manager_pipe[2]; + int pid; + struct pthread_request request; + int report_events; + pthread_descr mgr; +#ifdef USE_TLS + tcbhead_t *tcbp; +#endif + + __pthread_multiple_threads = 1; +#if TLS_MULTIPLE_THREADS_IN_TCB || !defined USE_TLS || !TLS_DTV_AT_TP + __pthread_main_thread->p_multiple_threads = 1; +#endif + *__libc_multiple_threads_ptr = 1; + +#ifndef HAVE_Z_NODELETE + if (__builtin_expect (&__dso_handle != NULL, 1)) + __cxa_atexit ((void (*) (void *)) pthread_atexit_retcode, NULL, + __dso_handle); +#endif + + if (__pthread_max_stacksize == 0) + __pthread_init_max_stacksize (); + /* If basic initialization not done yet (e.g. we're called from a + constructor run before our constructor), do it now */ + if (__pthread_initial_thread_bos == NULL) pthread_initialize(); + /* Setup stack for thread manager */ + __pthread_manager_thread_bos = malloc(THREAD_MANAGER_STACK_SIZE); + if (__pthread_manager_thread_bos == NULL) return -1; + __pthread_manager_thread_tos = + __pthread_manager_thread_bos + THREAD_MANAGER_STACK_SIZE; + /* Setup pipe to communicate with thread manager */ + if (pipe(manager_pipe) == -1) { + free(__pthread_manager_thread_bos); + return -1; + } + +#ifdef USE_TLS + /* Allocate memory for the thread descriptor and the dtv. */ + tcbp = _dl_allocate_tls (NULL); + if (tcbp == NULL) { + free(__pthread_manager_thread_bos); + close_not_cancel(manager_pipe[0]); + close_not_cancel(manager_pipe[1]); + return -1; + } + +# if TLS_TCB_AT_TP + mgr = (pthread_descr) tcbp; +# elif TLS_DTV_AT_TP + /* pthread_descr is located right below tcbhead_t which _dl_allocate_tls + returns. */ + mgr = (pthread_descr) ((char *) tcbp - TLS_PRE_TCB_SIZE); +# endif + __pthread_handles[1].h_descr = manager_thread = mgr; + + /* Initialize the descriptor. */ +#if !defined USE_TLS || !TLS_DTV_AT_TP + mgr->p_header.data.tcb = tcbp; + mgr->p_header.data.self = mgr; + mgr->p_header.data.multiple_threads = 1; +#elif TLS_MULTIPLE_THREADS_IN_TCB + mgr->p_multiple_threads = 1; +#endif + mgr->p_lock = &__pthread_handles[1].h_lock; +# ifndef HAVE___THREAD + mgr->p_errnop = &mgr->p_errno; +# endif + mgr->p_start_args = (struct pthread_start_args) PTHREAD_START_ARGS_INITIALIZER(__pthread_manager); + mgr->p_nr = 1; +# if __LT_SPINLOCK_INIT != 0 + self->p_resume_count = (struct pthread_atomic) __ATOMIC_INITIALIZER; +# endif + mgr->p_alloca_cutoff = PTHREAD_STACK_MIN / 4; +#else + mgr = &__pthread_manager_thread; +#endif + + __pthread_manager_request = manager_pipe[1]; /* writing end */ + __pthread_manager_reader = manager_pipe[0]; /* reading end */ + + /* Start the thread manager */ + pid = 0; +#ifdef USE_TLS + if (__linuxthreads_initial_report_events != 0) + THREAD_SETMEM (((pthread_descr) NULL), p_report_events, + __linuxthreads_initial_report_events); + report_events = THREAD_GETMEM (((pthread_descr) NULL), p_report_events); +#else + if (__linuxthreads_initial_report_events != 0) + __pthread_initial_thread.p_report_events + = __linuxthreads_initial_report_events; + report_events = __pthread_initial_thread.p_report_events; +#endif + if (__builtin_expect (report_events, 0)) + { + /* It's a bit more complicated. We have to report the creation of + the manager thread. */ + int idx = __td_eventword (TD_CREATE); + uint32_t mask = __td_eventmask (TD_CREATE); + uint32_t event_bits; + +#ifdef USE_TLS + event_bits = THREAD_GETMEM_NC (((pthread_descr) NULL), + p_eventbuf.eventmask.event_bits[idx]); +#else + event_bits = __pthread_initial_thread.p_eventbuf.eventmask.event_bits[idx]; +#endif + + if ((mask & (__pthread_threads_events.event_bits[idx] | event_bits)) + != 0) + { + __pthread_lock(mgr->p_lock, NULL); + +#ifdef NEED_SEPARATE_REGISTER_STACK + pid = __clone2(__pthread_manager_event, + (void **) __pthread_manager_thread_bos, + THREAD_MANAGER_STACK_SIZE, + CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, + mgr); +#elif _STACK_GROWS_UP + pid = __clone(__pthread_manager_event, + (void **) __pthread_manager_thread_bos, + CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, + mgr); +#else + pid = __clone(__pthread_manager_event, + (void **) __pthread_manager_thread_tos, + CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, + mgr); +#endif + + if (pid != -1) + { + /* 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. */ + mgr->p_eventbuf.eventdata = mgr; + mgr->p_eventbuf.eventnum = TD_CREATE; + __pthread_last_event = mgr; + mgr->p_tid = 2* PTHREAD_THREADS_MAX + 1; + mgr->p_pid = pid; + + /* Now call the function which signals the event. */ + __linuxthreads_create_event (); + } + + /* Now restart the thread. */ + __pthread_unlock(mgr->p_lock); + } + } + + if (__builtin_expect (pid, 0) == 0) + { +#ifdef NEED_SEPARATE_REGISTER_STACK + pid = __clone2(__pthread_manager, (void **) __pthread_manager_thread_bos, + THREAD_MANAGER_STACK_SIZE, + CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, mgr); +#elif _STACK_GROWS_UP + pid = __clone(__pthread_manager, (void **) __pthread_manager_thread_bos, + CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, mgr); +#else + pid = __clone(__pthread_manager, (void **) __pthread_manager_thread_tos, + CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, mgr); +#endif + } + if (__builtin_expect (pid, 0) == -1) { +#ifdef USE_TLS + _dl_deallocate_tls (tcbp, true); +#endif + free(__pthread_manager_thread_bos); + close_not_cancel(manager_pipe[0]); + close_not_cancel(manager_pipe[1]); + return -1; + } + mgr->p_tid = 2* PTHREAD_THREADS_MAX + 1; + mgr->p_pid = pid; + /* Make gdb aware of new thread manager */ + if (__builtin_expect (__pthread_threads_debug, 0) && __pthread_sig_debug > 0) + { + raise(__pthread_sig_debug); + /* We suspend ourself and gdb will wake us up when it is + ready to handle us. */ + __pthread_wait_for_restart_signal(thread_self()); + } + /* Synchronize debugging of the thread manager */ + request.req_kind = REQ_DEBUG; + TEMP_FAILURE_RETRY(write_not_cancel(__pthread_manager_request, + (char *) &request, sizeof(request))); + return 0; +} + +/* Thread creation */ + +int __pthread_create_2_1(pthread_t *thread, const pthread_attr_t *attr, + void * (*start_routine)(void *), void *arg) +{ + pthread_descr self = thread_self(); + struct pthread_request request; + int retval; + if (__builtin_expect (__pthread_manager_request, 0) < 0) { + if (__pthread_initialize_manager() < 0) return EAGAIN; + } + request.req_thread = self; + request.req_kind = REQ_CREATE; + request.req_args.create.attr = attr; + request.req_args.create.fn = start_routine; + request.req_args.create.arg = arg; + sigprocmask(SIG_SETMASK, (const sigset_t *) NULL, + &request.req_args.create.mask); + TEMP_FAILURE_RETRY(write_not_cancel(__pthread_manager_request, + (char *) &request, sizeof(request))); + suspend(self); + retval = THREAD_GETMEM(self, p_retcode); + if (__builtin_expect (retval, 0) == 0) + *thread = (pthread_t) THREAD_GETMEM(self, p_retval); + return retval; +} + +versioned_symbol (libpthread, __pthread_create_2_1, pthread_create, GLIBC_2_1); + +#if SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_1) + +int __pthread_create_2_0(pthread_t *thread, const pthread_attr_t *attr, + void * (*start_routine)(void *), void *arg) +{ + /* The ATTR attribute is not really of type `pthread_attr_t *'. It has + the old size and access to the new members might crash the program. + We convert the struct now. */ + pthread_attr_t new_attr; + + if (attr != NULL) + { + size_t ps = __getpagesize (); + + memcpy (&new_attr, attr, + (size_t) &(((pthread_attr_t*)NULL)->__guardsize)); + new_attr.__guardsize = ps; + new_attr.__stackaddr_set = 0; + new_attr.__stackaddr = NULL; + new_attr.__stacksize = STACK_SIZE - ps; + attr = &new_attr; + } + return __pthread_create_2_1 (thread, attr, start_routine, arg); +} +compat_symbol (libpthread, __pthread_create_2_0, pthread_create, GLIBC_2_0); +#endif + +/* Simple operations on thread identifiers */ + +pthread_descr __pthread_thread_self(void) +{ + return thread_self(); +} + +pthread_t __pthread_self(void) +{ + pthread_descr self = thread_self(); + return THREAD_GETMEM(self, p_tid); +} +strong_alias (__pthread_self, pthread_self); + +int __pthread_equal(pthread_t thread1, pthread_t thread2) +{ + return thread1 == thread2; +} +strong_alias (__pthread_equal, pthread_equal); + +/* Helper function for thread_self in the case of user-provided stacks */ + +#ifndef THREAD_SELF + +pthread_descr __pthread_find_self(void) +{ + char * sp = CURRENT_STACK_FRAME; + pthread_handle h; + + /* __pthread_handles[0] is the initial thread, __pthread_handles[1] is + the manager threads handled specially in thread_self(), so start at 2 */ + h = __pthread_handles + 2; +# ifdef _STACK_GROWS_UP + while (! (sp >= (char *) h->h_descr && sp < h->h_descr->p_guardaddr)) h++; +# else + while (! (sp <= (char *) h->h_descr && sp >= h->h_bottom)) h++; +# endif + return h->h_descr; +} + +#else + +pthread_descr __pthread_self_stack(void) +{ + char *sp = CURRENT_STACK_FRAME; + pthread_handle h; + + if (sp >= __pthread_manager_thread_bos && sp < __pthread_manager_thread_tos) + return manager_thread; + h = __pthread_handles + 2; +# ifdef USE_TLS +# ifdef _STACK_GROWS_UP + while (h->h_descr == NULL + || ! (sp >= h->h_descr->p_stackaddr && sp < h->h_descr->p_guardaddr)) + h++; +# else + while (h->h_descr == NULL + || ! (sp <= (char *) h->h_descr->p_stackaddr && sp >= h->h_bottom)) + h++; +# endif +# else +# ifdef _STACK_GROWS_UP + while (! (sp >= (char *) h->h_descr && sp < h->h_descr->p_guardaddr)) + h++; +# else + while (! (sp <= (char *) h->h_descr && sp >= h->h_bottom)) + h++; +# endif +# endif + return h->h_descr; +} + +#endif + +/* Thread scheduling */ + +int __pthread_setschedparam(pthread_t thread, int policy, + const struct sched_param *param) +{ + pthread_handle handle = thread_handle(thread); + pthread_descr th; + + __pthread_lock(&handle->h_lock, NULL); + if (__builtin_expect (invalid_handle(handle, thread), 0)) { + __pthread_unlock(&handle->h_lock); + return ESRCH; + } + th = handle->h_descr; + if (__builtin_expect (__sched_setscheduler(th->p_pid, policy, param) == -1, + 0)) { + __pthread_unlock(&handle->h_lock); + return errno; + } + th->p_priority = policy == SCHED_OTHER ? 0 : param->sched_priority; + __pthread_unlock(&handle->h_lock); + if (__pthread_manager_request >= 0) + __pthread_manager_adjust_prio(th->p_priority); + return 0; +} +strong_alias (__pthread_setschedparam, pthread_setschedparam); + +int __pthread_getschedparam(pthread_t thread, int *policy, + struct sched_param *param) +{ + pthread_handle handle = thread_handle(thread); + int pid, pol; + + __pthread_lock(&handle->h_lock, NULL); + if (__builtin_expect (invalid_handle(handle, thread), 0)) { + __pthread_unlock(&handle->h_lock); + return ESRCH; + } + pid = handle->h_descr->p_pid; + __pthread_unlock(&handle->h_lock); + pol = __sched_getscheduler(pid); + if (__builtin_expect (pol, 0) == -1) return errno; + if (__sched_getparam(pid, param) == -1) return errno; + *policy = pol; + return 0; +} +strong_alias (__pthread_getschedparam, pthread_getschedparam); + +int __pthread_yield (void) +{ + /* For now this is equivalent with the POSIX call. */ + return sched_yield (); +} +weak_alias (__pthread_yield, pthread_yield) + +/* Process-wide exit() request */ + +static void pthread_onexit_process(int retcode, void *arg) +{ + if (__builtin_expect (__pthread_manager_request, 0) >= 0) { + struct pthread_request request; + pthread_descr self = thread_self(); + + request.req_thread = self; + request.req_kind = REQ_PROCESS_EXIT; + request.req_args.exit.code = retcode; + TEMP_FAILURE_RETRY(write_not_cancel(__pthread_manager_request, + (char *) &request, sizeof(request))); + suspend(self); + /* Main thread should accumulate times for thread manager and its + children, so that timings for main thread account for all threads. */ + if (self == __pthread_main_thread) + { +#ifdef USE_TLS + waitpid(manager_thread->p_pid, NULL, __WCLONE); +#else + waitpid(__pthread_manager_thread.p_pid, NULL, __WCLONE); +#endif + /* Since all threads have been asynchronously terminated + (possibly holding locks), free cannot be used any more. + For mtrace, we'd like to print something though. */ + /* #ifdef USE_TLS + tcbhead_t *tcbp = (tcbhead_t *) manager_thread; + # if TLS_DTV_AT_TP + tcbp = (tcbhead_t) ((char *) tcbp + TLS_PRE_TCB_SIZE); + # endif + _dl_deallocate_tls (tcbp, true); + #endif + free (__pthread_manager_thread_bos); */ + __pthread_manager_thread_bos = __pthread_manager_thread_tos = NULL; + } + } +} + +#ifndef HAVE_Z_NODELETE +static int __pthread_atexit_retcode; + +static void pthread_atexit_process(void *arg, int retcode) +{ + pthread_onexit_process (retcode ?: __pthread_atexit_retcode, arg); +} + +static void pthread_atexit_retcode(void *arg, int retcode) +{ + __pthread_atexit_retcode = retcode; +} +#endif + +/* The handler for the RESTART signal just records the signal received + in the thread descriptor, and optionally performs a siglongjmp + (for pthread_cond_timedwait). */ + +static void pthread_handle_sigrestart(int sig) +{ + pthread_descr self = check_thread_self(); + THREAD_SETMEM(self, p_signal, sig); + if (THREAD_GETMEM(self, p_signal_jmp) != NULL) + siglongjmp(*THREAD_GETMEM(self, p_signal_jmp), 1); +} + +/* The handler for the CANCEL signal checks for cancellation + (in asynchronous mode), for process-wide exit and exec requests. + For the thread manager thread, redirect the signal to + __pthread_manager_sighandler. */ + +static void pthread_handle_sigcancel(int sig) +{ + pthread_descr self = check_thread_self(); + sigjmp_buf * jmpbuf; + + if (self == manager_thread) + { + __pthread_manager_sighandler(sig); + return; + } + if (__builtin_expect (__pthread_exit_requested, 0)) { + /* Main thread should accumulate times for thread manager and its + children, so that timings for main thread account for all threads. */ + if (self == __pthread_main_thread) { +#ifdef USE_TLS + waitpid(manager_thread->p_pid, NULL, __WCLONE); +#else + waitpid(__pthread_manager_thread.p_pid, NULL, __WCLONE); +#endif + } + _exit(__pthread_exit_code); + } + if (__builtin_expect (THREAD_GETMEM(self, p_canceled), 0) + && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) { + if (THREAD_GETMEM(self, p_canceltype) == PTHREAD_CANCEL_ASYNCHRONOUS) + __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME); + jmpbuf = THREAD_GETMEM(self, p_cancel_jmp); + if (jmpbuf != NULL) { + THREAD_SETMEM(self, p_cancel_jmp, NULL); + siglongjmp(*jmpbuf, 1); + } + } +} + +/* Handler for the DEBUG signal. + The debugging strategy is as follows: + On reception of a REQ_DEBUG request (sent by new threads created to + the thread manager under debugging mode), the thread manager throws + __pthread_sig_debug to itself. The debugger (if active) intercepts + this signal, takes into account new threads and continue execution + of the thread manager by propagating the signal because it doesn't + know what it is specifically done for. In the current implementation, + the thread manager simply discards it. */ + +static void pthread_handle_sigdebug(int sig) +{ + /* Nothing */ +} + +/* Reset the state of the thread machinery after a fork(). + Close the pipe used for requests and set the main thread to the forked + thread. + Notice that we can't free the stack segments, as the forked thread + may hold pointers into them. */ + +void __pthread_reset_main_thread(void) +{ + pthread_descr self = thread_self(); + + if (__pthread_manager_request != -1) { + /* Free the thread manager stack */ + free(__pthread_manager_thread_bos); + __pthread_manager_thread_bos = __pthread_manager_thread_tos = NULL; + /* Close the two ends of the pipe */ + close_not_cancel(__pthread_manager_request); + close_not_cancel(__pthread_manager_reader); + __pthread_manager_request = __pthread_manager_reader = -1; + } + + /* Update the pid of the main thread */ + THREAD_SETMEM(self, p_pid, __getpid()); + /* Make the forked thread the main thread */ + __pthread_main_thread = self; + THREAD_SETMEM(self, p_nextlive, self); + THREAD_SETMEM(self, p_prevlive, self); +#if !(USE_TLS && HAVE___THREAD) + /* Now this thread modifies the global variables. */ + THREAD_SETMEM(self, p_errnop, &_errno); + THREAD_SETMEM(self, p_h_errnop, &_h_errno); + THREAD_SETMEM(self, p_resp, &_res); +#endif + +#ifndef FLOATING_STACKS + /* This is to undo the setrlimit call in __pthread_init_max_stacksize. + XXX This can be wrong if the user set the limit during the run. */ + { + struct rlimit limit; + if (getrlimit (RLIMIT_STACK, &limit) == 0 + && limit.rlim_cur != limit.rlim_max) + { + limit.rlim_cur = limit.rlim_max; + setrlimit(RLIMIT_STACK, &limit); + } + } +#endif +} + +/* Process-wide exec() request */ + +void __pthread_kill_other_threads_np(void) +{ + struct sigaction sa; + /* Terminate all other threads and thread manager */ + pthread_onexit_process(0, NULL); + /* Make current thread the main thread in case the calling thread + changes its mind, does not exec(), and creates new threads instead. */ + __pthread_reset_main_thread(); + + /* Reset the signal handlers behaviour for the signals the + implementation uses since this would be passed to the new + process. */ + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + sa.sa_handler = SIG_DFL; + __libc_sigaction(__pthread_sig_restart, &sa, NULL); + __libc_sigaction(__pthread_sig_cancel, &sa, NULL); + if (__pthread_sig_debug > 0) + __libc_sigaction(__pthread_sig_debug, &sa, NULL); +} +weak_alias (__pthread_kill_other_threads_np, pthread_kill_other_threads_np) + +/* Concurrency symbol level. */ +static int current_level; + +int __pthread_setconcurrency(int level) +{ + /* We don't do anything unless we have found a useful interpretation. */ + current_level = level; + return 0; +} +weak_alias (__pthread_setconcurrency, pthread_setconcurrency) + +int __pthread_getconcurrency(void) +{ + return current_level; +} +weak_alias (__pthread_getconcurrency, pthread_getconcurrency) + +/* Primitives for controlling thread execution */ + +void __pthread_wait_for_restart_signal(pthread_descr self) +{ + sigset_t mask; + + sigprocmask(SIG_SETMASK, NULL, &mask); /* Get current signal mask */ + sigdelset(&mask, __pthread_sig_restart); /* Unblock the restart signal */ + THREAD_SETMEM(self, p_signal, 0); + do { + __pthread_sigsuspend(&mask); /* Wait for signal. Must not be a + cancellation point. */ + } while (THREAD_GETMEM(self, p_signal) !=__pthread_sig_restart); + + READ_MEMORY_BARRIER(); /* See comment in __pthread_restart_new */ +} + +#if !__ASSUME_REALTIME_SIGNALS +/* The _old variants are for 2.0 and early 2.1 kernels which don't have RT + signals. + On these kernels, we use SIGUSR1 and SIGUSR2 for restart and cancellation. + Since the restart signal does not queue, we use an atomic counter to create + queuing semantics. This is needed to resolve a rare race condition in + pthread_cond_timedwait_relative. */ + +void __pthread_restart_old(pthread_descr th) +{ + if (atomic_increment(&th->p_resume_count) == -1) + kill(th->p_pid, __pthread_sig_restart); +} + +void __pthread_suspend_old(pthread_descr self) +{ + if (atomic_decrement(&self->p_resume_count) <= 0) + __pthread_wait_for_restart_signal(self); +} + +int +__pthread_timedsuspend_old(pthread_descr self, const struct timespec *abstime) +{ + sigset_t unblock, initial_mask; + int was_signalled = 0; + sigjmp_buf jmpbuf; + + if (atomic_decrement(&self->p_resume_count) == 0) { + /* Set up a longjmp handler for the restart signal, unblock + the signal and sleep. */ + + if (sigsetjmp(jmpbuf, 1) == 0) { + THREAD_SETMEM(self, p_signal_jmp, &jmpbuf); + THREAD_SETMEM(self, p_signal, 0); + /* Unblock the restart signal */ + sigemptyset(&unblock); + sigaddset(&unblock, __pthread_sig_restart); + sigprocmask(SIG_UNBLOCK, &unblock, &initial_mask); + + while (1) { + struct timeval now; + struct timespec reltime; + + /* Compute a time offset relative to now. */ + __gettimeofday (&now, NULL); + reltime.tv_nsec = abstime->tv_nsec - now.tv_usec * 1000; + reltime.tv_sec = abstime->tv_sec - now.tv_sec; + if (reltime.tv_nsec < 0) { + reltime.tv_nsec += 1000000000; + reltime.tv_sec -= 1; + } + + /* Sleep for the required duration. If woken by a signal, + resume waiting as required by Single Unix Specification. */ + if (reltime.tv_sec < 0 || __libc_nanosleep(&reltime, NULL) == 0) + break; + } + + /* Block the restart signal again */ + sigprocmask(SIG_SETMASK, &initial_mask, NULL); + was_signalled = 0; + } else { + was_signalled = 1; + } + THREAD_SETMEM(self, p_signal_jmp, NULL); + } + + /* Now was_signalled is true if we exited the above code + due to the delivery of a restart signal. In that case, + we know we have been dequeued and resumed and that the + resume count is balanced. Otherwise, there are some + cases to consider. First, try to bump up the resume count + back to zero. If it goes to 1, it means restart() was + invoked on this thread. The signal must be consumed + and the count bumped down and everything is cool. We + can return a 1 to the caller. + Otherwise, no restart was delivered yet, so a potential + race exists; we return a 0 to the caller which must deal + with this race in an appropriate way; for example by + atomically removing the thread from consideration for a + wakeup---if such a thing fails, it means a restart is + being delivered. */ + + if (!was_signalled) { + if (atomic_increment(&self->p_resume_count) != -1) { + __pthread_wait_for_restart_signal(self); + atomic_decrement(&self->p_resume_count); /* should be zero now! */ + /* woke spontaneously and consumed restart signal */ + return 1; + } + /* woke spontaneously but did not consume restart---caller must resolve */ + return 0; + } + /* woken due to restart signal */ + return 1; +} +#endif /* __ASSUME_REALTIME_SIGNALS */ + +void __pthread_restart_new(pthread_descr th) +{ + /* The barrier is proabably not needed, in which case it still documents + our assumptions. The intent is to commit previous writes to shared + memory so the woken thread will have a consistent view. Complementary + read barriers are present to the suspend functions. */ + WRITE_MEMORY_BARRIER(); + kill(th->p_pid, __pthread_sig_restart); +} + +/* There is no __pthread_suspend_new because it would just + be a wasteful wrapper for __pthread_wait_for_restart_signal */ + +int +__pthread_timedsuspend_new(pthread_descr self, const struct timespec *abstime) +{ + sigset_t unblock, initial_mask; + int was_signalled = 0; + sigjmp_buf jmpbuf; + + if (sigsetjmp(jmpbuf, 1) == 0) { + THREAD_SETMEM(self, p_signal_jmp, &jmpbuf); + THREAD_SETMEM(self, p_signal, 0); + /* Unblock the restart signal */ + sigemptyset(&unblock); + sigaddset(&unblock, __pthread_sig_restart); + sigprocmask(SIG_UNBLOCK, &unblock, &initial_mask); + + while (1) { + struct timeval now; + struct timespec reltime; + + /* Compute a time offset relative to now. */ + __gettimeofday (&now, NULL); + reltime.tv_nsec = abstime->tv_nsec - now.tv_usec * 1000; + reltime.tv_sec = abstime->tv_sec - now.tv_sec; + if (reltime.tv_nsec < 0) { + reltime.tv_nsec += 1000000000; + reltime.tv_sec -= 1; + } + + /* Sleep for the required duration. If woken by a signal, + resume waiting as required by Single Unix Specification. */ + if (reltime.tv_sec < 0 || __libc_nanosleep(&reltime, NULL) == 0) + break; + } + + /* Block the restart signal again */ + sigprocmask(SIG_SETMASK, &initial_mask, NULL); + was_signalled = 0; + } else { + was_signalled = 1; + } + THREAD_SETMEM(self, p_signal_jmp, NULL); + + /* Now was_signalled is true if we exited the above code + due to the delivery of a restart signal. In that case, + everything is cool. We have been removed from whatever + we were waiting on by the other thread, and consumed its signal. + + Otherwise we this thread woke up spontaneously, or due to a signal other + than restart. This is an ambiguous case that must be resolved by + the caller; the thread is still eligible for a restart wakeup + so there is a race. */ + + READ_MEMORY_BARRIER(); /* See comment in __pthread_restart_new */ + return was_signalled; +} + + +/* Debugging aid */ + +#ifdef DEBUG +#include <stdarg.h> + +void __pthread_message(const char * fmt, ...) +{ + char buffer[1024]; + va_list args; + sprintf(buffer, "%05d : ", __getpid()); + va_start(args, fmt); + vsnprintf(buffer + 8, sizeof(buffer) - 8, fmt, args); + va_end(args); + TEMP_FAILURE_RETRY(write_not_cancel(2, buffer, strlen(buffer))); +} + +#endif diff --git a/linuxthreads/pthread_atfork.c b/linuxthreads/pthread_atfork.c new file mode 100644 index 0000000000..2464acb6b2 --- /dev/null +++ b/linuxthreads/pthread_atfork.c @@ -0,0 +1,63 @@ +/* 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 "internals.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 +#ifndef __pthread_atfork +/* Don't mark the compatibility function as hidden. */ +attribute_hidden +#endif +__pthread_atfork (prepare, parent, child) + void (*prepare) (void); + void (*parent) (void); + void (*child) (void); +{ + return __register_atfork (prepare, parent, child, + &__dso_handle == NULL ? NULL : __dso_handle); +} +#ifndef __pthread_atfork +extern int pthread_atfork (void (*prepare) (void), void (*parent) (void), + void (*child) (void)) attribute_hidden; +strong_alias (__pthread_atfork, pthread_atfork) +#endif diff --git a/linuxthreads/pthread_setegid.c b/linuxthreads/pthread_setegid.c new file mode 100644 index 0000000000..9e16828fa5 --- /dev/null +++ b/linuxthreads/pthread_setegid.c @@ -0,0 +1,27 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <unistd.h> + + +int +pthread_setegid_np (gid_t gid) +{ + return setegid (gid); +} diff --git a/linuxthreads/pthread_seteuid.c b/linuxthreads/pthread_seteuid.c new file mode 100644 index 0000000000..9d29d81118 --- /dev/null +++ b/linuxthreads/pthread_seteuid.c @@ -0,0 +1,27 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <unistd.h> + + +int +pthread_seteuid_np (uid_t uid) +{ + return seteuid (uid); +} diff --git a/linuxthreads/pthread_setgid.c b/linuxthreads/pthread_setgid.c new file mode 100644 index 0000000000..db37dd1465 --- /dev/null +++ b/linuxthreads/pthread_setgid.c @@ -0,0 +1,27 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <unistd.h> + + +int +pthread_setgid_np (gid_t gid) +{ + return setgid (gid); +} diff --git a/linuxthreads/pthread_setregid.c b/linuxthreads/pthread_setregid.c new file mode 100644 index 0000000000..bd75154c50 --- /dev/null +++ b/linuxthreads/pthread_setregid.c @@ -0,0 +1,27 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <unistd.h> + + +int +pthread_setregid_np (gid_t rgid, gid_t egid) +{ + return setregid (rgid, egid); +} diff --git a/linuxthreads/pthread_setresgid.c b/linuxthreads/pthread_setresgid.c new file mode 100644 index 0000000000..b5702804ee --- /dev/null +++ b/linuxthreads/pthread_setresgid.c @@ -0,0 +1,27 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <unistd.h> + + +int +pthread_setresgid_np (gid_t rgid, gid_t egid, gid_t sgid) +{ + return setresgid (rgid, egid, sgid); +} diff --git a/linuxthreads/pthread_setresuid.c b/linuxthreads/pthread_setresuid.c new file mode 100644 index 0000000000..ceb724deaf --- /dev/null +++ b/linuxthreads/pthread_setresuid.c @@ -0,0 +1,27 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <unistd.h> + + +int +pthread_setresuid_np (uid_t ruid, uid_t euid, uid_t suid) +{ + return setresuid (ruid, euid, suid); +} diff --git a/linuxthreads/pthread_setreuid.c b/linuxthreads/pthread_setreuid.c new file mode 100644 index 0000000000..ae8933ece5 --- /dev/null +++ b/linuxthreads/pthread_setreuid.c @@ -0,0 +1,27 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <unistd.h> + + +int +pthread_setreuid_np (uid_t ruid, uid_t euid) +{ + return setreuid (ruid, euid); +} diff --git a/linuxthreads/pthread_setuid.c b/linuxthreads/pthread_setuid.c new file mode 100644 index 0000000000..f82ccc1a2f --- /dev/null +++ b/linuxthreads/pthread_setuid.c @@ -0,0 +1,27 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <unistd.h> + + +int +pthread_setuid_np (uid_t uid) +{ + return setuid (uid); +} diff --git a/linuxthreads/queue.h b/linuxthreads/queue.h new file mode 100644 index 0000000000..28bd75531c --- /dev/null +++ b/linuxthreads/queue.h @@ -0,0 +1,61 @@ +/* Linuxthreads - a simple clone()-based implementation of Posix */ +/* threads for Linux. */ +/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ +/* */ +/* This program is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public License */ +/* as published by the Free Software Foundation; either version 2 */ +/* of the License, or (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Library General Public License for more details. */ + +/* Waiting queues */ + +/* Waiting queues are represented by lists of thread descriptors + linked through their p_nextwaiting field. The lists are kept + sorted by decreasing priority, and then decreasing waiting time. */ + +static inline void enqueue(pthread_descr * q, pthread_descr th) +{ + int prio = th->p_priority; + ASSERT(th->p_nextwaiting == NULL); + for (; *q != NULL; q = &((*q)->p_nextwaiting)) { + if (prio > (*q)->p_priority) { + th->p_nextwaiting = *q; + *q = th; + return; + } + } + *q = th; +} + +static inline pthread_descr dequeue(pthread_descr * q) +{ + pthread_descr th; + th = *q; + if (th != NULL) { + *q = th->p_nextwaiting; + th->p_nextwaiting = NULL; + } + return th; +} + +static inline int remove_from_queue(pthread_descr * q, pthread_descr th) +{ + for (; *q != NULL; q = &((*q)->p_nextwaiting)) { + if (*q == th) { + *q = th->p_nextwaiting; + th->p_nextwaiting = NULL; + return 1; + } + } + return 0; +} + +static inline int queue_is_empty(pthread_descr * q) +{ + return *q == NULL; +} diff --git a/linuxthreads/restart.h b/linuxthreads/restart.h new file mode 100644 index 0000000000..24d9fab748 --- /dev/null +++ b/linuxthreads/restart.h @@ -0,0 +1,49 @@ +/* Linuxthreads - a simple clone()-based implementation of Posix */ +/* threads for Linux. */ +/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ +/* */ +/* This program is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public License */ +/* as published by the Free Software Foundation; either version 2 */ +/* of the License, or (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Library General Public License for more details. */ + +#include <signal.h> +#include <kernel-features.h> + +/* Primitives for controlling thread execution */ + +static inline void restart(pthread_descr th) +{ + /* See pthread.c */ +#if __ASSUME_REALTIME_SIGNALS + __pthread_restart_new(th); +#else + __pthread_restart(th); +#endif +} + +static inline void suspend(pthread_descr self) +{ + /* See pthread.c */ +#if __ASSUME_REALTIME_SIGNALS + __pthread_wait_for_restart_signal(self); +#else + __pthread_suspend(self); +#endif +} + +static inline int timedsuspend(pthread_descr self, + const struct timespec *abstime) +{ + /* See pthread.c */ +#if __ASSUME_REALTIME_SIGNALS + return __pthread_timedsuspend_new(self, abstime); +#else + return __pthread_timedsuspend(self, abstime); +#endif +} diff --git a/linuxthreads/rwlock.c b/linuxthreads/rwlock.c new file mode 100644 index 0000000000..f565f18706 --- /dev/null +++ b/linuxthreads/rwlock.c @@ -0,0 +1,658 @@ +/* Read-write lock implementation. + Copyright (C) 1998, 2000 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Xavier Leroy <Xavier.Leroy@inria.fr> + and Ulrich Drepper <drepper@cygnus.com>, 1998. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General 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 <bits/libc-lock.h> +#include <errno.h> +#include <pthread.h> +#include <stdlib.h> +#include "internals.h" +#include "queue.h" +#include "spinlock.h" +#include "restart.h" + +/* Function called by pthread_cancel to remove the thread from + waiting inside pthread_rwlock_timedrdlock or pthread_rwlock_timedwrlock. */ + +static int rwlock_rd_extricate_func(void *obj, pthread_descr th) +{ + pthread_rwlock_t *rwlock = obj; + int did_remove = 0; + + __pthread_lock(&rwlock->__rw_lock, NULL); + did_remove = remove_from_queue(&rwlock->__rw_read_waiting, th); + __pthread_unlock(&rwlock->__rw_lock); + + return did_remove; +} + +static int rwlock_wr_extricate_func(void *obj, pthread_descr th) +{ + pthread_rwlock_t *rwlock = obj; + int did_remove = 0; + + __pthread_lock(&rwlock->__rw_lock, NULL); + did_remove = remove_from_queue(&rwlock->__rw_write_waiting, th); + __pthread_unlock(&rwlock->__rw_lock); + + return did_remove; +} + +/* + * Check whether the calling thread already owns one or more read locks on the + * specified lock. If so, return a pointer to the read lock info structure + * corresponding to that lock. + */ + +static pthread_readlock_info * +rwlock_is_in_list(pthread_descr self, pthread_rwlock_t *rwlock) +{ + pthread_readlock_info *info; + + for (info = THREAD_GETMEM (self, p_readlock_list); info != NULL; + info = info->pr_next) + { + if (info->pr_lock == rwlock) + return info; + } + + return NULL; +} + +/* + * Add a new lock to the thread's list of locks for which it has a read lock. + * A new info node must be allocated for this, which is taken from the thread's + * free list, or by calling malloc. If malloc fails, a null pointer is + * returned. Otherwise the lock info structure is initialized and pushed + * onto the thread's list. + */ + +static pthread_readlock_info * +rwlock_add_to_list(pthread_descr self, pthread_rwlock_t *rwlock) +{ + pthread_readlock_info *info = THREAD_GETMEM (self, p_readlock_free); + + if (info != NULL) + THREAD_SETMEM (self, p_readlock_free, info->pr_next); + else + info = malloc(sizeof *info); + + if (info == NULL) + return NULL; + + info->pr_lock_count = 1; + info->pr_lock = rwlock; + info->pr_next = THREAD_GETMEM (self, p_readlock_list); + THREAD_SETMEM (self, p_readlock_list, info); + + return info; +} + +/* + * If the thread owns a read lock over the given pthread_rwlock_t, + * and this read lock is tracked in the thread's lock list, + * this function returns a pointer to the info node in that list. + * It also decrements the lock count within that node, and if + * it reaches zero, it removes the node from the list. + * If nothing is found, it returns a null pointer. + */ + +static pthread_readlock_info * +rwlock_remove_from_list(pthread_descr self, pthread_rwlock_t *rwlock) +{ + pthread_readlock_info **pinfo; + + for (pinfo = &self->p_readlock_list; *pinfo != NULL; pinfo = &(*pinfo)->pr_next) + { + if ((*pinfo)->pr_lock == rwlock) + { + pthread_readlock_info *info = *pinfo; + if (--info->pr_lock_count == 0) + *pinfo = info->pr_next; + return info; + } + } + + return NULL; +} + +/* + * This function checks whether the conditions are right to place a read lock. + * It returns 1 if so, otherwise zero. The rwlock's internal lock must be + * locked upon entry. + */ + +static int +rwlock_can_rdlock(pthread_rwlock_t *rwlock, int have_lock_already) +{ + /* Can't readlock; it is write locked. */ + if (rwlock->__rw_writer != NULL) + return 0; + + /* Lock prefers readers; get it. */ + if (rwlock->__rw_kind == PTHREAD_RWLOCK_PREFER_READER_NP) + return 1; + + /* Lock prefers writers, but none are waiting. */ + if (queue_is_empty(&rwlock->__rw_write_waiting)) + return 1; + + /* Writers are waiting, but this thread already has a read lock */ + if (have_lock_already) + return 1; + + /* Writers are waiting, and this is a new lock */ + return 0; +} + +/* + * This function helps support brain-damaged recursive read locking + * semantics required by Unix 98, while maintaining write priority. + * This basically determines whether this thread already holds a read lock + * already. It returns 1 if so, otherwise it returns 0. + * + * If the thread has any ``untracked read locks'' then it just assumes + * that this lock is among them, just to be safe, and returns 1. + * + * Also, if it finds the thread's lock in the list, it sets the pointer + * referenced by pexisting to refer to the list entry. + * + * If the thread has no untracked locks, and the lock is not found + * in its list, then it is added to the list. If this fails, + * then *pout_of_mem is set to 1. + */ + +static int +rwlock_have_already(pthread_descr *pself, pthread_rwlock_t *rwlock, + pthread_readlock_info **pexisting, int *pout_of_mem) +{ + pthread_readlock_info *existing = NULL; + int out_of_mem = 0, have_lock_already = 0; + pthread_descr self = *pself; + + if (rwlock->__rw_kind == PTHREAD_RWLOCK_PREFER_WRITER_NP) + { + if (!self) + *pself = self = thread_self(); + + existing = rwlock_is_in_list(self, rwlock); + + if (existing != NULL + || THREAD_GETMEM (self, p_untracked_readlock_count) > 0) + have_lock_already = 1; + else + { + existing = rwlock_add_to_list(self, rwlock); + if (existing == NULL) + out_of_mem = 1; + } + } + + *pout_of_mem = out_of_mem; + *pexisting = existing; + + return have_lock_already; +} + +int +__pthread_rwlock_init (pthread_rwlock_t *rwlock, + const pthread_rwlockattr_t *attr) +{ + __pthread_init_lock(&rwlock->__rw_lock); + rwlock->__rw_readers = 0; + rwlock->__rw_writer = NULL; + rwlock->__rw_read_waiting = NULL; + rwlock->__rw_write_waiting = NULL; + + if (attr == NULL) + { + rwlock->__rw_kind = PTHREAD_RWLOCK_DEFAULT_NP; + rwlock->__rw_pshared = PTHREAD_PROCESS_PRIVATE; + } + else + { + rwlock->__rw_kind = attr->__lockkind; + rwlock->__rw_pshared = attr->__pshared; + } + + return 0; +} +strong_alias (__pthread_rwlock_init, pthread_rwlock_init) + + +int +__pthread_rwlock_destroy (pthread_rwlock_t *rwlock) +{ + int readers; + _pthread_descr writer; + + __pthread_lock (&rwlock->__rw_lock, NULL); + readers = rwlock->__rw_readers; + writer = rwlock->__rw_writer; + __pthread_unlock (&rwlock->__rw_lock); + + if (readers > 0 || writer != NULL) + return EBUSY; + + return 0; +} +strong_alias (__pthread_rwlock_destroy, pthread_rwlock_destroy) + +int +__pthread_rwlock_rdlock (pthread_rwlock_t *rwlock) +{ + pthread_descr self = NULL; + pthread_readlock_info *existing; + int out_of_mem, have_lock_already; + + have_lock_already = rwlock_have_already(&self, rwlock, + &existing, &out_of_mem); + + if (self == NULL) + self = thread_self (); + + for (;;) + { + __pthread_lock (&rwlock->__rw_lock, self); + + if (rwlock_can_rdlock(rwlock, have_lock_already)) + break; + + enqueue (&rwlock->__rw_read_waiting, self); + __pthread_unlock (&rwlock->__rw_lock); + suspend (self); /* This is not a cancellation point */ + } + + ++rwlock->__rw_readers; + __pthread_unlock (&rwlock->__rw_lock); + + if (have_lock_already || out_of_mem) + { + if (existing != NULL) + ++existing->pr_lock_count; + else + ++self->p_untracked_readlock_count; + } + + return 0; +} +strong_alias (__pthread_rwlock_rdlock, pthread_rwlock_rdlock) + +int +__pthread_rwlock_timedrdlock (pthread_rwlock_t *rwlock, + const struct timespec *abstime) +{ + pthread_descr self = NULL; + pthread_readlock_info *existing; + int out_of_mem, have_lock_already; + pthread_extricate_if extr; + + if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) + return EINVAL; + + have_lock_already = rwlock_have_already(&self, rwlock, + &existing, &out_of_mem); + + if (self == NULL) + self = thread_self (); + + /* Set up extrication interface */ + extr.pu_object = rwlock; + extr.pu_extricate_func = rwlock_rd_extricate_func; + + /* Register extrication interface */ + __pthread_set_own_extricate_if (self, &extr); + + for (;;) + { + __pthread_lock (&rwlock->__rw_lock, self); + + if (rwlock_can_rdlock(rwlock, have_lock_already)) + break; + + enqueue (&rwlock->__rw_read_waiting, self); + __pthread_unlock (&rwlock->__rw_lock); + /* This is not a cancellation point */ + if (timedsuspend (self, abstime) == 0) + { + int was_on_queue; + + __pthread_lock (&rwlock->__rw_lock, self); + was_on_queue = remove_from_queue (&rwlock->__rw_read_waiting, self); + __pthread_unlock (&rwlock->__rw_lock); + + if (was_on_queue) + { + __pthread_set_own_extricate_if (self, 0); + return ETIMEDOUT; + } + + /* Eat the outstanding restart() from the signaller */ + suspend (self); + } + } + + __pthread_set_own_extricate_if (self, 0); + + ++rwlock->__rw_readers; + __pthread_unlock (&rwlock->__rw_lock); + + if (have_lock_already || out_of_mem) + { + if (existing != NULL) + ++existing->pr_lock_count; + else + ++self->p_untracked_readlock_count; + } + + return 0; +} +strong_alias (__pthread_rwlock_timedrdlock, pthread_rwlock_timedrdlock) + +int +__pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock) +{ + pthread_descr self = thread_self(); + pthread_readlock_info *existing; + int out_of_mem, have_lock_already; + int retval = EBUSY; + + have_lock_already = rwlock_have_already(&self, rwlock, + &existing, &out_of_mem); + + __pthread_lock (&rwlock->__rw_lock, self); + + /* 0 is passed to here instead of have_lock_already. + This is to meet Single Unix Spec requirements: + if writers are waiting, pthread_rwlock_tryrdlock + does not acquire a read lock, even if the caller has + one or more read locks already. */ + + if (rwlock_can_rdlock(rwlock, 0)) + { + ++rwlock->__rw_readers; + retval = 0; + } + + __pthread_unlock (&rwlock->__rw_lock); + + if (retval == 0) + { + if (have_lock_already || out_of_mem) + { + if (existing != NULL) + ++existing->pr_lock_count; + else + ++self->p_untracked_readlock_count; + } + } + + return retval; +} +strong_alias (__pthread_rwlock_tryrdlock, pthread_rwlock_tryrdlock) + + +int +__pthread_rwlock_wrlock (pthread_rwlock_t *rwlock) +{ + pthread_descr self = thread_self (); + + while(1) + { + __pthread_lock (&rwlock->__rw_lock, self); + if (rwlock->__rw_readers == 0 && rwlock->__rw_writer == NULL) + { + rwlock->__rw_writer = self; + __pthread_unlock (&rwlock->__rw_lock); + return 0; + } + + /* Suspend ourselves, then try again */ + enqueue (&rwlock->__rw_write_waiting, self); + __pthread_unlock (&rwlock->__rw_lock); + suspend (self); /* This is not a cancellation point */ + } +} +strong_alias (__pthread_rwlock_wrlock, pthread_rwlock_wrlock) + + +int +__pthread_rwlock_timedwrlock (pthread_rwlock_t *rwlock, + const struct timespec *abstime) +{ + pthread_descr self; + pthread_extricate_if extr; + + if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) + return EINVAL; + + self = thread_self (); + + /* Set up extrication interface */ + extr.pu_object = rwlock; + extr.pu_extricate_func = rwlock_wr_extricate_func; + + /* Register extrication interface */ + __pthread_set_own_extricate_if (self, &extr); + + while(1) + { + __pthread_lock (&rwlock->__rw_lock, self); + + if (rwlock->__rw_readers == 0 && rwlock->__rw_writer == NULL) + { + rwlock->__rw_writer = self; + __pthread_set_own_extricate_if (self, 0); + __pthread_unlock (&rwlock->__rw_lock); + return 0; + } + + /* Suspend ourselves, then try again */ + enqueue (&rwlock->__rw_write_waiting, self); + __pthread_unlock (&rwlock->__rw_lock); + /* This is not a cancellation point */ + if (timedsuspend (self, abstime) == 0) + { + int was_on_queue; + + __pthread_lock (&rwlock->__rw_lock, self); + was_on_queue = remove_from_queue (&rwlock->__rw_write_waiting, self); + __pthread_unlock (&rwlock->__rw_lock); + + if (was_on_queue) + { + __pthread_set_own_extricate_if (self, 0); + return ETIMEDOUT; + } + + /* Eat the outstanding restart() from the signaller */ + suspend (self); + } + } +} +strong_alias (__pthread_rwlock_timedwrlock, pthread_rwlock_timedwrlock) + + +int +__pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock) +{ + int result = EBUSY; + + __pthread_lock (&rwlock->__rw_lock, NULL); + if (rwlock->__rw_readers == 0 && rwlock->__rw_writer == NULL) + { + rwlock->__rw_writer = thread_self (); + result = 0; + } + __pthread_unlock (&rwlock->__rw_lock); + + return result; +} +strong_alias (__pthread_rwlock_trywrlock, pthread_rwlock_trywrlock) + + +int +__pthread_rwlock_unlock (pthread_rwlock_t *rwlock) +{ + pthread_descr torestart; + pthread_descr th; + + __pthread_lock (&rwlock->__rw_lock, NULL); + if (rwlock->__rw_writer != NULL) + { + /* Unlocking a write lock. */ + if (rwlock->__rw_writer != thread_self ()) + { + __pthread_unlock (&rwlock->__rw_lock); + return EPERM; + } + rwlock->__rw_writer = NULL; + + if ((rwlock->__rw_kind == PTHREAD_RWLOCK_PREFER_READER_NP + && !queue_is_empty(&rwlock->__rw_read_waiting)) + || (th = dequeue(&rwlock->__rw_write_waiting)) == NULL) + { + /* Restart all waiting readers. */ + torestart = rwlock->__rw_read_waiting; + rwlock->__rw_read_waiting = NULL; + __pthread_unlock (&rwlock->__rw_lock); + while ((th = dequeue (&torestart)) != NULL) + restart (th); + } + else + { + /* Restart one waiting writer. */ + __pthread_unlock (&rwlock->__rw_lock); + restart (th); + } + } + else + { + /* Unlocking a read lock. */ + if (rwlock->__rw_readers == 0) + { + __pthread_unlock (&rwlock->__rw_lock); + return EPERM; + } + + --rwlock->__rw_readers; + if (rwlock->__rw_readers == 0) + /* Restart one waiting writer, if any. */ + th = dequeue (&rwlock->__rw_write_waiting); + else + th = NULL; + + __pthread_unlock (&rwlock->__rw_lock); + if (th != NULL) + restart (th); + + /* Recursive lock fixup */ + + if (rwlock->__rw_kind == PTHREAD_RWLOCK_PREFER_WRITER_NP) + { + pthread_descr self = thread_self(); + pthread_readlock_info *victim = rwlock_remove_from_list(self, rwlock); + + if (victim != NULL) + { + if (victim->pr_lock_count == 0) + { + victim->pr_next = THREAD_GETMEM (self, p_readlock_free); + THREAD_SETMEM (self, p_readlock_free, victim); + } + } + else + { + int val = THREAD_GETMEM (self, p_untracked_readlock_count); + if (val > 0) + THREAD_SETMEM (self, p_untracked_readlock_count, val - 1); + } + } + } + + return 0; +} +strong_alias (__pthread_rwlock_unlock, pthread_rwlock_unlock) + + + +int +pthread_rwlockattr_init (pthread_rwlockattr_t *attr) +{ + attr->__lockkind = 0; + attr->__pshared = PTHREAD_PROCESS_PRIVATE; + + return 0; +} + + +int +__pthread_rwlockattr_destroy (pthread_rwlockattr_t *attr) +{ + return 0; +} +strong_alias (__pthread_rwlockattr_destroy, pthread_rwlockattr_destroy) + + +int +pthread_rwlockattr_getpshared (const pthread_rwlockattr_t *attr, int *pshared) +{ + *pshared = attr->__pshared; + return 0; +} + + +int +pthread_rwlockattr_setpshared (pthread_rwlockattr_t *attr, int pshared) +{ + if (pshared != PTHREAD_PROCESS_PRIVATE && pshared != PTHREAD_PROCESS_SHARED) + return EINVAL; + + /* For now it is not possible to shared a conditional variable. */ + if (pshared != PTHREAD_PROCESS_PRIVATE) + return ENOSYS; + + attr->__pshared = pshared; + + return 0; +} + + +int +pthread_rwlockattr_getkind_np (const pthread_rwlockattr_t *attr, int *pref) +{ + *pref = attr->__lockkind; + return 0; +} + + +int +pthread_rwlockattr_setkind_np (pthread_rwlockattr_t *attr, int pref) +{ + if (pref != PTHREAD_RWLOCK_PREFER_READER_NP + && pref != PTHREAD_RWLOCK_PREFER_WRITER_NP + && pref != PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP + && pref != PTHREAD_RWLOCK_DEFAULT_NP) + return EINVAL; + + attr->__lockkind = pref; + + return 0; +} diff --git a/linuxthreads/semaphore.c b/linuxthreads/semaphore.c new file mode 100644 index 0000000000..017539e176 --- /dev/null +++ b/linuxthreads/semaphore.c @@ -0,0 +1,307 @@ +/* Linuxthreads - a simple clone()-based implementation of Posix */ +/* threads for Linux. */ +/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ +/* */ +/* This program is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public License */ +/* as published by the Free Software Foundation; either version 2 */ +/* of the License, or (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Library General Public License for more details. */ + +/* Semaphores a la POSIX 1003.1b */ + +#include <errno.h> +#include "pthread.h" +#include "semaphore.h" +#include "internals.h" +#include "spinlock.h" +#include "restart.h" +#include "queue.h" +#include <shlib-compat.h> +#include <not-cancel.h> + +int __new_sem_init(sem_t *sem, int pshared, unsigned int value) +{ + if (value > SEM_VALUE_MAX) { + errno = EINVAL; + return -1; + } + if (pshared) { + errno = ENOSYS; + return -1; + } + __pthread_init_lock(&sem->__sem_lock); + sem->__sem_value = value; + sem->__sem_waiting = NULL; + return 0; +} + +/* Function called by pthread_cancel to remove the thread from + waiting inside __new_sem_wait. */ + +static int new_sem_extricate_func(void *obj, pthread_descr th) +{ + volatile pthread_descr self = thread_self(); + sem_t *sem = obj; + int did_remove = 0; + + __pthread_lock(&sem->__sem_lock, self); + did_remove = remove_from_queue(&sem->__sem_waiting, th); + __pthread_unlock(&sem->__sem_lock); + + return did_remove; +} + +int __new_sem_wait(sem_t * sem) +{ + volatile pthread_descr self = thread_self(); + pthread_extricate_if extr; + int already_canceled = 0; + int spurious_wakeup_count; + + /* Set up extrication interface */ + extr.pu_object = sem; + extr.pu_extricate_func = new_sem_extricate_func; + + __pthread_lock(&sem->__sem_lock, self); + if (sem->__sem_value > 0) { + sem->__sem_value--; + __pthread_unlock(&sem->__sem_lock); + return 0; + } + /* Register extrication interface */ + THREAD_SETMEM(self, p_sem_avail, 0); + __pthread_set_own_extricate_if(self, &extr); + /* Enqueue only if not already cancelled. */ + if (!(THREAD_GETMEM(self, p_canceled) + && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE)) + enqueue(&sem->__sem_waiting, self); + else + already_canceled = 1; + __pthread_unlock(&sem->__sem_lock); + + if (already_canceled) { + __pthread_set_own_extricate_if(self, 0); + __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME); + } + + /* Wait for sem_post or cancellation, or fall through if already canceled */ + spurious_wakeup_count = 0; + while (1) + { + suspend(self); + if (THREAD_GETMEM(self, p_sem_avail) == 0 + && (THREAD_GETMEM(self, p_woken_by_cancel) == 0 + || THREAD_GETMEM(self, p_cancelstate) != PTHREAD_CANCEL_ENABLE)) + { + /* Count resumes that don't belong to us. */ + spurious_wakeup_count++; + continue; + } + break; + } + __pthread_set_own_extricate_if(self, 0); + + /* Terminate only if the wakeup came from cancellation. */ + /* Otherwise ignore cancellation because we got the semaphore. */ + + if (THREAD_GETMEM(self, p_woken_by_cancel) + && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) { + THREAD_SETMEM(self, p_woken_by_cancel, 0); + __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME); + } + /* We got the semaphore */ + return 0; +} + +int __new_sem_trywait(sem_t * sem) +{ + int retval; + + __pthread_lock(&sem->__sem_lock, NULL); + if (sem->__sem_value == 0) { + errno = EAGAIN; + retval = -1; + } else { + sem->__sem_value--; + retval = 0; + } + __pthread_unlock(&sem->__sem_lock); + return retval; +} + +int __new_sem_post(sem_t * sem) +{ + pthread_descr self = thread_self(); + pthread_descr th; + struct pthread_request request; + + if (THREAD_GETMEM(self, p_in_sighandler) == NULL) { + __pthread_lock(&sem->__sem_lock, self); + if (sem->__sem_waiting == NULL) { + if (sem->__sem_value >= SEM_VALUE_MAX) { + /* Overflow */ + errno = ERANGE; + __pthread_unlock(&sem->__sem_lock); + return -1; + } + sem->__sem_value++; + __pthread_unlock(&sem->__sem_lock); + } else { + th = dequeue(&sem->__sem_waiting); + __pthread_unlock(&sem->__sem_lock); + th->p_sem_avail = 1; + WRITE_MEMORY_BARRIER(); + restart(th); + } + } else { + /* If we're in signal handler, delegate post operation to + the thread manager. */ + if (__pthread_manager_request < 0) { + if (__pthread_initialize_manager() < 0) { + errno = EAGAIN; + return -1; + } + } + request.req_kind = REQ_POST; + request.req_args.post = sem; + TEMP_FAILURE_RETRY(write_not_cancel(__pthread_manager_request, + (char *) &request, sizeof(request))); + } + return 0; +} + +int __new_sem_getvalue(sem_t * sem, int * sval) +{ + *sval = sem->__sem_value; + return 0; +} + +int __new_sem_destroy(sem_t * sem) +{ + if (sem->__sem_waiting != NULL) { + __set_errno (EBUSY); + return -1; + } + return 0; +} + +sem_t *sem_open(const char *name, int oflag, ...) +{ + __set_errno (ENOSYS); + return SEM_FAILED; +} + +int sem_close(sem_t *sem) +{ + __set_errno (ENOSYS); + return -1; +} + +int sem_unlink(const char *name) +{ + __set_errno (ENOSYS); + return -1; +} + +int sem_timedwait(sem_t *sem, const struct timespec *abstime) +{ + pthread_descr self = thread_self(); + pthread_extricate_if extr; + int already_canceled = 0; + int spurious_wakeup_count; + + __pthread_lock(&sem->__sem_lock, self); + if (sem->__sem_value > 0) { + --sem->__sem_value; + __pthread_unlock(&sem->__sem_lock); + return 0; + } + + if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) { + /* The standard requires that if the function would block and the + time value is illegal, the function returns with an error. */ + __pthread_unlock(&sem->__sem_lock); + __set_errno (EINVAL); + return -1; + } + + /* Set up extrication interface */ + extr.pu_object = sem; + extr.pu_extricate_func = new_sem_extricate_func; + + /* Register extrication interface */ + THREAD_SETMEM(self, p_sem_avail, 0); + __pthread_set_own_extricate_if(self, &extr); + /* Enqueue only if not already cancelled. */ + if (!(THREAD_GETMEM(self, p_canceled) + && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE)) + enqueue(&sem->__sem_waiting, self); + else + already_canceled = 1; + __pthread_unlock(&sem->__sem_lock); + + if (already_canceled) { + __pthread_set_own_extricate_if(self, 0); + __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME); + } + + spurious_wakeup_count = 0; + while (1) + { + if (timedsuspend(self, abstime) == 0) { + int was_on_queue; + + /* __pthread_lock will queue back any spurious restarts that + may happen to it. */ + + __pthread_lock(&sem->__sem_lock, self); + was_on_queue = remove_from_queue(&sem->__sem_waiting, self); + __pthread_unlock(&sem->__sem_lock); + + if (was_on_queue) { + __pthread_set_own_extricate_if(self, 0); + __set_errno (ETIMEDOUT); + return -1; + } + + /* Eat the outstanding restart() from the signaller */ + suspend(self); + } + + if (THREAD_GETMEM(self, p_sem_avail) == 0 + && (THREAD_GETMEM(self, p_woken_by_cancel) == 0 + || THREAD_GETMEM(self, p_cancelstate) != PTHREAD_CANCEL_ENABLE)) + { + /* Count resumes that don't belong to us. */ + spurious_wakeup_count++; + continue; + } + break; + } + + __pthread_set_own_extricate_if(self, 0); + + /* Terminate only if the wakeup came from cancellation. */ + /* Otherwise ignore cancellation because we got the semaphore. */ + + if (THREAD_GETMEM(self, p_woken_by_cancel) + && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) { + THREAD_SETMEM(self, p_woken_by_cancel, 0); + __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME); + } + /* We got the semaphore */ + return 0; +} + + +versioned_symbol (libpthread, __new_sem_init, sem_init, GLIBC_2_1); +versioned_symbol (libpthread, __new_sem_wait, sem_wait, GLIBC_2_1); +versioned_symbol (libpthread, __new_sem_trywait, sem_trywait, GLIBC_2_1); +versioned_symbol (libpthread, __new_sem_post, sem_post, GLIBC_2_1); +versioned_symbol (libpthread, __new_sem_getvalue, sem_getvalue, GLIBC_2_1); +versioned_symbol (libpthread, __new_sem_destroy, sem_destroy, GLIBC_2_1); diff --git a/linuxthreads/semaphore.h b/linuxthreads/semaphore.h new file mode 100644 index 0000000000..8407007d0b --- /dev/null +++ b/linuxthreads/semaphore.h @@ -0,0 +1,87 @@ +/* Linuxthreads - a simple clone()-based implementation of Posix */ +/* threads for Linux. */ +/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ +/* */ +/* This program is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public License */ +/* as published by the Free Software Foundation; either version 2 */ +/* of the License, or (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Library General Public License for more details. */ + +#ifndef _SEMAPHORE_H +#define _SEMAPHORE_H 1 + +#include <features.h> +#include <sys/types.h> +#ifdef __USE_XOPEN2K +# define __need_timespec +# include <time.h> +#endif + +#ifndef _PTHREAD_DESCR_DEFINED +/* Thread descriptors. Needed for `sem_t' definition. */ +typedef struct _pthread_descr_struct *_pthread_descr; +# define _PTHREAD_DESCR_DEFINED +#endif + +/* System specific semaphore definition. */ +typedef struct +{ + struct _pthread_fastlock __sem_lock; + int __sem_value; + _pthread_descr __sem_waiting; +} sem_t; + + + +/* Value returned if `sem_open' failed. */ +#define SEM_FAILED ((sem_t *) 0) + +/* Maximum value the semaphore can have. */ +#define SEM_VALUE_MAX (2147483647) + + +__BEGIN_DECLS + +/* Initialize semaphore object SEM to VALUE. If PSHARED then share it + with other processes. */ +extern int sem_init (sem_t *__sem, int __pshared, unsigned int __value) __THROW; + +/* Free resources associated with semaphore object SEM. */ +extern int sem_destroy (sem_t *__sem) __THROW; + +/* Open a named semaphore NAME with open flaot OFLAG. */ +extern sem_t *sem_open (__const char *__name, int __oflag, ...) __THROW; + +/* Close descriptor for named semaphore SEM. */ +extern int sem_close (sem_t *__sem) __THROW; + +/* Remove named semaphore NAME. */ +extern int sem_unlink (__const char *__name) __THROW; + +/* Wait for SEM being posted. */ +extern int sem_wait (sem_t *__sem); + +#ifdef __USE_XOPEN2K +/* Similar to `sem_wait' but wait only until ABSTIME. */ +extern int sem_timedwait (sem_t *__restrict __sem, + __const struct timespec *__restrict __abstime); +#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/linuxthreads/shlib-versions b/linuxthreads/shlib-versions new file mode 100644 index 0000000000..58488ce65c --- /dev/null +++ b/linuxthreads/shlib-versions @@ -0,0 +1,11 @@ +# Xavier Leroy's Linux clone based thread library. +mips.*-.*-linux.* libpthread=0 GLIBC_2.0 GLIBC_2.2 +sparc64-.*-linux.* libpthread=0 GLIBC_2.2 +sh.*-.*-linux.* libpthread=0 GLIBC_2.2 +ia64.*-.*-linux.* libpthread=0 GLIBC_2.2 +hppa.*-.*-linux.* libpthread=0 GLIBC_2.2 +s390x-.*-linux.* libpthread=0 GLIBC_2.2 +cris-.*-linux.* libpthread=0 GLIBC_2.2 +x86_64-.*-linux.* libpthread=0 GLIBC_2.2.5 +powerpc64-.*-linux.* libpthread=0 GLIBC_2.3 +.*-.*-linux.* libpthread=0 diff --git a/linuxthreads/sighandler.c b/linuxthreads/sighandler.c new file mode 100644 index 0000000000..9dd3e228f6 --- /dev/null +++ b/linuxthreads/sighandler.c @@ -0,0 +1,71 @@ +/* Linuxthreads - a simple clone()-based implementation of Posix */ +/* threads for Linux. */ +/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ +/* */ +/* This program is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public License */ +/* as published by the Free Software Foundation; either version 2 */ +/* of the License, or (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Library General Public License for more details. */ + +/* Signal handlers */ + +#include "internals.h" + + +/* The wrapper around user-provided signal handlers */ +void __pthread_sighandler(int signo, SIGCONTEXT ctx) +{ + pthread_descr self; + char * in_sighandler; + self = check_thread_self(); + + /* If we're in a sigwait operation, just record the signal received + and return without calling the user's handler */ + if (THREAD_GETMEM(self, p_sigwaiting)) { + THREAD_SETMEM(self, p_sigwaiting, 0); + THREAD_SETMEM(self, p_signal, signo); + return; + } + /* Record that we're in a signal handler and call the user's + handler function */ + in_sighandler = THREAD_GETMEM(self, p_in_sighandler); + if (in_sighandler == NULL) + THREAD_SETMEM(self, p_in_sighandler, CURRENT_STACK_FRAME); + CALL_SIGHANDLER(__sighandler[signo].old, signo, ctx); + if (in_sighandler == NULL) + THREAD_SETMEM(self, p_in_sighandler, NULL); +} + +/* The same, this time for real-time signals. */ +void __pthread_sighandler_rt(int signo, struct siginfo *si, + struct ucontext *uc) +{ + pthread_descr self; + char * in_sighandler; + self = check_thread_self(); + + /* If we're in a sigwait operation, just record the signal received + and return without calling the user's handler */ + if (THREAD_GETMEM(self, p_sigwaiting)) { + THREAD_SETMEM(self, p_sigwaiting, 0); + THREAD_SETMEM(self, p_signal, signo); + return; + } + /* Record that we're in a signal handler and call the user's + handler function */ + in_sighandler = THREAD_GETMEM(self, p_in_sighandler); + if (in_sighandler == NULL) + THREAD_SETMEM(self, p_in_sighandler, CURRENT_STACK_FRAME); + __sighandler[signo].rt(signo, si, uc); + if (in_sighandler == NULL) + THREAD_SETMEM(self, p_in_sighandler, NULL); +} + + +/* A signal handler that does nothing */ +void __pthread_null_sighandler(int sig) { } diff --git a/linuxthreads/signals.c b/linuxthreads/signals.c new file mode 100644 index 0000000000..50f55995a3 --- /dev/null +++ b/linuxthreads/signals.c @@ -0,0 +1,213 @@ +/* Linuxthreads - a simple clone()-based implementation of Posix */ +/* threads for Linux. */ +/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ +/* */ +/* This program is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public License */ +/* as published by the Free Software Foundation; either version 2 */ +/* of the License, or (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Library General Public License for more details. */ + +/* Handling of signals */ + +#include <errno.h> +#include <signal.h> +#include "pthread.h" +#include "internals.h" +#include "spinlock.h" +#include <ucontext.h> + + +int pthread_sigmask(int how, const sigset_t * newmask, sigset_t * oldmask) +{ + sigset_t mask; + + if (newmask != NULL) { + mask = *newmask; + /* Don't allow __pthread_sig_restart to be unmasked. + Don't allow __pthread_sig_cancel to be masked. */ + switch(how) { + case SIG_SETMASK: + sigaddset(&mask, __pthread_sig_restart); + sigdelset(&mask, __pthread_sig_cancel); + if (__pthread_sig_debug > 0) + sigdelset(&mask, __pthread_sig_debug); + break; + case SIG_BLOCK: + sigdelset(&mask, __pthread_sig_cancel); + if (__pthread_sig_debug > 0) + sigdelset(&mask, __pthread_sig_debug); + break; + case SIG_UNBLOCK: + sigdelset(&mask, __pthread_sig_restart); + break; + } + newmask = &mask; + } + if (sigprocmask(how, newmask, oldmask) == -1) + return errno; + else + return 0; +} + +int pthread_kill(pthread_t thread, int signo) +{ + pthread_handle handle = thread_handle(thread); + int pid; + + __pthread_lock(&handle->h_lock, NULL); + if (invalid_handle(handle, thread)) { + __pthread_unlock(&handle->h_lock); + return ESRCH; + } + pid = handle->h_descr->p_pid; + __pthread_unlock(&handle->h_lock); + if (kill(pid, signo) == -1) + return errno; + else + return 0; +} + +union sighandler __sighandler[NSIG] = + { [1 ... NSIG - 1] = { (arch_sighandler_t) SIG_ERR } }; + +/* The wrapper around sigaction. Install our own signal handler + around the signal. */ +int __pthread_sigaction(int sig, const struct sigaction * act, + struct sigaction * oact) +{ + struct sigaction newact; + struct sigaction *newactp; + __sighandler_t old = SIG_DFL; + + if (sig == __pthread_sig_restart || + sig == __pthread_sig_cancel || + (sig == __pthread_sig_debug && __pthread_sig_debug > 0)) + { + __set_errno (EINVAL); + return -1; + } + if (sig > 0 && sig < NSIG) + old = (__sighandler_t) __sighandler[sig].old; + if (act) + { + newact = *act; + if (act->sa_handler != SIG_IGN && act->sa_handler != SIG_DFL + && sig > 0 && sig < NSIG) + { + if (act->sa_flags & SA_SIGINFO) + newact.sa_handler = (__sighandler_t) __pthread_sighandler_rt; + else + newact.sa_handler = (__sighandler_t) __pthread_sighandler; + if (old == SIG_IGN || old == SIG_DFL || old == SIG_ERR) + __sighandler[sig].old = (arch_sighandler_t) act->sa_handler; + } + newactp = &newact; + } + else + newactp = NULL; + if (__libc_sigaction(sig, newactp, oact) == -1) + { + if (act) + __sighandler[sig].old = (arch_sighandler_t) old; + return -1; + } + if (sig > 0 && sig < NSIG) + { + if (oact != NULL + /* We may have inherited SIG_IGN from the parent, so return the + kernel's idea of the signal handler the first time + through. */ + && old != SIG_ERR) + oact->sa_handler = old; + if (act) + /* For the assignment it does not matter whether it's a normal + or real-time signal. */ + __sighandler[sig].old = (arch_sighandler_t) act->sa_handler; + } + return 0; +} +#ifdef SHARED +strong_alias(__pthread_sigaction, __sigaction) +strong_alias(__pthread_sigaction, sigaction) +#endif + +/* sigwait -- synchronously wait for a signal */ +int __pthread_sigwait(const sigset_t * set, int * sig) +{ + volatile pthread_descr self = thread_self(); + sigset_t mask; + int s; + sigjmp_buf jmpbuf; + struct sigaction sa; + + /* Get ready to block all signals except those in set + and the cancellation signal. + Also check that handlers are installed on all signals in set, + and if not, install our dummy handler. This is conformant to + POSIX: "The effect of sigwait() on the signal actions for the + signals in set is unspecified." */ + sigfillset(&mask); + sigdelset(&mask, __pthread_sig_cancel); + for (s = 1; s < NSIG; s++) { + if (sigismember(set, s) && + s != __pthread_sig_restart && + s != __pthread_sig_cancel && + s != __pthread_sig_debug) { + sigdelset(&mask, s); + if (__sighandler[s].old == (arch_sighandler_t) SIG_ERR || + __sighandler[s].old == (arch_sighandler_t) SIG_DFL || + __sighandler[s].old == (arch_sighandler_t) SIG_IGN) { + sa.sa_handler = __pthread_null_sighandler; + sigfillset(&sa.sa_mask); + sa.sa_flags = 0; + sigaction(s, &sa, NULL); + } + } + } + /* Test for cancellation */ + if (sigsetjmp(jmpbuf, 1) == 0) { + THREAD_SETMEM(self, p_cancel_jmp, &jmpbuf); + if (! (THREAD_GETMEM(self, p_canceled) + && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE)) { + /* Reset the signal count */ + THREAD_SETMEM(self, p_signal, 0); + /* Say we're in sigwait */ + THREAD_SETMEM(self, p_sigwaiting, 1); + /* Unblock the signals and wait for them */ + sigsuspend(&mask); + } + } + THREAD_SETMEM(self, p_cancel_jmp, NULL); + /* The signals are now reblocked. Check for cancellation */ + pthread_testcancel(); + /* We should have self->p_signal != 0 and equal to the signal received */ + *sig = THREAD_GETMEM(self, p_signal); + return 0; +} +#ifdef SHARED +strong_alias (__pthread_sigwait, sigwait) +#endif + +/* Redefine raise() to send signal to calling thread only, + as per POSIX 1003.1c */ +int __pthread_raise (int sig) +{ + int retcode = pthread_kill(pthread_self(), sig); + if (retcode == 0) + return 0; + else { + errno = retcode; + return -1; + } +} +#ifdef SHARED +strong_alias (__pthread_raise, raise) +#endif + +/* This files handles cancellation internally. */ +LIBC_CANCEL_HANDLED (); diff --git a/linuxthreads/specific.c b/linuxthreads/specific.c new file mode 100644 index 0000000000..f54fabaeb9 --- /dev/null +++ b/linuxthreads/specific.c @@ -0,0 +1,235 @@ +/* Linuxthreads - a simple clone()-based implementation of Posix */ +/* threads for Linux. */ +/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ +/* */ +/* This program is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public License */ +/* as published by the Free Software Foundation; either version 2 */ +/* of the License, or (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Library General Public License for more details. */ + +/* Thread-specific data */ + +#include <errno.h> +#include <stddef.h> +#include <stdlib.h> +#include "pthread.h" +#include "internals.h" +#include "spinlock.h" +#include "restart.h" +#include <bits/libc-lock.h> +#include <not-cancel.h> + +/* Table of keys. */ + +static struct pthread_key_struct pthread_keys[PTHREAD_KEYS_MAX] = + { { 0, NULL } }; + +/* For debugging purposes put the maximum number of keys in a variable. */ +const int __linuxthreads_pthread_keys_max = PTHREAD_KEYS_MAX; +const int __linuxthreads_pthread_key_2ndlevel_size = PTHREAD_KEY_2NDLEVEL_SIZE; + +/* Mutex to protect access to pthread_keys */ + +static pthread_mutex_t pthread_keys_mutex = PTHREAD_MUTEX_INITIALIZER; + +/* Create a new key */ + +int __pthread_key_create(pthread_key_t * key, destr_function destr) +{ + int i; + + pthread_mutex_lock(&pthread_keys_mutex); + for (i = 0; i < PTHREAD_KEYS_MAX; i++) { + if (! pthread_keys[i].in_use) { + /* Mark key in use */ + pthread_keys[i].in_use = 1; + pthread_keys[i].destr = destr; + pthread_mutex_unlock(&pthread_keys_mutex); + *key = i; + return 0; + } + } + pthread_mutex_unlock(&pthread_keys_mutex); + return EAGAIN; +} +strong_alias (__pthread_key_create, pthread_key_create) + +/* Reset deleted key's value to NULL in each live thread. + * NOTE: this executes in the context of the thread manager! */ + +struct pthread_key_delete_helper_args { + /* Damn, we need lexical closures in C! ;) */ + unsigned int idx1st, idx2nd; + pthread_descr self; +}; + +static void pthread_key_delete_helper(void *arg, pthread_descr th) +{ + struct pthread_key_delete_helper_args *args = arg; + unsigned int idx1st = args->idx1st; + unsigned int idx2nd = args->idx2nd; + pthread_descr self = args->self; + + if (self == 0) + self = args->self = thread_self(); + + if (!th->p_terminated) { + /* pthread_exit() may try to free th->p_specific[idx1st] concurrently. */ + __pthread_lock(th->p_lock, self); + if (th->p_specific[idx1st] != NULL) + th->p_specific[idx1st][idx2nd] = NULL; + __pthread_unlock(th->p_lock); + } +} + +/* Delete a key */ +int pthread_key_delete(pthread_key_t key) +{ + pthread_descr self = thread_self(); + + pthread_mutex_lock(&pthread_keys_mutex); + if (key >= PTHREAD_KEYS_MAX || !pthread_keys[key].in_use) { + pthread_mutex_unlock(&pthread_keys_mutex); + return EINVAL; + } + pthread_keys[key].in_use = 0; + pthread_keys[key].destr = NULL; + + /* Set the value of the key to NULL in all running threads, so + that if the key is reallocated later by pthread_key_create, its + associated values will be NULL in all threads. + + Do nothing if no threads have been created yet. */ + + if (__pthread_manager_request != -1) + { + struct pthread_key_delete_helper_args args; + struct pthread_request request; + + args.idx1st = key / PTHREAD_KEY_2NDLEVEL_SIZE; + args.idx2nd = key % PTHREAD_KEY_2NDLEVEL_SIZE; + args.self = 0; + + request.req_thread = self; + request.req_kind = REQ_FOR_EACH_THREAD; + request.req_args.for_each.arg = &args; + request.req_args.for_each.fn = pthread_key_delete_helper; + + TEMP_FAILURE_RETRY(write_not_cancel(__pthread_manager_request, + (char *) &request, sizeof(request))); + suspend(self); + } + + pthread_mutex_unlock(&pthread_keys_mutex); + return 0; +} + +/* Set the value of a key */ + +int __pthread_setspecific(pthread_key_t key, const void * pointer) +{ + pthread_descr self = thread_self(); + unsigned int idx1st, idx2nd; + + if (key >= PTHREAD_KEYS_MAX || !pthread_keys[key].in_use) + return EINVAL; + idx1st = key / PTHREAD_KEY_2NDLEVEL_SIZE; + idx2nd = key % PTHREAD_KEY_2NDLEVEL_SIZE; + if (THREAD_GETMEM_NC(self, p_specific[idx1st]) == NULL) { + void *newp = calloc(PTHREAD_KEY_2NDLEVEL_SIZE, sizeof (void *)); + if (newp == NULL) + return ENOMEM; + THREAD_SETMEM_NC(self, p_specific[idx1st], newp); + } + THREAD_GETMEM_NC(self, p_specific[idx1st])[idx2nd] = (void *) pointer; + return 0; +} +strong_alias (__pthread_setspecific, pthread_setspecific) + +/* Get the value of a key */ + +void * __pthread_getspecific(pthread_key_t key) +{ + pthread_descr self = thread_self(); + unsigned int idx1st, idx2nd; + + if (key >= PTHREAD_KEYS_MAX) + return NULL; + idx1st = key / PTHREAD_KEY_2NDLEVEL_SIZE; + idx2nd = key % PTHREAD_KEY_2NDLEVEL_SIZE; + if (THREAD_GETMEM_NC(self, p_specific[idx1st]) == NULL + || !pthread_keys[key].in_use) + return NULL; + return THREAD_GETMEM_NC(self, p_specific[idx1st])[idx2nd]; +} +strong_alias (__pthread_getspecific, pthread_getspecific) + +/* Call the destruction routines on all keys */ + +void __pthread_destroy_specifics() +{ + pthread_descr self = thread_self(); + int i, j, round, found_nonzero; + destr_function destr; + void * data; + + for (round = 0, found_nonzero = 1; + found_nonzero && round < PTHREAD_DESTRUCTOR_ITERATIONS; + round++) { + found_nonzero = 0; + for (i = 0; i < PTHREAD_KEY_1STLEVEL_SIZE; i++) + if (THREAD_GETMEM_NC(self, p_specific[i]) != NULL) + for (j = 0; j < PTHREAD_KEY_2NDLEVEL_SIZE; j++) { + destr = pthread_keys[i * PTHREAD_KEY_2NDLEVEL_SIZE + j].destr; + data = THREAD_GETMEM_NC(self, p_specific[i])[j]; + if (destr != NULL && data != NULL) { + THREAD_GETMEM_NC(self, p_specific[i])[j] = NULL; + destr(data); + found_nonzero = 1; + } + } + } + __pthread_lock(THREAD_GETMEM(self, p_lock), self); + for (i = 0; i < PTHREAD_KEY_1STLEVEL_SIZE; i++) { + if (THREAD_GETMEM_NC(self, p_specific[i]) != NULL) { + free(THREAD_GETMEM_NC(self, p_specific[i])); + THREAD_SETMEM_NC(self, p_specific[i], NULL); + } + } + __pthread_unlock(THREAD_GETMEM(self, p_lock)); +} + +#if !(USE_TLS && HAVE___THREAD) + +/* Thread-specific data for libc. */ + +int +__pthread_internal_tsd_set (int key, const void * pointer) +{ + pthread_descr self = thread_self(); + + THREAD_SETMEM_NC(self, p_libc_specific[key], (void *) pointer); + return 0; +} + +void * +__pthread_internal_tsd_get (int key) +{ + pthread_descr self = thread_self(); + + return THREAD_GETMEM_NC(self, p_libc_specific[key]); +} + +void ** __attribute__ ((__const__)) +__pthread_internal_tsd_address (int key) +{ + pthread_descr self = thread_self(); + return &self->p_libc_specific[key]; +} + +#endif diff --git a/linuxthreads/spinlock.c b/linuxthreads/spinlock.c new file mode 100644 index 0000000000..08fff082ef --- /dev/null +++ b/linuxthreads/spinlock.c @@ -0,0 +1,720 @@ +/* Linuxthreads - a simple clone()-based implementation of Posix */ +/* threads for Linux. */ +/* Copyright (C) 1998 Xavier Leroy (Xavier.Leroy@inria.fr) */ +/* */ +/* This program is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public License */ +/* as published by the Free Software Foundation; either version 2 */ +/* of the License, or (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Library General Public License for more details. */ + +/* Internal locks */ + +#include <errno.h> +#include <sched.h> +#include <time.h> +#include <stdlib.h> +#include <limits.h> +#include "pthread.h" +#include "internals.h" +#include "spinlock.h" +#include "restart.h" + +static void __pthread_acquire(int * spinlock); + +static inline void __pthread_release(int * spinlock) +{ + WRITE_MEMORY_BARRIER(); + *spinlock = __LT_SPINLOCK_INIT; + __asm __volatile ("" : "=m" (*spinlock) : "m" (*spinlock)); +} + + +/* The status field of a spinlock is a pointer whose least significant + bit is a locked flag. + + Thus the field values have the following meanings: + + status == 0: spinlock is free + status == 1: spinlock is taken; no thread is waiting on it + + (status & 1) == 1: spinlock is taken and (status & ~1L) is a + pointer to the first waiting thread; other + waiting threads are linked via the p_nextlock + field. + (status & 1) == 0: same as above, but spinlock is not taken. + + The waiting list is not sorted by priority order. + Actually, we always insert at top of list (sole insertion mode + that can be performed without locking). + For __pthread_unlock, we perform a linear search in the list + to find the highest-priority, oldest waiting thread. + This is safe because there are no concurrent __pthread_unlock + operations -- only the thread that locked the mutex can unlock it. */ + + +void internal_function __pthread_lock(struct _pthread_fastlock * lock, + pthread_descr self) +{ +#if defined HAS_COMPARE_AND_SWAP + long oldstatus, newstatus; + int successful_seizure, spurious_wakeup_count; + int spin_count; +#endif + +#if defined TEST_FOR_COMPARE_AND_SWAP + if (!__pthread_has_cas) +#endif +#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP + { + __pthread_acquire(&lock->__spinlock); + return; + } +#endif + +#if defined HAS_COMPARE_AND_SWAP + /* First try it without preparation. Maybe it's a completely + uncontested lock. */ + if (lock->__status == 0 && __compare_and_swap (&lock->__status, 0, 1)) + return; + + spurious_wakeup_count = 0; + spin_count = 0; + + /* On SMP, try spinning to get the lock. */ + + if (__pthread_smp_kernel) { + int max_count = lock->__spinlock * 2 + 10; + + if (max_count > MAX_ADAPTIVE_SPIN_COUNT) + max_count = MAX_ADAPTIVE_SPIN_COUNT; + + for (spin_count = 0; spin_count < max_count; spin_count++) { + if (((oldstatus = lock->__status) & 1) == 0) { + if(__compare_and_swap(&lock->__status, oldstatus, oldstatus | 1)) + { + if (spin_count) + lock->__spinlock += (spin_count - lock->__spinlock) / 8; + READ_MEMORY_BARRIER(); + return; + } + } +#ifdef BUSY_WAIT_NOP + BUSY_WAIT_NOP; +#endif + __asm __volatile ("" : "=m" (lock->__status) : "m" (lock->__status)); + } + + lock->__spinlock += (spin_count - lock->__spinlock) / 8; + } + +again: + + /* No luck, try once more or suspend. */ + + do { + oldstatus = lock->__status; + successful_seizure = 0; + + if ((oldstatus & 1) == 0) { + newstatus = oldstatus | 1; + successful_seizure = 1; + } else { + if (self == NULL) + self = thread_self(); + newstatus = (long) self | 1; + } + + if (self != NULL) { + THREAD_SETMEM(self, p_nextlock, (pthread_descr) (oldstatus)); + /* Make sure the store in p_nextlock completes before performing + the compare-and-swap */ + MEMORY_BARRIER(); + } + } while(! __compare_and_swap(&lock->__status, oldstatus, newstatus)); + + /* Suspend with guard against spurious wakeup. + This can happen in pthread_cond_timedwait_relative, when the thread + wakes up due to timeout and is still on the condvar queue, and then + locks the queue to remove itself. At that point it may still be on the + queue, and may be resumed by a condition signal. */ + + if (!successful_seizure) { + for (;;) { + suspend(self); + if (self->p_nextlock != NULL) { + /* Count resumes that don't belong to us. */ + spurious_wakeup_count++; + continue; + } + break; + } + goto again; + } + + /* Put back any resumes we caught that don't belong to us. */ + while (spurious_wakeup_count--) + restart(self); + + READ_MEMORY_BARRIER(); +#endif +} + +int __pthread_unlock(struct _pthread_fastlock * lock) +{ +#if defined HAS_COMPARE_AND_SWAP + long oldstatus; + pthread_descr thr, * ptr, * maxptr; + int maxprio; +#endif + +#if defined TEST_FOR_COMPARE_AND_SWAP + if (!__pthread_has_cas) +#endif +#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP + { + __pthread_release(&lock->__spinlock); + return 0; + } +#endif + +#if defined HAS_COMPARE_AND_SWAP + WRITE_MEMORY_BARRIER(); + +again: + while ((oldstatus = lock->__status) == 1) { + if (__compare_and_swap_with_release_semantics(&lock->__status, + oldstatus, 0)) + return 0; + } + + /* Find thread in waiting queue with maximal priority */ + ptr = (pthread_descr *) &lock->__status; + thr = (pthread_descr) (oldstatus & ~1L); + maxprio = 0; + maxptr = ptr; + + /* Before we iterate over the wait queue, we need to execute + a read barrier, otherwise we may read stale contents of nodes that may + just have been inserted by other processors. One read barrier is enough to + ensure we have a stable list; we don't need one for each pointer chase + through the list, because we are the owner of the lock; other threads + can only add nodes at the front; if a front node is consistent, + the ones behind it must also be. */ + + READ_MEMORY_BARRIER(); + + while (thr != 0) { + if (thr->p_priority >= maxprio) { + maxptr = ptr; + maxprio = thr->p_priority; + } + ptr = &(thr->p_nextlock); + thr = (pthread_descr)((long)(thr->p_nextlock) & ~1L); + } + + /* Remove max prio thread from waiting list. */ + if (maxptr == (pthread_descr *) &lock->__status) { + /* If max prio thread is at head, remove it with compare-and-swap + to guard against concurrent lock operation. This removal + also has the side effect of marking the lock as released + because the new status comes from thr->p_nextlock whose + least significant bit is clear. */ + thr = (pthread_descr) (oldstatus & ~1L); + if (! __compare_and_swap_with_release_semantics + (&lock->__status, oldstatus, (long)(thr->p_nextlock) & ~1L)) + goto again; + } else { + /* No risk of concurrent access, remove max prio thread normally. + But in this case we must also flip the least significant bit + of the status to mark the lock as released. */ + thr = (pthread_descr)((long)*maxptr & ~1L); + *maxptr = thr->p_nextlock; + + /* Ensure deletion from linked list completes before we + release the lock. */ + WRITE_MEMORY_BARRIER(); + + do { + oldstatus = lock->__status; + } while (!__compare_and_swap_with_release_semantics(&lock->__status, + oldstatus, oldstatus & ~1L)); + } + + /* Wake up the selected waiting thread. Woken thread can check + its own p_nextlock field for NULL to detect that it has been removed. No + barrier is needed here, since restart() and suspend() take + care of memory synchronization. */ + + thr->p_nextlock = NULL; + restart(thr); + + return 0; +#endif +} + +/* + * Alternate fastlocks do not queue threads directly. Instead, they queue + * these wait queue node structures. When a timed wait wakes up due to + * a timeout, it can leave its wait node in the queue (because there + * is no safe way to remove from the quue). Some other thread will + * deallocate the abandoned node. + */ + + +struct wait_node { + struct wait_node *next; /* Next node in null terminated linked list */ + pthread_descr thr; /* The thread waiting with this node */ + int abandoned; /* Atomic flag */ +}; + +static long wait_node_free_list; +static int wait_node_free_list_spinlock; + +/* Allocate a new node from the head of the free list using an atomic + operation, or else using malloc if that list is empty. A fundamental + assumption here is that we can safely access wait_node_free_list->next. + That's because we never free nodes once we allocate them, so a pointer to a + node remains valid indefinitely. */ + +static struct wait_node *wait_node_alloc(void) +{ + struct wait_node *new_node = 0; + + __pthread_acquire(&wait_node_free_list_spinlock); + if (wait_node_free_list != 0) { + new_node = (struct wait_node *) wait_node_free_list; + wait_node_free_list = (long) new_node->next; + } + WRITE_MEMORY_BARRIER(); + __pthread_release(&wait_node_free_list_spinlock); + + if (new_node == 0) + return malloc(sizeof *wait_node_alloc()); + + return new_node; +} + +/* Return a node to the head of the free list using an atomic + operation. */ + +static void wait_node_free(struct wait_node *wn) +{ + __pthread_acquire(&wait_node_free_list_spinlock); + wn->next = (struct wait_node *) wait_node_free_list; + wait_node_free_list = (long) wn; + WRITE_MEMORY_BARRIER(); + __pthread_release(&wait_node_free_list_spinlock); + return; +} + +#if defined HAS_COMPARE_AND_SWAP + +/* Remove a wait node from the specified queue. It is assumed + that the removal takes place concurrently with only atomic insertions at the + head of the queue. */ + +static void wait_node_dequeue(struct wait_node **pp_head, + struct wait_node **pp_node, + struct wait_node *p_node) +{ + /* If the node is being deleted from the head of the + list, it must be deleted using atomic compare-and-swap. + Otherwise it can be deleted in the straightforward way. */ + + if (pp_node == pp_head) { + /* We don't need a read barrier between these next two loads, + because it is assumed that the caller has already ensured + the stability of *p_node with respect to p_node. */ + + long oldvalue = (long) p_node; + long newvalue = (long) p_node->next; + + if (__compare_and_swap((long *) pp_node, oldvalue, newvalue)) + return; + + /* Oops! Compare and swap failed, which means the node is + no longer first. We delete it using the ordinary method. But we don't + know the identity of the node which now holds the pointer to the node + being deleted, so we must search from the beginning. */ + + for (pp_node = pp_head; p_node != *pp_node; ) { + pp_node = &(*pp_node)->next; + READ_MEMORY_BARRIER(); /* Stabilize *pp_node for next iteration. */ + } + } + + *pp_node = p_node->next; + return; +} + +#endif + +void __pthread_alt_lock(struct _pthread_fastlock * lock, + pthread_descr self) +{ +#if defined HAS_COMPARE_AND_SWAP + long oldstatus, newstatus; +#endif + struct wait_node wait_node; + +#if defined TEST_FOR_COMPARE_AND_SWAP + if (!__pthread_has_cas) +#endif +#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP + { + int suspend_needed = 0; + __pthread_acquire(&lock->__spinlock); + + if (lock->__status == 0) + lock->__status = 1; + else { + if (self == NULL) + self = thread_self(); + + wait_node.abandoned = 0; + wait_node.next = (struct wait_node *) lock->__status; + wait_node.thr = self; + lock->__status = (long) &wait_node; + suspend_needed = 1; + } + + __pthread_release(&lock->__spinlock); + + if (suspend_needed) + suspend (self); + return; + } +#endif + +#if defined HAS_COMPARE_AND_SWAP + do { + oldstatus = lock->__status; + if (oldstatus == 0) { + newstatus = 1; + } else { + if (self == NULL) + self = thread_self(); + wait_node.thr = self; + newstatus = (long) &wait_node; + } + wait_node.abandoned = 0; + wait_node.next = (struct wait_node *) oldstatus; + /* Make sure the store in wait_node.next completes before performing + the compare-and-swap */ + MEMORY_BARRIER(); + } while(! __compare_and_swap(&lock->__status, oldstatus, newstatus)); + + /* Suspend. Note that unlike in __pthread_lock, we don't worry + here about spurious wakeup. That's because this lock is not + used in situations where that can happen; the restart can + only come from the previous lock owner. */ + + if (oldstatus != 0) + suspend(self); + + READ_MEMORY_BARRIER(); +#endif +} + +/* Timed-out lock operation; returns 0 to indicate timeout. */ + +int __pthread_alt_timedlock(struct _pthread_fastlock * lock, + pthread_descr self, const struct timespec *abstime) +{ + long oldstatus = 0; +#if defined HAS_COMPARE_AND_SWAP + long newstatus; +#endif + struct wait_node *p_wait_node = wait_node_alloc(); + + /* Out of memory, just give up and do ordinary lock. */ + if (p_wait_node == 0) { + __pthread_alt_lock(lock, self); + return 1; + } + +#if defined TEST_FOR_COMPARE_AND_SWAP + if (!__pthread_has_cas) +#endif +#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP + { + __pthread_acquire(&lock->__spinlock); + + if (lock->__status == 0) + lock->__status = 1; + else { + if (self == NULL) + self = thread_self(); + + p_wait_node->abandoned = 0; + p_wait_node->next = (struct wait_node *) lock->__status; + p_wait_node->thr = self; + lock->__status = (long) p_wait_node; + oldstatus = 1; /* force suspend */ + } + + __pthread_release(&lock->__spinlock); + goto suspend; + } +#endif + +#if defined HAS_COMPARE_AND_SWAP + do { + oldstatus = lock->__status; + if (oldstatus == 0) { + newstatus = 1; + } else { + if (self == NULL) + self = thread_self(); + p_wait_node->thr = self; + newstatus = (long) p_wait_node; + } + p_wait_node->abandoned = 0; + p_wait_node->next = (struct wait_node *) oldstatus; + /* Make sure the store in wait_node.next completes before performing + the compare-and-swap */ + MEMORY_BARRIER(); + } while(! __compare_and_swap(&lock->__status, oldstatus, newstatus)); +#endif + +#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP + suspend: +#endif + + /* If we did not get the lock, do a timed suspend. If we wake up due + to a timeout, then there is a race; the old lock owner may try + to remove us from the queue. This race is resolved by us and the owner + doing an atomic testandset() to change the state of the wait node from 0 + to 1. If we succeed, then it's a timeout and we abandon the node in the + queue. If we fail, it means the owner gave us the lock. */ + + if (oldstatus != 0) { + if (timedsuspend(self, abstime) == 0) { + if (!testandset(&p_wait_node->abandoned)) + return 0; /* Timeout! */ + + /* Eat oustanding resume from owner, otherwise wait_node_free() below + will race with owner's wait_node_dequeue(). */ + suspend(self); + } + } + + wait_node_free(p_wait_node); + + READ_MEMORY_BARRIER(); + + return 1; /* Got the lock! */ +} + +void __pthread_alt_unlock(struct _pthread_fastlock *lock) +{ + struct wait_node *p_node, **pp_node, *p_max_prio, **pp_max_prio; + struct wait_node ** const pp_head = (struct wait_node **) &lock->__status; + int maxprio; + + WRITE_MEMORY_BARRIER(); + +#if defined TEST_FOR_COMPARE_AND_SWAP + if (!__pthread_has_cas) +#endif +#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP + { + __pthread_acquire(&lock->__spinlock); + } +#endif + + while (1) { + + /* If no threads are waiting for this lock, try to just + atomically release it. */ +#if defined TEST_FOR_COMPARE_AND_SWAP + if (!__pthread_has_cas) +#endif +#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP + { + if (lock->__status == 0 || lock->__status == 1) { + lock->__status = 0; + break; + } + } +#endif + +#if defined TEST_FOR_COMPARE_AND_SWAP + else +#endif + +#if defined HAS_COMPARE_AND_SWAP + { + long oldstatus = lock->__status; + if (oldstatus == 0 || oldstatus == 1) { + if (__compare_and_swap_with_release_semantics (&lock->__status, oldstatus, 0)) + break; + else + continue; + } + } +#endif + + /* Process the entire queue of wait nodes. Remove all abandoned + wait nodes and put them into the global free queue, and + remember the one unabandoned node which refers to the thread + having the highest priority. */ + + pp_max_prio = pp_node = pp_head; + p_max_prio = p_node = *pp_head; + maxprio = INT_MIN; + + READ_MEMORY_BARRIER(); /* Prevent access to stale data through p_node */ + + while (p_node != (struct wait_node *) 1) { + int prio; + + if (p_node->abandoned) { + /* Remove abandoned node. */ +#if defined TEST_FOR_COMPARE_AND_SWAP + if (!__pthread_has_cas) +#endif +#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP + *pp_node = p_node->next; +#endif +#if defined TEST_FOR_COMPARE_AND_SWAP + else +#endif +#if defined HAS_COMPARE_AND_SWAP + wait_node_dequeue(pp_head, pp_node, p_node); +#endif + wait_node_free(p_node); + /* Note that the next assignment may take us to the beginning + of the queue, to newly inserted nodes, if pp_node == pp_head. + In that case we need a memory barrier to stabilize the first of + these new nodes. */ + p_node = *pp_node; + if (pp_node == pp_head) + READ_MEMORY_BARRIER(); /* No stale reads through p_node */ + continue; + } else if ((prio = p_node->thr->p_priority) >= maxprio) { + /* Otherwise remember it if its thread has a higher or equal priority + compared to that of any node seen thus far. */ + maxprio = prio; + pp_max_prio = pp_node; + p_max_prio = p_node; + } + + /* This canno6 jump backward in the list, so no further read + barrier is needed. */ + pp_node = &p_node->next; + p_node = *pp_node; + } + + /* If all threads abandoned, go back to top */ + if (maxprio == INT_MIN) + continue; + + ASSERT (p_max_prio != (struct wait_node *) 1); + + /* Now we want to to remove the max priority thread's wait node from + the list. Before we can do this, we must atomically try to change the + node's abandon state from zero to nonzero. If we succeed, that means we + have the node that we will wake up. If we failed, then it means the + thread timed out and abandoned the node in which case we repeat the + whole unlock operation. */ + + if (!testandset(&p_max_prio->abandoned)) { +#if defined TEST_FOR_COMPARE_AND_SWAP + if (!__pthread_has_cas) +#endif +#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP + *pp_max_prio = p_max_prio->next; +#endif +#if defined TEST_FOR_COMPARE_AND_SWAP + else +#endif +#if defined HAS_COMPARE_AND_SWAP + wait_node_dequeue(pp_head, pp_max_prio, p_max_prio); +#endif + restart(p_max_prio->thr); + break; + } + } + +#if defined TEST_FOR_COMPARE_AND_SWAP + if (!__pthread_has_cas) +#endif +#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP + { + __pthread_release(&lock->__spinlock); + } +#endif +} + + +/* Compare-and-swap emulation with a spinlock */ + +#ifdef TEST_FOR_COMPARE_AND_SWAP +int __pthread_has_cas = 0; +#endif + +#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP + +int __pthread_compare_and_swap(long * ptr, long oldval, long newval, + int * spinlock) +{ + int res; + + __pthread_acquire(spinlock); + + if (*ptr == oldval) { + *ptr = newval; res = 1; + } else { + res = 0; + } + + __pthread_release(spinlock); + + return res; +} + +#endif + +/* The retry strategy is as follows: + - We test and set the spinlock MAX_SPIN_COUNT times, calling + sched_yield() each time. This gives ample opportunity for other + threads with priority >= our priority to make progress and + release the spinlock. + - If a thread with priority < our priority owns the spinlock, + calling sched_yield() repeatedly is useless, since we're preventing + the owning thread from making progress and releasing the spinlock. + So, after MAX_SPIN_LOCK attemps, we suspend the calling thread + using nanosleep(). This again should give time to the owning thread + for releasing the spinlock. + Notice that the nanosleep() interval must not be too small, + since the kernel does busy-waiting for short intervals in a realtime + process (!). The smallest duration that guarantees thread + suspension is currently 2ms. + - When nanosleep() returns, we try again, doing MAX_SPIN_COUNT + sched_yield(), then sleeping again if needed. */ + +static void __pthread_acquire(int * spinlock) +{ + int cnt = 0; + struct timespec tm; + + READ_MEMORY_BARRIER(); + + while (testandset(spinlock)) { + if (cnt < MAX_SPIN_COUNT) { + sched_yield(); + cnt++; + } else { + tm.tv_sec = 0; + tm.tv_nsec = SPIN_SLEEP_DURATION; + nanosleep(&tm, NULL); + cnt = 0; + } + } +} diff --git a/linuxthreads/spinlock.h b/linuxthreads/spinlock.h new file mode 100644 index 0000000000..ff96fc3360 --- /dev/null +++ b/linuxthreads/spinlock.h @@ -0,0 +1,218 @@ +/* Linuxthreads - a simple clone()-based implementation of Posix */ +/* threads for Linux. */ +/* Copyright (C) 1998 Xavier Leroy (Xavier.Leroy@inria.fr) */ +/* */ +/* This program is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public License */ +/* as published by the Free Software Foundation; either version 2 */ +/* of the License, or (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Library General Public License for more details. */ + +#include <bits/initspin.h> + + +/* There are 2 compare and swap synchronization primitives with + different semantics: + + 1. compare_and_swap, which has acquire semantics (i.e. it + completes befor subsequent writes.) + 2. compare_and_swap_with_release_semantics, which has release + semantics (it completes after previous writes.) + + For those platforms on which they are the same. HAS_COMPARE_AND_SWAP + should be defined. For those platforms on which they are different, + HAS_COMPARE_AND_SWAP_WITH_RELEASE_SEMANTICS has to be defined. */ + +#ifndef HAS_COMPARE_AND_SWAP +#ifdef HAS_COMPARE_AND_SWAP_WITH_RELEASE_SEMANTICS +#define HAS_COMPARE_AND_SWAP +#endif +#endif + +#if defined(TEST_FOR_COMPARE_AND_SWAP) + +extern int __pthread_has_cas; +extern int __pthread_compare_and_swap(long * ptr, long oldval, long newval, + int * spinlock); + +static inline int compare_and_swap(long * ptr, long oldval, long newval, + int * spinlock) +{ + if (__builtin_expect (__pthread_has_cas, 1)) + return __compare_and_swap(ptr, oldval, newval); + else + return __pthread_compare_and_swap(ptr, oldval, newval, spinlock); +} + +#elif defined(HAS_COMPARE_AND_SWAP) + +#ifdef IMPLEMENT_TAS_WITH_CAS +#define testandset(p) !__compare_and_swap((long int *) p, 0, 1) +#endif + +#ifdef HAS_COMPARE_AND_SWAP_WITH_RELEASE_SEMANTICS + +static inline int +compare_and_swap_with_release_semantics (long * ptr, long oldval, + long newval, int * spinlock) +{ + return __compare_and_swap_with_release_semantics (ptr, oldval, + newval); +} + +#endif + +static inline int compare_and_swap(long * ptr, long oldval, long newval, + int * spinlock) +{ + return __compare_and_swap(ptr, oldval, newval); +} + +#else + +extern int __pthread_compare_and_swap(long * ptr, long oldval, long newval, + int * spinlock); + +static inline int compare_and_swap(long * ptr, long oldval, long newval, + int * spinlock) +{ + return __pthread_compare_and_swap(ptr, oldval, newval, spinlock); +} + +#endif + +#ifndef HAS_COMPARE_AND_SWAP_WITH_RELEASE_SEMANTICS +#define compare_and_swap_with_release_semantics compare_and_swap +#define __compare_and_swap_with_release_semantics __compare_and_swap +#endif + +/* Internal locks */ + +extern void internal_function __pthread_lock(struct _pthread_fastlock * lock, + pthread_descr self); +extern int __pthread_unlock(struct _pthread_fastlock *lock); + +static inline void __pthread_init_lock(struct _pthread_fastlock * lock) +{ + lock->__status = 0; + lock->__spinlock = __LT_SPINLOCK_INIT; +} + +static inline int __pthread_trylock (struct _pthread_fastlock * lock) +{ +#if defined TEST_FOR_COMPARE_AND_SWAP + if (!__pthread_has_cas) +#endif +#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP + { + return (testandset(&lock->__spinlock) ? EBUSY : 0); + } +#endif + +#if defined HAS_COMPARE_AND_SWAP + do { + if (lock->__status != 0) return EBUSY; + } while(! __compare_and_swap(&lock->__status, 0, 1)); + return 0; +#endif +} + +/* Variation of internal lock used for pthread_mutex_t, supporting + timed-out waits. Warning: do not mix these operations with the above ones + over the same lock object! */ + +extern void __pthread_alt_lock(struct _pthread_fastlock * lock, + pthread_descr self); + +extern int __pthread_alt_timedlock(struct _pthread_fastlock * lock, + pthread_descr self, const struct timespec *abstime); + +extern void __pthread_alt_unlock(struct _pthread_fastlock *lock); + +static inline void __pthread_alt_init_lock(struct _pthread_fastlock * lock) +{ + lock->__status = 0; + lock->__spinlock = __LT_SPINLOCK_INIT; +} + +static inline int __pthread_alt_trylock (struct _pthread_fastlock * lock) +{ +#if defined TEST_FOR_COMPARE_AND_SWAP + if (!__pthread_has_cas) +#endif +#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP + { + int res = EBUSY; + + if (testandset(&lock->__spinlock) == 0) + { + if (lock->__status == 0) + { + lock->__status = 1; + WRITE_MEMORY_BARRIER(); + res = 0; + } + lock->__spinlock = __LT_SPINLOCK_INIT; + } + return res; + } +#endif + +#if defined HAS_COMPARE_AND_SWAP + do { + if (lock->__status != 0) return EBUSY; + } while(! compare_and_swap(&lock->__status, 0, 1, &lock->__spinlock)); + return 0; +#endif +} + +/* Operations on pthread_atomic, which is defined in internals.h */ + +static inline long atomic_increment(struct pthread_atomic *pa) +{ + long oldval; + + do { + oldval = pa->p_count; + } while (!compare_and_swap(&pa->p_count, oldval, oldval + 1, &pa->p_spinlock)); + + return oldval; +} + + +static inline long atomic_decrement(struct pthread_atomic *pa) +{ + long oldval; + + do { + oldval = pa->p_count; + } while (!compare_and_swap(&pa->p_count, oldval, oldval - 1, &pa->p_spinlock)); + + return oldval; +} + + +static inline __attribute__((always_inline)) void +__pthread_set_own_extricate_if (pthread_descr self, pthread_extricate_if *peif) +{ + /* Only store a non-null peif if the thread has cancellation enabled. + Otherwise pthread_cancel will unconditionally call the extricate handler, + and restart the thread giving rise to forbidden spurious wakeups. */ + if (peif == NULL + || THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) + { + /* If we are removing the extricate interface, we need to synchronize + against pthread_cancel so that it does not continue with a pointer + to a deallocated pthread_extricate_if struct! The thread lock + is (ab)used for this synchronization purpose. */ + if (peif == NULL) + __pthread_lock (THREAD_GETMEM(self, p_lock), self); + THREAD_SETMEM(self, p_extricate, peif); + if (peif == NULL) + __pthread_unlock (THREAD_GETMEM(self, p_lock)); + } +} diff --git a/linuxthreads/sysdeps/alpha/elf/pt-initfini.c b/linuxthreads/sysdeps/alpha/elf/pt-initfini.c new file mode 100644 index 0000000000..ee25582101 --- /dev/null +++ b/linuxthreads/sysdeps/alpha/elf/pt-initfini.c @@ -0,0 +1,90 @@ +/* Special .init and .fini section support for Alpha. Linuxthreads version. + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* 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\ + jsr $26, __pthread_initialize_minimal \n\ + ldq $29, 8($30) \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/linuxthreads/sysdeps/alpha/pspinlock.c b/linuxthreads/sysdeps/alpha/pspinlock.c new file mode 100644 index 0000000000..79b7836293 --- /dev/null +++ b/linuxthreads/sysdeps/alpha/pspinlock.c @@ -0,0 +1,110 @@ +/* POSIX spinlock implementation. Alpha version. + Copyright (C) 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; 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 "internals.h" + + +/* This implementation is similar to the one used in the Linux kernel. + But the kernel is byte instructions for the memory access. This is + faster but unusable here. The problem is that only 128 + threads/processes could use the spinlock at the same time. If (by + a design error in the program) a thread/process would hold the + spinlock for a time long enough to accumulate 128 waiting + processes, the next one will find a positive value in the spinlock + and assume it is unlocked. We cannot accept that. */ + +int +__pthread_spin_lock (pthread_spinlock_t *lock) +{ + unsigned int tmp; + asm volatile + ("1: ldl_l %0,%1\n" + " blbs %0,2f\n" + " or %0,1,%0\n" + " stl_c %0,%1\n" + " beq %0,2f\n" + " mb\n" + ".subsection 2\n" + "2: ldl %0,%1\n" + " blbs %0,2b\n" + " br 1b\n" + ".previous" + : "=r" (tmp), "=m" (lock) + : "m" (lock)); + return 0; +} +weak_alias (__pthread_spin_lock, pthread_spin_lock) + + +int +__pthread_spin_trylock (pthread_spinlock_t *lock) +{ + unsigned long int oldval; + unsigned long int temp; + + asm volatile + ("1: ldl_l %0,%1\n" + " and %0,%3,%2\n" + " bne %2,2f\n" + " xor %0,%3,%0\n" + " stl_c %0,%1\n" + " beq %0,3f\n" + " mb\n" + "2:\n" + ".subsection 2\n" + "3: br 1b\n" + ".previous" + : "=&r" (temp), "=m" (*lock), "=&r" (oldval) + : "Ir" (1UL), "m" (*lock)); + + return oldval == 0 ? 0 : EBUSY; +} +weak_alias (__pthread_spin_trylock, pthread_spin_trylock) + + +int +__pthread_spin_unlock (pthread_spinlock_t *lock) +{ + asm volatile ("mb"); + return *lock = 0; +} +weak_alias (__pthread_spin_unlock, pthread_spin_unlock) + + +int +__pthread_spin_init (pthread_spinlock_t *lock, int pshared) +{ + /* We can ignore the `pshared' parameter. Since we are busy-waiting + all processes which can access the memory location `lock' points + to can use the spinlock. */ + *lock = 0; + return 0; +} +weak_alias (__pthread_spin_init, pthread_spin_init) + + +int +__pthread_spin_destroy (pthread_spinlock_t *lock) +{ + /* Nothing to do. */ + return 0; +} +weak_alias (__pthread_spin_destroy, pthread_spin_destroy) diff --git a/linuxthreads/sysdeps/alpha/pt-machine.h b/linuxthreads/sysdeps/alpha/pt-machine.h new file mode 100644 index 0000000000..853ac6f04a --- /dev/null +++ b/linuxthreads/sysdeps/alpha/pt-machine.h @@ -0,0 +1,128 @@ +/* Machine-dependent pthreads configuration and inline functions. + Alpha version. + Copyright (C) 1996, 1997, 1998, 2000, 2002, 2003 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Richard Henderson <rth@tamu.edu>. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; 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 _PT_MACHINE_H +#define _PT_MACHINE_H 1 + +#ifndef PT_EI +# define PT_EI extern inline __attribute__ ((always_inline)) +#endif + +#ifdef __linux__ +# include <asm/pal.h> +#else +# include <machine/pal.h> +#endif + +extern long int testandset (int *spinlock); +extern int __compare_and_swap (long int *p, long int oldval, long int newval); + +/* Get some notion of the current stack. Need not be exactly the top + of the stack, just something somewhere in the current frame. */ +#define CURRENT_STACK_FRAME stack_pointer +register char *stack_pointer __asm__("$30"); + + +/* Memory barrier; default is to do nothing */ +#define MEMORY_BARRIER() __asm__ __volatile__("mb" : : : "memory") +/* Write barrier. */ +#define WRITE_MEMORY_BARRIER() __asm__ __volatile__("wmb" : : : "memory") + + +/* Spinlock implementation; required. */ +PT_EI long int +testandset (int *spinlock) +{ + long int ret, temp; + + __asm__ __volatile__( + "/* Inline spinlock test & set */\n" + "1:\t" + "ldl_l %0,%3\n\t" + "bne %0,2f\n\t" + "or $31,1,%1\n\t" + "stl_c %1,%2\n\t" + "beq %1,1b\n" + "2:\tmb\n" + "/* End spinlock test & set */" + : "=&r"(ret), "=&r"(temp), "=m"(*spinlock) + : "m"(*spinlock) + : "memory"); + + return ret; +} + + +/* Begin allocating thread stacks at this address. Default is to allocate + them just below the initial program stack. */ +#define THREAD_STACK_START_ADDRESS 0x40000000000 + + +/* Return the thread descriptor for the current thread. */ +#define THREAD_SELF \ +({ \ + register pthread_descr __self __asm__("$0"); \ + __asm__ ("call_pal %1" : "=r"(__self) : "i"(PAL_rduniq)); \ + __self; \ +}) + +/* Initialize the thread-unique value. */ +#define INIT_THREAD_SELF(descr, nr) \ +{ \ + register pthread_descr __self __asm__("$16") = (descr); \ + __asm__ __volatile__ ("call_pal %1" : : "r"(__self), "i"(PAL_wruniq)); \ +} + + +/* Compare-and-swap for semaphores. */ + +#define HAS_COMPARE_AND_SWAP +PT_EI int +__compare_and_swap (long int *p, long int oldval, long int newval) +{ + long int ret; + + __asm__ __volatile__ ( + "/* Inline compare & swap */\n" + "1:\t" + "ldq_l %0,%4\n\t" + "cmpeq %0,%2,%0\n\t" + "beq %0,2f\n\t" + "mov %3,%0\n\t" + "stq_c %0,%1\n\t" + "beq %0,1b\n\t" + "2:\tmb\n" + "/* End compare & swap */" + : "=&r"(ret), "=m"(*p) + : "r"(oldval), "r"(newval), "m"(*p) + : "memory"); + + return ret; +} + +/* We want the OS to assign stack addresses. */ +#define FLOATING_STACKS 1 + +/* Maximum size of the stack if the rlimit is unlimited. */ +#define ARCH_STACK_MAX_SIZE 32*1024*1024 + +#endif /* pt-machine.h */ diff --git a/linuxthreads/sysdeps/alpha/tls.h b/linuxthreads/sysdeps/alpha/tls.h new file mode 100644 index 0000000000..261d333eb4 --- /dev/null +++ b/linuxthreads/sysdeps/alpha/tls.h @@ -0,0 +1,129 @@ +/* Definitions for thread-local data handling. linuxthreads/Alpha version. + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _TLS_H +#define _TLS_H + +#ifndef __ASSEMBLER__ + +# include <pt-machine.h> +# include <stddef.h> + +/* Type for the dtv. */ +typedef union dtv +{ + size_t counter; + void *pointer; +} dtv_t; + + +typedef struct +{ + dtv_t *dtv; + + /* Reserved for the thread implementation. Unused in LinuxThreads. */ + void *private; +} tcbhead_t; +#endif + + +#ifdef HAVE_TLS_SUPPORT + +/* 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) + +/* Alignment requirements for the TCB. */ +# define TLS_TCB_ALIGN __alignof__ (tcbhead_t) + +/* This is the size we need before TCB. */ +# define TLS_PRE_TCB_SIZE sizeof (struct _pthread_descr_struct) + +/* The DTV is allocated at the TP; the TCB is placed elsewhere. */ +# define TLS_DTV_AT_TP 1 + +/* 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 *)__builtin_thread_pointer ())->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 (TCBP), 0) + +/* 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. */ +# undef THREAD_SELF +# define THREAD_SELF \ + ((pthread_descr)__builtin_thread_pointer () - 1) + +# undef INIT_THREAD_SELF +# define INIT_THREAD_SELF(DESCR, NR) \ + __builtin_set_thread_pointer ((struct _pthread_descr_struct *)(DESCR) + 1) + +/* Get the thread descriptor definition. */ +# include <linuxthreads/descr.h> + +/* ??? Generic bits of LinuxThreads may call these macros with + DESCR set to NULL. We are expected to be able to reference + the "current" value. + + In our case, we'd really prefer to use DESCR, since lots of + PAL_code calls would be expensive. We can only trust that + the compiler does its job and unifies the multiple + __builtin_thread_pointer instances. */ + +#define THREAD_GETMEM(descr, member) \ + ((void) sizeof (descr), THREAD_SELF->member) +#define THREAD_GETMEM_NC(descr, member) \ + ((void) sizeof (descr), THREAD_SELF->member) +#define THREAD_SETMEM(descr, member, value) \ + ((void) sizeof (descr), THREAD_SELF->member = (value)) +#define THREAD_SETMEM_NC(descr, member, value) \ + ((void) sizeof (descr), THREAD_SELF->member = (value)) + +# endif /* HAVE_TLS_SUPPORT */ +#endif /* __ASSEMBLER__ */ + +#endif /* tls.h */ diff --git a/linuxthreads/sysdeps/arm/pspinlock.c b/linuxthreads/sysdeps/arm/pspinlock.c new file mode 100644 index 0000000000..665e270b69 --- /dev/null +++ b/linuxthreads/sysdeps/arm/pspinlock.c @@ -0,0 +1,82 @@ +/* POSIX spinlock implementation. Arm version. + Copyright (C) 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; 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 "internals.h" + + +int +__pthread_spin_lock (pthread_spinlock_t *lock) +{ + unsigned int val; + + do + asm volatile ("swp %0, %1, [%2]" + : "=r" (val) + : "0" (1), "r" (lock) + : "memory"); + while (val != 0); + + return 0; +} +weak_alias (__pthread_spin_lock, pthread_spin_lock) + + +int +__pthread_spin_trylock (pthread_spinlock_t *lock) +{ + unsigned int val; + + asm volatile ("swp %0, %1, [%2]" + : "=r" (val) + : "0" (1), "r" (lock) + : "memory"); + + return val ? EBUSY : 0; +} +weak_alias (__pthread_spin_trylock, pthread_spin_trylock) + + +int +__pthread_spin_unlock (pthread_spinlock_t *lock) +{ + return *lock = 0; +} +weak_alias (__pthread_spin_unlock, pthread_spin_unlock) + + +int +__pthread_spin_init (pthread_spinlock_t *lock, int pshared) +{ + /* We can ignore the `pshared' parameter. Since we are busy-waiting + all processes which can access the memory location `lock' points + to can use the spinlock. */ + return *lock = 0; +} +weak_alias (__pthread_spin_init, pthread_spin_init) + + +int +__pthread_spin_destroy (pthread_spinlock_t *lock) +{ + /* Nothing to do. */ + return 0; +} +weak_alias (__pthread_spin_destroy, pthread_spin_destroy) diff --git a/linuxthreads/sysdeps/arm/pt-machine.h b/linuxthreads/sysdeps/arm/pt-machine.h new file mode 100644 index 0000000000..a4c2f314cb --- /dev/null +++ b/linuxthreads/sysdeps/arm/pt-machine.h @@ -0,0 +1,55 @@ +/* Machine-dependent pthreads configuration and inline functions. + ARM version. + Copyright (C) 1997, 1998, 2000, 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Philip Blundell <philb@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; 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 _PT_MACHINE_H +#define _PT_MACHINE_H 1 + +#ifndef PT_EI +# define PT_EI extern inline __attribute__ ((always_inline)) +#endif + +extern long int testandset (int *spinlock); +extern int __compare_and_swap (long int *p, long int oldval, long int newval); + +/* This will not work on ARM1 or ARM2 because SWP is lacking on those + machines. Unfortunately we have no way to detect this at compile + time; let's hope nobody tries to use one. */ + +/* Spinlock implementation; required. */ +PT_EI long int +testandset (int *spinlock) +{ + register unsigned int ret; + + __asm__ __volatile__("swp %0, %1, [%2]" + : "=r"(ret) + : "0"(1), "r"(spinlock)); + + return ret; +} + + +/* Get some notion of the current stack. Need not be exactly the top + of the stack, just something somewhere in the current frame. */ +#define CURRENT_STACK_FRAME stack_pointer +register char * stack_pointer __asm__ ("sp"); + +#endif /* pt-machine.h */ diff --git a/linuxthreads/sysdeps/cris/pspinlock.c b/linuxthreads/sysdeps/cris/pspinlock.c new file mode 100644 index 0000000000..402e838c00 --- /dev/null +++ b/linuxthreads/sysdeps/cris/pspinlock.c @@ -0,0 +1,72 @@ +/* POSIX spinlock implementation. CRIS version. + Copyright (C) 2000, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; 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 "internals.h" + +/* FIXME: These are just dummies. I don't know why or if they're needed; + configury should default to these definitions. We just follow the + crowd here. */ + +int +__pthread_spin_lock (pthread_spinlock_t *lock) +{ + while (testandset (lock) != 0) + ; + + return 0; +} +weak_alias (__pthread_spin_lock, pthread_spin_lock) + + +int +__pthread_spin_trylock (pthread_spinlock_t *lock) +{ + return testandset (lock) != 0 ? EBUSY : 0; +} +weak_alias (__pthread_spin_trylock, pthread_spin_trylock) + + +int +__pthread_spin_unlock (pthread_spinlock_t *lock) +{ + return *lock = 0; +} +weak_alias (__pthread_spin_unlock, pthread_spin_unlock) + + +int +__pthread_spin_init (pthread_spinlock_t *lock, int pshared) +{ + /* We can ignore the `pshared' parameter. Since we are busy-waiting + all processes which can access the memory location `lock' points + to can use the spinlock. */ + return *lock = 0; +} +weak_alias (__pthread_spin_init, pthread_spin_init) + + +int +__pthread_spin_destroy (pthread_spinlock_t *lock) +{ + /* Nothing to do. */ + return 0; +} +weak_alias (__pthread_spin_destroy, pthread_spin_destroy) diff --git a/linuxthreads/sysdeps/cris/pt-machine.h b/linuxthreads/sysdeps/cris/pt-machine.h new file mode 100644 index 0000000000..431da7101d --- /dev/null +++ b/linuxthreads/sysdeps/cris/pt-machine.h @@ -0,0 +1,58 @@ +/* Machine-dependent pthreads configuration and inline functions. + CRIS version. + 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. */ + +#ifndef _PT_MACHINE_H +#define _PT_MACHINE_H 1 + +#ifndef PT_EI +# define PT_EI extern inline __attribute__ ((always_inline)) +#endif + +extern long int testandset (int *spinlock); +extern int __compare_and_swap (long int *p, long int oldval, long int newval); + +PT_EI long int +testandset (int *spinlock) +{ + register unsigned long int ret; + + /* Note the use of a dummy output of *spinlock to expose the write. The + memory barrier is to stop *other* writes being moved past this code. */ + __asm__ __volatile__("clearf\n" + "0:\n\t" + "movu.b [%2],%0\n\t" + "ax\n\t" + "move.b %3,[%2]\n\t" + "bwf 0b\n\t" + "clearf" + : "=&r" (ret), "=m" (*spinlock) + : "r" (spinlock), "r" ((int) 1) + : "memory"); + return ret; +} + + +/* Get some notion of the current stack. Need not be exactly the top + of the stack, just something somewhere in the current frame. + I don't trust register variables, so let's do this the safe way. */ +#define CURRENT_STACK_FRAME \ + ({ char *sp; __asm__ ("move.d $sp,%0" : "=rm" (sp)); sp; }) + +#endif /* pt-machine.h */ diff --git a/linuxthreads/sysdeps/hppa/pspinlock.c b/linuxthreads/sysdeps/hppa/pspinlock.c new file mode 100644 index 0000000000..7f481fa4b6 --- /dev/null +++ b/linuxthreads/sysdeps/hppa/pspinlock.c @@ -0,0 +1,81 @@ +/* POSIX spinlock implementation. hppa version. + Copyright (C) 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; 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 "internals.h" + +int +__pthread_spin_lock (pthread_spinlock_t *lock) +{ + unsigned int val; + + do + asm volatile ("ldcw %1,%0" + : "=r" (val), "=m" (*lock) + : "m" (*lock)); + while (!val); + + return 0; +} +weak_alias (__pthread_spin_lock, pthread_spin_lock) + + +int +__pthread_spin_trylock (pthread_spinlock_t *lock) +{ + unsigned int val; + + asm volatile ("ldcw %1,%0" + : "=r" (val), "=m" (*lock) + : "m" (*lock)); + + return val ? 0 : EBUSY; +} +weak_alias (__pthread_spin_trylock, pthread_spin_trylock) + + +int +__pthread_spin_unlock (pthread_spinlock_t *lock) +{ + *lock = 1; + return 0; +} +weak_alias (__pthread_spin_unlock, pthread_spin_unlock) + + +int +__pthread_spin_init (pthread_spinlock_t *lock, int pshared) +{ + /* We can ignore the `pshared' parameter. Since we are busy-waiting + all processes which can access the memory location `lock' points + to can use the spinlock. */ + *lock = 1; + return 0; +} +weak_alias (__pthread_spin_init, pthread_spin_init) + + +int +__pthread_spin_destroy (pthread_spinlock_t *lock) +{ + /* Nothing to do. */ + return 0; +} +weak_alias (__pthread_spin_destroy, pthread_spin_destroy) diff --git a/linuxthreads/sysdeps/hppa/pt-machine.h b/linuxthreads/sysdeps/hppa/pt-machine.h new file mode 100644 index 0000000000..abc25c4ca4 --- /dev/null +++ b/linuxthreads/sysdeps/hppa/pt-machine.h @@ -0,0 +1,62 @@ +/* Machine-dependent pthreads configuration and inline functions. + hppa version. + Copyright (C) 2000, 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Richard Henderson <rth@tamu.edu>. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; 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 _PT_MACHINE_H +#define _PT_MACHINE_H 1 + +#include <bits/initspin.h> + +#ifndef PT_EI +# define PT_EI extern inline __attribute__ ((always_inline)) +#endif + +extern long int testandset (int *spinlock); +extern int __compare_and_swap (long int *p, long int oldval, long int newval); + +/* Get some notion of the current stack. Need not be exactly the top + of the stack, just something somewhere in the current frame. */ +#define CURRENT_STACK_FRAME stack_pointer +register char * stack_pointer __asm__ ("%r30"); + + +/* The hppa only has one atomic read and modify memory operation, + load and clear, so hppa spinlocks must use zero to signify that + someone is holding the lock. */ + +#define xstr(s) str(s) +#define str(s) #s +/* Spinlock implementation; required. */ +PT_EI long int +testandset (int *spinlock) +{ + int ret; + + __asm__ __volatile__( + "ldcw 0(%2),%0" + : "=r"(ret), "=m"(*spinlock) + : "r"(spinlock)); + + return ret == 0; +} +#undef str +#undef xstr + +#endif /* pt-machine.h */ diff --git a/linuxthreads/sysdeps/i386/Makefile b/linuxthreads/sysdeps/i386/Makefile new file mode 100644 index 0000000000..418fa5c6ef --- /dev/null +++ b/linuxthreads/sysdeps/i386/Makefile @@ -0,0 +1,23 @@ +ifeq ($(subdir),linuxthreads) +# On i686 we must avoid generating the trampoline functions generated +# to get the GOT pointer. +CFLAGS-pt-initfini.s += -march=i386 -mcpu=i386 + +# Most files must not be compiled without frame pointer since we need +# the frame base address which is stored in %ebp unless the frame pointer +# is optimized out. +CFLAGS-cancel.c += -fno-omit-frame-pointer -mpreferred-stack-boundary=4 +CFLAGS-condvar.c += -fno-omit-frame-pointer +CFLAGS-join.c += -fno-omit-frame-pointer +CFLAGS-manager.c += -fno-omit-frame-pointer -mpreferred-stack-boundary=4 +CFLAGS-oldsemaphore.c += -fno-omit-frame-pointer +CFLAGS-pthread.c += -fno-omit-frame-pointer -mpreferred-stack-boundary=4 +CFLAGS-ptlongjmp.c += -fno-omit-frame-pointer +CFLAGS-semaphore.c += -fno-omit-frame-pointer +CFLAGS-sighandler.c += -fno-omit-frame-pointer -mpreferred-stack-boundary=4 +CFLAGS-tst-align.c += -mpreferred-stack-boundary=4 +endif + +ifeq ($(subdir),csu) +gen-as-const-headers += tcb-offsets.sym +endif diff --git a/linuxthreads/sysdeps/i386/i586/Versions b/linuxthreads/sysdeps/i386/i586/Versions new file mode 100644 index 0000000000..32da57080d --- /dev/null +++ b/linuxthreads/sysdeps/i386/i586/Versions @@ -0,0 +1,5 @@ +libpthread { + GLIBC_PRIVATE { + __pthread_clock_gettime; __pthread_clock_settime; + } +} diff --git a/linuxthreads/sysdeps/i386/i686/Versions b/linuxthreads/sysdeps/i386/i686/Versions new file mode 100644 index 0000000000..32da57080d --- /dev/null +++ b/linuxthreads/sysdeps/i386/i686/Versions @@ -0,0 +1,5 @@ +libpthread { + GLIBC_PRIVATE { + __pthread_clock_gettime; __pthread_clock_settime; + } +} diff --git a/linuxthreads/sysdeps/i386/i686/pt-machine.h b/linuxthreads/sysdeps/i386/i686/pt-machine.h new file mode 100644 index 0000000000..1c75bf9807 --- /dev/null +++ b/linuxthreads/sysdeps/i386/i686/pt-machine.h @@ -0,0 +1,79 @@ +/* Machine-dependent pthreads configuration and inline functions. + i686 version. + Copyright (C) 1996-2001, 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Richard Henderson <rth@tamu.edu>. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; 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 _PT_MACHINE_H +#define _PT_MACHINE_H 1 + +#ifndef PT_EI +# define PT_EI extern inline __attribute__ ((always_inline)) +#endif +#include "kernel-features.h" + +#ifndef __ASSEMBLER__ +extern long int testandset (int *spinlock); +extern int __compare_and_swap (long int *p, long int oldval, long int newval); + +/* Get some notion of the current stack. Need not be exactly the top + of the stack, just something somewhere in the current frame. */ +#define CURRENT_STACK_FRAME __builtin_frame_address (0) + + +/* Spinlock implementation; required. */ +PT_EI long int +testandset (int *spinlock) +{ + long int ret; + + __asm__ __volatile__ ( + "xchgl %0, %1" + : "=r" (ret), "=m" (*spinlock) + : "0" (1), "m" (*spinlock) + : "memory"); + + return ret; +} + + +/* Compare-and-swap for semaphores. It's always available on i686. */ +#define HAS_COMPARE_AND_SWAP + +PT_EI int +__compare_and_swap (long int *p, long int oldval, long int newval) +{ + char ret; + long int readval; + + __asm__ __volatile__ ("lock; cmpxchgl %3, %1; sete %0" + : "=q" (ret), "=m" (*p), "=a" (readval) + : "r" (newval), "m" (*p), "a" (oldval) + : "memory"); + return ret; +} +#endif + +#if __ASSUME_LDT_WORKS > 0 +#include "../useldt.h" +#endif + +/* The P4 and above really want some help to prevent overheating. */ +#define BUSY_WAIT_NOP __asm__ ("rep; nop") + +#endif /* pt-machine.h */ diff --git a/linuxthreads/sysdeps/i386/pspinlock.c b/linuxthreads/sysdeps/i386/pspinlock.c new file mode 100644 index 0000000000..6a70093957 --- /dev/null +++ b/linuxthreads/sysdeps/i386/pspinlock.c @@ -0,0 +1,103 @@ +/* POSIX spinlock implementation. x86 version. + Copyright (C) 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. */ + +#include <errno.h> +#include <pthread.h> +#include "internals.h" +#include "kernel-features.h" + + +/* This implementation is similar to the one used in the Linux kernel. + But the kernel is byte instructions for the memory access. This is + faster but unusable here. The problem is that only 128 + threads/processes could use the spinlock at the same time. If (by + a design error in the program) a thread/process would hold the + spinlock for a time long enough to accumulate 128 waiting + processes, the next one will find a positive value in the spinlock + and assume it is unlocked. We cannot accept that. */ + +int +__pthread_spin_lock (pthread_spinlock_t *lock) +{ + asm volatile + ("\n" + "1:\n\t" + "lock; decl %0\n\t" + "js 2f\n\t" + ".section .text.spinlock,\"ax\"\n" + "2:\n\t" + "cmpl $0,%0\n\t" + "rep; nop\n\t" + "jle 2b\n\t" + "jmp 1b\n\t" + ".previous" + : "=m" (*lock)); + return 0; +} +weak_alias (__pthread_spin_lock, pthread_spin_lock) + + +int +__pthread_spin_trylock (pthread_spinlock_t *lock) +{ + int oldval; + + asm volatile + ("xchgl %0,%1" + : "=r" (oldval), "=m" (*lock) + : "0" (0)); + return oldval > 0 ? 0 : EBUSY; +} +weak_alias (__pthread_spin_trylock, pthread_spin_trylock) + + +int +__pthread_spin_unlock (pthread_spinlock_t *lock) +{ + asm volatile + ("movl $1,%0" + : "=m" (*lock)); + return 0; +} +weak_alias (__pthread_spin_unlock, pthread_spin_unlock) + + +int +__pthread_spin_init (pthread_spinlock_t *lock, int pshared) +{ + /* We can ignore the `pshared' parameter. Since we are busy-waiting + all processes which can access the memory location `lock' points + to can use the spinlock. */ + *lock = 1; + return 0; +} +weak_alias (__pthread_spin_init, pthread_spin_init) + + +int +__pthread_spin_destroy (pthread_spinlock_t *lock) +{ + /* Nothing to do. */ + return 0; +} +weak_alias (__pthread_spin_destroy, pthread_spin_destroy) + +#ifndef __ASSUME_SET_THREAD_AREA_SYSCALL +int __have_no_set_thread_area; +#endif diff --git a/linuxthreads/sysdeps/i386/pt-machine.h b/linuxthreads/sysdeps/i386/pt-machine.h new file mode 100644 index 0000000000..0df096d152 --- /dev/null +++ b/linuxthreads/sysdeps/i386/pt-machine.h @@ -0,0 +1,108 @@ +/* Machine-dependent pthreads configuration and inline functions. + i386 version. + Copyright (C) 1996-2001, 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Richard Henderson <rth@tamu.edu>. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; 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 _PT_MACHINE_H +#define _PT_MACHINE_H 1 + +#ifndef __ASSEMBLER__ +#ifndef PT_EI +# define PT_EI extern inline __attribute__ ((always_inline)) +#endif + +extern long int testandset (int *spinlock); +extern int __compare_and_swap (long int *p, long int oldval, long int newval); + +/* Get some notion of the current stack. Need not be exactly the top + of the stack, just something somewhere in the current frame. */ +#define CURRENT_STACK_FRAME __builtin_frame_address (0) + + +/* Spinlock implementation; required. */ +PT_EI long int +testandset (int *spinlock) +{ + long int ret; + + __asm__ __volatile__( + "xchgl %0, %1" + : "=r"(ret), "=m"(*spinlock) + : "0"(1), "m"(*spinlock) + : "memory"); + + return ret; +} + + +/* Compare-and-swap for semaphores. + Available on the 486 and above, but not on the 386. + We test dynamically whether it's available or not. */ + +#define HAS_COMPARE_AND_SWAP +#define TEST_FOR_COMPARE_AND_SWAP + +PT_EI int +__compare_and_swap (long int *p, long int oldval, long int newval) +{ + char ret; + long int readval; + + __asm__ __volatile__ ("lock; cmpxchgl %3, %1; sete %0" + : "=q" (ret), "=m" (*p), "=a" (readval) + : "r" (newval), "m" (*p), "a" (oldval) + : "memory"); + return ret; +} + + +PT_EI int +get_eflags (void) +{ + int res; + __asm__ __volatile__ ("pushfl; popl %0" : "=r" (res) : ); + return res; +} + + +PT_EI void +set_eflags (int newflags) +{ + __asm__ __volatile__ ("pushl %0; popfl" : : "r" (newflags) : "cc"); +} + + +PT_EI int +compare_and_swap_is_available (void) +{ + int oldflags = get_eflags (); + int changed; + /* Flip AC bit in EFLAGS. */ + set_eflags (oldflags ^ 0x40000); + /* See if bit changed. */ + changed = (get_eflags () ^ oldflags) & 0x40000; + /* Restore EFLAGS. */ + set_eflags (oldflags); + /* If the AC flag did not change, it's a 386 and it lacks cmpxchg. + Otherwise, it's a 486 or above and it has cmpxchg. */ + return changed != 0; +} +#endif /* __ASSEMBLER__ */ + +#endif /* pt-machine.h */ diff --git a/linuxthreads/sysdeps/i386/tcb-offsets.sym b/linuxthreads/sysdeps/i386/tcb-offsets.sym new file mode 100644 index 0000000000..69a5018d88 --- /dev/null +++ b/linuxthreads/sysdeps/i386/tcb-offsets.sym @@ -0,0 +1,7 @@ +#include <sysdep.h> +#include <tls.h> + +MULTIPLE_THREADS_OFFSET offsetof (tcbhead_t, multiple_threads) +#ifdef NEED_DL_SYSINFO +SYSINFO_OFFSET offsetof (tcbhead_t, sysinfo) +#endif diff --git a/linuxthreads/sysdeps/i386/tls.h b/linuxthreads/sysdeps/i386/tls.h new file mode 100644 index 0000000000..5306d082bb --- /dev/null +++ b/linuxthreads/sysdeps/i386/tls.h @@ -0,0 +1,225 @@ +/* Definition for thread-local data handling. linuxthreads/i386 version. + 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 _TLS_H +#define _TLS_H + +# include <dl-sysdep.h> +# include <pt-machine.h> + +#ifndef __ASSEMBLER__ +# include <stddef.h> +# include <stdint.h> + +/* Type for the dtv. */ +typedef union dtv +{ + size_t counter; + void *pointer; +} dtv_t; + + +typedef struct +{ + void *tcb; /* Pointer to the TCB. Not necessary the + thread descriptor used by libpthread. */ + dtv_t *dtv; + void *self; /* Pointer to the thread descriptor. */ + int multiple_threads; +#ifdef NEED_DL_SYSINFO + uintptr_t sysinfo; +#endif +} tcbhead_t; + +#else /* __ASSEMBLER__ */ +# include <tcb-offsets.h> +#endif + +/* We can support TLS only if the floating-stack support is available. + However, we want to compile in the support and test at runtime whether + the running kernel can support it or not. To avoid bothering with the + TLS support code at all, use configure --without-tls. + + We need USE_TLS to be consistently defined, for ldsodefs.h conditionals. + But some of the code below can cause problems in building libpthread + (e.g. useldt.h will defined FLOATING_STACKS when it shouldn't). */ + +#if defined HAVE_TLS_SUPPORT \ + && (defined FLOATING_STACKS || !defined IS_IN_libpthread) + +/* Signal that TLS support is available. */ +# define USE_TLS 1 + +# ifndef __ASSEMBLER__ +/* Get system call information. */ +# include <sysdep.h> + + +/* Get the thread descriptor definition. */ +# include <linuxthreads/descr.h> + +/* This is the size of the initial TCB. */ +# define TLS_INIT_TCB_SIZE sizeof (tcbhead_t) + +/* Alignment requirements for the initial TCB. */ +# define TLS_INIT_TCB_ALIGN __alignof__ (tcbhead_t) + +/* This is the size of the TCB. */ +# define TLS_TCB_SIZE sizeof (struct _pthread_descr_struct) + +/* Alignment requirements for the TCB. */ +# define TLS_TCB_ALIGN __alignof__ (struct _pthread_descr_struct) + +/* The TCB can have any size and the memory following the address the + thread pointer points to is unspecified. Allocate the TCB there. */ +# define TLS_TCB_AT_TP 1 + + +/* Install the dtv pointer. The pointer passed is to the element with + index -1 which contain the length. */ +# define INSTALL_DTV(descr, dtvp) \ + ((tcbhead_t *) (descr))->dtv = (dtvp) + 1 + +/* Install new dtv for current thread. */ +# define INSTALL_NEW_DTV(dtv) \ + ({ struct _pthread_descr_struct *__descr; \ + THREAD_SETMEM (__descr, p_header.data.dtvp, (dtv)); }) + +/* Return dtv of given thread descriptor. */ +# define GET_DTV(descr) \ + (((tcbhead_t *) (descr))->dtv) + +# 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 IS_IN_linuxthreads && !defined DO_MODIFY_LDT +# include "useldt.h" /* For the structure. */ +# endif +# if __ASSUME_LDT_WORKS > 0 +# define TLS_DO_MODIFY_LDT_KERNEL_CHECK(doit) (doit) /* Nothing to check. */ +# else +# define TLS_DO_MODIFY_LDT_KERNEL_CHECK(doit) \ + (__builtin_expect (GLRO(dl_osversion) < 131939, 0) \ + ? "kernel too old for thread-local storage support\n" \ + : (doit)) +# endif + +# define TLS_DO_MODIFY_LDT(descr, nr) \ +TLS_DO_MODIFY_LDT_KERNEL_CHECK( \ +({ \ + struct modify_ldt_ldt_s ldt_entry = \ + { nr, (unsigned long int) (descr), 0xfffff /* 4GB in pages */, \ + 1, 0, 0, 1, 0, 1, 0 }; \ + int result; \ + asm volatile (TLS_LOAD_EBX \ + "int $0x80\n\t" \ + TLS_LOAD_EBX \ + : "=a" (result) \ + : "0" (__NR_modify_ldt), \ + /* The extra argument with the "m" constraint is necessary \ + to let the compiler know that we are accessing LDT_ENTRY \ + here. */ \ + "m" (ldt_entry), TLS_EBX_ARG (1), "c" (&ldt_entry), \ + "d" (sizeof (ldt_entry))); \ + __builtin_expect (result, 0) == 0 \ + ? ({ asm ("movw %w0, %%gs" : : "q" ((nr) * 8 + 7)); NULL; }) \ + : "cannot set up LDT for thread-local storage\n"; \ +})) + +# define TLS_DO_SET_THREAD_AREA(descr, secondcall) \ +({ \ + struct modify_ldt_ldt_s ldt_entry = \ + { -1, (unsigned long int) (descr), 0xfffff /* 4GB in pages */, \ + 1, 0, 0, 1, 0, 1, 0 }; \ + int result; \ + if (secondcall) \ + ldt_entry.entry_number = ({ int _gs; \ + asm ("movw %%gs, %w0" : "=q" (_gs)); \ + (_gs & 0xffff) >> 3; }); \ + asm volatile (TLS_LOAD_EBX \ + "int $0x80\n\t" \ + TLS_LOAD_EBX \ + : "=a" (result), "=m" (ldt_entry.entry_number) \ + : "0" (__NR_set_thread_area), \ + /* The extra argument with the "m" constraint is necessary \ + to let the compiler know that we are accessing LDT_ENTRY \ + here. */ \ + TLS_EBX_ARG (&ldt_entry), "m" (ldt_entry)); \ + if (__builtin_expect (result, 0) == 0) \ + asm ("movw %w0, %%gs" : : "q" (ldt_entry.entry_number * 8 + 3)); \ + result; \ +}) + +# ifdef __ASSUME_SET_THREAD_AREA_SYSCALL +# define TLS_SETUP_GS_SEGMENT(descr, secondcall) \ + (TLS_DO_SET_THREAD_AREA (descr, secondcall) \ + ? "set_thread_area failed when setting up thread-local storage\n" : NULL) +# elif defined __NR_set_thread_area +# define TLS_SETUP_GS_SEGMENT(descr, secondcall) \ + (TLS_DO_SET_THREAD_AREA (descr, secondcall) \ + ? TLS_DO_MODIFY_LDT (descr, 0) : NULL) +# else +# define TLS_SETUP_GS_SEGMENT(descr, secondcall) \ + TLS_DO_MODIFY_LDT ((descr), 0) +# endif + +#if defined NEED_DL_SYSINFO +# define INIT_SYSINFO \ + head->sysinfo = GLRO(dl_sysinfo) +#else +# define INIT_SYSINFO +#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. + + The value of this macro is null if successful, or an error string. */ +# define TLS_INIT_TP(descr, secondcall) \ + ({ \ + void *_descr = (descr); \ + tcbhead_t *head = _descr; \ + \ + head->tcb = _descr; \ + /* For now the thread descriptor is at the same address. */ \ + head->self = _descr; \ + \ + INIT_SYSINFO; \ + TLS_SETUP_GS_SEGMENT (_descr, secondcall); \ + }) + +/* Indicate that dynamic linker shouldn't try to initialize TLS even + when no PT_TLS segments are found in the program and libraries + it is linked against. */ +# define TLS_INIT_TP_EXPENSIVE 1 + +/* Return the address of the dtv for the current thread. */ +# define THREAD_DTV() \ + ({ struct _pthread_descr_struct *__descr; \ + THREAD_GETMEM (__descr, p_header.data.dtvp); }) + +# endif /* HAVE_TLS_SUPPORT && (FLOATING_STACKS || !IS_IN_libpthread) */ +#endif /* __ASSEMBLER__ */ + +#endif /* tls.h */ diff --git a/linuxthreads/sysdeps/i386/useldt.h b/linuxthreads/sysdeps/i386/useldt.h new file mode 100644 index 0000000000..4ac82f1ab0 --- /dev/null +++ b/linuxthreads/sysdeps/i386/useldt.h @@ -0,0 +1,314 @@ +/* Special definitions for ix86 machine using segment register based + thread descriptor. + Copyright (C) 1998, 2000, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.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. */ + +#ifndef __ASSEMBLER__ +#include <stddef.h> /* For offsetof. */ +#include <stdlib.h> /* For abort(). */ +#include <sysdep.h> + + +/* We don't want to include the kernel header. So duplicate the + information. */ + +/* Structure passed on `modify_ldt' call. */ +struct modify_ldt_ldt_s +{ + 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; +}; + +/* System call to set LDT entry. */ +extern int __modify_ldt (int, struct modify_ldt_ldt_s *, size_t); + + +/* 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 \ +({ \ + register pthread_descr __self; \ + __asm__ ("movl %%gs:%c1,%0" : "=r" (__self) \ + : "i" (offsetof (struct _pthread_descr_struct, \ + p_header.data.self))); \ + __self; \ +}) + + +/* Initialize the thread-unique value. Two possible ways to do it. */ + +#define DO_MODIFY_LDT(descr, nr) \ +({ \ + struct modify_ldt_ldt_s ldt_entry = \ + { nr, (unsigned long int) (descr), 0xfffff /* 4GB in pages */, \ + 1, 0, 0, 1, 0, 1, 0 }; \ + if (__modify_ldt (1, &ldt_entry, sizeof (ldt_entry)) != 0) \ + abort (); \ + asm ("movw %w0, %%gs" : : "q" (nr * 8 + 7)); \ +}) + +#ifdef __PIC__ +# define USETLS_EBX_ARG "r" +# define USETLS_LOAD_EBX "xchgl %1, %%ebx\n\t" +#else +# define USETLS_EBX_ARG "b" +# define USETLS_LOAD_EBX +#endif + +/* When using the new set_thread_area call, we don't need to change %gs + because we inherited the value set up in the main thread by TLS setup. + We need to extract that value and set up the same segment in this + thread. */ +#if USE_TLS +# define DO_SET_THREAD_AREA_REUSE(nr) 1 +#else +/* Without TLS, we do the initialization of the main thread, where NR == 0. */ +# define DO_SET_THREAD_AREA_REUSE(nr) (!__builtin_constant_p (nr) || (nr)) +#endif +#define DO_SET_THREAD_AREA(descr, nr) \ +({ \ + int __gs; \ + if (DO_SET_THREAD_AREA_REUSE (nr)) \ + { \ + asm ("movw %%gs, %w0" : "=q" (__gs)); \ + struct modify_ldt_ldt_s ldt_entry = \ + { (__gs & 0xffff) >> 3, \ + (unsigned long int) (descr), 0xfffff /* 4GB in pages */, \ + 1, 0, 0, 1, 0, 1, 0 }; \ + \ + int __result; \ + __asm (USETLS_LOAD_EBX \ + "movl %2, %%eax\n\t" \ + "int $0x80\n\t" \ + USETLS_LOAD_EBX \ + : "=&a" (__result) \ + : USETLS_EBX_ARG (&ldt_entry), "i" (__NR_set_thread_area), \ + "m" (ldt_entry) \ + : "memory"); \ + if (__result == 0) \ + asm ("movw %w0, %%gs" :: "q" (__gs)); \ + else \ + __gs = -1; \ + } \ + else \ + { \ + struct modify_ldt_ldt_s ldt_entry = \ + { -1, \ + (unsigned long int) (descr), 0xfffff /* 4GB in pages */, \ + 1, 0, 0, 1, 0, 1, 0 }; \ + int __result; \ + __asm (USETLS_LOAD_EBX \ + "movl %2, %%eax\n\t" \ + "int $0x80\n\t" \ + USETLS_LOAD_EBX \ + : "=&a" (__result) \ + : USETLS_EBX_ARG (&ldt_entry), "i" (__NR_set_thread_area), \ + "m" (ldt_entry) \ + : "memory"); \ + if (__result == 0) \ + { \ + __gs = (ldt_entry.entry_number << 3) + 3; \ + asm ("movw %w0, %%gs" : : "q" (__gs)); \ + } \ + else \ + __gs = -1; \ + } \ + __gs; \ +}) + +#if defined __ASSUME_SET_THREAD_AREA_SYSCALL +# define INIT_THREAD_SELF(descr, nr) DO_SET_THREAD_AREA (descr, nr) +#elif defined __NR_set_thread_area +# define INIT_THREAD_SELF(descr, nr) \ +({ \ + if (__builtin_expect (__have_no_set_thread_area, 0) \ + || (DO_SET_THREAD_AREA (descr, DO_SET_THREAD_AREA_REUSE (nr)) == -1 \ + && (__have_no_set_thread_area = 1))) \ + DO_MODIFY_LDT (descr, nr); \ +}) +/* Defined in pspinlock.c. */ +extern int __have_no_set_thread_area; +#else +# define INIT_THREAD_SELF(descr, nr) DO_MODIFY_LDT (descr, nr) +#endif + +/* Free resources associated with thread descriptor. */ +#ifdef __ASSUME_SET_THREAD_AREA_SYSCALL +#define FREE_THREAD(descr, nr) do { } while (0) +#elif defined __NR_set_thread_area +#define FREE_THREAD(descr, nr) \ +{ \ + int __gs; \ + __asm__ __volatile__ ("movw %%gs, %w0" : "=q" (__gs)); \ + if (__builtin_expect (__gs & 4, 0)) \ + { \ + struct modify_ldt_ldt_s ldt_entry = \ + { nr, 0, 0, 0, 0, 1, 0, 1, 0, 0 }; \ + __modify_ldt (1, &ldt_entry, sizeof (ldt_entry)); \ + } \ +} +#else +#define FREE_THREAD(descr, nr) \ +{ \ + struct modify_ldt_ldt_s ldt_entry = \ + { nr, 0, 0, 0, 0, 1, 0, 1, 0, 0 }; \ + __modify_ldt (1, &ldt_entry, sizeof (ldt_entry)); \ +} +#endif + +/* 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_descr_struct, \ + member))); \ + else if (sizeof (__value) == 4) \ + __asm__ __volatile__ ("movl %%gs:%P1,%0" \ + : "=r" (__value) \ + : "i" (offsetof (struct _pthread_descr_struct, \ + 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_descr_struct, \ + member)), \ + "i" (offsetof (struct _pthread_descr_struct, \ + member) + 4)); \ + } \ + __value; \ +}) + +/* Same as THREAD_GETMEM, but the member offset can be non-constant. */ +#define THREAD_GETMEM_NC(descr, member) \ +({ \ + __typeof__ (descr->member) __value; \ + if (sizeof (__value) == 1) \ + __asm__ __volatile__ ("movb %%gs:(%2),%b0" \ + : "=q" (__value) \ + : "0" (0), \ + "r" (offsetof (struct _pthread_descr_struct, \ + member))); \ + else if (sizeof (__value) == 4) \ + __asm__ __volatile__ ("movl %%gs:(%1),%0" \ + : "=r" (__value) \ + : "r" (offsetof (struct _pthread_descr_struct, \ + 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:(%1),%%eax\n\t" \ + "movl %%gs:4(%1),%%edx" \ + : "=&A" (__value) \ + : "r" (offsetof (struct _pthread_descr_struct, \ + member))); \ + } \ + __value; \ +}) + +/* Same as THREAD_SETMEM, but the member offset can be non-constant. */ +#define THREAD_SETMEM(descr, member, value) \ +({ \ + __typeof__ (descr->member) __value = (value); \ + if (sizeof (__value) == 1) \ + __asm__ __volatile__ ("movb %0,%%gs:%P1" : \ + : "q" (__value), \ + "i" (offsetof (struct _pthread_descr_struct, \ + member))); \ + else if (sizeof (__value) == 4) \ + __asm__ __volatile__ ("movl %0,%%gs:%P1" : \ + : "r" (__value), \ + "i" (offsetof (struct _pthread_descr_struct, \ + 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 %%eax,%%gs:%P1\n\n" \ + "movl %%edx,%%gs:%P2" : \ + : "A" (__value), \ + "i" (offsetof (struct _pthread_descr_struct, \ + member)), \ + "i" (offsetof (struct _pthread_descr_struct, \ + member) + 4)); \ + } \ +}) + +/* Set member of the thread descriptor directly. */ +#define THREAD_SETMEM_NC(descr, member, value) \ +({ \ + __typeof__ (descr->member) __value = (value); \ + if (sizeof (__value) == 1) \ + __asm__ __volatile__ ("movb %0,%%gs:(%1)" : \ + : "q" (__value), \ + "r" (offsetof (struct _pthread_descr_struct, \ + member))); \ + else if (sizeof (__value) == 4) \ + __asm__ __volatile__ ("movl %0,%%gs:(%1)" : \ + : "r" (__value), \ + "r" (offsetof (struct _pthread_descr_struct, \ + 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 %%eax,%%gs:(%1)\n\t" \ + "movl %%edx,%%gs:4(%1)" : \ + : "A" (__value), \ + "r" (offsetof (struct _pthread_descr_struct, \ + member))); \ + } \ +}) +#endif + +#if __ASSUME_LDT_WORKS > 0 +/* We want the OS to assign stack addresses. */ +#define FLOATING_STACKS 1 + +/* Maximum size of the stack if the rlimit is unlimited. */ +#define ARCH_STACK_MAX_SIZE 8*1024*1024 +#endif diff --git a/linuxthreads/sysdeps/ia64/Makefile b/linuxthreads/sysdeps/ia64/Makefile new file mode 100644 index 0000000000..81bddf688c --- /dev/null +++ b/linuxthreads/sysdeps/ia64/Makefile @@ -0,0 +1,3 @@ +ifeq ($(subdir),csu) +gen-as-const-headers += tcb-offsets.sym +endif diff --git a/linuxthreads/sysdeps/ia64/Versions b/linuxthreads/sysdeps/ia64/Versions new file mode 100644 index 0000000000..32da57080d --- /dev/null +++ b/linuxthreads/sysdeps/ia64/Versions @@ -0,0 +1,5 @@ +libpthread { + GLIBC_PRIVATE { + __pthread_clock_gettime; __pthread_clock_settime; + } +} diff --git a/linuxthreads/sysdeps/ia64/pspinlock.c b/linuxthreads/sysdeps/ia64/pspinlock.c new file mode 100644 index 0000000000..14c7f3a181 --- /dev/null +++ b/linuxthreads/sysdeps/ia64/pspinlock.c @@ -0,0 +1,79 @@ +/* POSIX spinlock implementation. ia64 version. + Copyright (C) 2000, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jes Sorensen <jes@linuxcare.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 <errno.h> +#include <pthread.h> +#include "internals.h" +#include <ia64intrin.h> + +/* This implementation is inspired by the implementation used in the + Linux kernel. */ + +int +__pthread_spin_lock (pthread_spinlock_t *lock) +{ + int *p = (int *) lock; + + while (__builtin_expect (__sync_val_compare_and_swap_si (p, 0, 1), 0)) + { + /* Spin without using the atomic instruction. */ + do + __asm __volatile ("" : : : "memory"); + while (*p); + } + return 0; +} +weak_alias (__pthread_spin_lock, pthread_spin_lock) + + +int +__pthread_spin_trylock (pthread_spinlock_t *lock) +{ + return __sync_val_compare_and_swap_si ((int *) lock, 0, 1) == 0 ? 0 : EBUSY; +} +weak_alias (__pthread_spin_trylock, pthread_spin_trylock) + + +int +__pthread_spin_unlock (pthread_spinlock_t *lock) +{ + return *lock = 0; +} +weak_alias (__pthread_spin_unlock, pthread_spin_unlock) + + +int +__pthread_spin_init (pthread_spinlock_t *lock, int pshared) +{ + /* We can ignore the `pshared' parameter. Since we are busy-waiting + all processes which can access the memory location `lock' points + to can use the spinlock. */ + return *lock = 0; +} +weak_alias (__pthread_spin_init, pthread_spin_init) + + +int +__pthread_spin_destroy (pthread_spinlock_t *lock) +{ + /* Nothing to do. */ + return 0; +} +weak_alias (__pthread_spin_destroy, pthread_spin_destroy) diff --git a/linuxthreads/sysdeps/ia64/pt-machine.h b/linuxthreads/sysdeps/ia64/pt-machine.h new file mode 100644 index 0000000000..6c5dfe93bb --- /dev/null +++ b/linuxthreads/sysdeps/ia64/pt-machine.h @@ -0,0 +1,133 @@ +/* Machine-dependent pthreads configuration and inline functions. + IA-64 version. + Copyright (C) 1999, 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. */ + +#ifndef _PT_MACHINE_H +#define _PT_MACHINE_H 1 + +#include <ia64intrin.h> + +#ifndef PT_EI +# define PT_EI extern inline __attribute__ ((always_inline)) +#endif + +extern long int testandset (int *spinlock); +extern int __compare_and_swap (long int *p, long int oldval, long int newval); + +/* Make sure gcc doesn't try to be clever and move things around on + us. We need to use _exactly_ the address the user gave us, not some + alias that contains the same information. */ +#define __atomic_fool_gcc(x) (*(volatile struct { int a[100]; } *)x) + +#ifndef ELF_MACHINE_NAME + +#define NEED_SEPARATE_REGISTER_STACK + +/* We want the OS to assign stack addresses. */ +#define FLOATING_STACKS 1 + +/* Maximum size of the stack if the rlimit is unlimited. */ +#define ARCH_STACK_MAX_SIZE 32*1024*1024 + +/* Get some notion of the current stack. Need not be exactly the top + of the stack, just something somewhere in the current frame. + r12 (sp) is the stack pointer. */ +#define CURRENT_STACK_FRAME stack_pointer +register char *stack_pointer __asm__ ("sp"); + + +/* Register r13 (tp) is reserved by the ABI as "thread pointer". */ +struct _pthread_descr_struct; +register struct _pthread_descr_struct *__thread_self __asm__("r13"); + +/* Return the thread descriptor for the current thread. */ +#define THREAD_SELF __thread_self + +/* Initialize the thread-unique value. */ +#define INIT_THREAD_SELF(descr, nr) (__thread_self = (descr)) + + +/* Access to data in the thread descriptor is easy. */ +#define THREAD_GETMEM(descr, member) \ + ((void) sizeof (descr), THREAD_SELF->member) +#define THREAD_GETMEM_NC(descr, member) \ + ((void) sizeof (descr), THREAD_SELF->member) +#define THREAD_SETMEM(descr, member, value) \ + ((void) sizeof (descr), THREAD_SELF->member = (value)) +#define THREAD_SETMEM_NC(descr, member, value) \ + ((void) sizeof (descr), THREAD_SELF->member = (value)) + + +/* Memory barrier */ +#define MEMORY_BARRIER() __sync_synchronize () + + +#define HAS_COMPARE_AND_SWAP_WITH_RELEASE_SEMANTICS + +PT_EI int +__compare_and_swap (long int *p, long int oldval, long int newval) +{ + long int readval; + + __asm__ __volatile__ + ("mov ar.ccv=%4;;\n\t" + "cmpxchg8.acq %0=%1,%2,ar.ccv" + : "=r" (readval), "=m" (__atomic_fool_gcc (p)) + : "r"(newval), "m" (__atomic_fool_gcc (p)), "r" (oldval) + : "memory"); + return readval == oldval; +} + +PT_EI int +__compare_and_swap_with_release_semantics (long int *p, + long int oldval, + long int newval) +{ + long int readval; + + __asm__ __volatile__ + ("mov ar.ccv=%4;;\n\t" + "cmpxchg8.rel %0=%1,%2,ar.ccv" + : "=r" (readval), "=m" (__atomic_fool_gcc (p)) + : "r"(newval), "m" (__atomic_fool_gcc (p)), "r" (oldval) + : "memory"); + return readval == oldval; +} + +#endif /* ELF_MACHINE_NAME */ + +/* Spinlock implementation; required. */ +PT_EI long int +testandset (int *spinlock) +{ + long int ret; + + __asm__ __volatile__( + "xchg4 %0=%1,%2" + : "=r"(ret), "=m"(__atomic_fool_gcc (spinlock)) + : "r"(1), "m"(__atomic_fool_gcc (spinlock)) + : "memory"); + + return ret; +} + +/* Indicate that we are looping. */ +#define BUSY_WAIT_NOP __asm__ ("hint @pause") + +#endif /* pt-machine.h */ diff --git a/linuxthreads/sysdeps/ia64/tcb-offsets.sym b/linuxthreads/sysdeps/ia64/tcb-offsets.sym new file mode 100644 index 0000000000..f7793f7665 --- /dev/null +++ b/linuxthreads/sysdeps/ia64/tcb-offsets.sym @@ -0,0 +1,9 @@ +#include <sysdep.h> +#include <tls.h> + +-- +#ifdef USE_TLS +MULTIPLE_THREADS_OFFSET offsetof (struct _pthread_descr_struct, p_multiple_threads) - sizeof (struct _pthread_descr_struct) +#else +MULTIPLE_THREADS_OFFSET offsetof (tcbhead_t, multiple_threads) +#endif diff --git a/linuxthreads/sysdeps/ia64/tls.h b/linuxthreads/sysdeps/ia64/tls.h new file mode 100644 index 0000000000..3ec2eda783 --- /dev/null +++ b/linuxthreads/sysdeps/ia64/tls.h @@ -0,0 +1,141 @@ +/* Definitions for thread-local data handling. linuxthreads/IA-64 version. + 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 _TLS_H +#define _TLS_H + +#ifndef __ASSEMBLER__ + +# include <dl-sysdep.h> +# include <pt-machine.h> +# include <stddef.h> + +/* Type for the dtv. */ +typedef union dtv +{ + size_t counter; + void *pointer; +} dtv_t; + +#else /* __ASSEMBLER__ */ +# include <tcb-offsets.h> +#endif /* __ASSEMBLER__ */ + +#ifdef HAVE_TLS_SUPPORT + +/* Signal that TLS support is available. */ +# define USE_TLS 1 + +# ifndef __ASSEMBLER__ + +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 __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_descr_struct) + +/* Alignment requirements for the TCB. */ +# define TLS_TCB_ALIGN __alignof__ (struct _pthread_descr_struct) + +/* The DTV is allocated at the TP; the TCB is placed elsewhere. */ +# define TLS_DTV_AT_TP 1 + +/* 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 *)__thread_self)->dtv = (DTV)) + +/* Return dtv of given thread descriptor. */ +# define GET_DTV(tcbp) \ + (((tcbhead_t *) (tcbp))->dtv) + +#if defined NEED_DL_SYSINFO +# define INIT_SYSINFO \ + (((tcbhead_t *) __thread_self)->private = (void *) GLRO(dl_sysinfo)) +#else +# define INIT_SYSINFO 0 +#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(tcbp, secondcall) \ + (__thread_self = (__typeof (__thread_self)) (tcbp), INIT_SYSINFO, 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. */ +# undef THREAD_SELF +# define THREAD_SELF (__thread_self - 1) + +# undef INIT_THREAD_SELF +# define INIT_THREAD_SELF(descr, nr) \ + (__thread_self = (struct _pthread_descr_struct *)(descr) + 1) + +# define TLS_MULTIPLE_THREADS_IN_TCB 1 + +/* Get the thread descriptor definition. */ +# include <linuxthreads/descr.h> + +# endif + +#else + +# ifndef __ASSEMBLER__ + +typedef struct +{ + void *tcb; + dtv_t *dtv; + void *self; + int multiple_threads; +} tcbhead_t; + +/* Get the thread descriptor definition. */ +# include <linuxthreads/descr.h> + +# define NONTLS_INIT_TP \ + do { \ + static const tcbhead_t nontls_init_tp = { .multiple_threads = 0 }; \ + __thread_self = (__typeof (__thread_self)) &nontls_init_tp; \ + } while (0) + +#endif + +#endif /* USE_TLS */ + +#endif /* tls.h */ diff --git a/linuxthreads/sysdeps/m68k/Makefile b/linuxthreads/sysdeps/m68k/Makefile new file mode 100644 index 0000000000..1cd27d44ca --- /dev/null +++ b/linuxthreads/sysdeps/m68k/Makefile @@ -0,0 +1,7 @@ +ifeq ($(subdir), linuxthreads) +object-suffixes-left := $(libpthread-nonshared) +define o-iterator-doit +$(objpfx)$o.os: pic-ccflag = -fPIC +endef +include $(o-iterator) +endif diff --git a/linuxthreads/sysdeps/m68k/pspinlock.c b/linuxthreads/sysdeps/m68k/pspinlock.c new file mode 100644 index 0000000000..30b9b9e8b9 --- /dev/null +++ b/linuxthreads/sysdeps/m68k/pspinlock.c @@ -0,0 +1,82 @@ +/* POSIX spinlock implementation. M68k version. + Copyright (C) 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; 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 "internals.h" + + +int +__pthread_spin_lock (pthread_spinlock_t *lock) +{ + unsigned int val; + + do + asm volatile ("tas %1; sne %0" + : "=dm" (val), "=m" (*lock) + : "m" (*lock) + : "cc"); + while (val); + + return 0; +} +weak_alias (__pthread_spin_lock, pthread_spin_lock) + + +int +__pthread_spin_trylock (pthread_spinlock_t *lock) +{ + unsigned int val; + + asm volatile ("tas %1; sne %0" + : "=dm" (val), "=m" (*lock) + : "m" (*lock) + : "cc"); + + return val ? EBUSY : 0; +} +weak_alias (__pthread_spin_trylock, pthread_spin_trylock) + + +int +__pthread_spin_unlock (pthread_spinlock_t *lock) +{ + return *lock = 0; +} +weak_alias (__pthread_spin_unlock, pthread_spin_unlock) + + +int +__pthread_spin_init (pthread_spinlock_t *lock, int pshared) +{ + /* We can ignore the `pshared' parameter. Since we are busy-waiting + all processes which can access the memory location `lock' points + to can use the spinlock. */ + return *lock = 0; +} +weak_alias (__pthread_spin_init, pthread_spin_init) + + +int +__pthread_spin_destroy (pthread_spinlock_t *lock) +{ + /* Nothing to do. */ + return 0; +} +weak_alias (__pthread_spin_destroy, pthread_spin_destroy) diff --git a/linuxthreads/sysdeps/m68k/pt-machine.h b/linuxthreads/sysdeps/m68k/pt-machine.h new file mode 100644 index 0000000000..ad524d6d2e --- /dev/null +++ b/linuxthreads/sysdeps/m68k/pt-machine.h @@ -0,0 +1,69 @@ +/* Machine-dependent pthreads configuration and inline functions. + m68k version. + Copyright (C) 1996, 1998, 2000, 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Richard Henderson <rth@tamu.edu>. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; 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 _PT_MACHINE_H +#define _PT_MACHINE_H 1 + +#ifndef PT_EI +# define PT_EI extern inline __attribute__ ((always_inline)) +#endif + +extern long int testandset (int *spinlock); +extern int __compare_and_swap (long int *p, long int oldval, long int newval); + +/* Spinlock implementation; required. */ +PT_EI long int +testandset (int *spinlock) +{ + char ret; + + __asm__ __volatile__("tas %1; sne %0" + : "=dm"(ret), "=m"(*spinlock) + : "m"(*spinlock) + : "cc"); + + return ret; +} + + +/* Get some notion of the current stack. Need not be exactly the top + of the stack, just something somewhere in the current frame. */ +#define CURRENT_STACK_FRAME stack_pointer +register char * stack_pointer __asm__ ("%sp"); + + +/* Compare-and-swap for semaphores. */ + +#define HAS_COMPARE_AND_SWAP +PT_EI int +__compare_and_swap (long int *p, long int oldval, long int newval) +{ + char ret; + long int readval; + + __asm__ __volatile__ ("casl %2, %3, %1; seq %0" + : "=dm" (ret), "=m" (*p), "=d" (readval) + : "d" (newval), "m" (*p), "2" (oldval)); + + return ret; +} + +#endif /* pt-machine.h */ diff --git a/linuxthreads/sysdeps/mips/pspinlock.c b/linuxthreads/sysdeps/mips/pspinlock.c new file mode 100644 index 0000000000..350aa7553c --- /dev/null +++ b/linuxthreads/sysdeps/mips/pspinlock.c @@ -0,0 +1,98 @@ +/* POSIX spinlock implementation. MIPS version. + Copyright (C) 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. */ + +#include <errno.h> +#include <pthread.h> +#include <sgidefs.h> +#include <sys/tas.h> +#include "internals.h" + +#include <sgidefs.h> + +/* This implementation is similar to the one used in the Linux kernel. */ +int +__pthread_spin_lock (pthread_spinlock_t *lock) +{ + unsigned int tmp1, tmp2; + + asm volatile + ("\t\t\t# spin_lock\n" + "1:\n\t" + ".set push\n\t" +#if _MIPS_SIM == _ABIO32 + ".set mips2\n\t" +#endif + "ll %1,%3\n\t" + "li %2,1\n\t" + "bnez %1,1b\n\t" + "sc %2,%0\n\t" + ".set pop\n\t" + "beqz %2,1b" + : "=m" (*lock), "=&r" (tmp1), "=&r" (tmp2) + : "m" (*lock) + : "memory"); + + return 0; +} + +weak_alias (__pthread_spin_lock, pthread_spin_lock) + + +int +__pthread_spin_trylock (pthread_spinlock_t *lock) +{ + /* To be done. */ + return 0; +} +weak_alias (__pthread_spin_trylock, pthread_spin_trylock) + + +int +__pthread_spin_unlock (pthread_spinlock_t *lock) +{ + asm volatile + ("\t\t\t# spin_unlock\n\t" + "sw $0,%0" + : "=m" (*lock) + : + : "memory"); + return 0; +} +weak_alias (__pthread_spin_unlock, pthread_spin_unlock) + + +int +__pthread_spin_init (pthread_spinlock_t *lock, int pshared) +{ + /* We can ignore the `pshared' parameter. Since we are busy-waiting + all processes which can access the memory location `lock' points + to can use the spinlock. */ + *lock = 0; + return 0; +} +weak_alias (__pthread_spin_init, pthread_spin_init) + + +int +__pthread_spin_destroy (pthread_spinlock_t *lock) +{ + /* Nothing to do. */ + return 0; +} +weak_alias (__pthread_spin_destroy, pthread_spin_destroy) diff --git a/linuxthreads/sysdeps/mips/pt-machine.h b/linuxthreads/sysdeps/mips/pt-machine.h new file mode 100644 index 0000000000..96f7a7f8c6 --- /dev/null +++ b/linuxthreads/sysdeps/mips/pt-machine.h @@ -0,0 +1,92 @@ +/* Machine-dependent pthreads configuration and inline functions. + + Copyright (C) 1996, 1997, 1998, 2000, 2002, 2003, 2004 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ralf Baechle <ralf@gnu.org>. + Based on the Alpha version by Richard Henderson <rth@tamu.edu>. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; 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 _PT_MACHINE_H +#define _PT_MACHINE_H 1 + +#include <sgidefs.h> +#include <sys/tas.h> + +#ifndef PT_EI +# define PT_EI extern inline __attribute__ ((always_inline)) +#endif + +extern long int testandset (int *spinlock); +extern int __compare_and_swap (long int *p, long int oldval, long int newval); + + +/* Spinlock implementation; required. */ + +PT_EI long int +testandset (int *spinlock) +{ + return _test_and_set (spinlock, 1); +} + + +/* Get some notion of the current stack. Need not be exactly the top + of the stack, just something somewhere in the current frame. */ +#define CURRENT_STACK_FRAME stack_pointer +register char * stack_pointer __asm__ ("$29"); + + +/* Compare-and-swap for semaphores. */ + +#define HAS_COMPARE_AND_SWAP +PT_EI int +__compare_and_swap (long int *p, long int oldval, long int newval) +{ + long int ret, temp; + + __asm__ __volatile__ + ("/* Inline compare & swap */\n" + "1:\n\t" + ".set push\n\t" +#if _MIPS_SIM == _ABIO32 + ".set mips2\n\t" +#endif +#if _MIPS_SIM == _ABI64 + "lld %1,%5\n\t" +#else + "ll %1,%5\n\t" +#endif + "move %0,$0\n\t" + "bne %1,%3,2f\n\t" + "move %0,%4\n\t" +#if _MIPS_SIM == _ABI64 + "scd %0,%2\n\t" +#else + "sc %0,%2\n\t" +#endif + ".set pop\n\t" + "beqz %0,1b\n" + "2:\n\t" + "/* End compare & swap */" + : "=&r" (ret), "=&r" (temp), "=m" (*p) + : "r" (oldval), "r" (newval), "m" (*p) + : "memory"); + + return ret; +} + +#endif /* pt-machine.h */ diff --git a/linuxthreads/sysdeps/powerpc/Makefile b/linuxthreads/sysdeps/powerpc/Makefile new file mode 100644 index 0000000000..33e4aceb5b --- /dev/null +++ b/linuxthreads/sysdeps/powerpc/Makefile @@ -0,0 +1,7 @@ +ifeq ($(subdir):$(elf),linuxthreads:yes) +# See CFLAGS-initfini.s above; this is the same code. +CFLAGS-pt-initfini.s = -g0 -fpic -O1 +endif +ifeq ($(subdir),csu) +gen-as-const-headers += tcb-offsets.sym +endif diff --git a/linuxthreads/sysdeps/powerpc/powerpc32/pspinlock.c b/linuxthreads/sysdeps/powerpc/powerpc32/pspinlock.c new file mode 100644 index 0000000000..15fd545c14 --- /dev/null +++ b/linuxthreads/sysdeps/powerpc/powerpc32/pspinlock.c @@ -0,0 +1,70 @@ +/* POSIX spinlock implementation. PowerPC version. + Copyright (C) 2000, 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 <pthread.h> +#include "internals.h" + +int +__pthread_spin_lock (pthread_spinlock_t *lock) +{ + while (! __compare_and_swap ((long int *)lock, 0, 1)) + ; + return 0; +} +weak_alias (__pthread_spin_lock, pthread_spin_lock) + + +int +__pthread_spin_trylock (pthread_spinlock_t *lock) +{ + return __compare_and_swap ((long int *)lock, 0, 1) ? 0 : EBUSY; +} +weak_alias (__pthread_spin_trylock, pthread_spin_trylock) + + +int +__pthread_spin_unlock (pthread_spinlock_t *lock) +{ + MEMORY_BARRIER (); + *lock = 0; + return 0; +} +weak_alias (__pthread_spin_unlock, pthread_spin_unlock) + + +int +__pthread_spin_init (pthread_spinlock_t *lock, int pshared) +{ + /* We can ignore the `pshared' parameter. Since we are busy-waiting + all processes which can access the memory location `lock' points + to can use the spinlock. */ + *lock = 0; + return 0; +} +weak_alias (__pthread_spin_init, pthread_spin_init) + + +int +__pthread_spin_destroy (pthread_spinlock_t *lock) +{ + /* Nothing to do. */ + return 0; +} +weak_alias (__pthread_spin_destroy, pthread_spin_destroy) diff --git a/linuxthreads/sysdeps/powerpc/powerpc32/pt-machine.h b/linuxthreads/sysdeps/powerpc/powerpc32/pt-machine.h new file mode 100644 index 0000000000..8363d16d08 --- /dev/null +++ b/linuxthreads/sysdeps/powerpc/powerpc32/pt-machine.h @@ -0,0 +1,120 @@ +/* Machine-dependent pthreads configuration and inline functions. + powerpc version. + Copyright (C) 1996, 1997, 1998, 2000, 2001, 2002, 2003 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* These routines are from Appendix G of the 'PowerPC 601 RISC Microprocessor + User's Manual', by IBM and Motorola. */ + +#ifndef _PT_MACHINE_H +#define _PT_MACHINE_H 1 + +#ifndef PT_EI +# define PT_EI extern inline __attribute__ ((always_inline)) +#endif + +extern long int testandset (int *spinlock); +extern int __compare_and_swap (long int *p, long int oldval, long int newval); + +/* For multiprocessor systems, we want to ensure all memory accesses + are completed before we reset a lock. On other systems, we still + need to make sure that the compiler has flushed everything to memory. */ +#define MEMORY_BARRIER() __asm__ __volatile__ ("sync" : : : "memory") + +/* We want the OS to assign stack addresses. */ +#define FLOATING_STACKS 1 + +/* Maximum size of the stack if the rlimit is unlimited. */ +#define ARCH_STACK_MAX_SIZE 8*1024*1024 + +/* Get some notion of the current stack. Need not be exactly the top + of the stack, just something somewhere in the current frame. */ +#define CURRENT_STACK_FRAME stack_pointer +register char * stack_pointer __asm__ ("r1"); + +/* Register r2 (tp) is reserved by the ABI as "thread pointer". */ +struct _pthread_descr_struct; +register struct _pthread_descr_struct *__thread_self __asm__("r2"); + +/* Return the thread descriptor for the current thread. */ +#define THREAD_SELF __thread_self + +/* Initialize the thread-unique value. */ +#define INIT_THREAD_SELF(descr, nr) (__thread_self = (descr)) + +/* Access to data in the thread descriptor is easy. */ +#define THREAD_GETMEM(descr, member) \ + ((void) (descr), THREAD_SELF->member) +#define THREAD_GETMEM_NC(descr, member) \ + ((void) (descr), THREAD_SELF->member) +#define THREAD_SETMEM(descr, member, value) \ + ((void) (descr), THREAD_SELF->member = (value)) +#define THREAD_SETMEM_NC(descr, member, value) \ + ((void) (descr), THREAD_SELF->member = (value)) + +/* Compare-and-swap for semaphores. */ +/* note that test-and-set(x) is the same as !compare-and-swap(x, 0, 1) */ + +#define HAS_COMPARE_AND_SWAP_WITH_RELEASE_SEMANTICS +#define IMPLEMENT_TAS_WITH_CAS + +PT_EI int +__compare_and_swap (long int *p, long int oldval, long int newval) +{ + int ret; + + __asm__ __volatile__ ( + "0: lwarx %0,0,%1 ;" + " xor. %0,%3,%0;" + " bne 1f;" + " stwcx. %2,0,%1;" + " bne- 0b;" + "1: " + : "=&r"(ret) + : "r"(p), "r"(newval), "r"(oldval) + : "cr0", "memory"); + /* This version of __compare_and_swap is to be used when acquiring + a lock, so we don't need to worry about whether other memory + operations have completed, but we do need to be sure that any loads + after this point really occur after we have acquired the lock. */ + __asm__ __volatile__ ("isync" : : : "memory"); + return ret == 0; +} + +PT_EI int +__compare_and_swap_with_release_semantics (long int *p, + long int oldval, long int newval) +{ + int ret; + + MEMORY_BARRIER (); + __asm__ __volatile__ ( + "0: lwarx %0,0,%1 ;" + " xor. %0,%3,%0;" + " bne 1f;" + " stwcx. %2,0,%1;" + " bne- 0b;" + "1: " + : "=&r"(ret) + : "r"(p), "r"(newval), "r"(oldval) + : "cr0", "memory"); + return ret == 0; +} + +#endif /* pt-machine.h */ diff --git a/linuxthreads/sysdeps/powerpc/powerpc64/pspinlock.c b/linuxthreads/sysdeps/powerpc/powerpc64/pspinlock.c new file mode 100644 index 0000000000..19161c6e10 --- /dev/null +++ b/linuxthreads/sysdeps/powerpc/powerpc64/pspinlock.c @@ -0,0 +1,70 @@ +/* POSIX spinlock implementation. PowerPC version. + Copyright (C) 2000, 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 <pthread.h> +#include "internals.h" + +int +__pthread_spin_lock (pthread_spinlock_t *lock) +{ + while (! __compare_and_swap32 ((int *)lock, 0, 1)) + ; + return 0; +} +weak_alias (__pthread_spin_lock, pthread_spin_lock) + + +int +__pthread_spin_trylock (pthread_spinlock_t *lock) +{ + return __compare_and_swap32 ((int *)lock, 0, 1) ? 0 : EBUSY; +} +weak_alias (__pthread_spin_trylock, pthread_spin_trylock) + + +int +__pthread_spin_unlock (pthread_spinlock_t *lock) +{ + MEMORY_BARRIER (); + *lock = 0; + return 0; +} +weak_alias (__pthread_spin_unlock, pthread_spin_unlock) + + +int +__pthread_spin_init (pthread_spinlock_t *lock, int pshared) +{ + /* We can ignore the `pshared' parameter. Since we are busy-waiting + all processes which can access the memory location `lock' points + to can use the spinlock. */ + *lock = 0; + return 0; +} +weak_alias (__pthread_spin_init, pthread_spin_init) + + +int +__pthread_spin_destroy (pthread_spinlock_t *lock) +{ + /* Nothing to do. */ + return 0; +} +weak_alias (__pthread_spin_destroy, pthread_spin_destroy) diff --git a/linuxthreads/sysdeps/powerpc/powerpc64/pt-machine.h b/linuxthreads/sysdeps/powerpc/powerpc64/pt-machine.h new file mode 100644 index 0000000000..562e69fa18 --- /dev/null +++ b/linuxthreads/sysdeps/powerpc/powerpc64/pt-machine.h @@ -0,0 +1,185 @@ +/* Machine-dependent pthreads configuration and inline functions. + powerpc version. + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU 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. */ + +/* These routines are from Appendix G of the 'PowerPC 601 RISC Microprocessor + User's Manual', by IBM and Motorola. */ + +#ifndef _PT_MACHINE_H +#define _PT_MACHINE_H 1 + +#ifndef PT_EI +# define PT_EI extern inline __attribute__ ((always_inline)) +#endif + +extern long int testandset (int *spinlock); +extern int __compare_and_swap (long int *p, long int oldval, long int newval); +extern int __compare_and_swap32 (int *p, int oldval, int newval); + +/* For multiprocessor systems, we want to ensure all memory accesses + are completed before we reset a lock. On other systems, we still + need to make sure that the compiler has flushed everything to memory. */ +#define MEMORY_BARRIER() __asm__ __volatile__ ("lwsync" : : : "memory") +#define READ_MEMORY_BARRIER() __asm__ __volatile__ ("lwsync" : : : "memory") +#define WRITE_MEMORY_BARRIER() __asm__ __volatile__ ("eieio" : : : "memory") + +/* We want the OS to assign stack addresses. */ +#define FLOATING_STACKS 1 + +/* Maximum size of the stack if the rlimit is unlimited. */ +#define ARCH_STACK_MAX_SIZE 16*1024*1024 + +/* Get some notion of the current stack. Need not be exactly the top + of the stack, just something somewhere in the current frame. */ +#define CURRENT_STACK_FRAME stack_pointer +register char * stack_pointer __asm__ ("r1"); + +/* Register r13 (tp) is reserved by the ABI as "thread pointer". */ +struct _pthread_descr_struct; +register struct _pthread_descr_struct *__thread_self __asm__("r13"); + +/* Return the thread descriptor for the current thread. */ +#define THREAD_SELF __thread_self + +/* Initialize the thread-unique value. */ +#define INIT_THREAD_SELF(descr, nr) (__thread_self = (descr)) + +/* Access to data in the thread descriptor is easy. */ +#define THREAD_GETMEM(descr, member) \ + ((void) (descr), THREAD_SELF->member) +#define THREAD_GETMEM_NC(descr, member) \ + ((void) (descr), THREAD_SELF->member) +#define THREAD_SETMEM(descr, member, value) \ + ((void) (descr), THREAD_SELF->member = (value)) +#define THREAD_SETMEM_NC(descr, member, value) \ + ((void) (descr), THREAD_SELF->member = (value)) + +/* Compare-and-swap for semaphores. */ +/* note that test-and-set(x) is the same as !compare-and-swap(x, 0, 1) */ + +#define HAS_COMPARE_AND_SWAP +#define HAS_COMPARE_AND_SWAP_WITH_RELEASE_SEMANTICS + +PT_EI int +__compare_and_swap (long int *p, long int oldval, long int newval) +{ + long int ret; + + __asm__ __volatile__ ( + "0: ldarx %0,0,%1 ;" + " xor. %0,%3,%0;" + " bne 1f;" + " stdcx. %2,0,%1;" + " bne- 0b;" + "1: " + : "=&r"(ret) + : "r"(p), "r"(newval), "r"(oldval) + : "cr0", "memory"); + /* This version of __compare_and_swap is to be used when acquiring + a lock, so we don't need to worry about whether other memory + operations have completed, but we do need to be sure that any loads + after this point really occur after we have acquired the lock. */ + __asm__ __volatile__ ("isync" : : : "memory"); + return (int)(ret == 0); +} + +PT_EI int +__compare_and_swap_with_release_semantics (long int *p, + long int oldval, long int newval) +{ + long int ret; + + MEMORY_BARRIER (); + __asm__ __volatile__ ( + "0: ldarx %0,0,%1 ;" + " xor. %0,%3,%0;" + " bne 1f;" + " stdcx. %2,0,%1;" + " bne- 0b;" + "1: " + : "=&r"(ret) + : "r"(p), "r"(newval), "r"(oldval) + : "cr0", "memory"); + return (int)(ret == 0); +} + +PT_EI int +__compare_and_swap32 (int *p, int oldval, int newval) +{ + int ret; + + __asm__ __volatile__ ( + "0: lwarx %0,0,%1 ;" + " xor. %0,%3,%0;" + " bne 1f;" + " stwcx. %2,0,%1;" + " bne- 0b;" + "1: " + : "=&r"(ret) + : "r"(p), "r"(newval), "r"(oldval) + : "cr0", "memory"); + /* This version of __compare_and_swap is to be used when acquiring + a lock, so we don't need to worry about whether other memory + operations have completed, but we do need to be sure that any loads + after this point really occur after we have acquired the lock. */ + __asm__ __volatile__ ("isync" : : : "memory"); + return (int)(ret == 0); +} + +PT_EI int +__compare_and_swap32_with_release_semantics (long int *p, + long int oldval, long int newval) +{ + long int ret; + + MEMORY_BARRIER (); + __asm__ __volatile__ ( + "0: lwarx %0,0,%1 ;" + " xor. %0,%3,%0;" + " bne 1f;" + " stwcx. %2,0,%1;" + " bne- 0b;" + "1: " + : "=&r"(ret) + : "r"(p), "r"(newval), "r"(oldval) + : "cr0", "memory"); + return (int)(ret == 0); +} + +PT_EI long int +testandset (int *p) +{ + long int ret, val = 1; + + MEMORY_BARRIER (); + __asm__ __volatile__ ( + "0: lwarx %0,0,%1 ;" + " cmpwi 0,%0,0;" + " bne 1f;" + " stwcx. %2,0,%1;" + " bne- 0b;" + "1: " + : "=&r"(ret) + : "r"(p), "r" (val) + : "cr0", "memory"); + MEMORY_BARRIER (); + return ret != 0; +} + +#endif /* pt-machine.h */ diff --git a/linuxthreads/sysdeps/powerpc/tcb-offsets.sym b/linuxthreads/sysdeps/powerpc/tcb-offsets.sym new file mode 100644 index 0000000000..b526b62336 --- /dev/null +++ b/linuxthreads/sysdeps/powerpc/tcb-offsets.sym @@ -0,0 +1,19 @@ +#include <sysdep.h> +#include <tls.h> + +-- This line separates the #include lines from conditionals. + +# ifdef USE_TLS + +-- Abuse tls.h macros to derive offsets relative to the thread register. +# undef __thread_register +# define __thread_register ((void *) 0) +# define thread_offsetof(mem) ((void *) &THREAD_SELF->p_##mem - (void *) 0) + +# else + +# define thread_offsetof(mem) offsetof (tcbhead_t, mem) + +# endif + +MULTIPLE_THREADS_OFFSET thread_offsetof (multiple_threads) diff --git a/linuxthreads/sysdeps/powerpc/tls.h b/linuxthreads/sysdeps/powerpc/tls.h new file mode 100644 index 0000000000..f6eb48b434 --- /dev/null +++ b/linuxthreads/sysdeps/powerpc/tls.h @@ -0,0 +1,160 @@ +/* Definitions for thread-local data handling. linuxthreads/PPC 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 _TLS_H +#define _TLS_H + +#ifndef __ASSEMBLER__ + +# include <pt-machine.h> +# include <stddef.h> + +/* Type for the dtv. */ +typedef union dtv +{ + size_t counter; + void *pointer; +} dtv_t; + +#else /* __ASSEMBLER__ */ +# include <tcb-offsets.h> +#endif /* __ASSEMBLER__ */ + +#ifdef HAVE_TLS_SUPPORT + +/* Signal that TLS support is available. */ +# define USE_TLS 1 + +# ifndef __ASSEMBLER__ + +/* This layout is actually wholly private and not affected by the ABI. + Nor does it overlap the pthread data structure, so we need nothing + extra here at all. */ +typedef struct +{ + 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_descr_struct) + +/* This is the size of the TCB. */ +# define TLS_TCB_SIZE 0 + +/* Alignment requirements for the TCB. */ +# define TLS_TCB_ALIGN __alignof__ (struct _pthread_descr_struct) + +/* This is the size we need before TCB. */ +# define TLS_PRE_TCB_SIZE \ + (sizeof (struct _pthread_descr_struct) \ + + ((sizeof (tcbhead_t) + TLS_TCB_ALIGN - 1) & ~(TLS_TCB_ALIGN - 1))) + +/* The following assumes that TP (R2 or R13) is 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_descr 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 + +/* The DTV is allocated at the TP; the TCB is placed elsewhere. */ +/* This is not really true for powerpc64. We are following alpha + where the DTV pointer is first doubleword in the TCB. */ +# define TLS_DTV_AT_TP 1 + +/* 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) + +/* We still need this define so that tcb-offsets.sym can override it and + use THREAD_SELF to generate MULTIPLE_THREADS_OFFSET. */ +# define __thread_register ((void *) __thread_self) + +/* 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. + + The global register variable is declared in pt-machine.h with the + wrong type, so we need some extra casts to get the desired result. + This avoids a lvalue cast that gcc-3.4 does not like. */ +# define TLS_INIT_TP(TCBP, SECONDCALL) \ + (__thread_self = (struct _pthread_descr_struct *) \ + ((void *) (TCBP) + TLS_TCB_OFFSET), NULL) + +/* Return the address of the dtv for the current thread. */ +# define THREAD_DTV() \ + (((tcbhead_t *) ((void *) __thread_self - TLS_TCB_OFFSET))[-1].dtv) + +/* Return the thread descriptor for the current thread. */ +# undef THREAD_SELF +# define THREAD_SELF \ + ((pthread_descr) (__thread_register \ + - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE)) + +# undef INIT_THREAD_SELF +# define INIT_THREAD_SELF(DESCR, NR) \ + (__thread_self = (struct _pthread_descr_struct *)((void *) (DESCR) \ + + TLS_TCB_OFFSET + TLS_PRE_TCB_SIZE)) + +/* Make sure we have the p_multiple_threads member in the thread structure. + See below. */ +# define TLS_MULTIPLE_THREADS_IN_TCB 1 + +/* Get the thread descriptor definition. */ +# include <linuxthreads/descr.h> + +/* 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__ */ + +#elif !defined __ASSEMBLER__ + +/* This overlaps the start of the pthread_descr. System calls + and such use this to find the multiple_threads flag and need + to use the same offset relative to the thread register in both + single-threaded and multi-threaded code. */ +typedef struct +{ + void *tcb; /* Never used. */ + dtv_t *dtv; /* Never used. */ + void *self; /* Used only if multithreaded, and rarely. */ + int multiple_threads; /* Only this member is really used. */ +} tcbhead_t; + +#define NONTLS_INIT_TP \ + do { \ + static const tcbhead_t nontls_init_tp = { .multiple_threads = 0 }; \ + __thread_self = (__typeof (__thread_self)) &nontls_init_tp; \ + } while (0) + +#endif /* HAVE_TLS_SUPPORT */ + +#endif /* tls.h */ diff --git a/linuxthreads/sysdeps/pthread/Makefile b/linuxthreads/sysdeps/pthread/Makefile new file mode 100644 index 0000000000..f73f40e9d9 --- /dev/null +++ b/linuxthreads/sysdeps/pthread/Makefile @@ -0,0 +1,14 @@ +ifeq ($(subdir),rt) +librt-sysdep_routines += timer_routines +CPPFLAGS += -DBROKEN_THREAD_SIGNALS + +ifeq (yes,$(build-shared)) +$(objpfx)tst-timer: $(objpfx)librt.so $(shared-thread-library) +else +$(objpfx)tst-timer: $(objpfx)librt.a $(static-thread-library) +endif +endif + +ifeq ($(subdir),posix) +CFLAGS-confstr.c += -DLIBPTHREAD_VERSION="\"$(shell sed 's/\(.*\) by .*/\1/' ../linuxthreads/Banner)\"" +endif diff --git a/linuxthreads/sysdeps/pthread/Subdirs b/linuxthreads/sysdeps/pthread/Subdirs new file mode 100644 index 0000000000..2c56497842 --- /dev/null +++ b/linuxthreads/sysdeps/pthread/Subdirs @@ -0,0 +1 @@ +linuxthreads_db diff --git a/linuxthreads/sysdeps/pthread/bits/initspin.h b/linuxthreads/sysdeps/pthread/bits/initspin.h new file mode 100644 index 0000000000..a19ec077e8 --- /dev/null +++ b/linuxthreads/sysdeps/pthread/bits/initspin.h @@ -0,0 +1,28 @@ +/* Generic definitions for spinlock initializers. + Copyright (C) 2000, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* Initial value of a spinlock. Most platforms should use zero, + unless they only implement a "test and clear" operation instead of + the usual "test and set". */ +#define __LT_SPINLOCK_INIT 0 + +/* Macros for lock initializers, using the above definition. */ +#define __LOCK_INITIALIZER { 0, __LT_SPINLOCK_INIT } +#define __ALT_LOCK_INITIALIZER { 0, __LT_SPINLOCK_INIT } +#define __ATOMIC_INITIALIZER { 0, __LT_SPINLOCK_INIT } diff --git a/linuxthreads/sysdeps/pthread/bits/libc-lock.h b/linuxthreads/sysdeps/pthread/bits/libc-lock.h new file mode 100644 index 0000000000..7e22166862 --- /dev/null +++ b/linuxthreads/sysdeps/pthread/bits/libc-lock.h @@ -0,0 +1,413 @@ +/* libc-internal interface for mutex locks. LinuxThreads version. + Copyright (C) 1996,1997,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; 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> + +#if defined _LIBC && !defined NOT_IN_libc +#include <linuxthreads/internals.h> +#endif + +/* Mutex type. */ +#if defined(_LIBC) || defined(_IO_MTSAFE_IO) +typedef pthread_mutex_t __libc_lock_t; +typedef struct { pthread_mutex_t mutex; } __libc_lock_recursive_t; +# ifdef __USE_UNIX98 +typedef pthread_rwlock_t __libc_rwlock_t; +# else +typedef struct __libc_rwlock_opaque__ __libc_rwlock_t; +# endif +typedef __libc_lock_recursive_t __rtld_lock_recursive_t; +#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 __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 + +#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. */ +#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} + +#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} + +#if defined _LIBC && defined IS_IN_libpthread +# define __libc_maybe_call(FUNC, ARGS, ELSE) FUNC ARGS +#else +# if defined __PIC__ || (defined _LIBC && defined SHARED) +# 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 +#endif +#if defined _LIBC && !defined NOT_IN_libc && defined SHARED +# define __libc_maybe_call2(FUNC, ARGS, ELSE) \ + ({__builtin_expect (__libc_pthread_functions.ptr_##FUNC != NULL, 0) \ + ? __libc_pthread_functions.ptr_##FUNC ARGS : ELSE; }) +#else +# define __libc_maybe_call2(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 SHARED +#define __libc_lock_init(NAME) \ + ({ \ + (NAME).__m_count = 0; \ + (NAME).__m_owner = NULL; \ + (NAME).__m_kind = PTHREAD_MUTEX_TIMED_NP; \ + (NAME).__m_lock.__status = 0; \ + (NAME).__m_lock.__spinlock = __LT_SPINLOCK_INIT; \ + 0; }) +#else +#define __libc_lock_init(NAME) \ + (__libc_maybe_call2 (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 SHARED +#define __libc_lock_init_recursive(NAME) \ + ({ \ + (NAME).mutex.__m_count = 0; \ + (NAME).mutex.__m_owner = NULL; \ + (NAME).mutex.__m_kind = PTHREAD_MUTEX_RECURSIVE_NP; \ + (NAME).mutex.__m_lock.__status = 0; \ + (NAME).mutex.__m_lock.__spinlock = __LT_SPINLOCK_INIT; \ + 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) \ + __libc_lock_init_recursive (NAME) + +/* 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. */ +#define __libc_lock_fini(NAME) \ + (__libc_maybe_call2 (pthread_mutex_destroy, (&(NAME)), 0)); +#define __libc_rwlock_fini(NAME) \ + (__libc_maybe_call (__pthread_rwlock_destroy, (&(NAME)), 0)); + +/* Finalize recursive named lock. */ +#define __libc_lock_fini_recursive(NAME) __libc_lock_fini ((NAME).mutex) +#define __rtld_lock_fini_recursive(NAME) __libc_lock_fini_recursive (NAME) + +/* Lock the named lock variable. */ +#define __libc_lock_lock(NAME) \ + (__libc_maybe_call2 (pthread_mutex_lock, (&(NAME)), 0)); +#define __libc_rwlock_rdlock(NAME) \ + (__libc_maybe_call (__pthread_rwlock_rdlock, (&(NAME)), 0)); +#define __libc_rwlock_wrlock(NAME) \ + (__libc_maybe_call (__pthread_rwlock_wrlock, (&(NAME)), 0)); + +/* Lock the recursive named lock variable. */ +#define __libc_lock_lock_recursive(NAME) __libc_lock_lock ((NAME).mutex) + +/* Try to lock the named lock variable. */ +#define __libc_lock_trylock(NAME) \ + (__libc_maybe_call2 (pthread_mutex_trylock, (&(NAME)), 0)) +#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. */ +#define __libc_lock_trylock_recursive(NAME) __libc_lock_trylock ((NAME).mutex) +#define __rtld_lock_trylock_recursive(NAME) \ + __libc_lock_trylock_recursive (NAME) + +/* Unlock the named lock variable. */ +#define __libc_lock_unlock(NAME) \ + (__libc_maybe_call2 (pthread_mutex_unlock, (&(NAME)), 0)); +#define __libc_rwlock_unlock(NAME) \ + (__libc_maybe_call (__pthread_rwlock_unlock, (&(NAME)), 0)); + +/* Unlock the recursive named lock variable. */ +#define __libc_lock_unlock_recursive(NAME) __libc_lock_unlock ((NAME).mutex) + +#if defined _LIBC && defined SHARED +# define __rtld_lock_default_lock_recursive(lock) \ + ++((pthread_mutex_t *)(lock))->__m_count; + +# define __rtld_lock_default_unlock_recursive(lock) \ + --((pthread_mutex_t *)(lock))->__m_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_lock_lock_recursive (NAME) +#define __rtld_lock_unlock_recursive(NAME) __libc_lock_unlock_recursive (NAME) +#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 (__pthread_once != NULL) \ + __pthread_once (&(ONCE_CONTROL), (INIT_FUNCTION)); \ + else if ((ONCE_CONTROL) == PTHREAD_ONCE_INIT) { \ + INIT_FUNCTION (); \ + (ONCE_CONTROL) = 2; \ + } \ + } while (0) + + +/* Start critical region with cleanup. */ +#define __libc_cleanup_region_start(DOIT, FCT, ARG) \ + { struct _pthread_cleanup_buffer _buffer; \ + int _avail = (DOIT) && _pthread_cleanup_push_defer != NULL; \ + if (_avail) { \ + _pthread_cleanup_push_defer (&_buffer, (FCT), (ARG)); \ + } + +/* End critical region with cleanup. */ +#define __libc_cleanup_region_end(DOIT) \ + if (_avail) { \ + _pthread_cleanup_pop_restore (&_buffer, (DOIT)); \ + } \ + } + +/* Sometimes we have to exit the block in the middle. */ +#define __libc_cleanup_end(DOIT) \ + if (_avail) { \ + _pthread_cleanup_pop_restore (&_buffer, (DOIT)); \ + } + +#define __libc_cleanup_push(fct, arg) \ + { struct _pthread_cleanup_buffer _buffer; \ + __libc_maybe_call (_pthread_cleanup_push, (&_buffer, (fct), (arg)), 0) + +#define __libc_cleanup_pop(execute) \ + __libc_maybe_call (_pthread_cleanup_pop, (&_buffer, execute), 0); \ + } + +/* Create thread-specific key. */ +#define __libc_key_create(KEY, DESTRUCTOR) \ + (__libc_maybe_call (__pthread_key_create, (KEY, DESTRUCTOR), 1)) + +/* Get thread-specific data. */ +#define __libc_getspecific(KEY) \ + (__libc_maybe_call (__pthread_getspecific, (KEY), NULL)) + +/* Set thread-specific data. */ +#define __libc_setspecific(KEY, VALUE) \ + (__libc_maybe_call (__pthread_setspecific, (KEY, VALUE), 0)) + + +/* Register handlers to execute before and after `fork'. */ +#define __libc_atfork(PREPARE, PARENT, CHILD) \ + (__libc_maybe_call (__pthread_atfork, (PREPARE, PARENT, CHILD), 0)) + +/* 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 +# if _LIBC +# include <bp-sym.h> +# else +# define BP_SYM (sym) sym +# endif +weak_extern (BP_SYM (__pthread_mutex_init)) +weak_extern (BP_SYM (__pthread_mutex_destroy)) +weak_extern (BP_SYM (__pthread_mutex_lock)) +weak_extern (BP_SYM (__pthread_mutex_trylock)) +weak_extern (BP_SYM (__pthread_mutex_unlock)) +weak_extern (BP_SYM (__pthread_mutexattr_init)) +weak_extern (BP_SYM (__pthread_mutexattr_destroy)) +weak_extern (BP_SYM (__pthread_mutexattr_settype)) +weak_extern (BP_SYM (__pthread_rwlock_init)) +weak_extern (BP_SYM (__pthread_rwlock_destroy)) +weak_extern (BP_SYM (__pthread_rwlock_rdlock)) +weak_extern (BP_SYM (__pthread_rwlock_tryrdlock)) +weak_extern (BP_SYM (__pthread_rwlock_wrlock)) +weak_extern (BP_SYM (__pthread_rwlock_trywrlock)) +weak_extern (BP_SYM (__pthread_rwlock_unlock)) +weak_extern (BP_SYM (__pthread_key_create)) +weak_extern (BP_SYM (__pthread_setspecific)) +weak_extern (BP_SYM (__pthread_getspecific)) +weak_extern (BP_SYM (__pthread_once)) +weak_extern (__pthread_initialize) +weak_extern (__pthread_atfork) +weak_extern (BP_SYM (_pthread_cleanup_push)) +weak_extern (BP_SYM (_pthread_cleanup_pop)) +weak_extern (BP_SYM (_pthread_cleanup_push_defer)) +weak_extern (BP_SYM (_pthread_cleanup_pop_restore)) +# else +# pragma weak __pthread_mutex_init +# pragma weak __pthread_mutex_destroy +# pragma weak __pthread_mutex_lock +# pragma weak __pthread_mutex_trylock +# pragma weak __pthread_mutex_unlock +# pragma weak __pthread_mutexattr_init +# pragma weak __pthread_mutexattr_destroy +# pragma weak __pthread_mutexattr_settype +# pragma weak __pthread_rwlock_destroy +# pragma weak __pthread_rwlock_rdlock +# pragma weak __pthread_rwlock_tryrdlock +# pragma weak __pthread_rwlock_wrlock +# pragma weak __pthread_rwlock_trywrlock +# pragma weak __pthread_rwlock_unlock +# pragma weak __pthread_key_create +# pragma weak __pthread_setspecific +# pragma weak __pthread_getspecific +# pragma weak __pthread_once +# pragma weak __pthread_initialize +# pragma weak __pthread_atfork +# pragma weak _pthread_cleanup_push_defer +# pragma weak _pthread_cleanup_pop_restore +# pragma weak _pthread_cleanup_push +# pragma weak _pthread_cleanup_pop +# endif +#endif + +/* We need portable names for some functions. E.g., when they are + used as argument to __libc_cleanup_region_start. */ +#define __libc_mutex_unlock __pthread_mutex_unlock + +#endif /* bits/libc-lock.h */ diff --git a/linuxthreads/sysdeps/pthread/bits/libc-tsd.h b/linuxthreads/sysdeps/pthread/bits/libc-tsd.h new file mode 100644 index 0000000000..fa6eb4be28 --- /dev/null +++ b/linuxthreads/sysdeps/pthread/bits/libc-tsd.h @@ -0,0 +1,59 @@ +/* libc-internal interface for thread-specific data. LinuxThreads version. + Copyright (C) 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; 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_TSD_H +#define _BITS_LIBC_TSD_H 1 + +#include <linuxthreads/descr.h> +#include <tls.h> + +#if USE_TLS && HAVE___THREAD + +/* When __thread works, the generic definition is what we want. */ +# include <sysdeps/generic/bits/libc-tsd.h> + +#else + +# include <bits/libc-lock.h> + +# ifndef SHARED +extern void ** __pthread_internal_tsd_address (int); +extern void *__pthread_internal_tsd_get (int); +extern int __pthread_internal_tsd_set (int, const void *); + +weak_extern (__pthread_internal_tsd_address) +weak_extern (__pthread_internal_tsd_get) +weak_extern (__pthread_internal_tsd_set) +# endif + +#define __libc_tsd_define(CLASS, KEY) CLASS void *__libc_tsd_##KEY##_data; +#define __libc_tsd_address(KEY) \ + __libc_maybe_call2 (pthread_internal_tsd_address, \ + (_LIBC_TSD_KEY_##KEY), &__libc_tsd_##KEY##_data) +#define __libc_tsd_get(KEY) \ + __libc_maybe_call2 (pthread_internal_tsd_get, \ + (_LIBC_TSD_KEY_##KEY), __libc_tsd_##KEY##_data) +#define __libc_tsd_set(KEY, VALUE) \ + __libc_maybe_call2 (pthread_internal_tsd_set, \ + (_LIBC_TSD_KEY_##KEY, (VALUE)), \ + (__libc_tsd_##KEY##_data = (VALUE), 0)) + +#endif + +#endif /* bits/libc-tsd.h */ diff --git a/linuxthreads/sysdeps/pthread/bits/pthreadtypes.h b/linuxthreads/sysdeps/pthread/bits/pthreadtypes.h new file mode 100644 index 0000000000..d1daef07aa --- /dev/null +++ b/linuxthreads/sysdeps/pthread/bits/pthreadtypes.h @@ -0,0 +1,152 @@ +/* Linuxthreads - a simple clone()-based implementation of Posix */ +/* threads for Linux. */ +/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ +/* */ +/* This program is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public License */ +/* as published by the Free Software Foundation; either version 2 */ +/* of the License, or (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Library General Public License for more details. */ + +#if !defined _BITS_TYPES_H && !defined _PTHREAD_H +# error "Never include <bits/pthreadtypes.h> directly; use <sys/types.h> instead." +#endif + +#ifndef _BITS_PTHREADTYPES_H +#define _BITS_PTHREADTYPES_H 1 + +#define __need_schedparam +#include <bits/sched.h> + +/* Fast locks (not abstract because mutexes and conditions aren't abstract). */ +struct _pthread_fastlock +{ + long int __status; /* "Free" or "taken" or head of waiting list */ + int __spinlock; /* Used by compare_and_swap emulation. Also, + adaptive SMP lock stores spin count here. */ +}; + +#ifndef _PTHREAD_DESCR_DEFINED +/* Thread descriptors */ +typedef struct _pthread_descr_struct *_pthread_descr; +# define _PTHREAD_DESCR_DEFINED +#endif + + +/* Attributes for threads. */ +typedef struct __pthread_attr_s +{ + int __detachstate; + int __schedpolicy; + struct __sched_param __schedparam; + int __inheritsched; + int __scope; + size_t __guardsize; + int __stackaddr_set; + void *__stackaddr; + size_t __stacksize; +} pthread_attr_t; + + +/* Conditions (not abstract because of PTHREAD_COND_INITIALIZER */ + +#ifdef __GLIBC_HAVE_LONG_LONG +__extension__ typedef long long __pthread_cond_align_t; +#else +typedef long __pthread_cond_align_t; +#endif + +typedef struct +{ + struct _pthread_fastlock __c_lock; /* Protect against concurrent access */ + _pthread_descr __c_waiting; /* Threads waiting on this condition */ + char __padding[48 - sizeof (struct _pthread_fastlock) + - sizeof (_pthread_descr) - sizeof (__pthread_cond_align_t)]; + __pthread_cond_align_t __align; +} pthread_cond_t; + + +/* Attribute for conditionally variables. */ +typedef struct +{ + int __dummy; +} pthread_condattr_t; + +/* Keys for thread-specific data */ +typedef unsigned int pthread_key_t; + + +/* Mutexes (not abstract because of PTHREAD_MUTEX_INITIALIZER). */ +/* (The layout is unnatural to maintain binary compatibility + with earlier releases of LinuxThreads.) */ +typedef struct +{ + int __m_reserved; /* Reserved for future use */ + int __m_count; /* Depth of recursive locking */ + _pthread_descr __m_owner; /* Owner thread (if recursive or errcheck) */ + int __m_kind; /* Mutex kind: fast, recursive or errcheck */ + struct _pthread_fastlock __m_lock; /* Underlying fast lock */ +} pthread_mutex_t; + + +/* Attribute for mutex. */ +typedef struct +{ + int __mutexkind; +} pthread_mutexattr_t; + + +/* Once-only execution */ +typedef int pthread_once_t; + + +#if defined __USE_UNIX98 || defined __USE_XOPEN2K +/* Read-write locks. */ +typedef struct _pthread_rwlock_t +{ + struct _pthread_fastlock __rw_lock; /* Lock to guarantee mutual exclusion */ + int __rw_readers; /* Number of readers */ + _pthread_descr __rw_writer; /* Identity of writer, or NULL if none */ + _pthread_descr __rw_read_waiting; /* Threads waiting for reading */ + _pthread_descr __rw_write_waiting; /* Threads waiting for writing */ + int __rw_kind; /* Reader/Writer preference selection */ + int __rw_pshared; /* Shared between processes or not */ +} pthread_rwlock_t; + + +/* Attribute for read-write locks. */ +typedef struct +{ + int __lockkind; + int __pshared; +} pthread_rwlockattr_t; +#endif + +#ifdef __USE_XOPEN2K +/* POSIX spinlock data type. */ +typedef volatile int pthread_spinlock_t; + +/* POSIX barrier. */ +typedef struct { + struct _pthread_fastlock __ba_lock; /* Lock to guarantee mutual exclusion */ + int __ba_required; /* Threads needed for completion */ + int __ba_present; /* Threads waiting */ + _pthread_descr __ba_waiting; /* Queue of waiting threads */ +} pthread_barrier_t; + +/* barrier attribute */ +typedef struct { + int __pshared; +} pthread_barrierattr_t; + +#endif + + +/* Thread identifiers */ +typedef unsigned long int pthread_t; + +#endif /* bits/pthreadtypes.h */ diff --git a/linuxthreads/sysdeps/pthread/bits/typesizes.h b/linuxthreads/sysdeps/pthread/bits/typesizes.h new file mode 100644 index 0000000000..45264ac9cf --- /dev/null +++ b/linuxthreads/sysdeps/pthread/bits/typesizes.h @@ -0,0 +1,66 @@ +/* bits/typesizes.h -- underlying types for *_t. Generic version. + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _BITS_TYPES_H +# error "Never include <bits/typesizes.h> directly; use <sys/types.h> instead." +#endif + +#ifndef _BITS_TYPESIZES_H +#define _BITS_TYPESIZES_H 1 + +/* See <bits/types.h> for the meaning of these macros. This file exists so + that <bits/types.h> need not vary across different GNU platforms. */ + +#define __DEV_T_TYPE __UQUAD_TYPE +#define __UID_T_TYPE __U32_TYPE +#define __GID_T_TYPE __U32_TYPE +#define __INO_T_TYPE __ULONGWORD_TYPE +#define __INO64_T_TYPE __UQUAD_TYPE +#define __MODE_T_TYPE __U32_TYPE +#define __NLINK_T_TYPE __UWORD_TYPE +#define __OFF_T_TYPE __SLONGWORD_TYPE +#define __OFF64_T_TYPE __SQUAD_TYPE +#define __PID_T_TYPE __S32_TYPE +#define __RLIM_T_TYPE __ULONGWORD_TYPE +#define __RLIM64_T_TYPE __UQUAD_TYPE +#define __BLKCNT_T_TYPE __SLONGWORD_TYPE +#define __BLKCNT64_T_TYPE __SQUAD_TYPE +#define __FSBLKCNT_T_TYPE __ULONGWORD_TYPE +#define __FSBLKCNT64_T_TYPE __UQUAD_TYPE +#define __FSFILCNT_T_TYPE __ULONGWORD_TYPE +#define __FSFILCNT64_T_TYPE __UQUAD_TYPE +#define __ID_T_TYPE __U32_TYPE +#define __CLOCK_T_TYPE __SLONGWORD_TYPE +#define __TIME_T_TYPE __SLONGWORD_TYPE +#define __USECONDS_T_TYPE __U32_TYPE +#define __SUSECONDS_T_TYPE __SLONGWORD_TYPE +#define __DADDR_T_TYPE __S32_TYPE +#define __SWBLK_T_TYPE __SLONGWORD_TYPE +#define __KEY_T_TYPE __S32_TYPE +#define __CLOCKID_T_TYPE __S32_TYPE +#define __TIMER_T_TYPE __S32_TYPE +#define __BLKSIZE_T_TYPE __SLONGWORD_TYPE +#define __FSID_T_TYPE struct { int __val[2]; } +#define __SSIZE_T_TYPE __SWORD_TYPE + +/* Number of descriptors that can fit in an `fd_set'. */ +#define __FD_SETSIZE 1024 + + +#endif /* bits/typesizes.h */ diff --git a/linuxthreads/sysdeps/pthread/errno-loc.c b/linuxthreads/sysdeps/pthread/errno-loc.c new file mode 100644 index 0000000000..0a8f0f9076 --- /dev/null +++ b/linuxthreads/sysdeps/pthread/errno-loc.c @@ -0,0 +1,46 @@ +/* MT support function to get address of `errno' variable, linuxthreads + version. + Copyright (C) 1996, 1998, 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 <errno.h> +#include <tls.h> +#include <linuxthreads/internals.h> +#include <sysdep-cancel.h> + +#if ! USE___THREAD && !RTLD_PRIVATE_ERRNO +#undef errno +extern int errno; +#endif + +int * +#if ! USE___THREAD +weak_const_function +#endif +__errno_location (void) +{ +#if ! USE___THREAD && !defined NOT_IN_libc + if (! SINGLE_THREAD_P) + { + pthread_descr self = thread_self(); + return LIBC_THREAD_GETMEM (self, p_errnop); + } +#endif + return &errno; +} +libc_hidden_def (__errno_location) diff --git a/linuxthreads/sysdeps/pthread/flockfile.c b/linuxthreads/sysdeps/pthread/flockfile.c new file mode 100644 index 0000000000..918cb84f61 --- /dev/null +++ b/linuxthreads/sysdeps/pthread/flockfile.c @@ -0,0 +1,33 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <stdio.h> +#include <libio.h> +#include <bits/stdio-lock.h> + + +void +__flockfile (stream) + FILE *stream; +{ + _IO_lock_lock (*stream->_lock); +} +strong_alias (__flockfile, _IO_flockfile) +weak_alias (__flockfile, flockfile) diff --git a/linuxthreads/sysdeps/pthread/ftrylockfile.c b/linuxthreads/sysdeps/pthread/ftrylockfile.c new file mode 100644 index 0000000000..21c1ea01ed --- /dev/null +++ b/linuxthreads/sysdeps/pthread/ftrylockfile.c @@ -0,0 +1,33 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <bits/stdio-lock.h> + + +int +__ftrylockfile (stream) + FILE *stream; +{ + return _IO_lock_trylock (*stream->_lock); +} +strong_alias (__ftrylockfile, _IO_ftrylockfile) +weak_alias (__ftrylockfile, ftrylockfile) diff --git a/linuxthreads/sysdeps/pthread/funlockfile.c b/linuxthreads/sysdeps/pthread/funlockfile.c new file mode 100644 index 0000000000..f941fc9851 --- /dev/null +++ b/linuxthreads/sysdeps/pthread/funlockfile.c @@ -0,0 +1,33 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <stdio.h> +#include <libio.h> +#include <bits/stdio-lock.h> + + +void +__funlockfile (stream) + FILE *stream; +{ + _IO_lock_unlock (*stream->_lock); +} +strong_alias (__funlockfile, _IO_funlockfile) +weak_alias (__funlockfile, funlockfile) diff --git a/linuxthreads/sysdeps/pthread/getcpuclockid.c b/linuxthreads/sysdeps/pthread/getcpuclockid.c new file mode 100644 index 0000000000..032caeb081 --- /dev/null +++ b/linuxthreads/sysdeps/pthread/getcpuclockid.c @@ -0,0 +1,49 @@ +/* Copyright (C) 2000, 2001, 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. */ + +#include <errno.h> +#include <pthread.h> +#include <sys/time.h> +#include <time.h> +#include <internals.h> + +int +pthread_getcpuclockid (pthread_t thread_id, clockid_t *clock_id) +{ +#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 (2 * PTHREAD_THREADS_MAX + >= 1 << (8 * sizeof (*clock_id) - CLOCK_IDFIELD_SIZE)) + return ERANGE; + + /* Store the number. */ + *clock_id = CLOCK_THREAD_CPUTIME_ID | (thread_id << CLOCK_IDFIELD_SIZE); + + return 0; +#else + /* We don't have a timer for that. */ + return ENOENT; +#endif +} diff --git a/linuxthreads/sysdeps/pthread/herrno-loc.c b/linuxthreads/sysdeps/pthread/herrno-loc.c new file mode 100644 index 0000000000..fbc5576166 --- /dev/null +++ b/linuxthreads/sysdeps/pthread/herrno-loc.c @@ -0,0 +1,43 @@ +/* Copyright (C) 1996, 97, 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. */ + +#include <netdb.h> +#include <tls.h> +#include <linuxthreads/internals.h> +#include <sysdep-cancel.h> + +#if ! USE___THREAD +# undef h_errno +extern int h_errno; +#endif + +/* When threaded, h_errno may be a per-thread variable. */ +int * +weak_const_function +__h_errno_location (void) +{ +#if ! USE___THREAD + if (! SINGLE_THREAD_P) + { + pthread_descr self = thread_self(); + return LIBC_THREAD_GETMEM (self, p_h_errnop); + } +#endif + return &h_errno; +} +libc_hidden_def (__h_errno_location) diff --git a/linuxthreads/sysdeps/pthread/list.h b/linuxthreads/sysdeps/pthread/list.h new file mode 100644 index 0000000000..43186a2d51 --- /dev/null +++ b/linuxthreads/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/linuxthreads/sysdeps/pthread/malloc-machine.h b/linuxthreads/sysdeps/pthread/malloc-machine.h new file mode 100644 index 0000000000..5191f8c779 --- /dev/null +++ b/linuxthreads/sysdeps/pthread/malloc-machine.h @@ -0,0 +1,67 @@ +/* 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_maybe_call2 (pthread_mutex_init, (m, NULL), (*(int *)(m) = 0)) +#define mutex_lock(m) \ + __libc_maybe_call2 (pthread_mutex_lock, (m), ((*(int *)(m) = 1), 0)) +#define mutex_trylock(m) \ + __libc_maybe_call2 (pthread_mutex_trylock, (m), \ + (*(int *)(m) ? 1 : ((*(int *)(m) = 1), 0))) +#define mutex_unlock(m) \ + __libc_maybe_call2 (pthread_mutex_unlock, (m), (*(int *)(m) = 0)) + +/* 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/linuxthreads/sysdeps/pthread/posix-timer.h b/linuxthreads/sysdeps/pthread/posix-timer.h new file mode 100644 index 0000000000..1b0a2b65e4 --- /dev/null +++ b/linuxthreads/sysdeps/pthread/posix-timer.h @@ -0,0 +1,204 @@ +/* Definitions for POSIX timer implementation on top of LinuxThreads. + Copyright (C) 2000, 2002, 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; +}; + + +/* 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; + +/* Nodes for the threads used to deliver signals. */ +/* A distinct thread is used for each clock type. */ + +extern struct thread_node __timer_signal_thread_rclk; + + +/* Return pointer to timer structure corresponding to ID. */ +static inline struct timer_node * +timer_id2ptr (timer_t timerid) +{ + if (timerid >= 0 && timerid < TIMER_MAX) + return &__timer_array[timerid]; + + return NULL; +} + +/* Return ID of TIMER. */ +static inline int +timer_ptr2id (struct timer_node *timer) +{ + return timer - __timer_array; +} + +/* 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 +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/linuxthreads/sysdeps/pthread/pt-initfini.c b/linuxthreads/sysdeps/pthread/pt-initfini.c new file mode 100644 index 0000000000..1ccac2f6ef --- /dev/null +++ b/linuxthreads/sysdeps/pthread/pt-initfini.c @@ -0,0 +1,124 @@ +/* Special .init and .fini section support. Linuxthread version. + Copyright (C) 1995, 1996, 1997, 2000, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it + and/or modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + 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 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.) + + The GNU C Library is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General 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 (void); + + __pthread_initialize_minimal (); +} + +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/linuxthreads/sysdeps/pthread/pthread-functions.h b/linuxthreads/sysdeps/pthread/pthread-functions.h new file mode 100644 index 0000000000..43a328ae9c --- /dev/null +++ b/linuxthreads/sysdeps/pthread/pthread-functions.h @@ -0,0 +1,96 @@ +/* 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. */ + +#ifndef _PTHREAD_FUNCTIONS_H +#define _PTHREAD_FUNCTIONS_H 1 + +#include <pthread.h> +#include <setjmp.h> +#include <linuxthreads/descr.h> + +struct fork_block; + +/* Data type shared with libc. The libc uses it to pass on calls to + the thread functions. Wine pokes directly into this structure, + so if possible avoid breaking it and append new hooks to the end. */ +struct pthread_functions +{ + pid_t (*ptr_pthread_fork) (struct fork_block *); + 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_equal) (pthread_t, pthread_t); + void (*ptr___pthread_exit) (void *); + int (*ptr_pthread_getschedparam) (pthread_t, int *, struct sched_param *); + int (*ptr_pthread_setschedparam) (pthread_t, int, + const struct sched_param *); + int (*ptr_pthread_mutex_destroy) (pthread_mutex_t *); + int (*ptr_pthread_mutex_init) (pthread_mutex_t *, + const pthread_mutexattr_t *); + int (*ptr_pthread_mutex_lock) (pthread_mutex_t *); + int (*ptr_pthread_mutex_trylock) (pthread_mutex_t *); + int (*ptr_pthread_mutex_unlock) (pthread_mutex_t *); + pthread_t (*ptr_pthread_self) (void); + int (*ptr_pthread_setcancelstate) (int, int *); + int (*ptr_pthread_setcanceltype) (int, int *); + void (*ptr_pthread_do_exit) (void *retval, char *currentframe); + void (*ptr_pthread_cleanup_upto) (__jmp_buf target, + char *targetframe); + pthread_descr (*ptr_pthread_thread_self) (void); + int (*ptr_pthread_internal_tsd_set) (int key, const void *pointer); + void * (*ptr_pthread_internal_tsd_get) (int key); + void ** __attribute__ ((__const__)) + (*ptr_pthread_internal_tsd_address) (int key); + int (*ptr_pthread_sigaction) (int sig, const struct sigaction * act, + struct sigaction *oact); + int (*ptr_pthread_sigwait) (const sigset_t *set, int *sig); + int (*ptr_pthread_raise) (int sig); + int (*ptr___pthread_cond_timedwait) (pthread_cond_t *, pthread_mutex_t *, + const struct timespec *); + void (*ptr__pthread_cleanup_push) (struct _pthread_cleanup_buffer * buffer, + void (*routine)(void *), void * arg); + + void (*ptr__pthread_cleanup_pop) (struct _pthread_cleanup_buffer * buffer, + int execute); +}; + +/* Variable in libc.so. */ +extern struct pthread_functions __libc_pthread_functions attribute_hidden; + +#endif /* pthread-functions.h */ diff --git a/linuxthreads/sysdeps/pthread/pthread.h b/linuxthreads/sysdeps/pthread/pthread.h new file mode 100644 index 0000000000..86c7ff7391 --- /dev/null +++ b/linuxthreads/sysdeps/pthread/pthread.h @@ -0,0 +1,686 @@ +/* Linuxthreads - a simple clone()-based implementation of Posix */ +/* threads for Linux. */ +/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ +/* */ +/* This program is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public License */ +/* as published by the Free Software Foundation; either version 2 */ +/* of the License, or (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Library General Public License for more details. */ + +#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/initspin.h> + + +__BEGIN_DECLS + +/* Initializers. */ + +#define PTHREAD_MUTEX_INITIALIZER \ + {0, 0, 0, PTHREAD_MUTEX_TIMED_NP, __LOCK_INITIALIZER} +#ifdef __USE_GNU +# define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP \ + {0, 0, 0, PTHREAD_MUTEX_RECURSIVE_NP, __LOCK_INITIALIZER} +# define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP \ + {0, 0, 0, PTHREAD_MUTEX_ERRORCHECK_NP, __LOCK_INITIALIZER} +# define PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP \ + {0, 0, 0, PTHREAD_MUTEX_ADAPTIVE_NP, __LOCK_INITIALIZER} +#endif + +#define PTHREAD_COND_INITIALIZER {__LOCK_INITIALIZER, 0, "", 0} + +#if defined __USE_UNIX98 || defined __USE_XOPEN2K +# define PTHREAD_RWLOCK_INITIALIZER \ + { __LOCK_INITIALIZER, 0, NULL, NULL, NULL, \ + PTHREAD_RWLOCK_DEFAULT_NP, PTHREAD_PROCESS_PRIVATE } +#endif +#ifdef __USE_GNU +# define PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP \ + { __LOCK_INITIALIZER, 0, NULL, NULL, NULL, \ + PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP, PTHREAD_PROCESS_PRIVATE } +#endif + +/* Values for attributes. */ + +enum +{ + PTHREAD_CREATE_JOINABLE, +#define PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_JOINABLE + PTHREAD_CREATE_DETACHED +#define PTHREAD_CREATE_DETACHED PTHREAD_CREATE_DETACHED +}; + +enum +{ + PTHREAD_INHERIT_SCHED, +#define PTHREAD_INHERIT_SCHED PTHREAD_INHERIT_SCHED + PTHREAD_EXPLICIT_SCHED +#define PTHREAD_EXPLICIT_SCHED PTHREAD_EXPLICIT_SCHED +}; + +enum +{ + PTHREAD_SCOPE_SYSTEM, +#define PTHREAD_SCOPE_SYSTEM PTHREAD_SCOPE_SYSTEM + PTHREAD_SCOPE_PROCESS +#define PTHREAD_SCOPE_PROCESS PTHREAD_SCOPE_PROCESS +}; + +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_ADAPTIVE_NP +#endif +}; + +enum +{ + PTHREAD_PROCESS_PRIVATE, +#define PTHREAD_PROCESS_PRIVATE PTHREAD_PROCESS_PRIVATE + PTHREAD_PROCESS_SHARED +#define PTHREAD_PROCESS_SHARED PTHREAD_PROCESS_SHARED +}; + +#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_WRITER_NP +}; +#endif /* Unix98 */ + +#define PTHREAD_ONCE_INIT 0 + +/* Special constants */ + +#ifdef __USE_XOPEN2K +/* -1 is distinct from 0 and all errno constants */ +# define PTHREAD_BARRIER_SERIAL_THREAD -1 +#endif + +/* 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) + + +/* Function for handling threads. */ + +/* Create a thread with given attributes ATTR (or default attributes + if ATTR is NULL), and call function START_ROUTINE with given + arguments ARG. */ +extern int pthread_create (pthread_t *__restrict __threadp, + __const pthread_attr_t *__restrict __attr, + void *(*__start_routine) (void *), + void *__restrict __arg) __THROW; + +/* Obtain the identifier of the current thread. */ +extern pthread_t pthread_self (void) __THROW; + +/* Compare two thread identifiers. */ +extern int pthread_equal (pthread_t __thread1, pthread_t __thread2) __THROW; + +/* Terminate calling thread. */ +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. */ +extern int pthread_join (pthread_t __th, void **__thread_return); + +/* 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; + + +/* Functions for handling attributes. */ + +/* 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; + +/* Set the `detachstate' attribute in *ATTR according to DETACHSTATE. */ +extern int pthread_attr_setdetachstate (pthread_attr_t *__attr, + int __detachstate) __THROW; + +/* Return in *DETACHSTATE the `detachstate' attribute in *ATTR. */ +extern int pthread_attr_getdetachstate (__const pthread_attr_t *__attr, + int *__detachstate) __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 *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 policy in *ATTR according to POLICY. */ +extern int pthread_attr_setschedpolicy (pthread_attr_t *__attr, int __policy) + __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 inheritance mode in *ATTR according to INHERIT. */ +extern int pthread_attr_setinheritsched (pthread_attr_t *__attr, + int __inherit) __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 contention scope in *ATTR according to SCOPE. */ +extern int pthread_attr_setscope (pthread_attr_t *__attr, int __scope) + __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; + +#ifdef __USE_UNIX98 +/* Set the size of the guard area at the bottom of the thread. */ +extern int pthread_attr_setguardsize (pthread_attr_t *__attr, + size_t __guardsize) __THROW; + +/* Get the size of the guard area at the bottom of the thread. */ +extern int pthread_attr_getguardsize (__const pthread_attr_t *__restrict + __attr, size_t *__restrict __guardsize) + __THROW; +#endif + +/* 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; + +/* Return the previously set address for the stack. */ +extern int pthread_attr_getstackaddr (__const pthread_attr_t *__restrict + __attr, void **__restrict __stackaddr) + __THROW; + +#ifdef __USE_XOPEN2K +/* 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; + +/* 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; +#endif + +/* 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; + +/* Return the currently used minimal stack size. */ +extern int pthread_attr_getstacksize (__const pthread_attr_t *__restrict + __attr, size_t *__restrict __stacksize) + __THROW; + +#ifdef __USE_GNU +/* 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; + +#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; +#endif + +/* Functions for mutex handling. */ + +/* Initialize MUTEX using attributes in *MUTEX_ATTR, or use the + default values if later is NULL. */ +extern int pthread_mutex_init (pthread_mutex_t *__restrict __mutex, + __const pthread_mutexattr_t *__restrict + __mutex_attr) __THROW; + +/* Destroy MUTEX. */ +extern int pthread_mutex_destroy (pthread_mutex_t *__mutex) __THROW; + +/* Try to lock MUTEX. */ +extern int pthread_mutex_trylock (pthread_mutex_t *__mutex) __THROW; + +/* Wait until lock for MUTEX becomes available and lock it. */ +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 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 +/* 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; + +/* Return in *KIND the mutex kind attribute in *ATTR. */ +extern int pthread_mutexattr_gettype (__const pthread_mutexattr_t *__restrict + __attr, int *__restrict __kind) __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. */ +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). */ +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; + + +#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 *__attr, + int *__pref) __THROW; + +/* Set reader/write preference. */ +extern int pthread_rwlockattr_setkind_np (pthread_rwlockattr_t *__attr, + int __pref) __THROW; +#endif + +#ifdef __USE_XOPEN2K +/* The IEEE Std. 1003.1j-2000 introduces functions to implement + 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; + + +/* Barriers are a also a new feature in 1003.1j-2000. */ + +extern int pthread_barrier_init (pthread_barrier_t *__restrict __barrier, + __const pthread_barrierattr_t *__restrict + __attr, unsigned int __count) __THROW; + +extern int pthread_barrier_destroy (pthread_barrier_t *__barrier) __THROW; + +extern int pthread_barrierattr_init (pthread_barrierattr_t *__attr) __THROW; + +extern int pthread_barrierattr_destroy (pthread_barrierattr_t *__attr) __THROW; + +extern int pthread_barrierattr_getpshared (__const pthread_barrierattr_t * + __restrict __attr, + int *__restrict __pshared) __THROW; + +extern int pthread_barrierattr_setpshared (pthread_barrierattr_t *__attr, + int __pshared) __THROW; + +extern int pthread_barrier_wait (pthread_barrier_t *__barrier) __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; + +/* Store POINTER in the thread-specific data slot identified by KEY. */ +extern int pthread_setspecific (pthread_key_t __key, + __const void *__pointer) __THROW; + +/* Return current value of the thread-specific data slot identified by KEY. */ +extern void *pthread_getspecific (pthread_key_t __key) __THROW; + + +/* 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. */ + +/* 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 __cancelthread); + +/* 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); + + +/* Install a cleanup handler: ROUTINE will be called with arguments ARG + when the thread is cancelled 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) \ + { struct _pthread_cleanup_buffer _buffer; \ + _pthread_cleanup_push (&_buffer, (routine), (arg)); + +extern void _pthread_cleanup_push (struct _pthread_cleanup_buffer *__buffer, + void (*__routine) (void *), + void *__arg) __THROW; + +/* 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) \ + _pthread_cleanup_pop (&_buffer, (execute)); } + +extern void _pthread_cleanup_pop (struct _pthread_cleanup_buffer *__buffer, + int __execute) __THROW; + +/* Install a cleanup handler as pthread_cleanup_push does, but also + saves the current cancellation type and set it to deferred cancellation. */ + +#ifdef __USE_GNU +# define pthread_cleanup_push_defer_np(routine,arg) \ + { struct _pthread_cleanup_buffer _buffer; \ + _pthread_cleanup_push_defer (&_buffer, (routine), (arg)); + +extern void _pthread_cleanup_push_defer (struct _pthread_cleanup_buffer *__buffer, + void (*__routine) (void *), + void *__arg) __THROW; + +/* 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) \ + _pthread_cleanup_pop_restore (&_buffer, (execute)); } + +extern void _pthread_cleanup_pop_restore (struct _pthread_cleanup_buffer *__buffer, + int __execute) __THROW; +#endif + + +#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 + + +/* Functions for handling signals. */ +#include <bits/sigthread.h> + + +/* Functions for handling process creation and process execution. */ + +/* 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; + +/* Terminate all threads in the program except the calling process. + Should be called just before invoking one of the exec*() functions. */ + +extern void pthread_kill_other_threads_np (void) __THROW; + +__END_DECLS + +#endif /* pthread.h */ diff --git a/linuxthreads/sysdeps/pthread/ptlongjmp.c b/linuxthreads/sysdeps/pthread/ptlongjmp.c new file mode 100644 index 0000000000..a2a56b8d9c --- /dev/null +++ b/linuxthreads/sysdeps/pthread/ptlongjmp.c @@ -0,0 +1,39 @@ +/* Linuxthreads - a simple clone()-based implementation of Posix */ +/* threads for Linux. */ +/* Copyright (C) 1998 Xavier Leroy (Xavier.Leroy@inria.fr) */ +/* */ +/* This program is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public License */ +/* as published by the Free Software Foundation; either version 2 */ +/* of the License, or (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Library General Public License for more details. */ + +/* Redefine siglongjmp and longjmp so that they interact correctly + with cleanup handlers */ + +#include <setjmp.h> +#include "pthread.h" +#include "internals.h" + +/* These functions are not declared anywhere since they shouldn't be + used at another place but here. */ +extern void __libc_siglongjmp (sigjmp_buf env, int val) + __attribute__ ((noreturn)); +extern void __libc_longjmp (sigjmp_buf env, int val) + __attribute__ ((noreturn)); + +#ifdef SHARED +void siglongjmp (sigjmp_buf env, int val) +{ + __libc_siglongjmp (env, val); +} + +void longjmp (jmp_buf env, int val) +{ + __libc_longjmp (env, val); +} +#endif diff --git a/linuxthreads/sysdeps/pthread/res-state.c b/linuxthreads/sysdeps/pthread/res-state.c new file mode 100644 index 0000000000..016e20b4ef --- /dev/null +++ b/linuxthreads/sysdeps/pthread/res-state.c @@ -0,0 +1,47 @@ +/* Copyright (C) 1996, 97, 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. */ + +#include <resolv.h> +#include <tls.h> +#include <linuxthreads/internals.h> +#include <sysdep-cancel.h> + +#if ! USE___THREAD +# undef _res +extern struct __res_state _res; +#endif + +/* When threaded, _res may be a per-thread variable. */ +struct __res_state * +#if ! USE___THREAD +weak_const_function +#endif +__res_state (void) +{ +#if ! USE___THREAD + if (! SINGLE_THREAD_P) + { + pthread_descr self = thread_self(); + return LIBC_THREAD_GETMEM (self, p_resp); + } + return &_res; +#else + return __resp; +#endif +} +libc_hidden_def (__res_state) diff --git a/linuxthreads/sysdeps/pthread/semaphore.h b/linuxthreads/sysdeps/pthread/semaphore.h new file mode 100644 index 0000000000..8793768a8e --- /dev/null +++ b/linuxthreads/sysdeps/pthread/semaphore.h @@ -0,0 +1 @@ +#include <linuxthreads/semaphore.h> diff --git a/linuxthreads/sysdeps/pthread/sigaction.c b/linuxthreads/sysdeps/pthread/sigaction.c new file mode 100644 index 0000000000..f4e20790d9 --- /dev/null +++ b/linuxthreads/sysdeps/pthread/sigaction.c @@ -0,0 +1,55 @@ +/* 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. */ + +/* 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 <bits/libc-lock.h> + +# define LIBC_SIGACTION 1 + +# include <linuxthreads/sysdeps/pthread/sigaction.c> + +# ifndef NOT_IN_libc +# ifndef SHARED +weak_extern (__pthread_sigaction) +# endif + +int +__sigaction (sig, act, oact) + int sig; + const struct sigaction *act; + struct sigaction *oact; +{ + return __libc_maybe_call2 (pthread_sigaction, (sig, act, oact), + __libc_sigaction (sig, act, oact)); +} +# else +weak_alias (__libc_sigaction, __sigaction) +# endif +libc_hidden_weak (__sigaction) +weak_alias (__sigaction, sigaction) + +#else + +# include_next <sigaction.c> + +#endif /* LIBC_SIGACTION */ diff --git a/linuxthreads/sysdeps/pthread/tcb-offsets.h b/linuxthreads/sysdeps/pthread/tcb-offsets.h new file mode 100644 index 0000000000..3fe13702ea --- /dev/null +++ b/linuxthreads/sysdeps/pthread/tcb-offsets.h @@ -0,0 +1 @@ +/* This is overridden by generated tcb-offsets.h on arches which need it. */ diff --git a/linuxthreads/sysdeps/pthread/timer_create.c b/linuxthreads/sysdeps/pthread/timer_create.c new file mode 100644 index 0000000000..7f7e886c83 --- /dev/null +++ b/linuxthreads/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 (clock_id, evp, timerid) + clockid_t clock_id; + struct sigevent *evp; + timer_t *timerid; +{ + int retval = -1; + struct timer_node *newtimer = NULL; + struct thread_node *thread = NULL; + + if (0 +#ifdef _POSIX_CPUTIME + || clock_id == CLOCK_PROCESS_CPUTIME_ID +#endif +#ifdef _POSIX_THREAD_CPUTIME + || 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_int = 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/linuxthreads/sysdeps/pthread/timer_delete.c b/linuxthreads/sysdeps/pthread/timer_delete.c new file mode 100644 index 0000000000..48ba1f2726 --- /dev/null +++ b/linuxthreads/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 (timerid) + timer_t timerid; +{ + struct timer_node *timer; + int retval = -1; + + pthread_mutex_lock (&__timer_mutex); + + timer = timer_id2ptr (timerid); + if (! timer_valid (timer)) + /* Invalid timer ID or the timer is not in use. */ + __set_errno (EINVAL); + else + { + if (timer->armed && timer->thread != NULL) + { + struct thread_node *thread = timer->thread; + assert (thread != NULL); + + /* If thread is cancelled while waiting for handler to terminate, + the mutex is unlocked and timer_delete is aborted. */ + pthread_cleanup_push (__timer_mutex_cancel_handler, &__timer_mutex); + + /* If timer is currently being serviced, wait for it to finish. */ + while (thread->current_timer == timer) + pthread_cond_wait (&thread->cond, &__timer_mutex); + + pthread_cleanup_pop (0); + } + + /* Remove timer from whatever queue it may be on and deallocate it. */ + timer->inuse = TIMER_DELETED; + list_unlink_ip (&timer->links); + timer_delref (timer); + retval = 0; + } + + pthread_mutex_unlock (&__timer_mutex); + + return retval; +} diff --git a/linuxthreads/sysdeps/pthread/timer_getoverr.c b/linuxthreads/sysdeps/pthread/timer_getoverr.c new file mode 100644 index 0000000000..f3e22215b2 --- /dev/null +++ b/linuxthreads/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/linuxthreads/sysdeps/pthread/timer_gettime.c b/linuxthreads/sysdeps/pthread/timer_gettime.c new file mode 100644 index 0000000000..723a61632f --- /dev/null +++ b/linuxthreads/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/linuxthreads/sysdeps/pthread/timer_routines.c b/linuxthreads/sysdeps/pthread/timer_routines.c new file mode 100644 index 0000000000..3877b86fbb --- /dev/null +++ b/linuxthreads/sysdeps/pthread/timer_routines.c @@ -0,0 +1,573 @@ +/* Helper code for POSIX timer implementation on LinuxThreads. + Copyright (C) 2000, 2001, 2002, 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" + + +/* 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 LinuxThreads-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) +{ + return (left->__detachstate == right->__detachstate + && left->__schedpolicy == right->__schedpolicy + && left->__guardsize == right->__guardsize + && (left->__schedparam.sched_priority + == right->__schedparam.sched_priority) + && left->__inheritsched == right->__inheritsched + && left->__scope == right->__scope + && left->__stacksize == right->__stacksize + && left->__stackaddr_set == right->__stackaddr_set + && (left->__stackaddr_set + || left->__stackaddr == right->__stackaddr)); +} + + +/* 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/linuxthreads/sysdeps/pthread/timer_settime.c b/linuxthreads/sysdeps/pthread/timer_settime.c new file mode 100644 index 0000000000..592b5271ba --- /dev/null +++ b/linuxthreads/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/linuxthreads/sysdeps/pthread/tst-timer.c b/linuxthreads/sysdeps/pthread/tst-timer.c new file mode 100644 index 0000000000..7417bcd5f0 --- /dev/null +++ b/linuxthreads/sysdeps/pthread/tst-timer.c @@ -0,0 +1,114 @@ +/* Tests for POSIX timer implementation. + Copyright (C) 2000, 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 <signal.h> +#include <stdio.h> +#include <time.h> +#include <unistd.h> + + +static void +notify_func (union sigval sigval) +{ + puts ("notify_func"); +} + + +static void +signal_func (int sig) +{ + static const char text[] = "signal_func\n"; + signal (sig, signal_func); + write (STDOUT_FILENO, text, sizeof text - 1); +} + +static void +intr_sleep (int sec) +{ + struct timespec ts; + + ts.tv_sec = sec; + ts.tv_nsec = 0; + + while (nanosleep (&ts, &ts) == -1 && errno == EINTR) + ; +} + +#define ZSIGALRM 14 + + +int +main (void) +{ + struct timespec ts; + timer_t timer_sig, timer_thr1, timer_thr2; + int retval; + struct sigevent sigev1 = + { + .sigev_notify = SIGEV_SIGNAL, + .sigev_signo = ZSIGALRM + }; + struct sigevent sigev2; + struct itimerspec itimer1 = { { 0, 200000000 }, { 0, 200000000 } }; + struct itimerspec itimer2 = { { 0, 100000000 }, { 0, 500000000 } }; + struct itimerspec itimer3 = { { 0, 150000000 }, { 0, 300000000 } }; + struct itimerspec old; + + retval = clock_gettime (CLOCK_REALTIME, &ts); + + sigev2.sigev_notify = SIGEV_THREAD; + sigev2.sigev_notify_function = notify_func; + sigev2.sigev_notify_attributes = NULL; + + setvbuf (stdout, 0, _IOLBF, 0); + + printf ("clock_gettime returned %d, timespec = { %ld, %ld }\n", + retval, ts.tv_sec, ts.tv_nsec); + + retval = clock_getres (CLOCK_REALTIME, &ts); + + printf ("clock_getres returned %d, timespec = { %ld, %ld }\n", + retval, ts.tv_sec, ts.tv_nsec); + + timer_create (CLOCK_REALTIME, &sigev1, &timer_sig); + timer_create (CLOCK_REALTIME, &sigev2, &timer_thr1); + timer_create (CLOCK_REALTIME, &sigev2, &timer_thr2); + + timer_settime (timer_thr1, 0, &itimer2, &old); + timer_settime (timer_thr2, 0, &itimer3, &old); + + signal (ZSIGALRM, signal_func); + + timer_settime (timer_sig, 0, &itimer1, &old); + + timer_delete (-1); + + intr_sleep (3); + + timer_delete (timer_sig); + timer_delete (timer_thr1); + + intr_sleep (3); + + timer_delete (timer_thr2); + + return 0; +} diff --git a/linuxthreads/sysdeps/s390/Makefile b/linuxthreads/sysdeps/s390/Makefile new file mode 100644 index 0000000000..2885c968b3 --- /dev/null +++ b/linuxthreads/sysdeps/s390/Makefile @@ -0,0 +1,6 @@ +ifeq ($(subdir),csu) +gen-as-const-headers += tcb-offsets.sym +endif +ifeq ($(subdir),linuxthreads) +libpthread-routines += ptw-sysdep +endif diff --git a/linuxthreads/sysdeps/s390/pspinlock.c b/linuxthreads/sysdeps/s390/pspinlock.c new file mode 100644 index 0000000000..f963f35371 --- /dev/null +++ b/linuxthreads/sysdeps/s390/pspinlock.c @@ -0,0 +1,91 @@ +/* POSIX spinlock implementation. S/390 version. + Copyright (C) 2000, 2004 Free Software Foundation, Inc. + Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com). + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General 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 "internals.h" + +/* This implementation is similar to the one used in the Linux kernel. + But the kernel is byte instructions for the memory access. This is + faster but unusable here. The problem is that only 128 + threads/processes could use the spinlock at the same time. If (by + a design error in the program) a thread/process would hold the + spinlock for a time long enough to accumulate 128 waiting + processes, the next one will find a positive value in the spinlock + and assume it is unlocked. We cannot accept that. */ + +int +__pthread_spin_lock (pthread_spinlock_t *lock) +{ + asm volatile(" basr 1,0\n" + "0: slr 0,0\n" + " cs 0,1,%1\n" + " jl 0b\n" + : "=m" (*lock) + : "m" (*lock) : "0", "1", "cc" ); + return 0; +} +weak_alias (__pthread_spin_lock, pthread_spin_lock) + +int +__pthread_spin_trylock (pthread_spinlock_t *lock) +{ + int oldval; + + asm volatile(" slr %1,%1\n" + " basr 1,0\n" + "0: cs %1,1,%0" + : "=m" (*lock), "=&d" (oldval) + : "m" (*lock) : "1", "cc" ); + return oldval == 0 ? 0 : EBUSY; +} +weak_alias (__pthread_spin_trylock, pthread_spin_trylock) + + +int +__pthread_spin_unlock (pthread_spinlock_t *lock) +{ + asm volatile(" xc 0(4,%0),0(%0)\n" + " bcr 15,0" + : : "a" (lock) : "memory" ); + return 0; +} +weak_alias (__pthread_spin_unlock, pthread_spin_unlock) + + +int +__pthread_spin_init (pthread_spinlock_t *lock, int pshared) +{ + /* We can ignore the `pshared' parameter. Since we are busy-waiting + all processes which can access the memory location `lock' points + to can use the spinlock. */ + *lock = 0; + return 0; +} +weak_alias (__pthread_spin_init, pthread_spin_init) + + +int +__pthread_spin_destroy (pthread_spinlock_t *lock) +{ + /* Nothing to do. */ + return 0; +} +weak_alias (__pthread_spin_destroy, pthread_spin_destroy) diff --git a/linuxthreads/sysdeps/s390/s390-32/pt-machine.h b/linuxthreads/sysdeps/s390/s390-32/pt-machine.h new file mode 100644 index 0000000000..398332965f --- /dev/null +++ b/linuxthreads/sysdeps/s390/s390-32/pt-machine.h @@ -0,0 +1,120 @@ +/* Machine-dependent pthreads configuration and inline functions. + S390 version. + Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com). + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General 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 _PT_MACHINE_H +#define _PT_MACHINE_H 1 + +#ifndef PT_EI +# define PT_EI extern inline __attribute__ ((always_inline)) +#endif + +extern long int testandset (int *spinlock); +extern int __compare_and_swap (long int *p, long int oldval, long int newval); + +/* For multiprocessor systems, we want to ensure all memory accesses + are completed before we reset a lock. On other systems, we still + need to make sure that the compiler has flushed everything to memory. */ +#define MEMORY_BARRIER() __asm__ __volatile__ ("bcr 15,0" : : : "memory") + +/* Spinlock implementation; required. */ +PT_EI long int +testandset (int *spinlock) +{ + int ret; + + __asm__ __volatile__( + " la 1,%1\n" + " lhi 0,1\n" + " l %0,%1\n" + "0: cs %0,0,0(1)\n" + " jl 0b" + : "=&d" (ret), "+m" (*spinlock) + : : "0", "1", "cc"); + + return ret; +} + + +/* Get some notion of the current stack. Need not be exactly the top + of the stack, just something somewhere in the current frame. */ +#define CURRENT_STACK_FRAME stack_pointer +register char * stack_pointer __asm__ ("15"); + +#ifdef USE_TLS +/* Return the thread descriptor for the current thread. */ +# define THREAD_SELF ((pthread_descr) __builtin_thread_pointer ()) + +/* Initialize the thread-unique value. */ +#define INIT_THREAD_SELF(descr, nr) __builtin_set_thread_pointer (descr) +#else +/* Return the thread descriptor for the current thread. + S/390 registers uses access register 0 as "thread register". */ +#define THREAD_SELF ({ \ + register pthread_descr __self; \ + __asm__ ("ear %0,%%a0" : "=d" (__self) ); \ + __self; \ +}) + +/* Initialize the thread-unique value. */ +#define INIT_THREAD_SELF(descr, nr) ({ \ + __asm__ ("sar %%a0,%0" : : "d" (descr) ); \ +}) +#endif + +/* Access to data in the thread descriptor is easy. */ +#define THREAD_GETMEM(descr, member) \ + ((void) sizeof (descr), THREAD_SELF->member) +#define THREAD_GETMEM_NC(descr, member) \ + ((void) sizeof (descr), THREAD_SELF->member) +#define THREAD_SETMEM(descr, member, value) \ + ((void) sizeof (descr), THREAD_SELF->member = (value)) +#define THREAD_SETMEM_NC(descr, member, value) \ + ((void) sizeof (descr), THREAD_SELF->member = (value)) + +/* We want the OS to assign stack addresses. */ +#define FLOATING_STACKS 1 + +/* Maximum size of the stack if the rlimit is unlimited. */ +#define ARCH_STACK_MAX_SIZE 8*1024*1024 + +/* Compare-and-swap for semaphores. */ + +#define HAS_COMPARE_AND_SWAP + +PT_EI int +__compare_and_swap(long int *p, long int oldval, long int newval) +{ + int retval; + + __asm__ __volatile__( + " la 1,%1\n" + " lr 0,%2\n" + " cs 0,%3,0(1)\n" + " ipm %0\n" + " srl %0,28\n" + "0:" + : "=&d" (retval), "+m" (*p) + : "d" (oldval) , "d" (newval) + : "cc", "0", "1" ); + return retval == 0; +} + +#endif /* pt-machine.h */ diff --git a/linuxthreads/sysdeps/s390/s390-64/pt-machine.h b/linuxthreads/sysdeps/s390/s390-64/pt-machine.h new file mode 100644 index 0000000000..49f8ae2b9a --- /dev/null +++ b/linuxthreads/sysdeps/s390/s390-64/pt-machine.h @@ -0,0 +1,125 @@ +/* Machine-dependent pthreads configuration and inline functions. + 64 bit S/390 version. + Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc. + Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com). + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General 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 _PT_MACHINE_H +#define _PT_MACHINE_H 1 + +#ifndef PT_EI +# define PT_EI extern inline __attribute__ ((always_inline)) +#endif + +extern long int testandset (int *spinlock); +extern int __compare_and_swap (long int *p, long int oldval, long int newval); + +/* For multiprocessor systems, we want to ensure all memory accesses + are completed before we reset a lock. On other systems, we still + need to make sure that the compiler has flushed everything to memory. */ +#define MEMORY_BARRIER() __asm__ __volatile__ ("bcr 15,0" : : : "memory") + +/* Spinlock implementation; required. */ +PT_EI long int +testandset (int *spinlock) +{ + int ret; + + __asm__ __volatile__( + " la 1,%1\n" + " lhi 0,1\n" + " l %0,%1\n" + "0: cs %0,0,0(1)\n" + " jl 0b" + : "=&d" (ret), "+m" (*spinlock) + : : "0", "1", "cc"); + + return ret; +} + + +/* Get some notion of the current stack. Need not be exactly the top + of the stack, just something somewhere in the current frame. */ +#define CURRENT_STACK_FRAME stack_pointer +register char * stack_pointer __asm__ ("15"); + +#ifdef USE_TLS +/* Return the thread descriptor for the current thread. */ +# define THREAD_SELF ((pthread_descr) __builtin_thread_pointer ()) + +/* Initialize the thread-unique value. */ +#define INIT_THREAD_SELF(descr, nr) __builtin_set_thread_pointer (descr) +#else +/* Return the thread descriptor for the current thread. + 64 bit S/390 uses access register 0 and 1 as "thread register". */ +#define THREAD_SELF ({ \ + register pthread_descr __self; \ + __asm__ (" ear %0,%%a0\n" \ + " sllg %0,%0,32\n" \ + " ear %0,%%a1\n" \ + : "=d" (__self) ); \ + __self; \ +}) + +/* Initialize the thread-unique value. */ +#define INIT_THREAD_SELF(descr, nr) ({ \ + __asm__ (" sar %%a1,%0\n" \ + " srlg 0,%0,32\n" \ + " sar %%a0,0\n" \ + : : "d" (descr) : "0" ); \ +}) +#endif + +/* Access to data in the thread descriptor is easy. */ +#define THREAD_GETMEM(descr, member) \ + ((void) sizeof (descr), THREAD_SELF->member) +#define THREAD_GETMEM_NC(descr, member) \ + ((void) sizeof (descr), THREAD_SELF->member) +#define THREAD_SETMEM(descr, member, value) \ + ((void) sizeof (descr), THREAD_SELF->member = (value)) +#define THREAD_SETMEM_NC(descr, member, value) \ + ((void) sizeof (descr), THREAD_SELF->member = (value)) + +/* We want the OS to assign stack addresses. */ +#define FLOATING_STACKS 1 + +/* Maximum size of the stack if the rlimit is unlimited. */ +#define ARCH_STACK_MAX_SIZE 8*1024*1024 + +/* Compare-and-swap for semaphores. */ + +#define HAS_COMPARE_AND_SWAP + +PT_EI int +__compare_and_swap(long int *p, long int oldval, long int newval) +{ + int retval; + + __asm__ __volatile__( + " lgr 0,%2\n" + " csg 0,%3,%1\n" + " ipm %0\n" + " srl %0,28\n" + "0:" + : "=&d" (retval), "+m" (*p) + : "d" (oldval) , "d" (newval) + : "cc", "0"); + return retval == 0; +} + +#endif /* pt-machine.h */ diff --git a/linuxthreads/sysdeps/s390/tcb-offsets.sym b/linuxthreads/sysdeps/s390/tcb-offsets.sym new file mode 100644 index 0000000000..aee6be2570 --- /dev/null +++ b/linuxthreads/sysdeps/s390/tcb-offsets.sym @@ -0,0 +1,4 @@ +#include <sysdep.h> +#include <tls.h> + +MULTIPLE_THREADS_OFFSET offsetof (tcbhead_t, multiple_threads) diff --git a/linuxthreads/sysdeps/s390/tls.h b/linuxthreads/sysdeps/s390/tls.h new file mode 100644 index 0000000000..41a83a72fb --- /dev/null +++ b/linuxthreads/sysdeps/s390/tls.h @@ -0,0 +1,140 @@ +/* Definitions for thread-local data handling. linuxthreads/s390 version. + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _TLS_H +#define _TLS_H + +#ifndef __ASSEMBLER__ + +# include <pt-machine.h> +# include <stddef.h> + +/* Type for the dtv. */ +typedef union dtv +{ + size_t counter; + void *pointer; +} dtv_t; + +typedef struct +{ + void *tcb; /* Pointer to the TCB. Not necessary the + thread descriptor used by libpthread. */ + dtv_t *dtv; + void *self; /* Pointer to the thread descriptor. */ + int multiple_threads; +} tcbhead_t; + +#else /* __ASSEMBLER__ */ +# include <tcb-offsets.h> +#endif /* __ASSEMBLER__ */ + +/* TLS is always supported if the tools support it. There are no + kernel dependencies. To avoid bothering with the TLS support code + at all, use configure --without-tls. + + We need USE_TLS to be consistently defined, for ldsodefs.h + conditionals. */ + +#ifdef HAVE_TLS_SUPPORT + +/* Signal that TLS support is available. */ +# define USE_TLS 1 + +# ifndef __ASSEMBLER__ +/* Get system call information. */ +# include <sysdep.h> + + +/* Get the thread descriptor definition. */ +# include <linuxthreads/descr.h> + +/* This is the size of the initial TCB. */ +# define TLS_INIT_TCB_SIZE sizeof (tcbhead_t) + +/* Alignment requirements for the initial TCB. */ +# define TLS_INIT_TCB_ALIGN __alignof__ (tcbhead_t) + +/* This is the size of the TCB. */ +# define TLS_TCB_SIZE sizeof (struct _pthread_descr_struct) + +/* Alignment requirements for the TCB. */ +# define TLS_TCB_ALIGN __alignof__ (struct _pthread_descr_struct) + +/* 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 *) __builtin_thread_pointer ())->dtv = (dtv)) + +/* Return dtv of given thread descriptor. */ +# define GET_DTV(descr) \ + (((tcbhead_t *) (descr))->dtv) + +/* Code to initially initialize the thread pointer. This might need + special attention since 'errno' is not yet available and if the + operation can cause a failure 'errno' must not be touched. + + The value of this macro is null if successful, or an error string. */ +# define TLS_INIT_TP(descr, secondcall) \ + ({ \ + void *_descr = (descr); \ + tcbhead_t *head = _descr; \ + \ + head->tcb = _descr; \ + /* For now the thread descriptor is at the same address. */ \ + head->self = _descr; \ + \ + __builtin_set_thread_pointer (_descr); \ + NULL; \ + }) + +/* Return the address of the dtv for the current thread. */ +# define THREAD_DTV() \ + (((tcbhead_t *) __builtin_thread_pointer ())->dtv) + +# endif /* __ASSEMBLER__ */ + +#else /* HAVE_TLS_SUPPORT && (FLOATING_STACKS || !IS_IN_libpthread) */ + +# ifndef __ASSEMBLER__ + +/* Get the thread descriptor definition. */ +# include <linuxthreads/descr.h> + +# define NONTLS_INIT_TP \ + do { \ + static const tcbhead_t nontls_init_tp \ + = { .multiple_threads = 0 }; \ + INIT_THREAD_SELF (&nontls_init_tp, 0); \ + } while (0) + +# endif /* __ASSEMBLER__ */ + +#endif /* HAVE_TLS_SUPPORT && (FLOATING_STACKS || !IS_IN_libpthread) */ + +#endif /* tls.h */ diff --git a/linuxthreads/sysdeps/sh/Makefile b/linuxthreads/sysdeps/sh/Makefile new file mode 100644 index 0000000000..81bddf688c --- /dev/null +++ b/linuxthreads/sysdeps/sh/Makefile @@ -0,0 +1,3 @@ +ifeq ($(subdir),csu) +gen-as-const-headers += tcb-offsets.sym +endif diff --git a/linuxthreads/sysdeps/sh/pspinlock.c b/linuxthreads/sysdeps/sh/pspinlock.c new file mode 100644 index 0000000000..2dec849d3c --- /dev/null +++ b/linuxthreads/sysdeps/sh/pspinlock.c @@ -0,0 +1,80 @@ +/* POSIX spinlock implementation. SH version. + Copyright (C) 2000, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; 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 "internals.h" + +int +__pthread_spin_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; +} +weak_alias (__pthread_spin_lock, pthread_spin_lock) + + +int +__pthread_spin_trylock (pthread_spinlock_t *lock) +{ + unsigned int val; + + asm volatile ("tas.b @%1; movt %0" + : "=r" (val) + : "r" (lock) + : "memory"); + return val ? 0 : EBUSY; +} +weak_alias (__pthread_spin_trylock, pthread_spin_trylock) + + +int +__pthread_spin_unlock (pthread_spinlock_t *lock) +{ + return *lock = 0; +} +weak_alias (__pthread_spin_unlock, pthread_spin_unlock) + + +int +__pthread_spin_init (pthread_spinlock_t *lock, int pshared) +{ + /* We can ignore the `pshared' parameter. Since we are busy-waiting + all processes which can access the memory location `lock' points + to can use the spinlock. */ + return *lock = 0; +} +weak_alias (__pthread_spin_init, pthread_spin_init) + + +int +__pthread_spin_destroy (pthread_spinlock_t *lock) +{ + /* Nothing to do. */ + return 0; +} +weak_alias (__pthread_spin_destroy, pthread_spin_destroy) diff --git a/linuxthreads/sysdeps/sh/pt-machine.h b/linuxthreads/sysdeps/sh/pt-machine.h new file mode 100644 index 0000000000..02545e6b45 --- /dev/null +++ b/linuxthreads/sysdeps/sh/pt-machine.h @@ -0,0 +1,81 @@ +/* Machine-dependent pthreads configuration and inline functions. + SuperH version. + Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Niibe Yutaka <gniibe@m17n.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; 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 _PT_MACHINE_H +#define _PT_MACHINE_H 1 + +#ifndef __ASSEMBLER__ +#ifndef PT_EI +# define PT_EI extern inline __attribute__ ((always_inline)) +#endif + +extern long int testandset (int *spinlock); +extern int __compare_and_swap (long int *p, long int oldval, long int newval); + +/* Spinlock implementation; required. */ +PT_EI long int +testandset (int *spinlock) +{ + int ret; + + __asm__ __volatile__( + "tas.b @%1\n\t" + "movt %0" + : "=r" (ret) + : "r" (spinlock) + : "memory", "cc"); + + return (ret == 0); +} + +/* We want the OS to assign stack addresses. */ +#define FLOATING_STACKS 1 + +/* Maximum size of the stack if the rlimit is unlimited. */ +#define ARCH_STACK_MAX_SIZE 32*1024*1024 + +/* Get some notion of the current stack. Need not be exactly the top + of the stack, just something somewhere in the current frame. */ +#define CURRENT_STACK_FRAME stack_pointer +register char * stack_pointer __asm__ ("r15"); + +/* Return the thread descriptor for the current thread. */ +struct _pthread_descr_struct; +#define THREAD_SELF \ + ({ struct _pthread_descr_struct *self; \ + __asm__("stc gbr,%0" : "=r" (self)); self;}) + +/* Initialize the thread-unique value. */ +#define INIT_THREAD_SELF(descr, nr) \ + ({ __asm__ __volatile__("ldc %0,gbr" : : "r" (descr));}) + +/* Access to data in the thread descriptor is easy. */ +#define THREAD_GETMEM(descr, member) \ + ((void) sizeof (descr), THREAD_SELF->member) +#define THREAD_GETMEM_NC(descr, member) \ + ((void) sizeof (descr), THREAD_SELF->member) +#define THREAD_SETMEM(descr, member, value) \ + ((void) sizeof (descr), THREAD_SELF->member = (value)) +#define THREAD_SETMEM_NC(descr, member, value) \ + ((void) sizeof (descr), THREAD_SELF->member = (value)) +#endif /* __ASSEMBLER__ */ + +#endif /* pt-machine.h */ diff --git a/linuxthreads/sysdeps/sh/tcb-offsets.sym b/linuxthreads/sysdeps/sh/tcb-offsets.sym new file mode 100644 index 0000000000..328eb05738 --- /dev/null +++ b/linuxthreads/sysdeps/sh/tcb-offsets.sym @@ -0,0 +1,10 @@ +#include <sysdep.h> +#include <tls.h> + +-- +#ifdef USE_TLS +MULTIPLE_THREADS_OFFSET offsetof (struct _pthread_descr_struct, p_multiple_threads) +TLS_PRE_TCB_SIZE sizeof (struct _pthread_descr_struct) +#else +MULTIPLE_THREADS_OFFSET offsetof (tcbhead_t, multiple_threads) +#endif diff --git a/linuxthreads/sysdeps/sh/tls.h b/linuxthreads/sysdeps/sh/tls.h new file mode 100644 index 0000000000..17a247c6b6 --- /dev/null +++ b/linuxthreads/sysdeps/sh/tls.h @@ -0,0 +1,148 @@ +/* Definition for thread-local data handling. linuxthreads/SH version. + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _TLS_H +#define _TLS_H + +# include <dl-sysdep.h> +# include <pt-machine.h> + +#ifndef __ASSEMBLER__ +# include <stddef.h> +# include <stdint.h> + +/* Type for the dtv. */ +typedef union dtv +{ + size_t counter; + void *pointer; +} dtv_t; + +#else /* __ASSEMBLER__ */ +# include <tcb-offsets.h> +#endif /* __ASSEMBLER__ */ + + +/* We can support TLS only if the floating-stack support is available. */ +#if defined HAVE_TLS_SUPPORT \ + && (defined FLOATING_STACKS || !defined IS_IN_libpthread) + +/* Signal that TLS support is available. */ +# define USE_TLS 1 + +# ifndef __ASSEMBLER__ + +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 __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_descr_struct) + +/* Alignment requirements for the TCB. */ +# define TLS_TCB_ALIGN __alignof__ (struct _pthread_descr_struct) + +/* The TLS blocks start right after the TCB. */ +# define TLS_DTV_AT_TP 1 + +/* 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. */ +# undef THREAD_SELF +# define THREAD_SELF \ + ({ struct _pthread_descr_struct *__self; \ + __asm ("stc gbr,%0" : "=r" (__self)); \ + __self - 1;}) + +# undef INIT_THREAD_SELF +# define INIT_THREAD_SELF(descr, nr) \ + ({ struct _pthread_descr_struct *__self = (void *) descr; \ + __asm __volatile ("ldc %0,gbr" : : "r" (__self + 1)); \ + 0; }) + +# define TLS_MULTIPLE_THREADS_IN_TCB 1 + +/* Get the thread descriptor definition. This must be after the + the definition of THREAD_SELF for TLS. */ +# include <linuxthreads/descr.h> + +# endif /* __ASSEMBLER__ */ + +#else + +# ifndef __ASSEMBLER__ + +typedef struct +{ + void *tcb; + dtv_t *dtv; + void *self; + int multiple_threads; +} tcbhead_t; + +/* Get the thread descriptor definition. */ +# include <linuxthreads/descr.h> + +# define NONTLS_INIT_TP \ + do { \ + static const tcbhead_t nontls_init_tp = { .multiple_threads = 0 }; \ + __asm __volatile ("ldc %0,gbr" : : "r" (&nontls_init_tp)); \ + } while (0) + +# endif /* __ASSEMBLER__ */ + +#endif /* HAVE_TLS_SUPPORT && (FLOATING_STACKS || !IS_IN_libpthread) */ + +#endif /* tls.h */ diff --git a/linuxthreads/sysdeps/sparc/Makefile b/linuxthreads/sysdeps/sparc/Makefile new file mode 100644 index 0000000000..81bddf688c --- /dev/null +++ b/linuxthreads/sysdeps/sparc/Makefile @@ -0,0 +1,3 @@ +ifeq ($(subdir),csu) +gen-as-const-headers += tcb-offsets.sym +endif diff --git a/linuxthreads/sysdeps/sparc/sparc32/pspinlock.c b/linuxthreads/sysdeps/sparc/sparc32/pspinlock.c new file mode 100644 index 0000000000..a67dbf901e --- /dev/null +++ b/linuxthreads/sysdeps/sparc/sparc32/pspinlock.c @@ -0,0 +1,88 @@ +/* POSIX spinlock implementation. SPARC32 version. + Copyright (C) 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; 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 "internals.h" + +/* This implementation is similar to the one used in the Linux kernel. */ +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; +} +weak_alias (__pthread_spin_lock, pthread_spin_lock) + + +int +__pthread_spin_trylock (pthread_spinlock_t *lock) +{ + int result; + asm volatile + ("ldstub [%1], %0" + : "=r" (result) + : "r" (lock) + : "memory"); + return result == 0 ? 0 : EBUSY; +} +weak_alias (__pthread_spin_trylock, pthread_spin_trylock) + + +int +__pthread_spin_unlock (pthread_spinlock_t *lock) +{ + *lock = 0; + return 0; +} +weak_alias (__pthread_spin_unlock, pthread_spin_unlock) + + +int +__pthread_spin_init (pthread_spinlock_t *lock, int pshared) +{ + /* We can ignore the `pshared' parameter. Since we are busy-waiting + all processes which can access the memory location `lock' points + to can use the spinlock. */ + *lock = 0; + return 0; +} +weak_alias (__pthread_spin_init, pthread_spin_init) + + +int +__pthread_spin_destroy (pthread_spinlock_t *lock) +{ + /* Nothing to do. */ + return 0; +} +weak_alias (__pthread_spin_destroy, pthread_spin_destroy) diff --git a/linuxthreads/sysdeps/sparc/sparc32/pt-machine.h b/linuxthreads/sysdeps/sparc/sparc32/pt-machine.h new file mode 100644 index 0000000000..322a52051f --- /dev/null +++ b/linuxthreads/sysdeps/sparc/sparc32/pt-machine.h @@ -0,0 +1,83 @@ +/* Machine-dependent pthreads configuration and inline functions. + sparc version. + Copyright (C) 1996-1998, 2000-2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Richard Henderson <rth@tamu.edu>. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; 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 _PT_MACHINE_H +#define _PT_MACHINE_H 1 + +#ifndef PT_EI +# define PT_EI extern inline __attribute__ ((always_inline)) +#endif + +extern long int testandset (int *spinlock); +extern int __compare_and_swap (long int *p, long int oldval, long int newval); + +/* Spinlock implementation; required. */ +PT_EI long int +testandset (int *spinlock) +{ + int ret; + + __asm__ __volatile__("ldstub %1,%0" + : "=r"(ret), "=m"(*spinlock) + : "m"(*spinlock)); + + return ret; +} + + +/* Memory barrier; default is to do nothing */ +#define MEMORY_BARRIER() __asm__ __volatile__("stbar" : : : "memory") + + +/* Get some notion of the current stack. Need not be exactly the top + of the stack, just something somewhere in the current frame. */ +#define CURRENT_STACK_FRAME (stack_pointer + (2 * 64)) +register char *stack_pointer __asm__("%sp"); + + +/* Registers %g6 and %g7 are reserved by the ABI for "system use". + %g7 is specified in the TLS ABI as thread pointer -- we do the same. */ +struct _pthread_descr_struct; +register struct _pthread_descr_struct *__thread_self __asm__("%g7"); + +/* Return the thread descriptor for the current thread. */ +#define THREAD_SELF __thread_self + +/* Initialize the thread-unique value. */ +#define INIT_THREAD_SELF(descr, nr) (__thread_self = (descr)) + +/* Access to data in the thread descriptor is easy. */ +#define THREAD_GETMEM(descr, member) \ + ((void) sizeof (descr), THREAD_SELF->member) +#define THREAD_GETMEM_NC(descr, member) \ + ((void) sizeof (descr), THREAD_SELF->member) +#define THREAD_SETMEM(descr, member, value) \ + ((void) sizeof (descr), THREAD_SELF->member = (value)) +#define THREAD_SETMEM_NC(descr, member, value) \ + ((void) sizeof (descr), THREAD_SELF->member = (value)) + +/* We want the OS to assign stack addresses. */ +#define FLOATING_STACKS 1 + +/* Maximum size of the stack if the rlimit is unlimited. */ +#define ARCH_STACK_MAX_SIZE 8*1024*1024 + +#endif /* pt-machine.h */ diff --git a/linuxthreads/sysdeps/sparc/sparc32/sparcv9/Versions b/linuxthreads/sysdeps/sparc/sparc32/sparcv9/Versions new file mode 100644 index 0000000000..32da57080d --- /dev/null +++ b/linuxthreads/sysdeps/sparc/sparc32/sparcv9/Versions @@ -0,0 +1,5 @@ +libpthread { + GLIBC_PRIVATE { + __pthread_clock_gettime; __pthread_clock_settime; + } +} diff --git a/linuxthreads/sysdeps/sparc/sparc32/sparcv9/pspinlock.c b/linuxthreads/sysdeps/sparc/sparc32/sparcv9/pspinlock.c new file mode 100644 index 0000000000..04f588bed5 --- /dev/null +++ b/linuxthreads/sysdeps/sparc/sparc32/sparcv9/pspinlock.c @@ -0,0 +1,94 @@ +/* POSIX spinlock implementation. SPARC v9 version. + Copyright (C) 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; 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 "internals.h" + + +/* This implementation is similar to the one used in the Linux kernel. */ +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; +} +weak_alias (__pthread_spin_lock, pthread_spin_lock) + + +int +__pthread_spin_trylock (pthread_spinlock_t *lock) +{ + int result; + asm volatile + ("ldstub [%1], %0\n" + "membar #StoreLoad | #StoreStore" + : "=r" (result) + : "r" (lock) + : "memory"); + return result == 0 ? 0 : EBUSY; +} +weak_alias (__pthread_spin_trylock, pthread_spin_trylock) + + +int +__pthread_spin_unlock (pthread_spinlock_t *lock) +{ + asm volatile + ("membar #StoreStore | #LoadStore\n" + "stb %%g0, [%0]" + : + : "r" (lock) + : "memory"); + return 0; +} +weak_alias (__pthread_spin_unlock, pthread_spin_unlock) + + +int +__pthread_spin_init (pthread_spinlock_t *lock, int pshared) +{ + /* We can ignore the `pshared' parameter. Since we are busy-waiting + all processes which can access the memory location `lock' points + to can use the spinlock. */ + *lock = 0; + return 0; +} +weak_alias (__pthread_spin_init, pthread_spin_init) + + +int +__pthread_spin_destroy (pthread_spinlock_t *lock) +{ + /* Nothing to do. */ + return 0; +} +weak_alias (__pthread_spin_destroy, pthread_spin_destroy) diff --git a/linuxthreads/sysdeps/sparc/sparc64/Versions b/linuxthreads/sysdeps/sparc/sparc64/Versions new file mode 100644 index 0000000000..32da57080d --- /dev/null +++ b/linuxthreads/sysdeps/sparc/sparc64/Versions @@ -0,0 +1,5 @@ +libpthread { + GLIBC_PRIVATE { + __pthread_clock_gettime; __pthread_clock_settime; + } +} diff --git a/linuxthreads/sysdeps/sparc/sparc64/pspinlock.c b/linuxthreads/sysdeps/sparc/sparc64/pspinlock.c new file mode 100644 index 0000000000..92b84f5108 --- /dev/null +++ b/linuxthreads/sysdeps/sparc/sparc64/pspinlock.c @@ -0,0 +1,93 @@ +/* POSIX spinlock implementation. SPARC64 version. + Copyright (C) 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; 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 "internals.h" + +/* This implementation is similar to the one used in the Linux kernel. */ +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; +} +weak_alias (__pthread_spin_lock, pthread_spin_lock) + + +int +__pthread_spin_trylock (pthread_spinlock_t *lock) +{ + int result; + asm volatile + ("ldstub [%1], %0\n" + "membar #StoreLoad | #StoreStore" + : "=r" (result) + : "r" (lock) + : "memory"); + return result == 0 ? 0 : EBUSY; +} +weak_alias (__pthread_spin_trylock, pthread_spin_trylock) + + +int +__pthread_spin_unlock (pthread_spinlock_t *lock) +{ + asm volatile + ("membar #StoreStore | #LoadStore\n" + "stb %%g0, [%0]" + : + : "r" (lock) + : "memory"); + return 0; +} +weak_alias (__pthread_spin_unlock, pthread_spin_unlock) + + +int +__pthread_spin_init (pthread_spinlock_t *lock, int pshared) +{ + /* We can ignore the `pshared' parameter. Since we are busy-waiting + all processes which can access the memory location `lock' points + to can use the spinlock. */ + *lock = 0; + return 0; +} +weak_alias (__pthread_spin_init, pthread_spin_init) + + +int +__pthread_spin_destroy (pthread_spinlock_t *lock) +{ + /* Nothing to do. */ + return 0; +} +weak_alias (__pthread_spin_destroy, pthread_spin_destroy) diff --git a/linuxthreads/sysdeps/sparc/sparc64/pt-machine.h b/linuxthreads/sysdeps/sparc/sparc64/pt-machine.h new file mode 100644 index 0000000000..f65c13be1b --- /dev/null +++ b/linuxthreads/sysdeps/sparc/sparc64/pt-machine.h @@ -0,0 +1,105 @@ +/* Machine-dependent pthreads configuration and inline functions. + Sparc v9 version. + Copyright (C) 1997-2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Richard Henderson <rth@tamu.edu>. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; 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 _PT_MACHINE_H +#define _PT_MACHINE_H 1 + +#ifndef PT_EI +# define PT_EI extern inline __attribute__ ((always_inline)) +#endif + +extern long int testandset (int *spinlock); +extern int __compare_and_swap (long int *p, long int oldval, long int newval); + +/* Spinlock implementation; required. */ +PT_EI long int +testandset (int *spinlock) +{ + int ret; + + __asm__ __volatile__("ldstub %1,%0" + : "=r" (ret), "=m" (*spinlock) : "m" (*spinlock)); + + return ret; +} + + +/* Memory barrier; default is to do nothing */ +#define MEMORY_BARRIER() \ + __asm__ __volatile__("membar #LoadLoad | #LoadStore | #StoreLoad | #StoreStore" : : : "memory") +/* Read barrier. */ +#define READ_MEMORY_BARRIER() \ + __asm__ __volatile__("membar #LoadLoad | #LoadStore" : : : "memory") +/* Write barrier. */ +#define WRITE_MEMORY_BARRIER() \ + __asm__ __volatile__("membar #StoreLoad | #StoreStore" : : : "memory") + + +/* Get some notion of the current stack. Need not be exactly the top + of the stack, just something somewhere in the current frame. */ +#define CURRENT_STACK_FRAME (stack_pointer + (2 * 128)) +register char *stack_pointer __asm__ ("%sp"); + + +/* Registers %g6 and %g7 are reserved by the ABI for "system use". The + TLS ABI specifies %g7 as the thread pointer. */ +struct _pthread_descr_struct; +register struct _pthread_descr_struct *__thread_self __asm__ ("%g7"); + +/* Return the thread descriptor for the current thread. */ +#define THREAD_SELF __thread_self + +/* Initialize the thread-unique value. */ +#define INIT_THREAD_SELF(descr, nr) (__thread_self = (descr)) + + +/* Compare-and-swap for semaphores. */ + +#define HAS_COMPARE_AND_SWAP +PT_EI int +__compare_and_swap (long int *p, long int oldval, long int newval) +{ + long int readval; + + __asm__ __volatile__ ("casx [%4], %2, %0" + : "=r"(readval), "=m"(*p) + : "r"(oldval), "m"(*p), "r"(p), "0"(newval)); + MEMORY_BARRIER(); + return readval == oldval; +} + +/* Access to data in the thread descriptor is easy. */ +#define THREAD_GETMEM(descr, member) \ + ((void) sizeof (descr), THREAD_SELF->member) +#define THREAD_GETMEM_NC(descr, member) \ + ((void) sizeof (descr), THREAD_SELF->member) +#define THREAD_SETMEM(descr, member, value) \ + ((void) sizeof (descr), THREAD_SELF->member = (value)) +#define THREAD_SETMEM_NC(descr, member, value) \ + ((void) sizeof (descr), THREAD_SELF->member = (value)) + +/* We want the OS to assign stack addresses. */ +#define FLOATING_STACKS 1 + +/* Maximum size of the stack if the rlimit is unlimited. */ +#define ARCH_STACK_MAX_SIZE 32*1024*1024 + +#endif /* pt-machine.h */ diff --git a/linuxthreads/sysdeps/sparc/tcb-offsets.sym b/linuxthreads/sysdeps/sparc/tcb-offsets.sym new file mode 100644 index 0000000000..aee6be2570 --- /dev/null +++ b/linuxthreads/sysdeps/sparc/tcb-offsets.sym @@ -0,0 +1,4 @@ +#include <sysdep.h> +#include <tls.h> + +MULTIPLE_THREADS_OFFSET offsetof (tcbhead_t, multiple_threads) diff --git a/linuxthreads/sysdeps/sparc/tls.h b/linuxthreads/sysdeps/sparc/tls.h new file mode 100644 index 0000000000..6b1966fe1c --- /dev/null +++ b/linuxthreads/sysdeps/sparc/tls.h @@ -0,0 +1,110 @@ +/* Definitions for thread-local data handling. linuxthreads/sparc version. + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _TLS_H +#define _TLS_H + +#ifndef __ASSEMBLER__ + +# include <pt-machine.h> +# include <stddef.h> + +/* Type for the dtv. */ +typedef union dtv +{ + size_t counter; + void *pointer; +} dtv_t; + +typedef struct +{ + void *tcb; /* Pointer to the TCB. Not necessary the + thread descriptor used by libpthread. */ + dtv_t *dtv; + void *self; /* Pointer to the thread descriptor. */ + int multiple_threads; +} tcbhead_t; + +#else /* __ASSEMBLER__ */ +# include <tcb-offsets.h> +#endif /* __ASSEMBLER__ */ + +#ifdef HAVE_TLS_SUPPORT + +/* Signal that TLS support is available. */ +# define USE_TLS 1 + +# ifndef __ASSEMBLER__ +/* Get system call information. */ +# include <sysdep.h> + +/* Get the thread descriptor definition. */ +# include <linuxthreads/descr.h> + +/* This is the size of the initial TCB. */ +# define TLS_INIT_TCB_SIZE sizeof (tcbhead_t) + +/* Alignment requirements for the initial TCB. */ +# define TLS_INIT_TCB_ALIGN __alignof__ (tcbhead_t) + +/* This is the size of the TCB. */ +# define TLS_TCB_SIZE sizeof (struct _pthread_descr_struct) + +/* Alignment requirements for the TCB. */ +# define TLS_TCB_ALIGN __alignof__ (struct _pthread_descr_struct) + +/* 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) + +# endif + +#else + +# define NONTLS_INIT_TP \ + do { \ + static const tcbhead_t nontls_init_tp \ + = { .multiple_threads = 0 }; \ + __thread_self = (__typeof (__thread_self)) &nontls_init_tp; \ + } while (0) + +#endif /* USE_TLS */ + +#endif /* tls.h */ diff --git a/linuxthreads/sysdeps/unix/sysv/linux/Implies b/linuxthreads/sysdeps/unix/sysv/linux/Implies new file mode 100644 index 0000000000..f1b3e8939c --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/Implies @@ -0,0 +1 @@ +pthread diff --git a/linuxthreads/sysdeps/unix/sysv/linux/Makefile b/linuxthreads/sysdeps/unix/sysv/linux/Makefile new file mode 100644 index 0000000000..38c6cbc1af --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/Makefile @@ -0,0 +1,3 @@ +ifeq ($(subdir),linuxthreads) +sysdep_routines += register-atfork unregister-atfork +endif diff --git a/linuxthreads/sysdeps/unix/sysv/linux/Versions b/linuxthreads/sysdeps/unix/sysv/linux/Versions new file mode 100644 index 0000000000..6cd3dbe372 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/Versions @@ -0,0 +1,5 @@ +libc { + GLIBC_2.3.2 { + __register_atfork; + } +} diff --git a/linuxthreads/sysdeps/unix/sysv/linux/allocalim.h b/linuxthreads/sysdeps/unix/sysv/linux/allocalim.h new file mode 100644 index 0000000000..f62f7d6e9f --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/allocalim.h @@ -0,0 +1,26 @@ +/* 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 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 <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/linuxthreads/sysdeps/unix/sysv/linux/allocrtsig.c b/linuxthreads/sysdeps/unix/sysv/linux/allocrtsig.c new file mode 100644 index 0000000000..af1581a4c3 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/allocrtsig.c @@ -0,0 +1,87 @@ +/* Handle real-time signal allocation. + Copyright (C) 1997,98,99,2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 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. */ + +#include <signal.h> + +/* Sanity check. */ +#if !defined __SIGRTMIN || (__SIGRTMAX - __SIGRTMIN) < 3 +# error "This must not happen" +#endif + +static int current_rtmin; +static int current_rtmax; + +static int initialized; + +#include <testrtsig.h> + +static void +init (void) +{ + if (!kernel_has_rtsig ()) + { + current_rtmin = -1; + current_rtmax = -1; + } + else + { + current_rtmin = __SIGRTMIN + 3; + current_rtmax = __SIGRTMAX; + } + initialized = 1; +} + +/* Return number of available real-time signal with highest priority. */ +int +__libc_current_sigrtmin (void) +{ + if (!initialized) + init (); + return current_rtmin; +} +strong_alias (__libc_current_sigrtmin, __libc_current_sigrtmin_private); +libc_hidden_def (__libc_current_sigrtmin) + +/* Return number of available real-time signal with lowest priority. */ +int +__libc_current_sigrtmax (void) +{ + if (!initialized) + init (); + return current_rtmax; +} +strong_alias (__libc_current_sigrtmax, __libc_current_sigrtmax_private); +libc_hidden_def (__libc_current_sigrtmax) + +/* Allocate real-time signal with highest/lowest available + priority. Please note that we don't use a lock since we assume + this function to be called at program start. */ +int +__libc_allocate_rtsig (int high) +{ + if (!initialized) + init (); + if (current_rtmin == -1 || current_rtmin > current_rtmax) + /* We don't have anymore signal available. */ + return -1; + + return high ? current_rtmin++ : current_rtmax--; +} +strong_alias (__libc_allocate_rtsig, __libc_allocate_rtsig_private); diff --git a/linuxthreads/sysdeps/unix/sysv/linux/alpha/Makefile b/linuxthreads/sysdeps/unix/sysv/linux/alpha/Makefile new file mode 100644 index 0000000000..e03aee99fc --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/alpha/Makefile @@ -0,0 +1,3 @@ +ifeq ($(subdir),linuxthreads) +libpthread-routines += ptw-sysdep ptw-sigblock ptw-sigprocmask +endif diff --git a/linuxthreads/sysdeps/unix/sysv/linux/alpha/Versions b/linuxthreads/sysdeps/unix/sysv/linux/alpha/Versions new file mode 100644 index 0000000000..d102772482 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/alpha/Versions @@ -0,0 +1,6 @@ +libpthread { + GLIBC_2.3.3 { + # Changed PTHREAD_STACK_MIN. + pthread_attr_setstack; pthread_attr_setstacksize; + } +} diff --git a/linuxthreads/sysdeps/unix/sysv/linux/alpha/aio_cancel.c b/linuxthreads/sysdeps/unix/sysv/linux/alpha/aio_cancel.c new file mode 100644 index 0000000000..0d6da82919 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/alpha/aio_cancel.c @@ -0,0 +1,33 @@ +#include <shlib-compat.h> + +#define aio_cancel64 XXX +#include <aio.h> +#undef aio_cancel64 +#include <errno.h> + +extern __typeof (aio_cancel) __new_aio_cancel; +extern __typeof (aio_cancel) __old_aio_cancel; + +#define aio_cancel __new_aio_cancel + +#include <sysdeps/pthread/aio_cancel.c> + +#undef aio_cancel +strong_alias (__new_aio_cancel, __new_aio_cancel64); +versioned_symbol (librt, __new_aio_cancel, aio_cancel, GLIBC_2_3); +versioned_symbol (librt, __new_aio_cancel64, aio_cancel64, GLIBC_2_3); + +#if SHLIB_COMPAT (librt, GLIBC_2_1, GLIBC_2_3) + +#undef ECANCELED +#define aio_cancel __old_aio_cancel +#define ECANCELED 125 + +#include <sysdeps/pthread/aio_cancel.c> + +#undef aio_cancel +strong_alias (__old_aio_cancel, __old_aio_cancel64); +compat_symbol (librt, __old_aio_cancel, aio_cancel, GLIBC_2_1); +compat_symbol (librt, __old_aio_cancel64, aio_cancel64, GLIBC_2_1); + +#endif diff --git a/linuxthreads/sysdeps/unix/sysv/linux/alpha/bits/local_lim.h b/linuxthreads/sysdeps/unix/sysv/linux/alpha/bits/local_lim.h new file mode 100644 index 0000000000..96893c59da --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/alpha/bits/local_lim.h @@ -0,0 +1,92 @@ +/* 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 Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General 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 +/* This is the value this implementation supports. */ +#define PTHREAD_THREADS_MAX 16384 + +/* 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 POSIX timers available. */ +#define TIMER_MAX 256 + +/* 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/linuxthreads/sysdeps/unix/sysv/linux/alpha/bits/typesizes.h b/linuxthreads/sysdeps/unix/sysv/linux/alpha/bits/typesizes.h new file mode 100644 index 0000000000..a2724885e2 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/alpha/bits/typesizes.h @@ -0,0 +1,66 @@ +/* bits/typesizes.h -- underlying types for *_t. Linux/Alpha version. + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _BITS_TYPES_H +# error "Never include <bits/typesizes.h> directly; use <sys/types.h> instead." +#endif + +#ifndef _BITS_TYPESIZES_H +#define _BITS_TYPESIZES_H 1 + +/* See <bits/types.h> for the meaning of these macros. This file exists so + that <bits/types.h> need not vary across different GNU platforms. */ + +#define __DEV_T_TYPE __U64_TYPE +#define __UID_T_TYPE __U32_TYPE +#define __GID_T_TYPE __U32_TYPE +#define __INO_T_TYPE __U32_TYPE +#define __INO64_T_TYPE __U64_TYPE +#define __MODE_T_TYPE __U32_TYPE +#define __NLINK_T_TYPE __U32_TYPE +#define __OFF_T_TYPE __SLONGWORD_TYPE +#define __OFF64_T_TYPE __S64_TYPE +#define __PID_T_TYPE __S32_TYPE +#define __RLIM_T_TYPE __ULONGWORD_TYPE +#define __RLIM64_T_TYPE __U64_TYPE +#define __BLKCNT_T_TYPE __U32_TYPE +#define __BLKCNT64_T_TYPE __U64_TYPE +#define __FSBLKCNT_T_TYPE __S32_TYPE +#define __FSBLKCNT64_T_TYPE __S64_TYPE +#define __FSFILCNT_T_TYPE __U32_TYPE +#define __FSFILCNT64_T_TYPE __U64_TYPE +#define __ID_T_TYPE __U32_TYPE +#define __CLOCK_T_TYPE __SLONGWORD_TYPE +#define __TIME_T_TYPE __SLONGWORD_TYPE +#define __USECONDS_T_TYPE __U32_TYPE +#define __SUSECONDS_T_TYPE __S64_TYPE +#define __DADDR_T_TYPE __S32_TYPE +#define __SWBLK_T_TYPE __SLONGWORD_TYPE +#define __KEY_T_TYPE __S32_TYPE +#define __CLOCKID_T_TYPE __S32_TYPE +#define __TIMER_T_TYPE __S32_TYPE +#define __BLKSIZE_T_TYPE __U32_TYPE +#define __FSID_T_TYPE struct { int __val[2]; } +#define __SSIZE_T_TYPE __SWORD_TYPE + +/* Number of descriptors that can fit in an `fd_set'. */ +#define __FD_SETSIZE 1024 + + +#endif /* bits/typesizes.h */ diff --git a/linuxthreads/sysdeps/unix/sysv/linux/alpha/pt-sigsuspend.S b/linuxthreads/sysdeps/unix/sysv/linux/alpha/pt-sigsuspend.S new file mode 100644 index 0000000000..91e5c86782 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/alpha/pt-sigsuspend.S @@ -0,0 +1,28 @@ +/* Internal sigsuspend system call for LinuxThreads. 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 <sysdep.h> + +#undef PSEUDO_PREPARE_ARGS +#define PSEUDO_PREPARE_ARGS ldq a0, 0(a0); + + .hidden __pthread_sigsuspend +PSEUDO_NOERRNO(__pthread_sigsuspend, sigsuspend, 1) + ret +PSEUDO_END_NOERRNO(__pthread_sigsuspend) diff --git a/linuxthreads/sysdeps/unix/sysv/linux/alpha/sysdep-cancel.h b/linuxthreads/sysdeps/unix/sysv/linux/alpha/sysdep-cancel.h new file mode 100644 index 0000000000..9ea779e0d5 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/alpha/sysdep-cancel.h @@ -0,0 +1,146 @@ +/* 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> +#ifndef __ASSEMBLER__ +# include <linuxthreads/internals.h> +#endif + +#if !defined NOT_IN_libc || defined IS_IN_libpthread + +# 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; \ + lda v0, SYS_ify(syscall_name); \ + call_pal PAL_callsys; \ + stq v0, 8(sp); \ + 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 +# else +# define __local_enable_asynccancel __libc_enable_asynccancel +# define __local_disable_asynccancel __libc_disable_asynccancel +# define __local_multiple_threads __libc_multiple_threads +# 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 + +# 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 + +#elif !defined __ASSEMBLER__ + +/* This code should never be used but we define it anyhow. */ +# define SINGLE_THREAD_P (1) + +#endif diff --git a/linuxthreads/sysdeps/unix/sysv/linux/alpha/vfork.S b/linuxthreads/sysdeps/unix/sysv/linux/alpha/vfork.S new file mode 100644 index 0000000000..cfaae10606 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/alpha/vfork.S @@ -0,0 +1,70 @@ +/* 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-cancel.h> + + .align 4 + .globl __vfork + .type __vfork, @function + .usepv __vfork, std + cfi_startproc +__vfork: + ldgp gp, 0(pv) + PSEUDO_PROF + +#ifdef SHARED + ldq t0, __libc_pthread_functions(gp) !gprel + bne t0, HIDDEN_JUMPTARGET (__fork) !samegp +#else + .weak pthread_create + ldq t0, pthread_create(gp) !literal + bne t0, $do_fork +#endif + + lda v0, SYS_ify(vfork) + call_pal PAL_callsys + bne a3, SYSCALL_ERROR_LABEL + ret + +#ifndef SHARED + /* Can't tail-call due to possible mismatch between GP in + fork and vfork object files. */ +$do_fork: + subq sp, 16, sp + cfi_adjust_cfa_offset(16) + stq ra, 0(sp) + cfi_offset(ra, -16) + jsr ra, HIDDEN_JUMPTARGET (__fork) + ldgp gp, 0(ra) + ldq ra, 0(sp) + addq sp, 16, sp + cfi_restore(ra) + cfi_adjust_cfa_offset(-16) + ret + +$syscall_error: + SYSCALL_ERROR_HANDLER +#endif + + cfi_endproc + .size __vfork, .-__vfork + +libc_hidden_def (__vfork) + +weak_alias (__vfork, vfork) diff --git a/linuxthreads/sysdeps/unix/sysv/linux/arm/sysdep-cancel.h b/linuxthreads/sysdeps/unix/sysv/linux/arm/sysdep-cancel.h new file mode 100644 index 0000000000..019bd54913 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/arm/sysdep-cancel.h @@ -0,0 +1,145 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Phil Blundell <pb@nexus.co.uk>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with 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 __ASSEMBLER__ +# include <linuxthreads/internals.h> +#endif + +#if !defined NOT_IN_libc || defined IS_IN_libpthread + +/* We push lr onto the stack, so we have to use ldmib instead of ldmia + to find the saved arguments. */ +# ifdef PIC +# undef DOARGS_5 +# undef DOARGS_6 +# undef DOARGS_7 +# define DOARGS_5 str r4, [sp, $-4]!; ldr r4, [sp, $8]; +# define DOARGS_6 mov ip, sp; stmfd sp!, {r4, r5}; ldmib ip, {r4, r5}; +# define DOARGS_7 mov ip, sp; stmfd sp!, {r4, r5, r6}; ldmib ip, {r4, r5, r6}; +# endif + +# undef PSEUDO_RET +# define PSEUDO_RET \ + ldrcc pc, [sp], $4; \ + ldr lr, [sp], $4; \ + b PLTJMP(SYSCALL_ERROR) + +# undef PSEUDO +# define PSEUDO(name, syscall_name, args) \ + .section ".text"; \ + PSEUDO_PROLOGUE; \ + ENTRY (name); \ + SINGLE_THREAD_P_INT; \ + bne .Lpseudo_cancel; \ + DO_CALL (syscall_name, args); \ + cmn r0, $4096; \ + PSEUDO_RET_MOV; \ + .Lpseudo_cancel: \ + MAYBE_SAVE_LR; \ + DOCARGS_##args; /* save syscall args around CENABLE. */ \ + CENABLE; \ + mov ip, r0; /* put mask in safe place. */ \ + UNDOCARGS_##args; /* restore syscall args. */ \ + swi SYS_ify (syscall_name); /* do the call. */ \ + str r0, [sp, $-4]!; /* save syscall return value. */ \ + mov r0, ip; /* get mask back. */ \ + CDISABLE; \ + ldr r0, [sp], $4; /* retrieve return value. */ \ + UNDOC2ARGS_##args; /* fix register damage. */ \ + cmn r0, $4096; + +# define DOCARGS_0 +# define UNDOCARGS_0 +# define UNDOC2ARGS_0 + +# define DOCARGS_1 str r0, [sp, #-4]!; +# define UNDOCARGS_1 ldr r0, [sp], #4; +# define UNDOC2ARGS_1 + +# define DOCARGS_2 str r1, [sp, #-4]!; str r0, [sp, #-4]!; +# define UNDOCARGS_2 ldr r0, [sp], #4; ldr r1, [sp], #4; +# define UNDOC2ARGS_2 + +# define DOCARGS_3 str r2, [sp, #-4]!; str r1, [sp, #-4]!; str r0, [sp, #-4]!; +# define UNDOCARGS_3 ldr r0, [sp], #4; ldr r1, [sp], #4; ldr r2, [sp], #4 +# define UNDOC2ARGS_3 + +# define DOCARGS_4 stmfd sp!, {r0-r3} +# define UNDOCARGS_4 ldmfd sp!, {r0-r3} +# define UNDOC2ARGS_4 + +# define DOCARGS_5 stmfd sp!, {r0-r3} +# define UNDOCARGS_5 ldmfd sp, {r0-r3}; str r4, [sp, #-4]!; ldr r4, [sp, #24] +# define UNDOC2ARGS_5 ldr r4, [sp], #20 + +# 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 +# else +# define CENABLE bl PLTJMP(__libc_enable_asynccancel) +# define CDISABLE bl PLTJMP(__libc_disable_asynccancel) +# define __local_multiple_threads __libc_multiple_threads +# endif + +# ifndef __ASSEMBLER__ +extern int __local_multiple_threads attribute_hidden; +# define SINGLE_THREAD_P __builtin_expect (__local_multiple_threads == 0, 1) +# else +# if !defined PIC +# define SINGLE_THREAD_P_INT \ + ldr ip, =__local_multiple_threads; \ + ldr ip, [ip]; \ + teq ip, #0; +# define SINGLE_THREAD_P SINGLE_THREAD_P_INT +# define MAYBE_SAVE_LR \ + str lr, [sp, $-4]!; +# define PSEUDO_RET_MOV \ + RETINSTR(cc, lr); \ + b PLTJMP(SYSCALL_ERROR) +# define PSEUDO_PROLOGUE +# else +# define SINGLE_THREAD_P_PIC(reg) \ + ldr ip, 1b; \ + ldr reg, 2b; \ +3: \ + add ip, pc, ip; \ + ldr ip, [ip, reg]; \ + teq ip, #0; +# define SINGLE_THREAD_P_INT \ + str lr, [sp, $-4]!; \ + SINGLE_THREAD_P_PIC(lr) +# define SINGLE_THREAD_P \ + SINGLE_THREAD_P_INT; \ + ldr lr, [sp], $4 +# define PSEUDO_PROLOGUE \ + 1: .word _GLOBAL_OFFSET_TABLE_ - 3f - 8; \ + 2: .word __local_multiple_threads(GOTOFF); +# define MAYBE_SAVE_LR /* lr already saved */ +# define PSEUDO_RET_MOV PSEUDO_RET +# endif +# endif + +#elif !defined __ASSEMBLER__ + +/* This code should never be used but we define it anyhow. */ +# define SINGLE_THREAD_P (1) + +#endif diff --git a/linuxthreads/sysdeps/unix/sysv/linux/arm/vfork.S b/linuxthreads/sysdeps/unix/sysv/linux/arm/vfork.S new file mode 100644 index 0000000000..2708c701eb --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/arm/vfork.S @@ -0,0 +1,80 @@ +/* Copyright (C) 1999, 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Philip Blundell <philb@gnu.org>. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep-cancel.h> +#define _ERRNO_H 1 +#include <bits/errno.h> +#include <kernel-features.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. */ + + PSEUDO_PROLOGUE + +ENTRY (__vfork) + +#ifdef __NR_vfork + +#ifdef SHARED + ldr ip, 1f + ldr r0, 2f +3: add ip, pc, ip + ldr r0, [ip, r0] +#else + ldr r0, 1f +#endif + movs r0, r0 + bne HIDDEN_JUMPTARGET (__fork) + + swi __NR_vfork + cmn a1, #4096 + RETINSTR(cc, lr) + +#ifndef __ASSUME_VFORK_SYSCALL + /* Check if vfork syscall is known at all. */ + cmn a1, #ENOSYS + bne PLTJMP(C_SYMBOL_NAME(__syscall_error)) +#endif + +#endif + +#ifndef __ASSUME_VFORK_SYSCALL + /* If we don't have vfork, fork is close enough. */ + swi __NR_fork + cmn a1, #4096 + RETINSTR(cc, lr) +#elif !defined __NR_vfork +# error "__NR_vfork not available and __ASSUME_VFORK_SYSCALL defined" +#endif + b PLTJMP(C_SYMBOL_NAME(__syscall_error)) + +#ifdef SHARED +1: .word _GLOBAL_OFFSET_TABLE_ - 3b - 8 +2: .word __libc_pthread_functions(GOTOFF) +#else + .weak pthread_create +1: .word pthread_create +#endif + +PSEUDO_END (__vfork) +libc_hidden_def (__vfork) + +weak_alias (__vfork, vfork) diff --git a/linuxthreads/sysdeps/unix/sysv/linux/bits/local_lim.h b/linuxthreads/sysdeps/unix/sysv/linux/bits/local_lim.h new file mode 100644 index 0000000000..ed6c3c589b --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/bits/local_lim.h @@ -0,0 +1,92 @@ +/* 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 +/* This is the value this implementation supports. */ +#define PTHREAD_THREADS_MAX 16384 + +/* 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 POSIX timers available. */ +#define TIMER_MAX 256 + +/* 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/linuxthreads/sysdeps/unix/sysv/linux/bits/posix_opt.h b/linuxthreads/sysdeps/unix/sysv/linux/bits/posix_opt.h new file mode 100644 index 0000000000..71b7e74649 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/bits/posix_opt.h @@ -0,0 +1,181 @@ +/* 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 + +/* X/Open realtime thread support is available. */ +#define _XOPEN_REALTIME_THREADS 1 + +/* XPG4.2 shared memory is supported. */ +#define _XOPEN_SHM 1 + +/* Tell we have POSIX threads. */ +#define _POSIX_THREADS 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, but only the non-shared form for now. */ +#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 not supported. */ +#define _POSIX_THREAD_PROCESS_SHARED -1 + +/* The monotonic clock might be available. */ +#define _POSIX_MONOTONIC_CLOCK 0 + +/* The clock selection interfaces are not available. */ +#define _POSIX_CLOCK_SELECTION -1 + +/* 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. */ +#define _POSIX_THREAD_PRIO_INHERIT -1 +#define _POSIX_THREAD_PRIO_PROTECT -1 + +#endif /* posix_opt.h */ diff --git a/linuxthreads/sysdeps/unix/sysv/linux/bits/sigthread.h b/linuxthreads/sysdeps/unix/sysv/linux/bits/sigthread.h new file mode 100644 index 0000000000..960bde18a9 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/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/linuxthreads/sysdeps/unix/sysv/linux/execve.c b/linuxthreads/sysdeps/unix/sysv/linux/execve.c new file mode 100644 index 0000000000..9fa912b90d --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/execve.c @@ -0,0 +1,73 @@ +/* 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; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <unistd.h> + +#include <sysdep.h> +#include <alloca.h> +#include <sys/syscall.h> +#include <bp-checks.h> + +extern int __syscall_execve (const char *__unbounded file, + char *__unbounded const *__unbounded argv, + char *__unbounded const *__unbounded envp); +extern void __pthread_kill_other_threads_np (void); +weak_extern (__pthread_kill_other_threads_np) + + +int +__execve (file, argv, envp) + const char *file; + char *const argv[]; + char *const envp[]; +{ + /* If this is a threaded application kill all other threads. */ + if (__pthread_kill_other_threads_np) + __pthread_kill_other_threads_np (); +#if __BOUNDED_POINTERS__ + { + char *const *v; + int i; + char *__unbounded *__unbounded ubp_argv; + char *__unbounded *__unbounded ubp_envp; + char *__unbounded *__unbounded ubp_v; + + for (v = argv; *v; v++) + ; + i = v - argv + 1; + ubp_argv = (char *__unbounded *__unbounded) alloca (sizeof (*ubp_argv) * i); + for (v = argv, ubp_v = ubp_argv; --i; v++, ubp_v++) + *ubp_v = CHECK_STRING (*v); + *ubp_v = 0; + + for (v = envp; *v; v++) + ; + i = v - envp + 1; + ubp_envp = (char *__unbounded *__unbounded) alloca (sizeof (*ubp_envp) * i); + for (v = envp, ubp_v = ubp_envp; --i; v++, ubp_v++) + *ubp_v = CHECK_STRING (*v); + *ubp_v = 0; + + return INLINE_SYSCALL (execve, 3, CHECK_STRING (file), ubp_argv, ubp_envp); + } +#else + return INLINE_SYSCALL (execve, 3, file, argv, envp); +#endif +} +weak_alias (__execve, execve) diff --git a/linuxthreads/sysdeps/unix/sysv/linux/fork.c b/linuxthreads/sysdeps/unix/sysv/linux/fork.c new file mode 100644 index 0000000000..00eb787093 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/fork.c @@ -0,0 +1,43 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <fork.h> +#include <bits/libc-lock.h> + +#ifndef SHARED +weak_extern (__pthread_fork); +#endif + +struct fork_block __fork_block = +{ + .lock = PTHREAD_MUTEX_INITIALIZER, + .prepare_list = { &__fork_block.prepare_list, &__fork_block.prepare_list }, + .parent_list = { &__fork_block.parent_list, &__fork_block.parent_list }, + .child_list = { &__fork_block.child_list, &__fork_block.child_list } +}; + +pid_t +__libc_fork (void) +{ + return __libc_maybe_call2 (pthread_fork, (&__fork_block), ARCH_FORK ()); +} +weak_alias (__libc_fork, __fork) +libc_hidden_def (__fork) +weak_alias (__libc_fork, fork) diff --git a/linuxthreads/sysdeps/unix/sysv/linux/fork.h b/linuxthreads/sysdeps/unix/sysv/linux/fork.h new file mode 100644 index 0000000000..76708e3e39 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/fork.h @@ -0,0 +1,60 @@ +/* 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 <list.h> +#include <bits/libc-lock.h> +#include <sysdep.h> + +struct fork_block +{ + /* Lock to protect handling of fork handlers. */ + __libc_lock_define (, lock); + + /* Lists of registered fork handlers. */ + list_t prepare_list; + list_t parent_list; + list_t child_list; +}; + +extern struct fork_block __fork_block attribute_hidden; + +/* Elements of the fork handler lists. */ +struct fork_handler +{ + list_t list; + void (*handler) (void); + void *dso_handle; +}; + + +/* Function to call to unregister fork handlers. */ +extern void __unregister_atfork (void *dso_handle) attribute_hidden; +#define UNREGISTER_ATFORK(dso_handle) __unregister_atfork (dso_handle) + + +/* C library side function to register new fork handlers. */ +extern int __register_atfork (void (*__prepare) (void), + void (*__parent) (void), + void (*__child) (void), + void *dso_handle); +libc_hidden_proto (__register_atfork) + +#ifndef ARCH_FORK +# define ARCH_FORK() INLINE_SYSCALL (fork, 0) +#endif diff --git a/linuxthreads/sysdeps/unix/sysv/linux/hppa/aio_cancel.c b/linuxthreads/sysdeps/unix/sysv/linux/hppa/aio_cancel.c new file mode 100644 index 0000000000..0d6da82919 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/hppa/aio_cancel.c @@ -0,0 +1,33 @@ +#include <shlib-compat.h> + +#define aio_cancel64 XXX +#include <aio.h> +#undef aio_cancel64 +#include <errno.h> + +extern __typeof (aio_cancel) __new_aio_cancel; +extern __typeof (aio_cancel) __old_aio_cancel; + +#define aio_cancel __new_aio_cancel + +#include <sysdeps/pthread/aio_cancel.c> + +#undef aio_cancel +strong_alias (__new_aio_cancel, __new_aio_cancel64); +versioned_symbol (librt, __new_aio_cancel, aio_cancel, GLIBC_2_3); +versioned_symbol (librt, __new_aio_cancel64, aio_cancel64, GLIBC_2_3); + +#if SHLIB_COMPAT (librt, GLIBC_2_1, GLIBC_2_3) + +#undef ECANCELED +#define aio_cancel __old_aio_cancel +#define ECANCELED 125 + +#include <sysdeps/pthread/aio_cancel.c> + +#undef aio_cancel +strong_alias (__old_aio_cancel, __old_aio_cancel64); +compat_symbol (librt, __old_aio_cancel, aio_cancel, GLIBC_2_1); +compat_symbol (librt, __old_aio_cancel64, aio_cancel64, GLIBC_2_1); + +#endif diff --git a/linuxthreads/sysdeps/unix/sysv/linux/hppa/bits/initspin.h b/linuxthreads/sysdeps/unix/sysv/linux/hppa/bits/initspin.h new file mode 100644 index 0000000000..9b13400286 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/hppa/bits/initspin.h @@ -0,0 +1,27 @@ +/* PA-RISC specific definitions for spinlock initializers. + Copyright (C) 2000, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* Initial value of a spinlock. PA-RISC only implements atomic load + and clear so this must be non-zero. */ +#define __LT_SPINLOCK_INIT 1 + +/* Macros for lock initializers, using the above definition. */ +#define __LOCK_INITIALIZER { 0, __LT_SPINLOCK_INIT } +#define __ALT_LOCK_INITIALIZER { 0, __LT_SPINLOCK_INIT } +#define __ATOMIC_INITIALIZER { 0, __LT_SPINLOCK_INIT } diff --git a/linuxthreads/sysdeps/unix/sysv/linux/hppa/malloc-machine.h b/linuxthreads/sysdeps/unix/sysv/linux/hppa/malloc-machine.h new file mode 100644 index 0000000000..817cf59222 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/hppa/malloc-machine.h @@ -0,0 +1,73 @@ +/* HP-PARISC 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. + Contributed by Carlos O'Donell <carlos@baldric.uwo.ca>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along 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) + +/* Since our lock structure does not tolerate being initialized to zero, we must + modify the standard function calls made by malloc */ +# define mutex_init(m) \ + __libc_maybe_call (__pthread_mutex_init, (m, NULL), \ + (((m)->__m_lock.__spinlock = __LT_SPINLOCK_INIT),(*(int *)(m))) ) +# define mutex_lock(m) \ + __libc_maybe_call (__pthread_mutex_lock, (m), \ + (__load_and_clear(&((m)->__m_lock.__spinlock)), 0)) +# define mutex_trylock(m) \ + __libc_maybe_call (__pthread_mutex_trylock, (m), \ + (*(int *)(m) ? 1 : (__load_and_clear(&((m)->__m_lock.__spinlock)), 0))) +# define mutex_unlock(m) \ + __libc_maybe_call (__pthread_mutex_unlock, (m), \ + (((m)->__m_lock.__spinlock = __LT_SPINLOCK_INIT), (*(int *)(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/linuxthreads/sysdeps/unix/sysv/linux/hppa/pt-initfini.c b/linuxthreads/sysdeps/unix/sysv/linux/hppa/pt-initfini.c new file mode 100644 index 0000000000..27f850cf8f --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/hppa/pt-initfini.c @@ -0,0 +1,109 @@ +/* Special .init and .fini section support for HPPA. Linuxthreads version. + Copyright (C) 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. + + 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 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.) + + The GNU C Library is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General 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. */ + +/* If we use the standard C version, the linkage table pointer won't + be properly preserved due to the splitting up of function prologues + and epilogues. Therefore we write these in assembly to make sure + they do the right thing. */ + +__asm__ ( +"#include \"defs.h\"\n" +"\n" +"/*@HEADER_ENDS*/\n" +"\n" +"/*@_init_PROLOG_BEGINS*/\n" +" .section .init\n" +" .align 4\n" +" .globl _init\n" +" .type _init,@function\n" +"_init:\n" +" stw %rp,-20(%sp)\n" +" stwm %r4,64(%sp)\n" +" stw %r19,-32(%sp)\n" +" bl __pthread_initialize_minimal,%rp\n" +" copy %r19,%r4 /* delay slot */\n" +" copy %r4,%r19\n" +"/*@_init_PROLOG_ENDS*/\n" +"\n" +"/*@_init_EPILOG_BEGINS*/\n" +"/* Here is the tail end of _init. */\n" +" .section .init\n" +" ldw -84(%sp),%rp\n" +" copy %r4,%r19\n" +" bv %r0(%rp)\n" +"_end_init:\n" +" ldwm -64(%sp),%r4\n" +"\n" +"/* Our very own unwind info, because the assembler can't handle\n" +" functions split into two or more pieces. */\n" +" .section .PARISC.unwind,\"a\",@progbits\n" +" .extern _init\n" +" .word _init, _end_init\n" +" .byte 0x08, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08\n" +"\n" +"/*@_init_EPILOG_ENDS*/\n" +"\n" +"/*@_fini_PROLOG_BEGINS*/\n" +" .section .fini\n" +" .align 4\n" +" .globl _fini\n" +" .type _fini,@function\n" +"_fini:\n" +" stw %rp,-20(%sp)\n" +" stwm %r4,64(%sp)\n" +" stw %r19,-32(%sp)\n" +" copy %r19,%r4\n" +"/*@_fini_PROLOG_ENDS*/\n" +"\n" +"/*@_fini_EPILOG_BEGINS*/\n" +" .section .fini\n" +" ldw -84(%sp),%rp\n" +" copy %r4,%r19\n" +" bv %r0(%rp)\n" +"_end_fini:\n" +" ldwm -64(%sp),%r4\n" +"\n" +" .section .PARISC.unwind,\"a\",@progbits\n" +" .extern _fini\n" +" .word _fini, _end_fini\n" +" .byte 0x08, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08\n" +"\n" +"/*@_fini_EPILOG_ENDS*/\n" +"\n" +"/*@TRAILER_BEGINS*/\n" +); diff --git a/linuxthreads/sysdeps/unix/sysv/linux/hppa/sysdep-cancel.h b/linuxthreads/sysdeps/unix/sysv/linux/hppa/sysdep-cancel.h new file mode 100644 index 0000000000..134977e074 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/hppa/sysdep-cancel.h @@ -0,0 +1,189 @@ +/* cancellable system calls for Linux/HPPA. + Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Carlos O'Donell <carlos@baldric.uwo.ca>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with 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 __ASSEMBLER__ +# include <linuxthreads/internals.h> +#endif + +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt + +# ifndef NO_ERROR +# define NO_ERROR -0x1000 +# endif + +# undef PSEUDO +# define PSEUDO(name, syscall_name, args) \ + ENTRY (name) \ + SINGLE_THREAD_P ASM_LINE_SEP \ + cmpib,<> 0,%ret0,Lpseudo_cancel ASM_LINE_SEP \ + nop ASM_LINE_SEP \ + DO_CALL(syscall_name, args) ASM_LINE_SEP \ + /* DONE! */ ASM_LINE_SEP \ + bv 0(2) ASM_LINE_SEP \ + nop ASM_LINE_SEP \ + Lpseudo_cancel: ASM_LINE_SEP \ + /* store return ptr */ ASM_LINE_SEP \ + stw %rp, -20(%sr0,%sp) ASM_LINE_SEP \ + /* save syscall args */ ASM_LINE_SEP \ + PUSHARGS_##args /* MACRO */ ASM_LINE_SEP \ + STW_PIC ASM_LINE_SEP \ + CENABLE /* FUNC CALL */ ASM_LINE_SEP \ + ldo 64(%sp), %sp ASM_LINE_SEP \ + ldo -64(%sp), %sp ASM_LINE_SEP \ + LDW_PIC ASM_LINE_SEP \ + /* restore syscall args */ ASM_LINE_SEP \ + POPARGS_##args ASM_LINE_SEP \ + /* save r4 in arg0 stack slot */ ASM_LINE_SEP \ + stw %r4, -36(%sr0,%sp) ASM_LINE_SEP \ + /* save mask from cenable */ ASM_LINE_SEP \ + copy %ret0, %r4 ASM_LINE_SEP \ + ble 0x100(%sr2,%r0) ASM_LINE_SEP \ + ldi SYS_ify (syscall_name), %r20 ASM_LINE_SEP \ + LDW_PIC ASM_LINE_SEP \ + /* pass mask as arg0 to cdisable */ ASM_LINE_SEP \ + copy %r4, %r26 ASM_LINE_SEP \ + copy %ret0, %r4 ASM_LINE_SEP \ + CDISABLE ASM_LINE_SEP \ + ldo 64(%sp), %sp ASM_LINE_SEP \ + ldo -64(%sp), %sp ASM_LINE_SEP \ + LDW_PIC ASM_LINE_SEP \ + /* compare error */ ASM_LINE_SEP \ + ldi NO_ERROR,%r1 ASM_LINE_SEP \ + /* branch if no error */ ASM_LINE_SEP \ + cmpb,>>=,n %r1,%r4,Lpre_end ASM_LINE_SEP \ + nop ASM_LINE_SEP \ + SYSCALL_ERROR_HANDLER ASM_LINE_SEP \ + ldo 64(%sp), %sp ASM_LINE_SEP \ + ldo -64(%sp), %sp ASM_LINE_SEP \ + /* No need to LDW_PIC */ ASM_LINE_SEP \ + /* make syscall res value positive */ ASM_LINE_SEP \ + sub %r0, %r4, %r4 ASM_LINE_SEP \ + /* store into errno location */ ASM_LINE_SEP \ + stw %r4, 0(%sr0,%ret0) ASM_LINE_SEP \ + /* return -1 */ ASM_LINE_SEP \ + ldo -1(%r0), %ret0 ASM_LINE_SEP \ + Lpre_end: ASM_LINE_SEP \ + ldw -20(%sr0,%sp), %rp ASM_LINE_SEP \ + /* No need to LDW_PIC */ ASM_LINE_SEP \ + ldw -36(%sr0,%sp), %r4 ASM_LINE_SEP + +/* Save arguments into our frame */ +# define PUSHARGS_0 /* nothing to do */ +# define PUSHARGS_1 PUSHARGS_0 stw %r26, -36(%sr0,%sp) ASM_LINE_SEP +# define PUSHARGS_2 PUSHARGS_1 stw %r25, -40(%sr0,%sp) ASM_LINE_SEP +# define PUSHARGS_3 PUSHARGS_2 stw %r24, -44(%sr0,%sp) ASM_LINE_SEP +# define PUSHARGS_4 PUSHARGS_3 stw %r23, -48(%sr0,%sp) ASM_LINE_SEP +# define PUSHARGS_5 PUSHARGS_4 /* Args are on the stack... */ +# define PUSHARGS_6 PUSHARGS_5 + +/* Bring them back from the stack */ +# define POPARGS_0 /* nothing to do */ +# define POPARGS_1 POPARGS_0 ldw -36(%sr0,%sp), %r26 ASM_LINE_SEP +# define POPARGS_2 POPARGS_1 ldw -40(%sr0,%sp), %r25 ASM_LINE_SEP +# define POPARGS_3 POPARGS_2 ldw -44(%sr0,%sp), %r24 ASM_LINE_SEP +# define POPARGS_4 POPARGS_3 ldw -48(%sr0,%sp), %r23 ASM_LINE_SEP +# define POPARGS_5 POPARGS_4 ldw -52(%sr0,%sp), %r22 ASM_LINE_SEP +# define POPARGS_6 POPARGS_5 ldw -54(%sr0,%sp), %r21 ASM_LINE_SEP + +# ifdef IS_IN_libpthread +# ifdef PIC +# define CENABLE .import __pthread_enable_asynccancel,code ASM_LINE_SEP \ + bl __pthread_enable_asynccancel,%r2 ASM_LINE_SEP +# define CDISABLE .import __pthread_disable_asynccancel,code ASM_LINE_SEP \ + bl __pthread_disable_asynccancel,%r2 ASM_LINE_SEP +# else +# define CENABLE .import __pthread_enable_asynccancel,code ASM_LINE_SEP \ + bl __pthread_enable_asynccancel,%r2 ASM_LINE_SEP +# define CDISABLE .import __pthread_disable_asynccancel,code ASM_LINE_SEP \ + bl __pthread_disable_asynccancel,%r2 ASM_LINE_SEP +# endif +# elif !defined NOT_IN_libc +# ifdef PIC +# define CENABLE .import __libc_enable_asynccancel,code ASM_LINE_SEP \ + bl __libc_enable_asynccancel,%r2 ASM_LINE_SEP +# define CDISABLE .import __libc_disable_asynccancel,code ASM_LINE_SEP \ + bl __libc_disable_asynccancel,%r2 ASM_LINE_SEP +# else +# define CENABLE .import __libc_enable_asynccancel,code ASM_LINE_SEP \ + bl __libc_enable_asynccancel,%r2 ASM_LINE_SEP +# define CDISABLE .import __libc_disable_asynccancel,code ASM_LINE_SEP \ + bl __libc_disable_asynccancel,%r2 ASM_LINE_SEP +# endif +# else +# ifdef PIC +# define CENABLE .import __librt_enable_asynccancel,code ASM_LINE_SEP \ + bl __librt_enable_asynccancel,%r2 ASM_LINE_SEP +# define CDISABLE .import __librt_disable_asynccancel,code ASM_LINE_SEP \ + bl __librt_disable_asynccancel,%r2 ASM_LINE_SEP +# else +# define CENABLE .import __librt_enable_asynccancel,code ASM_LINE_SEP \ + bl __librt_enable_asynccancel,%r2 ASM_LINE_SEP +# define CDISABLE .import __librt_disable_asynccancel,code ASM_LINE_SEP \ + bl __librt_disable_asynccancel,%r2 ASM_LINE_SEP +# endif +# endif + +/* p_header.multiple_threads is +12 from the pthread_descr struct start, + We could have called __get_cr27() but we really want less overhead */ +# define MULTIPLE_THREADS_OFFSET 0xC + +/* cr27 has been initialized to 0x0 by kernel */ +# define NO_THREAD_CR27 0x0 + +# ifdef IS_IN_libpthread +# define __local_multiple_threads __pthread_multiple_threads +# elif !defined NOT_IN_libc +# define __local_multiple_threads __libc_multiple_threads +# else +# define __local_multiple_threads __librt_multiple_threads +# endif + +# ifndef __ASSEMBLER__ + extern int __local_multiple_threads attribute_hidden; +# define SINGLE_THREAD_P __builtin_expect (__local_multiple_threads == 0, 1) +# else +/* This ALT version requires newer kernel support */ +# define SINGLE_THREAD_P_MFCTL \ + mfctl %cr27, %ret0 ASM_LINE_SEP \ + cmpib,= NO_THREAD_CR27,%ret0,Lstp ASM_LINE_SEP \ + nop ASM_LINE_SEP \ + ldw MULTIPLE_THREADS_OFFSET(%sr0,%ret0),%ret0 ASM_LINE_SEP \ + Lstp: ASM_LINE_SEP +# ifdef PIC +/* Slower version uses GOT to get value of __local_multiple_threads */ +# define SINGLE_THREAD_P \ + addil LT%__local_multiple_threads, %r19 ASM_LINE_SEP \ + ldw RT%__local_multiple_threads(%sr0,%r1), %ret0 ASM_LINE_SEP \ + ldw 0(%sr0,%ret0), %ret0 ASM_LINE_SEP +# else + /* Slow non-pic version using DP */ +# define SINGLE_THREAD_P \ + addil LR%__local_multiple_threads-$global$,%r27 ASM_LINE_SEP \ + ldw RR%__local_multiple_threads-$global$(%sr0,%r1),%ret0 ASM_LINE_SEP +# endif +# endif +#elif !defined __ASSEMBLER__ + +/* This code should never be used but we define it anyhow. */ +# define SINGLE_THREAD_P (1) + +#endif +/* !defined NOT_IN_libc || defined IS_IN_libpthread */ diff --git a/linuxthreads/sysdeps/unix/sysv/linux/i386/dl-sysdep.h b/linuxthreads/sysdeps/unix/sysv/linux/i386/dl-sysdep.h new file mode 100644 index 0000000000..5355310ccd --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/i386/dl-sysdep.h @@ -0,0 +1,64 @@ +/* System-specific settings for dynamic linker code. IA-32 version. + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _DL_SYSDEP_H +#define _DL_SYSDEP_H 1 + +/* This macro must be defined to either 0 or 1. + + If 1, then an errno global variable hidden in ld.so will work right with + all the errno-using libc code compiled for ld.so, and there is never a + need to share the errno location with libc. This is appropriate only if + all the libc functions that ld.so uses are called without PLT and always + get the versions linked into ld.so rather than the libc ones. */ + +#ifdef IS_IN_rtld +# define RTLD_PRIVATE_ERRNO 1 +#else +# define RTLD_PRIVATE_ERRNO 0 +#endif + +/* Traditionally system calls have been made using int $0x80. A + second method was introduced which, if possible, will use the + sysenter/syscall instructions. To signal the presence and where to + find the code the kernel passes an AT_SYSINFO value in the + auxiliary vector to the application. + sysenter/syscall is not useful on i386 through i586, but the dynamic + linker and dl code in libc.a has to be able to load i686 compiled + libraries. */ +#define NEED_DL_SYSINFO 1 +#undef USE_DL_SYSINFO + +#if defined NEED_DL_SYSINFO && !defined __ASSEMBLER__ +extern void _dl_sysinfo_int80 (void) attribute_hidden; +# define DL_SYSINFO_DEFAULT (uintptr_t) _dl_sysinfo_int80 +# define DL_SYSINFO_IMPLEMENTATION \ + asm (".text\n\t" \ + ".type _dl_sysinfo_int80,@function\n\t" \ + ".hidden _dl_sysinfo_int80\n" \ + CFI_STARTPROC "\n" \ + "_dl_sysinfo_int80:\n\t" \ + "int $0x80;\n\t" \ + "ret;\n\t" \ + CFI_ENDPROC "\n" \ + ".size _dl_sysinfo_int80,.-_dl_sysinfo_int80\n\t" \ + ".previous"); +#endif + +#endif /* dl-sysdep.h */ diff --git a/linuxthreads/sysdeps/unix/sysv/linux/i386/sysdep-cancel.h b/linuxthreads/sysdeps/unix/sysv/linux/i386/sysdep-cancel.h new file mode 100644 index 0000000000..7865f7165e --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/i386/sysdep-cancel.h @@ -0,0 +1,179 @@ +/* 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 <sysdep.h> +#include <tls.h> +#include <pt-machine.h> +#ifndef __ASSEMBLER__ +# include <linuxthreads/internals.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) \ + SINGLE_THREAD_P; \ + jne L(pseudo_cancel); \ + DO_CALL (syscall_name, args); \ + cmpl $-4095, %eax; \ + jae SYSCALL_ERROR_LABEL; \ + ret; \ + L(pseudo_cancel): \ + CENABLE \ + SAVE_OLDTYPE_##args \ + PUSHCARGS_##args \ + DOCARGS_##args \ + movl $SYS_ify (syscall_name), %eax; \ + int $0x80 \ + 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; +# 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; PUSHCARGS_0 +# define DOCARGS_1 _DOARGS_1 (4) +# define POPCARGS_1 POPCARGS_0; movl %edx, %ebx +# define _PUSHCARGS_1 pushl %ebx; L(PUSHBX2): _PUSHCARGS_0 +# define _POPCARGS_1 _POPCARGS_0; popl %ebx; L(POPBX2): + +# 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; L(PUSHSI2): _PUSHCARGS_3 +# define _POPCARGS_4 _POPCARGS_3; popl %esi; L(POPSI2): + +# define PUSHCARGS_5 _PUSHCARGS_5 +# define DOCARGS_5 _DOARGS_5 (36) +# define POPCARGS_5 _POPCARGS_5 +# define _PUSHCARGS_5 pushl %edi; L(PUSHDI2): _PUSHCARGS_4 +# define _POPCARGS_5 _POPCARGS_4; popl %edi; L(POPDI2): + +# ifdef IS_IN_libpthread +# define CENABLE call __pthread_enable_asynccancel; +# define CDISABLE call __pthread_disable_asynccancel +# elif defined IS_IN_librt +# ifdef PIC +# define CENABLE pushl %ebx; \ + call __i686.get_pc_thunk.bx; \ + addl $_GLOBAL_OFFSET_TABLE_, %ebx; \ + call __librt_enable_asynccancel@PLT; \ + popl %ebx; +# define CDISABLE pushl %ebx; \ + call __i686.get_pc_thunk.bx; \ + addl $_GLOBAL_OFFSET_TABLE_, %ebx; \ + call __librt_disable_asynccancel@PLT; \ + popl %ebx; +# else +# define CENABLE call __librt_enable_asynccancel; +# define CDISABLE call __librt_disable_asynccancel +# endif +# else +# define CENABLE call __libc_enable_asynccancel; +# define CDISABLE call __libc_disable_asynccancel +# endif +# define POPSTATE_0 pushl %eax; movl %ecx, %eax; CDISABLE; popl %eax; +# define POPSTATE_1 POPSTATE_0 +# define POPSTATE_2 xchgl (%esp), %eax; CDISABLE; popl %eax; +# define POPSTATE_3 POPSTATE_2 +# define POPSTATE_4 POPSTATE_2 +# define POPSTATE_5 POPSTATE_2 + +#if !defined NOT_IN_libc +# define __local_multiple_threads __libc_multiple_threads +#elif defined IS_IN_libpthread +# define __local_multiple_threads __pthread_multiple_threads +#else +# define __local_multiple_threads __librt_multiple_threads +#endif + +# ifndef __ASSEMBLER__ +# if defined FLOATING_STACKS && USE___THREAD && defined PIC +# define SINGLE_THREAD_P \ + __builtin_expect (THREAD_GETMEM (THREAD_SELF, \ + p_header.data.multiple_threads) == 0, 1) +# else +extern int __local_multiple_threads +# if !defined NOT_IN_libc || defined IS_IN_libpthread + attribute_hidden; +# else + ; +# endif +# define SINGLE_THREAD_P __builtin_expect (__local_multiple_threads == 0, 1) +# endif +# else +# if !defined PIC +# define SINGLE_THREAD_P cmpl $0, __local_multiple_threads +# elif defined FLOATING_STACKS && USE___THREAD +# define SINGLE_THREAD_P cmpl $0, %gs:MULTIPLE_THREADS_OFFSET +# else +# if !defined NOT_IN_libc || defined IS_IN_libpthread +# define __SINGLE_THREAD_CMP cmpl $0, __local_multiple_threads@GOTOFF(%ecx) +# else +# define __SINGLE_THREAD_CMP \ + movl __local_multiple_threads@GOT(%ecx), %ecx;\ + cmpl $0, (%ecx) +# endif +# if !defined HAVE_HIDDEN || !USE___THREAD +# define SINGLE_THREAD_P \ + SETUP_PIC_REG (cx); \ + addl $_GLOBAL_OFFSET_TABLE_, %ecx; \ + __SINGLE_THREAD_CMP +# else +# define SINGLE_THREAD_P \ + call __i686.get_pc_thunk.cx; \ + addl $_GLOBAL_OFFSET_TABLE_, %ecx; \ + __SINGLE_THREAD_CMP +# endif +# endif +# endif + +#elif !defined __ASSEMBLER__ + +/* This code should never be used but we define it anyhow. */ +# define SINGLE_THREAD_P (1) + +#endif diff --git a/linuxthreads/sysdeps/unix/sysv/linux/i386/vfork.S b/linuxthreads/sysdeps/unix/sysv/linux/i386/vfork.S new file mode 100644 index 0000000000..c7a120d239 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/i386/vfork.S @@ -0,0 +1,95 @@ +/* Copyright (C) 1999, 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Andreas Schwab <schwab@gnu.org>. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep-cancel.h> +#define _ERRNO_H 1 +#include <bits/errno.h> +#include <kernel-features.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) + +#ifdef __NR_vfork + +# ifdef SHARED +# if !defined HAVE_HIDDEN || !USE___THREAD + SETUP_PIC_REG (cx) +# else + call __i686.get_pc_thunk.cx +# endif + addl $_GLOBAL_OFFSET_TABLE_, %ecx + cmpl $0, __libc_pthread_functions@GOTOFF(%ecx) +# else + .weak pthread_create + movl $pthread_create, %eax + testl %eax, %eax +# endif + jne HIDDEN_JUMPTARGET (__fork) + + /* Pop the return PC value into ECX. */ + popl %ecx + + /* Stuff the syscall number in EAX and enter into the kernel. */ + movl $SYS_ify (vfork), %eax + int $0x80 + + /* Jump to the return PC. Don't jump directly since this + disturbs the branch target cache. Instead push the return + address back on the stack. */ + pushl %ecx + + cmpl $-4095, %eax + /* Branch forward if it failed. */ +# ifdef __ASSUME_VFORK_SYSCALL + jae SYSCALL_ERROR_LABEL +.Lpseudo_end: +# else + jae .Lerror +# endif + + ret + +# ifndef __ASSUME_VFORK_SYSCALL +.Lerror: + /* Check if vfork syscall is known at all. */ + cmpl $-ENOSYS, %eax + jne SYSCALL_ERROR_LABEL +# endif +#endif + +#ifndef __ASSUME_VFORK_SYSCALL + /* If we don't have vfork, fork is close enough. */ + + movl $SYS_ify (fork), %eax + int $0x80 + cmpl $-4095, %eax + jae SYSCALL_ERROR_LABEL +.Lpseudo_end: + ret +#elif !defined __NR_vfork +# error "__NR_vfork not available and __ASSUME_VFORK_SYSCALL defined" +#endif +PSEUDO_END (__vfork) +libc_hidden_def (__vfork) + +weak_alias (__vfork, vfork) diff --git a/linuxthreads/sysdeps/unix/sysv/linux/ia64/Makefile b/linuxthreads/sysdeps/unix/sysv/linux/ia64/Makefile new file mode 100644 index 0000000000..e03aee99fc --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/ia64/Makefile @@ -0,0 +1,3 @@ +ifeq ($(subdir),linuxthreads) +libpthread-routines += ptw-sysdep ptw-sigblock ptw-sigprocmask +endif diff --git a/linuxthreads/sysdeps/unix/sysv/linux/ia64/Versions b/linuxthreads/sysdeps/unix/sysv/linux/ia64/Versions new file mode 100644 index 0000000000..d102772482 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/ia64/Versions @@ -0,0 +1,6 @@ +libpthread { + GLIBC_2.3.3 { + # Changed PTHREAD_STACK_MIN. + pthread_attr_setstack; pthread_attr_setstacksize; + } +} diff --git a/linuxthreads/sysdeps/unix/sysv/linux/ia64/bits/local_lim.h b/linuxthreads/sysdeps/unix/sysv/linux/ia64/bits/local_lim.h new file mode 100644 index 0000000000..629b1f89c1 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/ia64/bits/local_lim.h @@ -0,0 +1,92 @@ +/* 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 Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General 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 +/* This is the value this implementation supports. */ +#define PTHREAD_THREADS_MAX 16384 + +/* 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 196608 + +/* Maximum number of POSIX timers available. */ +#define TIMER_MAX 256 + +/* 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/linuxthreads/sysdeps/unix/sysv/linux/ia64/dl-sysdep.h b/linuxthreads/sysdeps/unix/sysv/linux/ia64/dl-sysdep.h new file mode 100644 index 0000000000..27d5fdfbf5 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/ia64/dl-sysdep.h @@ -0,0 +1,49 @@ +/* System-specific settings for dynamic linker code. IA-64 version. + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _DL_SYSDEP_H +#define _DL_SYSDEP_H 1 + +#define NEED_DL_SYSINFO 1 +#undef USE_DL_SYSINFO + +#if defined NEED_DL_SYSINFO && !defined __ASSEMBLER__ +/* Don't declare this as a function---we want it's entry-point, not + it's function descriptor... */ +extern int _dl_sysinfo_break attribute_hidden; +# define DL_SYSINFO_DEFAULT ((uintptr_t) &_dl_sysinfo_break) +# define DL_SYSINFO_IMPLEMENTATION \ + asm (".text\n\t" \ + ".hidden _dl_sysinfo_break\n\t" \ + ".proc _dl_sysinfo_break\n\t" \ + "_dl_sysinfo_break:\n\t" \ + ".prologue\n\t" \ + ".altrp b6\n\t" \ + ".body\n\t" \ + "break 0x100000;\n\t" \ + "br.ret.sptk.many b6;\n\t" \ + ".endp _dl_sysinfo_break" \ + ".previous"); +#endif + +/* _dl_argv cannot be attribute_relro, because _dl_start_user + might write into it after _dl_start returns. */ +#define DL_ARGV_NOT_RELRO 1 + +#endif /* dl-sysdep.h */ diff --git a/linuxthreads/sysdeps/unix/sysv/linux/ia64/fork.h b/linuxthreads/sysdeps/unix/sysv/linux/ia64/fork.h new file mode 100644 index 0000000000..30a0cc1918 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/ia64/fork.h @@ -0,0 +1,25 @@ +/* Copyright (C) 2002 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 <signal.h> +#include <sysdep.h> + +#define ARCH_FORK() INLINE_SYSCALL (clone, 2, SIGCHLD, 0) + +#include_next <fork.h> diff --git a/linuxthreads/sysdeps/unix/sysv/linux/ia64/pt-initfini.c b/linuxthreads/sysdeps/unix/sysv/linux/ia64/pt-initfini.c new file mode 100644 index 0000000000..85fd33f4a8 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/ia64/pt-initfini.c @@ -0,0 +1,140 @@ +/* Special .init and .fini section support for ia64. LinuxThreads 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. + + 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 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.) + + The GNU C Library is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General 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 <stddef.h> + +#ifdef HAVE_INITFINI_ARRAY + +# define INIT_NEW_WAY \ + ".xdata8 \".init_array\", @fptr(__pthread_initialize_minimal)\n" +# define INIT_OLD_WAY "" +#else +# define INIT_NEW_WAY "" +# define INIT_OLD_WAY \ + "\n\ + st8 [r12] = gp, -16\n\ + br.call.sptk.many b0 = __pthread_initialize_minimal# ;;\n\ + ;;\n\ + adds r12 = 16, r12\n\ + ;;\n\ + ld8 gp = [r12]\n\ + ;;\n" +#endif + +__asm__ ("\n\ +\n\ +#include \"defs.h\"\n\ +\n\ +/*@HEADER_ENDS*/\n\ +\n\ +/*@_init_PROLOG_BEGINS*/\n" + INIT_NEW_WAY + ".section .init\n\ + .align 16\n\ + .global _init#\n\ + .proc _init#\n\ +_init:\n\ + .prologue\n\ + .save ar.pfs, r34\n\ + alloc r34 = ar.pfs, 0, 3, 0, 0\n\ + .vframe r32\n\ + mov r32 = r12\n\ + .save rp, r33\n\ + mov r33 = b0\n\ + .body\n\ + adds r12 = -16, r12\n\ + ;;\n" + INIT_OLD_WAY + ".endp _init#\n\ +\n\ +/*@_init_PROLOG_ENDS*/\n\ +\n\ +/*@_init_EPILOG_BEGINS*/\n\ + .section .init\n\ + .proc _init#\n\ + .prologue\n\ + .save ar.pfs, r34\n\ + .vframe r32\n\ + .save rp, r33\n\ + .body\n\ + mov r12 = r32\n\ + mov ar.pfs = r34\n\ + mov b0 = r33\n\ + br.ret.sptk.many b0\n\ + .endp _init#\n\ +/*@_init_EPILOG_ENDS*/\n\ +\n\ +/*@_fini_PROLOG_BEGINS*/\n\ + .section .fini\n\ + .align 16\n\ + .global _fini#\n\ + .proc _fini#\n\ +_fini:\n\ + .prologue\n\ + .save ar.pfs, r34\n\ + alloc r34 = ar.pfs, 0, 3, 0, 0\n\ + .vframe r32\n\ + mov r32 = r12\n\ + .save rp, r33\n\ + mov r33 = b0\n\ + .body\n\ + adds r12 = -16, r12\n\ + ;;\n\ + .endp _fini#\n\ +\n\ +/*@_fini_PROLOG_ENDS*/\n\ +\n\ +/*@_fini_EPILOG_BEGINS*/\n\ + .section .fini\n\ + .proc _fini#\n\ + .prologue\n\ + .save ar.pfs, r34\n\ + .vframe r32\n\ + .save rp, r33\n\ + .body\n\ + mov r12 = r32\n\ + mov ar.pfs = r34\n\ + mov b0 = r33\n\ + br.ret.sptk.many b0\n\ + .endp _fini#\n\ +\n\ +/*@_fini_EPILOG_ENDS*/\n\ +\n\ +/*@TRAILER_BEGINS*/\n\ + .weak __gmon_start__#\n\ +"); diff --git a/linuxthreads/sysdeps/unix/sysv/linux/ia64/pt-sigsuspend.c b/linuxthreads/sysdeps/unix/sysv/linux/ia64/pt-sigsuspend.c new file mode 100644 index 0000000000..0b96e3d5bd --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/ia64/pt-sigsuspend.c @@ -0,0 +1,33 @@ +/* Internal sigsuspend system call for LinuxThreads. IA64 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 <errno.h> +#include <signal.h> +#include <unistd.h> + +#include <sysdep.h> +#include <sys/syscall.h> +#include <linuxthreads/internals.h> + +void +__pthread_sigsuspend (const sigset_t *set) +{ + INTERNAL_SYSCALL_DECL (err); + INTERNAL_SYSCALL (rt_sigsuspend, err, 2, set, _NSIG / 8); +} diff --git a/linuxthreads/sysdeps/unix/sysv/linux/ia64/sysdep-cancel.h b/linuxthreads/sysdeps/unix/sysv/linux/ia64/sysdep-cancel.h new file mode 100644 index 0000000000..dd9637d2b5 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/ia64/sysdep-cancel.h @@ -0,0 +1,144 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <tls.h> +#ifndef __ASSEMBLER__ +# include <linuxthreads/internals.h> +#endif + +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt + +# ifdef IS_IN_librt +# define PSEUDO_NLOCAL 6 +# define PSEUDO_SAVE_GP mov loc5 = gp +# define PSEUDO_RESTORE_GP mov gp = loc5 +# define PSEUDO_SAVE_GP_1 +# define PSEUDO_RESTORE_GP_1 mov gp = loc5 +# else +# define PSEUDO_NLOCAL 5 +# define PSEUDO_SAVE_GP +# define PSEUDO_RESTORE_GP +# define PSEUDO_SAVE_GP_1 mov loc4 = gp;; +# define PSEUDO_RESTORE_GP_1 mov gp = loc4 +# endif + +# undef PSEUDO +# define PSEUDO(name, syscall_name, args) \ +.text; \ +ENTRY (name) \ + adds r14 = MULTIPLE_THREADS_OFFSET, r13;; \ + ld4 r14 = [r14]; \ + mov r15 = SYS_ify(syscall_name);; \ + cmp4.ne p6, p7 = 0, r14; \ +(p6) br.cond.spnt .Lpseudo_cancel;; \ + break __BREAK_SYSCALL;; \ + cmp.eq p6,p0=-1,r10; \ +(p6) br.cond.spnt.few __syscall_error; \ + ret;; \ + .endp name; \ + .proc __GC_##name; \ + .globl __GC_##name; \ + .hidden __GC_##name; \ +__GC_##name: \ +.Lpseudo_cancel: \ + .prologue; \ + .regstk args, PSEUDO_NLOCAL, args, 0; \ + .save ar.pfs, loc0; \ + alloc loc0 = ar.pfs, args, PSEUDO_NLOCAL, args, 0; \ + .save rp, loc1; \ + mov loc1 = rp; \ + PSEUDO_SAVE_GP;; \ + .body; \ + CENABLE;; \ + PSEUDO_RESTORE_GP; \ + mov loc2 = r8; \ + COPY_ARGS_##args \ + mov r15 = SYS_ify(syscall_name); \ + break __BREAK_SYSCALL;; \ + mov loc3 = r8; \ + mov loc4 = r10; \ + mov out0 = loc2; \ + CDISABLE;; \ + PSEUDO_RESTORE_GP; \ + cmp.eq p6,p0=-1,loc4; \ +(p6) br.cond.spnt.few __syscall_error_##args; \ + mov r8 = loc3; \ + mov rp = loc1; \ + mov ar.pfs = loc0; \ +.Lpseudo_end: \ + ret; \ + .endp __GC_##name; \ +.section .gnu.linkonce.t.__syscall_error_##args, "ax"; \ + .align 32; \ + .proc __syscall_error_##args; \ + .global __syscall_error_##args; \ + .hidden __syscall_error_##args; \ + .size __syscall_error_##args, 64; \ +__syscall_error_##args: \ + .prologue; \ + .regstk args, PSEUDO_NLOCAL, args, 0; \ + .save ar.pfs, loc0; \ + .save rp, loc1; \ + .body; \ + PSEUDO_SAVE_GP_1; \ + br.call.sptk.many b0 = __errno_location;; \ + st4 [r8] = loc3; \ + PSEUDO_RESTORE_GP_1; \ + mov rp = loc1; \ + mov r8 = -1; \ + mov ar.pfs = loc0 + +#undef PSEUDO_END +#define PSEUDO_END(name) .endp + +# ifdef IS_IN_libpthread +# define CENABLE br.call.sptk.many b0 = __pthread_enable_asynccancel +# define CDISABLE br.call.sptk.many b0 = __pthread_disable_asynccancel +# elif !defined NOT_IN_libc +# define CENABLE br.call.sptk.many b0 = __libc_enable_asynccancel +# define CDISABLE br.call.sptk.many b0 = __libc_disable_asynccancel +# else +# define CENABLE br.call.sptk.many b0 = __librt_enable_asynccancel +# define CDISABLE br.call.sptk.many b0 = __librt_disable_asynccancel +# endif + +#define COPY_ARGS_0 /* Nothing */ +#define COPY_ARGS_1 COPY_ARGS_0 mov out0 = in0; +#define COPY_ARGS_2 COPY_ARGS_1 mov out1 = in1; +#define COPY_ARGS_3 COPY_ARGS_2 mov out2 = in2; +#define COPY_ARGS_4 COPY_ARGS_3 mov out3 = in3; +#define COPY_ARGS_5 COPY_ARGS_4 mov out4 = in4; +#define COPY_ARGS_6 COPY_ARGS_5 mov out5 = in5; +#define COPY_ARGS_7 COPY_ARGS_6 mov out6 = in6; + +# ifndef __ASSEMBLER__ +# define SINGLE_THREAD_P \ + __builtin_expect (THREAD_GETMEM (THREAD_SELF, p_multiple_threads) == 0, 1) +# else +# define SINGLE_THREAD_P \ + adds r14 = MULTIPLE_THREADS_OFFSET, r13 ;; ld4 r14 = [r14] ;; cmp4.ne p6, p7 = 0, r14 +# endif + +#elif !defined __ASSEMBLER__ + +/* This code should never be used but we define it anyhow. */ +# define SINGLE_THREAD_P (1) + +#endif diff --git a/linuxthreads/sysdeps/unix/sysv/linux/ia64/vfork.S b/linuxthreads/sysdeps/unix/sysv/linux/ia64/vfork.S new file mode 100644 index 0000000000..54acedad4c --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/ia64/vfork.S @@ -0,0 +1,54 @@ +/* Copyright (C) 2000, 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 <sysdep-cancel.h> +#define _SIGNAL_H +#include <bits/signum.h> + +/* The following are defined in linux/sched.h, which unfortunately */ +/* is not safe for inclusion in an assembly file. */ +#define CLONE_VM 0x00000100 /* set if VM shared between processes */ +#define CLONE_VFORK 0x00004000 /* set if the parent wants the child to wake it up on mm_release */ + +/* pid_t vfork(void); */ +/* Implemented as __clone_syscall(CLONE_VFORK | CLONE_VM | SIGCHLD, 0) */ + +ENTRY(__vfork) +#ifdef SHARED + addl r14 = @gprel(__libc_pthread_functions#), gp;; +#else + .weak pthread_create + addl r14 = @ltoff(@fptr(pthread_create#)), gp;; +#endif + ld8 r14 = [r14];; + cmp.ne p6, p7 = 0, r14 +(p6) br.cond.spnt.few HIDDEN_JUMPTARGET (__fork);; + alloc r2=ar.pfs,0,0,2,0 + mov out0=CLONE_VM+CLONE_VFORK+SIGCHLD + mov out1=0 /* Standard sp value. */ + ;; + DO_CALL (SYS_ify (clone)) + cmp.eq p6,p0=-1,r10 + ;; +(p6) br.cond.spnt.few __syscall_error + ret +PSEUDO_END(__vfork) +libc_hidden_def (__vfork) + +weak_alias (__vfork, vfork) diff --git a/linuxthreads/sysdeps/unix/sysv/linux/jmp-unwind.c b/linuxthreads/sysdeps/unix/sysv/linux/jmp-unwind.c new file mode 100644 index 0000000000..4b90315707 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/jmp-unwind.c @@ -0,0 +1,34 @@ +/* _longjmp_unwind -- Clean up stack frames unwound by longjmp. + 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 <setjmp.h> +#include <stddef.h> +#include <bits/libc-lock.h> + +#ifndef SHARED +weak_extern (__pthread_cleanup_upto); +#endif + +void +_longjmp_unwind (jmp_buf env, int val) +{ + __libc_maybe_call2 (pthread_cleanup_upto, + (env->__jmpbuf, __builtin_frame_address (0)), + (void) 0); +} diff --git a/linuxthreads/sysdeps/unix/sysv/linux/m68k/sysdep-cancel.h b/linuxthreads/sysdeps/unix/sysv/linux/m68k/sysdep-cancel.h new file mode 100644 index 0000000000..bb798e40d6 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/m68k/sysdep-cancel.h @@ -0,0 +1,129 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Andreas Schwab <schwab@suse.de>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with 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 __ASSEMBLER__ +# include <linuxthreads/internals.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) \ + SINGLE_THREAD_P; \ + jne .Lpseudo_cancel; \ + DO_CALL (syscall_name, args); \ + cmp.l &-4095, %d0; \ + jcc SYSCALL_ERROR_LABEL; \ + rts; \ + .Lpseudo_cancel: \ + CENABLE; \ + DOCARGS_##args \ + move.l %d0, -(%sp); \ + move.l &SYS_ify (syscall_name), %d0; \ + trap &0; \ + move.l %d0, %d2; \ + CDISABLE; \ + addq.l &4, %sp; \ + move.l %d2, %d0; \ + UNDOCARGS_##args \ + cmp.l &-4095, %d0; \ + jcc SYSCALL_ERROR_LABEL + +# define DOCARGS_0 move.l %d2, -(%sp); +# define _DOCARGS_0(n) +# define UNDOCARGS_0 move.l (%sp)+, %d2; + +# define DOCARGS_1 _DOCARGS_1 (4); DOCARGS_0 +# define _DOCARGS_1(n) move.l n(%sp), %d1; _DOARGS_0 (n) +# define UNDOCARGS_1 UNDOCARGS_0 + +# define DOCARGS_2 _DOCARGS_2 (8) +# define _DOCARGS_2(n) move.l %d2, -(%sp); move.l n+4(%sp), %d2; \ + _DOCARGS_1 (n) +# define UNDOCARGS_2 UNDOCARGS_1 + +# define DOCARGS_3 _DOCARGS_3 (12) +# define _DOCARGS_3(n) move.l %d3, -(%sp); move.l n+4(%sp), %d3; \ + _DOCARGS_2 (n) +# define UNDOCARGS_3 UNDOCARGS_2; move.l (%sp)+, %d3; + +# define DOCARGS_4 _DOCARGS_4 (16) +# define _DOCARGS_4(n) move.l %d4, -(%sp); move.l n+4(%sp), %d4; \ + _DOCARGS_3 (n) +# define UNDOCARGS_4 UNDOCARGS_3; move.l (%sp)+, %d4; + +# define DOCARGS_5 _DOCARGS_5 (20) +# define _DOCARGS_5(n) move.l %d5, -(%sp); move.l n+4(%sp), %d5; \ + _DOCARGS_4 (n) +# define UNDOCARGS_5 UNDOCARGS_4; move.l (%sp)+, %d5; + +# ifdef IS_IN_libpthread +# ifdef PIC +# define CENABLE jbsr __pthread_enable_asynccancel@PLTPC +# define CDISABLE jbsr __pthread_disable_asynccancel@PLTPC +# else +# define CENABLE jbsr __pthread_enable_asynccancel +# define CDISABLE jbsr __pthread_disable_asynccancel +# endif +# elif !defined NOT_IN_libc +# ifdef PIC +# define CENABLE jbsr __libc_enable_asynccancel@PLTPC +# define CDISABLE jbsr __libc_disable_asynccancel@PLTPC +# else +# define CENABLE jbsr __libc_enable_asynccancel +# define CDISABLE jbsr __libc_disable_asynccancel +# endif +# else +# ifdef PIC +# define CENABLE jbsr __librt_enable_asynccancel@PLTPC +# define CDISABLE jbsr __librt_disable_asynccancel@PLTPC +# else +# define CENABLE jbsr __librt_enable_asynccancel +# define CDISABLE jbsr __librt_disable_asynccancel +# endif +# endif + +# if !defined NOT_IN_libc +# define __local_multiple_threads __libc_multiple_threads +# elif defined IS_IN_libpthread +# define __local_multiple_threads __pthread_multiple_threads +# else +# define __local_multiple_threads __librt_multiple_threads +# endif + +# ifndef __ASSEMBLER__ +extern int __local_multiple_threads attribute_hidden; +# define SINGLE_THREAD_P __builtin_expect (__local_multiple_threads == 0, 1) +# else +# if !defined PIC +# define SINGLE_THREAD_P tst.l __local_multiple_threads +# else +# define SINGLE_THREAD_P tst.l (__local_multiple_threads, %pc) +# endif +# endif + +#elif !defined __ASSEMBLER__ + +/* This code should never be used but we define it anyhow. */ +# define SINGLE_THREAD_P (1) + +#endif diff --git a/linuxthreads/sysdeps/unix/sysv/linux/m68k/vfork.S b/linuxthreads/sysdeps/unix/sysv/linux/m68k/vfork.S new file mode 100644 index 0000000000..49b8a3c0ac --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/m68k/vfork.S @@ -0,0 +1,84 @@ +/* Copyright (C) 1999, 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Andreas Schwab <schwab@gnu.org>. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep-cancel.h> +#define _ERRNO_H 1 +#include <bits/errno.h> +#include <kernel-features.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) + +#ifdef SHARED + tstl (__libc_pthread_functions@GOTPC, %pc) +#else + .weak pthread_create + movel #pthread_create, %d0 +#endif + jbne HIDDEN_JUMPTARGET (__fork) + +#ifdef __NR_vfork + + /* Pop the return PC value into A0. */ + movel %sp@+, %a0 + + /* Stuff the syscall number in D0 and trap into the kernel. */ + movel #SYS_ify (vfork), %d0 + trap #0 + tstl %d0 + jmi .Lerror /* Branch forward if it failed. */ + + /* Jump to the return PC. */ + jmp %a0@ + +.Lerror: + /* Push back the return PC. */ + movel %a0,%sp@- + +# ifdef __ASSUME_VFORK_SYSCALL +# ifndef PIC + jbra SYSCALL_ERROR_LABEL +# endif +# else + /* Check if vfork syscall is known at all. */ + movel #-ENOSYS,%d1 + cmpl %d0,%d1 + jne SYSCALL_ERROR_LABEL + +# endif +#endif + +#ifndef __ASSUME_VFORK_SYSCALL + /* If we don't have vfork, fork is close enough. */ + + movel #SYS_ify (fork), %d0 + trap #0 + tstl %d0 + jmi SYSCALL_ERROR_LABEL + rts +#endif + +PSEUDO_END (__vfork) +libc_hidden_def (__vfork) + +weak_alias (__vfork, vfork) diff --git a/linuxthreads/sysdeps/unix/sysv/linux/mips/Makefile b/linuxthreads/sysdeps/unix/sysv/linux/mips/Makefile new file mode 100644 index 0000000000..56eeecc789 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/mips/Makefile @@ -0,0 +1,3 @@ +# pull in __syscall_error routine +libpthread-routines += sysdep + diff --git a/linuxthreads/sysdeps/unix/sysv/linux/mips/mips64/sysdep-cancel.h b/linuxthreads/sysdeps/unix/sysv/linux/mips/mips64/sysdep-cancel.h new file mode 100644 index 0000000000..fc51774252 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/mips/mips64/sysdep-cancel.h @@ -0,0 +1,144 @@ +/* system call stubs with cancellation handling. Linux/MIPS version. + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Chris Demetriou of Broadcom Corporation, + based on work by Guido Guenther <agx@sigxcpu.org>. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#ifndef __ASSEMBLER__ +# include <linuxthreads/internals.h> +#endif +#include <sys/asm.h> + +#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; \ + 99: \ + PTR_LA t9,__syscall_error; \ + /* manual cpreturn. */ \ + REG_L gp, STKOFF_GP(sp); \ + RESTORESTK ; \ + jr t9; \ + ENTRY (name) \ + SAVESTK ; \ + .cpsetup t9, STKOFF_GP, name ; \ + .set reorder; \ + SINGLE_THREAD_P(t0); \ + bne zero, t0, L(pseudo_cancel); \ + .set noreorder; \ + li v0, SYS_ify(syscall_name); \ + syscall; \ + .set reorder; \ + bne a3, zero, SYSCALL_ERROR_LABEL; \ + /* manual cpreturn. */ \ + REG_L gp, STKOFF_GP(sp); \ + RESTORESTK ; \ + ret; \ + L(pseudo_cancel): \ + REG_S ra, STKOFF_RA(sp); \ + PUSHARGS_##args; /* save syscall args */ \ + CENABLE; \ + REG_S v0, STKOFF_SVMSK(sp); /* save mask */ \ + POPARGS_##args; /* restore syscall args */ \ + .set noreorder; \ + li v0, SYS_ify (syscall_name); \ + syscall; \ + .set reorder; \ + REG_S v0, STKOFF_SC_V0(sp); /* save syscall result */ \ + REG_S a3, STKOFF_SC_ERR(sp); /* save syscall error flag */ \ + REG_L a0, STKOFF_SVMSK(sp); /* pass mask as arg1 */ \ + CDISABLE; \ + REG_L a3, STKOFF_SC_ERR(sp); /* restore syscall error flag */ \ + REG_L ra, STKOFF_RA(sp); /* restore return address */ \ + REG_L v0, STKOFF_SC_V0(sp); /* restore syscall result */ \ + bne a3, zero, SYSCALL_ERROR_LABEL; \ + /* manual cpreturn. */ \ + REG_L gp, STKOFF_GP(sp); \ + RESTORESTK ; \ + L(pseudo_end): +#endif + +# define PUSHARGS_0 /* nothing to do */ +# define PUSHARGS_1 PUSHARGS_0 REG_S a0, STKOFF_A0(sp); +# define PUSHARGS_2 PUSHARGS_1 REG_S a1, STKOFF_A1(sp); +# define PUSHARGS_3 PUSHARGS_2 REG_S a2, STKOFF_A2(sp); +# define PUSHARGS_4 PUSHARGS_3 REG_S a3, STKOFF_A3(sp); +# define PUSHARGS_5 PUSHARGS_4 REG_S a4, STKOFF_A4(sp); +# define PUSHARGS_6 PUSHARGS_5 REG_S a5, STKOFF_A5(sp); + +# define POPARGS_0 /* nothing to do */ +# define POPARGS_1 POPARGS_0 REG_L a0, STKOFF_A0(sp); +# define POPARGS_2 POPARGS_1 REG_L a1, STKOFF_A1(sp); +# define POPARGS_3 POPARGS_2 REG_L a2, STKOFF_A2(sp); +# define POPARGS_4 POPARGS_3 REG_L a3, STKOFF_A3(sp); +# define POPARGS_5 POPARGS_4 REG_L a4, STKOFF_A4(sp); +# define POPARGS_6 POPARGS_5 REG_L a5, STKOFF_A5(sp); + +/* Save an even number of slots. Should be 0 if an even number of slots + are used below, or SZREG if an odd number are used. */ +# define STK_PAD SZREG + +/* Place values that we are more likely to use later in this sequence, i.e. + closer to the SP at function entry. If you do that, the are more + likely to already be in your d-cache. */ +# define STKOFF_A5 (STK_PAD) +# define STKOFF_A4 (STKOFF_A5 + SZREG) +# define STKOFF_A3 (STKOFF_A4 + SZREG) +# define STKOFF_A2 (STKOFF_A3 + SZREG) /* MT and more args. */ +# define STKOFF_A1 (STKOFF_A2 + SZREG) /* MT and 2 args. */ +# define STKOFF_A0 (STKOFF_A1 + SZREG) /* MT and 1 arg. */ +# define STKOFF_RA (STKOFF_A0 + SZREG) /* Used if MT. */ +# define STKOFF_SC_V0 (STKOFF_RA + SZREG) /* Used if MT. */ +# define STKOFF_SC_ERR (STKOFF_SC_V0 + SZREG) /* Used if MT. */ +# define STKOFF_SVMSK (STKOFF_SC_ERR + SZREG) /* Used if MT. */ +# define STKOFF_GP (STKOFF_SVMSK + SZREG) /* Always used. */ + +# define STKSPACE (STKOFF_GP + SZREG) +# define SAVESTK PTR_SUBU sp, STKSPACE +# define RESTORESTK PTR_ADDU sp, STKSPACE + +# ifdef IS_IN_libpthread +# define CENABLE PTR_LA t9, __pthread_enable_asynccancel; jalr t9; +# define CDISABLE PTR_LA t9, __pthread_disable_asynccancel; jalr t9; +# define __local_multiple_threads __pthread_multiple_threads +# elif defined IS_IN_librt +# define CENABLE PTR_LA t9, __librt_enable_asynccancel; jalr t9; +# define CDISABLE PTR_LA t9, __librt_disable_asynccancel; jalr t9; +# define __local_multiple_threads __librt_multiple_threads +# else +# define CENABLE PTR_LA t9, __libc_enable_asynccancel; jalr t9; +# define CDISABLE PTR_LA t9, __libc_disable_asynccancel; jalr t9; +# define __local_multiple_threads __libc_multiple_threads +# endif + +# 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(reg) lw reg, __local_multiple_threads +#endif + +#elif !defined __ASSEMBLER__ + +/* This code should never be used but we define it anyhow. */ +# define SINGLE_THREAD_P (1) + +#endif diff --git a/linuxthreads/sysdeps/unix/sysv/linux/mips/sysdep-cancel.h b/linuxthreads/sysdeps/unix/sysv/linux/mips/sysdep-cancel.h new file mode 100644 index 0000000000..1fff782397 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/mips/sysdep-cancel.h @@ -0,0 +1,143 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Guido Guenther <agx@sigxcpu.org>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with 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 __ASSEMBLER__ +# include <linuxthreads/internals.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; \ + 99: la t9,__syscall_error; \ + jr t9; \ + ENTRY (name) \ + .set noreorder; \ + .cpload t9; \ + .set reorder; \ + SINGLE_THREAD_P(t0); \ + bne zero, t0, 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); \ + sw gp, 32(sp); \ + 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 */ \ + RESTORESTK; \ + bne a3, zero, SYSCALL_ERROR_LABEL; \ + L(pseudo_end): +#endif + +# define PUSHARGS_0 /* nothing to do */ +# define PUSHARGS_1 PUSHARGS_0 sw a0, 0(sp); +# define PUSHARGS_2 PUSHARGS_1 sw a1, 4(sp); +# define PUSHARGS_3 PUSHARGS_2 sw a2, 8(sp); +# define PUSHARGS_4 PUSHARGS_3 sw a3, 12(sp); +# define PUSHARGS_5 PUSHARGS_4 /* handeld 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 +# 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); \ + subu sp, STKSPACE; \ + sw t0, 16(sp) + +# define SAVESTK_6 lw t0, 16(sp); \ + lw t1, 20(sp); \ + subu sp, STKSPACE; \ + sw t0, 16(sp); \ + sw t1, 20(sp) + +# define SAVESTK_7 lw t0, 16(sp); \ + lw t1, 20(sp); \ + lw t2, 24(sp); \ + subu sp, STKSPACE; \ + sw t0, 16(sp); \ + sw t1, 20(sp); \ + sw t2, 24(sp) + +# define RESTORESTK addu sp, STKSPACE + + +# ifdef IS_IN_libpthread +# define CENABLE la t9, __pthread_enable_asynccancel; jalr t9; +# define CDISABLE la t9, __pthread_disable_asynccancel; jalr t9; +# define __local_multiple_threads __pthread_multiple_threads +# elif defined IS_IN_librt +# define CENABLE la t9, __librt_enable_asynccancel; jalr t9; +# define CDISABLE la t9, __librt_disable_asynccancel; jalr t9; +# define __local_multiple_threads __librt_multiple_threads +# else +# define CENABLE la t9, __libc_enable_asynccancel; jalr t9; +# define CDISABLE la t9, __libc_disable_asynccancel; jalr t9; +# define __local_multiple_threads __libc_multiple_threads +# endif + +# 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(reg) lw reg, __local_multiple_threads +#endif + +#elif !defined __ASSEMBLER__ + +/* This code should never be used but we define it anyhow. */ +# define SINGLE_THREAD_P (1) + +#endif diff --git a/linuxthreads/sysdeps/unix/sysv/linux/mq_notify.c b/linuxthreads/sysdeps/unix/sysv/linux/mq_notify.c new file mode 100644 index 0000000000..e9c2b6e79a --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/mq_notify.c @@ -0,0 +1,287 @@ +/* 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; +} + +#else +# include <sysdeps/generic/mq_notify.c> +#endif diff --git a/linuxthreads/sysdeps/unix/sysv/linux/powerpc/Makefile b/linuxthreads/sysdeps/unix/sysv/linux/powerpc/Makefile new file mode 100644 index 0000000000..e98c9bd866 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/powerpc/Makefile @@ -0,0 +1,2 @@ +# pull in __syscall_error routine +libpthread-routines += sysdep diff --git a/linuxthreads/sysdeps/unix/sysv/linux/powerpc/Versions b/linuxthreads/sysdeps/unix/sysv/linux/powerpc/Versions new file mode 100644 index 0000000000..326307c30c --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/powerpc/Versions @@ -0,0 +1,5 @@ +libpthread { + GLIBC_2.3.4 { + longjmp; siglongjmp; + } +} diff --git a/linuxthreads/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h b/linuxthreads/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h new file mode 100644 index 0000000000..0ee10c1c3a --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h @@ -0,0 +1,131 @@ +/* Copyright (C) 2003 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 <linuxthreads/internals.h> +#endif + +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt + +# undef PSEUDO +# define PSEUDO(name, syscall_name, args) \ + .section ".text"; \ + ENTRY (name) \ + SINGLE_THREAD_P; \ + bne- .Lpseudo_cancel; \ + DO_CALL (SYS_ify (syscall_name)); \ + PSEUDO_RET; \ + .Lpseudo_cancel: \ + stwu 1,-48(1); \ + mflr 9; \ + stw 9,52(1); \ + DOCARGS_##args; /* save syscall args around CENABLE. */ \ + CENABLE; \ + stw 3,16(1); /* store CENABLE return value (MASK). */ \ + UNDOCARGS_##args; /* restore syscall args. */ \ + DO_CALL (SYS_ify (syscall_name)); \ + mfcr 0; /* save CR/R3 around CDISABLE. */ \ + stw 3,8(1); \ + stw 0,12(1); \ + lwz 3,16(1); /* pass MASK to CDISABLE. */ \ + CDISABLE; \ + lwz 4,52(1); \ + lwz 0,12(1); /* restore CR/R3. */ \ + lwz 3,8(1); \ + mtlr 4; \ + mtcr 0; \ + addi 1,1,48; + +# define DOCARGS_0 +# define UNDOCARGS_0 + +# define DOCARGS_1 stw 3,20(1); DOCARGS_0 +# define UNDOCARGS_1 lwz 3,20(1); UNDOCARGS_0 + +# define DOCARGS_2 stw 4,24(1); DOCARGS_1 +# define UNDOCARGS_2 lwz 4,24(1); UNDOCARGS_1 + +# define DOCARGS_3 stw 5,28(1); DOCARGS_2 +# define UNDOCARGS_3 lwz 5,28(1); UNDOCARGS_2 + +# define DOCARGS_4 stw 6,32(1); DOCARGS_3 +# define UNDOCARGS_4 lwz 6,32(1); UNDOCARGS_3 + +# define DOCARGS_5 stw 7,36(1); DOCARGS_4 +# define UNDOCARGS_5 lwz 7,36(1); UNDOCARGS_4 + +# define DOCARGS_6 stw 8,40(1); DOCARGS_5 +# define UNDOCARGS_6 lwz 8,40(1); UNDOCARGS_5 + +# ifdef IS_IN_libpthread +# define CENABLE bl 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) +# else +# define CENABLE bl JUMPTARGET(__librt_enable_asynccancel) +# define CDISABLE bl JUMPTARGET(__librt_disable_asynccancel) +# endif + +# ifdef HAVE_TLS_SUPPORT +# ifndef __ASSEMBLER__ +# define SINGLE_THREAD_P \ + __builtin_expect (THREAD_GETMEM (THREAD_SELF, p_multiple_threads) == 0, 1) +# else +# define SINGLE_THREAD_P \ + lwz 10,MULTIPLE_THREADS_OFFSET(2); \ + cmpwi 10,0 +# endif +# else +# if !defined NOT_IN_libc +# define __local_multiple_threads __libc_multiple_threads +# else +# define __local_multiple_threads __librt_multiple_threads +# endif +# ifndef __ASSEMBLER__ +extern int __local_multiple_threads attribute_hidden; +# define SINGLE_THREAD_P __builtin_expect (__local_multiple_threads == 0, 1) +# else +# if !defined PIC +# define SINGLE_THREAD_P \ + lis 10,__local_multiple_threads@ha; \ + lwz 10,__local_multiple_threads@l(10); \ + cmpwi 10,0 +# else +# define SINGLE_THREAD_P \ + mflr 9; \ + bl _GLOBAL_OFFSET_TABLE_@local-4; \ + mflr 10; \ + mtlr 9; \ + lwz 10,__local_multiple_threads@got(10); \ + lwz 10,0(10); \ + cmpwi 10,0 +# endif +# endif +# endif + +#elif !defined __ASSEMBLER__ + +/* This code should never be used but we define it anyhow. */ +# define SINGLE_THREAD_P (1) + +#endif diff --git a/linuxthreads/sysdeps/unix/sysv/linux/powerpc/powerpc32/vfork.S b/linuxthreads/sysdeps/unix/sysv/linux/powerpc/powerpc32/vfork.S new file mode 100644 index 0000000000..ee6254a950 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/powerpc/powerpc32/vfork.S @@ -0,0 +1,78 @@ +/* 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-cancel.h> +#define _ERRNO_H 1 +#include <bits/errno.h> +#include <kernel-features.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) + +#ifdef __NR_vfork +# ifdef SHARED + mflr 9 + bl _GLOBAL_OFFSET_TABLE_@local-4 + mflr 10 + mtlr 9 + lwz 10,__libc_pthread_functions@got(10) + lwz 10,0(10) +# else + .weak pthread_create + lis 10,pthread_create@ha + la 10,pthread_create@l(10) +# endif + + cmpwi 10,0 + bne- .Lhidden_fork + + DO_CALL (SYS_ify (vfork)); + +# ifdef __ASSUME_VFORK_SYSCALL + PSEUDO_RET +# else + bnslr+ + /* Check if vfork syscall is known at all. */ + cmpwi r3,ENOSYS + bne- .Lsyscall_error + +# endif + +.Lhidden_fork: + b HIDDEN_JUMPTARGET(__fork) + +#endif + +#ifndef __ASSUME_VFORK_SYSCALL + /* If we don't have vfork, fork is close enough. */ + + DO_CALL (SYS_ify (fork)); + bnslr+ + +.Lsyscall_error: + b JUMPTARGET(__syscall_error) +#endif + +PSEUDO_END (__vfork) +libc_hidden_def (__vfork) + +weak_alias (__vfork, vfork) diff --git a/linuxthreads/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h b/linuxthreads/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h new file mode 100644 index 0000000000..0c74676766 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h @@ -0,0 +1,127 @@ +/* Copyright (C) 2003 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 <linuxthreads/internals.h> +#endif + +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt + +# undef PSEUDO +# define PSEUDO(name, syscall_name, args) \ + .section ".text"; \ + ENTRY (name) \ + SINGLE_THREAD_P; \ + bne- .Lpseudo_cancel; \ + DO_CALL (SYS_ify (syscall_name)); \ + PSEUDO_RET; \ + .Lpseudo_cancel: \ + stdu 1,-128(1); \ + mflr 9; \ + std 9,128+16(1); \ + DOCARGS_##args; /* save syscall args around CENABLE. */ \ + CENABLE; \ + std 3,72(1); /* store CENABLE return value (MASK). */ \ + UNDOCARGS_##args; /* restore syscall args. */ \ + DO_CALL (SYS_ify (syscall_name)); \ + mfcr 0; /* save CR/R3 around CDISABLE. */ \ + std 3,64(1); \ + std 0,8(1); \ + ld 3,72(1); /* pass MASK to CDISABLE. */ \ + CDISABLE; \ + ld 9,128+16(1); \ + ld 0,8(1); /* restore CR/R3. */ \ + ld 3,64(1); \ + mtlr 9; \ + mtcr 0; \ + addi 1,1,128; + +# define DOCARGS_0 +# define UNDOCARGS_0 + +# define DOCARGS_1 std 3,80(1); DOCARGS_0 +# define UNDOCARGS_1 ld 3,80(1); UNDOCARGS_0 + +# define DOCARGS_2 std 4,88(1); DOCARGS_1 +# define UNDOCARGS_2 ld 4,88(1); UNDOCARGS_1 + +# define DOCARGS_3 std 5,96(1); DOCARGS_2 +# define UNDOCARGS_3 ld 5,96(1); UNDOCARGS_2 + +# define DOCARGS_4 std 6,104(1); DOCARGS_3 +# define UNDOCARGS_4 ld 6,104(1); UNDOCARGS_3 + +# define DOCARGS_5 std 7,112(1); DOCARGS_4 +# define UNDOCARGS_5 ld 7,112(1); UNDOCARGS_4 + +# define DOCARGS_6 std 8,120(1); DOCARGS_5 +# define UNDOCARGS_6 ld 8,120(1); UNDOCARGS_5 + +# ifdef IS_IN_libpthread +# define CENABLE bl JUMPTARGET(__pthread_enable_asynccancel) +# define CDISABLE bl JUMPTARGET(__pthread_disable_asynccancel) +# define __local_multiple_threads __pthread_multiple_threads +# elif !defined NOT_IN_libc +# define CENABLE bl JUMPTARGET(__libc_enable_asynccancel) +# define CDISABLE bl JUMPTARGET(__libc_disable_asynccancel) +# define __local_multiple_threads __libc_multiple_threads +# else +# define CENABLE bl JUMPTARGET(__librt_enable_asynccancel); nop +# define CDISABLE bl JUMPTARGET(__librt_disable_asynccancel); nop +# define __local_multiple_threads __librt_multiple_threads +# endif + +# ifdef HAVE_TLS_SUPPORT +# ifndef __ASSEMBLER__ +# define SINGLE_THREAD_P \ + __builtin_expect (THREAD_GETMEM (THREAD_SELF, p_multiple_threads) == 0, 1) +# else +# define SINGLE_THREAD_P \ + lwz 10,MULTIPLE_THREADS_OFFSET(13); \ + cmpwi 10,0 +# endif +# else /* !HAVE_TLS_SUPPORT */ +# ifndef __ASSEMBLER__ +extern int __local_multiple_threads +# if !defined NOT_IN_libc || defined IS_IN_libpthread + attribute_hidden; +# else + ; +# endif +# define SINGLE_THREAD_P __builtin_expect (__local_multiple_threads == 0, 1) +# else +# define SINGLE_THREAD_P \ + .section ".toc","aw"; \ +.LC__local_multiple_threads:; \ + .tc __local_multiple_threads[TC],__local_multiple_threads; \ + .previous; \ + ld 10,.LC__local_multiple_threads@toc(2); \ + lwz 10,0(10); \ + cmpwi 10,0 +# endif +# endif + +#elif !defined __ASSEMBLER__ + +/* This code should never be used but we define it anyhow. */ +# define SINGLE_THREAD_P (1) + +#endif diff --git a/linuxthreads/sysdeps/unix/sysv/linux/powerpc/powerpc64/vfork.S b/linuxthreads/sysdeps/unix/sysv/linux/powerpc/powerpc64/vfork.S new file mode 100644 index 0000000000..b408e31b7b --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/powerpc/powerpc64/vfork.S @@ -0,0 +1,91 @@ +/* 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-cancel.h> +#define _ERRNO_H 1 +#include <bits/errno.h> +#include <kernel-features.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. */ + +#ifdef SHARED + .section ".toc","aw" +.LC0: + .tc __libc_pthread_functions[TC],__libc_pthread_functions + .section ".text" + .align 2 +#endif + +ENTRY (__vfork) + +#ifdef __NR_vfork + +# ifdef SHARED + ld 10,.LC0@toc(2) + ld 10,0(10) + cmpwi 10,0 + bne- HIDDEN_JUMPTARGET(__fork) +# else + .weak pthread_create + lis 10,pthread_create@highest + ori 10,10,pthread_create@higher + sldi 10,10,32 + oris 10,10,pthread_create@h + ori 10,10,pthread_create@l + cmpwi 10,0 + bne- .Lhidden_fork +# endif + + DO_CALL (SYS_ify (vfork)); + +# ifdef __ASSUME_VFORK_SYSCALL + PSEUDO_RET +# else + bnslr+ + /* Check if vfork syscall is known at all. */ + cmpdi r3,ENOSYS +# ifdef SHARED + bne JUMPTARGET(__syscall_error) +# else + bne- .Lsyscall_error +# endif + +# endif +#endif + +#ifndef __ASSUME_VFORK_SYSCALL + /* If we don't have vfork, fork is close enough. */ + + DO_CALL (SYS_ify (fork)); + PSEUDO_RET +#endif + +# ifndef SHARED +.Lhidden_fork: + b HIDDEN_JUMPTARGET(__fork) +.Lsyscall_error: + b JUMPTARGET(__syscall_error) +# endif + +PSEUDO_END (__vfork) +libc_hidden_def (__vfork) + +weak_alias (__vfork, vfork) diff --git a/linuxthreads/sysdeps/unix/sysv/linux/powerpc/ptlongjmp.c b/linuxthreads/sysdeps/unix/sysv/linux/powerpc/ptlongjmp.c new file mode 100644 index 0000000000..177256c7fb --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/powerpc/ptlongjmp.c @@ -0,0 +1,70 @@ +/* Linuxthreads - a simple clone()-based implementation of Posix */ +/* threads for Linux. */ +/* Copyright (C) 1998 Xavier Leroy (Xavier.Leroy@inria.fr) */ +/* */ +/* This program is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public License */ +/* as published by the Free Software Foundation; either version 2 */ +/* of the License, or (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Library General Public License for more details. */ + +/* Redefine siglongjmp and longjmp so that they interact correctly + with cleanup handlers */ +/* Derived from linuxthreads/ptlongjmp.c & added AltiVec/VMX versioning. */ +#include "pthread.h" +#include <setjmp.h> +#include <bits/wordsize.h> +#include <shlib-compat.h> +#if defined SHARED +# if SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_3_4) + +/* These functions are not declared anywhere since they shouldn't be + used at another place but here. */ +extern void __novmx__libc_siglongjmp (sigjmp_buf env, int val) + __attribute__ ((noreturn)); +extern void __novmx__libc_longjmp (sigjmp_buf env, int val) + __attribute__ ((noreturn)); + + +void __novmx_siglongjmp (sigjmp_buf env, int val) +{ + __novmx__libc_siglongjmp (env, val); +} + +void __novmx_longjmp (jmp_buf env, int val) +{ + __novmx__libc_longjmp (env, val); +} + +# if __WORDSIZE == 64 +symbol_version (__novmx_longjmp,longjmp,GLIBC_2.3); +symbol_version (__novmx_siglongjmp,siglongjmp,GLIBC_2.3); +# else +symbol_version (__novmx_longjmp,longjmp,GLIBC_2.0); +symbol_version (__novmx_siglongjmp,siglongjmp,GLIBC_2.0); +# endif +# endif /* SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_3_4) ) */ + +/* These functions are not declared anywhere since they shouldn't be + used at another place but here. */ +extern void __vmx__libc_siglongjmp (sigjmp_buf env, int val) + __attribute__ ((noreturn)); +extern void __vmx__libc_longjmp (sigjmp_buf env, int val) + __attribute__ ((noreturn)); + +void __vmx_siglongjmp (sigjmp_buf env, int val) +{ + __vmx__libc_siglongjmp (env, val); +} + +void __vmx_longjmp (jmp_buf env, int val) +{ + __vmx__libc_longjmp (env, val); +} +default_symbol_version (__vmx_longjmp,longjmp,GLIBC_2.3.4); +default_symbol_version (__vmx_siglongjmp,siglongjmp,GLIBC_2.3.4); +#endif /* SHARED */ diff --git a/linuxthreads/sysdeps/unix/sysv/linux/pt-sigsuspend.c b/linuxthreads/sysdeps/unix/sysv/linux/pt-sigsuspend.c new file mode 100644 index 0000000000..5528c55ca5 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/pt-sigsuspend.c @@ -0,0 +1,56 @@ +/* Internal sigsuspend system call for LinuxThreads. Generic Linux 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 <errno.h> +#include <signal.h> +#include <unistd.h> + +#include <sysdep.h> +#include <sys/syscall.h> +#include <linuxthreads/internals.h> + +#include "kernel-features.h" + +void +__pthread_sigsuspend (const sigset_t *set) +{ + INTERNAL_SYSCALL_DECL (err); +#if !__ASSUME_REALTIME_SIGNALS + static int __pthread_missing_rt_sigs; + +# ifdef __NR_rt_sigsuspend + /* First try the RT signals. */ + if (!__pthread_missing_rt_sigs) + { + /* XXX The size argument hopefully will have to be changed to the + real size of the user-level sigset_t. */ + int r; + r = INTERNAL_SYSCALL (rt_sigsuspend, err, 2, set, _NSIG / 8); + if (INTERNAL_SYSCALL_ERRNO (r, err) != ENOSYS) + return; + + __pthread_missing_rt_sigs = 1; + } +# endif + + INTERNAL_SYSCALL (sigsuspend, err, 3, 0, 0, set->__val[0]); +#else + INTERNAL_SYSCALL (rt_sigsuspend, err, 2, set, _NSIG / 8); +#endif +} diff --git a/linuxthreads/sysdeps/unix/sysv/linux/raise.c b/linuxthreads/sysdeps/unix/sysv/linux/raise.c new file mode 100644 index 0000000000..9dad2b2697 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/raise.c @@ -0,0 +1,36 @@ +/* Copyright (C) 1991, 1996, 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 <signal.h> +#include <unistd.h> +#include <bits/libc-lock.h> + +#ifndef SHARED +weak_extern (__pthread_raise) +#endif + +/* Raise the signal SIG. */ +int +raise (sig) + int sig; +{ + return __libc_maybe_call2 (pthread_raise, (sig), + __kill (__getpid (), sig)); +} +libc_hidden_def (raise) +weak_alias (raise, gsignal) diff --git a/linuxthreads/sysdeps/unix/sysv/linux/register-atfork.c b/linuxthreads/sysdeps/unix/sysv/linux/register-atfork.c new file mode 100644 index 0000000000..e4490e73e9 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/register-atfork.c @@ -0,0 +1,88 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <stdlib.h> +#include "fork.h" + + +int +__register_atfork (prepare, parent, child, dso_handle) + void (*prepare) (void); + void (*parent) (void); + void (*child) (void); + void *dso_handle; +{ + struct fork_handler *new_prepare = NULL; + struct fork_handler *new_parent = NULL; + struct fork_handler *new_child = NULL; + + if (prepare != NULL) + { + new_prepare = (struct fork_handler *) malloc (sizeof (*new_prepare)); + if (new_prepare == NULL) + goto out1; + + new_prepare->handler = prepare; + new_prepare->dso_handle = dso_handle; + } + + if (parent != NULL) + { + new_parent = (struct fork_handler *) malloc (sizeof (*new_parent)); + if (new_parent == NULL) + goto out2; + + new_parent->handler = parent; + new_parent->dso_handle = dso_handle; + } + + if (child != NULL) + { + new_child = (struct fork_handler *) malloc (sizeof (*new_child)); + if (new_child == NULL) + { + free (new_parent); + out2: + free (new_prepare); + out1: + return errno; + } + + new_child->handler = child; + new_child->dso_handle = dso_handle; + } + + /* Get the lock to not conflict with running forks. */ + __libc_lock_lock (__fork_block.lock); + + /* Now that we have all the handlers allocate enqueue them. */ + if (new_prepare != NULL) + list_add_tail (&new_prepare->list, &__fork_block.prepare_list); + if (new_parent != NULL) + list_add_tail (&new_parent->list, &__fork_block.parent_list); + if (new_child != NULL) + list_add_tail (&new_child->list, &__fork_block.child_list); + + /* Release the lock. */ + __libc_lock_unlock (__fork_block.lock); + + return 0; +} +libc_hidden_def (__register_atfork) diff --git a/linuxthreads/sysdeps/unix/sysv/linux/s390/bits/typesizes.h b/linuxthreads/sysdeps/unix/sysv/linux/s390/bits/typesizes.h new file mode 100644 index 0000000000..bee7639f06 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/s390/bits/typesizes.h @@ -0,0 +1,72 @@ +/* bits/typesizes.h -- underlying types for *_t. Linux/s390 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 _BITS_TYPES_H +# error "Never include <bits/typesizes.h> directly; use <sys/types.h> instead." +#endif + +#ifndef _BITS_TYPESIZES_H +#define _BITS_TYPESIZES_H 1 + +/* See <bits/types.h> for the meaning of these macros. This file exists so + that <bits/types.h> need not vary across different GNU platforms. */ + +#define __DEV_T_TYPE __UQUAD_TYPE +#define __UID_T_TYPE __U32_TYPE +#define __GID_T_TYPE __U32_TYPE +#define __INO_T_TYPE __ULONGWORD_TYPE +#define __INO64_T_TYPE __UQUAD_TYPE +#define __MODE_T_TYPE __U32_TYPE +#define __NLINK_T_TYPE __UWORD_TYPE +#define __OFF_T_TYPE __SLONGWORD_TYPE +#define __OFF64_T_TYPE __SQUAD_TYPE +#define __PID_T_TYPE __S32_TYPE +#define __RLIM_T_TYPE __ULONGWORD_TYPE +#define __RLIM64_T_TYPE __UQUAD_TYPE +#define __BLKCNT_T_TYPE __SLONGWORD_TYPE +#define __BLKCNT64_T_TYPE __SQUAD_TYPE +#define __FSBLKCNT_T_TYPE __ULONGWORD_TYPE +#define __FSBLKCNT64_T_TYPE __UQUAD_TYPE +#define __FSFILCNT_T_TYPE __ULONGWORD_TYPE +#define __FSFILCNT64_T_TYPE __UQUAD_TYPE +#define __ID_T_TYPE __U32_TYPE +#define __CLOCK_T_TYPE __SLONGWORD_TYPE +#define __TIME_T_TYPE __SLONGWORD_TYPE +#define __USECONDS_T_TYPE __U32_TYPE +#define __SUSECONDS_T_TYPE __SLONGWORD_TYPE +#define __DADDR_T_TYPE __S32_TYPE +#define __SWBLK_T_TYPE __SLONGWORD_TYPE +#define __KEY_T_TYPE __S32_TYPE +#define __CLOCKID_T_TYPE __S32_TYPE +#define __TIMER_T_TYPE __S32_TYPE +#define __BLKSIZE_T_TYPE __SLONGWORD_TYPE +#define __FSID_T_TYPE struct { int __val[2]; } +#if defined __GNUC__ && __GNUC__ <= 2 +/* Compatibility with g++ 2.95.x. */ +#define __SSIZE_T_TYPE __SWORD_TYPE +#else +/* size_t is unsigned long int on s390 -m31. */ +#define __SSIZE_T_TYPE __SLONGWORD_TYPE +#endif + +/* Number of descriptors that can fit in an `fd_set'. */ +#define __FD_SETSIZE 1024 + + +#endif /* bits/typesizes.h */ diff --git a/linuxthreads/sysdeps/unix/sysv/linux/s390/s390-32/pt-initfini.c b/linuxthreads/sysdeps/unix/sysv/linux/s390/s390-32/pt-initfini.c new file mode 100644 index 0000000000..b7d901c4c6 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/s390/s390-32/pt-initfini.c @@ -0,0 +1,154 @@ +/* Special .init and .fini section support for S/390. + Copyright (C) 2000, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it + and/or modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + 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 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.) + + The GNU C Library is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General 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. */ + +__asm__ ("\ +\n\ +#include \"defs.h\"\n\ +\n\ +/*@HEADER_ENDS*/\n\ +\n\ +/*@TESTS_BEGIN*/\n\ +\n\ +/*@TESTS_END*/\n\ +\n\ +/*@_init_PROLOG_BEGINS*/\n\ +\n\ + .section .init\n\ +#NO_APP\n\ + .align 4\n\ +.globl _init\n\ + .type _init,@function\n\ +_init:\n\ +# leaf function 0\n\ +# automatics 0\n\ +# outgoing args 0\n\ +# need frame pointer 0\n\ +# call alloca 0\n\ +# has varargs 0\n\ +# incoming args (stack) 0\n\ +# function length 36\n\ + STM 6,15,24(15)\n\ + BRAS 13,.LTN1_0\n\ +.LT1_0:\n\ +.LC13:\n\ + .long __pthread_initialize_minimal@PLT-.LT1_0\n\ +.LC14:\n\ + .long __gmon_start__@GOT\n\ +.LC15:\n\ + .long _GLOBAL_OFFSET_TABLE_-.LT1_0\n\ +.LTN1_0:\n\ + LR 1,15\n\ + AHI 15,-96\n\ + ST 1,0(15)\n\ + L 12,.LC15-.LT1_0(13)\n\ + AR 12,13\n\ + L 1,.LC13-.LT1_0(13)\n\ + LA 1,0(1,13)\n\ + BASR 14,1\n\ + L 1,.LC14-.LT1_0(13)\n\ + L 1,0(1,12)\n\ + LTR 1,1\n\ + JE .L22\n\ + BASR 14,1\n\ +.L22:\n\ +#APP\n\ + .align 4,0x07\n\ + END_INIT\n\ +\n\ +/*@_init_PROLOG_ENDS*/\n\ +\n\ +/*@_init_EPILOG_BEGINS*/\n\ + .align 4\n\ + .section .init\n\ +#NO_APP\n\ + .align 4\n\ + L 4,152(15)\n\ + LM 6,15,120(15)\n\ + BR 4\n\ +#APP\n\ + END_INIT\n\ +\n\ +/*@_init_EPILOG_ENDS*/\n\ +\n\ +/*@_fini_PROLOG_BEGINS*/\n\ + .section .fini\n\ +#NO_APP\n\ + .align 4\n\ +.globl _fini\n\ + .type _fini,@function\n\ +_fini:\n\ +# leaf function 0\n\ +# automatics 0\n\ +# outgoing args 0\n\ +# need frame pointer 0\n\ +# call alloca 0\n\ +# has varargs 0\n\ +# incoming args (stack) 0\n\ +# function length 30\n\ + STM 6,15,24(15)\n\ + BRAS 13,.LTN2_0\n\ +.LT2_0:\n\ +.LC17:\n\ + .long _GLOBAL_OFFSET_TABLE_-.LT2_0\n\ +.LTN2_0:\n\ + LR 1,15\n\ + AHI 15,-96\n\ + ST 1,0(15)\n\ + L 12,.LC17-.LT2_0(13)\n\ + AR 12,13\n\ +#APP\n\ + .align 4,0x07\n\ + END_FINI\n\ +\n\ +/*@_fini_PROLOG_ENDS*/\n\ +\n\ +/*@_fini_EPILOG_BEGINS*/\n\ + .align 4\n\ + .section .fini\n\ +#NO_APP\n\ + .align 4\n\ + L 4,152(15)\n\ + LM 6,15,120(15)\n\ + BR 4\n\ +#APP\n\ + END_FINI\n\ +\n\ +/*@_fini_EPILOG_ENDS*/\n\ +\n\ +/*@TRAILER_BEGINS*/\ +"); diff --git a/linuxthreads/sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h b/linuxthreads/sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h new file mode 100644 index 0000000000..06f7aed7dc --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h @@ -0,0 +1,137 @@ +/* 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 <sysdep.h> +#include <tls.h> +#ifndef __ASSEMBLER__ +# include <linuxthreads/internals.h> +#endif + +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt + +# if !defined NOT_IN_libc || defined IS_IN_libpthread + +# define PSEUDO_CANCEL(name, syscall_name, args) \ +L(pseudo_cancel): \ + STM_##args \ + stm %r12,%r15,48(%r15); \ + lr %r14,%r15; \ + ahi %r15,-96; \ + st %r14,0(%r15); \ + basr %r13,0; \ +0: l %r1,1f-0b(%r13); \ + bas %r14,0(%r1,%r13); \ + lr %r0,%r2; \ + LM_##args \ + DO_CALL(syscall_name, args); \ + l %r1,2f-0b(%r13); \ + lr %r12,%r2; \ + lr %r2,%r0; \ + bas %r14,0(%r1,%r13); \ + lr %r2,%r12; \ + lm %r12,%r15,48+96(%r15); \ + j L(pseudo_check); \ +1: .long CENABLE-0b; \ +2: .long CDISABLE-0b; + +# else /* !libc.so && !libpthread.so */ + +# define PSEUDO_CANCEL(name, syscall_name, args) \ +L(pseudo_cancel): \ + STM_##args \ + stm %r11,%r15,44(%r15); \ + lr %r14,%r15; \ + ahi %r15,-96; \ + st %r14,0(%r15); \ + basr %r13,0; \ +0: l %r12,3f-0b(%r13); \ + l %r1,1f-0b(%r13); \ + la %r12,0(%r12,%r13); \ + bas %r14,0(%r1,%r13); \ + lr %r0,%r2; \ + LM_##args \ + DO_CALL(syscall_name, args); \ + l %r1,2f-0b(%r13); \ + lr %r11,%r2; \ + lr %r2,%r0; \ + bas %r14,0(%r1,%r13); \ + lr %r2,%r11; \ + lm %r11,%r15,44+96(%r15); \ + j L(pseudo_check); \ +1: .long CENABLE@PLT-0b; \ +2: .long CDISABLE@PLT-0b; \ +3: .long _GLOBAL_OFFSET_TABLE_-0b; + +# endif + +# undef PSEUDO +# define PSEUDO(name, syscall_name, args) \ + .text; \ +PSEUDO_CANCEL(name, syscall_name, args) \ +ENTRY(name) \ + SINGLE_THREAD_P(%r1) \ + jne L(pseudo_cancel); \ + DO_CALL(syscall_name, args); \ +L(pseudo_check): \ + lhi %r4,-4095; \ + clr %r2,%r4; \ + jnl SYSCALL_ERROR_LABEL; \ +L(pseudo_end): + +# ifdef IS_IN_libpthread +# define CENABLE __pthread_enable_asynccancel +# define CDISABLE __pthread_disable_asynccancel +# elif !defined NOT_IN_libc +# define CENABLE __libc_enable_asynccancel +# define CDISABLE __libc_disable_asynccancel +# else +# define CENABLE __librt_enable_asynccancel +# define CDISABLE __librt_disable_asynccancel +# endif + +#define STM_0 /* Nothing */ +#define STM_1 st %r2,8(%r15); +#define STM_2 stm %r2,%r3,8(%r15); +#define STM_3 stm %r2,%r4,8(%r15); +#define STM_4 stm %r2,%r5,8(%r15); +#define STM_5 stm %r2,%r5,8(%r15); + +#define LM_0 /* Nothing */ +#define LM_1 l %r2,8+96(%r15); +#define LM_2 lm %r2,%r3,8+96(%r15); +#define LM_3 lm %r2,%r4,8+96(%r15); +#define LM_4 lm %r2,%r5,8+96(%r15); +#define LM_5 lm %r2,%r5,8+96(%r15); + +# ifndef __ASSEMBLER__ +# define SINGLE_THREAD_P \ + __builtin_expect (THREAD_GETMEM (THREAD_SELF, \ + p_header.data.multiple_threads) == 0, 1) +# else +# define SINGLE_THREAD_P(reg) \ + ear reg,%a0; \ + icm reg,15,MULTIPLE_THREADS_OFFSET(reg); +# endif + +#elif !defined __ASSEMBLER__ + +/* This code should never be used but we define it anyhow. */ +# define SINGLE_THREAD_P (1) + +#endif diff --git a/linuxthreads/sysdeps/unix/sysv/linux/s390/s390-32/vfork.S b/linuxthreads/sysdeps/unix/sysv/linux/s390/s390-32/vfork.S new file mode 100644 index 0000000000..6dfeca86d4 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/s390/s390-32/vfork.S @@ -0,0 +1,69 @@ +/* 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. */ + +#include <sysdep-cancel.h> +#define _ERRNO_H 1 +#include <bits/errno.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) + basr %r1,0 +0: +#ifdef SHARED + al %r1,4f-0b(%r1) + l %r1,0(%r1) + ltr %r1,%r1 +#else + icm %r1,15,4f-0b(%r1) +#endif + jne 1f + + /* Do vfork system call. */ + svc SYS_ify (vfork) + + /* Check for error. */ + lhi %r4,-4095 + clr %r2,%r4 + jnl SYSCALL_ERROR_LABEL + + /* Normal return. */ + br %r14 +1: + basr %r1,0 +2: + al %r1,3f-2b(%r1) + br %r1 +3: + .long HIDDEN_JUMPTARGET(__fork)-2b +4: +#ifdef SHARED + .long __libc_pthread_functions-0b +#else + .weak pthread_create + .long pthread_create +#endif +PSEUDO_END(__vfork) + +libc_hidden_def (__vfork) + +weak_alias (__vfork, vfork) diff --git a/linuxthreads/sysdeps/unix/sysv/linux/s390/s390-64/pt-initfini.c b/linuxthreads/sysdeps/unix/sysv/linux/s390/s390-64/pt-initfini.c new file mode 100644 index 0000000000..540443e6a3 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/s390/s390-64/pt-initfini.c @@ -0,0 +1,137 @@ +/* Special .init and .fini section support for 64 bit S/390. + Copyright (C) 2001 Free Software Foundation, Inc. + Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com). + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it + and/or modify it under the terms of the GNU Lesser 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 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.) + + The GNU C Library is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General 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. */ + +__asm__ ("\ +\n\ +#include \"defs.h\"\n\ +\n\ +/*@HEADER_ENDS*/\n\ +\n\ +/*@TESTS_BEGIN*/\n\ +\n\ +/*@TESTS_END*/\n\ +\n\ +/*@_init_PROLOG_BEGINS*/\n\ +\n\ + .section .init\n\ +#NO_APP\n\ + .align 4\n\ +.globl _init\n\ + .type _init,@function\n\ +_init:\n\ +# leaf function 0\n\ +# automatics 0\n\ +# outgoing args 0\n\ +# need frame pointer 0\n\ +# call alloca 0\n\ +# has varargs 0\n\ +# incoming args (stack) 0\n\ +# function length 36\n\ + STMG 6,15,48(15)\n\ + LGR 1,15\n\ + AGHI 15,-160\n\ + STG 1,0(15)\n\ + LARL 12,_GLOBAL_OFFSET_TABLE_\n\ + BRASL 14,__pthread_initialize_minimal@PLT\n\ + LARL 1,__gmon_start__@GOTENT\n\ + LG 1,0(1)\n\ + LTGR 1,1\n\ + JE .L22\n\ + BASR 14,1\n\ +.L22:\n\ +#APP\n\ + .align 4,0x07\n\ + END_INIT\n\ +\n\ +/*@_init_PROLOG_ENDS*/\n\ +\n\ +/*@_init_EPILOG_BEGINS*/\n\ + .align 4\n\ + .section .init\n\ +#NO_APP\n\ + .align 4\n\ + LG 4,272(15)\n\ + LMG 6,15,208(15)\n\ + BR 4\n\ +#APP\n\ + END_INIT\n\ +\n\ +/*@_init_EPILOG_ENDS*/\n\ +\n\ +/*@_fini_PROLOG_BEGINS*/\n\ + .section .fini\n\ +#NO_APP\n\ + .align 4\n\ +.globl _fini\n\ + .type _fini,@function\n\ +_fini:\n\ +# leaf function 0\n\ +# automatics 0\n\ +# outgoing args 0\n\ +# need frame pointer 0\n\ +# call alloca 0\n\ +# has varargs 0\n\ +# incoming args (stack) 0\n\ +# function length 30\n\ + STMG 6,15,48(15)\n\ + LGR 1,15\n\ + AGHI 15,-160\n\ + STG 1,0(15)\n\ + LARL 12,_GLOBAL_OFFSET_TABLE_\n\ +#APP\n\ + .align 4,0x07\n\ + END_FINI\n\ +\n\ +/*@_fini_PROLOG_ENDS*/\n\ +\n\ +/*@_fini_EPILOG_BEGINS*/\n\ + .align 4\n\ + .section .fini\n\ +#NO_APP\n\ + .align 4\n\ + LG 4,272(15)\n\ + LMG 6,15,208(15)\n\ + BR 4\n\ +#APP\n\ + END_FINI\n\ +\n\ +/*@_fini_EPILOG_ENDS*/\n\ +\n\ +/*@TRAILER_BEGINS*/\n\ + "); diff --git a/linuxthreads/sysdeps/unix/sysv/linux/s390/s390-64/pt-sigsuspend.c b/linuxthreads/sysdeps/unix/sysv/linux/s390/s390-64/pt-sigsuspend.c new file mode 100644 index 0000000000..d57283ad23 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/s390/s390-64/pt-sigsuspend.c @@ -0,0 +1 @@ +#include "../../ia64/pt-sigsuspend.c" diff --git a/linuxthreads/sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h b/linuxthreads/sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h new file mode 100644 index 0000000000..f71ef3f689 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h @@ -0,0 +1,116 @@ +/* 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 <sysdep.h> +#include <tls.h> +#ifndef __ASSEMBLER__ +# include <linuxthreads/internals.h> +#endif + +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt + +# undef PSEUDO +# define PSEUDO(name, syscall_name, args) \ + .text; \ +L(pseudo_cancel): \ + STM_##args \ + stmg %r13,%r15,104(%r15); \ + lgr %r14,%r15; \ + aghi %r15,-160; \ + stg %r14,0(%r15); \ + brasl %r14,CENABLE; \ + lgr %r0,%r2; \ + LM_##args \ + DO_CALL(syscall_name, args); \ + lgr %r13,%r2; \ + lgr %r2,%r0; \ + brasl %r14,CDISABLE; \ + lgr %r2,%r13; \ + lmg %r13,%r15,104+160(%r15); \ + j L(pseudo_check); \ +ENTRY(name) \ + SINGLE_THREAD_P \ + jne L(pseudo_cancel); \ + DO_CALL(syscall_name, args); \ +L(pseudo_check): \ + lghi %r4,-4095; \ + clgr %r2,%r4; \ + jgnl SYSCALL_ERROR_LABEL; \ +L(pseudo_end): + +# ifdef IS_IN_libpthread +# define CENABLE __pthread_enable_asynccancel +# define CDISABLE __pthread_disable_asynccancel +# define __local_multiple_threads __pthread_multiple_threads +# elif !defined NOT_IN_libc +# define CENABLE __libc_enable_asynccancel +# define CDISABLE __libc_disable_asynccancel +# define __local_multiple_threads __libc_multiple_threads +# else +# define CENABLE __librt_enable_asynccancel@PLT +# define CDISABLE __librt_disable_asynccancel@PLT +# endif + +#define STM_0 /* Nothing */ +#define STM_1 stg %r2,16(%r15); +#define STM_2 stmg %r2,%r3,16(%r15); +#define STM_3 stmg %r2,%r4,16(%r15); +#define STM_4 stmg %r2,%r5,16(%r15); +#define STM_5 stmg %r2,%r5,16(%r15); + +#define LM_0 /* Nothing */ +#define LM_1 lg %r2,16+160(%r15); +#define LM_2 lmg %r2,%r3,16+160(%r15); +#define LM_3 lmg %r2,%r4,16+160(%r15); +#define LM_4 lmg %r2,%r5,16+160(%r15); +#define LM_5 lmg %r2,%r5,16+160(%r15); + +# if !defined NOT_IN_libc || defined IS_IN_libpthread +# 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 \ + larl %r1,__local_multiple_threads; \ + icm %r0,15,0(%r1); +# endif + +# else + +# ifndef __ASSEMBLER__ +# define SINGLE_THREAD_P \ + __builtin_expect (THREAD_GETMEM (THREAD_SELF, \ + p_header.data.multiple_threads) == 0, 1) +# else +# define SINGLE_THREAD_P \ + ear %r1,%a0; \ + sllg %r1,%r1,32; \ + ear %r1,%a1; \ + icm %r1,15,MULTIPLE_THREADS_OFFSET(%r1); +# endif + +# endif + +#elif !defined __ASSEMBLER__ + +/* This code should never be used but we define it anyhow. */ +# define SINGLE_THREAD_P (1) + +#endif diff --git a/linuxthreads/sysdeps/unix/sysv/linux/s390/s390-64/vfork.S b/linuxthreads/sysdeps/unix/sysv/linux/s390/s390-64/vfork.S new file mode 100644 index 0000000000..199f0017ff --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/s390/s390-64/vfork.S @@ -0,0 +1,54 @@ +/* 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. */ + +#include <sysdep-cancel.h> +#define _ERRNO_H 1 +#include <bits/errno.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) +#ifdef SHARED + larl %r1,__libc_pthread_functions + lg %r1,0(%r1) +#else + .weak pthread_create + larl %r1,pthread_create +#endif + ltgr %r1,%r1 + jgne HIDDEN_JUMPTARGET(__fork) + + /* Do vfork system call. */ + svc SYS_ify (vfork) + + /* Check for error. */ + lghi %r4,-4095 + clgr %r2,%r4 + jgnl SYSCALL_ERROR_LABEL + + /* Normal return. */ + br %r14 +PSEUDO_END(__vfork) + +libc_hidden_def (__vfork) + +weak_alias (__vfork, vfork) diff --git a/linuxthreads/sysdeps/unix/sysv/linux/sh/pt-initfini.c b/linuxthreads/sysdeps/unix/sysv/linux/sh/pt-initfini.c new file mode 100644 index 0000000000..1cdb98f0f7 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/sh/pt-initfini.c @@ -0,0 +1,143 @@ +/* Special .init and .fini section support for SH. Linuxthread version. + Copyright (C) 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. + + 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 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.) + + The GNU C Library is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General 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. */ + +__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@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/linuxthreads/sysdeps/unix/sysv/linux/sh/smp.h b/linuxthreads/sysdeps/unix/sysv/linux/sh/smp.h new file mode 100644 index 0000000000..2c0cbe99ac --- /dev/null +++ b/linuxthreads/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/linuxthreads/sysdeps/unix/sysv/linux/sh/sysdep-cancel.h b/linuxthreads/sysdeps/unix/sysv/linux/sh/sysdep-cancel.h new file mode 100644 index 0000000000..03c6fedbfe --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/sh/sysdep-cancel.h @@ -0,0 +1,227 @@ +/* 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 <tls.h> +#include <pt-machine.h> +#ifndef __ASSEMBLER__ +# include <linuxthreads/internals.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); \ + SINGLE_THREAD_P; \ + bf .Lpseudo_cancel; \ + 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; \ + .Lpseudo_cancel: \ + sts.l pr,@-r15; \ + add _IMM16,r15; \ + SAVE_ARGS_##args; \ + CENABLE; \ + LOAD_ARGS_##args; \ + add _IMP16,r15; \ + lds.l @r15+,pr; \ + DO_CALL(syscall_name, args); \ + SYSCALL_INST_PAD; \ + sts.l pr,@-r15; \ + mov.l r0,@-r15; \ + CDISABLE; \ + mov.l @r15+,r0; \ + lds.l @r15+,pr; \ + mov r0,r1; \ + mov _IMM12,r2; \ + shad r2,r1; \ + not r1,r1; \ + tst r1,r1; \ + bf .Lpseudo_end; \ + .Lsyscall_error: \ + SYSCALL_ERROR_HANDLER; \ + .Lpseudo_end: + +# undef PSEUDO_END +# define PSEUDO_END(sym) \ + END (sym) + +# define SAVE_ARGS_0 /* Nothing. */ +# define SAVE_ARGS_1 SAVE_ARGS_0; mov.l r4,@(0,r15) +# 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 +# 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 +# else +# define __local_enable_asynccancel __librt_enable_asynccancel +# define __local_disable_asynccancel __librt_disable_asynccancel +# define __local_multiple_threads __librt_multiple_threads +# endif + +# if defined IS_IN_librt && defined PIC +# define CENABLE \ + mov.l r12,@-r15; \ + mov.l 1f,r12; \ + mova 1f,r0; \ + add r0,r12; \ + mov.l 2f,r0; \ + bsrf r0; \ + nop; \ + 0: bra 3f; \ + mov r0,r2; \ + .align 2; \ + 1: .long _GLOBAL_OFFSET_TABLE_; \ + 2: .long __local_enable_asynccancel@PLT - (0b-.); \ + 3: mov.l @r15+,r12 + +# define CDISABLE \ + mov.l r12,@-r15; \ + mov.l 1f,r12; \ + mova 1f,r0; \ + add r0,r12; \ + mov.l 2f,r0; \ + bsrf r0; \ + mov r2,r4; \ + 0: bra 3f; \ + nop; \ + .align 2; \ + 1: .long _GLOBAL_OFFSET_TABLE_; \ + 2: .long __local_disable_asynccancel@PLT - (0b-.); \ + 3: mov.l @r15+,r12 +# else +# 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: +# endif + +# ifndef __ASSEMBLER__ +# if defined FLOATING_STACKS && USE___THREAD && defined PIC +# define SINGLE_THREAD_P \ + __builtin_expect (THREAD_GETMEM (THREAD_SELF, p_multiple_threads) == 0, 1) +# else +extern int __local_multiple_threads attribute_hidden; +# define SINGLE_THREAD_P __builtin_expect (__local_multiple_threads == 0, 1) +# endif +# else +# if !defined PIC +# define SINGLE_THREAD_P \ + mov.l 1f,r0; \ + mov.l @r0,r0; \ + bra 2f; \ + tst r0,r0; \ + .align 2; \ + 1: .long __local_multiple_threads; \ + 2: +# elif defined FLOATING_STACKS && USE___THREAD +# 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: + +# else +# if !defined NOT_IN_libc || defined IS_IN_libpthread +# define SINGLE_THREAD_P \ + 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; \ + bra 2f; \ + tst r0,r0; \ + .align 2; \ + 0: .long _GLOBAL_OFFSET_TABLE_; \ + 1: .long __local_multiple_threads@GOTOFF; \ + 2: +# else +# define SINGLE_THREAD_P \ + mov r12,r2; \ + mov.l 0f,r12; \ + mova 0f,r0; \ + add r0,r12; \ + mov.l 1f,r0; \ + mov.l @(r0,r12),r0; \ + mov.l @r0,r0; \ + mov r2,r12; \ + bra 2f; \ + tst r0,r0; \ + .align 2; \ + 0: .long _GLOBAL_OFFSET_TABLE_; \ + 1: .long __local_multiple_threads@GOT; \ + 2: +# endif +# endif +# endif + +#elif !defined __ASSEMBLER__ + +/* This code should never be used but we define it anyhow. */ +# define SINGLE_THREAD_P (1) + +#endif diff --git a/linuxthreads/sysdeps/unix/sysv/linux/sh/vfork.S b/linuxthreads/sysdeps/unix/sysv/linux/sh/vfork.S new file mode 100644 index 0000000000..f230c01226 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/sh/vfork.S @@ -0,0 +1,77 @@ +/* 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-cancel.h> +#define _ERRNO_H 1 +#include <bits/errno.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) +#ifdef SHARED + mov.l .Lgot, r1 + mova .Lgot, r0 + add r0, r1 + mov.l .Lpthread_func, r0 + mov.l @(r0,r1), r0 +#else + mov.l .Lpthread_create, r0 +#endif + tst r0, r0 + bf .Lhidden_fork + + mov.w .L1, r3 + trapa #0x10 + mov r0, r1 + 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 + .align 2 +#ifdef SHARED +.Lgot: + .long _GLOBAL_OFFSET_TABLE_ +.Lpthread_func: + .long __libc_pthread_functions@GOTOFF +#else +.Lpthread_create: + .weak pthread_create + .long pthread_create +#endif + +.Lhidden_fork: + mov.l .L2, r1 + braf r1 + nop +1: + .align 2 +.L2: .long HIDDEN_JUMPTARGET(__fork)-1b + +PSEUDO_END (__vfork) +libc_hidden_def (__vfork) + +weak_alias (__vfork, vfork) diff --git a/linuxthreads/sysdeps/unix/sysv/linux/sigwait.c b/linuxthreads/sysdeps/unix/sysv/linux/sigwait.c new file mode 100644 index 0000000000..fdec09455a --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/sigwait.c @@ -0,0 +1,88 @@ +/* Copyright (C) 1997, 1998, 2000, 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 <errno.h> +#include <signal.h> +#define __need_NULL +#include <stddef.h> + +#include <sysdep-cancel.h> +#include <sys/syscall.h> +#include <bp-checks.h> +#include <bits/libc-lock.h> + +extern int __syscall_rt_sigtimedwait (const sigset_t *__unbounded, siginfo_t *__unbounded, + const struct timespec *__unbounded, size_t); + + +/* Return any pending signal or wait for one for the given time. */ +static inline int +do_sigwait (const sigset_t *set, int *sig) +{ + int ret; + + /* XXX The size argument hopefully will have to be changed to the + real size of the user-level sigset_t. */ +#ifdef INTERNAL_SYSCALL + INTERNAL_SYSCALL_DECL (err); + ret = INTERNAL_SYSCALL (rt_sigtimedwait, err, 4, CHECK_SIGSET (set), + NULL, NULL, _NSIG / 8); + if (! INTERNAL_SYSCALL_ERROR_P (ret, err)) + { + *sig = ret; + ret = 0; + } + else + ret = INTERNAL_SYSCALL_ERRNO (ret, err); +#else + ret = INLINE_SYSCALL (rt_sigtimedwait, 4, CHECK_SIGSET (set), + NULL, NULL, _NSIG / 8); + if (ret != -1) + { + *sig = ret; + ret = 0; + } + else + ret = errno; +#endif + + return ret; +} + +#ifndef SHARED +weak_extern (__pthread_sigwait) +#endif + +int +__sigwait (set, sig) + const sigset_t *set; + int *sig; +{ +#ifndef NOT_IN_libc + return __libc_maybe_call2 (pthread_sigwait, (set, sig), + do_sigwait (set, sig)); +#else + return do_sigwait (set, sig); +#endif +} +libc_hidden_def (__sigwait) +weak_alias (__sigwait, sigwait) +strong_alias (__sigwait, __libc_sigwait) + +/* Cancellation is handled in __pthread_sigwait. */ +LIBC_CANCEL_HANDLED (); diff --git a/linuxthreads/sysdeps/unix/sysv/linux/smp.h b/linuxthreads/sysdeps/unix/sysv/linux/smp.h new file mode 100644 index 0000000000..81289294b4 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/smp.h @@ -0,0 +1,48 @@ +/* Determine whether the host has multiple processors. Linux version. + Copyright (C) 1996, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU 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 <sys/sysctl.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 ("/proc/sys/kernel/version", O_RDONLY); + if (__builtin_expect (fd, 0) == -1 + || (reslen = __read (fd, buf, sizeof (buf))) <= 0) + /* This also didn't work. We give up and say it's a UP machine. */ + buf[0] = '\0'; + + __close (fd); + } + + return strstr (buf, "SMP") != NULL; +} diff --git a/linuxthreads/sysdeps/unix/sysv/linux/sparc/Versions b/linuxthreads/sysdeps/unix/sysv/linux/sparc/Versions new file mode 100644 index 0000000000..d102772482 --- /dev/null +++ b/linuxthreads/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/linuxthreads/sysdeps/unix/sysv/linux/sparc/aio_cancel.c b/linuxthreads/sysdeps/unix/sysv/linux/sparc/aio_cancel.c new file mode 100644 index 0000000000..0d6da82919 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/sparc/aio_cancel.c @@ -0,0 +1,33 @@ +#include <shlib-compat.h> + +#define aio_cancel64 XXX +#include <aio.h> +#undef aio_cancel64 +#include <errno.h> + +extern __typeof (aio_cancel) __new_aio_cancel; +extern __typeof (aio_cancel) __old_aio_cancel; + +#define aio_cancel __new_aio_cancel + +#include <sysdeps/pthread/aio_cancel.c> + +#undef aio_cancel +strong_alias (__new_aio_cancel, __new_aio_cancel64); +versioned_symbol (librt, __new_aio_cancel, aio_cancel, GLIBC_2_3); +versioned_symbol (librt, __new_aio_cancel64, aio_cancel64, GLIBC_2_3); + +#if SHLIB_COMPAT (librt, GLIBC_2_1, GLIBC_2_3) + +#undef ECANCELED +#define aio_cancel __old_aio_cancel +#define ECANCELED 125 + +#include <sysdeps/pthread/aio_cancel.c> + +#undef aio_cancel +strong_alias (__old_aio_cancel, __old_aio_cancel64); +compat_symbol (librt, __old_aio_cancel, aio_cancel, GLIBC_2_1); +compat_symbol (librt, __old_aio_cancel64, aio_cancel64, GLIBC_2_1); + +#endif diff --git a/linuxthreads/sysdeps/unix/sysv/linux/sparc/bits/local_lim.h b/linuxthreads/sysdeps/unix/sysv/linux/sparc/bits/local_lim.h new file mode 100644 index 0000000000..27ffa668f4 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/sparc/bits/local_lim.h @@ -0,0 +1,92 @@ +/* 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 Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General 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 +/* This is the value this implementation supports. */ +#define PTHREAD_THREADS_MAX 16384 + +/* 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 POSIX timers available. */ +#define TIMER_MAX 256 + +/* 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/linuxthreads/sysdeps/unix/sysv/linux/sparc/bits/typesizes.h b/linuxthreads/sysdeps/unix/sysv/linux/sparc/bits/typesizes.h new file mode 100644 index 0000000000..7e4253789c --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/sparc/bits/typesizes.h @@ -0,0 +1,66 @@ +/* bits/typesizes.h -- underlying types for *_t. Linux/SPARC version. + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _BITS_TYPES_H +# error "Never include <bits/typesizes.h> directly; use <sys/types.h> instead." +#endif + +#ifndef _BITS_TYPESIZES_H +#define _BITS_TYPESIZES_H 1 + +/* See <bits/types.h> for the meaning of these macros. This file exists so + that <bits/types.h> need not vary across different GNU platforms. */ + +#define __DEV_T_TYPE __UQUAD_TYPE +#define __UID_T_TYPE __U32_TYPE +#define __GID_T_TYPE __U32_TYPE +#define __INO_T_TYPE __ULONGWORD_TYPE +#define __INO64_T_TYPE __UQUAD_TYPE +#define __MODE_T_TYPE __U32_TYPE +#define __NLINK_T_TYPE __U32_TYPE +#define __OFF_T_TYPE __SLONGWORD_TYPE +#define __OFF64_T_TYPE __SQUAD_TYPE +#define __PID_T_TYPE __S32_TYPE +#define __RLIM_T_TYPE __ULONGWORD_TYPE +#define __RLIM64_T_TYPE __UQUAD_TYPE +#define __BLKCNT_T_TYPE __SLONGWORD_TYPE +#define __BLKCNT64_T_TYPE __SQUAD_TYPE +#define __FSBLKCNT_T_TYPE __ULONGWORD_TYPE +#define __FSBLKCNT64_T_TYPE __UQUAD_TYPE +#define __FSFILCNT_T_TYPE __ULONGWORD_TYPE +#define __FSFILCNT64_T_TYPE __UQUAD_TYPE +#define __ID_T_TYPE __U32_TYPE +#define __CLOCK_T_TYPE __SLONGWORD_TYPE +#define __TIME_T_TYPE __SLONGWORD_TYPE +#define __USECONDS_T_TYPE __U32_TYPE +#define __SUSECONDS_T_TYPE __S32_TYPE +#define __DADDR_T_TYPE __S32_TYPE +#define __SWBLK_T_TYPE __SLONGWORD_TYPE +#define __KEY_T_TYPE __S32_TYPE +#define __CLOCKID_T_TYPE __S32_TYPE +#define __TIMER_T_TYPE __S32_TYPE +#define __BLKSIZE_T_TYPE __SLONGWORD_TYPE +#define __FSID_T_TYPE struct { int __val[2]; } +#define __SSIZE_T_TYPE __SWORD_TYPE + +/* Number of descriptors that can fit in an `fd_set'. */ +#define __FD_SETSIZE 1024 + + +#endif /* bits/typesizes.h */ diff --git a/linuxthreads/sysdeps/unix/sysv/linux/sparc/fork.h b/linuxthreads/sysdeps/unix/sysv/linux/sparc/fork.h new file mode 100644 index 0000000000..793cb1d5f9 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/sparc/fork.h @@ -0,0 +1,34 @@ +/* Copyright (C) 2002 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> + +#define ARCH_FORK() \ +({ \ + register long __o0 __asm__ ("o0"); \ + register long __o1 __asm__ ("o1"); \ + register long __g1 __asm__ ("g1") = __NR_fork; \ + __asm __volatile (__SYSCALL_STRING \ + : "=r" (__g1), "=r" (__o0), "=r" (__o1) \ + : "0" (__g1) \ + : __SYSCALL_CLOBBERS); \ + __o0 == -1 ? __o0 : (__o0 & (__o1 - 1)); \ +}) + +#include_next <fork.h> diff --git a/linuxthreads/sysdeps/unix/sysv/linux/sparc/sparc32/sysdep-cancel.h b/linuxthreads/sysdeps/unix/sysv/linux/sparc/sparc32/sysdep-cancel.h new file mode 100644 index 0000000000..dd3f52a989 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/sparc/sparc32/sysdep-cancel.h @@ -0,0 +1,102 @@ +/* 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 <sysdep.h> +#include <tls.h> +#ifndef __ASSEMBLER__ +# include <linuxthreads/internals.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) \ + ld [%g7 + MULTIPLE_THREADS_OFFSET], %g1; \ + cmp %g1, 0; \ + bne 1f; \ + mov SYS_ify(syscall_name), %g1; \ + ta 0x10; \ + bcs __syscall_error_handler; \ + nop; \ + .subsection 2; \ +1: save %sp, -96, %sp; \ + CENABLE; \ + nop; \ + mov %o0, %l0; \ + COPY_ARGS_##args \ + mov SYS_ify(syscall_name), %g1; \ + ta 0x10; \ + bcs __syscall_error_handler2; \ + mov %o0, %l1; \ + CDISABLE; \ + mov %l0, %o0; \ + jmpl %i7 + 8, %g0; \ + restore %g0, %l1, %o0; \ + .previous; \ + SYSCALL_ERROR_HANDLER \ + SYSCALL_ERROR_HANDLER2 + +#define SYSCALL_ERROR_HANDLER2 \ +SYSCALL_ERROR_HANDLER_ENTRY(__syscall_error_handler2) \ + .global __errno_location; \ + .type __errno_location,@function; \ + CDISABLE; \ + mov %l0, %o0; \ + call __errno_location; \ + nop; \ + st %l1, [%o0]; \ + jmpl %i7 + 8, %g0; \ + restore %g0, -1, %o0; \ + .previous; + +# 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 +# else +# define CENABLE call __librt_enable_asynccancel +# define CDISABLE call __librt_disable_asynccancel +# 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, \ + p_header.data.multiple_threads) == 0, 1) +# else +# define SINGLE_THREAD_P ld [%g7 + MULTIPLE_THREADS_OFFSET], %g1 +# endif + +#elif !defined __ASSEMBLER__ + +/* This code should never be used but we define it anyhow. */ +# define SINGLE_THREAD_P (1) + +#endif diff --git a/linuxthreads/sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S b/linuxthreads/sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S new file mode 100644 index 0000000000..132da67a14 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S @@ -0,0 +1,65 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep-cancel.h> + + .text +#ifdef SHARED +.LLGETPC0: + retl + add %o7, %o0, %o0 +#endif +ENTRY(__vfork) +#ifdef SHARED + mov %o7, %o1 + sethi %hi(_GLOBAL_OFFSET_TABLE_-4), %o0 + call .LLGETPC0 + add %o0, %lo(_GLOBAL_OFFSET_TABLE_+4), %o0 + sethi %hi(__libc_pthread_functions), %o2 + mov %o1, %o7 + or %o2, %lo(__libc_pthread_functions), %o2 + ld [%o0 + %o2], %o2 + ld [%o2], %o2 + cmp %o2, 0 +#else + .weak pthread_create + sethi %hi(pthread_create), %o0 + orcc %o0, %lo(pthread_create), %o0 +#endif +#if defined SHARED && !defined BROKEN_SPARC_WDISP22 + bne HIDDEN_JUMPTARGET(__fork) +#else + bne 1f +#endif + mov __NR_vfork, %g1 + ta 0x10 + bcs __syscall_error_handler + nop + sub %o1, 1, %o1 + retl + and %o0, %o1, %o0 +#if !defined SHARED || defined BROKEN_SPARC_WDISP22 +1: mov %o7, %g1 + call HIDDEN_JUMPTARGET(__fork) + mov %g1, %o7 +#endif + SYSCALL_ERROR_HANDLER +PSEUDO_END (__vfork) +libc_hidden_def (__vfork) +weak_alias (__vfork, vfork) diff --git a/linuxthreads/sysdeps/unix/sysv/linux/sparc/sparc64/Makefile b/linuxthreads/sysdeps/unix/sysv/linux/sparc/sparc64/Makefile new file mode 100644 index 0000000000..90203051ae --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/sparc/sparc64/Makefile @@ -0,0 +1,5 @@ +# glibc makefile fragment for linuxthreads on sparc/sparc64. + +ifeq ($(subdir),linuxthreads) +libpthread-routines += ptw-sigprocmask +endif diff --git a/linuxthreads/sysdeps/unix/sysv/linux/sparc/sparc64/pt-sigsuspend.c b/linuxthreads/sysdeps/unix/sysv/linux/sparc/sparc64/pt-sigsuspend.c new file mode 100644 index 0000000000..d57283ad23 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/sparc/sparc64/pt-sigsuspend.c @@ -0,0 +1 @@ +#include "../../ia64/pt-sigsuspend.c" diff --git a/linuxthreads/sysdeps/unix/sysv/linux/sparc/sparc64/sysdep-cancel.h b/linuxthreads/sysdeps/unix/sysv/linux/sparc/sparc64/sysdep-cancel.h new file mode 100644 index 0000000000..80834292e5 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/sparc/sparc64/sysdep-cancel.h @@ -0,0 +1,101 @@ +/* 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 <sysdep.h> +#include <tls.h> +#ifndef __ASSEMBLER__ +# include <linuxthreads/internals.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) \ + ld [%g7 + MULTIPLE_THREADS_OFFSET], %g1; \ + brnz,pn %g1, 1f; \ + mov SYS_ify(syscall_name), %g1; \ + ta 0x6d; \ + bcs,pn %xcc, __syscall_error_handler; \ + nop; \ + .subsection 2; \ +1: save %sp, -192, %sp; \ + CENABLE; \ + nop; \ + mov %o0, %l0; \ + COPY_ARGS_##args \ + mov SYS_ify(syscall_name), %g1; \ + ta 0x6d; \ + bcs,pn %xcc, __syscall_error_handler2; \ + mov %o0, %l1; \ + CDISABLE; \ + mov %l0, %o0; \ + jmpl %i7 + 8, %g0; \ + restore %g0, %l1, %o0; \ + .previous; \ + SYSCALL_ERROR_HANDLER \ + SYSCALL_ERROR_HANDLER2 + +#define SYSCALL_ERROR_HANDLER2 \ +SYSCALL_ERROR_HANDLER_ENTRY(__syscall_error_handler2) \ + .global __errno_location; \ + .type __errno_location,@function; \ + CDISABLE; \ + mov %l0, %o0; \ + call __errno_location; \ + nop; \ + st %l1, [%o0]; \ + jmpl %i7 + 8, %g0; \ + restore %g0, -1, %o0; \ + .previous; + +# 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 +# else +# define CENABLE call __librt_enable_asynccancel +# define CDISABLE call __librt_disable_asynccancel +# 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, \ + p_header.data.multiple_threads) == 0, 1) +# else +# define SINGLE_THREAD_P ld [%g7 + MULTIPLE_THREADS_OFFSET], %g1 +# endif + +#elif !defined __ASSEMBLER__ + +/* This code should never be used but we define it anyhow. */ +# define SINGLE_THREAD_P (1) + +#endif diff --git a/linuxthreads/sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S b/linuxthreads/sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S new file mode 100644 index 0000000000..8a6d2771e8 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S @@ -0,0 +1,64 @@ +/* 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 <sysdep-cancel.h> + +#ifdef SHARED +.LLGETPC0: + retl + add %o7, %o0, %o0 +#endif +ENTRY(__vfork) +#ifdef SHARED + mov %o7, %o1 + sethi %hi(_GLOBAL_OFFSET_TABLE_-4), %o0 + call .LLGETPC0 + add %o0, %lo(_GLOBAL_OFFSET_TABLE_+4), %o0 + sethi %hi(__libc_pthread_functions), %o2 + mov %o1, %o7 + or %o2, %lo(__libc_pthread_functions), %o2 + ldx [%o0 + %o2], %o2 + ldx [%o2], %o0 +#else + .weak pthread_create + sethi %hi(pthread_create), %o0 + or %o0, %lo(pthread_create), %o0 +#endif +#if defined SHARED && !defined BROKEN_SPARC_WDISP22 + cmp %o0, 0 + bne HIDDEN_JUMPTARGET(__fork) +#else + brnz,pn %o0, 1f +#endif + mov __NR_vfork, %g1 + ta 0x6d + bcs,pn %xcc, __syscall_error_handler + nop + sub %o1, 1, %o1 + retl + and %o0, %o1, %o0 +#if !defined SHARED || defined BROKEN_SPARC_WDISP22 +1: mov %o7, %g1 + call HIDDEN_JUMPTARGET(__fork) + mov %g1, %o7 +#endif + SYSCALL_ERROR_HANDLER +PSEUDO_END (__vfork) +libc_hidden_def (__vfork) +weak_alias (__vfork, vfork) diff --git a/linuxthreads/sysdeps/unix/sysv/linux/unregister-atfork.c b/linuxthreads/sysdeps/unix/sysv/linux/unregister-atfork.c new file mode 100644 index 0000000000..dad273fdf5 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/unregister-atfork.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 <stdlib.h> +#include "fork.h" + + +void +__unregister_atfork (dso_handle) + void *dso_handle; +{ + /* Get the lock to not conflict with running forks. */ + __libc_lock_lock (__fork_block.lock); + + list_t *runp; + list_t *prevp; + + list_for_each_prev_safe (runp, prevp, &__fork_block.prepare_list) + if (list_entry (runp, struct fork_handler, list)->dso_handle == dso_handle) + list_del (runp); + + list_for_each_prev_safe (runp, prevp, &__fork_block.parent_list) + if (list_entry (runp, struct fork_handler, list)->dso_handle == dso_handle) + list_del (runp); + + list_for_each_prev_safe (runp, prevp, &__fork_block.child_list) + if (list_entry (runp, struct fork_handler, list)->dso_handle == dso_handle) + list_del (runp); + + /* Release the lock. */ + __libc_lock_unlock (__fork_block.lock); +} diff --git a/linuxthreads/sysdeps/unix/sysv/linux/x86_64/Makefile b/linuxthreads/sysdeps/unix/sysv/linux/x86_64/Makefile new file mode 100644 index 0000000000..b5e5d5d480 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/x86_64/Makefile @@ -0,0 +1,4 @@ +ifeq ($(subdir),linuxthreads) +CFLAGS-pt-initfini.s = -g0 -fPIC -fno-inline-functions \ + -fno-asynchronous-unwind-tables $(fno-unit-at-a-time) +endif diff --git a/linuxthreads/sysdeps/unix/sysv/linux/x86_64/pt-sigsuspend.c b/linuxthreads/sysdeps/unix/sysv/linux/x86_64/pt-sigsuspend.c new file mode 100644 index 0000000000..3a0c2afc0f --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/x86_64/pt-sigsuspend.c @@ -0,0 +1 @@ +#include "../ia64/pt-sigsuspend.c" diff --git a/linuxthreads/sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h b/linuxthreads/sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h new file mode 100644 index 0000000000..742dbeb0de --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h @@ -0,0 +1,132 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <tls.h> +#include <pt-machine.h> +#ifndef __ASSEMBLER__ +# include <linuxthreads/internals.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) \ + SINGLE_THREAD_P; \ + jne L(pseudo_cancel); \ + DO_CALL (syscall_name, args); \ + cmpq $-4095, %rax; \ + jae SYSCALL_ERROR_LABEL; \ + ret; \ + L(pseudo_cancel): \ + /* Save registers that might get destroyed. */ \ + SAVESTK_##args \ + PUSHARGS_##args \ + CENABLE \ + /* Restore registers. */ \ + POPARGS_##args \ + /* The return value from CENABLE is argument for CDISABLE. */ \ + movq %rax, (%rsp); \ + movq $SYS_ify (syscall_name), %rax; \ + syscall; \ + movq (%rsp), %rdi; \ + /* Save %rax since it's the error code from the syscall. */ \ + movq %rax, 8(%rsp); \ + CDISABLE \ + movq 8(%rsp), %rax; \ + RESTSTK_##args \ + cmpq $-4095, %rax; \ + jae SYSCALL_ERROR_LABEL; \ + L(pseudo_end): + +# define PUSHARGS_0 /* Nothing. */ +# define PUSHARGS_1 PUSHARGS_0 movq %rdi, 8(%rsp); +# define PUSHARGS_2 PUSHARGS_1 movq %rsi, 16(%rsp); +# define PUSHARGS_3 PUSHARGS_2 movq %rdx, 24(%rsp); +# define PUSHARGS_4 PUSHARGS_3 movq %rcx, 32(%rsp); +# define PUSHARGS_5 PUSHARGS_4 movq %r8, 40(%rsp); +# define PUSHARGS_6 PUSHARGS_5 movq %r9, 48(%rsp); + +# define POPARGS_0 /* Nothing. */ +# define POPARGS_1 POPARGS_0 movq 8(%rsp), %rdi; +# define POPARGS_2 POPARGS_1 movq 16(%rsp), %rsi; +# define POPARGS_3 POPARGS_2 movq 24(%rsp), %rdx; +# define POPARGS_4 POPARGS_3 movq 32(%rsp), %r10; +# define POPARGS_5 POPARGS_4 movq 40(%rsp), %r8; +# define POPARGS_6 POPARGS_5 movq 48(%rsp), %r9; + +/* We always have to align the stack before calling a function. */ +# define SAVESTK_0 subq $24, %rsp;cfi_adjust_cfa_offset(24); +# define SAVESTK_1 SAVESTK_0 +# define SAVESTK_2 SAVESTK_1 +# define SAVESTK_3 subq $40, %rsp;cfi_adjust_cfa_offset(40); +# define SAVESTK_4 SAVESTK_3 +# define SAVESTK_5 subq $56, %rsp;cfi_adjust_cfa_offset(56); +# define SAVESTK_6 SAVESTK_5 + +# define RESTSTK_0 addq $24,%rsp;cfi_adjust_cfa_offset(-24); +# define RESTSTK_1 RESTSTK_0 +# define RESTSTK_2 RESTSTK_1 +# define RESTSTK_3 addq $40, %rsp;cfi_adjust_cfa_offset(-40); +# define RESTSTK_4 RESTSTK_3 +# define RESTSTK_5 addq $56, %rsp;cfi_adjust_cfa_offset(-56); +# define RESTSTK_6 RESTSTK_5 + +# 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 +# else +# define CENABLE call __librt_enable_asynccancel@plt; +# define CDISABLE call __librt_disable_asynccancel@plt; +# 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, \ + p_header.data.multiple_threads) == 0, 1) +# else +# define SINGLE_THREAD_P cmpl $0, %fs:MULTIPLE_THREADS_OFFSET +# endif + +# endif + +#elif !defined __ASSEMBLER__ + +/* This code should never be used but we define it anyhow. */ +# define SINGLE_THREAD_P (1) + +#endif diff --git a/linuxthreads/sysdeps/unix/sysv/linux/x86_64/vfork.S b/linuxthreads/sysdeps/unix/sysv/linux/x86_64/vfork.S new file mode 100644 index 0000000000..25d1d3f96a --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/x86_64/vfork.S @@ -0,0 +1,62 @@ +/* Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep-cancel.h> +#define _ERRNO_H 1 +#include <bits/errno.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) + +#ifdef SHARED + cmpq $0, __libc_pthread_functions(%rip) +#else + .weak pthread_create + movq $pthread_create, %rax + testq %rax, %rax +#endif + jne HIDDEN_JUMPTARGET (__fork) + + /* Pop the return PC value into RDI. We need a register that + is preserved by the syscall and that we're allowed to destroy. */ + popq %rdi + cfi_adjust_cfa_offset(-8) + + /* Stuff the syscall number in RAX and enter into the kernel. */ + movl $SYS_ify (vfork), %eax + syscall + + /* Push back the return PC. */ + pushq %rdi + cfi_adjust_cfa_offset(8) + + cmpl $-4095, %eax + jae SYSCALL_ERROR_LABEL /* Branch forward if it failed. */ + + /* Normal return. */ +.Lpseudo_end: + ret + +PSEUDO_END (__vfork) +libc_hidden_def (__vfork) + +weak_alias (__vfork, vfork) diff --git a/linuxthreads/sysdeps/x86_64/Makefile b/linuxthreads/sysdeps/x86_64/Makefile new file mode 100644 index 0000000000..81bddf688c --- /dev/null +++ b/linuxthreads/sysdeps/x86_64/Makefile @@ -0,0 +1,3 @@ +ifeq ($(subdir),csu) +gen-as-const-headers += tcb-offsets.sym +endif diff --git a/linuxthreads/sysdeps/x86_64/Versions b/linuxthreads/sysdeps/x86_64/Versions new file mode 100644 index 0000000000..32da57080d --- /dev/null +++ b/linuxthreads/sysdeps/x86_64/Versions @@ -0,0 +1,5 @@ +libpthread { + GLIBC_PRIVATE { + __pthread_clock_gettime; __pthread_clock_settime; + } +} diff --git a/linuxthreads/sysdeps/x86_64/pspinlock.c b/linuxthreads/sysdeps/x86_64/pspinlock.c new file mode 100644 index 0000000000..e1b2a66841 --- /dev/null +++ b/linuxthreads/sysdeps/x86_64/pspinlock.c @@ -0,0 +1,97 @@ +/* POSIX spinlock implementation. x86-64 version. + Copyright (C) 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include "internals.h" + +/* This implementation is similar to the one used in the Linux kernel. + But the kernel is byte instructions for the memory access. This is + faster but unusable here. The problem is that only 128 + threads/processes could use the spinlock at the same time. If (by + a design error in the program) a thread/process would hold the + spinlock for a time long enough to accumulate 128 waiting + processes, the next one will find a positive value in the spinlock + and assume it is unlocked. We cannot accept that. */ + +int +__pthread_spin_lock (pthread_spinlock_t *lock) +{ + asm volatile + ("\n" + "1:\n\t" + "lock; decl %0\n\t" + "js 2f\n\t" + ".section .text.spinlock,\"ax\"\n" + "2:\n\t" + "cmpl $0,%0\n\t" + "rep; nop\n\t" + "jle 2b\n\t" + "jmp 1b\n\t" + ".previous" + : "=m" (*lock)); + return 0; +} +weak_alias (__pthread_spin_lock, pthread_spin_lock) + + +int +__pthread_spin_trylock (pthread_spinlock_t *lock) +{ + int oldval; + + asm volatile + ("xchgl %0,%1" + : "=r" (oldval), "=m" (*lock) + : "0" (0)); + return oldval > 0 ? 0 : EBUSY; +} +weak_alias (__pthread_spin_trylock, pthread_spin_trylock) + + +int +__pthread_spin_unlock (pthread_spinlock_t *lock) +{ + asm volatile + ("movl $1,%0" + : "=m" (*lock)); + return 0; +} +weak_alias (__pthread_spin_unlock, pthread_spin_unlock) + + +int +__pthread_spin_init (pthread_spinlock_t *lock, int pshared) +{ + /* We can ignore the `pshared' parameter. Since we are busy-waiting + all processes which can access the memory location `lock' points + to can use the spinlock. */ + *lock = 1; + return 0; +} +weak_alias (__pthread_spin_init, pthread_spin_init) + + +int +__pthread_spin_destroy (pthread_spinlock_t *lock) +{ + /* Nothing to do. */ + return 0; +} +weak_alias (__pthread_spin_destroy, pthread_spin_destroy) diff --git a/linuxthreads/sysdeps/x86_64/pt-machine.h b/linuxthreads/sysdeps/x86_64/pt-machine.h new file mode 100644 index 0000000000..df187a7c03 --- /dev/null +++ b/linuxthreads/sysdeps/x86_64/pt-machine.h @@ -0,0 +1,225 @@ +/* Machine-dependent pthreads configuration and inline functions. + x86-64 version. + Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _PT_MACHINE_H +#define _PT_MACHINE_H 1 + +#ifndef __ASSEMBLER__ +# include <stddef.h> /* For offsetof. */ +# include <stdlib.h> /* For abort(). */ +# include <asm/prctl.h> + + +# ifndef PT_EI +# define PT_EI extern inline __attribute__ ((always_inline)) +# endif + +extern long int testandset (int *spinlock); +extern int __compare_and_swap (long int *p, long int oldval, long int newval); + +/* Get some notion of the current stack. Need not be exactly the top + of the stack, just something somewhere in the current frame. */ +# define CURRENT_STACK_FRAME stack_pointer +register char * stack_pointer __asm__ ("%rsp") __attribute_used__; + + +/* Spinlock implementation; required. */ +PT_EI long int +testandset (int *spinlock) +{ + long int ret; + + __asm__ __volatile__ ( + "xchgl %k0, %1" + : "=r"(ret), "=m"(*spinlock) + : "0"(1), "m"(*spinlock) + : "memory"); + + return ret; +} + + +/* Compare-and-swap for semaphores. */ +# define HAS_COMPARE_AND_SWAP + +PT_EI int +__compare_and_swap (long int *p, long int oldval, long int newval) +{ + char ret; + long int readval; + + __asm__ __volatile__ ("lock; cmpxchgq %3, %1; sete %0" + : "=q" (ret), "=m" (*p), "=a" (readval) + : "r" (newval), "m" (*p), "a" (oldval) + : "memory"); + return ret; +} + +/* 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 \ +({ \ + register pthread_descr __self; \ + __asm__ ("movq %%fs:%c1,%0" : "=r" (__self) \ + : "i" (offsetof (struct _pthread_descr_struct, \ + p_header.data.self))); \ + __self; \ +}) + +/* Prototype for the system call. */ +extern int __arch_prctl (int __code, unsigned long __addr); + +/* Initialize the thread-unique value. */ +# define INIT_THREAD_SELF(descr, nr) \ +{ \ + if (__arch_prctl (ARCH_SET_FS, (unsigned long)descr) != 0) \ + abort (); \ +} + +/* 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_descr_struct, \ + member))); \ + else if (sizeof (__value) == 4) \ + __asm__ __volatile__ ("movl %%fs:%P2,%k0" \ + : "=r" (__value) \ + : "0" (0), \ + "i" (offsetof (struct _pthread_descr_struct, \ + 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,%0" \ + : "=r" (__value) \ + : "i" (offsetof (struct _pthread_descr_struct, \ + member))); \ + } \ + __value; \ +}) + +/* Same as THREAD_GETMEM, but the member offset can be non-constant. */ +# define THREAD_GETMEM_NC(descr, member) \ +({ \ + __typeof__ (descr->member) __value; \ + if (sizeof (__value) == 1) \ + __asm__ __volatile__ ("movb %%fs:(%2),%b0" \ + : "=q" (__value) \ + : "0" (0), \ + "r" (offsetof (struct _pthread_descr_struct, \ + member))); \ + else if (sizeof (__value) == 4) \ + __asm__ __volatile__ ("movl %%fs:(%2),%k0" \ + : "=r" (__value) \ + : "0" (0), \ + "r" (offsetof (struct _pthread_descr_struct, \ + 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:(%1),%0" \ + : "=r" (__value) \ + : "r" (offsetof (struct _pthread_descr_struct, \ + member))); \ + } \ + __value; \ +}) + +/* Set member of the thread descriptor directly. */ +# define THREAD_SETMEM(descr, member, value) \ +({ \ + __typeof__ (descr->member) __value = (value); \ + if (sizeof (__value) == 1) \ + __asm__ __volatile__ ("movb %0,%%fs:%P1" : \ + : "q" (__value), \ + "i" (offsetof (struct _pthread_descr_struct, \ + member))); \ + else if (sizeof (__value) == 4) \ + __asm__ __volatile__ ("movl %k0,%%fs:%P1" : \ + : "r" (__value), \ + "i" (offsetof (struct _pthread_descr_struct, \ + 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 %0,%%fs:%P1" : \ + : "r" (__value), \ + "i" (offsetof (struct _pthread_descr_struct, \ + member))); \ + } \ +}) + +/* Same as THREAD_SETMEM, but the member offset can be non-constant. */ +# define THREAD_SETMEM_NC(descr, member, value) \ +({ \ + __typeof__ (descr->member) __value = (value); \ + if (sizeof (__value) == 1) \ + __asm__ __volatile__ ("movb %0,%%fs:(%1)" : \ + : "q" (__value), \ + "r" (offsetof (struct _pthread_descr_struct, \ + member))); \ + else if (sizeof (__value) == 4) \ + __asm__ __volatile__ ("movl %k0,%%fs:(%1)" : \ + : "r" (__value), \ + "r" (offsetof (struct _pthread_descr_struct, \ + 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 %0,%%fs:(%1)" : \ + : "r" (__value), \ + "r" (offsetof (struct _pthread_descr_struct, \ + member))); \ + } \ +}) + +#endif /* !__ASSEMBLER__ */ + +/* We want the OS to assign stack addresses. */ +#define FLOATING_STACKS 1 + +/* Maximum size of the stack if the rlimit is unlimited. */ +#define ARCH_STACK_MAX_SIZE 32*1024*1024 + +/* The ia32e really want some help to prevent overheating. */ +#define BUSY_WAIT_NOP __asm__ ("rep; nop") + +#endif /* pt-machine.h */ diff --git a/linuxthreads/sysdeps/x86_64/tcb-offsets.sym b/linuxthreads/sysdeps/x86_64/tcb-offsets.sym new file mode 100644 index 0000000000..aee6be2570 --- /dev/null +++ b/linuxthreads/sysdeps/x86_64/tcb-offsets.sym @@ -0,0 +1,4 @@ +#include <sysdep.h> +#include <tls.h> + +MULTIPLE_THREADS_OFFSET offsetof (tcbhead_t, multiple_threads) diff --git a/linuxthreads/sysdeps/x86_64/tls.h b/linuxthreads/sysdeps/x86_64/tls.h new file mode 100644 index 0000000000..63feebdb2c --- /dev/null +++ b/linuxthreads/sysdeps/x86_64/tls.h @@ -0,0 +1,129 @@ +/* Definitions for thread-local data handling. linuxthreads/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. */ + +#ifndef _TLS_H +#define _TLS_H + +#ifndef __ASSEMBLER__ + +# include <pt-machine.h> +# include <stddef.h> + +/* Type for the dtv. */ +typedef union dtv +{ + size_t counter; + void *pointer; +} dtv_t; + + +typedef struct +{ + void *tcb; /* Pointer to the TCB. Not necessary the + thread descriptor used by libpthread. */ + dtv_t *dtv; + void *self; /* Pointer to the thread descriptor. */ + int multiple_threads; +} tcbhead_t; + +#else /* __ASSEMBLER__ */ +# include <tcb-offsets.h> +#endif + + +#ifdef HAVE_TLS_SUPPORT + +/* Signal that TLS support is available. */ +# define USE_TLS 1 + +# ifndef __ASSEMBLER__ +/* Get system call information. */ +# include <sysdep.h> + +/* Get the thread descriptor definition. */ +# include <linuxthreads/descr.h> + +/* This is the size of the initial TCB. */ +# define TLS_INIT_TCB_SIZE sizeof (tcbhead_t) + +/* Alignment requirements for the initial TCB. */ +# define TLS_INIT_TCB_ALIGN __alignof__ (tcbhead_t) + +/* This is the size of the TCB. */ +# define TLS_TCB_SIZE sizeof (struct _pthread_descr_struct) + +/* Alignment requirements for the TCB. */ +# define TLS_TCB_ALIGN __alignof__ (struct _pthread_descr_struct) + +/* The TCB can have any size and the memory following the address the + thread pointer points to is unspecified. Allocate the TCB there. */ +# define TLS_TCB_AT_TP 1 + + +/* Install the dtv pointer. The pointer passed is to the element with + index -1 which contain the length. */ +# define INSTALL_DTV(descr, dtvp) \ + ((tcbhead_t *) (descr))->dtv = (dtvp) + 1 + +/* Install new dtv for current thread. */ +# define INSTALL_NEW_DTV(dtv) \ + ({ struct _pthread_descr_struct *__descr; \ + THREAD_SETMEM (__descr, p_header.data.dtvp, (dtv)); }) + +/* Return dtv of given thread descriptor. */ +# define GET_DTV(descr) \ + (((tcbhead_t *) (descr))->dtv) + +/* Code to initially initialize the thread pointer. This might need + special attention since 'errno' is not yet available and if the + operation can cause a failure 'errno' must not be touched. */ +# define TLS_INIT_TP(descr, secondcall) \ + ({ \ + void *_descr = (descr); \ + tcbhead_t *head = _descr; \ + long int _result; \ + \ + head->tcb = _descr; \ + /* For now the thread descriptor is at the same address. */ \ + head->self = _descr; \ + \ + asm volatile ("syscall" \ + : "=a" (_result) \ + : "0" ((unsigned long int) __NR_arch_prctl), \ + "D" ((unsigned long int) ARCH_SET_FS), \ + "S" (_descr) \ + : "memory", "cc", "r11", "cx"); \ + \ + _result ? "cannot set %fs base address for thread-local storage" : 0; \ + }) + +/* Indicate that dynamic linker shouldn't try to initialize TLS even + when no PT_TLS segments are found in the program and libraries + it is linked against. */ +# define TLS_INIT_TP_EXPENSIVE 1 + +/* Return the address of the dtv for the current thread. */ +# define THREAD_DTV() \ + ({ struct _pthread_descr_struct *__descr; \ + THREAD_GETMEM (__descr, p_header.data.dtvp); }) + +# endif /* HAVE_TLS_SUPPORT */ +#endif /* __ASSEMBLER__ */ + +#endif /* tls.h */ diff --git a/linuxthreads/tst-_res1.c b/linuxthreads/tst-_res1.c new file mode 100644 index 0000000000..651e3cc40d --- /dev/null +++ b/linuxthreads/tst-_res1.c @@ -0,0 +1,69 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* Test whether _res in glibc 2.1.x and earlier (before __res_state() + was introduced) works. Portable programs should never do the + dirty things below. */ + +#include <pthread.h> +#include <resolv.h> +#include <stdlib.h> +#include <stdio.h> + +void *tf (void *resp) +{ + if (resp == &_res || resp == __res_state ()) + abort (); + _res.retry = 24; + return NULL; +} + +void do_test (struct __res_state *resp) +{ + if (resp != &_res || resp != __res_state ()) + abort (); + if (_res.retry != 12) + abort (); +} + +int main (void) +{ +#undef _res + extern struct __res_state _res; + pthread_t th; + + _res.retry = 12; + if (pthread_create (&th, NULL, tf, &_res) != 0) + { + puts ("create failed"); + exit (1); + } + + do_test (&_res); + + if (pthread_join (th, NULL) != 0) + { + puts ("join failed"); + exit (1); + } + + do_test (&_res); + + exit (0); +} diff --git a/linuxthreads/tst-_res1mod1.c b/linuxthreads/tst-_res1mod1.c new file mode 100644 index 0000000000..73b190e6ba --- /dev/null +++ b/linuxthreads/tst-_res1mod1.c @@ -0,0 +1,23 @@ +/* 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 <resolv.h> +#undef _res + +struct __res_state _res; diff --git a/linuxthreads/tst-_res1mod2.c b/linuxthreads/tst-_res1mod2.c new file mode 100644 index 0000000000..d2a3509c6d --- /dev/null +++ b/linuxthreads/tst-_res1mod2.c @@ -0,0 +1 @@ +/* Nothing. */ diff --git a/linuxthreads/tst-align.c b/linuxthreads/tst-align.c new file mode 100644 index 0000000000..2de9d7a107 --- /dev/null +++ b/linuxthreads/tst-align.c @@ -0,0 +1,71 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <tst-stack-align.h> + +static void * +tf (void *arg) +{ + bool ok = true; + + puts ("in thread"); + + if (TEST_STACK_ALIGN ()) + ok = false; + + return ok ? NULL : (void *) -1l; +} + +static int +do_test (void) +{ + bool ok = true; + + puts ("in main"); + + if (TEST_STACK_ALIGN ()) + ok = false; + + pthread_t th; + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + return 1; + } + + void *res; + if (pthread_join (th, &res) != 0) + { + puts ("join failed"); + return 1; + } + + if (res != NULL) + ok = false; + + return ok ? 0 : 1; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/linuxthreads/tst-attr1.c b/linuxthreads/tst-attr1.c new file mode 100644 index 0000000000..7960cf930a --- /dev/null +++ b/linuxthreads/tst-attr1.c @@ -0,0 +1,358 @@ +/* pthread_getattr_np test. + Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <error.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <stackinfo.h> + +static void * +tf (void *arg) +{ + pthread_attr_t a, *ap, a2; + int err; + void *result = NULL; + + if (arg == NULL) + { + ap = &a2; + err = pthread_attr_init (ap); + if (err) + { + error (0, err, "pthread_attr_init failed"); + return tf; + } + } + else + ap = (pthread_attr_t *) arg; + + err = pthread_getattr_np (pthread_self (), &a); + if (err) + { + error (0, err, "pthread_getattr_np failed"); + result = tf; + } + + int detachstate1, detachstate2; + err = pthread_attr_getdetachstate (&a, &detachstate1); + if (err) + { + error (0, err, "pthread_attr_getdetachstate failed"); + result = tf; + } + else + { + err = pthread_attr_getdetachstate (ap, &detachstate2); + if (err) + { + error (0, err, "pthread_attr_getdetachstate failed"); + result = tf; + } + else if (detachstate1 != detachstate2) + { + error (0, 0, "detachstate differs %d != %d", + detachstate1, detachstate2); + result = tf; + } + } + + void *stackaddr; + size_t stacksize; + err = pthread_attr_getstack (&a, &stackaddr, &stacksize); + if (err) + { + error (0, err, "pthread_attr_getstack failed"); + result = tf; + } + else if ((void *) &a < stackaddr + || (void *) &a >= stackaddr + stacksize) + { + error (0, 0, "pthread_attr_getstack returned range does not cover thread's stack"); + result = tf; + } + else + printf ("thread stack %p-%p (0x%zx)\n", stackaddr, stackaddr + stacksize, + stacksize); + + size_t guardsize1, guardsize2; + err = pthread_attr_getguardsize (&a, &guardsize1); + if (err) + { + error (0, err, "pthread_attr_getguardsize failed"); + result = tf; + } + else + { + err = pthread_attr_getguardsize (ap, &guardsize2); + if (err) + { + error (0, err, "pthread_attr_getguardsize failed"); + result = tf; + } + else if (guardsize1 != guardsize2) + { + error (0, 0, "guardsize differs %zd != %zd", + guardsize1, guardsize2); + result = tf; + } + else + printf ("thread guardsize %zd\n", guardsize1); + } + + int scope1, scope2; + err = pthread_attr_getscope (&a, &scope1); + if (err) + { + error (0, err, "pthread_attr_getscope failed"); + result = tf; + } + else + { + err = pthread_attr_getscope (ap, &scope2); + if (err) + { + error (0, err, "pthread_attr_getscope failed"); + result = tf; + } + else if (scope1 != scope2) + { + error (0, 0, "scope differs %d != %d", + scope1, scope2); + result = tf; + } + } + + err = pthread_attr_destroy (&a); + if (err) + { + error (0, err, "pthread_attr_destroy failed"); + result = tf; + } + + if (ap == &a2) + { + err = pthread_attr_destroy (ap); + if (err) + { + error (0, err, "pthread_attr_destroy failed"); + result = tf; + } + } + + return result; +} + + +static int +do_test (void) +{ + int result = 0; + pthread_attr_t a; + + int err = pthread_attr_init (&a); + if (err) + { + error (0, err, "pthread_attr_init failed"); + result = 1; + } + + err = pthread_attr_destroy (&a); + if (err) + { + error (0, err, "pthread_attr_destroy failed"); + result = 1; + } + + err = pthread_getattr_np (pthread_self (), &a); + if (err) + { + error (0, err, "pthread_getattr_np failed"); + result = 1; + } + + int detachstate; + err = pthread_attr_getdetachstate (&a, &detachstate); + if (err) + { + error (0, err, "pthread_attr_getdetachstate failed"); + result = 1; + } + else if (detachstate != PTHREAD_CREATE_JOINABLE) + { + error (0, 0, "initial thread not joinable"); + result = 1; + } + + void *stackaddr; + size_t stacksize; + err = pthread_attr_getstack (&a, &stackaddr, &stacksize); + if (err) + { + error (0, err, "pthread_attr_getstack failed"); + result = 1; + } + else if ((void *) &a < stackaddr + || (void *) &a >= stackaddr + stacksize) + { + error (0, 0, "pthread_attr_getstack returned range does not cover main's stack"); + result = 1; + } + else + printf ("initial thread stack %p-%p (0x%zx)\n", stackaddr, + stackaddr + stacksize, stacksize); + + size_t guardsize; + err = pthread_attr_getguardsize (&a, &guardsize); + if (err) + { + error (0, err, "pthread_attr_getguardsize failed"); + result = 1; + } + else if (guardsize != 0) + { + error (0, 0, "pthread_attr_getguardsize returned %zd != 0", + guardsize); + result = 1; + } + + int scope; + err = pthread_attr_getscope (&a, &scope); + if (err) + { + error (0, err, "pthread_attr_getscope failed"); + result = 1; + } + else if (scope != PTHREAD_SCOPE_SYSTEM) + { + error (0, 0, "pthread_attr_getscope returned %d != PTHREAD_SCOPE_SYSTEM", + scope); + result = 1; + } + + int inheritsched; + err = pthread_attr_getinheritsched (&a, &inheritsched); + if (err) + { + error (0, err, "pthread_attr_getinheritsched failed"); + result = 1; + } + else if (inheritsched != PTHREAD_INHERIT_SCHED) + { + error (0, 0, "pthread_attr_getinheritsched returned %d != PTHREAD_INHERIT_SCHED", + inheritsched); + result = 1; + } + + err = pthread_attr_destroy (&a); + if (err) + { + error (0, err, "pthread_attr_destroy failed"); + result = 1; + } + + pthread_t th; + err = pthread_create (&th, NULL, tf, NULL); + if (err) + { + error (0, err, "pthread_create #1 failed"); + result = 1; + } + else + { + void *ret; + err = pthread_join (th, &ret); + if (err) + { + error (0, err, "pthread_join #1 failed"); + result = 1; + } + else if (ret != NULL) + result = 1; + } + + err = pthread_attr_init (&a); + if (err) + { + error (0, err, "pthread_attr_init failed"); + result = 1; + } + + err = pthread_create (&th, &a, tf, &a); + if (err) + { + error (0, err, "pthread_create #2 failed"); + result = 1; + } + else + { + void *ret; + err = pthread_join (th, &ret); + if (err) + { + error (0, err, "pthread_join #2 failed"); + result = 1; + } + else if (ret != NULL) + result = 1; + } + + err = pthread_attr_setguardsize (&a, 16 * sysconf (_SC_PAGESIZE)); + if (err) + { + error (0, err, "pthread_attr_setguardsize failed"); + result = 1; + } + + err = pthread_create (&th, &a, tf, &a); + if (err) + { + error (0, err, "pthread_create #3 failed"); + result = 1; + } + else + { + void *ret; + err = pthread_join (th, &ret); + if (err) + { + error (0, err, "pthread_join #3 failed"); + result = 1; + } + else if (ret != NULL) + result = 1; + } + + err = pthread_attr_destroy (&a); + if (err) + { + error (0, err, "pthread_attr_destroy failed"); + result = 1; + } + + return result; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/linuxthreads/tst-cancel-static.c b/linuxthreads/tst-cancel-static.c new file mode 100644 index 0000000000..1c879eba8b --- /dev/null +++ b/linuxthreads/tst-cancel-static.c @@ -0,0 +1 @@ +#include "tst-cancel4.c" diff --git a/linuxthreads/tst-cancel-wrappers.sh b/linuxthreads/tst-cancel-wrappers.sh new file mode 100644 index 0000000000..d6f16d1ed2 --- /dev/null +++ b/linuxthreads/tst-cancel-wrappers.sh @@ -0,0 +1,92 @@ +#! /bin/sh +# Test whether all cancelable functions are cancelable. +# Copyright (C) 2002, 2003 Free Software Foundation, Inc. +# This file is part of the GNU C Library. +# Contributed by Jakub Jelinek <jakub@redhat.com>, 2002. + +# The GNU C Library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. + +# The GNU C Library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. + +# You should have received a copy of the GNU Lesser General Public +# License along with the GNU C Library; if not, write to the Free +# Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +# 02111-1307 USA. + +while [ $# -gt 0 ]; do + ( nm -P $1; echo 'end[end]:' ) | gawk ' BEGIN { +C["accept"]=1 +C["close"]=1 +C["connect"]=1 +C["creat"]=1 +C["fcntl"]=1 +C["fsync"]=1 +C["msgrcv"]=1 +C["msgsnd"]=1 +C["msync"]=1 +C["nanosleep"]=1 +C["open"]=1 +C["open64"]=1 +C["pause"]=1 +C["poll"]=1 +C["pread"]=1 +C["pread64"]=1 +C["pselect"]=1 +C["pwrite"]=1 +C["pwrite64"]=1 +C["read"]=1 +C["readv"]=1 +C["recv"]=1 +C["recvfrom"]=1 +C["recvmsg"]=1 +C["select"]=1 +C["send"]=1 +C["sendmsg"]=1 +C["sendto"]=1 +C["sigpause"]=1 +C["sigsuspend"]=1 +C["sigwait"]=1 +C["sigwaitinfo"]=1 +C["system"]=1 +C["tcdrain"]=1 +C["wait"]=1 +C["waitid"]=1 +C["waitpid"]=1 +C["write"]=1 +C["writev"]=1 +C["__xpg_sigpause"]=1 +} +/:$/ { + if (seen) + { + if (!seen_enable || !seen_disable) + { + printf "in '$1'(%s) %s'\''s cancellation missing\n", object, seen + ret = 1 + } + } + seen="" + seen_enable="" + seen_disable="" + object=gensub(/^.*\[(.*)\]:$/,"\\1","",$0) + next +} +{ + if (C[$1] && $2 ~ /^[TW]$/) + seen=$1 + else if ($1 ~ /^([.]|)__(libc|pthread)_enable_asynccancel$/ && $2 == "U") + seen_enable=1 + else if ($1 ~ /^([.]|)__(libc|pthread)_disable_asynccancel$/ && $2 == "U") + seen_disable=1 +} +END { + exit ret +}' || exit + shift +done diff --git a/linuxthreads/tst-cancel.c b/linuxthreads/tst-cancel.c new file mode 100644 index 0000000000..59c6f1f511 --- /dev/null +++ b/linuxthreads/tst-cancel.c @@ -0,0 +1,214 @@ +/* Tests for cancelation handling. */ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/stat.h> + +int fd; + +pthread_barrier_t bar; + + +#ifdef NOT_YET +static void +cleanup (void *arg) +{ + int nr = (int) (long int) arg; + char s[30]; + char *cp = stpcpy (s, "cleanup "); + *cp++ = '0' + nr; + *cp++ = '\n'; + __libc_lseek (fd, 0, SEEK_END); + __libc_write (fd, s, cp - s); +} + + +static void * +t1 (void *arg) +{ + pthread_cleanup_push (cleanup, (void *) (long int) 1); + return NULL; + pthread_cleanup_pop (0); +} + + +static void +inner (int a) +{ + pthread_cleanup_push (cleanup, (void *) (long int) a); + if (a) + return; + pthread_cleanup_pop (0); +} + + +static void * +t2 (void *arg) +{ + pthread_cleanup_push (cleanup, (void *) (long int) 2); + inner ((int) (long int) arg); + return NULL; + pthread_cleanup_pop (0); +} +#endif + +/* This does not work yet. */ +volatile int cleanupokcnt; + +static void +cleanupok (void *arg) +{ + ++cleanupokcnt; +} + +#ifdef NOT_YET +static void * +t3 (void *arg) +{ + pthread_cleanup_push (cleanupok, (void *) (long int) 4); + inner ((int) (long int) arg); + pthread_exit (NULL); + pthread_cleanup_pop (0); +} +#endif + +static void +innerok (int a) +{ + pthread_cleanup_push (cleanupok, (void *) (long int) a); + pthread_exit (NULL); + pthread_cleanup_pop (0); +} + + +static void * +t4 (void *arg) +{ + pthread_cleanup_push (cleanupok, (void *) (long int) 6); + innerok ((int) (long int) arg); + pthread_cleanup_pop (0); + return NULL; +} + + +int +main (int argc, char *argv[]) +{ + pthread_t td; + int err; + char *tmp; + const char *prefix; + const char template[] = "thtstXXXXXX"; + struct stat64 st; + int result = 0; + + prefix = argc > 1 ? argv[1] : ""; + tmp = (char *) alloca (strlen (prefix) + sizeof template); + strcpy (stpcpy (tmp, prefix), template); + + fd = mkstemp (tmp); + if (fd == -1) + { + printf ("cannot create temporary file: %m"); + exit (1); + } + unlink (tmp); + + err = pthread_barrier_init (&bar, NULL, 2); + if (err != 0 ) + { + printf ("cannot create barrier: %s\n", strerror (err)); + exit (1); + } + +#ifdef NOT_YET + err = pthread_create (&td, NULL, t1, NULL); + if (err != 0) + { + printf ("cannot create thread t1: %s\n", strerror (err)); + exit (1); + } + + err = pthread_join (td, NULL); + if (err != 0) + { + printf ("cannot join thread: %s\n", strerror (err)); + exit (1); + } + + err = pthread_create (&td, NULL, t2, (void *) 3); + if (err != 0) + { + printf ("cannot create thread t2: %s\n", strerror (err)); + exit (1); + } + + err = pthread_join (td, NULL); + if (err != 0) + { + printf ("cannot join thread: %s\n", strerror (err)); + exit (1); + } + + err = pthread_create (&td, NULL, t3, (void *) 5); + if (err != 0) + { + printf ("cannot create thread t3: %s\n", strerror (err)); + exit (1); + } + + err = pthread_join (td, NULL); + if (err != 0) + { + printf ("cannot join thread: %s\n", strerror (err)); + exit (1); + } +#endif + + err = pthread_create (&td, NULL, t4, (void *) 7); + if (err != 0) + { + printf ("cannot create thread t4: %s\n", strerror (err)); + exit (1); + } + + err = pthread_join (td, NULL); + if (err != 0) + { + printf ("cannot join thread: %s\n", strerror (err)); + exit (1); + } + + if (fstat64 (fd, &st) < 0) + { + printf ("cannot stat temporary file: %m\n"); + result = 1; + } + else if (st.st_size != 0) + { + char buf[512]; + puts ("some cleanup handlers ran:"); + fflush (stdout); + __lseek (fd, 0, SEEK_SET); + while (1) + { + ssize_t n = read (fd, buf, sizeof buf); + if (n <= 0) + break; + write (STDOUT_FILENO, buf, n); + } + result = 1; + } + + // if (cleanupokcnt != 3) will be three once t3 runs + if (cleanupokcnt != 2) + { + printf ("cleanupokcnt = %d\n", cleanupokcnt); + result = 1; + } + + return result; +} diff --git a/linuxthreads/tst-cancel1.c b/linuxthreads/tst-cancel1.c new file mode 100644 index 0000000000..99a8339f0c --- /dev/null +++ b/linuxthreads/tst-cancel1.c @@ -0,0 +1,150 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + + +static pthread_mutex_t m1 = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t m2 = PTHREAD_MUTEX_INITIALIZER; + +static int cntr; + + +static void +cleanup (void *arg) +{ + if (arg != (void *) 42l) + cntr = 42; + else + cntr = 1; +} + + +static void * +tf (void *arg) +{ + int err; + + pthread_cleanup_push (cleanup, (void *) 42l); + + err = pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL); + if (err != 0) + { + printf ("setcanceltype failed: %s\n", strerror (err)); + exit (1); + } + + err = pthread_mutex_unlock (&m2); + if (err != 0) + { + printf ("child: mutex_unlock failed: %s\n", strerror (err)); + exit (1); + } + + err = pthread_mutex_lock (&m1); + if (err != 0) + { + printf ("child: 1st mutex_lock failed: %s\n", strerror (err)); + exit (1); + } + + /* We should never come here. */ + + pthread_cleanup_pop (0); + + return NULL; +} + + +static int +do_test (void) +{ + int err; + pthread_t th; + int result = 0; + void *retval; + + /* Get the mutexes. */ + err = pthread_mutex_lock (&m1); + if (err != 0) + { + printf ("parent: 1st mutex_lock failed: %s\n", strerror (err)); + return 1; + } + err = pthread_mutex_lock (&m2); + if (err != 0) + { + printf ("parent: 2nd mutex_lock failed: %s\n", strerror (err)); + return 1; + } + + err = pthread_create (&th, NULL, tf, NULL); + if (err != 0) + { + printf ("create failed: %s\n", strerror (err)); + return 1; + } + + err = pthread_mutex_lock (&m2); + if (err != 0) + { + printf ("parent: 3rd mutex_lock failed: %s\n", strerror (err)); + return 1; + } + + err = pthread_cancel (th); + if (err != 0) + { + printf ("cancel failed: %s\n", strerror (err)); + return 1; + } + + err = pthread_join (th, &retval); + if (err != 0) + { + printf ("join failed: %s\n", strerror (err)); + return 1; + } + + if (retval != PTHREAD_CANCELED) + { + printf ("wrong return value: %p\n", retval); + result = 1; + } + + if (cntr == 42) + { + puts ("cleanup handler called with wrong argument"); + result = 1; + } + else if (cntr != 1) + { + puts ("cleanup handling not called"); + result = 1; + } + + return result; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/linuxthreads/tst-cancel2.c b/linuxthreads/tst-cancel2.c new file mode 100644 index 0000000000..6d80f8ae5e --- /dev/null +++ b/linuxthreads/tst-cancel2.c @@ -0,0 +1,100 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <unistd.h> + + +static int fd[2]; + + +static void * +tf (void *arg) +{ + /* The buffer size must be larger than the pipe size so that the + write blocks. */ + char buf[100000]; + + if (write (fd[1], buf, sizeof (buf)) == sizeof (buf)) + { + puts ("write succeeded"); + return (void *) 1l; + } + + return (void *) 42l; +} + + +static int +do_test (void) +{ + pthread_t th; + void *r; + struct sigaction sa; + + sa.sa_handler = SIG_IGN; + sigemptyset (&sa.sa_mask); + sa.sa_flags = 0; + + if (sigaction (SIGPIPE, &sa, NULL) != 0) + { + puts ("sigaction failed"); + return 1; + } + + if (pipe (fd) != 0) + { + puts ("pipe failed"); + return 1; + } + + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + return 1; + } + + if (pthread_cancel (th) != 0) + { + puts ("cancel failed"); + return 1; + } + + /* This will cause the write in the child to return. */ + close (fd[0]); + + if (pthread_join (th, &r) != 0) + { + puts ("join failed"); + return 1; + } + + if (r != PTHREAD_CANCELED) + { + printf ("result is wrong: expected %p, got %p\n", PTHREAD_CANCELED, r); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/linuxthreads/tst-cancel3.c b/linuxthreads/tst-cancel3.c new file mode 100644 index 0000000000..86c482bcc1 --- /dev/null +++ b/linuxthreads/tst-cancel3.c @@ -0,0 +1,98 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <unistd.h> + + +static int fd[2]; + + +static void * +tf (void *arg) +{ + char buf[100]; + + if (read (fd[0], buf, sizeof (buf)) == sizeof (buf)) + { + puts ("read succeeded"); + return (void *) 1l; + } + + return NULL; +} + + +static int +do_test (void) +{ + pthread_t th; + void *r; + struct sigaction sa; + + sa.sa_handler = SIG_IGN; + sigemptyset (&sa.sa_mask); + sa.sa_flags = 0; + + if (sigaction (SIGPIPE, &sa, NULL) != 0) + { + puts ("sigaction failed"); + return 1; + } + + if (pipe (fd) != 0) + { + puts ("pipe failed"); + return 1; + } + + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + return 1; + } + + if (pthread_cancel (th) != 0) + { + puts ("cancel failed"); + return 1; + } + + /* This will cause the read in the child to return. */ + close (fd[0]); + + if (pthread_join (th, &r) != 0) + { + puts ("join failed"); + return 1; + } + + if (r != PTHREAD_CANCELED) + { + puts ("result is wrong"); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/linuxthreads/tst-cancel4.c b/linuxthreads/tst-cancel4.c new file mode 100644 index 0000000000..03f6bfe056 --- /dev/null +++ b/linuxthreads/tst-cancel4.c @@ -0,0 +1,469 @@ +/* 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. */ + +/* NOTE: this tests functionality beyond POSIX. POSIX does not allow + exit to be called more than once. */ + +#include <errno.h> +#include <limits.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/poll.h> +#include <sys/select.h> +#include <sys/uio.h> +#include <sys/wait.h> + +/* The following interfaces are defined to be cancellation points but + tests are not yet implemented: + + accept() aio_suspend() clock_nanosleep() + close() connect() creat() + fcntl() fsync() getmsg() + getpmsg() lockf() mq_receive() + mq_send() mq_timedreceive() mq_timedsend() + msgrcv() msgsnd() msync() + open() pause() + pread() pthread_cond_timedwait() + pthread_cond_wait() pthread_join() pthread_testcancel() + putmsg() putpmsg() pwrite() + recv() + recvfrom() recvmsg() + sem_timedwait() sem_wait() send() + sendmsg() sendto() sigpause() + sigsuspend() sigtimedwait() sigwait() + sigwaitinfo() system() + tcdrain() + + Since STREAMS are not supported in the standard Linux kernel there + is no need to test the STREAMS related functions. +*/ + +/* Pipe descriptors. */ +static int fds[2]; + +/* Often used barrier for two threads. */ +static pthread_barrier_t b2; + + +static void * +tf_read (void *arg) +{ + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + char buf[100]; + ssize_t s = read (fds[0], buf, sizeof (buf)); + + printf ("%s: read returns with %zd\n", __FUNCTION__, s); + + exit (1); +} + + +static void * +tf_readv (void *arg) +{ + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + char buf[100]; + struct iovec iov[1] = { [0] = { .iov_base = buf, .iov_len = sizeof (buf) } }; + ssize_t s = readv (fds[0], iov, 1); + + printf ("%s: readv returns with %zd\n", __FUNCTION__, s); + + exit (1); +} + + +static void * +tf_write (void *arg) +{ + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + char buf[100000]; + memset (buf, '\0', sizeof (buf)); + ssize_t s = write (fds[1], buf, sizeof (buf)); + + printf ("%s: write returns with %zd\n", __FUNCTION__, s); + + exit (1); +} + + +static void * +tf_writev (void *arg) +{ + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + char buf[100000]; + memset (buf, '\0', sizeof (buf)); + struct iovec iov[1] = { [0] = { .iov_base = buf, .iov_len = sizeof (buf) } }; + ssize_t s = writev (fds[1], iov, 1); + + printf ("%s: writev returns with %zd\n", __FUNCTION__, s); + + exit (1); +} + + +static void * +tf_sleep (void *arg) +{ + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + sleep (1000000); + + printf ("%s: sleep returns\n", __FUNCTION__); + + exit (1); +} + + +static void * +tf_usleep (void *arg) +{ + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + usleep ((useconds_t) ULONG_MAX); + + printf ("%s: usleep returns\n", __FUNCTION__); + + exit (1); +} + + +static void * +tf_nanosleep (void *arg) +{ + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + struct timespec ts = { .tv_sec = 10000000, .tv_nsec = 0 }; + while (nanosleep (&ts, &ts) != 0) + continue; + + printf ("%s: nanosleep returns\n", __FUNCTION__); + + exit (1); +} + + +static void * +tf_select (void *arg) +{ + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + fd_set rfs; + FD_ZERO (&rfs); + FD_SET (fds[0], &rfs); + + int s = select (fds[0] + 1, &rfs, NULL, NULL, NULL); + + printf ("%s: select returns with %d (%s)\n", __FUNCTION__, s, + strerror (errno)); + + exit (1); +} + + +static void * +tf_pselect (void *arg) +{ + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + fd_set rfs; + FD_ZERO (&rfs); + FD_SET (fds[0], &rfs); + + int s = pselect (fds[0] + 1, &rfs, NULL, NULL, NULL, NULL); + + printf ("%s: pselect returns with %d (%s)\n", __FUNCTION__, s, + strerror (errno)); + + exit (1); +} + + +static void * +tf_poll (void *arg) +{ + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + struct pollfd rfs[1] = { [0] = { .fd = fds[0], .events = POLLIN } }; + + int s = poll (rfs, 1, -1); + + printf ("%s: poll returns with %d (%s)\n", __FUNCTION__, s, + strerror (errno)); + + exit (1); +} + + +static void * +tf_wait (void *arg) +{ + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + pid_t pid = fork (); + if (pid == -1) + { + puts ("fork failed"); + exit (1); + } + + if (pid == 0) + { + /* Make the program disappear after a while. */ + sleep (10); + exit (0); + } + + int s = wait (NULL); + + printf ("%s: wait returns with %d (%s)\n", __FUNCTION__, s, + strerror (errno)); + + exit (1); +} + + +static void * +tf_waitpid (void *arg) +{ + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + pid_t pid = fork (); + if (pid == -1) + { + puts ("fork failed"); + exit (1); + } + + if (pid == 0) + { + /* Make the program disappear after a while. */ + sleep (10); + exit (0); + } + + int s = waitpid (-1, NULL, 0); + + printf ("%s: waitpid returns with %d (%s)\n", __FUNCTION__, s, + strerror (errno)); + + exit (1); +} + + +static void * +tf_waitid (void *arg) +{ + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + pid_t pid = fork (); + if (pid == -1) + { + puts ("fork failed"); + exit (1); + } + + if (pid == 0) + { + /* Make the program disappear after a while. */ + sleep (10); + exit (0); + } + +#ifndef WEXITED +# define WEXITED 0 +#endif + siginfo_t si; + int s = waitid (P_PID, pid, &si, WEXITED); + + printf ("%s: waitid returns with %d (%s)\n", __FUNCTION__, s, + strerror (errno)); + + exit (1); +} + + +static struct +{ + void *(*tf) (void *); + int nb; +} tests[] = +{ + { tf_read, 2 }, + { tf_readv, 2 }, + { tf_select, 2 }, + { tf_pselect, 2 }, + { tf_poll, 2 }, + { tf_write, 2 }, + { tf_writev, 2}, + { tf_sleep, 2 }, + { tf_usleep, 2 }, + { tf_nanosleep, 2 }, + { tf_wait, 2 }, + { tf_waitid, 2 }, + { tf_waitpid, 2 }, +}; +#define ntest_tf (sizeof (tests) / sizeof (tests[0])) + + +static int +do_test (void) +{ + if (pipe (fds) != 0) + { + puts ("pipe failed"); + exit (1); + } + + int cnt; + for (cnt = 0; cnt < ntest_tf; ++cnt) + { + printf ("round %d\n", cnt); + + if (pthread_barrier_init (&b2, NULL, tests[cnt].nb) != 0) + { + puts ("b2 init failed"); + exit (1); + } + + pthread_t th; + if (pthread_create (&th, NULL, tests[cnt].tf, NULL) != 0) + { + printf ("create for round %d test failed\n", cnt); + exit (1); + } + + puts ("barrier waits"); + + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + puts ("nanosleep delay"); + + struct timespec ts = { .tv_sec = 0, .tv_nsec = 100000000 }; + while (nanosleep (&ts, &ts) != 0) + continue; + + if (pthread_cancel (th) != 0) + { + printf ("cancel in round %d failed\n", cnt); + exit (1); + } + + void *status; + if (pthread_join (th, &status) != 0) + { + printf ("join in round %d failed\n", cnt); + exit (1); + } + if (status != PTHREAD_CANCELED) + { + printf ("thread in round %d not canceled\n", cnt); + exit (1); + } + printf ("test %d successful\n", cnt); + + if (pthread_barrier_destroy (&b2) != 0) + { + puts ("barrier_destroy failed"); + exit (1); + } + } + + return 0; +} + +#define TIMEOUT 60 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/linuxthreads/tst-cancel5.c b/linuxthreads/tst-cancel5.c new file mode 100644 index 0000000000..1c879eba8b --- /dev/null +++ b/linuxthreads/tst-cancel5.c @@ -0,0 +1 @@ +#include "tst-cancel4.c" diff --git a/linuxthreads/tst-cancel6.c b/linuxthreads/tst-cancel6.c new file mode 100644 index 0000000000..94de85830b --- /dev/null +++ b/linuxthreads/tst-cancel6.c @@ -0,0 +1,79 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + + +static void * +tf (void *arg) +{ + char buf[100]; + fgets (buf, sizeof (buf), arg); + /* This call should never return. */ + return NULL; +} + + +static int +do_test (void) +{ + int fd[2]; + if (pipe (fd) != 0) + { + puts ("pipe failed"); + return 1; + } + + FILE *fp = fdopen (fd[0], "r"); + if (fp == NULL) + { + puts ("fdopen failed"); + return 1; + } + + pthread_t th; + if (pthread_create (&th, NULL, tf, fp) != 0) + { + puts ("pthread_create failed"); + return 1; + } + + sleep (1); + + if (pthread_cancel (th) != 0) + { + puts ("pthread_cancel failed"); + return 1; + } + + void *r; + if (pthread_join (th, &r) != 0) + { + puts ("pthread_join failed"); + return 1; + } + + return r != PTHREAD_CANCELED; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/linuxthreads/tst-cancel7.c b/linuxthreads/tst-cancel7.c new file mode 100644 index 0000000000..11298eae26 --- /dev/null +++ b/linuxthreads/tst-cancel7.c @@ -0,0 +1,111 @@ +/* Test for pthread cancellation of mutex blocks. + Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; +pthread_barrier_t b; +int value = 0; + +static void * +tf (void *arg) +{ + int r = pthread_barrier_wait (&b); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + pthread_mutex_lock (&lock); + ++value; + pthread_testcancel (); + ++value; + pthread_mutex_unlock (&lock); + return NULL; +} + + +static int +do_test (void) +{ + pthread_mutex_lock (&lock); + + if (pthread_barrier_init (&b, NULL, 2) != 0) + { + puts ("barrier init failed"); + return 1; + } + + pthread_t th; + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("pthread_create failed"); + return 1; + } + + int r = pthread_barrier_wait (&b); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + if (pthread_cancel (th) != 0) + { + puts ("pthread_cancel failed"); + return 1; + } + + pthread_mutex_unlock (&lock); + + void *status; + if (pthread_join (th, &status) != 0) + { + puts ("join failed"); + return 1; + } + + if (status != PTHREAD_CANCELED) + { + puts ("thread not canceled"); + return 1; + } + + if (value == 0) + { + puts ("thread cancelled in the pthread_mutex_lock call"); + return 1; + } + + if (value != 1) + { + puts ("thread not cancelled in pthread_testcancel call"); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/linuxthreads/tst-cancel8.c b/linuxthreads/tst-cancel8.c new file mode 100644 index 0000000000..478d104fb3 --- /dev/null +++ b/linuxthreads/tst-cancel8.c @@ -0,0 +1,287 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <error.h> +#include <fcntl.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/select.h> +#include <sys/time.h> +#include <unistd.h> + +static void * +tf (void *arg) +{ + return NULL; +} + +static void +handler (int sig) +{ +} + +static void __attribute__ ((noinline)) +clobber_lots_of_regs (void) +{ +#define X1(n) long r##n = 10##n; __asm __volatile ("" : "+r" (r##n)); +#define X2(n) X1(n##0) X1(n##1) X1(n##2) X1(n##3) X1(n##4) +#define X3(n) X2(n##0) X2(n##1) X2(n##2) X2(n##3) X2(n##4) + X3(0) X3(1) X3(2) X3(3) X3(4) +#undef X1 +#define X1(n) __asm __volatile ("" : : "r" (r##n)); + X3(0) X3(1) X3(2) X3(3) X3(4) +#undef X1 +#undef X2 +#undef X3 +} + +static int +do_test (void) +{ + pthread_t th; + int old, rc; + int ret = 0; + int fd[2]; + + rc = pipe (fd); + if (rc < 0) + error (EXIT_FAILURE, errno, "couldn't create pipe"); + + rc = pthread_create (&th, NULL, tf, NULL); + if (rc) + error (EXIT_FAILURE, rc, "couldn't create thread"); + + rc = pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, &old); + if (rc) + { + error (0, rc, "1st pthread_setcanceltype failed"); + ret = 1; + } + if (old != PTHREAD_CANCEL_DEFERRED && old != PTHREAD_CANCEL_ASYNCHRONOUS) + { + error (0, 0, "1st pthread_setcanceltype returned invalid value %d", + old); + ret = 1; + } + + clobber_lots_of_regs (); + close (fd[0]); + + rc = pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, &old); + if (rc) + { + error (0, rc, "pthread_setcanceltype after close failed"); + ret = 1; + } + if (old != PTHREAD_CANCEL_DEFERRED) + { + error (0, 0, "pthread_setcanceltype after close returned invalid value %d", + old); + ret = 1; + } + + clobber_lots_of_regs (); + close (fd[1]); + + rc = pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, &old); + if (rc) + { + error (0, rc, "pthread_setcanceltype after 2nd close failed"); + ret = 1; + } + if (old != PTHREAD_CANCEL_ASYNCHRONOUS) + { + error (0, 0, "pthread_setcanceltype after 2nd close returned invalid value %d", + old); + ret = 1; + } + + struct sigaction sa = { .sa_handler = handler, .sa_flags = 0 }; + sigemptyset (&sa.sa_mask); + sigaction (SIGALRM, &sa, NULL); + + struct itimerval it; + it.it_value.tv_sec = 1; + it.it_value.tv_usec = 0; + it.it_interval = it.it_value; + setitimer (ITIMER_REAL, &it, NULL); + + clobber_lots_of_regs (); + pause (); + + memset (&it, 0, sizeof (it)); + setitimer (ITIMER_REAL, &it, NULL); + + rc = pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, &old); + if (rc) + { + error (0, rc, "pthread_setcanceltype after pause failed"); + ret = 1; + } + if (old != PTHREAD_CANCEL_DEFERRED) + { + error (0, 0, "pthread_setcanceltype after pause returned invalid value %d", + old); + ret = 1; + } + + it.it_value.tv_sec = 1; + it.it_value.tv_usec = 0; + it.it_interval = it.it_value; + setitimer (ITIMER_REAL, &it, NULL); + + clobber_lots_of_regs (); + pause (); + + memset (&it, 0, sizeof (it)); + setitimer (ITIMER_REAL, &it, NULL); + + rc = pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, &old); + if (rc) + { + error (0, rc, "pthread_setcanceltype after 2nd pause failed"); + ret = 1; + } + if (old != PTHREAD_CANCEL_ASYNCHRONOUS) + { + error (0, 0, "pthread_setcanceltype after 2nd pause returned invalid value %d", + old); + ret = 1; + } + + char fname[] = "/tmp/tst-lt-cancel8-dir-XXXXXX\0foo/bar"; + char *enddir = strchr (fname, '\0'); + if (mkdtemp (fname) == NULL) + { + error (0, errno, "mkdtemp failed"); + ret = 1; + } + *enddir = '/'; + + clobber_lots_of_regs (); + creat (fname, 0400); + + rc = pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, &old); + if (rc) + { + error (0, rc, "pthread_setcanceltype after creat failed"); + ret = 1; + } + if (old != PTHREAD_CANCEL_DEFERRED) + { + error (0, 0, "pthread_setcanceltype after creat returned invalid value %d", + old); + ret = 1; + } + + clobber_lots_of_regs (); + creat (fname, 0400); + + rc = pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, &old); + if (rc) + { + error (0, rc, "pthread_setcanceltype after 2nd creat failed"); + ret = 1; + } + if (old != PTHREAD_CANCEL_ASYNCHRONOUS) + { + error (0, 0, "pthread_setcanceltype after 2nd creat returned invalid value %d", + old); + ret = 1; + } + + clobber_lots_of_regs (); + open (fname, O_CREAT, 0400); + + rc = pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, &old); + if (rc) + { + error (0, rc, "pthread_setcanceltype after open failed"); + ret = 1; + } + if (old != PTHREAD_CANCEL_DEFERRED) + { + error (0, 0, "pthread_setcanceltype after open returned invalid value %d", + old); + ret = 1; + } + + clobber_lots_of_regs (); + open (fname, O_CREAT, 0400); + + rc = pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, &old); + if (rc) + { + error (0, rc, "pthread_setcanceltype after 2nd open failed"); + ret = 1; + } + if (old != PTHREAD_CANCEL_ASYNCHRONOUS) + { + error (0, 0, "pthread_setcanceltype after 2nd open returned invalid value %d", + old); + ret = 1; + } + + *enddir = '\0'; + rmdir (fname); + + clobber_lots_of_regs (); + select (-1, NULL, NULL, NULL, NULL); + + rc = pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, &old); + if (rc) + { + error (0, rc, "pthread_setcanceltype after select failed"); + ret = 1; + } + if (old != PTHREAD_CANCEL_DEFERRED) + { + error (0, 0, "pthread_setcanceltype after select returned invalid value %d", + old); + ret = 1; + } + + clobber_lots_of_regs (); + select (-1, NULL, NULL, NULL, NULL); + + rc = pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, &old); + if (rc) + { + error (0, rc, "pthread_setcanceltype after 2nd select failed"); + ret = 1; + } + if (old != PTHREAD_CANCEL_ASYNCHRONOUS) + { + error (0, 0, "pthread_setcanceltype after 2nd select returned invalid value %d", + old); + ret = 1; + } + + pthread_join (th, NULL); + + return ret; +} + +#define TIMEOUT 20 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/linuxthreads/tst-clock1.c b/linuxthreads/tst-clock1.c new file mode 100644 index 0000000000..bca40956e2 --- /dev/null +++ b/linuxthreads/tst-clock1.c @@ -0,0 +1,202 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <unistd.h> + + +#if defined _POSIX_THREAD_CPUTIME && _POSIX_THREAD_CPUTIME >= 0 +static pthread_barrier_t b2; +static pthread_barrier_t bN; + + +static void * +tf (void *arg) +{ + int e = pthread_barrier_wait (&b2); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + exit (1); + } + + e = pthread_barrier_wait (&bN); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + exit (1); + } + + return NULL; +} +#endif + + +int +do_test (void) +{ +#if defined _POSIX_THREAD_CPUTIME && _POSIX_THREAD_CPUTIME >= 0 +# define N 10 + +# if _POSIX_THREAD_CPUTIME == 0 + if (sysconf (_SC_THREAD_CPUTIME) < 0) + { + puts ("_POSIX_THREAD_CPUTIME option not available"); + return 0; + } +# endif + + if (pthread_barrier_init (&b2, NULL, 2) != 0 + || pthread_barrier_init (&bN, NULL, N + 1) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + struct timespec ts = { .tv_sec = 0, .tv_nsec = 100000000 }; + TEMP_FAILURE_RETRY (nanosleep (&ts, &ts)); + + pthread_t th[N + 1]; + clockid_t cl[N + 1]; +# ifndef CLOCK_THREAD_CPUTIME_ID + if (pthread_getcpuclockid (pthread_self (), &cl[0]) != 0) + { + puts ("own pthread_getcpuclockid failed"); + return 1; + } +# else + cl[0] = CLOCK_THREAD_CPUTIME_ID; +# endif + + pthread_attr_t at; + + if (pthread_attr_init (&at) != 0) + { + puts ("attr_init failed"); + return 1; + } + + if (pthread_attr_setstacksize (&at, 1 * 1024 * 1024) != 0) + { + puts ("attr_setstacksize failed"); + return 1; + } + + int i; + int e; + for (i = 0; i < N; ++i) + { + if (pthread_create (&th[i], &at, tf, NULL) != 0) + { + puts ("create failed"); + return 1; + } + + e = pthread_barrier_wait (&b2); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + return 1; + } + + ts.tv_sec = 0; + ts.tv_nsec = 100000000; + TEMP_FAILURE_RETRY (nanosleep (&ts, &ts)); + + if (pthread_getcpuclockid (th[i], &cl[i + 1]) != 0) + { + puts ("pthread_getcpuclockid failed"); + return 1; + } + } + + if (pthread_attr_destroy (&at) != 0) + { + puts ("attr_destroy failed"); + return 1; + } + + struct timespec t[N + 1]; + for (i = 0; i < N + 1; ++i) + if (clock_gettime (cl[i], &t[i]) != 0) + { + printf ("clock_gettime round %d failed\n", i); + return 1; + } + + for (i = 0; i < N; ++i) + { + struct timespec diff; + + diff.tv_sec = t[i].tv_sec - t[i + 1].tv_sec; + diff.tv_nsec = t[i].tv_nsec - t[i + 1].tv_nsec; + if (diff.tv_nsec < 0) + { + diff.tv_nsec += 1000000000; + --diff.tv_sec; + } + + if (diff.tv_sec < 0 || (diff.tv_sec == 0 && diff.tv_nsec < 100000000)) + { + printf ("\ +difference between thread %d and %d too small (%ld.%09ld)\n", + i, i + 1, (long int) diff.tv_sec, (long int) diff.tv_nsec); + return 1; + } + + printf ("diff %d->%d: %ld.%09ld\n", + i, i + 1, (long int) diff.tv_sec, (long int) diff.tv_nsec); + } + + ts.tv_sec = 0; + ts.tv_nsec = 0; + for (i = 0; i < N + 1; ++i) + if (clock_settime (cl[i], &ts) != 0) + { + printf ("clock_settime(%d) round %d failed\n", cl[i], i); + return 1; + } + + for (i = 0; i < N + 1; ++i) + { + if (clock_gettime (cl[i], &ts) != 0) + { + puts ("clock_gettime failed"); + return 1; + } + + if (ts.tv_sec > t[i].tv_sec + || (ts.tv_sec == t[i].tv_sec && ts.tv_nsec > t[i].tv_nsec)) + { + puts ("clock_settime didn't reset clock"); + return 1; + } + } +#endif + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/linuxthreads/tst-context.c b/linuxthreads/tst-context.c new file mode 100644 index 0000000000..2938a9f7fa --- /dev/null +++ b/linuxthreads/tst-context.c @@ -0,0 +1,116 @@ +/* Ack, a hack! We need to get the proper definition, or lack thereof, + for FLOATING_STACKS. But when !IS_IN_libpthread, this can get defined + incidentally by <tls.h>. So kludge around it. */ + +#define IS_IN_libpthread +#include <tls.h> +#undef IS_IN_libpthread +#undef USE___THREAD + +#include <errno.h> +#include <error.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <ucontext.h> + + +#define N 4 + +#ifdef FLOATING_STACKS +static char stacks[N][8192]; +static ucontext_t ctx[N][2]; +static volatile int failures; + +static void +fct (long int n) +{ + /* Just to use the thread local descriptor. */ + printf ("%ld: in %s now\n", n, __FUNCTION__); + errno = 0; +} + +static void * +threadfct (void *arg) +{ + int n = (int) (long int) arg; + + if (getcontext (&ctx[n][1]) != 0) + { + printf ("%d: cannot get context: %m\n", n); + exit (1); + } + + printf ("%d: %s: before makecontext\n", n, __FUNCTION__); + + ctx[n][1].uc_stack.ss_sp = stacks[n]; + ctx[n][1].uc_stack.ss_size = 8192; + ctx[n][1].uc_link = &ctx[n][0]; + makecontext (&ctx[n][1], (void (*) (void)) fct, 1, (long int) n); + + printf ("%d: %s: before swapcontext\n", n, __FUNCTION__); + + if (swapcontext (&ctx[n][0], &ctx[n][1]) != 0) + { + ++failures; + printf ("%d: %s: swapcontext failed\n", n, __FUNCTION__); + } + else + printf ("%d: back in %s\n", n, __FUNCTION__); + + return NULL; +} +#endif + + +#ifdef FLOATING_STACKS +static volatile int global; +#endif + +int +main (void) +{ +#ifndef FLOATING_STACKS + puts ("not supported"); + return 0; +#else + int n; + pthread_t th[N]; + ucontext_t mctx; + + puts ("making contexts"); + if (getcontext (&mctx) != 0) + { + if (errno == ENOSYS) + { + puts ("context handling not supported"); + exit (0); + } + + printf ("%s: getcontext: %m\n", __FUNCTION__); + exit (1); + } + + /* Play some tricks with this context. */ + if (++global == 1) + if (setcontext (&mctx) != 0) + { + printf ("%s: setcontext: %m\n", __FUNCTION__); + exit (1); + } + if (global != 2) + { + printf ("%s: 'global' not incremented twice\n", __FUNCTION__); + exit (1); + } + + for (n = 0; n < N; ++n) + if (pthread_create (&th[n], NULL, threadfct, (void *) (long int) n) != 0) + error (EXIT_FAILURE, errno, "cannot create all threads"); + + for (n = 0; n < N; ++n) + pthread_join (th[n], NULL); + + return failures; +#endif +} diff --git a/linuxthreads/tst-popen.c b/linuxthreads/tst-popen.c new file mode 100644 index 0000000000..f76a6e79e5 --- /dev/null +++ b/linuxthreads/tst-popen.c @@ -0,0 +1,37 @@ +#include <errno.h> +#include <error.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +static void * +dummy (void *x) +{ + return NULL; +} + +static char buf[sizeof "something\n"]; + +static int +do_test (void) +{ + FILE *f; + pthread_t p; + + pthread_create (&p, NULL, dummy, NULL); + f = popen ("echo something", "r"); + if (f == NULL) + error (EXIT_FAILURE, errno, "popen failed"); + if (fgets (buf, sizeof (buf), f) == NULL) + error (EXIT_FAILURE, 0, "fgets failed"); + if (strcmp (buf, "something\n")) + error (EXIT_FAILURE, 0, "read wrong data"); + if (pclose (f)) + error (EXIT_FAILURE, errno, "pclose returned non-zero"); + exit (0); +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/linuxthreads/tst-popen2.c b/linuxthreads/tst-popen2.c new file mode 100644 index 0000000000..3ff69acd52 --- /dev/null +++ b/linuxthreads/tst-popen2.c @@ -0,0 +1,41 @@ +#include <errno.h> +#include <error.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +static void * +dummy (void *x) +{ + return NULL; +} + +static char buf[sizeof "something\n"]; + +static int +do_test (void) +{ + FILE *f; + pthread_t p; + int err; + + f = popen ("echo something", "r"); + if (f == NULL) + error (EXIT_FAILURE, errno, "popen failed"); + if (fgets (buf, sizeof (buf), f) == NULL) + error (EXIT_FAILURE, 0, "fgets failed"); + if (strcmp (buf, "something\n")) + error (EXIT_FAILURE, 0, "read wrong data"); + if (pclose (f)) + error (EXIT_FAILURE, errno, "pclose returned non-zero"); + if ((err = pthread_create (&p, NULL, dummy, NULL))) + error (EXIT_FAILURE, err, "pthread_create failed"); + if ((err = pthread_join (p, NULL))) + error (EXIT_FAILURE, err, "pthread_join failed"); + exit (0); +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/linuxthreads/tst-signal.c b/linuxthreads/tst-signal.c new file mode 100644 index 0000000000..5eb0170c6c --- /dev/null +++ b/linuxthreads/tst-signal.c @@ -0,0 +1,64 @@ +/* Test sigaction wrapper. */ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Andreas Schwab <schwab@suse.de>. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <stdio.h> +#include <stdlib.h> +#include <signal.h> + +int +main (int argc, char *argv[]) +{ + struct sigaction old_sa, new_sa; + + if (sigaction (SIGHUP, NULL, &old_sa) < 0) + { + printf ("cannot get signal action for SIGHUP: %m\n"); + exit (1); + } + + if (old_sa.sa_handler != SIG_IGN) + { + printf ("SIGHUP action should be SIG_IGN, is %p\n", + (void *) old_sa.sa_handler); + exit (1); + } + + new_sa.sa_handler = SIG_DFL; + if (sigaction (SIGHUP, &new_sa, NULL) < 0) + { + printf ("cannot set signal action for SIGHUP: %m\n"); + exit (1); + } + + if (sigaction (SIGHUP, NULL, &old_sa) < 0) + { + printf ("cannot get signal action for SIGHUP: %m\n"); + exit (1); + } + + if (old_sa.sa_handler != SIG_DFL) + { + printf ("SIGHUP action should be SIG_DFL, is %p\n", + (void *) old_sa.sa_handler); + exit (1); + } + + return 0; +} diff --git a/linuxthreads/tst-signal.sh b/linuxthreads/tst-signal.sh new file mode 100644 index 0000000000..fb58193822 --- /dev/null +++ b/linuxthreads/tst-signal.sh @@ -0,0 +1,28 @@ +#! /bin/sh +# Testing the sigaction wrapper. +# 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. + +common_objpfx=$1; shift + +# set up to ignore SIGHUP +trap '' 1 + +exec ${common_objpfx}elf/ld.so --library-path $common_objpfx:${common_objpfx}linuxthreads \ + ${common_objpfx}linuxthreads/tst-signal diff --git a/linuxthreads/tst-stack1.c b/linuxthreads/tst-stack1.c new file mode 100644 index 0000000000..057bfa3f9f --- /dev/null +++ b/linuxthreads/tst-stack1.c @@ -0,0 +1,97 @@ +/* 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. */ + +/* Test pthread_create/pthread_join with user defined stacks. */ + +#include <limits.h> +#include <pthread.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +static int seen; + +static void * +tf (void *p) +{ + ++seen; + return NULL; +} + +#define N 16 + +static int +do_test (void) +{ + void *stack; + int res = posix_memalign (&stack, getpagesize (), N * 4 * PTHREAD_STACK_MIN); + if (res) + { + printf ("malloc failed %s\n", strerror (res)); + return 1; + } + + pthread_attr_t attr; + pthread_attr_init (&attr); + + int result = 0; + for (int i = 0; i < N; ++i) + { + res = pthread_attr_setstack (&attr, stack + i * 4 * PTHREAD_STACK_MIN, + 4 * PTHREAD_STACK_MIN); + if (res) + { + printf ("pthread_attr_setstack failed %d\n", res); + result = 1; + continue; + } + + /* Create the thread. */ + pthread_t th; + res = pthread_create (&th, &attr, tf, NULL); + if (res) + { + printf ("pthread_create failed %d\n", res); + result = 1; + } + else + { + res = pthread_join (th, NULL); + if (res) + { + printf ("pthread_join failed %d\n", res); + result = 1; + } + } + } + + pthread_attr_destroy (&attr); + + if (seen != N) + { + printf ("seen %d != %d\n", seen, N); + result = 1; + } + + return result; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/linuxthreads/tst-static-locale.c b/linuxthreads/tst-static-locale.c new file mode 100644 index 0000000000..3c88e729ba --- /dev/null +++ b/linuxthreads/tst-static-locale.c @@ -0,0 +1,13 @@ +/* Test that the thread-local locale works right in the main thread + when statically linked. */ + +#include "../locale/tst-C-locale.c" + +#include <pthread.h> + +/* This is never called, just here to get pthreads linked in. */ +void +useless (void) +{ + pthread_create (0, 0, 0, 0); +} diff --git a/linuxthreads/tst-tls1.c b/linuxthreads/tst-tls1.c new file mode 100644 index 0000000000..3638b75455 --- /dev/null +++ b/linuxthreads/tst-tls1.c @@ -0,0 +1,91 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* Check alignment, overlapping and layout of TLS variables. */ +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <pthread.h> +#include <sys/param.h> + +#include "tst-tls1.h" + +#ifdef TLS_REGISTER + +struct tls_obj tls_registry[64]; + +static int +tls_addr_cmp (const void *a, const void *b) +{ + if (((struct tls_obj *)a)->addr < ((struct tls_obj *)b)->addr) + return -1; + if (((struct tls_obj *)a)->addr > ((struct tls_obj *)b)->addr) + return 1; + return 0; +} + +static int +do_test (void) +{ + size_t cnt, i; + int res = 0; + uintptr_t min_addr = ~(uintptr_t) 0, max_addr = 0; + + for (cnt = 0; tls_registry[cnt].name; ++cnt); + + qsort (tls_registry, cnt, sizeof (struct tls_obj), tls_addr_cmp); + + for (i = 0; i < cnt; ++i) + { + printf ("%s = %p, size %zd, align %zd", + tls_registry[i].name, (void *) tls_registry[i].addr, + tls_registry[i].size, tls_registry[i].align); + if (tls_registry[i].addr & (tls_registry[i].align - 1)) + { + fputs (", WRONG ALIGNMENT", stdout); + res = 1; + } + if (i > 0 + && (tls_registry[i - 1].addr + tls_registry[i - 1].size + > tls_registry[i].addr)) + { + fputs (", ADDRESS OVERLAP", stdout); + res = 1; + } + puts (""); + min_addr = MIN (tls_registry[i].addr, min_addr); + max_addr = MAX (tls_registry[i].addr + tls_registry[i].size, + max_addr); + } + + if (cnt > 1) + printf ("Initial TLS used block size %zd\n", + (size_t) (max_addr - min_addr)); + return res; +} + +#define TEST_FUNCTION do_test () + +#else + +#define TEST_FUNCTION 0 + +#endif + +#include "../test-skeleton.c" diff --git a/linuxthreads/tst-tls1.h b/linuxthreads/tst-tls1.h new file mode 100644 index 0000000000..b7c14eb82c --- /dev/null +++ b/linuxthreads/tst-tls1.h @@ -0,0 +1,28 @@ +#include <stdint.h> +#include <stdlib.h> +#include <tls.h> + +#if USE_TLS && HAVE___THREAD + +struct tls_obj +{ + const char *name; + uintptr_t addr; + size_t size; + size_t align; +}; +extern struct tls_obj tls_registry[]; + +#define TLS_REGISTER(x) \ +static void __attribute__((constructor)) \ +tls_register_##x (void) \ +{ \ + size_t i; \ + for (i = 0; tls_registry[i].name; ++i); \ + tls_registry[i].name = #x; \ + tls_registry[i].addr = (uintptr_t) &x; \ + tls_registry[i].size = sizeof (x); \ + tls_registry[i].align = __alignof__ (x); \ +} + +#endif diff --git a/linuxthreads/tst-tls1mod.c b/linuxthreads/tst-tls1mod.c new file mode 100644 index 0000000000..a93d2cb9e6 --- /dev/null +++ b/linuxthreads/tst-tls1mod.c @@ -0,0 +1,6 @@ +#include <tst-tls1.h> + +#ifdef TLS_REGISTER +/* Ensure tls_registry is exported from the binary. */ +void *tst_tls1mod attribute_hidden = tls_registry; +#endif diff --git a/linuxthreads/tst-tls1moda.c b/linuxthreads/tst-tls1moda.c new file mode 100644 index 0000000000..a652ef981f --- /dev/null +++ b/linuxthreads/tst-tls1moda.c @@ -0,0 +1,6 @@ +#include <tst-tls1.h> + +#ifdef TLS_REGISTER +static __thread char a [32] __attribute__ ((aligned (64))); +TLS_REGISTER (a) +#endif diff --git a/linuxthreads/tst-tls1modb.c b/linuxthreads/tst-tls1modb.c new file mode 100644 index 0000000000..be8c95b486 --- /dev/null +++ b/linuxthreads/tst-tls1modb.c @@ -0,0 +1,6 @@ +#include <tst-tls1.h> + +#ifdef TLS_REGISTER +static __thread int b; +TLS_REGISTER (b) +#endif diff --git a/linuxthreads/tst-tls1modc.c b/linuxthreads/tst-tls1modc.c new file mode 100644 index 0000000000..e1094bf7aa --- /dev/null +++ b/linuxthreads/tst-tls1modc.c @@ -0,0 +1,6 @@ +#include <tst-tls1.h> + +#ifdef TLS_REGISTER +static __thread int c; +TLS_REGISTER (c) +#endif diff --git a/linuxthreads/tst-tls1modd.c b/linuxthreads/tst-tls1modd.c new file mode 100644 index 0000000000..cd68e0c26a --- /dev/null +++ b/linuxthreads/tst-tls1modd.c @@ -0,0 +1,6 @@ +#include <tst-tls1.h> + +#ifdef TLS_REGISTER +static __thread int d; +TLS_REGISTER (d) +#endif diff --git a/linuxthreads/tst-tls1mode.c b/linuxthreads/tst-tls1mode.c new file mode 100644 index 0000000000..845d31a4e4 --- /dev/null +++ b/linuxthreads/tst-tls1mode.c @@ -0,0 +1,8 @@ +#include <tst-tls1.h> + +#ifdef TLS_REGISTER +static __thread int e1 = 24; +static __thread char e2 [32] __attribute__ ((aligned (64))); +TLS_REGISTER (e1) +TLS_REGISTER (e2) +#endif diff --git a/linuxthreads/tst-tls1modf.c b/linuxthreads/tst-tls1modf.c new file mode 100644 index 0000000000..a292e56c57 --- /dev/null +++ b/linuxthreads/tst-tls1modf.c @@ -0,0 +1,9 @@ +#include <tst-tls1.h> + +#ifdef TLS_REGISTER +char tst_tls1modf[60] attribute_hidden = { 26 }; +static __thread int f1 = 24; +static __thread char f2 [32] __attribute__ ((aligned (64))); +TLS_REGISTER (f1) +TLS_REGISTER (f2) +#endif diff --git a/linuxthreads/tst-tls2.sh b/linuxthreads/tst-tls2.sh new file mode 100644 index 0000000000..0d13963d5e --- /dev/null +++ b/linuxthreads/tst-tls2.sh @@ -0,0 +1,53 @@ +#!/bin/sh + +common_objpfx=$1; shift +elf_objpfx=$1; shift +rtld_installed_name=$1; shift +logfile=$common_objpfx/linuxthreads/tst-tls2.out + +# We have to find libc and linuxthreads +library_path=${common_objpfx}:${common_objpfx}linuxthreads +tst_tls1="${elf_objpfx}${rtld_installed_name} --library-path ${library_path} \ + ${common_objpfx}/linuxthreads/tst-tls1" + +LC_ALL=C +export LC_ALL +LANG=C +export LANG + +> $logfile +fail=0 + +for aligned in a e f; do + echo "preload tst-tls1mod{$aligned,b,c,d}.so" >> $logfile + echo "===============" >> $logfile + LD_PRELOAD=`echo ${common_objpfx}linuxthreads/tst-tls1mod{$aligned,b,c,d}.so \ + | sed 's/:$//;s/: /:/g'` ${tst_tls1} >> $logfile || fail=1 + echo >> $logfile + + echo "preload tst-tls1mod{b,$aligned,c,d}.so" >> $logfile + echo "===============" >> $logfile + LD_PRELOAD=`echo ${common_objpfx}linuxthreads/tst-tls1mod{b,$aligned,c,d}.so \ + | sed 's/:$//;s/: /:/g'` ${tst_tls1} >> $logfile || fail=1 + echo >> $logfile + + echo "preload tst-tls1mod{b,c,d,$aligned}.so" >> $logfile + echo "===============" >> $logfile + LD_PRELOAD=`echo ${common_objpfx}linuxthreads/tst-tls1mod{b,c,d,$aligned}.so \ + | sed 's/:$//;s/: /:/g'` ${tst_tls1} >> $logfile || fail=1 + echo >> $logfile +done + +echo "preload tst-tls1mod{d,a,b,c,e}" >> $logfile +echo "===============" >> $logfile +LD_PRELOAD=`echo ${common_objpfx}linuxthreads/tst-tls1mod{d,a,b,c,e}.so \ + | sed 's/:$//;s/: /:/g'` ${tst_tls1} >> $logfile || fail=1 +echo >> $logfile + +echo "preload tst-tls1mod{d,a,b,e,f}" >> $logfile +echo "===============" >> $logfile +LD_PRELOAD=`echo ${common_objpfx}linuxthreads/tst-tls1mod{d,a,b,e,f}.so \ + | sed 's/:$//;s/: /:/g'` ${tst_tls1} >> $logfile || fail=1 +echo >> $logfile + +exit $fail diff --git a/linuxthreads/tststack.c b/linuxthreads/tststack.c new file mode 100644 index 0000000000..02b15cb8bc --- /dev/null +++ b/linuxthreads/tststack.c @@ -0,0 +1,74 @@ +/* Tests for variable stack size handling. + Copyright (C) 2000, 2003 Free Software Foundation, Inc. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2000. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <pthread.h> +#include <stdio.h> +#include <unistd.h> +#include <limits.h> +#include <sys/param.h> + +static void *f1 (void *); +static void *f2 (void *); + +int +main (void) +{ + pthread_attr_t attr; + pthread_t th1 = 0; + pthread_t th2 = 0; + void *res1; + void *res2; + + pthread_attr_init (&attr); + if (pthread_attr_setstacksize (&attr, MAX (70*1024, PTHREAD_STACK_MIN)) != 0) + { + puts ("invalid stack size"); + return 1; + } + + pthread_create (&th1, NULL, f1, NULL); + pthread_create (&th2, &attr, f2, NULL); + + pthread_join (th1, &res1); + pthread_join (th2, &res2); + + printf ("res1 = %p\n", res1); + printf ("res2 = %p\n", res2); + + return res1 != (void *) 1 || res2 != (void *) 2; +} + +static void * +f1 (void *parm) +{ + printf ("This is `%s'\n", __FUNCTION__); + fflush (stdout); + + return (void *) 1; +} + +static void * +f2 (void *parm) +{ + printf ("This is `%s'\n", __FUNCTION__); + fflush (stdout); + sleep (1); + + return (void *) 2; +} diff --git a/linuxthreads/unload.c b/linuxthreads/unload.c new file mode 100644 index 0000000000..234d27f904 --- /dev/null +++ b/linuxthreads/unload.c @@ -0,0 +1,45 @@ +/* Tests for non-unloading of libpthread. + Copyright (C) 2000, 2002 Free Software Foundation, Inc. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2000. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <dlfcn.h> +#include <stdio.h> +#include <stdlib.h> +#include <gnu/lib-names.h> + +int +main (void) +{ + void *p = dlopen (PREFIX LIBPTHREAD_SO, RTLD_LAZY); + + if (p == NULL) + { + printf ("failed to load %s: %s\n", LIBPTHREAD_SO, dlerror ()); + exit (1); + } + + if (dlclose (p) != 0) + { + printf ("dlclose (%s) failed: %s\n", LIBPTHREAD_SO, dlerror ()); + exit (1); + } + + puts ("seems to work"); + + exit (0); +} |