]> sourceware.org Git - glibc.git/commitdiff
Initial revision cvs/initial
authorUlrich Drepper <drepper@redhat.com>
Tue, 26 Nov 2002 22:50:54 +0000 (22:50 +0000)
committerUlrich Drepper <drepper@redhat.com>
Tue, 26 Nov 2002 22:50:54 +0000 (22:50 +0000)
2002-11-26  Ulrich Drepper  <drepper@redhat.com>
* allocatestack.c (queue_stack): Don't remove stack from list here.
Do it in the caller.  Correct condition to prematurely terminate
loop to free stacks.
(__deallocate_stack): Remove stack from list here.
2002-11-26  Ulrich Drepper  <drepper@redhat.com>
* Makefile (tests): Add tst-stack1.
* tst-stack1.c: New file.
* allocatestack.c (allocate_stack): Initialize the TCB on a user
provided stack.
* pthread_attr_getstack.c: Return bottom of the thread area.
2002-11-25  Ulrich Drepper  <drepper@redhat.com>
* Makefile (libpthread-routines): Add pt-allocrtsig and
pthread_kill_other_threads.
* pt-allocrtsig.c: New file.
* pthread_kill_other_threads.c: New file.
* sysdeps/unix/sysv/linux/allocrtsig.c: Add additional aliases for
all three functions.
* sysdeps/unix/sysv/linux/Makefile (sysdep_routines): Remove
allocrtsig.
* sysdeps/unix/sysv/linux/Versions (libc:GLIBC_PRIVATE): Export
__libc_current_sigrtmin_private, __libc_current_sigrtmax_private,
and __libc_allocate_rtsig_private.
* Versions (libpthread): Export pthread_kill_other_threads_np,
__libc_current_sigrtmin, and __libc_current_sigrtmax.
2002-11-24  Ulrich Drepper  <drepper@redhat.com>

* allocatestack.c (allocate_stack): stackaddr in attribute points to
the end of the stack.  Adjust computations.
When mprotect call fails dequeue stack and free it.
* pthread_attr_setstack.c: Store top of the stack in stackaddr
attribute.
* pthread_getattr_np.c: Likewise.

* descr.h (IS_DETACHED): Add some more parenthesis to prevent
surprises.

2002-11-23  Ulrich Drepper  <drepper@redhat.com>

* sysdeps/pthread/pthread.h (pthread_self): __THROW must come before
attribute definitions.  Patch by Luca Barbieri <ldb@ldb.ods.org>.

2002-11-22  Ulrich Drepper  <drepper@redhat.com>

* pthread_getspecific.c: Optimize access to first 2nd-level array.
* pthread_setspecific.c: Likewise.

2002-11-21  Ulrich Drepper  <drepper@redhat.com>

* sysdeps/unix/sysv/linux/i386/createthread.c: Remove CLONE_ flags
definitions.  Get them from the official place.
* sysdeps/unix/sysv/linux/i386/fork.c: Likewise.

* sysdeps/unix/sysv/linux/i386/createthread.c: Update CLONE_* flags.
Use new CLONE_ flags in clone() calls.

* sysdeps/unix/sysv/linux/fork.c: Use ARCH_FORK to actually fork.
* sysdeps/unix/sysv/linux/i386/fork.c: New file.

* Versions: Add pthread_* functions for libc.
* forward.c: New file.

* sysdeps/pthread/Makefile (libpthread-sysdeps_routines): Add
errno-loc.
* herrno.c: New file.
* res.c: New file.

* Makefile (libpthread-routines): Remove sem_post, sem_wait,
sem_trywait, and sem_timedwait.  Add herrno and res.
* sem_init.c: Don't initialize lock and waiters members.
* sem_open.c: Likewise.
* sem_post.c: Removed.
* sem_wait.c: Removed.
* sem_trywait.c: Removed.
* sem_timedwait.c: Removed.
* sysdeps/unix/sysv/linux/i386/i486/lowlevelsem.S: Complete rewrite.
Includes full implementations of sem_post, sem_wait, sem_trywait,
and sem_timedwait.
* sysdeps/unix/sysv/linux/i386/lowlevelsem.h (lll_sem_post): Adjust
for new implementation.
* sysdeps/unix/sysv/linux/internaltypes.h (struct sem): Remove lock
and waiters fields.

* tst-sem3.c: Improve error message.
* tst-signal3.c: Likewise.

* init.c (__pthread_initialize_minimal): Use set_tid_address syscall
to tell the kernel about the termination futex and to initialize tid
member.  Don't initialize main_thread.
* descr.h (struct pthread): Remove main_thread member.
* cancelllation.c (__do_cancel): Remove code handling main thread.
The main thread is not special anymore.

* allocatestack.c (__reclaim_stacks): Mark stacks as unused.  Add
size of the stacks to stack_cache_actsize.

* pt-readv.c: Add missing "defined".
* pt-sigwait.c: Likewise.
* pt-writev.c: Likewise.

2002-11-09  Ulrich Drepper  <drepper@redhat.com>

* Versions: Export __connect from libpthread.
Patch by Luca Barbieri <ldb@ldb.ods.org>.

* Makefile (libpthread-routines): Add pt-raise.
* sysdeps/unix/sysv/linux/raise.c: New file.
* sysdeps/unix/sysv/linux/pt-raise.c: New file.
* sysdeps/generic/pt-raise.c: New file.

* pthread_cond_init.c: Initialize all data elements of the condvar
structure.  Patch by Luca Barbieri <ldb@ldb.ods.org>.

* pthread_attr_init.c: Actually implement 2.0 compatibility version.
* pthread_create.c: Likewise.

* Makefile (tests): Add tst-key1, tst-key2, tst-key3.
* tst-key1.c: New file.
* tst-key2.c: New file.
* tst-key3.c: New file.

* Versions: Export pthread_detach for version GLIBC_2.0.
Reported by Saurabh Desai <sdesai@austin.ibm.com>.

2002-11-08  Ulrich Drepper  <drepper@redhat.com>

* pthread_key_create.c: Terminate search after an unused key was found.
Patch by Luca Barbieri <ldb@ldb.ods.org>.

* sysdeps/unix/sysv/linux/i386/pthread_once.S: Return zero.
Patch by Luca Barbieri <ldb@ldb.ods.org>.

2002-10-10  Ulrich Drepper  <drepper@redhat.com>

* sysdeps/unix/sysv/linux/i386/i486/lowlevelsem.S: Use slow generic
dynamic lookup for errno in PIC.

* allocatestack.c (get_cached_stack): Rearrange code slightly to
release the stack lock as soon as possible.
Call _dl_allocate_tls_init for TCB from the cache to re-initialize
the static TLS block.
(allocate_stack): Call _dl_allocate_tls_init for user-provided stack.

* cancellation.c: Renamed from cancelation.c.
* Makefile: Adjust accordingly.
* pthreadP.h (CANCELLATION_P): Renamed from CANCELATION_P.
* cleanup_defer.c: Use CANCELLATION_P.
* pthread_testcancel.c: Likewise.
* descr.h: Fix spelling in comments.
* init.c: Likewise.
* pthread_getattr_np.c: Likewise.
* pthread_getschedparam.c: Likewise.
* pthread_setschedparam.c: Likewise.
* Versions: Likewise.

* pt-pselect.c: New file.
* Makefile (libpthread-routines): Add pt-pselect.
* Versions: Add pselect.

* tst-cancel4.c: New file.
* Makefile (tests): Add tst-cancel4.

2002-10-09  Ulrich Drepper  <drepper@redhat.com>

* pthread_mutex_lock.c: Always record lock ownership.
* pthread_mutex_timedlock.c: Likewise.
* pthread_mutex_trylock.c: Likewise.

* pt-readv.c: New file.
* pt-writev.c: New file.
* pt-creat.c: New file.
* pt-msgrcv.c: New file.
* pt-msgsnd.c: New file.
* pt-poll.c: New file.
* pt-select.c: New file.
* pt-sigpause.c: New file.
* pt-sigsuspend.c: New file.
* pt-sigwait.c: New file.
* pt-sigwaitinfo.c: New file.
* pt-waitid.c: New file.
* Makefile (libpthread-routines): Add pt-readv, pt-writev, pt-creat,
pt-msgrcv, pt-msgsnd, pt-poll, pt-select, pt-sigpause, pt-sigsuspend,
pt-sigwait, pt-sigwaitinfo, and pt-waitid.
* Versions: Add all the new functions.

* tst-exit1.c: New file.
* Makefile (tests): Add tst-exit1.

* sem_timedwait.c: Minor optimization for more optimal fastpath.

2002-10-08  Ulrich Drepper  <drepper@redhat.com>

* pt-fcntl.c: Only enable asynchronous cancellation for F_SETLKW.

* pthread_join.c: Enable asynchronous cancellation around lll_wait_tid
call.  pthread_join is an official cancellation point.
* pthread_timedjoin.c: Likewise.

* pthread_cond_wait.c: Revert order in which internal lock are dropped
and the condvar's mutex are retrieved.
* pthread_cond_timedwait.c: Likewise.
Reported by dice@saros.East.Sun.COM.

2002-10-07  Ulrich Drepper  <drepper@redhat.com>

* pthreadP.h: Cut out all type definitions and move them...
* sysdeps/unix/sysv/linux/internaltypes.h: ...here.  New file.
* pthreadP.h: Include <internaltypes.h>.

* sysdeps/unix/sysv/linux/i386/lowlevelsem.h (lll_sem_post): Little
performance tweaks.

* sem_trywait.c: Shuffle #includes around to get right order.
* sem_timedwait.c: Likewise.
* sem_post.c: Likewise.
* sem_wait.c: Likewise.

* nptl 0.3 released.

* Makefile (tests): Add tst-signal3.
* tst-signal3.c: New file.

2002-10-05  Ulrich Drepper  <drepper@redhat.com>

* sysdeps/unix/sysv/linux/i386/lowlevelsem.h: Tell the compiler that
the asms modify the sem object.
(__lll_sem_timedwait): Now takes struct sem* as first parameter.

* sysdeps/unix/sysv/linux/i386/bits/semaphore.h (sem_t): Don't expose
the actual members.
* pthreadP.h (struct sem): New type.  Actual semaphore type.
* semaphoreP.h: Include pthreadP.h.
* sem_getvalue.c: Adjust to sem_t change.
* sem_init.c: Likewise.
* sem_open.c: Likewise.
* sem_post.c: Likewise.
* sem_timedwait.c: Likewise.
* sem_trywait.c: Likewise.
* sem_wait.c: Likewise.

2002-10-04  Ulrich Drepper  <drepper@redhat.com>

* Makefile (tests): Add tst-basic2, tst-exec1, tst-exec3, tst-exec3.
* tst-basic2.c: New file.
* tst-exec1.c: New file.
* tst-exec2.c: New file.
* tst-exec3.c: New file.

* tst-fork1.c: Remove extra */.

* nptl 0.2 released.  The API for IA-32 is complete.

352 files changed:
nptl/ANNOUNCE [new file with mode: 0644]
nptl/Banner [new file with mode: 0644]
nptl/ChangeLog [new file with mode: 0644]
nptl/DESIGN-barrier.txt [new file with mode: 0644]
nptl/DESIGN-condvar.txt [new file with mode: 0644]
nptl/DESIGN-rwlock.txt [new file with mode: 0644]
nptl/DESIGN-sem-old.txt [new file with mode: 0644]
nptl/DESIGN-sem.txt [new file with mode: 0644]
nptl/Makeconfig [new file with mode: 0644]
nptl/Makefile [new file with mode: 0644]
nptl/TODO [new file with mode: 0644]
nptl/TODO-kernel [new file with mode: 0644]
nptl/Versions [new file with mode: 0644]
nptl/alloca_cutoff.c [new file with mode: 0644]
nptl/allocatestack.c [new file with mode: 0644]
nptl/atomic.h [new file with mode: 0644]
nptl/cancellation.c [new file with mode: 0644]
nptl/cleanup.c [new file with mode: 0644]
nptl/cleanup_defer.c [new file with mode: 0644]
nptl/configure [new file with mode: 0644]
nptl/descr.h [new file with mode: 0644]
nptl/events.c [new file with mode: 0644]
nptl/flockfile.c [new file with mode: 0644]
nptl/forward.c [new file with mode: 0644]
nptl/ftrylockfile.c [new file with mode: 0644]
nptl/funlockfile.c [new file with mode: 0644]
nptl/herrno.c [new file with mode: 0644]
nptl/init.c [new file with mode: 0644]
nptl/old_pthread_atfork.c [new file with mode: 0644]
nptl/perf.c [new file with mode: 0644]
nptl/pt-accept.c [new file with mode: 0644]
nptl/pt-allocrtsig.c [new file with mode: 0644]
nptl/pt-close.c [new file with mode: 0644]
nptl/pt-connect.c [new file with mode: 0644]
nptl/pt-creat.c [new file with mode: 0644]
nptl/pt-fcntl.c [new file with mode: 0644]
nptl/pt-fsync.c [new file with mode: 0644]
nptl/pt-longjmp.c [new file with mode: 0644]
nptl/pt-lseek.c [new file with mode: 0644]
nptl/pt-lseek64.c [new file with mode: 0644]
nptl/pt-msgrcv.c [new file with mode: 0644]
nptl/pt-msgsnd.c [new file with mode: 0644]
nptl/pt-msync.c [new file with mode: 0644]
nptl/pt-nanosleep.c [new file with mode: 0644]
nptl/pt-open.c [new file with mode: 0644]
nptl/pt-open64.c [new file with mode: 0644]
nptl/pt-pause.c [new file with mode: 0644]
nptl/pt-poll.c [new file with mode: 0644]
nptl/pt-pread.c [new file with mode: 0644]
nptl/pt-pread64.c [new file with mode: 0644]
nptl/pt-pselect.c [new file with mode: 0644]
nptl/pt-pwrite.c [new file with mode: 0644]
nptl/pt-pwrite64.c [new file with mode: 0644]
nptl/pt-read.c [new file with mode: 0644]
nptl/pt-readv.c [new file with mode: 0644]
nptl/pt-recv.c [new file with mode: 0644]
nptl/pt-recvfrom.c [new file with mode: 0644]
nptl/pt-recvmsg.c [new file with mode: 0644]
nptl/pt-select.c [new file with mode: 0644]
nptl/pt-send.c [new file with mode: 0644]
nptl/pt-sendmsg.c [new file with mode: 0644]
nptl/pt-sendto.c [new file with mode: 0644]
nptl/pt-siglongjmp.c [new file with mode: 0644]
nptl/pt-sigpause.c [new file with mode: 0644]
nptl/pt-sigsuspend.c [new file with mode: 0644]
nptl/pt-sigtimedwait.c [new file with mode: 0644]
nptl/pt-sigwait.c [new file with mode: 0644]
nptl/pt-sigwaitinfo.c [new file with mode: 0644]
nptl/pt-system.c [new file with mode: 0644]
nptl/pt-tcdrain.c [new file with mode: 0644]
nptl/pt-wait.c [new file with mode: 0644]
nptl/pt-waitid.c [new file with mode: 0644]
nptl/pt-waitpid.c [new file with mode: 0644]
nptl/pt-write.c [new file with mode: 0644]
nptl/pt-writev.c [new file with mode: 0644]
nptl/pthreadP.h [new file with mode: 0644]
nptl/pthread_atfork.c [new file with mode: 0644]
nptl/pthread_attr_destroy.c [new file with mode: 0644]
nptl/pthread_attr_getdetachstate.c [new file with mode: 0644]
nptl/pthread_attr_getguardsize.c [new file with mode: 0644]
nptl/pthread_attr_getinheritsched.c [new file with mode: 0644]
nptl/pthread_attr_getschedparam.c [new file with mode: 0644]
nptl/pthread_attr_getschedpolicy.c [new file with mode: 0644]
nptl/pthread_attr_getscope.c [new file with mode: 0644]
nptl/pthread_attr_getstack.c [new file with mode: 0644]
nptl/pthread_attr_getstackaddr.c [new file with mode: 0644]
nptl/pthread_attr_getstacksize.c [new file with mode: 0644]
nptl/pthread_attr_init.c [new file with mode: 0644]
nptl/pthread_attr_setdetachstate.c [new file with mode: 0644]
nptl/pthread_attr_setguardsize.c [new file with mode: 0644]
nptl/pthread_attr_setinheritsched.c [new file with mode: 0644]
nptl/pthread_attr_setschedparam.c [new file with mode: 0644]
nptl/pthread_attr_setschedpolicy.c [new file with mode: 0644]
nptl/pthread_attr_setscope.c [new file with mode: 0644]
nptl/pthread_attr_setstack.c [new file with mode: 0644]
nptl/pthread_attr_setstackaddr.c [new file with mode: 0644]
nptl/pthread_attr_setstacksize.c [new file with mode: 0644]
nptl/pthread_barrier_destroy.c [new file with mode: 0644]
nptl/pthread_barrier_init.c [new file with mode: 0644]
nptl/pthread_barrierattr_destroy.c [new file with mode: 0644]
nptl/pthread_barrierattr_getpshared.c [new file with mode: 0644]
nptl/pthread_barrierattr_init.c [new file with mode: 0644]
nptl/pthread_barrierattr_setpshared.c [new file with mode: 0644]
nptl/pthread_cancel.c [new file with mode: 0644]
nptl/pthread_clock_gettime.c [new file with mode: 0644]
nptl/pthread_clock_settime.c [new file with mode: 0644]
nptl/pthread_cond_broadcast.c [new file with mode: 0644]
nptl/pthread_cond_destroy.c [new file with mode: 0644]
nptl/pthread_cond_init.c [new file with mode: 0644]
nptl/pthread_cond_signal.c [new file with mode: 0644]
nptl/pthread_cond_timedwait.c [new file with mode: 0644]
nptl/pthread_cond_wait.c [new file with mode: 0644]
nptl/pthread_condattr_destroy.c [new file with mode: 0644]
nptl/pthread_condattr_getpshared.c [new file with mode: 0644]
nptl/pthread_condattr_init.c [new file with mode: 0644]
nptl/pthread_condattr_setpshared.c [new file with mode: 0644]
nptl/pthread_create.c [new file with mode: 0644]
nptl/pthread_detach.c [new file with mode: 0644]
nptl/pthread_equal.c [new file with mode: 0644]
nptl/pthread_exit.c [new file with mode: 0644]
nptl/pthread_getattr_np.c [new file with mode: 0644]
nptl/pthread_getconcurrency.c [new file with mode: 0644]
nptl/pthread_getschedparam.c [new file with mode: 0644]
nptl/pthread_getspecific.c [new file with mode: 0644]
nptl/pthread_join.c [new file with mode: 0644]
nptl/pthread_key_create.c [new file with mode: 0644]
nptl/pthread_key_delete.c [new file with mode: 0644]
nptl/pthread_kill_other_threads.c [new file with mode: 0644]
nptl/pthread_mutex_destroy.c [new file with mode: 0644]
nptl/pthread_mutex_init.c [new file with mode: 0644]
nptl/pthread_mutex_lock.c [new file with mode: 0644]
nptl/pthread_mutex_timedlock.c [new file with mode: 0644]
nptl/pthread_mutex_trylock.c [new file with mode: 0644]
nptl/pthread_mutex_unlock.c [new file with mode: 0644]
nptl/pthread_mutexattr_destroy.c [new file with mode: 0644]
nptl/pthread_mutexattr_getpshared.c [new file with mode: 0644]
nptl/pthread_mutexattr_gettype.c [new file with mode: 0644]
nptl/pthread_mutexattr_init.c [new file with mode: 0644]
nptl/pthread_mutexattr_setpshared.c [new file with mode: 0644]
nptl/pthread_mutexattr_settype.c [new file with mode: 0644]
nptl/pthread_rwlock_destroy.c [new file with mode: 0644]
nptl/pthread_rwlock_init.c [new file with mode: 0644]
nptl/pthread_rwlock_tryrdlock.c [new file with mode: 0644]
nptl/pthread_rwlock_trywrlock.c [new file with mode: 0644]
nptl/pthread_rwlockattr_destroy.c [new file with mode: 0644]
nptl/pthread_rwlockattr_getkind_np.c [new file with mode: 0644]
nptl/pthread_rwlockattr_getpshared.c [new file with mode: 0644]
nptl/pthread_rwlockattr_init.c [new file with mode: 0644]
nptl/pthread_rwlockattr_setkind_np.c [new file with mode: 0644]
nptl/pthread_rwlockattr_setpshared.c [new file with mode: 0644]
nptl/pthread_self.c [new file with mode: 0644]
nptl/pthread_setcancelstate.c [new file with mode: 0644]
nptl/pthread_setcanceltype.c [new file with mode: 0644]
nptl/pthread_setconcurrency.c [new file with mode: 0644]
nptl/pthread_setschedparam.c [new file with mode: 0644]
nptl/pthread_setspecific.c [new file with mode: 0644]
nptl/pthread_testcancel.c [new file with mode: 0644]
nptl/pthread_timedjoin.c [new file with mode: 0644]
nptl/pthread_tryjoin.c [new file with mode: 0644]
nptl/res.c [new file with mode: 0644]
nptl/sem_close.c [new file with mode: 0644]
nptl/sem_destroy.c [new file with mode: 0644]
nptl/sem_getvalue.c [new file with mode: 0644]
nptl/sem_init.c [new file with mode: 0644]
nptl/sem_open.c [new file with mode: 0644]
nptl/sem_unlink.c [new file with mode: 0644]
nptl/semaphore.h [new file with mode: 0644]
nptl/semaphoreP.h [new file with mode: 0644]
nptl/shlib-versions [new file with mode: 0644]
nptl/sockperf.c [new file with mode: 0644]
nptl/sysdeps/generic/lowlevellock.h [new file with mode: 0644]
nptl/sysdeps/generic/pt-raise.c [new file with mode: 0644]
nptl/sysdeps/i386/i686/bits/atomic.h [new file with mode: 0644]
nptl/sysdeps/i386/i686/pthread_spin_trylock.S [new file with mode: 0644]
nptl/sysdeps/i386/i686/tls.h [new file with mode: 0644]
nptl/sysdeps/i386/pthread_sigmask.c [new file with mode: 0644]
nptl/sysdeps/i386/pthread_spin_destroy.c [new file with mode: 0644]
nptl/sysdeps/i386/pthread_spin_init.c [new file with mode: 0644]
nptl/sysdeps/i386/pthread_spin_lock.c [new file with mode: 0644]
nptl/sysdeps/i386/pthread_spin_unlock.S [new file with mode: 0644]
nptl/sysdeps/i386/pthreaddef.h [new file with mode: 0644]
nptl/sysdeps/i386/tls.h [new file with mode: 0644]
nptl/sysdeps/pthread/Makefile [new file with mode: 0644]
nptl/sysdeps/pthread/Subdirs [new file with mode: 0644]
nptl/sysdeps/pthread/allocalim.h [new file with mode: 0644]
nptl/sysdeps/pthread/bits/libc-lock.h [new file with mode: 0644]
nptl/sysdeps/pthread/bits/sigthread.h [new file with mode: 0644]
nptl/sysdeps/pthread/list.h [new file with mode: 0644]
nptl/sysdeps/pthread/posix-timer.h [new file with mode: 0644]
nptl/sysdeps/pthread/pt-initfini.c [new file with mode: 0644]
nptl/sysdeps/pthread/pthread.h [new file with mode: 0644]
nptl/sysdeps/pthread/pthread_getcpuclockid.c [new file with mode: 0644]
nptl/sysdeps/pthread/pthread_once.c [new file with mode: 0644]
nptl/sysdeps/pthread/pthread_sigmask.c [new file with mode: 0644]
nptl/sysdeps/pthread/sigaction.c [new file with mode: 0644]
nptl/sysdeps/pthread/timer_create.c [new file with mode: 0644]
nptl/sysdeps/pthread/timer_delete.c [new file with mode: 0644]
nptl/sysdeps/pthread/timer_getoverr.c [new file with mode: 0644]
nptl/sysdeps/pthread/timer_gettime.c [new file with mode: 0644]
nptl/sysdeps/pthread/timer_routines.c [new file with mode: 0644]
nptl/sysdeps/pthread/timer_settime.c [new file with mode: 0644]
nptl/sysdeps/pthread/tst-timer.c [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/Implies [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/Makefile [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/Versions [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/allocrtsig.c [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/bits/local_lim.h [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/bits/posix_opt.h [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/configure [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/fork-gen.c [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/fork.c [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/fork.h [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/i386/bits/semaphore.h [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/i386/createthread.c [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/i386/fork.c [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevelcond.S [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevelmutex.S [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevelrwlock.S [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevelsem.S [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_barrier_wait.S [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevelcond.S [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevellock.S [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevelmutex.S [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevelrwlock.S [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevelsem.S [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_barrier_wait.S [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevelcond.S [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevellock.S [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevelmutex.S [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevelrwlock.S [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevelsem.S [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_barrier_wait.S [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/i386/lowlevelsem.h [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/i386/pt-vfork.S [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/i386/pthread_once.S [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/internaltypes.h [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/jmp-unwind.c [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/pt-fork.c [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/pt-raise.c [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/pthread_kill.c [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/pthread_yield.c [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/raise.c [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/register-atfork.c [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/unregister-atfork.c [new file with mode: 0644]
nptl/tst-atfork1.c [new file with mode: 0644]
nptl/tst-barrier1.c [new file with mode: 0644]
nptl/tst-barrier2.c [new file with mode: 0644]
nptl/tst-barrier3.c [new file with mode: 0644]
nptl/tst-basic1.c [new file with mode: 0644]
nptl/tst-basic2.c [new file with mode: 0644]
nptl/tst-cancel1.c [new file with mode: 0644]
nptl/tst-cancel2.c [new file with mode: 0644]
nptl/tst-cancel3.c [new file with mode: 0644]
nptl/tst-cancel4.c [new file with mode: 0644]
nptl/tst-cond1.c [new file with mode: 0644]
nptl/tst-cond2.c [new file with mode: 0644]
nptl/tst-cond3.c [new file with mode: 0644]
nptl/tst-cond4.c [new file with mode: 0644]
nptl/tst-cond5.c [new file with mode: 0644]
nptl/tst-cond6.c [new file with mode: 0644]
nptl/tst-exec1.c [new file with mode: 0644]
nptl/tst-exec2.c [new file with mode: 0644]
nptl/tst-exec3.c [new file with mode: 0644]
nptl/tst-exit1.c [new file with mode: 0644]
nptl/tst-flock1.c [new file with mode: 0644]
nptl/tst-flock2.c [new file with mode: 0644]
nptl/tst-fork1.c [new file with mode: 0644]
nptl/tst-join1.c [new file with mode: 0644]
nptl/tst-join2.c [new file with mode: 0644]
nptl/tst-join3.c [new file with mode: 0644]
nptl/tst-key1.c [new file with mode: 0644]
nptl/tst-key2.c [new file with mode: 0644]
nptl/tst-key3.c [new file with mode: 0644]
nptl/tst-mutex1.c [new file with mode: 0644]
nptl/tst-mutex2.c [new file with mode: 0644]
nptl/tst-mutex3.c [new file with mode: 0644]
nptl/tst-mutex4.c [new file with mode: 0644]
nptl/tst-mutex5.c [new file with mode: 0644]
nptl/tst-mutex6.c [new file with mode: 0644]
nptl/tst-mutex7.c [new file with mode: 0644]
nptl/tst-once1.c [new file with mode: 0644]
nptl/tst-once2.c [new file with mode: 0644]
nptl/tst-rwlock1.c [new file with mode: 0644]
nptl/tst-rwlock2.c [new file with mode: 0644]
nptl/tst-rwlock3.c [new file with mode: 0644]
nptl/tst-rwlock4.c [new file with mode: 0644]
nptl/tst-rwlock5.c [new file with mode: 0644]
nptl/tst-rwlock6.c [new file with mode: 0644]
nptl/tst-rwlock7.c [new file with mode: 0644]
nptl/tst-sem1.c [new file with mode: 0644]
nptl/tst-sem2.c [new file with mode: 0644]
nptl/tst-sem3.c [new file with mode: 0644]
nptl/tst-sem4.c [new file with mode: 0644]
nptl/tst-sem5.c [new file with mode: 0644]
nptl/tst-signal1.c [new file with mode: 0644]
nptl/tst-signal2.c [new file with mode: 0644]
nptl/tst-signal3.c [new file with mode: 0644]
nptl/tst-spin1.c [new file with mode: 0644]
nptl/tst-spin2.c [new file with mode: 0644]
nptl/tst-spin3.c [new file with mode: 0644]
nptl/tst-stack1.c [new file with mode: 0644]
nptl/tst-tsd1.c [new file with mode: 0644]
nptl/tst-tsd2.c [new file with mode: 0644]
nptl/tst-unload.c [new file with mode: 0644]
nptl_db/Makefile [new file with mode: 0644]
nptl_db/Versions [new file with mode: 0644]
nptl_db/proc_service.h [new file with mode: 0644]
nptl_db/shlib-versions [new file with mode: 0644]
nptl_db/td_init.c [new file with mode: 0644]
nptl_db/td_log.c [new file with mode: 0644]
nptl_db/td_symbol_list.c [new file with mode: 0644]
nptl_db/td_ta_clear_event.c [new file with mode: 0644]
nptl_db/td_ta_delete.c [new file with mode: 0644]
nptl_db/td_ta_enable_stats.c [new file with mode: 0644]
nptl_db/td_ta_event_addr.c [new file with mode: 0644]
nptl_db/td_ta_event_getmsg.c [new file with mode: 0644]
nptl_db/td_ta_get_nthreads.c [new file with mode: 0644]
nptl_db/td_ta_get_ph.c [new file with mode: 0644]
nptl_db/td_ta_get_stats.c [new file with mode: 0644]
nptl_db/td_ta_map_id2thr.c [new file with mode: 0644]
nptl_db/td_ta_map_lwp2thr.c [new file with mode: 0644]
nptl_db/td_ta_new.c [new file with mode: 0644]
nptl_db/td_ta_reset_stats.c [new file with mode: 0644]
nptl_db/td_ta_set_event.c [new file with mode: 0644]
nptl_db/td_ta_setconcurrency.c [new file with mode: 0644]
nptl_db/td_ta_thr_iter.c [new file with mode: 0644]
nptl_db/td_ta_tsd_iter.c [new file with mode: 0644]
nptl_db/td_thr_clear_event.c [new file with mode: 0644]
nptl_db/td_thr_dbresume.c [new file with mode: 0644]
nptl_db/td_thr_dbsuspend.c [new file with mode: 0644]
nptl_db/td_thr_event_enable.c [new file with mode: 0644]
nptl_db/td_thr_event_getmsg.c [new file with mode: 0644]
nptl_db/td_thr_get_info.c [new file with mode: 0644]
nptl_db/td_thr_getfpregs.c [new file with mode: 0644]
nptl_db/td_thr_getgregs.c [new file with mode: 0644]
nptl_db/td_thr_getxregs.c [new file with mode: 0644]
nptl_db/td_thr_getxregsize.c [new file with mode: 0644]
nptl_db/td_thr_set_event.c [new file with mode: 0644]
nptl_db/td_thr_setfpregs.c [new file with mode: 0644]
nptl_db/td_thr_setgregs.c [new file with mode: 0644]
nptl_db/td_thr_setprio.c [new file with mode: 0644]
nptl_db/td_thr_setsigpending.c [new file with mode: 0644]
nptl_db/td_thr_setxregs.c [new file with mode: 0644]
nptl_db/td_thr_sigsetmask.c [new file with mode: 0644]
nptl_db/td_thr_tls_get_addr.c [new file with mode: 0644]
nptl_db/td_thr_tsd.c [new file with mode: 0644]
nptl_db/td_thr_validate.c [new file with mode: 0644]
nptl_db/thread_db.h [new file with mode: 0644]
nptl_db/thread_dbP.h [new file with mode: 0644]

diff --git a/nptl/ANNOUNCE b/nptl/ANNOUNCE
new file mode 100644 (file)
index 0000000..b63c657
--- /dev/null
@@ -0,0 +1,92 @@
+Now that the Linux kernel is once again able to run all the tests we
+have and since glibc 2.3 was released it was time for a new code drop.
+I've uploaded the second code drop for the Native POSIX Thread
+Library:
+
+  ftp://people.redhat.com/drepper/nptl/nptl-0.2.tar.bz2
+
+You need
+
+- the latest of Linus' kernel from BitKeeper (or 2.5.41 when it
+  is released);
+
+- glibc 2.3
+
+- the very latest in tools such as
+
+  + gcc either from the current development branch or the gcc 3.2
+    from Red Hat Linux 8;
+
+  + binutils preferrably from CVS, from H.J. Lu's latest release for
+    Linux, or from RHL 8.
+
+
+Compiling glibc should proceed smoothly.  But there are a number of
+tests which fail, mostly because some functionality is missing in
+glibc.  Ignore those errors.  It is only important that all tests in
+nptl/ are passing.  Run
+
+  make subdirs=nptl check
+
+to run all thread tests.
+
+
+This version features several improvements:
+
+- all APIs are now implemented;
+
+- fork handling has been improved; stacks in the child are freed;
+  atfork handlers are removed if they were registered from a module
+  which gets unloaded.
+
+- pthread_tryjoin_np and pthread_timedjoin_np are implemented
+
+- TSD handling corrected and optimized.
+
+- many more tests which also test the underlying kernel implementation.
+
+- the build infrastructure has been implemented so that the DSO and
+  archives are built in usable form and with correct named.
+
+- libthread_db has been implemented.  This is the library which is
+  needed by all program which need to get access to internals of
+  libpthread (mainly debuggers).
+
+- the CPU clock functions are implemented
+
+
+
+The white paper hasn't yet been updated.  It's still available at
+
+  http://people.redhat.com/drepper/nptl-design.pdf
+
+
+This release should be ready for some serious testing.  I know it is
+hard to compile which I why I'm looking into providing binary RPMs.
+They can be used on non-critical systems.  I'll only be able to
+provide binaries for RHL8 based systems, though, and the kernel still
+must be installed separately.
+
+
+The next steps will include:
+
+- write more tests and fix the bugs which are discovered this way
+
+- update the white paper
+
+- write and run more performance tests
+
+- port to IA-64
+
+
+Interested parties are once again invited to join the mailing we
+created:
+
+
+  phil-list@redhat.com
+
+Go to
+
+  https://listman.redhat.com/mailman/listinfo/phil-list
+
+to subscribe, unsubscribe, or review the archive.
diff --git a/nptl/Banner b/nptl/Banner
new file mode 100644 (file)
index 0000000..e534282
--- /dev/null
@@ -0,0 +1 @@
+nptl 0.9 by Ulrich Drepper
diff --git a/nptl/ChangeLog b/nptl/ChangeLog
new file mode 100644 (file)
index 0000000..e34cbcf
--- /dev/null
@@ -0,0 +1,259 @@
+2002-11-26  Ulrich Drepper  <drepper@redhat.com>
+
+       * allocatestack.c (queue_stack): Don't remove stack from list here.
+       Do it in the caller.  Correct condition to prematurely terminate
+       loop to free stacks.
+       (__deallocate_stack): Remove stack from list here.
+
+2002-11-26  Ulrich Drepper  <drepper@redhat.com>
+
+       * Makefile (tests): Add tst-stack1.
+       * tst-stack1.c: New file.
+
+       * allocatestack.c (allocate_stack): Initialize the TCB on a user
+       provided stack.
+
+       * pthread_attr_getstack.c: Return bottom of the thread area.
+
+2002-11-25  Ulrich Drepper  <drepper@redhat.com>
+
+       * Makefile (libpthread-routines): Add pt-allocrtsig and
+       pthread_kill_other_threads.
+       * pt-allocrtsig.c: New file.
+       * pthread_kill_other_threads.c: New file.
+       * sysdeps/unix/sysv/linux/allocrtsig.c: Add additional aliases for
+       all three functions.
+       * sysdeps/unix/sysv/linux/Makefile (sysdep_routines): Remove
+       allocrtsig.
+       * sysdeps/unix/sysv/linux/Versions (libc:GLIBC_PRIVATE): Export
+       __libc_current_sigrtmin_private, __libc_current_sigrtmax_private,
+       and __libc_allocate_rtsig_private.
+       * Versions (libpthread): Export pthread_kill_other_threads_np,
+       __libc_current_sigrtmin, and __libc_current_sigrtmax.
+
+2002-11-24  Ulrich Drepper  <drepper@redhat.com>
+
+       * allocatestack.c (allocate_stack): stackaddr in attribute points to
+       the end of the stack.  Adjust computations.
+       When mprotect call fails dequeue stack and free it.
+       * pthread_attr_setstack.c: Store top of the stack in stackaddr
+       attribute.
+       * pthread_getattr_np.c: Likewise.
+
+       * descr.h (IS_DETACHED): Add some more parenthesis to prevent
+       surprises.
+
+2002-11-23  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/pthread/pthread.h (pthread_self): __THROW must come before
+       attribute definitions.  Patch by Luca Barbieri <ldb@ldb.ods.org>.
+
+2002-11-22  Ulrich Drepper  <drepper@redhat.com>
+
+       * pthread_getspecific.c: Optimize access to first 2nd-level array.
+       * pthread_setspecific.c: Likewise.
+
+2002-11-21  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/createthread.c: Remove CLONE_ flags
+       definitions.  Get them from the official place.
+       * sysdeps/unix/sysv/linux/i386/fork.c: Likewise.
+
+       * sysdeps/unix/sysv/linux/i386/createthread.c: Update CLONE_* flags.
+       Use new CLONE_ flags in clone() calls.
+
+       * sysdeps/unix/sysv/linux/fork.c: Use ARCH_FORK to actually fork.
+       * sysdeps/unix/sysv/linux/i386/fork.c: New file.
+
+       * Versions: Add pthread_* functions for libc.
+       * forward.c: New file.
+
+       * sysdeps/pthread/Makefile (libpthread-sysdeps_routines): Add
+       errno-loc.
+       * herrno.c: New file.
+       * res.c: New file.
+
+       * Makefile (libpthread-routines): Remove sem_post, sem_wait,
+       sem_trywait, and sem_timedwait.  Add herrno and res.
+       * sem_init.c: Don't initialize lock and waiters members.
+       * sem_open.c: Likewise.
+       * sem_post.c: Removed.
+       * sem_wait.c: Removed.
+       * sem_trywait.c: Removed.
+       * sem_timedwait.c: Removed.
+       * sysdeps/unix/sysv/linux/i386/i486/lowlevelsem.S: Complete rewrite.
+       Includes full implementations of sem_post, sem_wait, sem_trywait,
+       and sem_timedwait.
+       * sysdeps/unix/sysv/linux/i386/lowlevelsem.h (lll_sem_post): Adjust
+       for new implementation.
+       * sysdeps/unix/sysv/linux/internaltypes.h (struct sem): Remove lock
+       and waiters fields.
+
+       * tst-sem3.c: Improve error message.
+       * tst-signal3.c: Likewise.
+
+       * init.c (__pthread_initialize_minimal): Use set_tid_address syscall
+       to tell the kernel about the termination futex and to initialize tid
+       member.  Don't initialize main_thread.
+       * descr.h (struct pthread): Remove main_thread member.
+       * cancelllation.c (__do_cancel): Remove code handling main thread.
+       The main thread is not special anymore.
+
+       * allocatestack.c (__reclaim_stacks): Mark stacks as unused.  Add
+       size of the stacks to stack_cache_actsize.
+
+       * pt-readv.c: Add missing "defined".
+       * pt-sigwait.c: Likewise.
+       * pt-writev.c: Likewise.
+
+2002-11-09  Ulrich Drepper  <drepper@redhat.com>
+
+       * Versions: Export __connect from libpthread.
+       Patch by Luca Barbieri <ldb@ldb.ods.org>.
+
+       * Makefile (libpthread-routines): Add pt-raise.
+       * sysdeps/unix/sysv/linux/raise.c: New file.
+       * sysdeps/unix/sysv/linux/pt-raise.c: New file.
+       * sysdeps/generic/pt-raise.c: New file.
+
+       * pthread_cond_init.c: Initialize all data elements of the condvar
+       structure.  Patch by Luca Barbieri <ldb@ldb.ods.org>.
+
+       * pthread_attr_init.c: Actually implement 2.0 compatibility version.
+       * pthread_create.c: Likewise.
+
+       * Makefile (tests): Add tst-key1, tst-key2, tst-key3.
+       * tst-key1.c: New file.
+       * tst-key2.c: New file.
+       * tst-key3.c: New file.
+
+       * Versions: Export pthread_detach for version GLIBC_2.0.
+       Reported by Saurabh Desai <sdesai@austin.ibm.com>.
+
+2002-11-08  Ulrich Drepper  <drepper@redhat.com>
+
+       * pthread_key_create.c: Terminate search after an unused key was found.
+       Patch by Luca Barbieri <ldb@ldb.ods.org>.
+
+       * sysdeps/unix/sysv/linux/i386/pthread_once.S: Return zero.
+       Patch by Luca Barbieri <ldb@ldb.ods.org>.
+
+2002-10-10  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/i486/lowlevelsem.S: Use slow generic
+       dynamic lookup for errno in PIC.
+
+       * allocatestack.c (get_cached_stack): Rearrange code slightly to
+       release the stack lock as soon as possible.
+       Call _dl_allocate_tls_init for TCB from the cache to re-initialize
+       the static TLS block.
+       (allocate_stack): Call _dl_allocate_tls_init for user-provided stack.
+
+       * cancellation.c: Renamed from cancelation.c.
+       * Makefile: Adjust accordingly.
+       * pthreadP.h (CANCELLATION_P): Renamed from CANCELATION_P.
+       * cleanup_defer.c: Use CANCELLATION_P.
+       * pthread_testcancel.c: Likewise.
+       * descr.h: Fix spelling in comments.
+       * init.c: Likewise.
+       * pthread_getattr_np.c: Likewise.
+       * pthread_getschedparam.c: Likewise.
+       * pthread_setschedparam.c: Likewise.
+       * Versions: Likewise.
+
+       * pt-pselect.c: New file.
+       * Makefile (libpthread-routines): Add pt-pselect.
+       * Versions: Add pselect.
+
+       * tst-cancel4.c: New file.
+       * Makefile (tests): Add tst-cancel4.
+
+2002-10-09  Ulrich Drepper  <drepper@redhat.com>
+
+       * pthread_mutex_lock.c: Always record lock ownership.
+       * pthread_mutex_timedlock.c: Likewise.
+       * pthread_mutex_trylock.c: Likewise.
+
+       * pt-readv.c: New file.
+       * pt-writev.c: New file.
+       * pt-creat.c: New file.
+       * pt-msgrcv.c: New file.
+       * pt-msgsnd.c: New file.
+       * pt-poll.c: New file.
+       * pt-select.c: New file.
+       * pt-sigpause.c: New file.
+       * pt-sigsuspend.c: New file.
+       * pt-sigwait.c: New file.
+       * pt-sigwaitinfo.c: New file.
+       * pt-waitid.c: New file.
+       * Makefile (libpthread-routines): Add pt-readv, pt-writev, pt-creat,
+       pt-msgrcv, pt-msgsnd, pt-poll, pt-select, pt-sigpause, pt-sigsuspend,
+       pt-sigwait, pt-sigwaitinfo, and pt-waitid.
+       * Versions: Add all the new functions.
+
+       * tst-exit1.c: New file.
+       * Makefile (tests): Add tst-exit1.
+
+       * sem_timedwait.c: Minor optimization for more optimal fastpath.
+
+2002-10-08  Ulrich Drepper  <drepper@redhat.com>
+
+       * pt-fcntl.c: Only enable asynchronous cancellation for F_SETLKW.
+
+       * pthread_join.c: Enable asynchronous cancellation around lll_wait_tid
+       call.  pthread_join is an official cancellation point.
+       * pthread_timedjoin.c: Likewise.
+
+       * pthread_cond_wait.c: Revert order in which internal lock are dropped
+       and the condvar's mutex are retrieved.
+       * pthread_cond_timedwait.c: Likewise.
+       Reported by dice@saros.East.Sun.COM.
+
+2002-10-07  Ulrich Drepper  <drepper@redhat.com>
+
+       * pthreadP.h: Cut out all type definitions and move them...
+       * sysdeps/unix/sysv/linux/internaltypes.h: ...here.  New file.
+       * pthreadP.h: Include <internaltypes.h>.
+
+       * sysdeps/unix/sysv/linux/i386/lowlevelsem.h (lll_sem_post): Little
+       performance tweaks.
+
+       * sem_trywait.c: Shuffle #includes around to get right order.
+       * sem_timedwait.c: Likewise.
+       * sem_post.c: Likewise.
+       * sem_wait.c: Likewise.
+
+       * nptl 0.3 released.
+
+       * Makefile (tests): Add tst-signal3.
+       * tst-signal3.c: New file.
+
+2002-10-05  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/lowlevelsem.h: Tell the compiler that
+       the asms modify the sem object.
+       (__lll_sem_timedwait): Now takes struct sem* as first parameter.
+
+       * sysdeps/unix/sysv/linux/i386/bits/semaphore.h (sem_t): Don't expose
+       the actual members.
+       * pthreadP.h (struct sem): New type.  Actual semaphore type.
+       * semaphoreP.h: Include pthreadP.h.
+       * sem_getvalue.c: Adjust to sem_t change.
+       * sem_init.c: Likewise.
+       * sem_open.c: Likewise.
+       * sem_post.c: Likewise.
+       * sem_timedwait.c: Likewise.
+       * sem_trywait.c: Likewise.
+       * sem_wait.c: Likewise.
+
+2002-10-04  Ulrich Drepper  <drepper@redhat.com>
+
+       * Makefile (tests): Add tst-basic2, tst-exec1, tst-exec3, tst-exec3.
+       * tst-basic2.c: New file.
+       * tst-exec1.c: New file.
+       * tst-exec2.c: New file.
+       * tst-exec3.c: New file.
+
+       * tst-fork1.c: Remove extra */.
+
+       * nptl 0.2 released.  The API for IA-32 is complete.
diff --git a/nptl/DESIGN-barrier.txt b/nptl/DESIGN-barrier.txt
new file mode 100644 (file)
index 0000000..782377f
--- /dev/null
@@ -0,0 +1,49 @@
+Barriers pseudocode
+===================
+
+    int pthread_barrier_wait(barrier_t * barrier);
+
+struct barrier_t {
+
+   unsigned int lock:
+         - internal mutex
+
+   unsigned int left;
+         - current barrier count, # of threads still needed.
+
+   unsigned int init_count;
+         - number of threads needed for the barrier to continue.
+
+   unsigned int curr_event;
+         - generation count
+}
+
+pthread_barrier_wait(barrier_t *barrier)
+{
+  unsigned int event;
+
+  lll_lock(barrier->lock);
+  if (!--barrier->left) {
+    barrier->left = barrier->init_count;   
+    barrier->curr_event++;
+    futex_wake(&barrier->curr_event, INT_MAX)
+    lll_unlock(barrier->lock);
+
+    return BARRIER_SERIAL_THREAD;
+  }
+
+  event = barrier->curr_event;
+  for (;;) {
+    lll_unlock(barrier->lock);
+
+    futex_wait(&barrier->curr_event, event)
+
+    lll_lock(barrier->lock);
+    if (event != barrier->curr_event)
+      break;
+  }
+  lll_unlock(barrier->lock);
+
+  return 0;
+}
+
diff --git a/nptl/DESIGN-condvar.txt b/nptl/DESIGN-condvar.txt
new file mode 100644 (file)
index 0000000..303807b
--- /dev/null
@@ -0,0 +1,90 @@
+Conditional Variable pseudocode.
+================================
+
+       int pthread_cond_timedwait (pthread_cond_t *cv, pthread_mutex_t *mutex);
+       int pthread_cond_signal    (pthread_cond_t *cv);
+       int pthread_cond_broadcast (pthread_cond_t *cv);
+
+struct pthread_cond_t {
+
+   unsigned int lock:
+
+         internal mutex
+
+   unsigned int nr_wakers:
+
+         number of threads signalled to be woken up.
+
+   unsigned int nr_sleepers:
+
+         number of threads waiting for the cv.
+
+}
+
+#define ALL_THREADS (1 << (BITS_PER_LONG-1))
+
+cond_wait_timeout(cv, mutex, timeout):
+{
+   lll_lock(cv->lock);
+   mutex_unlock(mutex);
+
+   cv->nr_sleepers++;
+   for (;;) {
+
+       if (cv->nr_wakers) {
+           cv->nr_wakers--;
+           break;
+       }
+       val = cv->nr_wakers;
+
+       lll_unlock(cv->lock);
+
+       ret = FUTEX WAIT (cv->nr_wakers, val, timeout)
+
+       lll_lock(cv->lock);
+
+       if (ret == TIMEOUT)
+         break;
+       ret = 0;
+   }
+   if (!--cv->nr_sleepers)
+     cv->nr_wakers = 0; /* no memory of wakeups */
+   lll_unlock(cv->lock);
+   mutex_lock(mutex);
+
+   return ret;
+}
+
+cond_signal(cv)
+{
+   int do_wakeup = 0;
+
+   lll_lock(cv->lock);
+   if (cv->nr_sleepers) {
+     if (!++cv->nr_wakers) /* overflow detection for the nutcase */
+       cv->nr_wakers = ALL_THREADS;
+     do_wakeup = 1;
+   }
+   lll_unlock(cv->lock);
+   if (do_wakeup)
+     FUTEX WAKE (cv->nr_wakers, 1)
+}
+
+cond_broadcast(cv)
+{
+   int do_wakeup = 0;
+
+   lll_lock(cv->lock);
+   if (cv->nr_sleepers) {
+     cv->nr_wakers |= ALL_THREADS;
+     do_wakeup = 1;
+   }
+   lll_unlock(cv->lock);
+   if (do_wakeup)
+     FUTEX WAKE (cv->nr_wakers, ALL_THREADS);
+}
+
+weaknesses of the implementation:
+
+ it might generate spurious wakeups in the broadcast case, but those are
+ allowed by POSIX.
diff --git a/nptl/DESIGN-rwlock.txt b/nptl/DESIGN-rwlock.txt
new file mode 100644 (file)
index 0000000..6262a7a
--- /dev/null
@@ -0,0 +1,109 @@
+Reader Writer Locks pseudocode
+==============================
+
+       pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
+       pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
+       pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
+
+struct pthread_rwlock_t {
+
+   unsigned int lock:
+         - internal mutex
+
+   unsigned int writers_preferred;
+         - locking mode: 0 recursive, readers preferred
+                         1 nonrecursive, writers preferred
+
+   unsigned int readers;
+         - number of read-only references various threads have
+
+   pthread_t writer;
+         - descriptor of the writer or 0
+
+   unsigned int readers_wakeup;
+         - 'all readers should wake up' futex.
+
+   unsigned int writer_wakeup;
+         - 'one writer should wake up' futex.
+
+   unsigned int nr_readers_queued;
+         - number of readers queued up.
+
+   unsigned int nr_writers_queued;
+         - number of writers queued up.
+}
+
+pthread_rwlock_rdlock(pthread_rwlock_t *rwlock)
+{
+  lll_lock(rwlock->lock);
+  for (;;) {
+    if (!rwlock->writer && (!rwlock->nr_writers_queued ||
+                                       !rwlock->writers_preferred))
+        break;
+
+    rwlock->nr_readers_queued++;
+    lll_unlock(rwlock->lock);
+
+    futex_wait(&rwlock->readers_wakeup, 0)
+
+    lll_lock(rwlock->lock);
+    if (!--rwlock->nr_readers_queued)
+        rwlock->readers_wakeup = 0;
+  }
+  rwlock->readers++;
+  lll_unlock(rwlock->lock);
+}
+
+pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock)
+{
+  int result = EBUSY;
+  lll_lock(rwlock->lock);
+  if (!rwlock->writer && (!rwlock->nr_writers_queued ||
+                                       !rwlock->writers_preferred))
+    rwlock->readers++;
+  lll_unlock(rwlock->lock);
+  return result;
+}
+
+pthread_rwlock_wrlock(pthread_rwlock_t *rwlock)
+{
+  lll_lock(rwlock->lock);
+  for (;;) {
+    if (!rwlock->writer && !rwlock->readers)
+       break;
+
+    rwlock->nr_writers_queued++;
+    lll_unlock(rwlock->lock);
+
+    futex_wait(&rwlock->writer_wakeup, 0);
+
+    lll_lock(rwlock->lock);
+    rwlock->nr_writers_queued--;
+    rwlock->writer_wakeup = 0;
+  }
+  rwlock->writer = pthread_self();
+  lll_unlock(rwlock->lock);
+}
+
+pthread_rwlock_unlock(pthread_rwlock_t *rwlock)
+{
+  lll_lock(rwlock->lock);
+
+  if (rwlock->writer)
+    rwlock->writer = 0;
+  else
+    rwlock->readers--;
+
+  if (!rwlock->readers) {
+    if (rwlock->nr_writers_queued) {
+      rwlock->writer_wakeup = 1;
+      futex_wake(&rwlock->writer_wakeup, 1);
+    } else
+      if (rwlock->nr_readers_queued) {
+        rwlock->readers_wakeup = 1;
+        futex_wake(&rwlock->readers_wakeup, MAX_INT);
+      }
+  }
+
+  lll_unlock(rwlock->lock);
+}
diff --git a/nptl/DESIGN-sem-old.txt b/nptl/DESIGN-sem-old.txt
new file mode 100644 (file)
index 0000000..2db2f35
--- /dev/null
@@ -0,0 +1,67 @@
+Semaphores pseudocode
+==============================
+
+       int sem_wait(sem_t * sem);
+       int sem_trywait(sem_t * sem);
+       int sem_post(sem_t * sem);
+       int sem_getvalue(sem_t * sem, int * sval);
+
+struct sem_t {
+
+   unsigned int lock:
+         - internal mutex
+
+   unsigned int count;
+         - current semaphore count, also used as a futex
+
+   unsigned int waiters;
+         - number of threads queued in sem_wait().
+}
+
+sem_wait(sem_t *sem)
+{
+  lll_lock(sem->lock);
+  for (;;) {
+
+    if (sem->count)
+      break;
+
+    sem->waiters++;
+    lll_unlock(sem->lock);
+
+    futex_wait(&sem->count, 0)
+
+    lll_lock(sem->lock);
+    sem->waiters--;
+  }
+  sem->count--;
+  lll_unlock(sem->lock);
+}
+
+sem_post(sem_t *sem)
+{
+  lll_lock(sem->lock);
+  sem->count++;
+  if (sem->waiters)
+    futex_wake(&sem->count, sem->count);
+  lll_unlock(sem->lock);
+}
+
+sem_trywait(sem_t *sem)
+{
+  lll_lock(sem->lock);
+  if (sem->count) {
+    sem->count--;
+    lll_unlock(sem->lock);
+    return 0;
+  } else {
+    lll_unlock(sem->lock);
+    return -EAGAIN;
+  }
+}
+
+sem_getvalue(sem_t *sem, int *sval)
+{
+  *sval = sem->count;
+  read_barrier();
+}
diff --git a/nptl/DESIGN-sem.txt b/nptl/DESIGN-sem.txt
new file mode 100644 (file)
index 0000000..d25a1c2
--- /dev/null
@@ -0,0 +1,45 @@
+Semaphores pseudocode
+==============================
+
+       int sem_wait(sem_t * sem);
+       int sem_trywait(sem_t * sem);
+       int sem_post(sem_t * sem);
+       int sem_getvalue(sem_t * sem, int * sval);
+
+struct sem_t {
+
+   unsigned int count;
+         - current semaphore count, also used as a futex
+}
+
+sem_wait(sem_t *sem)
+{
+  for (;;) {
+
+    if (atomic_decrement_if_positive(sem->count))
+      break;
+
+    futex_wait(&sem->count, 0)
+  }
+}
+
+sem_post(sem_t *sem)
+{
+  n = atomic_increment(sem->count);
+  futex_wake(&sem->count, n);
+}
+
+sem_trywait(sem_t *sem)
+{
+  if (atomic_decrement_if_positive(sem->count)) {
+    return 0;
+  } else {
+    return EAGAIN;
+  }
+}
+
+sem_getvalue(sem_t *sem, int *sval)
+{
+  *sval = sem->count;
+  read_barrier();
+}
diff --git a/nptl/Makeconfig b/nptl/Makeconfig
new file mode 100644 (file)
index 0000000..61015d2
--- /dev/null
@@ -0,0 +1,30 @@
+# Copyright (C) 2002 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+# Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+# The GNU C Library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+
+# The GNU C Library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public
+# License along with the GNU C Library; if not, write to the Free
+# Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+# 02111-1307 USA.
+
+# Makeconfig fragment for linuxthreads add-on.
+# This gets included at the end of the main glibc Makeconfig.
+
+have-thread-library = yes
+
+shared-thread-library = $(common-objpfx)nptl/libpthread.so \
+                       $(common-objpfx)nptl/libpthread_nonshared.a
+static-thread-library = $(common-objpfx)nptl/libpthread.a
+bounded-thread-library = $(common-objpfx)nptl/libpthread_b.a
+
+rpath-dirs += nptl
diff --git a/nptl/Makefile b/nptl/Makefile
new file mode 100644 (file)
index 0000000..e596803
--- /dev/null
@@ -0,0 +1,226 @@
+# Copyright (C) 2002 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+
+# The GNU C Library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+
+# The GNU C Library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public
+# License along with the GNU C Library; if not, write to the Free
+# Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+# 02111-1307 USA.
+
+#
+#      Sub-makefile for NPTL portion of the library.
+#
+subdir := nptl
+
+nptl-version := $(shell sed -n 's/^.*$(subdir) \([0-9.]*\).*$$/\1/p' Banner)
+
+headers := pthread.h semaphore.h
+
+extra-libs := libpthread
+extra-libs-others := $(extra-libs)
+
+routines = alloca_cutoff forward
+shared-only-routines = forward
+
+libpthread-routines = init events \
+                     pthread_create pthread_exit pthread_detach \
+                     pthread_join pthread_tryjoin pthread_timedjoin \
+                     pthread_self pthread_equal pthread_yield \
+                     pthread_getconcurrency pthread_setconcurrency \
+                     pthread_getschedparam pthread_setschedparam \
+                     pthread_attr_init pthread_attr_destroy \
+                     pthread_attr_getdetachstate pthread_attr_setdetachstate \
+                     pthread_attr_getguardsize pthread_attr_setguardsize \
+                     pthread_attr_getschedparam pthread_attr_setschedparam \
+                     pthread_attr_getschedpolicy pthread_attr_setschedpolicy \
+                     pthread_attr_getinheritsched \
+                     pthread_attr_setinheritsched \
+                     pthread_attr_getscope pthread_attr_setscope \
+                     pthread_attr_getstackaddr pthread_attr_setstackaddr \
+                     pthread_attr_getstacksize pthread_attr_setstacksize \
+                     pthread_attr_getstack pthread_attr_setstack \
+                     pthread_getattr_np \
+                     pthread_mutex_init pthread_mutex_destroy \
+                     pthread_mutex_lock pthread_mutex_trylock \
+                     pthread_mutex_timedlock pthread_mutex_unlock \
+                     pthread_mutexattr_init pthread_mutexattr_destroy \
+                     pthread_mutexattr_getpshared \
+                     pthread_mutexattr_setpshared \
+                     pthread_mutexattr_gettype pthread_mutexattr_settype \
+                     pthread_rwlock_init pthread_rwlock_destroy \
+                     pthread_rwlock_tryrdlock pthread_rwlock_trywrlock \
+                     pthread_rwlockattr_init pthread_rwlockattr_destroy \
+                     pthread_rwlockattr_getpshared \
+                     pthread_rwlockattr_setpshared \
+                     pthread_rwlockattr_getkind_np \
+                     pthread_rwlockattr_setkind_np \
+                     pthread_cond_init pthread_cond_destroy \
+                     pthread_cond_wait pthread_cond_timedwait \
+                     pthread_cond_signal pthread_cond_broadcast \
+                     pthread_condattr_init pthread_condattr_destroy \
+                     pthread_condattr_getpshared pthread_condattr_setpshared \
+                     pthread_spin_init pthread_spin_destroy \
+                     pthread_spin_lock pthread_spin_trylock \
+                     pthread_spin_unlock \
+                     pthread_barrier_init pthread_barrier_destroy \
+                     pthread_barrier_wait \
+                     pthread_barrierattr_init pthread_barrierattr_destroy \
+                     pthread_barrierattr_getpshared \
+                     pthread_barrierattr_setpshared \
+                     pthread_key_create pthread_key_delete \
+                     pthread_getspecific pthread_setspecific \
+                     pthread_sigmask pthread_kill \
+                     pthread_cancel pthread_testcancel \
+                     pthread_setcancelstate pthread_setcanceltype \
+                     pthread_once \
+                     old_pthread_atfork\
+                     pthread_getcpuclockid \
+                     pthread_clock_gettime pthread_clock_settime \
+                     sem_init sem_destroy \
+                     sem_open sem_close sem_unlink \
+                     sem_getvalue \
+                     cleanup cleanup_defer \
+                     pt-longjmp \
+                     cancellation \
+                     lowlevellock lowlevelmutex lowlevelcond lowlevelrwlock \
+                     lowlevelsem \
+                     pt-vfork \
+                     pt-write pt-read pt-close pt-fcntl pt-accept pt-connect \
+                     pt-recv pt-recvfrom pt-recvmsg pt-send pt-sendmsg \
+                     pt-sendto pt-fsync pt-lseek pt-lseek64 pt-msync \
+                     pt-nanosleep pt-open pt-open64 pt-pause pt-pread \
+                     pt-pread64 pt-pwrite pt-pwrite64 pt-tcdrain pt-system \
+                     pt-wait pt-waitpid pt-readv pt-writev pt-creat \
+                     pt-msgrcv pt-msgsnd pt-poll pt-select pt-sigpause \
+                     pt-sigsuspend pt-sigwait pt-sigwaitinfo pt-waitid \
+                     pt-pselect pt-raise \
+                     flockfile ftrylockfile funlockfile \
+                     sigaction \
+                     herrno res pt-allocrtsig \
+                     pthread_kill_other_threads
+
+libpthread-nonshared = pthread_atfork
+
+
+tests = tst-mutex1 tst-mutex2 tst-mutex3 tst-mutex4 tst-mutex5 tst-mutex6 \
+       tst-mutex7 \
+       tst-spin1 tst-spin2 tst-spin3 \
+       tst-cond1 tst-cond2 tst-cond3 tst-cond4 tst-cond5 tst-cond6 \
+       tst-rwlock1 tst-rwlock2 tst-rwlock3 tst-rwlock4 tst-rwlock5 \
+       tst-rwlock6 tst-rwlock7 \
+       tst-once1 tst-once2 \
+       tst-key1 tst-key2 tst-key3 \
+       tst-sem1 tst-sem2 tst-sem3 tst-sem4 tst-sem5 \
+       tst-barrier1 tst-barrier2 tst-barrier3 \
+       tst-basic1 tst-basic2 \
+       tst-join1 tst-join2 tst-join3 \
+       tst-tsd1 tst-tsd2 \
+       tst-fork1 \
+       tst-atfork1 \
+       tst-cancel1 tst-cancel2 tst-cancel3 tst-cancel4 \
+       tst-flock1 tst-flock2 \
+       tst-signal1 tst-signal2 tst-signal3 \
+       tst-exec1 tst-exec2 tst-exec3 \
+       tst-exit1 \
+       tst-stack1 \
+       tst-unload
+
+LDFLAGS-pthread.so = -Wl,--enable-new-dtags,-z,nodelete,-z,initfirst
+
+
+include ../Makeconfig
+
+ifeq ($(build-shared),yes)
+others: $(objpfx)libpthread_nonshared.a
+endif
+
+$(objpfx)libpthread_nonshared.a: $(addprefix $(objpfx),$(addsuffix .os,$(libpthread-nonshared)))
+       $(AR) $(ARFLAGS) $@ $^
+
+ifeq ($(build-shared),yes)
+extra-objs += crti.o
+omit-deps += crti
+
+CFLAGS-pt-initfini.s = -g0 -fPIC -fno-inline-functions
+endif
+
+include ../Rules
+
+# What we install as libc.so for programs to link against is in fact a
+# link script.  It contains references for the various libraries we need.
+# The libc.so object is not complete since some functions are only defined
+# in libc_nonshared.a.
+# We need to use absolute paths since otherwise local copies (if they exist)
+# of the files are taken by the linker.
+install: $(inst_libdir)/libpthread.so
+$(inst_libdir)/libpthread.so: $(objpfx)libpthread.so$(libpthread.so-version) \
+                             $(inst_libdir)/$(patsubst %,$(libtype.oS),\
+                                                       $(libprefix)pthread) \
+                             $(+force)
+       (echo '/* GNU ld script';\
+        echo '   Use the shared library, but some functions are only in';\
+        echo '   the static library, so try that secondarily.  */';\
+        echo 'GROUP ( $(slibdir)/libpthread.so$(libpthread.so-version)' \
+             '$(libdir)/$(patsubst %,$(libtype.oS),$(libprefix)pthread)'\
+             ')' \
+       ) > $@.new
+       mv -f $@.new $@
+$(inst_libdir)/libpthread_nonshared.a: $(objpfx)libpthread_nonshared.a
+       $(do-install)
+
+
+CFLAGS-tst-unload.c += -DPREFIX=\"$(objpfx)\"
+
+extra-B-pthread.so = -B$(common-objpfx)linuxthreads/
+$(objpfx)libpthread.so: $(objpfx)crti.o
+$(objpfx)libpthread.so: +preinit += $(objpfx)crti.o
+
+# Depend on libc.so so a DT_NEEDED is generated in the shared objects.
+# This ensures they will load libc.so for needed symbols if loaded by
+# a statically-linked program that hasn't already loaded it.
+$(objpfx)libpthread.so: $(common-objpfx)libc.so \
+                       $(common-objpfx)libc_nonshared.a
+
+# Make sure we link with the thread library.
+ifeq ($(build-shared),yes)
+$(addprefix $(objpfx), \
+  $(filter-out $(tests-static), \
+    $(tests) $(test-srcs))): $(objpfx)libpthread.so \
+                            $(objpfx)libpthread_nonshared.a
+$(objpfx)tst-unload: $(common-objpfx)dlfcn/libdl.so
+else
+$(addprefix $(objpfx),$(tests) $(test-srcs)): $(objpfx)libpthread.a
+endif
+
+ifeq ($(build-shared),yes)
+vpath pt-initfini.c $(full_config_sysdirs)
+
+$(objpfx)pt-initfini.s: pt-initfini.c
+       $(compile.c) -S $(CFLAGS-pt-initfini.s) -finhibit-size-directive \
+               $(patsubst -f%,-fno-%,$(exceptions)) -o $@
+
+# We only have one kind of startup code files.  Static binaries and
+# shared libraries are build using the PIC version.
+$(objpfx)crti.S: $(objpfx)pt-initfini.s
+       sed -n -e '1,/@HEADER_ENDS/p' \
+              -e '/@_.*_PROLOG_BEGINS/,/@_.*_PROLOG_ENDS/p' \
+              -e '/@TRAILER_BEGINS/,$$p' $< > $@
+
+$(objpfx)defs.h: $(objpfx)pt-initfini.s
+       sed -n -e '/@TESTS_BEGIN/,/@TESTS_END/p' $< | \
+               $(AWK) -f ../csu/defs.awk > $@
+
+$(objpfx)crti.o: $(objpfx)crti.S $(objpfx)defs.h
+       $(compile.S) -g0 $(ASFLAGS-.os) -o $@
+
+generated += crti.S defs.h pt-initfini.s
+endif
diff --git a/nptl/TODO b/nptl/TODO
new file mode 100644 (file)
index 0000000..09392b1
--- /dev/null
+++ b/nptl/TODO
@@ -0,0 +1,24 @@
+- we should probably extend pthread_mutexattr_t with a field to create a
+  single linked list of all instances.  This requires changing the
+  pthread_mutexattr_* functions.
+
+
+- a new attribute for mutexes: number of times we spin before calling
+sys_futex
+
+
+
+- in case a thread calls 'fork' the stacks of all the other threads in
+  the child process are currently list.  Instead they should be recovered
+  and added to the stack cache.  This can be done by adding another global
+  list (maybe one per cluster) which lists all running threads and which
+  is processed by the child branch of fork.  All the stacks are simply
+  added to the stack cache.
+
+
+
+- test with threaded process terminating and semadj (?) being applied
+  only after all threads are gone
+
+
+- raise sends the signal to calling thread or process?
diff --git a/nptl/TODO-kernel b/nptl/TODO-kernel
new file mode 100644 (file)
index 0000000..2ee5da6
--- /dev/null
@@ -0,0 +1,26 @@
+- setuid/setgid must effect process
+  + test syscalls (getuid) afterwards
+  + test core file content
+
+  + use UID/GID in access(2), chmod(2), chown(2), link(2)
+
+- nice level is process property
+
+- process file creation mask (mkdir, mkfifo, open, creat) after umask call
+
+- getppid(() must return process ID of parent process of the thread
+  group leader
+  + test syscall
+  + test core file content (psinfo)
+
+- rlimit should be process-wide and SIGXCPU should be sent if all threads
+  together exceed the limit
+
+- getrusage() must return resource utilization for the process
+
+- sigaltstack must be per-thread (???)
+
+   I've an interpretation request outstanding
+
+- the scheduler must be thread group-aware, i.e., it has to give time to
+  the thread group not proportional to the number of threads.
diff --git a/nptl/Versions b/nptl/Versions
new file mode 100644 (file)
index 0000000..ce11c67
--- /dev/null
@@ -0,0 +1,205 @@
+libc {
+  GLIBC_2.0 {
+    pthread_attr_destroy;
+    pthread_attr_getdetachstate; pthread_attr_setdetachstate;
+    pthread_attr_getinheritsched; pthread_attr_setinheritsched;
+    pthread_attr_getschedparam; pthread_attr_setschedparam;
+    pthread_attr_getschedpolicy;  pthread_attr_setschedpolicy;
+    pthread_attr_getscope; pthread_attr_setscope;
+    pthread_condattr_destroy; pthread_condattr_init;
+    pthread_cond_broadcast; pthread_cond_destroy;
+    pthread_cond_init; pthread_cond_signal; pthread_cond_wait;
+    pthread_equal; pthread_exit;
+    pthread_getschedparam; pthread_setschedparam;
+    pthread_mutex_destroy; pthread_mutex_init;
+    pthread_mutex_lock; pthread_mutex_unlock;
+    pthread_self;
+    pthread_setcancelstate; pthread_setcanceltype;
+  }
+  GLIBC_2.1 {
+    pthread_attr_init;
+  }
+}
+
+libpthread {
+  GLIBC_2.0 {
+    pthread_create; pthread_join; pthread_self; pthread_equal;
+    pthread_exit; pthread_detach;
+
+    pthread_getschedparam; pthread_setschedparam;
+
+    pthread_attr_init; pthread_attr_destroy;
+    pthread_attr_getdetachstate; pthread_attr_setdetachstate;
+    pthread_attr_getschedparam; pthread_attr_setschedparam;
+    pthread_attr_getschedpolicy; pthread_attr_setschedpolicy;
+    pthread_attr_getinheritsched; pthread_attr_setinheritsched;
+    pthread_attr_getscope; pthread_attr_setscope;
+
+    pthread_mutex_init; pthread_mutex_destroy;
+    pthread_mutex_lock; pthread_mutex_trylock; pthread_mutex_unlock;
+
+    pthread_mutexattr_init; pthread_mutexattr_destroy;
+
+    pthread_cond_init; pthread_cond_destroy;
+    pthread_cond_wait; pthread_cond_timedwait;
+    pthread_cond_signal; pthread_cond_broadcast;
+
+    pthread_condattr_destroy; pthread_condattr_init;
+
+    pthread_cancel; pthread_testcancel;
+    pthread_setcancelstate; pthread_setcanceltype;
+
+    pthread_sigmask; pthread_kill;
+
+    pthread_key_create; pthread_key_delete;
+    pthread_getspecific; pthread_setspecific;
+
+    pthread_once;
+
+    pthread_atfork;
+
+    flockfile; funlockfile; ftrylockfile;
+
+    # Non-standard POSIX1.x functions.
+    pthread_mutexattr_getkind_np; pthread_mutexattr_setkind_np;
+
+    # Protected names for functions used in other shared objects.
+    __pthread_mutex_init; __pthread_mutex_destroy;
+    __pthread_mutex_lock; __pthread_mutex_trylock; __pthread_mutex_unlock;
+    __pthread_mutexattr_init; __pthread_mutexattr_destroy;
+    __pthread_mutexattr_settype;
+    __pthread_key_create; __pthread_getspecific; __pthread_setspecific;
+    __pthread_once; __pthread_atfork;
+    _IO_flockfile; _IO_ftrylockfile; _IO_funlockfile;
+
+    # Hidden entry point (through macros).
+    #_pthread_cleanup_pop; _pthread_cleanup_pop_restore; _pthread_cleanup_push;
+    #_pthread_cleanup_push_defer;
+
+    # Semaphores.
+    sem_destroy; sem_getvalue; sem_init; sem_post; sem_trywait; sem_wait;
+
+    # Special fork handling.
+    fork; __fork; vfork;
+
+    # Cancellation points.
+    close; __close; fcntl; __fcntl; read; __read; write; __write; accept;
+    connect; __connect; recv; recvfrom; recvmsg; send; __send; sendmsg; sendto;
+    fsync; lseek; __lseek; msync; nanosleep; open; __open; pause; tcdrain;
+    system; wait; __wait; waitpid;
+
+    # Hidden entry point (through macros).
+    _pthread_cleanup_push; _pthread_cleanup_pop;
+    _pthread_cleanup_push_defer; _pthread_cleanup_pop_restore;
+
+    pthread_kill_other_threads_np;
+
+    # The error functions.
+    __errno_location; __h_errno_location;
+
+    # Functions which previously have been overwritten.
+    sigwait; sigaction; __sigaction; _exit; _Exit; longjmp; siglongjmp;
+    raise;
+  }
+
+  GLIBC_2.1 {
+    pthread_create;
+    pthread_attr_init;
+
+    pthread_attr_getguardsize; pthread_attr_setguardsize;
+    pthread_attr_getstackaddr; pthread_attr_setstackaddr;
+    pthread_attr_getstacksize; pthread_attr_setstacksize;
+
+    pthread_mutexattr_gettype; pthread_mutexattr_settype;
+
+    pthread_rwlock_init; pthread_rwlock_destroy;
+    pthread_rwlock_rdlock; pthread_rwlock_wrlock; pthread_rwlock_unlock;
+    pthread_rwlock_tryrdlock; pthread_rwlock_trywrlock;
+
+    __pthread_rwlock_init; __pthread_rwlock_destroy;
+    __pthread_rwlock_rdlock; __pthread_rwlock_wrlock; __pthread_rwlock_unlock;
+    __pthread_rwlock_tryrdlock; __pthread_rwlock_trywrlock;
+
+    pthread_rwlockattr_init; pthread_rwlockattr_destroy;
+    pthread_rwlockattr_getpshared; pthread_rwlockattr_setpshared;
+    pthread_rwlockattr_getkind_np; pthread_rwlockattr_setkind_np;
+
+    pthread_getconcurrency; pthread_setconcurrency;
+
+    # Semaphores.
+    sem_destroy; sem_getvalue; sem_init; sem_post; sem_trywait; sem_wait;
+
+    __libc_current_sigrtmin; __libc_current_sigrtmax;
+    __libc_allocate_rtsig;
+  }
+
+  GLIBC_2.1.1 {
+    sem_close; sem_open; sem_unlink;
+  }
+
+  GLIBC_2.1.2 {
+    __vfork;
+  }
+
+  GLIBC_2.2 {
+    pthread_mutexattr_getpshared; pthread_mutexattr_setpshared;
+
+    pthread_condattr_getpshared; pthread_condattr_setpshared;
+
+    # New functions from IEEE Std. 1003.1-2001.
+    pthread_mutex_timedlock;
+
+    pthread_rwlock_timedrdlock; pthread_rwlock_timedwrlock;
+
+    pthread_attr_getstack; pthread_attr_setstack;
+
+    pthread_spin_destroy; pthread_spin_init; pthread_spin_lock;
+    pthread_spin_trylock; pthread_spin_unlock;
+
+    pthread_barrier_init; pthread_barrier_destroy; pthread_barrier_wait;
+    pthread_barrierattr_destroy; pthread_barrierattr_init;
+    pthread_barrierattr_getpshared; pthread_barrierattr_setpshared;
+
+    sem_timedwait;
+
+    pthread_yield;
+
+    pthread_getcpuclockid;
+
+    # Cancellation points.
+    lseek64; open64; __open64; pread; pread64; __pread64; pwrite; pwrite64;
+    __pwrite64;
+
+    # Names used internally.
+    __pthread_rwlock_init; __pthread_rwlock_destroy;
+    __pthread_rwlock_rdlock; __pthread_rwlock_tryrdlock;
+    __pthread_rwlock_wrlock; __pthread_rwlock_trywrlock;
+    __pthread_rwlock_unlock;
+
+    __res_state;
+  }
+
+  GLIBC_2.2.3 {
+    # Extensions.
+    pthread_getattr_np;
+  }
+
+  GLIBC_2.2.6 {
+    # Cancellation wrapper
+    __nanosleep;
+  }
+
+  # XXX Adjust number for final release.
+  GLIBC_2.3.1 {
+    # Proposed API extensions.
+    pthread_tryjoin_np; pthread_timedjoin_np;
+
+    creat; poll; pselect; readv; select; sigpause; sigsuspend; sigwait;
+    sigwaitinfo; waitid; writev;
+  }
+
+  GLIBC_PRIVATE {
+    __pthread_initialize_minimal; __pthread_cleanup_upto;
+    __pthread_clock_gettime; __pthread_clock_settime;
+  }
+}
diff --git a/nptl/alloca_cutoff.c b/nptl/alloca_cutoff.c
new file mode 100644 (file)
index 0000000..6dc5cfa
--- /dev/null
@@ -0,0 +1,36 @@
+/* Determine whether block of given size can be allocated on the stack or not.
+   Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU 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 <alloca.h>
+#include <stdlib.h>
+#include <sys/param.h>
+#include <pthreadP.h>
+
+
+int
+__libc_alloca_cutoff (size_t size)
+{
+  return size <= (MIN (__MAX_ALLOCA_CUTOFF,
+                      THREAD_GETMEM (THREAD_SELF, stackblock_size) / 4
+                      /* The main thread, before the thread library is
+                         initialized, has zero in the stackblock_size
+                         element.  Since it is the main thread we can
+                         assume the maximum available stack space.  */
+                      ?: __MAX_ALLOCA_CUTOFF * 4));
+}
diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c
new file mode 100644 (file)
index 0000000..2aaaaec
--- /dev/null
@@ -0,0 +1,507 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+#include <tls.h>
+
+
+
+
+/* Most architectures have exactly one stack pointer.  Some have more.  */
+#define STACK_VARIABLES void *stackaddr
+
+/* How to pass the values to the 'create_thread' function.  */
+#define STACK_VARIABLES_ARGS stackaddr
+
+/* How to declare function which gets there parameters.  */
+#define STACK_VARIABLES_PARMS void *stackaddr
+
+
+/* Default alignment of stack.  */
+#ifndef STACK_ALIGN
+# define STACK_ALIGN __alignof__ (long double)
+#endif
+
+/* Default value for minimal stack size after allocating thread
+   descriptor and guard.  */
+#ifndef MINIMAL_REST_STACK
+# define MINIMAL_REST_STACK    4096
+#endif
+
+
+
+
+/* Cache handling for not-yet free stacks.  */
+
+/* Maximum size in kB of cache.  */
+static size_t stack_cache_maxsize = 40 * 1024 * 1024; /* 40MiBi by default.  */
+static size_t stack_cache_actsize;
+
+/* Mutex protecting this variable.  */
+static lll_lock_t stack_cache_lock = LLL_LOCK_INITIALIZER;
+
+/* List of queued stack frames.  */
+static LIST_HEAD (stack_cache);
+
+/* List of the stacks in use.  */
+static LIST_HEAD (stack_used);
+
+/* List of the threads with user provided stacks in use.  */
+LIST_HEAD (__stack_user);
+
+/* Number of threads running.  */
+static unsigned int nptl_nthreads = 1;
+
+
+/* Check whether the stack is still used or not.  */
+#define FREE_P(descr) ((descr)->tid == 0)
+
+
+/* We create a double linked list of all cache entries.  Double linked
+   because this allows removing entries from the end.  */
+
+
+/* Get a stack frame from the cache.  We have to match by size since
+   some blocks might be too small or far too large.  */
+static struct pthread *
+get_cached_stack (size_t *sizep, void **memp)
+{
+  size_t size = *sizep;
+  struct pthread *result = NULL;
+  list_t *entry;
+
+  lll_lock (stack_cache_lock);
+
+  /* Search the cache for a matching entry.  We search for the
+     smallest stack which has at least the required size.  Note that
+     in normal situations the size of all allocated stacks is the
+     same.  As the very least there are only a few different sizes.
+     Therefore this loop will exit early most of the time with an
+     exact match.  */
+  list_for_each (entry, &stack_cache)
+    {
+      struct pthread *curr;
+
+      curr = list_entry(entry, struct pthread, header.data.list);
+      if (FREE_P (curr) && curr->stackblock_size >= size)
+       {
+         if (curr->stackblock_size == size)
+           {
+             result = curr;
+             break;
+           }
+
+         if (result->stackblock_size > curr->stackblock_size)
+           result = curr;
+       }
+    }
+
+  if (__builtin_expect (result == NULL, 0)
+      /* Make sure the size difference is not too excessive.  In that
+        case we do not use the block.  */
+      || __builtin_expect (result->stackblock_size > 4 * size, 0))
+    {
+      /* Release the lock.  */
+      lll_unlock (stack_cache_lock);
+
+      return NULL;
+    }
+
+  /* Dequeue the entry.  */
+  list_del (&result->header.data.list);
+
+  /* And add to the list of stacks in use.  */
+  list_add (&result->header.data.list, &stack_used);
+
+  /* One more thread.  */
+  ++nptl_nthreads;
+
+  /* And decrease the cache size.  */
+  stack_cache_actsize -= result->stackblock_size;
+
+  /* Release the lock early.  */
+  lll_unlock (stack_cache_lock);
+
+
+  *sizep = result->stackblock_size;
+  *memp = result->stackblock;
+
+  /* Cancellation handling is back to the default.  */
+  result->cancelhandling = 0;
+  result->cleanup = NULL;
+
+  /* No pending event.  */
+  result->nextevent = NULL;
+
+  /* Clear the DTV.  */
+  dtv_t *dtv = GET_DTV (result);
+  memset (dtv, '\0', (dtv[-1].counter + 1) * sizeof (dtv_t));
+
+  /* Re-initialize the TLS.  */
+  return _dl_allocate_tls_init (result);
+}
+
+
+/* Add a stack frame which is not used anymore to the stack.  Must be
+   called with the cache lock held.  */
+static void
+queue_stack (struct pthread *stack)
+{
+  /* We unconditionally add the stack to the list.  The memory may
+     still be in use but it will not be reused until the kernel marks
+     the stack as not used anymore.  */
+  list_add (&stack->header.data.list, &stack_cache);
+
+  stack_cache_actsize += stack->stackblock_size;
+  if (__builtin_expect (stack_cache_actsize > stack_cache_maxsize, 0))
+    {
+      /* We reduce the size of the cache.  Remove the last entries
+        until the size is below the limit.  */
+      list_t *entry;
+      list_t *prev;
+
+      /* Search from the end of the list.  */
+      list_for_each_prev_safe (entry, prev, &stack_cache)
+       {
+         struct pthread *curr;
+
+         curr = list_entry(entry, struct pthread, header.data.list);
+         if (FREE_P (curr))
+           {
+             /* Unlink the block.  */
+             list_del (entry);
+
+             /* Account for the freed memory.  */
+             stack_cache_actsize -= curr->stackblock_size;
+
+             /* Free the memory associated with the ELF TLS.  */
+             _dl_deallocate_tls (curr, false);
+
+             /* Remove this block.  This should never fail.  If it
+                does something is really wrong.  */
+             if (munmap (curr->stackblock, curr->stackblock_size) != 0)
+               abort ();
+
+             /* Maybe we have freed enough.  */
+             if (stack_cache_actsize <= stack_cache_maxsize)
+               break;
+           }
+       }
+    }
+}
+
+
+
+static int
+allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
+               void **stack)
+{
+  struct pthread *pd;
+  size_t size;
+  size_t pagesize = __sysconf (_SC_PAGESIZE);
+
+  assert (attr != NULL);
+  assert (powerof2 (pagesize));
+  assert (TCB_ALIGNMENT >= STACK_ALIGN);
+
+  /* Get the stack size from the attribute if it is set.  Otherwise we
+     use the default we determined at start time.  */
+  size = attr->stacksize ?: __default_stacksize;
+
+  /* Get memory for the stack.  */
+  if (__builtin_expect (attr->flags & ATTR_FLAG_STACKADDR, 0))
+    {
+      uintptr_t adj;
+
+      /* If the user also specified the size of the stack make sure it
+        is large enough.  */
+      if (attr->stacksize != 0
+         && attr->stacksize < (__static_tls_size + MINIMAL_REST_STACK))
+       return EINVAL;
+
+      /* Adjust stack size for alignment of the TLS block.  */
+      adj = ((uintptr_t) attr->stackaddr) & (__static_tls_align - 1);
+      assert (size > adj);
+
+      /* The user provided some memory.  Let's hope it matches the
+        size...  We do not allocate guard pages if the user provided
+        the stack.  It is the user's responsibility to do this if it
+        is wanted.  */
+      pd = (struct pthread *) (((uintptr_t) attr->stackaddr - adj)
+                              & ~(__alignof (struct pthread) - 1)) - 1;
+
+      /* The user provided stack memory need not be cleared.  */
+      memset (pd, '\0', sizeof (struct pthread));
+
+      /* The first TSD block is included in the TCB.  */
+      pd->specific[0] = pd->specific_1stblock;
+
+      /* Initialize the lock.  */
+      pd->lock = LLL_LOCK_INITIALIZER;
+
+      /* Remember the stack-related values.  Signal that this stack
+        must not be put into the stack cache.  */
+      pd->stackblock = (char *) attr->stackaddr - size;
+      pd->stackblock_size = size - adj;
+
+      /* This is a user-provided stack.  */
+      pd->user_stack = true;
+
+      /* Allocate the DTV for this thread.  */
+      if (_dl_allocate_tls (pd) == NULL)
+       /* Something went wrong.  */
+       return errno;
+
+
+      lll_lock (stack_cache_lock);
+
+      /* And add to the list of stacks in use.  */
+      list_add (&pd->header.data.list, &__stack_user);
+
+      /* One more thread.  */
+      ++nptl_nthreads;
+
+      lll_unlock (stack_cache_lock);
+    }
+  else
+    {
+      /* Allocate some anonymous memory.  If possible use the
+        cache.  */
+      size_t guardsize;
+      size_t reqsize;
+      void *mem;
+
+      /* Adjust the stack size for alignment.  */
+      size &= ~(__static_tls_align - 1);
+      assert (size != 0);
+
+      /* Make sure the size of the stack is enough for the guard and
+        eventually the thread descriptor.  */
+      guardsize = (attr->guardsize + pagesize - 1) & ~(pagesize - 1);
+      if (__builtin_expect (size < (guardsize + __static_tls_size
+                                   + MINIMAL_REST_STACK), 0))
+       /* The stack is too small (or the guard too large).  */
+       return EINVAL;
+
+      reqsize = size;
+      pd = get_cached_stack (&size, &mem);
+      if (pd == NULL)
+       {
+         mem = mmap (NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC,
+                     MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+
+         if (__builtin_expect (mem == MAP_FAILED, 0))
+           return errno;
+
+         /* 'size' is guaranteed to be greater than zero.  So we can
+            never get a NULL pointer back from MMAP.  */
+         assert (mem != NULL);
+
+         /* Place the thread descriptor at the end of the stack.  */
+         pd = (struct pthread *) ((char *) mem + size) - 1;
+
+         /* Remember the stack-related values.  */
+         pd->stackblock = mem;
+         pd->stackblock_size = size;
+
+         /* We allocated the first block thread-specific data array.
+            This address will not change for the lifetime of this
+            descriptor.  */
+         pd->specific[0] = pd->specific_1stblock;
+
+         /* Initialize the lock.  */
+         pd->lock = LLL_LOCK_INITIALIZER;
+
+         /* Allocate the DTV for this thread.  */
+         if (_dl_allocate_tls (pd) == NULL)
+           {
+             /* Something went wrong.  */
+             int err = errno;
+
+             /* Free the stack memory we just allocated.  */
+             munmap (mem, size);
+
+             return err;
+           }
+
+
+         lll_lock (stack_cache_lock);
+
+         /* And add to the list of stacks in use.  */
+         list_add (&pd->header.data.list, &stack_used);
+
+         /* One more thread.  */
+         ++nptl_nthreads;
+
+         lll_unlock (stack_cache_lock);
+
+
+         /* Note that all of the stack and the thread descriptor is
+            zeroed.  This means we do not have to initialize fields
+            with initial value zero.  This is specifically true for
+            the 'tid' field which is always set back to zero once the
+            stack is not used anymore and for the 'guardsize' field
+            which will be read next.  */
+       }
+
+      /* Create or resize the guard area if necessary.  */
+      if (__builtin_expect (guardsize > pd->guardsize, 0))
+       {
+         if (mprotect (mem, guardsize, PROT_NONE) != 0)
+           {
+             int err;
+           mprot_error:
+             err = errno;
+
+             lll_lock (stack_cache_lock);
+
+             /* Remove the thread from the list.  */
+             list_del (&pd->header.data.list);
+
+             /* The thread is gone.  */
+             --nptl_nthreads;
+
+             lll_unlock (stack_cache_lock);
+
+             /* Free the memory regardless of whether the size of the
+                cache is over the limit or not.  If this piece of
+                memory caused problems we better do not use it
+                anymore.  Uh, and we ignore possible errors.  There
+                is nothing we could do.  */
+             (void) munmap (mem, size);
+
+             return err;
+           }
+
+         pd->guardsize = guardsize;
+       }
+      else if (__builtin_expect (pd->guardsize - guardsize > size - reqsize,
+                                0))
+       {
+         /* The old guard area is too large.  */
+         if (mprotect ((char *) mem + guardsize,
+                       pd->guardsize - guardsize,
+                       PROT_READ | PROT_WRITE | PROT_EXEC) != 0)
+           goto mprot_error;
+
+         pd->guardsize = guardsize;
+       }
+    }
+
+  /* We place the thread descriptor at the end of the stack.  */
+  *pdp = pd;
+
+#if TLS_TCB_AT_TP
+  /* The stack begin before the TCB and the static TLS block.  */
+  *stack = ((char *) (pd + 1) - __static_tls_size);
+#else
+# error "Implement me"
+#endif
+
+  return 0;
+}
+
+/* This is how the function is called.  We do it this way to allow
+   other variants of the function to have more parameters.  */
+#define ALLOCATE_STACK(attr, pd) allocate_stack (attr, pd, &stackaddr)
+
+
+void
+__deallocate_stack (struct pthread *pd)
+{
+  lll_lock (stack_cache_lock);
+
+  /* Remove the thread from the list of threads with user defined
+     stacks.  */
+  list_del (&pd->header.data.list);
+
+  /* Not much to do.  Just free the mmap()ed memory.  Note that we do
+     not reset the 'used' flag in the 'tid' field.  This is done by
+     the kernel.  If no thread has been created yet this field is
+     still zero.  */
+  if (__builtin_expect (! pd->user_stack, 1))
+    (void) queue_stack (pd);
+  else
+    /* Free the memory associated with the ELF TLS.  */
+    _dl_deallocate_tls (pd, false);
+
+  /* One less thread.  */
+  --nptl_nthreads;
+
+  lll_unlock (stack_cache_lock);
+}
+
+
+/* In case of a fork() call the memory allocation in the child will be
+   the same but only one thread is running.  All stacks except that of
+   the one running thread are not used anymore.  We have to recycle
+   them.  */
+void
+__reclaim_stacks (void)
+{
+  struct pthread *self = (struct pthread *) THREAD_SELF;
+
+  /* No locking necessary.  The caller is the only stack in use.  */
+
+  /* Mark all stacks except the still running one as free.  */
+  list_t *runp;
+  list_for_each (runp, &stack_used)
+    {
+      struct pthread *curp;
+
+      curp = list_entry (runp, struct pthread, header.data.list);
+      if (curp != self)
+       {
+         /* This marks the stack as free.  */
+         curp->tid = 0;
+
+         /* Account for the size of the stack.  */
+         stack_cache_actsize += curp->stackblock_size;
+       }
+    }
+
+  /* Add the stack of all running threads to the cache.  */
+  list_splice (&stack_used, &stack_cache);
+
+  /* Remove the entry for the current thread to from the cache list
+     and add it to the list of running threads.  Which of the two
+     lists is decided by the user_stack flag.  */
+  list_del (&self->header.data.list);
+
+  /* Re-initialize the lists for all the threads.  */
+  INIT_LIST_HEAD (&stack_used);
+  INIT_LIST_HEAD (&__stack_user);
+
+  if (__builtin_expect (THREAD_GETMEM (self, user_stack), 0))
+    list_add (&self->header.data.list, &__stack_user);
+  else
+    list_add (&self->header.data.list, &stack_used);
+
+  /* There is one thread running.  */
+  nptl_nthreads = 1;
+
+  /* Initialize the lock.  */
+  stack_cache_lock = LLL_LOCK_INITIALIZER;
+}
diff --git a/nptl/atomic.h b/nptl/atomic.h
new file mode 100644 (file)
index 0000000..927e0fe
--- /dev/null
@@ -0,0 +1,109 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _ATOMIC_H
+#define _ATOMIC_H      1
+
+#include <stdlib.h>
+
+#include <bits/atomic.h>
+
+
+#ifndef atomic_compare_and_exchange_acq
+# define atomic_compare_and_exchange_acq(mem, newval, oldval) \
+  ({ __typeof (__arch_compare_and_exchange_8_acq (mem, newval, oldval))              \
+        __result;                                                            \
+     if (sizeof (*mem) == 1)                                                 \
+       __result = __arch_compare_and_exchange_8_acq (mem, newval, oldval);    \
+     else if (sizeof (*mem) == 2)                                            \
+       __result = __arch_compare_and_exchange_16_acq (mem, newval, oldval);   \
+     else if (sizeof (*mem) == 4)                                            \
+       __result = __arch_compare_and_exchange_32_acq (mem, newval, oldval);   \
+     else if (sizeof (*mem) == 8)                                            \
+       __result = __arch_compare_and_exchange_64_acq (mem, newval, oldval);   \
+     else                                                                    \
+       abort ();                                                             \
+     __result; })
+#endif
+
+
+#ifndef atomic_compare_and_exchange_rel
+# define atomic_compare_and_exchange_rel(mem, oldval, newval) \
+  compare_and_exchange_acq (mem, oldval, newval)
+#endif
+
+
+#ifndef atomic_exchange_and_add
+# define atomic_exchange_and_add(mem, value) \
+  ({ __typeof (*mem) __oldval;                                               \
+     __typeof (mem) __memp = (mem);                                          \
+     __typeof (*mem) __value = (value);                                              \
+                                                                             \
+     do                                                                              \
+       __oldval = (*__memp);                                                 \
+     while (compare_and_exchange_acq (__memp, __oldval + __value, __oldval)); \
+                                                                             \
+     __value; })
+#endif
+
+
+#ifndef atomic_add
+# define atomic_add(mem, value) (void) exchange_and_add (mem, value)
+#endif
+
+
+#ifndef atomic_increment
+# define atomic_increment(mem) atomic_add (mem, 1)
+#endif
+
+
+#ifndef atomic_decrement
+# define atomic_decrement(mem) atomic_add (mem, -1)
+#endif
+
+
+#ifndef atomic_set_bit
+# define atomic_set_bit(mem, bit) \
+  (void) ({ __typeof (mem) __memp = (mem);                                   \
+           while (1)                                                         \
+             {                                                               \
+               __typeof (*mem) __oldval = *__memp;                           \
+                                                                             \
+               if (compare_and_exchange_acq (__memp, __oldval | 1 << bit,    \
+                                             __oldval) == 0)                 \
+                 break;                                                      \
+             }})
+#endif
+
+
+#ifndef atomic_full_barrier
+# define full_barrier() __asm ("" ::: "memory")
+#endif
+
+
+#ifndef atomic_read_barrier
+# define read_barrier() full_barrier()
+#endif
+
+
+#ifndef atomic_write_barrier
+# define write_barrier() full_barrier()
+#endif
+
+#endif /* atomic.h */
diff --git a/nptl/cancellation.c b/nptl/cancellation.c
new file mode 100644 (file)
index 0000000..890b26e
--- /dev/null
@@ -0,0 +1,92 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <setjmp.h>
+#include <stdlib.h>
+#include "pthreadP.h"
+
+
+/* This function is responsible for calling all registered cleanup
+   handlers and then terminate the thread.  This includes dellocating
+   the thread-specific data.  The implementation is complicated by the
+   fact that we have to handle to cancellation handler registration
+   methods: exceptions using try/finally and setjmp.
+
+   The setjmp method is always available.  The user might compile some
+   code which uses this method because no modern compiler is
+   available.  So we have to handle these first since we cannot call
+   the cleanup handlers if the stack frames are gone.  At the same
+   time this opens a hole for the register exception handler blocks
+   since now they might be in danger of using an overwritten stack
+   frame.  The advise is to only use new or only old style cancellation
+   handling.  */
+void
+__do_cancel (char *currentframe)
+{
+  struct pthread *self = THREAD_SELF;
+
+  /* Cleanup the thread-local storage.  */
+  __cleanup_thread (self, currentframe);
+
+  /* Throw an exception.  */
+  // XXX TBI
+
+  /* If throwing an exception didn't work try the longjmp.  */
+  __libc_longjmp (self->cancelbuf, 1);
+
+  /* NOTREACHED */
+}
+
+
+void
+__cleanup_thread (struct pthread *self, char *currentframe)
+{
+  struct _pthread_cleanup_buffer *cleanups;
+
+  /* Call all registered cleanup handlers.  */
+  cleanups = THREAD_GETMEM (self, cleanup);
+  if (__builtin_expect (cleanups != NULL, 0))
+    {
+      struct _pthread_cleanup_buffer *last;
+
+      while (FRAME_LEFT (currentframe, cleanups))
+       {
+         last = cleanups;
+         cleanups = cleanups->__prev;
+
+         if (cleanups == NULL || FRAME_LEFT (last, cleanups))
+           {
+             cleanups = NULL;
+             break;
+           }
+       }
+
+      while (cleanups != NULL)
+       {
+         /* Call the registered cleanup function.  */
+         cleanups->__routine (cleanups->__arg);
+
+         last = cleanups;
+         cleanups = cleanups->__prev;
+
+         if (FRAME_LEFT (last, cleanups))
+           break;
+       }
+    }
+}
diff --git a/nptl/cleanup.c b/nptl/cleanup.c
new file mode 100644 (file)
index 0000000..6c7ba61
--- /dev/null
@@ -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.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stdlib.h>
+#include "pthreadP.h"
+
+
+void
+_pthread_cleanup_push (buffer, routine, arg)
+     struct _pthread_cleanup_buffer *buffer;
+     void (*routine) (void *);
+     void *arg;
+{
+  struct pthread *self = THREAD_SELF;
+
+  buffer->__routine = routine;
+  buffer->__arg = arg;
+  buffer->__prev = THREAD_GETMEM (self, cleanup);
+
+  if (buffer->__prev != NULL && FRAME_LEFT (buffer, buffer->__prev))
+    buffer->__prev = NULL;
+
+  THREAD_SETMEM (self, cleanup, buffer);
+}
+extern void _GI_pthread_cleanup_push (struct _pthread_cleanup_buffer *buffer,
+                                     void (*routine) (void *), void *arg)
+     attribute_hidden;
+strong_alias (_pthread_cleanup_push, _GI_pthread_cleanup_push)
+
+
+void
+_pthread_cleanup_pop (buffer, execute)
+     struct _pthread_cleanup_buffer *buffer;
+     int execute;
+{
+  struct pthread *self __attribute ((unused)) = THREAD_SELF;
+
+  THREAD_SETMEM (self, cleanup, buffer->__prev);
+
+  /* If necessary call the cleanup routine after we removed the
+     current cleanup block from the list.  */
+  if (execute)
+    buffer->__routine (buffer->__arg);
+}
+extern void _GI_pthread_cleanup_pop (struct _pthread_cleanup_buffer *buffer,
+                                    int execute) attribute_hidden;
+strong_alias (_pthread_cleanup_pop, _GI_pthread_cleanup_pop)
diff --git a/nptl/cleanup_defer.c b/nptl/cleanup_defer.c
new file mode 100644 (file)
index 0000000..192fea5
--- /dev/null
@@ -0,0 +1,86 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+#include <atomic.h>
+
+
+void
+_pthread_cleanup_push_defer (buffer, routine, arg)
+     struct _pthread_cleanup_buffer *buffer;
+     void (*routine) (void *);
+     void *arg;
+{
+  struct pthread *self = THREAD_SELF;
+
+  buffer->__routine = routine;
+  buffer->__arg = arg;
+  buffer->__prev = THREAD_GETMEM (self, cleanup);
+
+  if (buffer->__prev != NULL && FRAME_LEFT (buffer, buffer->__prev))
+    buffer->__prev = NULL;
+
+  int cancelhandling = THREAD_GETMEM (self, cancelhandling);
+
+  /* Disable asynchronous cancellation for now.  */
+  if (__builtin_expect (cancelhandling & CANCELTYPE_BITMASK, 0))
+    {
+      while (atomic_compare_and_exchange_acq (&self->cancelhandling,
+                                             cancelhandling
+                                             & ~CANCELTYPE_BITMASK,
+                                             cancelhandling) != 0)
+       cancelhandling = self->cancelhandling;
+    }
+
+  buffer->__canceltype = (cancelhandling & CANCELTYPE_BITMASK
+                         ? PTHREAD_CANCEL_ASYNCHRONOUS
+                         : PTHREAD_CANCEL_DEFERRED);
+
+  THREAD_SETMEM (self, cleanup, buffer);
+}
+
+
+void
+_pthread_cleanup_pop_restore (buffer, execute)
+     struct _pthread_cleanup_buffer *buffer;
+     int execute;
+{
+  struct pthread *self = THREAD_SELF;
+
+  THREAD_SETMEM (self, cleanup, buffer->__prev);
+
+  int cancelhandling;
+  if (__builtin_expect (buffer->__canceltype != PTHREAD_CANCEL_DEFERRED, 0)
+      && ((cancelhandling = THREAD_GETMEM (self, cancelhandling))
+         & CANCELTYPE_BITMASK) == 0)
+    {
+      while (atomic_compare_and_exchange_acq (&self->cancelhandling,
+                                             cancelhandling
+                                             | CANCELTYPE_BITMASK,
+                                             cancelhandling) != 0)
+       cancelhandling = self->cancelhandling;
+
+      CANCELLATION_P (self);
+    }
+
+  /* If necessary call the cleanup routine after we removed the
+     current cleanup block from the list.  */
+  if (execute)
+    buffer->__routine (buffer->__arg);
+}
diff --git a/nptl/configure b/nptl/configure
new file mode 100644 (file)
index 0000000..3eafc93
--- /dev/null
@@ -0,0 +1,5 @@
+# This is only to keep the GNU C library configure mechanism happy.
+#
+# Perhaps some day we need a real configuration script for different
+# kernel versions or so.
+exit 0
diff --git a/nptl/descr.h b/nptl/descr.h
new file mode 100644 (file)
index 0000000..f3a9620
--- /dev/null
@@ -0,0 +1,179 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _DESCR_H
+#define _DESCR_H       1
+
+#include <limits.h>
+#include <sched.h>
+#include <setjmp.h>
+#include <stdbool.h>
+#include <sys/types.h>
+#include <hp-timing.h>
+#include <list.h>
+#include <lowlevellock.h>
+#include <pthreaddef.h>
+#include "../nptl_db/thread_db.h"
+
+
+#ifndef TCB_ALIGNMENT
+# define TCB_ALIGNMENT sizeof (double)
+#endif
+
+
+/* We keep thread specific data in a special data structure, a two-level
+   array.  The top-level array contains pointers to dynamically allocated
+   arrays of a certain number of data pointers.  So we can implement a
+   sparse array.  Each dynamic second-level array has
+        PTHREAD_KEY_2NDLEVEL_SIZE
+   entries.  This value shouldn't be too large.  */
+#define PTHREAD_KEY_2NDLEVEL_SIZE       32
+
+/* We need to address PTHREAD_KEYS_MAX key with PTHREAD_KEY_2NDLEVEL_SIZE
+   keys in each subarray.  */
+#define PTHREAD_KEY_1STLEVEL_SIZE \
+  ((PTHREAD_KEYS_MAX + PTHREAD_KEY_2NDLEVEL_SIZE - 1) \
+   / PTHREAD_KEY_2NDLEVEL_SIZE)
+
+
+/* Thread descriptor data structure.  */
+struct pthread
+{
+  /* XXX Remove this union for IA-64 style TLS module */
+  union
+  {
+    struct
+    {
+      void *tcb;                /* Pointer to the TCB.  This is not always
+                                   the address of this thread descriptor.  */
+      union dtv *dtvp;
+      struct pthread *self;       /* Pointer to this structure */
+      list_t list;
+    } data;
+    void *__padding[16];
+  } header;
+
+  /* Two-level array for the thread-specific data.  */
+  struct pthread_key_data
+  {
+    /* Sequence number.  We use uintptr_t to not require padding on
+       32- and 64-bit machines.  On 64-bit machines it helps to avoid
+       wrapping, too.  */
+    uintptr_t seq;
+
+    /* Data pointer.  */
+    void *data;
+  } *specific[PTHREAD_KEY_1STLEVEL_SIZE];
+  /* We allocate one block of references here.  This should be enough
+     to avoid allocating any memory dynamically for most applications.  */
+  struct pthread_key_data specific_1stblock[PTHREAD_KEY_2NDLEVEL_SIZE];
+  /* Flag which is set when specific data is set.  */
+  bool specific_used;
+
+  /* True if the user provided the stack.  */
+  bool user_stack;
+
+  /* True if events must be reported.  */
+  bool report_events;
+
+  /* Lock to syncronize access to the descriptor.  */
+  lll_lock_t lock;
+
+#if HP_TIMING_AVAIL
+  /* Offset of the CPU clock at start thread start time.  */
+  hp_timing_t cpuclock_offset;
+#endif
+
+  /* If the thread waits to join another one the ID of the latter is
+     stored here.
+
+     In case a thread is detached this field contains a pointer of the
+     TCB if the thread itself.  This is something which cannot happen
+     in normal operation.  */
+  struct pthread *joinid;
+  /* Check whether a thread is detached.  */
+#define IS_DETACHED(pd) ((pd)->joinid == (pd))
+
+  /* List of cleanup buffers.  */
+  struct _pthread_cleanup_buffer *cleanup;
+  /* Flags determining processing of cancellation.  */
+  int cancelhandling;
+  /* Bit set if cancellation is disabled.  */
+#define CANCELSTATE_BIT                0
+#define CANCELSTATE_BITMASK    0x01
+  /* Bit set if asynchronous cancellation mode is selected.  */
+#define CANCELTYPE_BIT         1
+#define CANCELTYPE_BITMASK     0x02
+  /* Bit set if canceled.  */
+#define CANCELED_BIT           2
+#define CANCELED_BITMASK       0x04
+  /* Bit set if thread is exiting.  */
+#define EXITING_BIT            3
+#define EXITING_BITMASK                0x08
+  /* Bit set if thread terminated and TCB is freed.  */
+#define TERMINATED_BIT         4
+#define TERMINATED_BITMASK     0x10
+  /* Mask for the rest.  Helps the compiler to optimize.  */
+#define CANCEL_RESTMASK                0xffffffe0
+
+#define CANCEL_ENABLED_AND_CANCELED(value) \
+  (((value) & (CANCELSTATE_BITMASK | CANCELED_BITMASK | EXITING_BITMASK              \
+              | CANCEL_RESTMASK | TERMINATED_BITMASK)) == CANCELED_BITMASK)
+#define CANCEL_ENABLED_AND_CANCELED_AND_ASYNCHRONOUS(value) \
+  (((value) & (CANCELSTATE_BITMASK | CANCELTYPE_BITMASK | CANCELED_BITMASK    \
+              | EXITING_BITMASK | CANCEL_RESTMASK | TERMINATED_BITMASK))     \
+   == (CANCELTYPE_BITMASK | CANCELED_BITMASK))
+  /* Setjmp buffer to be used if try/finally is not available.  */
+  sigjmp_buf cancelbuf;
+#define HAVE_CANCELBUF 1
+
+  /* Thread ID - which is also a 'is this thread descriptor (and
+     therefore stack) used' flag.  */
+  pid_t tid;
+
+  /* Flags.  Including those copied from the thread attribute.  */
+  int flags;
+
+  /* The result of the thread function.  */
+  void *result;
+
+  /* Scheduling parameters for the new thread.  */
+  struct sched_param schedparam;
+  int schedpolicy;
+
+  /* Start position of the code to be executed and the argument passed
+     to the function.  */
+  void *(*start_routine) (void *);
+  void *arg;
+
+  /* Debug state.  */
+  td_eventbuf_t eventbuf;
+  /* Next descriptor with a pending event.  */
+  struct pthread *nextevent;
+
+  /* If nonzero pointer to area allocated for the stack and its
+     size.  */
+  void *stackblock;
+  size_t stackblock_size;
+  /* Size of the included guard area.  */
+  size_t guardsize;
+} __attribute ((aligned (TCB_ALIGNMENT)));
+
+
+#endif /* descr.h */
diff --git a/nptl/events.c b/nptl/events.c
new file mode 100644 (file)
index 0000000..8232d0c
--- /dev/null
@@ -0,0 +1,32 @@
+/* Event functions used while debugging.
+   Copyright (C) 1999, 2000, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+/* The functions contained here do nothing, they just return.  */
+
+#include "pthreadP.h"
+
+void
+__nptl_create_event (void)
+{
+}
+
+void
+__nptl_death_event (void)
+{
+}
diff --git a/nptl/flockfile.c b/nptl/flockfile.c
new file mode 100644 (file)
index 0000000..a82059f
--- /dev/null
@@ -0,0 +1,31 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <libio.h>
+
+
+void
+flockfile (stream)
+     FILE *stream;
+{
+  pthread_mutex_lock (stream->_lock);
+}
+strong_alias (flockfile, _IO_flockfile)
diff --git a/nptl/forward.c b/nptl/forward.c
new file mode 100644 (file)
index 0000000..29f291d
--- /dev/null
@@ -0,0 +1,151 @@
+/* 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 <dlfcn.h>
+#include <pthread.h>
+#include <stdlib.h>
+
+#include <shlib-compat.h>
+
+
+#if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_3_2)
+static void *libpthread_handle;
+
+
+static void
+test_loaded (void)
+{
+  void *h = __libc_dlopen_mode ("libpthread.so.0", RTLD_LAZY | RTLD_NOLOAD);
+
+  libpthread_handle = h ?: (void *) -1l;
+}
+
+
+#define FORWARD3(name, rettype, decl, params, defaction, version) \
+rettype                                                                              \
+__noexport_##name decl                                                       \
+{                                                                            \
+  if (libpthread_handle == NULL)                                             \
+    test_loaded ();                                                          \
+                                                                             \
+  if (libpthread_handle == (void *) -1l)                                     \
+    defaction;                                                               \
+                                                                             \
+  static __typeof (name) *p;                                                 \
+  p = __libc_dlsym (libpthread_handle, #name);                               \
+                                                                             \
+  return p params;                                                           \
+}                                                                            \
+compat_symbol (libc, __noexport_##name, name, version)
+
+#define FORWARD2(name, decl, params, defretval, version) \
+  FORWARD3 (name, int, decl, params, return defretval, version)
+
+#define FORWARD(name, decl, params, defretval) \
+  FORWARD2 (name, decl, params, defretval, GLIBC_2_0)
+
+
+FORWARD (pthread_attr_destroy, (pthread_attr_t *attr), (attr), 0);
+
+FORWARD2 (pthread_attr_init, (pthread_attr_t *attr), (attr), 0, 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);
+
+FORWARD (pthread_cond_destroy, (pthread_cond_t *cond), (cond), 0);
+
+FORWARD (pthread_cond_init,
+        (pthread_cond_t *cond, const pthread_condattr_t *cond_attr),
+        (cond, cond_attr), 0);
+
+FORWARD (pthread_cond_signal, (pthread_cond_t *cond), (cond), 0);
+
+FORWARD (pthread_cond_wait, (pthread_cond_t *cond, pthread_mutex_t *mutex),
+        (cond, mutex), 0);
+
+
+FORWARD (pthread_equal, (pthread_t thread1, pthread_t thread2),
+        (thread1, thread2), 1);
+
+
+FORWARD3 (pthread_exit, void, (void *retval), (retval), exit (EXIT_SUCCESS),
+         GLIBC_2_0);
+
+
+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);
+
+
+FORWARD (pthread_self, (void), (), 0);
+
+
+FORWARD (pthread_setcancelstate, (int state, int *oldstate), (state, oldstate),
+        0);
+
+FORWARD (pthread_setcanceltype, (int type, int *oldtype), (type, oldtype), 0);
+
+
+#endif
diff --git a/nptl/ftrylockfile.c b/nptl/ftrylockfile.c
new file mode 100644 (file)
index 0000000..9ed010d
--- /dev/null
@@ -0,0 +1,31 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <libio.h>
+
+
+int
+ftrylockfile (stream)
+     FILE *stream;
+{
+  return pthread_mutex_trylock (stream->_lock);
+}
+strong_alias (ftrylockfile, _IO_ftrylockfile)
diff --git a/nptl/funlockfile.c b/nptl/funlockfile.c
new file mode 100644 (file)
index 0000000..cbb3ec6
--- /dev/null
@@ -0,0 +1,31 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <libio.h>
+
+
+void
+funlockfile (stream)
+     FILE *stream;
+{
+  pthread_mutex_unlock (stream->_lock);
+}
+strong_alias (funlockfile, _IO_funlockfile)
diff --git a/nptl/herrno.c b/nptl/herrno.c
new file mode 100644 (file)
index 0000000..58d9784
--- /dev/null
@@ -0,0 +1,36 @@
+/* Copyright (C) 1996,97,98,2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <features.h>
+#include <netdb.h>
+#undef h_errno
+
+#include <tls.h>
+
+/* We need to have the error status variable of the resolver
+   accessible in the libc.  */
+extern __thread int h_errno;
+
+
+/* When threaded, h_errno may be a per-thread variable.  */
+int *
+weak_const_function
+__h_errno_location (void)
+{
+  return &h_errno;
+}
diff --git a/nptl/init.c b/nptl/init.c
new file mode 100644 (file)
index 0000000..395ede7
--- /dev/null
@@ -0,0 +1,172 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <assert.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <sys/resource.h>
+#include <pthreadP.h>
+#include <atomic.h>
+#include <ldsodefs.h>
+#include <tls.h>
+#include <fork.h>
+#include <version.h>
+
+
+/* XXX For the time being...  */
+#define __NR_set_tid_address   258
+
+
+/* Default stack size.  */
+size_t __default_stacksize attribute_hidden;
+
+/* Size and alignment of static TLS block.  */
+size_t __static_tls_size;
+size_t __static_tls_align;
+
+/* Version of the library, used in libthread_db to detect mismatches.  */
+static const char nptl_version[] = VERSION;
+
+
+#if defined USE_TLS && !defined SHARED
+extern void __libc_setup_tls (size_t tcbsize, size_t tcbalign);
+#endif
+
+
+/* For asynchronous cancellation we use a signal.  This is the handler.  */
+static void
+sigcancel_handler (int sig __attribute ((unused)))
+{
+  struct pthread *self = THREAD_SELF;
+
+  while (1)
+    {
+      /* We are canceled now.  When canceled by another thread this flag
+        is already set but if the signal is directly send (internally or
+        from another process) is has to be done here.  */
+      int oldval = THREAD_GETMEM (self, cancelhandling);
+      int newval = oldval | CANCELED_BITMASK;
+
+      if (oldval == newval || (oldval & EXITING_BITMASK) != 0)
+       /* Already canceled or exiting.  */
+       break;
+
+      if (atomic_compare_and_exchange_acq (&self->cancelhandling, newval,
+                                          oldval) == 0)
+       {
+         /* Set the return value.  */
+         THREAD_SETMEM (self, result, PTHREAD_CANCELED);
+
+         /* Make sure asynchronous cancellation is still enabled.  */
+         if ((newval & CANCELTYPE_BITMASK) != 0)
+           {
+             /* The thread is exiting now.  */
+             atomic_bit_set (&self->cancelhandling, EXITING_BIT);
+
+             /* Run the registered destructors and terminate the
+                thread.  */
+             __do_cancel (CURRENT_STACK_FRAME);
+           }
+
+         break;
+       }
+    }
+}
+
+
+
+void
+#ifdef SHARED
+__attribute ((constructor))
+#endif
+__pthread_initialize_minimal (void)
+{
+  struct sigaction sa;
+  struct rlimit limit;
+#ifdef USE_TLS
+  struct pthread *pd;
+#endif
+
+#ifndef SHARED
+  /* Unlike in the dynamically linked case the dynamic linker has not
+     taken care of initializing the TLS data structures.  */
+  __libc_setup_tls (TLS_TCB_SIZE, TLS_TCB_ALIGN);
+#endif
+
+  /* Minimal initialization of the thread descriptor.  */
+  pd = THREAD_SELF;
+  pd->tid = INTERNAL_SYSCALL (set_tid_address, 1, &pd->tid);
+  THREAD_SETMEM (pd, specific[0], &pd->specific_1stblock[0]);
+  THREAD_SETMEM (pd, user_stack, true);
+  if (LLL_LOCK_INITIALIZER != 0)
+    THREAD_SETMEM (pd, lock, LLL_LOCK_INITIALIZER);
+#if HP_TIMING_AVAIL
+  THREAD_SETMEM (pd, cpuclock_offset, GL(dl_cpuclock_offset));
+#endif
+
+  /* Add the main thread to the list of all running threads.  No need
+     to get the lock we are alone so far.  */
+  list_add (&pd->header.data.list, &__stack_user);
+
+
+  /* Install the cancellation signal handler.  If for some reason we
+     cannot install the handler we do not abort.  Maybe we should, but
+     it is only asynchronous cancellation which is affected.  */
+  sa.sa_handler = sigcancel_handler;
+  sa.sa_flags = 0;
+
+  /* Avoid another cancellation signal when we process one.  */
+  sigemptyset (&sa.sa_mask);
+  sigaddset (&sa.sa_mask, SIGCANCEL);
+
+  (void) __libc_sigaction (SIGCANCEL, &sa, NULL);
+
+
+  /* Determine the default allowed stack size.  This is the size used
+     in case the user does not specify one.  */
+  if (getrlimit (RLIMIT_STACK, &limit) != 0
+      || limit.rlim_cur == RLIM_INFINITY)
+    /* The system limit is not usable.  Use an architecture-specific
+       default.  */
+    limit.rlim_cur = ARCH_STACK_DEFAULT_SIZE;
+
+#ifdef NEED_SEPARATE_REGISTER_STACK
+  __default_stacksize = MAX (limit.rlim_cur / 2, PTHREAD_STACK_MIN);
+#else
+  __default_stacksize = MAX (limit.rlim_cur, PTHREAD_STACK_MIN);
+#endif
+  /* The maximum page size better should be a multiple of the page
+     size.  */
+  assert (__default_stacksize % __sysconf (_SC_PAGESIZE) == 0);
+
+  /* Get the size of the static and alignment requirements for the TLS
+     block.  */
+  _dl_get_tls_static_info (&__static_tls_size, &__static_tls_align);
+
+  /* Make sure the size takes all the alignments into account.  */
+  if (STACK_ALIGN > __static_tls_align)
+    __static_tls_align = STACK_ALIGN;
+  __static_tls_size = roundup (__static_tls_size, __static_tls_align);
+
+  /* Register the fork generation counter with the libc.  */
+  __register_pthread_fork_handler (&__fork_generation, __reclaim_stacks);
+}
diff --git a/nptl/old_pthread_atfork.c b/nptl/old_pthread_atfork.c
new file mode 100644 (file)
index 0000000..768e687
--- /dev/null
@@ -0,0 +1,27 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <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/nptl/perf.c b/nptl/perf.c
new file mode 100644 (file)
index 0000000..e94ccf8
--- /dev/null
@@ -0,0 +1,749 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#define _GNU_SOURCE    1
+#include <argp.h>
+#include <error.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <sys/types.h>
+
+#ifndef MAX_THREADS
+# define MAX_THREADS           100000
+#endif
+#ifndef DEFAULT_THREADS
+# define DEFAULT_THREADS       50
+#endif
+
+
+#define OPT_TO_THREAD          300
+#define OPT_TO_PROCESS         301
+#define OPT_SYNC_SIGNAL                302
+#define OPT_SYNC_JOIN          303
+#define OPT_TOPLEVEL           304
+
+
+static const struct argp_option options[] =
+  {
+    { NULL, 0, NULL, 0, "\
+This is a test for threads so we allow ther user to selection the number of \
+threads which are used at any one time.  Independently the total number of \
+rounds can be selected.  This is the total number of threads which will have \
+run when the process terminates:" },
+    { "threads", 't', "NUMBER", 0, "Number of threads used at once" },
+    { "starts", 's', "NUMBER", 0, "Total number of working threads" },
+    { "toplevel", OPT_TOPLEVEL, "NUMBER", 0,
+      "Number of toplevel threads which start the other threads; this \
+implies --sync-join" },
+
+    { NULL, 0, NULL, 0, "\
+Each thread can do one of two things: sleep or do work.  The latter is 100% \
+CPU bound.  The work load is the probability a thread does work.  All values \
+from zero to 100 (inclusive) are valid.  How often each thread repeats this \
+can be determined by the number of rounds.  The work cost determines how long \
+each work session (not sleeping) takes.  If it is zero a thread would \
+effectively nothing.  By setting the number of rounds to zero the thread \
+does no work at all and pure thread creation times can be measured." },
+    { "workload", 'w', "PERCENT", 0, "Percentage of time spent working" },
+    { "workcost", 'c', "NUMBER", 0,
+      "Factor in the cost of each round of working" },
+    { "rounds", 'r', "NUMBER", 0, "Number of rounds each thread runs" },
+
+    { NULL, 0, NULL, 0, "\
+There are a number of different methods how thread creation can be \
+synchronized.  Synchronization is necessary since the number of concurrently \
+running threads is limited." },
+    { "sync-signal", OPT_SYNC_SIGNAL, NULL, 0,
+      "Synchronize using a signal (default)" },
+    { "sync-join", OPT_SYNC_JOIN, NULL, 0, "Synchronize using pthread_join" },
+
+    { NULL, 0, NULL, 0, "\
+One parameter for each threads execution is the size of the stack.  If this \
+parameter is not used the system's default stack size is used.  If many \
+threads are used the stack size should be chosen quite small." },
+    { "stacksize", 'S', "BYTES", 0, "Size of threads stack" },
+    { "guardsize", 'g', "BYTES", 0,
+      "Size of stack guard area; must fit into the stack" },
+
+    { NULL, 0, NULL, 0, "Signal options:" },
+    { "to-thread", OPT_TO_THREAD, NULL, 0, "Send signal to main thread" },
+    { "to-process", OPT_TO_PROCESS, NULL, 0,
+      "Send signal to process (default)" },
+
+    { NULL, 0, NULL, 0, "Administrative options:" },
+    { "progress", 'p', NULL, 0, "Show signs of progress" },
+    { "timing", 'T', NULL, 0,
+      "Measure time from startup to the last thread finishing" },
+    { NULL, 0, NULL, 0, NULL }
+  };
+
+/* Prototype for option handler.  */
+static error_t parse_opt (int key, char *arg, struct argp_state *state);
+
+/* Data structure to communicate with argp functions.  */
+static struct argp argp =
+{
+  options, parse_opt
+};
+
+
+static unsigned long int threads = DEFAULT_THREADS;
+static unsigned long int workload = 75;
+static unsigned long int workcost = 20;
+static unsigned long int rounds = 10;
+static long int starts = 5000;
+static unsigned long int stacksize;
+static long int guardsize = -1;
+static bool progress;
+static bool timing;
+static bool to_thread;
+static unsigned long int toplevel = 1;
+
+
+static long int running;
+static pthread_mutex_t running_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static pid_t pid;
+static pthread_t tmain;
+
+static clockid_t cl;
+static struct timespec start_time;
+
+
+static pthread_mutex_t sum_mutex = PTHREAD_MUTEX_INITIALIZER;
+unsigned int sum;
+
+static enum
+  {
+    sync_signal,
+    sync_join
+  }
+sync_method;
+
+
+/* We use 64bit values for the times.  */
+typedef unsigned long long int hp_timing_t;
+
+
+/* Attributes for all created threads.  */
+static pthread_attr_t attr;
+
+
+static void *
+work (void *arg)
+{
+  unsigned long int i;
+  unsigned int state = (unsigned long int) arg;
+
+  for (i = 0; i < rounds; ++i)
+    {
+      /* Determine what to do.  */
+      unsigned int rnum;
+
+      /* Equal distribution.  */
+      do
+       rnum = rand_r (&state);
+      while (rnum >= UINT_MAX - (UINT_MAX % 100));
+
+      rnum %= 100;
+
+      if (rnum < workload)
+       {
+         int j;
+         int a[4] = { i, rnum, i + rnum, rnum - i };
+
+         if (progress)
+           write (STDERR_FILENO, "c", 1);
+
+         for (j = 0; j < workcost; ++j)
+           {
+             a[0] += a[3] >> 12;
+             a[1] += a[2] >> 20;
+             a[2] += a[1] ^ 0x3423423;
+             a[3] += a[0] - a[1];
+           }
+
+         pthread_mutex_lock (&sum_mutex);
+         sum += a[0] + a[1] + a[2] + a[3];
+         pthread_mutex_unlock (&sum_mutex);
+       }
+      else
+       {
+         /* Just sleep.  */
+         struct timespec tv;
+
+         tv.tv_sec = 0;
+         tv.tv_nsec = 10000000;
+
+         if (progress)
+           write (STDERR_FILENO, "w", 1);
+
+         nanosleep (&tv, NULL);
+       }
+    }
+
+  return NULL;
+}
+
+
+static void *
+thread_function (void *arg)
+{
+  work (arg);
+
+  pthread_mutex_lock (&running_mutex);
+  if (--running <= 0 && starts <= 0)
+    {
+      /* We are done.  */
+      if (progress)
+       write (STDERR_FILENO, "\n", 1);
+
+      if (timing)
+       {
+         struct timespec end_time;
+
+         if (clock_gettime (cl, &end_time) == 0)
+           {
+             end_time.tv_sec -= start_time.tv_sec;
+             end_time.tv_nsec -= start_time.tv_nsec;
+             if (end_time.tv_nsec < 0)
+               {
+                 end_time.tv_nsec += 1000000000;
+                 --end_time.tv_sec;
+               }
+
+             printf ("\nRuntime: %lu.%09lu seconds\n",
+                     (unsigned long int) end_time.tv_sec,
+                     (unsigned long int) end_time.tv_nsec);
+           }
+       }
+
+      printf ("Result: %08x\n", sum);
+
+      exit (0);
+    }
+  pthread_mutex_unlock (&running_mutex);
+
+  if (sync_method == sync_signal)
+    {
+      if (to_thread)
+       /* This code sends a signal to the main thread.  */
+       pthread_kill (tmain, SIGUSR1);
+      else
+       /* Use this code to test sending a signal to the process.  */
+       kill (pid, SIGUSR1);
+    }
+
+  if (progress)
+    write (STDERR_FILENO, "f", 1);
+
+  return NULL;
+}
+
+
+struct start_info
+{
+  unsigned int starts;
+  unsigned int threads;
+};
+
+
+static void *
+start_threads (void *arg)
+{
+  struct start_info *si = arg;
+  unsigned int starts = si->starts;
+  pthread_t ths[si->threads];
+  unsigned int state = starts;
+  unsigned int n;
+  unsigned int i = 0;
+  int err;
+
+  if (progress)
+    write (STDERR_FILENO, "T", 1);
+
+  memset (ths, '\0', sizeof (pthread_t) * si->threads);
+
+  while (starts-- > 0)
+    {
+      if (ths[i] != 0)
+       {
+         /* Wait for the threads in the order they were created.  */
+         err = pthread_join (ths[i], NULL);
+         if (err != 0)
+           error (EXIT_FAILURE, err, "cannot join thread");
+
+         if (progress)
+           write (STDERR_FILENO, "f", 1);
+       }
+
+      err = pthread_create (&ths[i], &attr, work,
+                           (void *) (rand_r (&state) + starts + i));
+
+      if (err != 0)
+       error (EXIT_FAILURE, err, "cannot start thread");
+
+      if (progress)
+       write (STDERR_FILENO, "t", 1);
+
+      if (++i == si->threads)
+       i = 0;
+    }
+
+  n = i;
+  do
+    {
+      if (ths[i] != 0)
+       {
+         err = pthread_join (ths[i], NULL);
+         if (err != 0)
+           error (EXIT_FAILURE, err, "cannot join thread");
+
+         if (progress)
+           write (STDERR_FILENO, "f", 1);
+       }
+
+      if (++i == si->threads)
+       i = 0;
+    }
+  while (i != n);
+
+  if (progress)
+    write (STDERR_FILENO, "F", 1);
+
+  return NULL;
+}
+
+
+int
+main (int argc, char *argv[])
+{
+  int remaining;
+  sigset_t ss;
+  pthread_t th;
+  pthread_t *ths = NULL;
+  int empty = 0;
+  int last;
+  bool cont = true;
+
+  /* Parse and process arguments.  */
+  argp_parse (&argp, argc, argv, 0, &remaining, NULL);
+
+  if (sync_method == sync_join)
+    {
+      ths = (pthread_t *) calloc (threads, sizeof (pthread_t));
+      if (ths == NULL)
+       error (EXIT_FAILURE, errno,
+              "cannot allocate memory for thread descriptor array");
+
+      last = threads;
+    }
+  else
+    {
+      ths = &th;
+      last = 1;
+    }
+
+  if (toplevel > threads)
+    {
+      printf ("resetting number of toplevel threads to %lu to not surpass number to concurrent threads\n",
+             threads);
+      toplevel = threads;
+    }
+
+  if (timing)
+    {
+      if (clock_getcpuclockid (0, &cl) != 0
+         || clock_gettime (cl, &start_time) != 0)
+       timing = false;
+    }
+
+  /* We need this later.  */
+  pid = getpid ();
+  tmain = pthread_self ();
+
+  /* We use signal SIGUSR1 for communication between the threads and
+     the main thread.  We only want sychronous notification.  */
+  if (sync_method == sync_signal)
+    {
+      sigemptyset (&ss);
+      sigaddset (&ss, SIGUSR1);
+      if (sigprocmask (SIG_BLOCK, &ss, NULL) != 0)
+       error (EXIT_FAILURE, errno, "cannot set signal mask");
+    }
+
+  /* Create the thread attributes.  */
+  pthread_attr_init (&attr);
+
+  /* If the user provided a stack size use it.  */
+  if (stacksize != 0
+      && pthread_attr_setstacksize (&attr, stacksize) != 0)
+    puts ("could not set stack size; will use default");
+  /* And stack guard size.  */
+  if (guardsize != -1
+      && pthread_attr_setguardsize (&attr, guardsize) != 0)
+    puts ("invalid stack guard size; will use default");
+
+  /* All threads are created detached if we are not using pthread_join
+     to synchronize.  */
+  if (sync_method != sync_join)
+    pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
+
+  if (sync_method == sync_signal)
+    {
+      while (1)
+       {
+         int err;
+         bool do_wait = false;
+
+         pthread_mutex_lock (&running_mutex);
+         if (starts-- < 0)
+           cont = false;
+         else
+           do_wait = ++running >= threads && starts > 0;
+
+         pthread_mutex_unlock (&running_mutex);
+
+         if (! cont)
+           break;
+
+         if (progress)
+           write (STDERR_FILENO, "t", 1);
+
+         err = pthread_create (&ths[empty], &attr, thread_function,
+                               (void *) starts);
+         if (err != 0)
+           error (EXIT_FAILURE, err, "cannot start thread %lu", starts);
+
+         if (++empty == last)
+           empty = 0;
+
+         if (do_wait)
+           sigwaitinfo (&ss, NULL);
+       }
+
+      /* Do nothing anymore.  On of the threads will terminate the program.  */
+      sigfillset (&ss);
+      sigdelset (&ss, SIGINT);
+      while (1)
+       sigsuspend (&ss);
+    }
+  else
+    {
+      pthread_t ths[toplevel];
+      struct start_info si[toplevel];
+      unsigned int i;
+
+      for (i = 0; i < toplevel; ++i)
+       {
+         unsigned int child_starts = starts / (toplevel - i);
+         unsigned int child_threads = threads / (toplevel - i);
+         int err;
+
+         si[i].starts = child_starts;
+         si[i].threads = child_threads;
+
+         err = pthread_create (&ths[i], &attr, start_threads, &si[i]);
+         if (err != 0)
+           error (EXIT_FAILURE, err, "cannot start thread");
+
+         starts -= child_starts;
+         threads -= child_threads;
+       }
+
+      for (i = 0; i < toplevel; ++i)
+       {
+         int err = pthread_join (ths[i], NULL);
+
+         if (err != 0)
+           error (EXIT_FAILURE, err, "cannot join thread");
+       }
+
+      /* We are done.  */
+      if (progress)
+       write (STDERR_FILENO, "\n", 1);
+
+      if (timing)
+       {
+         struct timespec end_time;
+
+         if (clock_gettime (cl, &end_time) == 0)
+           {
+             end_time.tv_sec -= start_time.tv_sec;
+             end_time.tv_nsec -= start_time.tv_nsec;
+             if (end_time.tv_nsec < 0)
+               {
+                 end_time.tv_nsec += 1000000000;
+                 --end_time.tv_sec;
+               }
+
+             printf ("\nRuntime: %lu.%09lu seconds\n",
+                     (unsigned long int) end_time.tv_sec,
+                     (unsigned long int) end_time.tv_nsec);
+           }
+       }
+
+      printf ("Result: %08x\n", sum);
+
+      exit (0);
+    }
+
+  /* NOTREACHED */
+  return 0;
+}
+
+
+/* Handle program arguments.  */
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+  unsigned long int num;
+  long int snum;
+
+  switch (key)
+    {
+    case 't':
+      num = strtoul (arg, NULL, 0);
+      if (num < MAX_THREADS)
+       threads = num;
+      else
+       printf ("\
+number of threads limited to %u; recompile with a higher limit if necessary",
+               MAX_THREADS);
+      break;
+
+    case 'w':
+      num = strtoul (arg, NULL, 0);
+      if (num <= 100)
+       workload = num;
+      else
+       puts ("workload must be between 0 and 100 percent");
+      break;
+
+    case 'c':
+      workcost = strtoul (arg, NULL, 0);
+      break;
+
+    case 'r':
+      rounds = strtoul (arg, NULL, 0);
+      break;
+
+    case 's':
+      starts = strtoul (arg, NULL, 0);
+      break;
+
+    case 'S':
+      num = strtoul (arg, NULL, 0);
+      if (num >= PTHREAD_STACK_MIN)
+       stacksize = num;
+      else
+       printf ("minimum stack size is %d\n", PTHREAD_STACK_MIN);
+      break;
+
+    case 'g':
+      snum = strtol (arg, NULL, 0);
+      if (snum < 0)
+       printf ("invalid guard size %s\n", arg);
+      else
+       guardsize = snum;
+      break;
+
+    case 'p':
+      progress = true;
+      break;
+
+    case 'T':
+      timing = true;
+      break;
+
+    case OPT_TO_THREAD:
+      to_thread = true;
+      break;
+
+    case OPT_TO_PROCESS:
+      to_thread = false;
+      break;
+
+    case OPT_SYNC_SIGNAL:
+      sync_method = sync_signal;
+      break;
+
+    case OPT_SYNC_JOIN:
+      sync_method = sync_join;
+      break;
+
+    case OPT_TOPLEVEL:
+      num = strtoul (arg, NULL, 0);
+      if (num < MAX_THREADS)
+       toplevel = num;
+      else
+       printf ("\
+number of threads limited to %u; recompile with a higher limit if necessary",
+               MAX_THREADS);
+      sync_method = sync_join;
+      break;
+
+    default:
+      return ARGP_ERR_UNKNOWN;
+    }
+
+  return 0;
+}
+
+
+static hp_timing_t
+get_clockfreq (void)
+{
+  /* We read the information from the /proc filesystem.  It contains at
+     least one line like
+       cpu MHz         : 497.840237
+     or also
+       cpu MHz         : 497.841
+     We search for this line and convert the number in an integer.  */
+  static hp_timing_t result;
+  int fd;
+
+  /* If this function was called before, we know the result.  */
+  if (result != 0)
+    return result;
+
+  fd = open ("/proc/cpuinfo", O_RDONLY);
+  if (__builtin_expect (fd != -1, 1))
+    {
+      /* XXX AFAIK the /proc filesystem can generate "files" only up
+         to a size of 4096 bytes.  */
+      char buf[4096];
+      ssize_t n;
+
+      n = read (fd, buf, sizeof buf);
+      if (__builtin_expect (n, 1) > 0)
+       {
+         char *mhz = memmem (buf, n, "cpu MHz", 7);
+
+         if (__builtin_expect (mhz != NULL, 1))
+           {
+             char *endp = buf + n;
+             int seen_decpoint = 0;
+             int ndigits = 0;
+
+             /* Search for the beginning of the string.  */
+             while (mhz < endp && (*mhz < '0' || *mhz > '9') && *mhz != '\n')
+               ++mhz;
+
+             while (mhz < endp && *mhz != '\n')
+               {
+                 if (*mhz >= '0' && *mhz <= '9')
+                   {
+                     result *= 10;
+                     result += *mhz - '0';
+                     if (seen_decpoint)
+                       ++ndigits;
+                   }
+                 else if (*mhz == '.')
+                   seen_decpoint = 1;
+
+                 ++mhz;
+               }
+
+             /* Compensate for missing digits at the end.  */
+             while (ndigits++ < 6)
+               result *= 10;
+           }
+       }
+
+      close (fd);
+    }
+
+  return result;
+}
+
+
+int
+clock_getcpuclockid (pid_t pid, clockid_t *clock_id)
+{
+  /* We don't allow any process ID but our own.  */
+  if (pid != 0 && pid != getpid ())
+    return EPERM;
+
+#ifdef CLOCK_PROCESS_CPUTIME_ID
+  /* Store the number.  */
+  *clock_id = CLOCK_PROCESS_CPUTIME_ID;
+
+  return 0;
+#else
+  /* We don't have a timer for that.  */
+  return ENOENT;
+#endif
+}
+
+
+#define HP_TIMING_NOW(Var)     __asm__ __volatile__ ("rdtsc" : "=A" (Var))
+
+/* Get current value of CLOCK and store it in TP.  */
+int
+clock_gettime (clockid_t clock_id, struct timespec *tp)
+{
+  int retval = -1;
+
+  switch (clock_id)
+    {
+    case CLOCK_PROCESS_CPUTIME_ID:
+      {
+
+       static hp_timing_t freq;
+       hp_timing_t tsc;
+
+       /* Get the current counter.  */
+       HP_TIMING_NOW (tsc);
+
+       if (freq == 0)
+         {
+           freq = get_clockfreq ();
+           if (freq == 0)
+             return EINVAL;
+         }
+
+       /* Compute the seconds.  */
+       tp->tv_sec = tsc / freq;
+
+       /* And the nanoseconds.  This computation should be stable until
+          we get machines with about 16GHz frequency.  */
+       tp->tv_nsec = ((tsc % freq) * UINT64_C (1000000000)) / freq;
+
+       retval = 0;
+      }
+    break;
+
+    default:
+      errno = EINVAL;
+      break;
+    }
+
+  return retval;
+}
diff --git a/nptl/pt-accept.c b/nptl/pt-accept.c
new file mode 100644 (file)
index 0000000..09e2c52
--- /dev/null
@@ -0,0 +1,40 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <sysdep.h>
+#include <sys/socket.h>
+#include "pthreadP.h"
+
+
+int
+accept (int fd, __SOCKADDR_ARG addr, socklen_t *addr_len)
+{
+  int oldtype;
+  int result;
+
+  CANCEL_ASYNC (oldtype);
+
+  result = __libc_accept (fd, addr, addr_len);
+
+  CANCEL_RESET (oldtype);
+
+  return result;
+}
diff --git a/nptl/pt-allocrtsig.c b/nptl/pt-allocrtsig.c
new file mode 100644 (file)
index 0000000..3598dbb
--- /dev/null
@@ -0,0 +1,50 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <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/nptl/pt-close.c b/nptl/pt-close.c
new file mode 100644 (file)
index 0000000..85115c9
--- /dev/null
@@ -0,0 +1,45 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <sysdep.h>
+#include <unistd.h>
+#include "pthreadP.h"
+
+
+int
+__close (int fd)
+{
+  int oldtype;
+  int result;
+
+  CANCEL_ASYNC (oldtype);
+
+#ifdef INLINE_SYSCALL
+  result = INLINE_SYSCALL (close, 1, fd);
+#else
+  result = __libc_close (fd);
+#endif
+
+  CANCEL_RESET (oldtype);
+
+  return result;
+}
+strong_alias (__close, close)
diff --git a/nptl/pt-connect.c b/nptl/pt-connect.c
new file mode 100644 (file)
index 0000000..105cb62
--- /dev/null
@@ -0,0 +1,41 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <sysdep.h>
+#include <sys/socket.h>
+#include "pthreadP.h"
+
+
+int
+__connect (int fd, __CONST_SOCKADDR_ARG addr, socklen_t addr_len)
+{
+  int oldtype;
+  int result;
+
+  CANCEL_ASYNC (oldtype);
+
+  result = __libc_connect (fd, addr, addr_len);
+
+  CANCEL_RESET (oldtype);
+
+  return result;
+}
+strong_alias (__connect, connect)
diff --git a/nptl/pt-creat.c b/nptl/pt-creat.c
new file mode 100644 (file)
index 0000000..bdb5e4f
--- /dev/null
@@ -0,0 +1,45 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sysdep.h>
+#include <unistd.h>
+#include "pthreadP.h"
+
+
+int
+creat (const char *pathname, mode_t mode)
+{
+  int result;
+  int oldtype;
+
+  CANCEL_ASYNC (oldtype);
+
+#if defined INLINE_SYSCALL && defined __NR_creat
+  result = INLINE_SYSCALL (creat, 2, pathname, mode);
+#else
+  result = __libc_open (pathname, O_WRONLY|O_CREAT|O_TRUNC, mode);
+#endif
+
+  CANCEL_RESET (oldtype);
+
+  return result;
+}
diff --git a/nptl/pt-fcntl.c b/nptl/pt-fcntl.c
new file mode 100644 (file)
index 0000000..194f6ca
--- /dev/null
@@ -0,0 +1,54 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <sysdep.h>
+#include <unistd.h>
+#include "pthreadP.h"
+
+
+int
+__fcntl (int fd, int cmd, ...)
+{
+  int oldtype;
+  int result;
+  va_list ap;
+
+  if (cmd == F_SETLKW)
+    CANCEL_ASYNC (oldtype);
+
+  va_start (ap, cmd);
+
+#ifdef INLINE_SYSCALL
+  result = INLINE_SYSCALL (fcntl, 3, fd, cmd, va_arg (ap, long int));
+#else
+  result = __libc_fcntl (fd, cmd, va_arg (ap, long int));
+#endif
+
+  va_end (ap);
+
+  if (cmd == F_SETLKW)
+    CANCEL_RESET (oldtype);
+
+  return result;
+}
+strong_alias (__fcntl, fcntl)
diff --git a/nptl/pt-fsync.c b/nptl/pt-fsync.c
new file mode 100644 (file)
index 0000000..6c41912
--- /dev/null
@@ -0,0 +1,44 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <sysdep.h>
+#include <unistd.h>
+#include "pthreadP.h"
+
+
+int
+fsync (int fd)
+{
+  int oldtype;
+  int result;
+
+  CANCEL_ASYNC (oldtype);
+
+#ifdef INLINE_SYSCALL
+  result = INLINE_SYSCALL (fsync, 1, fd);
+#else
+  result = __libc_fsync (fd);
+#endif
+
+  CANCEL_RESET (oldtype);
+
+  return result;
+}
diff --git a/nptl/pt-longjmp.c b/nptl/pt-longjmp.c
new file mode 100644 (file)
index 0000000..f333b8d
--- /dev/null
@@ -0,0 +1,65 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <setjmp.h>
+#include <stdlib.h>
+#include "pthreadP.h"
+
+
+void
+__pthread_cleanup_upto (__jmp_buf target, char *targetframe)
+{
+  struct pthread *self = THREAD_SELF;
+  struct _pthread_cleanup_buffer *cbuf;
+
+  for (cbuf = THREAD_GETMEM (self, cleanup);
+       cbuf != NULL && _JMPBUF_UNWINDS (target, cbuf);
+       cbuf = cbuf->__prev)
+    {
+#if _STACK_GROWS_DOWN
+      if ((char *) cbuf <= targetframe)
+        {
+          cbuf = NULL;
+          break;
+        }
+#elif _STACK_GROWS_UP
+      if ((char *) cbuf >= targetframe)
+        {
+          cbuf = NULL;
+          break;
+        }
+#else
+# error "Define either _STACK_GROWS_DOWN or _STACK_GROWS_UP"
+#endif
+
+      /* Call the cleanup code.  */
+      cbuf->__routine (cbuf->__arg);
+    }
+
+  THREAD_SETMEM (self, cleanup, cbuf);
+}
+
+
+
+void
+longjmp (jmp_buf env, int val)
+{
+  __libc_longjmp (env, val);
+}
+weak_alias (longjmp, siglongjmp)
diff --git a/nptl/pt-lseek.c b/nptl/pt-lseek.c
new file mode 100644 (file)
index 0000000..31e3ef7
--- /dev/null
@@ -0,0 +1,45 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <sysdep.h>
+#include <unistd.h>
+#include "pthreadP.h"
+
+
+off_t
+__lseek (int fd, off_t offset, int whence)
+{
+  int oldtype;
+  off_t result;
+
+  CANCEL_ASYNC (oldtype);
+
+#ifdef INLINE_SYSCALL
+  result = INLINE_SYSCALL (lseek, 3, fd, offset, whence);
+#else
+  result = __libc_lseek (fd, offset, whence);
+#endif
+
+  CANCEL_RESET (oldtype);
+
+  return result;
+}
+strong_alias (__lseek, lseek)
diff --git a/nptl/pt-lseek64.c b/nptl/pt-lseek64.c
new file mode 100644 (file)
index 0000000..f9faa16
--- /dev/null
@@ -0,0 +1,40 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <sysdep.h>
+#include <unistd.h>
+#include "pthreadP.h"
+
+
+off64_t
+lseek64 (int fd, off64_t offset, int whence)
+{
+  int oldtype;
+  off64_t result;
+
+  CANCEL_ASYNC (oldtype);
+
+  result = __libc_lseek64 (fd, offset, whence);
+
+  CANCEL_RESET (oldtype);
+
+  return result;
+}
diff --git a/nptl/pt-msgrcv.c b/nptl/pt-msgrcv.c
new file mode 100644 (file)
index 0000000..b8bf6bc
--- /dev/null
@@ -0,0 +1,40 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <sysdep.h>
+#include <sys/msg.h>
+#include "pthreadP.h"
+
+
+int
+msgrcv (int msqid, void *msgp, size_t msgsz, long int msgtyp, int msgflg)
+{
+  int oldtype;
+  int result;
+
+  CANCEL_ASYNC (oldtype);
+
+  result = __libc_msgrcv (msqid, msgp, msgsz, msgtyp, msgflg);
+
+  CANCEL_RESET (oldtype);
+
+  return result;
+}
diff --git a/nptl/pt-msgsnd.c b/nptl/pt-msgsnd.c
new file mode 100644 (file)
index 0000000..4297f9d
--- /dev/null
@@ -0,0 +1,46 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <sysdep.h>
+#include <sys/msg.h>
+#include <ipc_priv.h>
+#include "pthreadP.h"
+
+
+int
+msgsnd (int msqid, const void *msgp, size_t msgsz, int msgflg)
+{
+  int result;
+  int oldtype;
+
+  CANCEL_ASYNC (oldtype);
+
+#ifdef INLINE_SYSCALL
+  result = INLINE_SYSCALL (ipc, 5, IPCOP_msgsnd, msqid, msgsz,
+                          msgflg, (void *) msgp);
+#else
+  result = __libc_msgsnd (msqid, msgp, msgsz, msgflg);
+#endif
+
+  CANCEL_RESET (oldtype);
+
+  return result;
+}
diff --git a/nptl/pt-msync.c b/nptl/pt-msync.c
new file mode 100644 (file)
index 0000000..c1d6445
--- /dev/null
@@ -0,0 +1,44 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <sysdep.h>
+#include <sys/mman.h>
+#include "pthreadP.h"
+
+
+int
+msync (void *addr, size_t length, int flags)
+{
+  int oldtype;
+  int result;
+
+  CANCEL_ASYNC (oldtype);
+
+#ifdef INLINE_SYSCALL
+  result = INLINE_SYSCALL (msync, 3, addr, length, flags);
+#else
+  result = __libc_msync (addr, length, flags);
+#endif
+
+  CANCEL_RESET (oldtype);
+
+  return result;
+}
diff --git a/nptl/pt-nanosleep.c b/nptl/pt-nanosleep.c
new file mode 100644 (file)
index 0000000..1d6cbb5
--- /dev/null
@@ -0,0 +1,45 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <sysdep.h>
+#include <time.h>
+#include "pthreadP.h"
+
+
+int
+__nanosleep (const struct timespec *requested_time, struct timespec *remaining)
+{
+  int oldtype;
+  int result;
+
+  CANCEL_ASYNC (oldtype);
+
+#ifdef INLINE_SYSCALL
+  result = INLINE_SYSCALL (nanosleep, 2, requested_time, remaining);
+#else
+  result = __libc_nanosleep (requested_time, remaining);
+#endif
+
+  CANCEL_RESET (oldtype);
+
+  return result;
+}
+strong_alias (__nanosleep, nanosleep)
diff --git a/nptl/pt-open.c b/nptl/pt-open.c
new file mode 100644 (file)
index 0000000..00e06b1
--- /dev/null
@@ -0,0 +1,53 @@
+/* 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 <stdarg.h>
+#include <sysdep.h>
+#include <unistd.h>
+#include "pthreadP.h"
+
+
+int
+__open (const char *pathname, int flags, ...)
+{
+  int oldtype;
+  int result;
+  va_list ap;
+
+  va_start (ap, flags);
+
+  CANCEL_ASYNC (oldtype);
+
+#ifdef INLINE_SYSCALL
+  result = INLINE_SYSCALL (open, 3, pathname, flags,
+                          va_arg (ap, __typeof ((mode_t) 0 + 0)));
+#else
+  result = __libc_open (pathname, flags,
+                       va_arg (ap, __typeof ((mode_t) 0 + 0)));
+#endif
+
+  CANCEL_RESET (oldtype);
+
+  va_end (ap);
+
+  return result;
+}
+strong_alias (__open, open)
diff --git a/nptl/pt-open64.c b/nptl/pt-open64.c
new file mode 100644 (file)
index 0000000..25eec28
--- /dev/null
@@ -0,0 +1,54 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <sysdep.h>
+#include <unistd.h>
+#include "pthreadP.h"
+
+
+int
+__open64 (const char *pathname, int flags, ...)
+{
+  int oldtype;
+  int result;
+  va_list ap;
+
+  va_start (ap, flags);
+
+  CANCEL_ASYNC (oldtype);
+
+#if defined INLINE_SYSCALL && defined O_LARGEFILE
+  result = INLINE_SYSCALL (open, 3, pathname, flags | O_LARGEFILE,
+                          va_arg (ap, __typeof ((mode_t) 0 + 0)));
+#else
+  result = __libc_open64 (pathname, flags,
+                         va_arg (ap, __typeof ((mode_t) 0 + 0)));
+#endif
+
+  CANCEL_RESET (oldtype);
+
+  va_end (ap);
+
+  return result;
+}
+strong_alias (__open64, open64)
diff --git a/nptl/pt-pause.c b/nptl/pt-pause.c
new file mode 100644 (file)
index 0000000..dbc6250
--- /dev/null
@@ -0,0 +1,40 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <sysdep.h>
+#include <unistd.h>
+#include "pthreadP.h"
+
+
+int
+pause (void)
+{
+  int oldtype;
+  int result;
+
+  CANCEL_ASYNC (oldtype);
+
+  result = __libc_pause ();
+
+  CANCEL_RESET (oldtype);
+
+  return result;
+}
diff --git a/nptl/pt-poll.c b/nptl/pt-poll.c
new file mode 100644 (file)
index 0000000..65da7e6
--- /dev/null
@@ -0,0 +1,44 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <sysdep.h>
+#include <sys/poll.h>
+#include "pthreadP.h"
+
+
+int
+poll (struct pollfd *fds, nfds_t nfds, int timeout)
+{
+  int result;
+  int oldtype;
+
+  CANCEL_ASYNC (oldtype);
+
+#ifdef INLINE_SYSCALL
+  result = INLINE_SYSCALL (poll, 3, fds, nfds, timeout);
+#else
+  result = __poll (fds, nfds, timeout);
+#endif
+
+  CANCEL_RESET (oldtype);
+
+  return result;
+}
diff --git a/nptl/pt-pread.c b/nptl/pt-pread.c
new file mode 100644 (file)
index 0000000..bcc7e0d
--- /dev/null
@@ -0,0 +1,40 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <sysdep.h>
+#include <unistd.h>
+#include "pthreadP.h"
+
+
+ssize_t
+pread (int fd, void *buf, size_t count, off_t offset)
+{
+  int oldtype;
+  ssize_t result;
+
+  CANCEL_ASYNC (oldtype);
+
+  result = __libc_pread (fd, buf, count, offset);
+
+  CANCEL_RESET (oldtype);
+
+  return result;
+}
diff --git a/nptl/pt-pread64.c b/nptl/pt-pread64.c
new file mode 100644 (file)
index 0000000..1cf85f4
--- /dev/null
@@ -0,0 +1,41 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <sysdep.h>
+#include <unistd.h>
+#include "pthreadP.h"
+
+
+ssize_t
+__pread64 (int fd, void *buf, size_t count, off64_t offset)
+{
+  int oldtype;
+  ssize_t result;
+
+  CANCEL_ASYNC (oldtype);
+
+  result = __libc_pread64 (fd, buf, count, offset);
+
+  CANCEL_RESET (oldtype);
+
+  return result;
+}
+strong_alias (__pread64, pread64)
diff --git a/nptl/pt-pselect.c b/nptl/pt-pselect.c
new file mode 100644 (file)
index 0000000..e935a07
--- /dev/null
@@ -0,0 +1,41 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <sysdep.h>
+#include <sys/select.h>
+#include "pthreadP.h"
+
+
+int
+pselect (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+        const struct timespec *timeout, const sigset_t *sigmask)
+{
+  int result;
+  int oldtype;
+
+  CANCEL_ASYNC (oldtype);
+
+  result = __pselect (nfds, readfds, writefds, exceptfds, timeout, sigmask);
+
+  CANCEL_RESET (oldtype);
+
+  return result;
+}
diff --git a/nptl/pt-pwrite.c b/nptl/pt-pwrite.c
new file mode 100644 (file)
index 0000000..28910f6
--- /dev/null
@@ -0,0 +1,40 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <sysdep.h>
+#include <unistd.h>
+#include "pthreadP.h"
+
+
+ssize_t
+pwrite (int fd, const void *buf, size_t count, off_t offset)
+{
+  int oldtype;
+  ssize_t result;
+
+  CANCEL_ASYNC (oldtype);
+
+  result = __libc_pwrite (fd, buf, count, offset);
+
+  CANCEL_RESET (oldtype);
+
+  return result;
+}
diff --git a/nptl/pt-pwrite64.c b/nptl/pt-pwrite64.c
new file mode 100644 (file)
index 0000000..abe4106
--- /dev/null
@@ -0,0 +1,41 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <sysdep.h>
+#include <unistd.h>
+#include "pthreadP.h"
+
+
+ssize_t
+__pwrite64 (int fd, const void *buf, size_t count, off64_t offset)
+{
+  int oldtype;
+  ssize_t result;
+
+  CANCEL_ASYNC (oldtype);
+
+  result = __libc_pwrite64 (fd, buf, count, offset);
+
+  CANCEL_RESET (oldtype);
+
+  return result;
+}
+strong_alias (__pwrite64, pwrite64)
diff --git a/nptl/pt-read.c b/nptl/pt-read.c
new file mode 100644 (file)
index 0000000..8f31f0c
--- /dev/null
@@ -0,0 +1,45 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <sysdep.h>
+#include <unistd.h>
+#include "pthreadP.h"
+
+
+ssize_t
+__read (int fd, void *buf, size_t count)
+{
+  int oldtype;
+  ssize_t result;
+
+  CANCEL_ASYNC (oldtype);
+
+#ifdef INLINE_SYSCALL
+  result = INLINE_SYSCALL (read, 3, fd, buf, count);
+#else
+  result = __libc_read (fd, buf, count);
+#endif
+
+  CANCEL_RESET (oldtype);
+
+  return result;
+}
+strong_alias (__read, read)
diff --git a/nptl/pt-readv.c b/nptl/pt-readv.c
new file mode 100644 (file)
index 0000000..9f6e653
--- /dev/null
@@ -0,0 +1,58 @@
+/* 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 <sysdep.h>
+#include <sys/uio.h>
+#include "pthreadP.h"
+
+
+/* Not all versions of the kernel support the large number of records.  */
+#ifndef UIO_FASTIOV
+# define UIO_FASTIOV   8       /* 8 is a safe number.  */
+#endif
+
+
+ssize_t
+readv (fd, vector, count)
+     int fd;
+     const struct iovec *vector;
+     int count;
+{
+  int oldtype;
+  ssize_t result;
+
+  CANCEL_ASYNC (oldtype);
+
+#ifdef INTERNAL_SYSCALL
+  result = INTERNAL_SYSCALL (readv, 3, fd, vector, count);
+  if (INTERNAL_SYSCALL_ERROR_P (result)
+      && __builtin_expect (count > UIO_FASTIOV, 0))
+#elif defined INLINE_SYSCALL
+  result = INLINE_SYSCALL (readv, 3, fd, vector, count);
+  if (result < 0 && errno == EINVAL
+      && __builtin_expect (count > UIO_FASTIOV, 0))
+#endif
+    result = __libc_readv (fd, vector, count);
+
+  CANCEL_RESET (oldtype);
+
+  return result;
+}
diff --git a/nptl/pt-recv.c b/nptl/pt-recv.c
new file mode 100644 (file)
index 0000000..0b9f705
--- /dev/null
@@ -0,0 +1,40 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <sysdep.h>
+#include <sys/socket.h>
+#include "pthreadP.h"
+
+
+ssize_t
+recv (int fd, __ptr_t buf, size_t n, int flags)
+{
+  int oldtype;
+  ssize_t result;
+
+  CANCEL_ASYNC (oldtype);
+
+  result = __libc_recv (fd, buf, n, flags);
+
+  CANCEL_RESET (oldtype);
+
+  return result;
+}
diff --git a/nptl/pt-recvfrom.c b/nptl/pt-recvfrom.c
new file mode 100644 (file)
index 0000000..095b0b4
--- /dev/null
@@ -0,0 +1,41 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <sysdep.h>
+#include <sys/socket.h>
+#include "pthreadP.h"
+
+
+ssize_t
+recvfrom (int fd, __ptr_t buf, size_t n, int flags, __SOCKADDR_ARG addr,
+         socklen_t *addr_len)
+{
+  int oldtype;
+  ssize_t result;
+
+  CANCEL_ASYNC (oldtype);
+
+  result = __libc_recvfrom (fd, buf, n, flags, addr, addr_len);
+
+  CANCEL_RESET (oldtype);
+
+  return result;
+}
diff --git a/nptl/pt-recvmsg.c b/nptl/pt-recvmsg.c
new file mode 100644 (file)
index 0000000..e5ceaaa
--- /dev/null
@@ -0,0 +1,40 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <sysdep.h>
+#include <sys/socket.h>
+#include "pthreadP.h"
+
+
+ssize_t
+recvmsg (int fd, struct msghdr *message, int flags)
+{
+  int oldtype;
+  ssize_t result;
+
+  CANCEL_ASYNC (oldtype);
+
+  result = __libc_recvmsg (fd, message, flags);
+
+  CANCEL_RESET (oldtype);
+
+  return result;
+}
diff --git a/nptl/pt-select.c b/nptl/pt-select.c
new file mode 100644 (file)
index 0000000..03e10cd
--- /dev/null
@@ -0,0 +1,46 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <sysdep.h>
+#include <unistd.h>
+#include "pthreadP.h"
+
+
+int
+select (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+       struct timeval *timeout)
+{
+  int result;
+  int oldtype;
+
+  CANCEL_ASYNC (oldtype);
+
+#if defined INLINE_SYSCALL && defined __NR__newselect
+  result = INLINE_SYSCALL (_newselect, 5, nfds, readfds, writefds, exceptfds,
+                          timeout);
+#else
+  result = __select (nfds, readfds, writefds, exceptfds, timeout);
+#endif
+
+  CANCEL_RESET (oldtype);
+
+  return result;
+}
diff --git a/nptl/pt-send.c b/nptl/pt-send.c
new file mode 100644 (file)
index 0000000..90221ad
--- /dev/null
@@ -0,0 +1,41 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <sysdep.h>
+#include <sys/socket.h>
+#include "pthreadP.h"
+
+
+ssize_t
+__send (int fd, const __ptr_t buf, size_t n, int flags)
+{
+  int oldtype;
+  ssize_t result;
+
+  CANCEL_ASYNC (oldtype);
+
+  result = __libc_send (fd, buf, n, flags);
+
+  CANCEL_RESET (oldtype);
+
+  return result;
+}
+strong_alias (__send, send)
diff --git a/nptl/pt-sendmsg.c b/nptl/pt-sendmsg.c
new file mode 100644 (file)
index 0000000..5b4d8b9
--- /dev/null
@@ -0,0 +1,40 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <sysdep.h>
+#include <sys/socket.h>
+#include "pthreadP.h"
+
+
+ssize_t
+sendmsg (int fd, const struct msghdr *message, int flags)
+{
+  int oldtype;
+  ssize_t result;
+
+  CANCEL_ASYNC (oldtype);
+
+  result = __libc_sendmsg (fd, message, flags);
+
+  CANCEL_RESET (oldtype);
+
+  return result;
+}
diff --git a/nptl/pt-sendto.c b/nptl/pt-sendto.c
new file mode 100644 (file)
index 0000000..6a81e61
--- /dev/null
@@ -0,0 +1,41 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <sysdep.h>
+#include <sys/socket.h>
+#include "pthreadP.h"
+
+
+ssize_t
+sendto (int fd, const __ptr_t buf, size_t n, int flags,
+       __CONST_SOCKADDR_ARG addr, socklen_t addr_len)
+{
+  int oldtype;
+  ssize_t result;
+
+  CANCEL_ASYNC (oldtype);
+
+  result = __libc_sendto (fd, buf, n, flags, addr, addr_len);
+
+  CANCEL_RESET (oldtype);
+
+  return result;
+}
diff --git a/nptl/pt-siglongjmp.c b/nptl/pt-siglongjmp.c
new file mode 100644 (file)
index 0000000..6915710
--- /dev/null
@@ -0,0 +1,32 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <setjmp.h>
+#include "pthreadP.h"
+
+
+void
+siglongjmp (sigjmp_buf env, int val)
+{
+  /* XXX Do we have to reset the signal mask before calling the
+     destructors.  */
+  __pthread_cleanup_upto (env->__jmpbuf);
+
+  __libc_siglongjmp (env, val);
+}
diff --git a/nptl/pt-sigpause.c b/nptl/pt-sigpause.c
new file mode 100644 (file)
index 0000000..ad78662
--- /dev/null
@@ -0,0 +1,41 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <sysdep.h>
+#include "pthreadP.h"
+
+
+#undef sigpause
+int
+sigpause (int mask)
+{
+  int oldtype;
+  int result;
+
+  CANCEL_ASYNC (oldtype);
+
+  result = sigpause (mask);
+
+  CANCEL_RESET (oldtype);
+
+  return result;
+}
diff --git a/nptl/pt-sigsuspend.c b/nptl/pt-sigsuspend.c
new file mode 100644 (file)
index 0000000..d345b5d
--- /dev/null
@@ -0,0 +1,44 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sysdep.h>
+#include "pthreadP.h"
+
+
+int
+sigsuspend (const sigset_t *set)
+{
+  int result;
+  int oldtype;
+
+  CANCEL_ASYNC (oldtype);
+
+#ifdef INLINE_SYSCALL
+  result = INLINE_SYSCALL (rt_sigsuspend, 2, set, _NSIG / 8);
+#else
+  result = __sigsuspend (set);
+#endif
+
+  CANCEL_RESET (oldtype);
+
+  return result;
+}
diff --git a/nptl/pt-sigtimedwait.c b/nptl/pt-sigtimedwait.c
new file mode 100644 (file)
index 0000000..c2940f3
--- /dev/null
@@ -0,0 +1,45 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sysdep.h>
+#include "pthreadP.h"
+
+
+int
+sigtimedwait (const sigset_t *set, siginfo_t *info,
+             const struct timespec *timeout)
+{
+  int result;
+  int oldtype;
+
+  CANCEL_ASYNC (oldtype);
+
+#ifdef INLINE_SYSCALL
+  result = INLINE_SYSCALL (rt_sigtimedwait, 4, set, info, timeout, _NSIG / 8);
+#else
+  result = __sigtimedwait (set, info, timeout);
+#endif
+
+  CANCEL_RESET (oldtype);
+
+  return result;
+}
diff --git a/nptl/pt-sigwait.c b/nptl/pt-sigwait.c
new file mode 100644 (file)
index 0000000..efd05ed
--- /dev/null
@@ -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 <errno.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sysdep.h>
+#include "pthreadP.h"
+
+
+int
+sigwait (const sigset_t *set, int *sig)
+{
+  int result;
+  int oldtype;
+
+  CANCEL_ASYNC (oldtype);
+
+#ifdef INTERNAL_SYSCALL
+  result = INTERNAL_SYSCALL (rt_sigtimedwait, 4, set, NULL, NULL, _NSIG / 8);
+  if (! INTERNAL_SYSCALL_ERROR_P (result))
+    {
+      *sig = result;
+      result = 0;
+    }
+  else
+    result = INTERNAL_SYSCALL_ERRNO (result);
+#elif defined INLINE_SYSCALL
+  result = INLINE_SYSCALL (rt_sigtimedwait, 4, set, NULL, NULL, _NSIG / 8);
+  if (result != -1)
+    {
+      *sig = result;
+      result = 0;
+    }
+  else
+    result = errno;
+#else
+  result = __sigwait (set, sig);
+#endif
+
+  CANCEL_RESET (oldtype);
+
+  return result;
+}
diff --git a/nptl/pt-sigwaitinfo.c b/nptl/pt-sigwaitinfo.c
new file mode 100644 (file)
index 0000000..961293b
--- /dev/null
@@ -0,0 +1,44 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sysdep.h>
+#include "pthreadP.h"
+
+
+int
+sigwaitinfo (const sigset_t *set, siginfo_t *info)
+{
+  int result;
+  int oldtype;
+
+  CANCEL_ASYNC (oldtype);
+
+#ifdef INLINE_SYSCALL
+  result = INLINE_SYSCALL (rt_sigtimedwait, 4, set, info, NULL, _NSIG / 8);
+#else
+  result = __sigwaitinfo (set, info);
+#endif
+
+  CANCEL_RESET (oldtype);
+
+  return result;
+}
diff --git a/nptl/pt-system.c b/nptl/pt-system.c
new file mode 100644 (file)
index 0000000..2572c47
--- /dev/null
@@ -0,0 +1,40 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <sysdep.h>
+#include <stdlib.h>
+#include "pthreadP.h"
+
+
+int
+system (const char *line)
+{
+  int oldtype;
+  int result;
+
+  CANCEL_ASYNC (oldtype);
+
+  result = __libc_system (line);
+
+  CANCEL_RESET (oldtype);
+
+  return result;
+}
diff --git a/nptl/pt-tcdrain.c b/nptl/pt-tcdrain.c
new file mode 100644 (file)
index 0000000..65af7b8
--- /dev/null
@@ -0,0 +1,40 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <sysdep.h>
+#include <termios.h>
+#include "pthreadP.h"
+
+
+int
+tcdrain (int fd)
+{
+  int oldtype;
+  int result;
+
+  CANCEL_ASYNC (oldtype);
+
+  result = __libc_tcdrain (fd);
+
+  CANCEL_RESET (oldtype);
+
+  return result;
+}
diff --git a/nptl/pt-wait.c b/nptl/pt-wait.c
new file mode 100644 (file)
index 0000000..951bba6
--- /dev/null
@@ -0,0 +1,41 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <sysdep.h>
+#include <sys/wait.h>
+#include "pthreadP.h"
+
+
+pid_t
+__wait (__WAIT_STATUS_DEFN stat_loc)
+{
+  int oldtype;
+  pid_t result;
+
+  CANCEL_ASYNC (oldtype);
+
+  result = __libc_wait (stat_loc);
+
+  CANCEL_RESET (oldtype);
+
+  return result;
+}
+strong_alias (__wait, wait)
diff --git a/nptl/pt-waitid.c b/nptl/pt-waitid.c
new file mode 100644 (file)
index 0000000..977e5d4
--- /dev/null
@@ -0,0 +1,41 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <sysdep.h>
+#include <sys/wait.h>
+#include "pthreadP.h"
+
+
+int
+waitid (idtype_t idtype, id_t id, siginfo_t *infop, int options)
+{
+  int oldtype;
+  int result;
+
+  CANCEL_ASYNC (oldtype);
+
+  result = __waitid (idtype, id, infop, options);
+
+  CANCEL_RESET (oldtype);
+
+  return result;
+}
+strong_alias (__wait, wait)
diff --git a/nptl/pt-waitpid.c b/nptl/pt-waitpid.c
new file mode 100644 (file)
index 0000000..413328b
--- /dev/null
@@ -0,0 +1,40 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <sysdep.h>
+#include <sys/wait.h>
+#include "pthreadP.h"
+
+
+pid_t
+waitpid (pid_t pid, int *stat_loc, int options)
+{
+  int oldtype;
+  pid_t result;
+
+  CANCEL_ASYNC (oldtype);
+
+  result = __libc_waitpid (pid, stat_loc, options);
+
+  CANCEL_RESET (oldtype);
+
+  return result;
+}
diff --git a/nptl/pt-write.c b/nptl/pt-write.c
new file mode 100644 (file)
index 0000000..190bea9
--- /dev/null
@@ -0,0 +1,45 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <sysdep.h>
+#include <unistd.h>
+#include "pthreadP.h"
+
+
+ssize_t
+__write (int fd, const void *buf, size_t count)
+{
+  int oldtype;
+  ssize_t result;
+
+  CANCEL_ASYNC (oldtype);
+
+#ifdef INLINE_SYSCALL
+  result = INLINE_SYSCALL (write, 3, fd, buf, count);
+#else
+  result = __libc_write (fd, buf, count);
+#endif
+
+  CANCEL_RESET (oldtype);
+
+  return result;
+}
+strong_alias (__write, write)
diff --git a/nptl/pt-writev.c b/nptl/pt-writev.c
new file mode 100644 (file)
index 0000000..c1dda35
--- /dev/null
@@ -0,0 +1,58 @@
+/* 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 <sysdep.h>
+#include <sys/uio.h>
+#include "pthreadP.h"
+
+
+/* Not all versions of the kernel support the large number of records.  */
+#ifndef UIO_FASTIOV
+# define UIO_FASTIOV   8       /* 8 is a safe number.  */
+#endif
+
+
+ssize_t
+writev (fd, vector, count)
+     int fd;
+     const struct iovec *vector;
+     int count;
+{
+  int oldtype;
+  ssize_t result;
+
+  CANCEL_ASYNC (oldtype);
+
+#ifdef INTERNAL_SYSCALL
+  result = INTERNAL_SYSCALL (writev, 3, fd, vector, count);
+  if (INTERNAL_SYSCALL_ERROR_P (result)
+      && __builtin_expect (count > UIO_FASTIOV, 0))
+#elif defined INLINE_SYSCALL
+  result = INLINE_SYSCALL (writev, 3, fd, vector, count);
+  if (result < 0 && errno == EINVAL
+      && __builtin_expect (count > UIO_FASTIOV, 0))
+#endif
+    result = __libc_writev (fd, vector, count);
+
+  CANCEL_RESET (oldtype);
+
+  return result;
+}
diff --git a/nptl/pthreadP.h b/nptl/pthreadP.h
new file mode 100644 (file)
index 0000000..adca051
--- /dev/null
@@ -0,0 +1,182 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _PTHREADP_H
+#define _PTHREADP_H    1
+
+#include <pthread.h>
+#include <setjmp.h>
+#include <stdint.h>
+#include <sys/syscall.h>
+#include "descr.h"
+#include <tls.h>
+#include <lowlevellock.h>
+#include <stackinfo.h>
+#include <internaltypes.h>
+
+
+/* Internal variables.  */
+
+
+/* Default stack size.  */
+extern size_t __default_stacksize attribute_hidden;
+
+/* Size and alignment of static TLS block.  */
+extern size_t __static_tls_size attribute_hidden;
+extern size_t __static_tls_align attribute_hidden;
+
+/* Thread descriptor handling.  */
+extern list_t __stack_user attribute_hidden;
+
+/* Attribute handling.  */
+extern struct pthread_attr *__attr_list attribute_hidden;
+extern lll_lock_t __attr_list_lock attribute_hidden;
+
+/* First available RT signal.  */
+extern int __current_sigrtmin attribute_hidden;
+/* Last available RT signal.  */
+extern int __current_sigrtmax attribute_hidden;
+
+/* Concurrency handling.  */
+extern int __concurrency_level attribute_hidden;
+
+/* Thread-local data key handling.  */
+extern struct pthread_key_struct __pthread_keys[PTHREAD_KEYS_MAX]
+     attribute_hidden;
+
+/* The library can run in debugging mode where it performs a lot more
+   tests.  */
+extern int __pthread_debug attribute_hidden;
+#define DEBUGGING_P __builtin_expect (__pthread_debug, 0)
+
+
+/* Cancellation test.  */
+#define CANCELLATION_P(self) \
+  do {                                                                       \
+    int cancelhandling = THREAD_GETMEM (self, cancelhandling);               \
+    if (CANCEL_ENABLED_AND_CANCELED (cancelhandling))                        \
+      {                                                                              \
+       THREAD_SETMEM (self, result, PTHREAD_CANCELED);                       \
+       __do_cancel (CURRENT_STACK_FRAME);                                    \
+      }                                                                              \
+  } while (0)
+
+/* Set cancellation mode to asynchronous.  */
+#define CANCEL_ASYNC(oldtype) \
+  pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype)
+/* Reset to previous cancellation mode.  */
+#define CANCEL_RESET(oldtype) \
+  pthread_setcanceltype (oldtype, NULL)
+
+/* Function performing the cancellation.  */
+extern void __do_cancel (char *currentframe)
+     __attribute ((visibility ("hidden"), noreturn, regparm (1)));
+extern void __cleanup_thread (struct pthread *self, char *currentframe)
+     __attribute ((visibility ("hidden"), regparm (2)));
+
+
+/* Test whether stackframe is still active.  */
+#ifdef _STACK_GROWS_DOWN
+# define FRAME_LEFT(frame, other) ((char *) frame >= (char *) other)
+#elif _STACK_GROWS_UP
+# define FRAME_LEFT(frame, other) ((char *) frame <= (char *) other)
+#else
+# error "Define either _STACK_GROWS_DOWN or _STACK_GROWS_UP"
+#endif
+
+
+/* Internal prototypes.  */
+
+/* Thread list handling.  */
+extern struct pthread *__find_in_stack_list (struct pthread *pd)
+     attribute_hidden;
+
+/* Deallocate a thread's stack after optionally making sure the thread
+   descriptor is still valid.  */
+extern void __free_tcb (struct pthread *pd) attribute_hidden;
+
+/* Free allocated stack.  */
+extern void __deallocate_stack (struct pthread *pd) attribute_hidden;
+
+/* Mark all the stacks except for the current one as available.  This
+   function also re-initializes the lock for the stack cache.  */
+extern void __reclaim_stacks (void) attribute_hidden;
+
+/* longjmp handling.  */
+extern void __pthread_cleanup_upto (__jmp_buf target, char *targetframe);
+
+
+/* Functions with versioned interfaces.  */
+extern int __pthread_create_2_1 (pthread_t *newthread,
+                                const pthread_attr_t *attr,
+                                void *(*start_routine) (void *), void *arg);
+extern int __pthread_create_2_0 (pthread_t *newthread,
+                                const pthread_attr_t *attr,
+                                void *(*start_routine) (void *), void *arg);
+extern int __pthread_attr_init_2_1 (pthread_attr_t *attr);
+extern int __pthread_attr_init_2_0 (pthread_attr_t *attr);
+
+
+/* Event handlers for libthread_db interface.  */
+extern void __nptl_create_event (void) attribute_hidden;
+extern void __nptl_death_event (void) attribute_hidden;
+
+
+/* Namespace save aliases.  */
+extern int __pthread_mutex_init (pthread_mutex_t *__mutex,
+                                __const pthread_mutexattr_t *__mutexattr);
+extern int __pthread_mutex_destroy (pthread_mutex_t *__mutex);
+extern int __pthread_mutex_trylock (pthread_mutex_t *_mutex);
+extern int __pthread_mutex_lock (pthread_mutex_t *__mutex);
+extern int __pthread_mutex_unlock (pthread_mutex_t *__mutex);
+extern int __pthread_mutexattr_init (pthread_mutexattr_t *attr);
+extern int __pthread_mutexattr_destroy (pthread_mutexattr_t *attr);
+extern int __pthread_mutexattr_settype (pthread_mutexattr_t *attr, int kind);
+extern int __pthread_attr_getstackaddr (__const pthread_attr_t *__restrict
+                                       __attr, void **__restrict __stackaddr);
+extern int __pthread_attr_setstackaddr (pthread_attr_t *__attr,
+                                       void *__stackaddr);
+extern int __pthread_attr_getstacksize (__const pthread_attr_t *__restrict
+                                       __attr,
+                                       size_t *__restrict __stacksize);
+extern int __pthread_attr_setstacksize (pthread_attr_t *__attr,
+                                       size_t __stacksize);
+extern int __pthread_attr_getstack (__const pthread_attr_t *__restrict __attr,
+                                   void **__restrict __stackaddr,
+                                   size_t *__restrict __stacksize);
+extern int __pthread_attr_setstack (pthread_attr_t *__attr, void *__stackaddr,
+                                   size_t __stacksize);
+extern int __pthread_rwlock_init (pthread_rwlock_t *__restrict __rwlock,
+                                 __const pthread_rwlockattr_t *__restrict
+                                 __attr);
+extern int __pthread_rwlock_destroy (pthread_rwlock_t *__rwlock);
+extern int __pthread_rwlock_rdlock (pthread_rwlock_t *__rwlock);
+extern int __pthread_rwlock_tryrdlock (pthread_rwlock_t *__rwlock);
+extern int __pthread_rwlock_wrlock (pthread_rwlock_t *__rwlock);
+extern int __pthread_rwlock_trywrlock (pthread_rwlock_t *__rwlock);
+extern int __pthread_rwlock_unlock (pthread_rwlock_t *__rwlock);
+extern int __pthread_key_create (pthread_key_t *key, void (*destr) (void *));
+extern void *__pthread_getspecific (pthread_key_t key);
+extern int __pthread_setspecific (pthread_key_t key, const void *value);
+extern int __pthread_once (pthread_once_t *once_control,
+                          void (*init_routine) (void));
+extern int __pthread_atfork (void (*prepare) (void), void (*parent) (void),
+                            void (*child) (void));
+
+#endif /* pthreadP.h */
diff --git a/nptl/pthread_atfork.c b/nptl/pthread_atfork.c
new file mode 100644 (file)
index 0000000..00a52fd
--- /dev/null
@@ -0,0 +1,46 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+#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/nptl/pthread_attr_destroy.c b/nptl/pthread_attr_destroy.c
new file mode 100644 (file)
index 0000000..088800c
--- /dev/null
@@ -0,0 +1,66 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include "pthreadP.h"
+
+
+int
+pthread_attr_destroy (attr)
+     pthread_attr_t *attr;
+{
+  /* Enqueue the attributes to the list of all known variables.  */
+  if (DEBUGGING_P)
+    {
+      struct pthread_attr *iattr;
+      struct pthread_attr *prevp = NULL;
+      struct pthread_attr *runp;
+
+      assert (sizeof (*attr) >= sizeof (struct pthread_attr));
+      iattr = (struct pthread_attr *) attr;
+
+      lll_lock (__attr_list_lock);
+
+      runp = __attr_list;
+      while (runp != NULL && runp != iattr)
+       {
+         prevp = runp;
+         runp = runp->next;
+       }
+
+      if (runp != NULL)
+       {
+         if (prevp == NULL)
+           __attr_list = iattr->next;
+         else
+           prevp->next = iattr->next;
+       }
+
+      lll_unlock (__attr_list_lock);
+
+      if (runp == NULL)
+       /* Not a valid attribute.  */
+       return EINVAL;
+    }
+
+  return 0;
+}
diff --git a/nptl/pthread_attr_getdetachstate.c b/nptl/pthread_attr_getdetachstate.c
new file mode 100644 (file)
index 0000000..a1a0549
--- /dev/null
@@ -0,0 +1,38 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <assert.h>
+#include "pthreadP.h"
+
+
+int
+pthread_attr_getdetachstate (attr, detachstate)
+     const pthread_attr_t *attr;
+     int *detachstate;
+{
+  struct pthread_attr *iattr;
+
+  assert (sizeof (*attr) >= sizeof (struct pthread_attr));
+  iattr = (struct pthread_attr *) attr;
+
+  *detachstate = (iattr->flags & ATTR_FLAG_DETACHSTATE
+                 ? PTHREAD_CREATE_DETACHED : PTHREAD_CREATE_JOINABLE);
+
+  return 0;
+}
diff --git a/nptl/pthread_attr_getguardsize.c b/nptl/pthread_attr_getguardsize.c
new file mode 100644 (file)
index 0000000..e1d0ed6
--- /dev/null
@@ -0,0 +1,37 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <assert.h>
+#include "pthreadP.h"
+
+
+int
+pthread_attr_getguardsize (attr, guardsize)
+     const pthread_attr_t *attr;
+     size_t *guardsize;
+{
+  struct pthread_attr *iattr;
+
+  assert (sizeof (*attr) >= sizeof (struct pthread_attr));
+  iattr = (struct pthread_attr *) attr;
+
+  *guardsize = iattr->guardsize;
+
+  return 0;
+}
diff --git a/nptl/pthread_attr_getinheritsched.c b/nptl/pthread_attr_getinheritsched.c
new file mode 100644 (file)
index 0000000..faba994
--- /dev/null
@@ -0,0 +1,39 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <assert.h>
+#include "pthreadP.h"
+
+
+int
+pthread_attr_getinheritsched (attr, inherit)
+     const pthread_attr_t *attr;
+     int *inherit;
+{
+  struct pthread_attr *iattr;
+
+  assert (sizeof (*attr) >= sizeof (struct pthread_attr));
+  iattr = (struct pthread_attr *) attr;
+
+  /* Store the current values.  */
+  *inherit = (iattr->flags & ATTR_FLAG_NOTINHERITSCHED
+             ? PTHREAD_EXPLICIT_SCHED : PTHREAD_INHERIT_SCHED);
+
+  return 0;
+}
diff --git a/nptl/pthread_attr_getschedparam.c b/nptl/pthread_attr_getschedparam.c
new file mode 100644 (file)
index 0000000..93961d5
--- /dev/null
@@ -0,0 +1,39 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <assert.h>
+#include <string.h>
+#include "pthreadP.h"
+
+
+int
+pthread_attr_getschedparam (attr, param)
+     const pthread_attr_t *attr;
+     struct sched_param *param;
+{
+  struct pthread_attr *iattr;
+
+  assert (sizeof (*attr) >= sizeof (struct pthread_attr));
+  iattr = (struct pthread_attr *) attr;
+
+  /* Copy the current values.  */
+  memcpy (param, &iattr->schedparam, sizeof (struct sched_param));
+
+  return 0;
+}
diff --git a/nptl/pthread_attr_getschedpolicy.c b/nptl/pthread_attr_getschedpolicy.c
new file mode 100644 (file)
index 0000000..18293f2
--- /dev/null
@@ -0,0 +1,38 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <assert.h>
+#include "pthreadP.h"
+
+
+int
+pthread_attr_getschedpolicy (attr, policy)
+     const pthread_attr_t *attr;
+     int *policy;
+{
+  struct pthread_attr *iattr;
+
+  assert (sizeof (*attr) >= sizeof (struct pthread_attr));
+  iattr = (struct pthread_attr *) attr;
+
+  /* Store the current values.  */
+  *policy = iattr->schedpolicy;
+
+  return 0;
+}
diff --git a/nptl/pthread_attr_getscope.c b/nptl/pthread_attr_getscope.c
new file mode 100644 (file)
index 0000000..1b97ef3
--- /dev/null
@@ -0,0 +1,39 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <assert.h>
+#include "pthreadP.h"
+
+
+int
+pthread_attr_getscope (attr, scope)
+     const pthread_attr_t *attr;
+     int *scope;
+{
+  struct pthread_attr *iattr;
+
+  assert (sizeof (*attr) >= sizeof (struct pthread_attr));
+  iattr = (struct pthread_attr *) attr;
+
+  /* Store the current values.  */
+  *scope = (iattr->flags & ATTR_FLAG_SCOPEPROCESS
+             ? PTHREAD_SCOPE_PROCESS : PTHREAD_SCOPE_SYSTEM);
+
+  return 0;
+}
diff --git a/nptl/pthread_attr_getstack.c b/nptl/pthread_attr_getstack.c
new file mode 100644 (file)
index 0000000..1db135e
--- /dev/null
@@ -0,0 +1,41 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <assert.h>
+#include "pthreadP.h"
+
+
+int
+__pthread_attr_getstack (attr, stackaddr, stacksize)
+     const pthread_attr_t *attr;
+     void **stackaddr;
+     size_t *stacksize;
+{
+  struct pthread_attr *iattr;
+
+  assert (sizeof (*attr) >= sizeof (struct pthread_attr));
+  iattr = (struct pthread_attr *) attr;
+
+  /* Store the result.  */
+  *stackaddr = (char *) iattr->stackaddr - iattr->stacksize;
+  *stacksize = iattr->stacksize;
+
+  return 0;
+}
+strong_alias (__pthread_attr_getstack, pthread_attr_getstack)
diff --git a/nptl/pthread_attr_getstackaddr.c b/nptl/pthread_attr_getstackaddr.c
new file mode 100644 (file)
index 0000000..f483dc8
--- /dev/null
@@ -0,0 +1,49 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <assert.h>
+#include <errno.h>
+#include "pthreadP.h"
+
+
+int
+__pthread_attr_getstackaddr (attr, stackaddr)
+     const pthread_attr_t *attr;
+     void **stackaddr;
+{
+  struct pthread_attr *iattr;
+
+  assert (sizeof (*attr) >= sizeof (struct pthread_attr));
+  iattr = (struct pthread_attr *) attr;
+
+  /* XXX This function has a stupid definition.  The standard
+     specifies no error value but what is if no stack address was set?
+     We return an error anyway.  */
+  if ((iattr->flags & ATTR_FLAG_STACKADDR) == 0)
+    return EINVAL;
+
+  /* Store the result.  */
+  *stackaddr = iattr->stackaddr;
+
+  return 0;
+}
+strong_alias (__pthread_attr_getstackaddr, pthread_attr_getstackaddr)
+
+link_warning (pthread_attr_getstackaddr,
+              "the use of `pthread_attr_getstackaddr' is deprecated, use `pthread_attr_getstack'")
diff --git a/nptl/pthread_attr_getstacksize.c b/nptl/pthread_attr_getstacksize.c
new file mode 100644 (file)
index 0000000..d4ff54f
--- /dev/null
@@ -0,0 +1,40 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <assert.h>
+#include "pthreadP.h"
+
+
+int
+__pthread_attr_getstacksize (attr, stacksize)
+     const pthread_attr_t *attr;
+     size_t *stacksize;
+{
+  struct pthread_attr *iattr;
+
+  assert (sizeof (*attr) >= sizeof (struct pthread_attr));
+  iattr = (struct pthread_attr *) attr;
+
+  /* If the user has not set a stack size we return what the system
+     will use as the default.  */
+  *stacksize = iattr->stacksize ?: __default_stacksize;
+
+  return 0;
+}
+strong_alias (__pthread_attr_getstacksize, pthread_attr_getstacksize)
diff --git a/nptl/pthread_attr_init.c b/nptl/pthread_attr_init.c
new file mode 100644 (file)
index 0000000..90c8dc2
--- /dev/null
@@ -0,0 +1,97 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include "pthreadP.h"
+
+#include <shlib-compat.h>
+
+
+struct pthread_attr *__attr_list;
+lll_lock_t __attr_list_lock = LLL_LOCK_INITIALIZER;
+
+
+int
+__pthread_attr_init_2_1 (attr)
+     pthread_attr_t *attr;
+{
+  struct pthread_attr *iattr;
+
+  /* Many elements are initialized to zero so let us do it all at
+     once.  This also takes care of clearing the bytes which are not
+     internally used.  */
+  memset (attr, '\0', __SIZEOF_PTHREAD_ATTR_T);
+
+  assert (sizeof (*attr) >= sizeof (struct pthread_attr));
+  iattr = (struct pthread_attr *) attr;
+
+  /* Default guard size specified by the standard.  */
+  iattr->guardsize = __getpagesize ();
+
+  /* Enqueue the attributes to the list of all known variables.  */
+  if (DEBUGGING_P)
+    {
+      lll_lock (__attr_list_lock);
+
+      iattr->next = __attr_list;
+      __attr_list = iattr;
+
+      lll_unlock (__attr_list_lock);
+    }
+
+  return 0;
+}
+versioned_symbol (libpthread, __pthread_attr_init_2_1, pthread_attr_init,
+                 GLIBC_2_1);
+
+
+#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_1)
+int
+__pthread_attr_init_2_0 (attr)
+     pthread_attr_t *attr;
+{
+  /* This code is specific to the old LinuxThread code which has a too
+     small pthread_attr_t definition.  The struct looked like
+     this:  */
+  struct old_attr
+  {
+    int detachstate;
+    int schedpolicy;
+    struct sched_param schedparam;
+    int inheritsched;
+    int scope;
+  } *iattr;
+
+  /* Many elements are initialized to zero so let us do it all at
+     once.  This also takes care of clearing the bytes which are not
+     internally used.  */
+  memset (attr, '\0', sizeof (struct old_attr));
+
+  iattr = (struct old_attr *) attr;
+
+  /* We cannot enqueue the attribute because that member is not in the
+     old attribute structure.  */
+  return 0;
+}
+compat_symbol (libpthread, __pthread_attr_init_2_0, pthread_attr_init,
+              GLIBC_2_0);
+#endif
diff --git a/nptl/pthread_attr_setdetachstate.c b/nptl/pthread_attr_setdetachstate.c
new file mode 100644 (file)
index 0000000..3f247cf
--- /dev/null
@@ -0,0 +1,47 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <assert.h>
+#include <errno.h>
+#include "pthreadP.h"
+
+
+int
+pthread_attr_setdetachstate (attr, detachstate)
+     pthread_attr_t *attr;
+     int detachstate;
+{
+  struct pthread_attr *iattr;
+
+  assert (sizeof (*attr) >= sizeof (struct pthread_attr));
+  iattr = (struct pthread_attr *) attr;
+
+  /* Catch invalid values.  */
+  if (detachstate != PTHREAD_CREATE_DETACHED
+      && __builtin_expect (detachstate != PTHREAD_CREATE_JOINABLE, 0))
+    return EINVAL;
+
+  /* Set the flag.  It is nonzero if threads are created detached.  */
+  if (detachstate == PTHREAD_CREATE_DETACHED)
+    iattr->flags |= ATTR_FLAG_DETACHSTATE;
+  else
+    iattr->flags &= ~ATTR_FLAG_DETACHSTATE;
+
+  return 0;
+}
diff --git a/nptl/pthread_attr_setguardsize.c b/nptl/pthread_attr_setguardsize.c
new file mode 100644 (file)
index 0000000..4c674f4
--- /dev/null
@@ -0,0 +1,40 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <assert.h>
+#include "pthreadP.h"
+
+
+int
+pthread_attr_setguardsize (attr, guardsize)
+     pthread_attr_t *attr;
+     size_t guardsize;
+{
+  struct pthread_attr *iattr;
+
+  assert (sizeof (*attr) >= sizeof (struct pthread_attr));
+  iattr = (struct pthread_attr *) attr;
+
+  /* Note that we don't round the value here.  The standard requires
+     that subsequent pthread_attr_getguardsize calls return the value
+     set by the user.  */
+  iattr->guardsize = guardsize;
+
+  return 0;
+}
diff --git a/nptl/pthread_attr_setinheritsched.c b/nptl/pthread_attr_setinheritsched.c
new file mode 100644 (file)
index 0000000..f724396
--- /dev/null
@@ -0,0 +1,46 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <assert.h>
+#include <errno.h>
+#include "pthreadP.h"
+
+
+int
+pthread_attr_setinheritsched (attr, inherit)
+     pthread_attr_t *attr;
+     int inherit;
+{
+  struct pthread_attr *iattr;
+
+  assert (sizeof (*attr) >= sizeof (struct pthread_attr));
+  iattr = (struct pthread_attr *) attr;
+
+  /* Catch invalid values.  */
+  if (inherit != PTHREAD_INHERIT_SCHED && inherit != PTHREAD_EXPLICIT_SCHED)
+    return EINVAL;
+
+  /* Store the new values.  */
+  if (inherit != PTHREAD_INHERIT_SCHED)
+    iattr->flags |= ATTR_FLAG_NOTINHERITSCHED;
+  else
+    iattr->flags &= ~ATTR_FLAG_NOTINHERITSCHED;
+
+  return 0;
+}
diff --git a/nptl/pthread_attr_setschedparam.c b/nptl/pthread_attr_setschedparam.c
new file mode 100644 (file)
index 0000000..2ffba99
--- /dev/null
@@ -0,0 +1,49 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include "pthreadP.h"
+
+
+int
+pthread_attr_setschedparam (attr, param)
+     pthread_attr_t *attr;
+     const struct sched_param *param;
+{
+  struct pthread_attr *iattr;
+  int max_prio;
+  int min_prio;
+
+  assert (sizeof (*attr) >= sizeof (struct pthread_attr));
+  iattr = (struct pthread_attr *) attr;
+
+  max_prio = __sched_get_priority_max (iattr->schedpolicy);
+  min_prio = __sched_get_priority_min (iattr->schedpolicy);
+
+  /* Catch invalid values.  */
+  if (param->sched_priority < min_prio || param->sched_priority > max_prio)
+    return EINVAL;
+
+  /* Copy the new values.  */
+  memcpy (&iattr->schedparam, param, sizeof (struct sched_param));
+
+  return 0;
+}
diff --git a/nptl/pthread_attr_setschedpolicy.c b/nptl/pthread_attr_setschedpolicy.c
new file mode 100644 (file)
index 0000000..65bf155
--- /dev/null
@@ -0,0 +1,43 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <assert.h>
+#include <errno.h>
+#include "pthreadP.h"
+
+
+int
+pthread_attr_setschedpolicy (attr, policy)
+     pthread_attr_t *attr;
+     int policy;
+{
+  struct pthread_attr *iattr;
+
+  assert (sizeof (*attr) >= sizeof (struct pthread_attr));
+  iattr = (struct pthread_attr *) attr;
+
+  /* Catch invalid values.  */
+  if (policy != SCHED_OTHER && policy != SCHED_FIFO && policy != SCHED_RR)
+    return EINVAL;
+
+  /* Store the new values.  */
+  iattr->schedpolicy = policy;
+
+  return 0;
+}
diff --git a/nptl/pthread_attr_setscope.c b/nptl/pthread_attr_setscope.c
new file mode 100644 (file)
index 0000000..1435afb
--- /dev/null
@@ -0,0 +1,50 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <assert.h>
+#include <errno.h>
+#include "pthreadP.h"
+
+
+int
+pthread_attr_setscope (attr, scope)
+     pthread_attr_t *attr;
+     int scope;
+{
+  struct pthread_attr *iattr;
+
+  assert (sizeof (*attr) >= sizeof (struct pthread_attr));
+  iattr = (struct pthread_attr *) attr;
+
+  /* Catch invalid values.  */
+  switch (scope)
+    {
+    case PTHREAD_SCOPE_SYSTEM:
+      iattr->flags &= ~ATTR_FLAG_SCOPEPROCESS;
+      break;
+
+    case PTHREAD_SCOPE_PROCESS:
+      return ENOTSUP;
+
+    default:
+      return EINVAL;
+    }
+
+  return 0;
+}
diff --git a/nptl/pthread_attr_setstack.c b/nptl/pthread_attr_setstack.c
new file mode 100644 (file)
index 0000000..811ab69
--- /dev/null
@@ -0,0 +1,47 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include "pthreadP.h"
+
+
+int
+__pthread_attr_setstack (attr, stackaddr, stacksize)
+     pthread_attr_t *attr;
+     void *stackaddr;
+     size_t stacksize;
+{
+  struct pthread_attr *iattr;
+
+  assert (sizeof (*attr) >= sizeof (struct pthread_attr));
+  iattr = (struct pthread_attr *) attr;
+
+  /* Catch invalid sizes.  */
+  if (stacksize < PTHREAD_STACK_MIN)
+    return EINVAL;
+
+  iattr->stacksize = stacksize;
+  iattr->stackaddr = (char *) stackaddr + stacksize;
+  iattr->flags |= ATTR_FLAG_STACKADDR;
+
+  return 0;
+}
+strong_alias (__pthread_attr_setstack, pthread_attr_setstack)
diff --git a/nptl/pthread_attr_setstackaddr.c b/nptl/pthread_attr_setstackaddr.c
new file mode 100644 (file)
index 0000000..a725112
--- /dev/null
@@ -0,0 +1,43 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <assert.h>
+#include <errno.h>
+#include "pthreadP.h"
+
+
+int
+__pthread_attr_setstackaddr (attr, stackaddr)
+     pthread_attr_t *attr;
+     void *stackaddr;
+{
+  struct pthread_attr *iattr;
+
+  assert (sizeof (*attr) >= sizeof (struct pthread_attr));
+  iattr = (struct pthread_attr *) attr;
+
+  iattr->stackaddr = stackaddr;
+  iattr->flags |= ATTR_FLAG_STACKADDR;
+
+  return 0;
+}
+strong_alias (__pthread_attr_setstackaddr, pthread_attr_setstackaddr)
+
+link_warning (pthread_attr_setstackaddr,
+              "the use of `pthread_attr_setstackaddr' is deprecated, use `pthread_attr_setstack'")
diff --git a/nptl/pthread_attr_setstacksize.c b/nptl/pthread_attr_setstacksize.c
new file mode 100644 (file)
index 0000000..508cc3f
--- /dev/null
@@ -0,0 +1,44 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include "pthreadP.h"
+
+
+int
+__pthread_attr_setstacksize (attr, stacksize)
+     pthread_attr_t *attr;
+     size_t stacksize;
+{
+  struct pthread_attr *iattr;
+
+  assert (sizeof (*attr) >= sizeof (struct pthread_attr));
+  iattr = (struct pthread_attr *) attr;
+
+  /* Catch invalid sizes.  */
+  if (stacksize < PTHREAD_STACK_MIN)
+    return EINVAL;
+
+  iattr->stacksize = stacksize;
+
+  return 0;
+}
+strong_alias (__pthread_attr_setstacksize, pthread_attr_setstacksize)
diff --git a/nptl/pthread_barrier_destroy.c b/nptl/pthread_barrier_destroy.c
new file mode 100644 (file)
index 0000000..492b294
--- /dev/null
@@ -0,0 +1,44 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include "pthreadP.h"
+#include <lowlevellock.h>
+
+
+int
+pthread_barrier_destroy (barrier)
+     pthread_barrier_t *barrier;
+{
+  struct pthread_barrier *ibarrier;
+  int result = EBUSY;
+
+  ibarrier = (struct pthread_barrier *) barrier;
+
+  lll_lock (ibarrier->lock);
+
+  if (__builtin_expect (ibarrier->left == ibarrier->init_count, 1))
+    /* The barrier is not used anymore.  */
+    result = 0;
+  else
+    /* Still used, return with an error.  */
+    lll_unlock (ibarrier->lock);
+
+  return result;
+}
diff --git a/nptl/pthread_barrier_init.c b/nptl/pthread_barrier_init.c
new file mode 100644 (file)
index 0000000..19e82fa
--- /dev/null
@@ -0,0 +1,57 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include "pthreadP.h"
+#include <lowlevellock.h>
+
+
+int
+pthread_barrier_init (barrier, attr, count)
+     pthread_barrier_t *barrier;
+     const pthread_barrierattr_t *attr;
+     unsigned int count;
+{
+  struct pthread_barrier *ibarrier;
+
+  if (__builtin_expect (count == 0, 0))
+    return EINVAL;
+
+  if (attr != NULL)
+    {
+      struct pthread_barrierattr *iattr;
+
+      iattr = (struct pthread_barrierattr *) attr;
+
+      if (iattr->pshared != PTHREAD_PROCESS_PRIVATE
+         && __builtin_expect (iattr->pshared != PTHREAD_PROCESS_SHARED, 0))
+       /* Invalid attribute.  */
+       return EINVAL;
+    }
+
+  ibarrier = (struct pthread_barrier *) barrier;
+
+  /* Initialize the individual fields.  */
+  ibarrier->lock = LLL_LOCK_INITIALIZER;
+  ibarrier->left = count;
+  ibarrier->init_count = count;
+  ibarrier->curr_event = 0;
+
+  return 0;
+}
diff --git a/nptl/pthread_barrierattr_destroy.c b/nptl/pthread_barrierattr_destroy.c
new file mode 100644 (file)
index 0000000..f947daf
--- /dev/null
@@ -0,0 +1,30 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+
+
+int
+pthread_barrierattr_destroy (attr)
+     pthread_barrierattr_t *attr;
+{
+  /* Nothing to do.  */
+
+  return 0;
+}
diff --git a/nptl/pthread_barrierattr_getpshared.c b/nptl/pthread_barrierattr_getpshared.c
new file mode 100644 (file)
index 0000000..246c888
--- /dev/null
@@ -0,0 +1,31 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+
+
+int
+pthread_barrierattr_getpshared (attr, pshared)
+     const pthread_barrierattr_t *attr;
+     int *pshared;
+{
+  *pshared = ((const struct pthread_barrierattr *) attr)->pshared;
+
+  return 0;
+}
diff --git a/nptl/pthread_barrierattr_init.c b/nptl/pthread_barrierattr_init.c
new file mode 100644 (file)
index 0000000..a0be952
--- /dev/null
@@ -0,0 +1,30 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+
+
+int
+pthread_barrierattr_init (attr)
+     pthread_barrierattr_t *attr;
+{
+  ((struct pthread_barrierattr *) attr)->pshared = PTHREAD_PROCESS_PRIVATE;
+
+  return 0;
+}
diff --git a/nptl/pthread_barrierattr_setpshared.c b/nptl/pthread_barrierattr_setpshared.c
new file mode 100644 (file)
index 0000000..b69f23e
--- /dev/null
@@ -0,0 +1,40 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include "pthreadP.h"
+
+
+int
+pthread_barrierattr_setpshared (attr, pshared)
+     pthread_barrierattr_t *attr;
+     int pshared;
+{
+  struct pthread_barrierattr *iattr;
+
+  if (pshared != PTHREAD_PROCESS_PRIVATE
+      && __builtin_expect (pshared != PTHREAD_PROCESS_SHARED, 0))
+    return EINVAL;
+
+  iattr = (struct pthread_barrierattr *) attr;
+
+  iattr->pshared = pshared;
+
+  return 0;
+}
diff --git a/nptl/pthread_cancel.c b/nptl/pthread_cancel.c
new file mode 100644 (file)
index 0000000..1fa20e0
--- /dev/null
@@ -0,0 +1,62 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <signal.h>
+#include "pthreadP.h"
+#include "atomic.h"
+
+
+int
+pthread_cancel (th)
+     pthread_t th;
+{
+  volatile struct pthread *pd = (volatile struct pthread *) th;
+
+  while (1)
+    {
+      int oldval = pd->cancelhandling;
+      int newval = oldval | CANCELED_BITMASK;
+
+      /* Avoid doing unnecessary work.  The atomic operation can
+        potentially be expensive if the bug has to be locked and
+        remote cache lines have to be invalidated.  */
+      if (oldval == newval)
+       break;
+
+      /* If the cancellation is handled asynchronously just send a
+        signal.  We avoid this if possible since it's more
+        expensive.  */
+      if (CANCEL_ENABLED_AND_CANCELED_AND_ASYNCHRONOUS (newval))
+       {
+         /* The cancellation handler will take care of marking the
+            thread as canceled.  */
+         pthread_kill (th, SIGCANCEL);
+
+         break;
+       }
+
+      /* Mark the thread as canceled.  This has to be done
+        atomically since other bits could be modified as well.  */
+      if (atomic_compare_and_exchange_acq (&pd->cancelhandling, newval,
+                                          oldval) == 0)
+       break;
+    }
+
+  return 0;
+}
diff --git a/nptl/pthread_clock_gettime.c b/nptl/pthread_clock_gettime.c
new file mode 100644 (file)
index 0000000..0e6f67b
--- /dev/null
@@ -0,0 +1,46 @@
+/* Copyright (C) 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General 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 <stdlib.h>
+#include <time.h>
+#include <libc-internal.h>
+#include "pthreadP.h"
+
+
+#if HP_TIMING_AVAIL
+int
+__pthread_clock_gettime (hp_timing_t freq, struct timespec *tp)
+{
+  hp_timing_t tsc;
+
+  /* Get the current counter.  */
+  HP_TIMING_NOW (tsc);
+
+  /* Compute the offset since the start time of the process.  */
+  tsc -= THREAD_GETMEM (THREAD_SELF, 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/nptl/pthread_clock_settime.c b/nptl/pthread_clock_settime.c
new file mode 100644 (file)
index 0000000..ef6dc18
--- /dev/null
@@ -0,0 +1,32 @@
+/* Copyright (C) 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General 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 <stdlib.h>
+#include <time.h>
+#include <libc-internal.h>
+#include "pthreadP.h"
+
+
+#if HP_TIMING_AVAIL
+void
+__pthread_clock_settime (hp_timing_t offset)
+{
+  /* Compute the offset since the start time of the process.  */
+  THREAD_SETMEM (THREAD_SELF, cpuclock_offset, offset);
+}
+#endif
diff --git a/nptl/pthread_cond_broadcast.c b/nptl/pthread_cond_broadcast.c
new file mode 100644 (file)
index 0000000..20cc39f
--- /dev/null
@@ -0,0 +1,30 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+
+
+int
+pthread_cond_broadcast (cond)
+     pthread_cond_t *cond;
+{
+  lll_cond_broadcast (cond);
+
+  return 0;
+}
diff --git a/nptl/pthread_cond_destroy.c b/nptl/pthread_cond_destroy.c
new file mode 100644 (file)
index 0000000..05299fc
--- /dev/null
@@ -0,0 +1,29 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include "pthreadP.h"
+
+
+int
+pthread_cond_destroy (cond)
+     pthread_cond_t *cond;
+{
+  return 0;
+}
diff --git a/nptl/pthread_cond_init.c b/nptl/pthread_cond_init.c
new file mode 100644 (file)
index 0000000..309fc6a
--- /dev/null
@@ -0,0 +1,37 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+
+
+int
+pthread_cond_init (cond, cond_attr)
+     pthread_cond_t *cond;
+     const pthread_condattr_t *cond_attr;
+{
+  /* Note that we don't need the COND-ATTR.  It contains only the
+     PSHARED flag which is unimportant here since conditional
+     variables are always usable in multiple processes.  */
+
+  cond->__data.__lock = LLL_MUTEX_LOCK_INITIALIZER;
+  cond->__data.__nr_wakers = 0;
+  cond->__data.__nr_sleepers = 0;
+
+  return 0;
+}
diff --git a/nptl/pthread_cond_signal.c b/nptl/pthread_cond_signal.c
new file mode 100644 (file)
index 0000000..58573d3
--- /dev/null
@@ -0,0 +1,30 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+
+
+int
+pthread_cond_signal (cond)
+     pthread_cond_t *cond;
+{
+  lll_cond_wake (cond);
+
+  return 0;
+}
diff --git a/nptl/pthread_cond_timedwait.c b/nptl/pthread_cond_timedwait.c
new file mode 100644 (file)
index 0000000..792dbdc
--- /dev/null
@@ -0,0 +1,71 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+#include <lowlevellock.h>
+
+
+int
+pthread_cond_timedwait (cond, mutex, abstime)
+     pthread_cond_t *cond;
+     pthread_mutex_t *mutex;
+     const struct timespec *abstime;
+{
+  int result;
+  int err;
+
+  /* This function is a cancellation point.  Test before we potentially
+     go to sleep.  */
+  CANCELLATION_P (THREAD_SELF);
+
+  /* Make sure the condition is modified atomically.  */
+  lll_mutex_lock (cond->__data.__lock);
+
+  /* Release the mutex.  This might fail.  */
+  err = pthread_mutex_unlock (mutex);
+  if (__builtin_expect (err != 0, 0))
+    {
+      lll_mutex_unlock (cond->__data.__lock);
+      return err;
+    }
+
+  /* One more tread waiting.  */
+  ++cond->__data.__nr_sleepers;
+
+  /* The actual conditional variable implementation.  */
+  result = lll_cond_timedwait (cond, abstime);
+
+  if (--cond->__data.__nr_sleepers == 0)
+    /* Forget about the current wakeups now that they are done.  */
+    cond->__data.__nr_wakers = 0;
+
+  /* Lose the condvar lock.  */
+  lll_mutex_unlock (cond->__data.__lock);
+
+  /* We have to get the mutex before returning.  */
+  err = pthread_mutex_lock (mutex);
+  if (err != 0)
+    /* XXX Unconditionally overwrite the result of the wait?  */
+    result = err;
+
+  /* Cancellation handling.  */
+  CANCELLATION_P (THREAD_SELF);
+
+  return result;
+}
diff --git a/nptl/pthread_cond_wait.c b/nptl/pthread_cond_wait.c
new file mode 100644 (file)
index 0000000..37c5ffe
--- /dev/null
@@ -0,0 +1,66 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+#include <lowlevellock.h>
+
+
+int
+pthread_cond_wait (cond, mutex)
+     pthread_cond_t *cond;
+     pthread_mutex_t *mutex;
+{
+  int err;
+
+  /* This function is a cancellation point.  Test before we potentially
+     go to sleep.  */
+  CANCELLATION_P (THREAD_SELF);
+
+  /* Make sure the condition is modified atomically.  */
+  lll_mutex_lock (cond->__data.__lock);
+
+  /* Release the mutex.  This might fail.  */
+  err = pthread_mutex_unlock (mutex);
+  if (__builtin_expect (err != 0, 0))
+    {
+      lll_mutex_unlock (cond->__data.__lock);
+      return err;
+    }
+
+  /* One more tread waiting.  */
+  ++cond->__data.__nr_sleepers;
+
+  /* The actual conditional variable implementation.  */
+  lll_cond_wait (cond);
+
+  if (--cond->__data.__nr_sleepers == 0)
+    /* Forget about the current wakeups now that they are done.  */
+    cond->__data.__nr_wakers = 0;
+
+  /* Lose the condvar lock.  */
+  lll_mutex_unlock (cond->__data.__lock);
+
+  /* We have to get the mutex before returning.  */
+  err = pthread_mutex_lock (mutex);
+
+  /* Cancellation handling.  */
+  CANCELLATION_P (THREAD_SELF);
+
+  return err;
+}
diff --git a/nptl/pthread_condattr_destroy.c b/nptl/pthread_condattr_destroy.c
new file mode 100644 (file)
index 0000000..4bce09d
--- /dev/null
@@ -0,0 +1,29 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+
+
+int
+pthread_condattr_destroy (attr)
+     pthread_condattr_t *attr;
+{
+  /* Nothing to be done.  */
+  return 0;
+}
diff --git a/nptl/pthread_condattr_getpshared.c b/nptl/pthread_condattr_getpshared.c
new file mode 100644 (file)
index 0000000..7b91f14
--- /dev/null
@@ -0,0 +1,31 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+
+
+int
+pthread_condattr_getpshared (attr, pshared)
+     const pthread_condattr_t *attr;
+     int *pshared;
+{
+  *pshared = ((const struct pthread_condattr *) attr)->pshared;
+
+  return 0;
+}
diff --git a/nptl/pthread_condattr_init.c b/nptl/pthread_condattr_init.c
new file mode 100644 (file)
index 0000000..4e8aaf9
--- /dev/null
@@ -0,0 +1,31 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <string.h>
+#include "pthreadP.h"
+
+
+int
+pthread_condattr_init (attr)
+     pthread_condattr_t *attr;
+{
+  memset (attr, '\0', sizeof (*attr));
+
+  return 0;
+}
diff --git a/nptl/pthread_condattr_setpshared.c b/nptl/pthread_condattr_setpshared.c
new file mode 100644 (file)
index 0000000..518c1c7
--- /dev/null
@@ -0,0 +1,30 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+
+int
+pthread_condattr_setpshared (attr, pshared)
+     pthread_condattr_t *attr;
+     int pshared;
+{
+  ((struct pthread_condattr *) attr)->pshared = pshared;
+
+  return 0;
+}
diff --git a/nptl/pthread_create.c b/nptl/pthread_create.c
new file mode 100644 (file)
index 0000000..451a9b3
--- /dev/null
@@ -0,0 +1,419 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include "pthreadP.h"
+#include <hp-timing.h>
+#include <ldsodefs.h>
+
+#include <shlib-compat.h>
+
+
+/* Local function to start thread and handle cleanup.  */
+static int start_thread (void *arg);
+/* Similar version used when debugging.  */
+static int start_thread_debug (void *arg);
+
+
+/* Nozero if debugging mode is enabled.  */
+int __pthread_debug;
+
+/* Globally enabled events.  */
+td_thr_events_t __nptl_threads_events attribute_hidden;
+
+/* Pointer to descriptor with the last event.  */
+struct pthread *__nptl_last_event attribute_hidden;
+
+
+/* Code to allocate and deallocate a stack.  */
+#define DEFINE_DEALLOC
+#include "allocatestack.c"
+
+/* Code to create the thread.  */
+#include "createthread.c"
+
+
+/* Table of the key information.  */
+struct pthread_key_struct __pthread_keys[PTHREAD_KEYS_MAX];
+
+
+struct pthread *
+__find_in_stack_list (pd)
+     struct pthread *pd;
+{
+  list_t *entry;
+  struct pthread *result = NULL;
+
+  lll_lock (stack_cache_lock);
+
+  list_for_each (entry, &stack_used)
+    {
+      struct pthread *curp;
+
+      curp = list_entry (entry, struct pthread, header.data.list);
+      if (curp == pd)
+       {
+         result = curp;
+         break;
+       }
+    }
+
+  if (result == NULL)
+    list_for_each (entry, &__stack_user)
+      {
+       struct pthread *curp;
+
+       curp = list_entry (entry, struct pthread, header.data.list);
+       if (curp == pd)
+         {
+           result = curp;
+           break;
+         }
+      }
+
+  lll_unlock (stack_cache_lock);
+
+  return result;
+}
+
+
+/* Deallocate POSIX thread-local-storage.  */
+static void
+deallocate_tsd (struct pthread *pd)
+{
+  /* Maybe no data was ever allocated.  This happens often so we have
+     a flag for this.  */
+  if (pd->specific_used)
+    {
+      size_t round;
+      bool found_nonzero;
+
+      for (round = 0, found_nonzero = true;
+          found_nonzero && round < PTHREAD_DESTRUCTOR_ITERATIONS;
+          ++round)
+       {
+         size_t cnt;
+         size_t idx;
+
+         for (cnt = idx = 0; cnt < PTHREAD_KEY_1STLEVEL_SIZE; ++cnt)
+           if (pd->specific[cnt] != NULL)
+             {
+               size_t inner;
+
+               for (inner = 0; inner < PTHREAD_KEY_2NDLEVEL_SIZE;
+                    ++inner, ++idx)
+                 {
+                   void *data = pd->specific[cnt][inner].data;
+
+                   if (data != NULL
+                       /* Make sure the data corresponds to a valid
+                          key.  This test fails if the key was
+                          deallocated and also if it was
+                          re-allocated.  It is the user's
+                          responsibility to free the memory in this
+                          case.  */
+                       && (pd->specific[cnt][inner].seq
+                           == __pthread_keys[idx].seq)
+                       /* It is not necessary to register a destructor
+                          function.  */
+                       && __pthread_keys[idx].destr != NULL)
+                     {
+                       pd->specific[cnt][inner].data = NULL;
+                       __pthread_keys[idx].destr (data);
+                       found_nonzero = true;
+                     }
+                 }
+
+               if (cnt != 0)
+                 {
+                   /* The first block is allocated as part of the thread
+                      descriptor.  */
+                   free (pd->specific[cnt]);
+                   pd->specific[cnt] = NULL;
+                 }
+               else
+                 /* Clear the memory of the first block for reuse.  */
+                 memset (pd->specific[0], '\0',
+                         sizeof (struct pthread_key_data));
+             }
+           else
+             idx += PTHREAD_KEY_1STLEVEL_SIZE;
+       }
+
+      pd->specific_used = false;
+    }
+}
+
+
+/* Deallocate a thread's stack after optionally making sure the thread
+   descriptor is still valid.  */
+void
+__free_tcb (struct pthread *pd)
+{
+  /* The thread is exiting now.  */
+  if (atomic_bit_test_set (&pd->cancelhandling, TERMINATED_BIT) == 0)
+    {
+      /* Remove the descriptor from the list.  */
+      if (DEBUGGING_P && __find_in_stack_list (pd) == NULL)
+       /* Something is really wrong.  The descriptor for a still
+          running thread is gone.  */
+       abort ();
+
+      /* Run the destructor for the thread-local data.  */
+      deallocate_tsd (pd);
+
+      /* Queue the stack memory block for reuse and exit the process.  The
+        kernel will signal via writing to the address returned by
+        QUEUE-STACK when the stack is available.  */
+      __deallocate_stack (pd);
+    }
+}
+
+
+static int
+start_thread (void *arg)
+{
+  struct pthread *pd = (struct pthread *) arg;
+
+#if HP_TIMING_AVAIL
+  /* Remember the time when the thread was started.  */
+  hp_timing_t now;
+  HP_TIMING_NOW (now);
+  THREAD_SETMEM (pd, cpuclock_offset, now);
+#endif
+
+  /* This is where the try/finally block should be created.  For
+     compilers without that support we do use setjmp.  */
+  if (setjmp (pd->cancelbuf) == 0)
+    {
+      /* Run the code the user provided.  */
+      pd->result = pd->start_routine (pd->arg);
+    }
+
+
+  /* Report the death of the thread if this is wanted.  */
+  if (__builtin_expect (pd->report_events, 0))
+    {
+      /* See whether TD_DEATH is in any of the mask.  */
+      const int idx = __td_eventword (TD_DEATH);
+      const uint32_t mask = __td_eventmask (TD_DEATH);
+
+      if ((mask & (__nptl_threads_events.event_bits[idx]
+                  | pd->eventbuf.eventmask.event_bits[idx])) != 0)
+       {
+         /* Yep, we have to signal the death.  Add the descriptor to
+            the list but only if it is not already on it.  */
+         if (pd->nextevent == NULL)
+           {
+             pd->eventbuf.eventnum = TD_DEATH;
+             pd->eventbuf.eventdata = pd;
+
+             do
+               pd->nextevent = __nptl_last_event;
+             while (atomic_compare_and_exchange_acq (__nptl_last_event, pd,
+                                                     pd->nextevent) != 0);
+           }
+
+         /* Now call the function to signal the event.  */
+         __nptl_death_event ();
+       }
+    }
+
+
+  /* The thread is exiting now.  */
+  atomic_bit_set (&pd->cancelhandling, EXITING_BIT);
+
+  /* If the thread is detached free the TCB.  */
+  if (IS_DETACHED (pd))
+    /* Free the TCB.  */
+    __free_tcb (pd);
+
+  /* We cannot call '_exit' here.  '_exit' will terminate the process.
+
+     The 'exit' implementation in the kernel will signal when the
+     process is really dead since 'clone' got passed the CLONE_CLEARTID
+     flag.  The 'tid' field in the TCB will be set to zero.
+
+     The exit code is zero since in case all threads exit by calling
+     'pthread_exit' the exit status must be 0 (zero).  */
+  __exit_thread_inline (0);
+
+  /* NOTREACHED */
+  return 0;
+}
+
+
+/* Just list start_thread but we do some more things needed for a run
+   with a debugger attached.  */
+static int
+start_thread_debug (void *arg)
+{
+  struct pthread *pd = (struct pthread *) arg;
+
+  /* Get the lock the parent locked to force synchronization.  */
+  lll_lock (pd->lock);
+  /* And give it up right away.  */
+  lll_unlock (pd->lock);
+
+  /* Now do the actual startup.  */
+  return start_thread (arg);
+}
+
+
+/* Default thread attributes for the case when the user does not
+   provide any.  */
+static const struct pthread_attr default_attr =
+  {
+    /* Just some value > 0 which gets rounded to the nearest page size.  */
+    .guardsize = 1,
+  };
+
+
+int
+__pthread_create_2_1 (newthread, attr, start_routine, arg)
+     pthread_t *newthread;
+     const pthread_attr_t *attr;
+     void *(*start_routine) (void *);
+     void *arg;
+{
+  STACK_VARIABLES;
+  const struct pthread_attr *iattr;
+  struct pthread *pd;
+  int err;
+
+  iattr = (struct pthread_attr *) attr;
+  if (iattr == NULL)
+    /* Is this the best idea?  On NUMA machines this could mean
+       accessing far-away memory.  */
+    iattr = &default_attr;
+
+  err = ALLOCATE_STACK (iattr, &pd);
+  if (err != 0)
+    /* Something went wrong.  Maybe a parameter of the attributes is
+       invalid or we could not allocate memory.  */
+    return err;
+
+
+  /* Initialize the TCB.  All initializations with zero should be
+     performed in 'get_cached_stack'.  This way we avoid doing this if
+     the stack freshly allocated with 'mmap'.  */
+
+  /* Reference to the TCB itself.  */
+  pd->header.data.self = pd;
+
+#ifdef TLS_TCB_AT_TP
+  /* Self-reference.  */
+  pd->header.data.tcb = pd;
+#endif
+
+  /* Store the address of the start routine and the parameter.  Since
+     we do not start the function directly the stillborn thread will
+     get the information from its thread descriptor.  */
+  pd->start_routine = start_routine;
+  pd->arg = arg;
+
+  /* Copy the thread attribute flags.  */
+  pd->flags = iattr->flags;
+
+  /* Initialize the field for the ID of the thread which is waiting
+     for us.  This is a self-reference in case the thread is created
+     detached.  */
+  pd->joinid = iattr->flags & ATTR_FLAG_DETACHSTATE ? pd : NULL;
+
+  /* The debug events are inherited from the parent.  */
+  pd->eventbuf = THREAD_SELF->eventbuf;
+
+
+  /* Determine scheduling parameters for the thread.
+     XXX How to determine whether scheduling handling is needed?  */
+  if (0 && attr != NULL)
+    {
+      if (iattr->flags & ATTR_FLAG_NOTINHERITSCHED)
+       {
+         /* Use the scheduling parameters the user provided.  */
+         pd->schedpolicy = iattr->schedpolicy;
+         memcpy (&pd->schedparam, &iattr->schedparam,
+                 sizeof (struct sched_param));
+       }
+      else
+       {
+         /* Just store the scheduling attributes of the parent.  */
+         pd->schedpolicy = __sched_getscheduler (0);
+         __sched_getparam (0, &pd->schedparam);
+       }
+    }
+
+  /* Pass the descriptor to the caller.  */
+  *newthread = (pthread_t) pd;
+
+  /* Start the thread.  */
+  err = create_thread (pd, STACK_VARIABLES_ARGS);
+  if (err != 0)
+    {
+      /* Something went wrong.  Free the resources.  */
+      __deallocate_stack (pd);
+      return err;
+    }
+
+  return 0;
+}
+versioned_symbol (libpthread, __pthread_create_2_1, pthread_create, GLIBC_2_1);
+
+
+#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_1)
+int
+__pthread_create_2_0 (newthread, attr, start_routine, arg)
+     pthread_t *newthread;
+     const pthread_attr_t *attr;
+     void *(*start_routine) (void *);
+     void *arg;
+{
+  /* The ATTR attribute is not really of type `pthread_attr_t *'.  It has
+     the old size and access to the new members might crash the program.
+     We convert the struct now.  */
+  struct pthread_attr new_attr;
+
+  if (attr != NULL)
+    {
+      struct pthread_attr *iattr = (struct pthread_attr *) attr;
+      size_t ps = __getpagesize ();
+
+      /* Copy values from the user-provided attributes.  */
+      new_attr.schedparam = iattr->schedparam;
+      new_attr.schedpolicy = iattr->schedpolicy;
+      new_attr.flags = iattr->flags;
+
+      /* Fill in default values for the fields not present in the old
+        implementation.  */
+      new_attr.guardsize = ps;
+      new_attr.stackaddr = NULL;
+      new_attr.stacksize = 0;
+
+      /* We will pass this value on to the real implementation.  */
+      attr = (pthread_attr_t *) &new_attr;
+    }
+
+  return __pthread_create_2_1 (newthread, attr, start_routine, arg);
+}
+compat_symbol (libpthread, __pthread_create_2_0, pthread_create,
+              GLIBC_2_0);
+#endif
diff --git a/nptl/pthread_detach.c b/nptl/pthread_detach.c
new file mode 100644 (file)
index 0000000..2ba9f49
--- /dev/null
@@ -0,0 +1,51 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include "pthreadP.h"
+#include <atomic.h>
+
+
+int
+pthread_detach (th)
+     pthread_t th;
+{
+  struct pthread *pd = (struct pthread *) th;
+  int result = 0;
+
+  /* Mark the thread as detached.  */
+  if (atomic_compare_and_exchange_acq (&pd->joinid, pd, NULL) != 0)
+    {
+      /* There are two possibilities here.  First, the thread might
+        already be detached.  In this case we return EINVAL.
+        Otherwise there might already be a waiter.  The standard does
+        not mention what happens in this case.  */
+      if (IS_DETACHED (pd))
+       result = EINVAL;
+    }
+  else
+    /* Check whether the thread terminated meanwhile.  In this case we
+       will just free the TCB.  */
+    if ((pd->cancelhandling & EXITING_BITMASK) != 0)
+      /* Note that the code in __free_tcb makes sure each thread
+        control block is freed only once.  */
+      __free_tcb (pd);
+
+  return result;
+}
diff --git a/nptl/pthread_equal.c b/nptl/pthread_equal.c
new file mode 100644 (file)
index 0000000..f2ef2b4
--- /dev/null
@@ -0,0 +1,29 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+
+
+int
+pthread_equal (thread1, thread2)
+     pthread_t thread1;
+     pthread_t thread2;
+{
+  return thread1 == thread2;
+}
diff --git a/nptl/pthread_exit.c b/nptl/pthread_exit.c
new file mode 100644 (file)
index 0000000..5822a2e
--- /dev/null
@@ -0,0 +1,31 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stdlib.h>
+#include "pthreadP.h"
+
+
+void
+pthread_exit (value)
+     void *value;
+{
+  THREAD_SETMEM (THREAD_SELF, result, value);
+
+  __do_cancel (CURRENT_STACK_FRAME);
+}
diff --git a/nptl/pthread_getattr_np.c b/nptl/pthread_getattr_np.c
new file mode 100644 (file)
index 0000000..4e58043
--- /dev/null
@@ -0,0 +1,65 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <string.h>
+#include "pthreadP.h"
+#include <lowlevellock.h>
+
+
+int
+pthread_getattr_np (thread_id, attr)
+     pthread_t thread_id;
+     pthread_attr_t *attr;
+{
+  struct pthread *thread = (struct pthread *) thread_id;
+  struct pthread_attr *iattr = (struct pthread_attr *) attr;
+
+  /* We have to handle cancellation in the following code since we are
+     locking another threads desriptor.  */
+  pthread_cleanup_push ((void (*) (void *)) lll_unlock_wake_cb, &thread->lock);
+
+  lll_lock (thread->lock);
+
+  /* The thread library is responsible for keeping the values in the
+     thread desriptor up-to-date in case the user changes them.  */
+  memcpy (&iattr->schedparam, &thread->schedparam,
+         sizeof (struct sched_param));
+  iattr->schedpolicy = thread->schedpolicy;
+
+  /* Clear the flags work.  */
+  iattr->flags = thread->flags;
+
+  /* The thread might be detached by now.  */
+  if (IS_DETACHED (thread))
+    iattr->flags |= ATTR_FLAG_DETACHSTATE;
+
+  /* This is the guardsize after adjusting it.  */
+  iattr->guardsize = thread->guardsize;
+
+  /* The sizes are subject to alignment.  */
+  iattr->stacksize = thread->stackblock_size;
+  iattr->stackaddr = (char *) thread->stackblock + iattr->stacksize;
+  iattr->flags |= ATTR_FLAG_STACKADDR;
+
+  lll_unlock (thread->lock);
+
+  pthread_cleanup_pop (0);
+
+  return 0;
+}
diff --git a/nptl/pthread_getconcurrency.c b/nptl/pthread_getconcurrency.c
new file mode 100644 (file)
index 0000000..52c0c7c
--- /dev/null
@@ -0,0 +1,27 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+
+
+int
+pthread_getconcurrency (void)
+{
+  return __concurrency_level;
+}
diff --git a/nptl/pthread_getschedparam.c b/nptl/pthread_getschedparam.c
new file mode 100644 (file)
index 0000000..3e23ffa
--- /dev/null
@@ -0,0 +1,51 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <string.h>
+#include "pthreadP.h"
+#include <lowlevellock.h>
+
+
+int
+pthread_getschedparam (thread_id, policy, param)
+     pthread_t thread_id;
+     int *policy;
+     struct sched_param *param;
+{
+  struct pthread *thread = (struct pthread *) thread_id;
+
+  /* We have to handle cancellation in the following code since we are
+     locking another threads desriptor.  */
+  pthread_cleanup_push ((void (*) (void *)) lll_unlock_wake_cb, &thread->lock);
+
+  lll_lock (thread->lock);
+
+  /* The library is responsible for maintaining the values at all
+     times.  If the user uses a interface other than
+     pthread_setschedparam to modify the scheduler setting it is not
+     the library's problem.  */
+  *policy = thread->schedpolicy;
+  memcpy (param, &thread->schedparam, sizeof (struct sched_param));
+
+  lll_unlock (thread->lock);
+
+  pthread_cleanup_pop (0);
+
+  return 0;
+}
diff --git a/nptl/pthread_getspecific.c b/nptl/pthread_getspecific.c
new file mode 100644 (file)
index 0000000..9e3b694
--- /dev/null
@@ -0,0 +1,68 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stdlib.h>
+#include "pthreadP.h"
+
+
+void *
+__pthread_getspecific (key)
+     pthread_key_t key;
+{
+  struct pthread_key_data *data;
+
+  /* Special case access to the first 2nd-level block.  This is the
+     usual case.  */
+  if (__builtin_expect (key < PTHREAD_KEY_2NDLEVEL_SIZE, 1))
+    data = &THREAD_SELF->specific_1stblock[key];
+  else
+    {
+      /* Verify the key is sane.  */
+      if (key >= PTHREAD_KEYS_MAX)
+       /* Not valid.  */
+       return NULL;
+
+      unsigned int idx1st = key / PTHREAD_KEY_2NDLEVEL_SIZE;
+      unsigned int idx2nd = key % PTHREAD_KEY_2NDLEVEL_SIZE;
+
+      /* If the sequence number doesn't match or the key cannot be defined
+        for this thread since the second level array is not allocated
+        return NULL, too.  */
+      struct pthread_key_data *level2 = THREAD_GETMEM_NC (THREAD_SELF,
+                                                         specific[idx1st]);
+      if (level2 == NULL)
+       /* Not allocated, therefore no data.  */
+       return NULL;
+
+      /* There is data.  */
+      data = &level2[idx2nd];
+    }
+
+  void *result = data->data;
+  if (result != NULL)
+    {
+      uintptr_t seq = data->seq;
+
+      if (seq != __pthread_keys[key].seq)
+       result = data = NULL;
+    }
+
+  return result;
+}
+strong_alias (__pthread_getspecific, pthread_getspecific)
diff --git a/nptl/pthread_join.c b/nptl/pthread_join.c
new file mode 100644 (file)
index 0000000..a223a7d
--- /dev/null
@@ -0,0 +1,100 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <stdlib.h>
+
+#include "atomic.h"
+#include "pthreadP.h"
+
+
+static void
+cleanup (void *arg)
+{
+  *(void **) arg = NULL;
+}
+
+
+int
+pthread_join (threadid, thread_return)
+     pthread_t threadid;
+     void **thread_return;
+{
+  struct pthread *self;
+  struct pthread *pd = (struct pthread *) threadid;
+
+  /* Make sure the descriptor is valid.  */
+  if (DEBUGGING_P && __find_in_stack_list (pd) == NULL)
+    /* Not a valid thread handle.  */
+    return ESRCH;
+
+  /* Is the thread joinable?.  */
+  if (IS_DETACHED (pd))
+    /* We cannot wait for the thread.  */
+    return EINVAL;
+
+  self = THREAD_SELF;
+  if (pd == self || self->joinid == pd)
+    /* This is a deadlock situation.  The threads are waiting for each
+       other to finish.  Note that this is a "may" error.  To be 100%
+       sure we catch this error we would have to lock the data
+       structures but it is not necessary.  In the unlikely case that
+       two threads are really caught in this situation they will
+       deadlock.  It is the programmer's problem to figure this
+       out.  */
+    return EDEADLK;
+
+  /* Wait for the thread to finish.  If it is already locked something
+     is wrong.  There can only be one waiter.  */
+  if (atomic_compare_and_exchange_acq (&pd->joinid, self, NULL) != 0)
+    /* There is already somebody waiting for the thread.  */
+    return EINVAL;
+
+
+  /* During the wait we change to asynchronous cancellation.  If we
+     are cancelled the thread we are waiting for must be marked as
+     un-wait-ed for again.  */
+  pthread_cleanup_push (cleanup, &pd->joinid);
+
+  /* Switch to asynchronous cancellation.  */
+  int oldtype;
+  CANCEL_ASYNC (oldtype);
+
+
+  /* Wait for the child.  */
+  lll_wait_tid (pd->tid);
+
+
+  /* Restore cancellation mode.  */
+  CANCEL_RESET (oldtype);
+
+  /* Remove the handler.  */
+  pthread_cleanup_pop (0);
+
+
+  /* Store the return value if the caller is interested.  */
+  if (thread_return != NULL)
+    *thread_return = pd->result;
+
+
+  /* Free the TCB.  */
+  __free_tcb (pd);
+
+  return 0;
+}
diff --git a/nptl/pthread_key_create.c b/nptl/pthread_key_create.c
new file mode 100644 (file)
index 0000000..7a073f2
--- /dev/null
@@ -0,0 +1,68 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include "pthreadP.h"
+
+
+/* Internal mutex for __pthread_kyes table handling.  */
+lll_lock_t __pthread_keys_lock = LLL_LOCK_INITIALIZER;
+
+
+/* For debugging purposes put the maximum number of keys in a variable.  */
+const int __linuxthreads_pthread_keys_max = PTHREAD_KEYS_MAX;
+const int __linuxthreads_pthread_key_2ndlevel_size = PTHREAD_KEY_2NDLEVEL_SIZE;
+
+
+int
+__pthread_key_create (key, destr)
+     pthread_key_t *key;
+     void (*destr) (void *);
+{
+  int result = EAGAIN;
+  size_t cnt;
+
+  lll_lock (__pthread_keys_lock);
+
+  /* Find a slot in __pthread_kyes which is unused.  */
+  for (cnt = 0; cnt < PTHREAD_KEYS_MAX; ++cnt)
+    if (KEY_UNUSED (__pthread_keys[cnt].seq)
+       && KEY_USABLE (__pthread_keys[cnt].seq))
+      {
+       /* We found an unused slot.  */
+       ++__pthread_keys[cnt].seq;
+
+       /* Remember the destructor.  */
+       __pthread_keys[cnt].destr = destr;
+
+       /* Return the key to the caller.  */
+       *key = cnt;
+
+       /* The call succeeded.  */
+       result = 0;
+
+       /* We found a key and can stop now.  */
+       break;
+      }
+
+  lll_unlock (__pthread_keys_lock);
+
+  return result;
+}
+strong_alias (__pthread_key_create, pthread_key_create)
diff --git a/nptl/pthread_key_delete.c b/nptl/pthread_key_delete.c
new file mode 100644 (file)
index 0000000..a0145f8
--- /dev/null
@@ -0,0 +1,43 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include "pthreadP.h"
+#include <atomic.h>
+
+
+int
+pthread_key_delete (key)
+     pthread_key_t key;
+{
+  int result = EINVAL;
+
+  if (__builtin_expect (key < PTHREAD_KEYS_MAX, 1))
+    {
+      unsigned int seq = __pthread_keys[key].seq;
+
+      if (__builtin_expect (! KEY_UNUSED (seq), 1)
+         && atomic_compare_and_exchange_acq (&__pthread_keys[key].seq,
+                                             seq + 1, seq) == 0)
+       /* We deleted a valid key.  */
+       result = 0;
+    }
+
+  return result;
+}
diff --git a/nptl/pthread_kill_other_threads.c b/nptl/pthread_kill_other_threads.c
new file mode 100644 (file)
index 0000000..a446423
--- /dev/null
@@ -0,0 +1,37 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <shlib-compat.h>
+
+
+#ifdef SHARED
+/* This function does not serve a useful purpose in the thread library
+   implementation anymore.  It used to be necessary when then kernel
+   could not shut down "processes" but this is not the case anymore.
+
+   We could theoretically provide an equivalent implementation but
+   this is not necessary since the kernel already does a much better
+   job than we ever could.  */
+void
+__pthread_kill_other_threads_np (void)
+{
+}
+compat_symbol (libpthread, __pthread_kill_other_threads_np,
+              pthread_kill_other_threads_np, GLIBC_2_0);
+#endif
diff --git a/nptl/pthread_mutex_destroy.c b/nptl/pthread_mutex_destroy.c
new file mode 100644 (file)
index 0000000..e3dba37
--- /dev/null
@@ -0,0 +1,29 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+
+
+int
+__pthread_mutex_destroy (mutex)
+     pthread_mutex_t *mutex;
+{
+  return 0;
+}
+strong_alias (__pthread_mutex_destroy, pthread_mutex_destroy)
diff --git a/nptl/pthread_mutex_init.c b/nptl/pthread_mutex_init.c
new file mode 100644 (file)
index 0000000..3a783d7
--- /dev/null
@@ -0,0 +1,55 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <assert.h>
+#include <string.h>
+#include "pthreadP.h"
+
+
+static const struct pthread_mutexattr default_attr =
+  {
+    /* Default is a normal mutex, not shared between processes.  */
+    .mutexkind = PTHREAD_MUTEX_NORMAL
+  };
+
+
+int
+__pthread_mutex_init (mutex, mutexattr)
+     pthread_mutex_t *mutex;
+     const pthread_mutexattr_t *mutexattr;
+{
+  const struct pthread_mutexattr *imutexattr;
+
+  assert (sizeof (pthread_mutex_t) <= __SIZEOF_PTHREAD_MUTEX_T);
+
+  imutexattr = (const struct pthread_mutexattr *) mutexattr ?: &default_attr;
+
+  /* Clear the whole variable.  */
+  memset (mutex, '\0', __SIZEOF_PTHREAD_MUTEX_T);
+
+  /* Copy the values from the attribute.  */
+  mutex->__data.__kind = imutexattr->mutexkind & ~0x80000000;
+
+  /* Default values: mutex not used yet.  */
+  // mutex->__count = 0;       already done by memset
+  // mutex->__owner = NULL;    already done by memset
+
+  return 0;
+}
+strong_alias (__pthread_mutex_init, pthread_mutex_init)
diff --git a/nptl/pthread_mutex_lock.c b/nptl/pthread_mutex_lock.c
new file mode 100644 (file)
index 0000000..8398003
--- /dev/null
@@ -0,0 +1,77 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include "pthreadP.h"
+#include <lowlevellock.h>
+
+
+int
+__pthread_mutex_lock (mutex)
+     pthread_mutex_t *mutex;
+{
+  struct pthread *pd = THREAD_SELF;
+
+  switch (__builtin_expect (mutex->__data.__kind, PTHREAD_MUTEX_TIMED_NP))
+    {
+      /* Recursive mutex.  */
+    case PTHREAD_MUTEX_RECURSIVE_NP:
+      /* Check whether we already hold the mutex.  */
+      if (mutex->__data.__owner == pd)
+       {
+         /* Just bump the counter.  */
+         if (__builtin_expect (mutex->__data.__count + 1 == 0, 0))
+           /* Overflow of the counter.  */
+           return EAGAIN;
+
+         ++mutex->__data.__count;
+       }
+      else
+       {
+         /* We have to get the mutex.  */
+         lll_mutex_lock (mutex->__data.__lock);
+
+         /* Record the ownership.  */
+         mutex->__data.__owner = pd;
+         mutex->__data.__count = 1;
+       }
+      break;
+
+      /* Error checking mutex.  */
+    case PTHREAD_MUTEX_ERRORCHECK_NP:
+      /* Check whether we already hold the mutex.  */
+      if (mutex->__data.__owner == pd)
+       return EDEADLK;
+
+      /* FALLTHROUGH */
+
+    default:
+      /* Correct code cannot set any other type.  */
+    case PTHREAD_MUTEX_TIMED_NP:
+    case PTHREAD_MUTEX_ADAPTIVE_NP:
+      /* Normal mutex.  */
+      lll_mutex_lock (mutex->__data.__lock);
+      /* Record the ownership.  */
+      mutex->__data.__owner = pd;
+      break;
+    }
+
+  return 0;
+}
+strong_alias (__pthread_mutex_lock, pthread_mutex_lock)
diff --git a/nptl/pthread_mutex_timedlock.c b/nptl/pthread_mutex_timedlock.c
new file mode 100644 (file)
index 0000000..a63b204
--- /dev/null
@@ -0,0 +1,88 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include "pthreadP.h"
+#include <lowlevellock.h>
+
+
+int
+pthread_mutex_timedlock (mutex, abstime)
+     pthread_mutex_t *mutex;
+     const struct timespec *abstime;
+{
+  struct pthread *pd = THREAD_SELF;
+  int result = 0;
+
+  /* We must not check ABSTIME here.  If the thread does not block
+     abstime must not be checked for a valid value.  */
+
+  switch (mutex->__data.__kind)
+    {
+      /* Recursive mutex.  */
+    case PTHREAD_MUTEX_RECURSIVE_NP:
+      /* Check whether we already hold the mutex.  */
+      if (mutex->__data.__owner == pd)
+       {
+         /* Just bump the counter.  */
+         if (__builtin_expect (mutex->__data.__count + 1 == 0, 0))
+           /* Overflow of the counter.  */
+           return EAGAIN;
+
+         ++mutex->__data.__count;
+
+         goto out;
+       }
+      else
+       {
+         /* We have to get the mutex.  */
+         result = lll_mutex_timedlock (mutex->__data.__lock, abstime);
+
+         if (result != 0)
+           goto out;
+
+         /* Only locked once so far.  */
+         mutex->__data.__count = 1;
+       }
+      break;
+
+      /* Error checking mutex.  */
+    case PTHREAD_MUTEX_ERRORCHECK_NP:
+      /* Check whether we already hold the mutex.  */
+      if (mutex->__data.__owner == pd)
+       return EDEADLK;
+
+      /* FALLTHROUGH */
+
+    default:
+      /* Correct code cannot set any other type.  */
+    case PTHREAD_MUTEX_TIMED_NP:
+    case PTHREAD_MUTEX_ADAPTIVE_NP:
+      /* Normal mutex.  */
+      result = lll_mutex_timedlock (mutex->__data.__lock, abstime);
+      break;
+    }
+
+  if (result == 0)
+    /* Record the ownership.  */
+    mutex->__data.__owner = pd;
+
+ out:
+  return result;
+}
diff --git a/nptl/pthread_mutex_trylock.c b/nptl/pthread_mutex_trylock.c
new file mode 100644 (file)
index 0000000..aae5067
--- /dev/null
@@ -0,0 +1,70 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include "pthreadP.h"
+#include <lowlevellock.h>
+
+
+int
+__pthread_mutex_trylock (mutex)
+     pthread_mutex_t *mutex;
+{
+  struct pthread *pd = THREAD_SELF;
+
+  switch (__builtin_expect (mutex->__data.__kind, PTHREAD_MUTEX_TIMED_NP))
+    {
+      /* Recursive mutex.  */
+    case PTHREAD_MUTEX_RECURSIVE_NP:
+      /* Check whether we already hold the mutex.  */
+      if (mutex->__data.__owner == pd)
+       {
+         /* Just bump the counter.  */
+         ++mutex->__data.__count;
+         return 0;
+       }
+
+      if (lll_mutex_trylock (mutex->__data.__lock) == 0)
+       {
+         /* Record the ownership.  */
+         mutex->__data.__owner = pd;
+         mutex->__data.__count = 1;
+         return 0;
+       }
+      break;
+
+    case PTHREAD_MUTEX_ERRORCHECK_NP:
+      /* Error checking mutex.  We do not check for deadlocks.  */
+    default:
+      /* Correct code cannot set any other type.  */
+    case PTHREAD_MUTEX_TIMED_NP:
+    case PTHREAD_MUTEX_ADAPTIVE_NP:
+      /* Normal mutex.  */
+      if (lll_mutex_trylock (mutex->__data.__lock) == 0)
+       {
+         /* Record the ownership.  */
+         mutex->__data.__owner = pd;
+
+         return 0;
+       }
+    }
+
+  return EBUSY;
+}
+strong_alias (__pthread_mutex_trylock, pthread_mutex_trylock)
diff --git a/nptl/pthread_mutex_unlock.c b/nptl/pthread_mutex_unlock.c
new file mode 100644 (file)
index 0000000..be510cb
--- /dev/null
@@ -0,0 +1,65 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include "pthreadP.h"
+#include <lowlevellock.h>
+
+
+int
+__pthread_mutex_unlock (mutex)
+     pthread_mutex_t *mutex;
+{
+  switch (__builtin_expect (mutex->__data.__kind, PTHREAD_MUTEX_TIMED_NP))
+    {
+    case PTHREAD_MUTEX_RECURSIVE_NP:
+      /* Recursive mutex.  */
+      if (mutex->__data.__owner != THREAD_SELF)
+       return EPERM;
+
+      if (--mutex->__data.__count != 0)
+       /* We still hold the mutex.  */
+       return 0;
+
+      mutex->__data.__owner = NULL;
+      break;
+
+    case PTHREAD_MUTEX_ERRORCHECK_NP:
+      /* Error checking mutex.  */
+      if (mutex->__data.__owner != THREAD_SELF
+         || ! lll_mutex_islocked (mutex->__data.__lock))
+       return EPERM;
+
+      mutex->__data.__owner = NULL;
+      break;
+
+    default:
+      /* Correct code cannot set any other type.  */
+    case PTHREAD_MUTEX_TIMED_NP:
+    case PTHREAD_MUTEX_ADAPTIVE_NP:
+      /* Normal mutex.  Nothing special to do.  */
+      break;
+    }
+
+  /* Unlock.  */
+  lll_mutex_unlock (mutex->__data.__lock);
+
+  return 0;
+}
+strong_alias (__pthread_mutex_unlock, pthread_mutex_unlock)
diff --git a/nptl/pthread_mutexattr_destroy.c b/nptl/pthread_mutexattr_destroy.c
new file mode 100644 (file)
index 0000000..eab27d3
--- /dev/null
@@ -0,0 +1,29 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthreadP.h>
+
+
+int
+__pthread_mutexattr_destroy (attr)
+     pthread_mutexattr_t *attr;
+{
+  return 0;
+}
+strong_alias (__pthread_mutexattr_destroy, pthread_mutexattr_destroy)
diff --git a/nptl/pthread_mutexattr_getpshared.c b/nptl/pthread_mutexattr_getpshared.c
new file mode 100644 (file)
index 0000000..1769463
--- /dev/null
@@ -0,0 +1,38 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthreadP.h>
+
+
+int
+pthread_mutexattr_getpshared (attr, pshared)
+     const pthread_mutexattr_t *attr;
+     int *pshared;
+{
+  const struct pthread_mutexattr *iattr;
+
+  iattr = (const struct pthread_mutexattr *) attr;
+
+  /* We use bit 31 to single whether the mutex is going to be
+     process-shared or not.  */
+  *pshared = ((iattr->mutexkind & 0x80000000) != 0
+             ? PTHREAD_PROCESS_SHARED : PTHREAD_PROCESS_PRIVATE);
+
+  return 0;
+}
diff --git a/nptl/pthread_mutexattr_gettype.c b/nptl/pthread_mutexattr_gettype.c
new file mode 100644 (file)
index 0000000..82a938d
--- /dev/null
@@ -0,0 +1,38 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthreadP.h>
+
+
+int
+pthread_mutexattr_gettype (attr, kind)
+     const pthread_mutexattr_t *attr;
+     int *kind;
+{
+  const struct pthread_mutexattr *iattr;
+
+  iattr = (const struct pthread_mutexattr *) attr;
+
+  /* We use bit 31 to single whether the mutex is going to be
+     process-shared or not.  */
+  *kind = iattr->mutexkind & ~0x80000000;
+
+  return 0;
+}
+weak_alias (pthread_mutexattr_gettype, pthread_mutexattr_getkind_np)
diff --git a/nptl/pthread_mutexattr_init.c b/nptl/pthread_mutexattr_init.c
new file mode 100644 (file)
index 0000000..3270d53
--- /dev/null
@@ -0,0 +1,38 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <string.h>
+#include <pthreadP.h>
+
+
+int
+__pthread_mutexattr_init (attr)
+     pthread_mutexattr_t *attr;
+{
+  if (sizeof (struct pthread_mutexattr) != sizeof (pthread_mutexattr_t))
+    memset (attr, '\0', sizeof (*attr));
+
+  /* We use bit 31 to single whether the mutex is going to be
+     process-shared or not.  By default it is zero, i.e., the mutex is
+     not process-shared.  */
+  ((struct pthread_mutexattr *) attr)->mutexkind = PTHREAD_MUTEX_NORMAL;
+
+  return 0;
+}
+strong_alias (__pthread_mutexattr_init, pthread_mutexattr_init)
diff --git a/nptl/pthread_mutexattr_setpshared.c b/nptl/pthread_mutexattr_setpshared.c
new file mode 100644 (file)
index 0000000..9bc5c26
--- /dev/null
@@ -0,0 +1,45 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthreadP.h>
+
+
+int
+pthread_mutexattr_setpshared (attr, pshared)
+     pthread_mutexattr_t *attr;
+     int pshared;
+{
+  struct pthread_mutexattr *iattr;
+
+  if (pshared != PTHREAD_PROCESS_PRIVATE
+      && __builtin_expect (pshared != PTHREAD_PROCESS_SHARED, 0))
+    return EINVAL;
+
+  iattr = (struct pthread_mutexattr *) attr;
+
+  /* We use bit 31 to single whether the mutex is going to be
+     process-shared or not.  */
+  if (pshared == PTHREAD_PROCESS_PRIVATE)
+    iattr->mutexkind &= ~0x80000000;
+  else
+    iattr->mutexkind |= 0x80000000;
+
+  return 0;
+}
diff --git a/nptl/pthread_mutexattr_settype.c b/nptl/pthread_mutexattr_settype.c
new file mode 100644 (file)
index 0000000..54021b3
--- /dev/null
@@ -0,0 +1,43 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthreadP.h>
+
+
+int
+__pthread_mutexattr_settype (attr, kind)
+     pthread_mutexattr_t *attr;
+     int kind;
+{
+  struct pthread_mutexattr *iattr;
+
+  if (kind < PTHREAD_MUTEX_NORMAL || kind > PTHREAD_MUTEX_ADAPTIVE_NP)
+    return EINVAL;
+
+  iattr = (struct pthread_mutexattr *) attr;
+
+  /* We use bit 31 to single whether the mutex is going to be
+     process-shared or not.  */
+  iattr->mutexkind = (iattr->mutexkind & 0x80000000) | kind;
+
+  return 0;
+}
+weak_alias (__pthread_mutexattr_settype, pthread_mutexattr_setkind_np)
+strong_alias (__pthread_mutexattr_settype, pthread_mutexattr_settype)
diff --git a/nptl/pthread_rwlock_destroy.c b/nptl/pthread_rwlock_destroy.c
new file mode 100644 (file)
index 0000000..28fd24b
--- /dev/null
@@ -0,0 +1,30 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+
+
+int
+__pthread_rwlock_destroy (rwlock)
+     pthread_rwlock_t *rwlock;
+{
+  /* Nothing to be done.  For now.  */
+  return 0;
+}
+strong_alias (__pthread_rwlock_destroy, pthread_rwlock_destroy)
diff --git a/nptl/pthread_rwlock_init.c b/nptl/pthread_rwlock_init.c
new file mode 100644 (file)
index 0000000..f664dd8
--- /dev/null
@@ -0,0 +1,51 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+
+
+static const struct pthread_rwlockattr default_attr =
+  {
+    .lockkind = PTHREAD_RWLOCK_DEFAULT_NP,
+    .pshared = PTHREAD_PROCESS_PRIVATE
+  };
+
+
+int
+__pthread_rwlock_init (rwlock, attr)
+     pthread_rwlock_t *rwlock;
+     const pthread_rwlockattr_t *attr;
+{
+  const struct pthread_rwlockattr *iattr;
+
+  iattr = ((const struct pthread_rwlockattr *) attr) ?: &default_attr;
+
+  rwlock->__data.__lock = 0;
+  rwlock->__data.__flags
+    = iattr->lockkind == PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP;
+  rwlock->__data.__nr_readers = 0;
+  rwlock->__data.__writer = 0;
+  rwlock->__data.__readers_wakeup = 0;
+  rwlock->__data.__writer_wakeup = 0;
+  rwlock->__data.__nr_readers_queued = 0;
+  rwlock->__data.__nr_writers_queued = 0;
+
+  return 0;
+}
+strong_alias (__pthread_rwlock_init, pthread_rwlock_init)
diff --git a/nptl/pthread_rwlock_tryrdlock.c b/nptl/pthread_rwlock_tryrdlock.c
new file mode 100644 (file)
index 0000000..446af05
--- /dev/null
@@ -0,0 +1,50 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include "pthreadP.h"
+#include <lowlevellock.h>
+
+
+int
+__pthread_rwlock_tryrdlock (rwlock)
+     pthread_rwlock_t *rwlock;
+{
+  int result = EBUSY;
+
+  lll_mutex_lock (rwlock->__data.__lock);
+
+  if (rwlock->__data.__writer == 0
+      && (rwlock->__data.__nr_writers_queued == 0
+         || rwlock->__data.__flags == 0))
+    {
+      if (__builtin_expect (++rwlock->__data.__nr_readers == 0, 0))
+       {
+         --rwlock->__data.__nr_readers;
+         result = EAGAIN;
+       }
+      else
+       result = 0;
+    }
+
+  lll_mutex_unlock (rwlock->__data.__lock);
+
+  return result;
+}
+strong_alias (__pthread_rwlock_tryrdlock, pthread_rwlock_tryrdlock)
diff --git a/nptl/pthread_rwlock_trywrlock.c b/nptl/pthread_rwlock_trywrlock.c
new file mode 100644 (file)
index 0000000..32fcbba
--- /dev/null
@@ -0,0 +1,43 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include "pthreadP.h"
+#include <lowlevellock.h>
+
+
+int
+__pthread_rwlock_trywrlock (rwlock)
+     pthread_rwlock_t *rwlock;
+{
+  int result = EBUSY;
+
+  lll_mutex_lock (rwlock->__data.__lock);
+
+  if (rwlock->__data.__writer == 0 && rwlock->__data.__nr_readers == 0)
+    {
+      rwlock->__data.__writer = (pthread_t) THREAD_SELF;
+      result = 0;
+    }
+
+  lll_mutex_unlock (rwlock->__data.__lock);
+
+  return result;
+}
+strong_alias (__pthread_rwlock_trywrlock, pthread_rwlock_trywrlock)
diff --git a/nptl/pthread_rwlockattr_destroy.c b/nptl/pthread_rwlockattr_destroy.c
new file mode 100644 (file)
index 0000000..4f0c2c4
--- /dev/null
@@ -0,0 +1,30 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+
+
+int
+pthread_rwlockattr_destroy (attr)
+     pthread_rwlockattr_t *attr;
+{
+  /* Nothing to do.  For now.  */
+
+  return 0;
+}
diff --git a/nptl/pthread_rwlockattr_getkind_np.c b/nptl/pthread_rwlockattr_getkind_np.c
new file mode 100644 (file)
index 0000000..aad9468
--- /dev/null
@@ -0,0 +1,31 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+
+
+int
+pthread_rwlockattr_getkind_np (attr, pref)
+     const pthread_rwlockattr_t *attr;
+     int *pref;
+{
+  *pref = ((const struct pthread_rwlockattr *) attr)->lockkind;
+
+  return 0;
+}
diff --git a/nptl/pthread_rwlockattr_getpshared.c b/nptl/pthread_rwlockattr_getpshared.c
new file mode 100644 (file)
index 0000000..3a77683
--- /dev/null
@@ -0,0 +1,31 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+
+
+int
+pthread_rwlockattr_getpshared (attr, pshared)
+     const pthread_rwlockattr_t *attr;
+     int *pshared;
+{
+  *pshared = ((const struct pthread_rwlockattr *) attr)->pshared;
+
+  return 0;
+}
diff --git a/nptl/pthread_rwlockattr_init.c b/nptl/pthread_rwlockattr_init.c
new file mode 100644 (file)
index 0000000..b299534
--- /dev/null
@@ -0,0 +1,35 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+
+
+int
+pthread_rwlockattr_init (attr)
+     pthread_rwlockattr_t *attr;
+{
+  struct pthread_rwlockattr *iattr;
+
+  iattr = (struct pthread_rwlockattr *) attr;
+
+  iattr->lockkind = PTHREAD_RWLOCK_DEFAULT_NP;
+  iattr->pshared = PTHREAD_PROCESS_PRIVATE;
+
+  return 0;
+}
diff --git a/nptl/pthread_rwlockattr_setkind_np.c b/nptl/pthread_rwlockattr_setkind_np.c
new file mode 100644 (file)
index 0000000..0311f1b
--- /dev/null
@@ -0,0 +1,41 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include "pthreadP.h"
+
+
+int
+pthread_rwlockattr_setkind_np (attr, pref)
+     pthread_rwlockattr_t *attr;
+     int pref;
+{
+  struct pthread_rwlockattr *iattr;
+
+  if (pref != PTHREAD_RWLOCK_PREFER_READER_NP
+      && pref != PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP
+      && __builtin_expect  (pref != PTHREAD_RWLOCK_PREFER_WRITER_NP, 0))
+    return EINVAL;
+
+  iattr = (struct pthread_rwlockattr *) attr;
+
+  iattr->lockkind = pref;
+
+  return 0;
+}
diff --git a/nptl/pthread_rwlockattr_setpshared.c b/nptl/pthread_rwlockattr_setpshared.c
new file mode 100644 (file)
index 0000000..9438d29
--- /dev/null
@@ -0,0 +1,40 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include "pthreadP.h"
+
+
+int
+pthread_rwlockattr_setpshared (attr, pshared)
+     pthread_rwlockattr_t *attr;
+     int pshared;
+{
+  struct pthread_rwlockattr *iattr;
+
+  if (pshared != PTHREAD_PROCESS_SHARED
+      && __builtin_expect (pshared != PTHREAD_PROCESS_PRIVATE, 0))
+    return EINVAL;
+
+  iattr = (struct pthread_rwlockattr *) attr;
+
+  iattr->pshared = pshared;
+
+  return 0;
+}
diff --git a/nptl/pthread_self.c b/nptl/pthread_self.c
new file mode 100644 (file)
index 0000000..ad231cd
--- /dev/null
@@ -0,0 +1,28 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+#include <tls.h>
+
+
+pthread_t
+pthread_self (void)
+{
+  return (pthread_t) THREAD_SELF;
+}
diff --git a/nptl/pthread_setcancelstate.c b/nptl/pthread_setcancelstate.c
new file mode 100644 (file)
index 0000000..3f36df8
--- /dev/null
@@ -0,0 +1,68 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include "pthreadP.h"
+#include <atomic.h>
+
+
+int
+pthread_setcancelstate (state, oldstate)
+     int state;
+     int *oldstate;
+{
+  volatile struct pthread *self;
+
+  if (state < PTHREAD_CANCEL_ENABLE || state > PTHREAD_CANCEL_DISABLE)
+    return EINVAL;
+
+  self = THREAD_SELF;
+
+  while (1)
+    {
+      int oldval = THREAD_GETMEM (self, cancelhandling);
+      int newval = (state == PTHREAD_CANCEL_DISABLE
+                   ? oldval | CANCELSTATE_BITMASK
+                   : oldval & ~CANCELSTATE_BITMASK);
+
+      /* Store the old value.  */
+      if (oldstate != NULL)
+       *oldstate = ((oldval & CANCELSTATE_BITMASK)
+                    ? PTHREAD_CANCEL_DISABLE : PTHREAD_CANCEL_ENABLE);
+
+      /* Avoid doing unnecessary work.  The atomic operation can
+        potentially be expensive if the bug has to be locked and
+        remote cache lines have to be invalidated.  */
+      if (oldval == newval)
+       break;
+
+      /* Update the cancel handling word.  This has to be done
+        atomically since other bits could be modified as well.  */
+      if (atomic_compare_and_exchange_acq (&self->cancelhandling, newval,
+                                          oldval) == 0)
+       {
+         if (CANCEL_ENABLED_AND_CANCELED_AND_ASYNCHRONOUS (newval))
+           __do_cancel (CURRENT_STACK_FRAME);
+
+         break;
+       }
+    }
+
+  return 0;
+}
diff --git a/nptl/pthread_setcanceltype.c b/nptl/pthread_setcanceltype.c
new file mode 100644 (file)
index 0000000..8f84634
--- /dev/null
@@ -0,0 +1,71 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include "pthreadP.h"
+#include <atomic.h>
+
+
+int
+pthread_setcanceltype (type, oldtype)
+     int type;
+     int *oldtype;
+{
+  volatile struct pthread *self;
+
+  if (type < PTHREAD_CANCEL_DEFERRED || type > PTHREAD_CANCEL_ASYNCHRONOUS)
+    return EINVAL;
+
+  self = THREAD_SELF;
+
+  while (1)
+    {
+      int oldval = THREAD_GETMEM (self, cancelhandling);
+      int newval = (type == PTHREAD_CANCEL_ASYNCHRONOUS
+                   ? oldval | CANCELTYPE_BITMASK
+                   : oldval & ~CANCELTYPE_BITMASK);
+
+      /* Store the old value.  */
+      if (oldtype != NULL)
+       *oldtype = ((oldval & CANCELTYPE_BITMASK)
+                   ? PTHREAD_CANCEL_ASYNCHRONOUS : PTHREAD_CANCEL_DEFERRED);
+
+      /* Avoid doing unnecessary work.  The atomic operation can
+        potentially be expensive if the bug has to be locked and
+        remote cache lines have to be invalidated.  */
+      if (oldval == newval)
+       break;
+
+      /* Update the cancel handling word.  This has to be done
+        atomically since other bits could be modified as well.  */
+      if (atomic_compare_and_exchange_acq (&self->cancelhandling, newval,
+                                          oldval) == 0)
+       {
+         if (CANCEL_ENABLED_AND_CANCELED_AND_ASYNCHRONOUS (newval))
+           {
+             THREAD_SETMEM (self, result, PTHREAD_CANCELED);
+             __do_cancel (CURRENT_STACK_FRAME);
+           }
+
+         break;
+       }
+    }
+
+  return 0;
+}
diff --git a/nptl/pthread_setconcurrency.c b/nptl/pthread_setconcurrency.c
new file mode 100644 (file)
index 0000000..f65a174
--- /dev/null
@@ -0,0 +1,37 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+
+
+/* Global definition.  Needed in pthread_getconcurrency as well.  */
+int __concurrency_level;
+
+
+int
+pthread_setconcurrency (level)
+     int level;
+{
+  __concurrency_level = level;
+
+  /* XXX For ports which actually need to handle the concurrency level
+     some more code is probably needed here.  */
+
+  return 0;
+}
diff --git a/nptl/pthread_setschedparam.c b/nptl/pthread_setschedparam.c
new file mode 100644 (file)
index 0000000..f662405
--- /dev/null
@@ -0,0 +1,59 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <sched.h>
+#include <string.h>
+#include "pthreadP.h"
+#include <lowlevellock.h>
+
+
+int
+pthread_setschedparam (thread_id, policy, param)
+     pthread_t thread_id;
+     int policy;
+     const struct sched_param *param;
+{
+  struct pthread *thread = (struct pthread *) thread_id;
+  int result = 0;
+
+  /* We have to handle cancellation in the following code since we are
+     locking another threads desriptor.  */
+  pthread_cleanup_push ((void (*) (void *)) lll_unlock_wake_cb, &thread->lock);
+
+  lll_lock (thread->lock);
+
+  /* Try to set the scheduler information.  */
+  if (__builtin_expect (__sched_setscheduler (thread->tid, policy,
+                                             param) == -1, 0))
+    result = errno;
+  else
+    {
+      /* We succeeded changing the kernel information.  Reflect this
+        change in the thread descriptor.  */
+      thread->schedpolicy = policy;
+      memcpy (&thread->schedparam, param, sizeof (struct sched_param));
+    }
+
+  lll_unlock (thread->lock);
+
+  pthread_cleanup_pop (0);
+
+  return result;
+}
diff --git a/nptl/pthread_setspecific.c b/nptl/pthread_setspecific.c
new file mode 100644 (file)
index 0000000..5af6cae
--- /dev/null
@@ -0,0 +1,91 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <stdlib.h>
+#include "pthreadP.h"
+
+
+int
+__pthread_setspecific (key, value)
+     pthread_key_t key;
+     const void *value;
+{
+  struct pthread *self;
+  unsigned int idx1st;
+  unsigned int idx2nd;
+  struct pthread_key_data *level2;
+  unsigned int seq;
+
+  self = THREAD_SELF;
+
+  /* Special case access to the first 2nd-level block.  This is the
+     usual case.  */
+  if (__builtin_expect (key < PTHREAD_KEY_2NDLEVEL_SIZE, 1))
+    {
+      /* Verify the key is sane.  */
+      if (KEY_UNUSED ((seq = __pthread_keys[key].seq)))
+       /* Not valid.  */
+       return EINVAL;
+
+      level2 = &self->specific_1stblock[key];
+    }
+  else
+    {
+      if (KEY_UNUSED ((seq = __pthread_keys[key].seq))
+         || key >= PTHREAD_KEYS_MAX)
+       /* Not valid.  */
+       return EINVAL;
+
+      idx1st = key / PTHREAD_KEY_2NDLEVEL_SIZE;
+      idx2nd = key % PTHREAD_KEY_2NDLEVEL_SIZE;
+
+      /* This is the second level array.  Allocate it if necessary.  */
+      level2 = THREAD_GETMEM_NC (self, specific[idx1st]);
+      if (level2 == NULL)
+       {
+         if (value == NULL)
+           /* We don't have to do anything.  The value would in any case
+              be NULL.  We can save the memory allocation.  */
+           return 0;
+
+         level2
+           = (struct pthread_key_data *) calloc (PTHREAD_KEY_2NDLEVEL_SIZE,
+                                                 sizeof (*level2));
+         if (level2 == NULL)
+           return ENOMEM;
+
+         THREAD_SETMEM_NC (self, specific[idx1st], level2);
+       }
+
+      /* Pointer to the right array element.  */
+      level2 = &level2[idx2nd];
+    }
+
+  /* Store the data and the sequence number so that we can recognize
+     stale data.  */
+  level2->seq = seq;
+  level2->data = (void *) value;
+
+  /* Remember that we stored at least one set of data.  */
+  THREAD_SETMEM (self, specific_used, true);
+
+  return 0;
+}
+strong_alias (__pthread_setspecific, pthread_setspecific)
diff --git a/nptl/pthread_testcancel.c b/nptl/pthread_testcancel.c
new file mode 100644 (file)
index 0000000..e9b17b4
--- /dev/null
@@ -0,0 +1,28 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stdlib.h>
+#include "pthreadP.h"
+
+
+void
+pthread_testcancel (void)
+{
+  CANCELLATION_P (THREAD_SELF);
+}
diff --git a/nptl/pthread_timedjoin.c b/nptl/pthread_timedjoin.c
new file mode 100644 (file)
index 0000000..d3f4a28
--- /dev/null
@@ -0,0 +1,108 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <stdlib.h>
+
+#include "atomic.h"
+#include "pthreadP.h"
+
+
+static void
+cleanup (void *arg)
+{
+  *(void **) arg = NULL;
+}
+
+
+int
+pthread_timedjoin_np (threadid, thread_return, abstime)
+     pthread_t threadid;
+     void **thread_return;
+     const struct timespec *abstime;
+{
+  struct pthread *self;
+  struct pthread *pd = (struct pthread *) threadid;
+  int result;
+
+  /* Make sure the descriptor is valid.  */
+  if (DEBUGGING_P && __find_in_stack_list (pd) == NULL)
+    /* Not a valid thread handle.  */
+    return ESRCH;
+
+  /* Is the thread joinable?.  */
+  if (IS_DETACHED (pd))
+    /* We cannot wait for the thread.  */
+    return EINVAL;
+
+  self = THREAD_SELF;
+  if (pd == self || self->joinid == pd)
+    /* This is a deadlock situation.  The threads are waiting for each
+       other to finish.  Note that this is a "may" error.  To be 100%
+       sure we catch this error we would have to lock the data
+       structures but it is not necessary.  In the unlikely case that
+       two threads are really caught in this situation they will
+       deadlock.  It is the programmer's problem to figure this
+       out.  */
+    return EDEADLK;
+
+  /* Wait for the thread to finish.  If it is already locked something
+     is wrong.  There can only be one waiter.  */
+  if (atomic_compare_and_exchange_acq (&pd->joinid, self, NULL) != 0)
+    /* There is already somebody waiting for the thread.  */
+    return EINVAL;
+
+
+  /* During the wait we change to asynchronous cancellation.  If we
+     are cancelled the thread we are waiting for must be marked as
+     un-wait-ed for again.  */
+  pthread_cleanup_push (cleanup, &pd->joinid);
+
+  /* Switch to asynchronous cancellation.  */
+  int oldtype;
+  CANCEL_ASYNC (oldtype);
+
+
+  /* Wait for the child.  */
+  result = lll_timedwait_tid (pd->tid, abstime);
+
+
+  /* Restore cancellation mode.  */
+  CANCEL_RESET (oldtype);
+
+  /* Remove the handler.  */
+  pthread_cleanup_pop (0);
+
+
+  /* We might have timed out.  */
+  if (result == 0)
+    {
+      /* Store the return value if the caller is interested.  */
+      if (thread_return != NULL)
+       *thread_return = pd->result;
+
+
+      /* Free the TCB.  */
+      __free_tcb (pd);
+    }
+  else
+    pd->joinid = NULL;
+
+  return result;
+}
diff --git a/nptl/pthread_tryjoin.c b/nptl/pthread_tryjoin.c
new file mode 100644 (file)
index 0000000..88d2e8b
--- /dev/null
@@ -0,0 +1,75 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <stdlib.h>
+
+#include "atomic.h"
+#include "pthreadP.h"
+
+
+int
+pthread_tryjoin_np (threadid, thread_return)
+     pthread_t threadid;
+     void **thread_return;
+{
+  struct pthread *self;
+  struct pthread *pd = (struct pthread *) threadid;
+
+  /* Make sure the descriptor is valid.  */
+  if (DEBUGGING_P && __find_in_stack_list (pd) == NULL)
+    /* Not a valid thread handle.  */
+    return ESRCH;
+
+  /* Is the thread joinable?.  */
+  if (IS_DETACHED (pd))
+    /* We cannot wait for the thread.  */
+    return EINVAL;
+
+  self = THREAD_SELF;
+  if (pd == self || self->joinid == pd)
+    /* This is a deadlock situation.  The threads are waiting for each
+       other to finish.  Note that this is a "may" error.  To be 100%
+       sure we catch this error we would have to lock the data
+       structures but it is not necessary.  In the unlikely case that
+       two threads are really caught in this situation they will
+       deadlock.  It is the programmer's problem to figure this
+       out.  */
+    return EDEADLK;
+
+  /* Return right away if the thread hasn't terminated yet.  */
+  if (pd->tid != 0)
+    return EBUSY;
+
+  /* Wait for the thread to finish.  If it is already locked something
+     is wrong.  There can only be one waiter.  */
+  if (atomic_compare_and_exchange_acq (&pd->joinid, self, NULL) != 0)
+    /* There is already somebody waiting for the thread.  */
+    return EINVAL;
+
+  /* Store the return value if the caller is interested.  */
+  if (thread_return != NULL)
+    *thread_return = pd->result;
+
+
+  /* Free the TCB.  */
+  __free_tcb (pd);
+
+  return 0;
+}
diff --git a/nptl/res.c b/nptl/res.c
new file mode 100644 (file)
index 0000000..6c2e3f8
--- /dev/null
@@ -0,0 +1,33 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <features.h>
+#include <resolv.h>
+#undef _res
+
+#include <tls.h>
+
+/* With __thread support, this per-thread variable is used in all cases.  */
+extern __thread struct __res_state _res;
+
+
+struct __res_state *
+__res_state (void)
+{
+  return &_res;
+}
diff --git a/nptl/sem_close.c b/nptl/sem_close.c
new file mode 100644 (file)
index 0000000..379565f
--- /dev/null
@@ -0,0 +1,29 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <semaphore.h>
+#include <sys/mman.h>
+
+
+int
+sem_close (sem)
+     sem_t *sem;
+{
+  return munmap (sem, sizeof (sem_t));
+}
diff --git a/nptl/sem_destroy.c b/nptl/sem_destroy.c
new file mode 100644 (file)
index 0000000..790a80e
--- /dev/null
@@ -0,0 +1,34 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <semaphore.h>
+#include <shlib-compat.h>
+#include "semaphoreP.h"
+
+
+int
+__new_sem_destroy (sem)
+     sem_t *sem;
+{
+  /* XXX Check for valid parameter.  */
+
+  /* Nothing to do.  */
+  return 0;
+}
+versioned_symbol (libpthread, __new_sem_destroy, sem_destroy, GLIBC_2_1);
diff --git a/nptl/sem_getvalue.c b/nptl/sem_getvalue.c
new file mode 100644 (file)
index 0000000..ee976c3
--- /dev/null
@@ -0,0 +1,38 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <semaphore.h>
+#include <shlib-compat.h>
+#include "semaphoreP.h"
+
+
+int
+__new_sem_getvalue (sem, sval)
+     sem_t *sem;
+     int *sval;
+{
+  struct sem *isem = (struct sem *) sem;
+
+  /* XXX Check for valid SEM parameter.  */
+
+  *sval = isem->count;
+
+  return 0;
+}
+versioned_symbol (libpthread, __new_sem_getvalue, sem_getvalue, GLIBC_2_1);
diff --git a/nptl/sem_init.c b/nptl/sem_init.c
new file mode 100644 (file)
index 0000000..c8b80ff
--- /dev/null
@@ -0,0 +1,51 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <semaphore.h>
+#include <lowlevellock.h>
+#include <shlib-compat.h>
+#include "semaphoreP.h"
+
+
+int
+__new_sem_init (sem, pshared, value)
+     sem_t *sem;
+     int pshared;
+     unsigned int value;
+{
+  /* Parameter sanity check.  */
+  if (__builtin_expect (value > SEM_VALUE_MAX, 0))
+    {
+      __set_errno (EINVAL);
+      return -1;
+    }
+
+  /* Map to the internal type.  */
+  struct sem *isem = (struct sem *) sem;
+
+  /* Use the value the user provided.  */
+  isem->count = value;
+
+  /* We can completely ignore the PSHARED parameter since inter-process
+     use needs no special preparation.  */
+
+  return 0;
+}
+versioned_symbol (libpthread, __new_sem_init, sem_init, GLIBC_2_1);
diff --git a/nptl/sem_open.c b/nptl/sem_open.c
new file mode 100644 (file)
index 0000000..6fc72f7
--- /dev/null
@@ -0,0 +1,258 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <mntent.h>
+#include <paths.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/statfs.h>
+#include <linux_fsinfo.h>
+#include "semaphoreP.h"
+
+
+
+/* Information about the mount point.  */
+struct mountpoint_info mountpoint attribute_hidden;
+
+/* This is the default mount point.  */
+static const char defaultmount[] = "/dev/shm";
+/* This is the default directory.  */
+static const char defaultdir[] = "/dev/shm/sem.";
+
+/* Protect the `mountpoint' variable above.  */
+pthread_once_t __namedsem_once attribute_hidden = PTHREAD_ONCE_INIT;
+
+
+/* Determine where the shmfs is mounted (if at all).  */
+void
+attribute_hidden
+__where_is_shmfs (void)
+{
+  char buf[512];
+  struct statfs f;
+  struct mntent resmem;
+  struct mntent *mp;
+  FILE *fp;
+
+  /* The canonical place is /dev/shm.  This is at least what the
+     documentation tells everybody to do.  */
+  if (__statfs (defaultmount, &f) == 0 && f.f_type == SHMFS_SUPER_MAGIC)
+    {
+      /* It is in the normal place.  */
+      mountpoint.dir = (char *) defaultdir;
+      mountpoint.dirlen = sizeof (defaultdir) - 1;
+
+      return;
+    }
+
+  /* OK, do it the hard way.  Look through the /proc/mounts file and if
+     this does not exist through /etc/fstab to find the mount point.  */
+  fp = __setmntent ("/proc/mounts", "r");
+  if (__builtin_expect (fp == NULL, 0))
+    {
+      fp = __setmntent (_PATH_MNTTAB, "r");
+      if (__builtin_expect (fp == NULL, 0))
+       /* There is nothing we can do.  Blind guesses are not helpful.  */
+       return;
+    }
+
+  /* Now read the entries.  */
+  while ((mp = __getmntent_r (fp, &resmem, buf, sizeof buf)) != NULL)
+    /* The original name is "shm" but this got changed in early Linux
+       2.4.x to "tmpfs".  */
+    if (strcmp (mp->mnt_type, "tmpfs") == 0
+       || strcmp (mp->mnt_type, "shm") == 0)
+      {
+       /* Found it.  There might be more than one place where the
+           filesystem is mounted but one is enough for us.  */
+       size_t namelen;
+
+       /* First make sure this really is the correct entry.  At least
+          some versions of the kernel give wrong information because
+          of the implicit mount of the shmfs for SysV IPC.  */
+       if (__statfs (mp->mnt_dir, &f) != 0 || f.f_type != SHMFS_SUPER_MAGIC)
+         continue;
+
+       namelen = strlen (mp->mnt_dir);
+
+       if (namelen == 0)
+         /* Hum, maybe some crippled entry.  Keep on searching.  */
+         continue;
+
+       mountpoint.dir = (char *) malloc (namelen + 4 + 2);
+       if (mountpoint.dir != NULL)
+         {
+           char *cp = __mempcpy (mountpoint.dir, mp->mnt_dir, namelen);
+           if (cp[-1] != '/')
+             *cp++ = '/';
+           cp = stpcpy (cp, "sem.");
+           mountpoint.dirlen = cp - mountpoint.dir;
+         }
+
+       break;
+      }
+
+  /* Close the stream.  */
+  __endmntent (fp);
+}
+
+
+sem_t *
+sem_open (const char *name, int oflag, ...)
+{
+  char *finalname;
+  size_t namelen;
+  sem_t *result;
+  int fd;
+
+  /* Determine where the shmfs is mounted.  */
+  pthread_once (&__namedsem_once, __where_is_shmfs);
+
+  /* If we don't know the mount points there is nothing we can do.  Ever.  */
+  if (mountpoint.dir == NULL)
+    {
+      __set_errno (ENOSYS);
+      return SEM_FAILED;
+    }
+
+  /* Construct the filename.  */
+  while (name[0] == '/')
+    ++name;
+
+  if (name[0] == '\0')
+    {
+      /* The name "/" is not supported.  */
+      __set_errno (EINVAL);
+      return SEM_FAILED;
+    }
+  namelen = strlen (name);
+
+  /* Create the name of the final file.  */
+  finalname = (char *) alloca (mountpoint.dirlen + namelen + 1);
+  __mempcpy (__mempcpy (finalname, mountpoint.dir, mountpoint.dirlen),
+            name, namelen + 1);
+
+  /* If the semaphore object has to exist simply open it.  */
+  if ((oflag & O_CREAT) == 0)
+    {
+      fd = open (finalname, oflag | O_NOFOLLOW);
+
+      if (fd == -1)
+       /* Return.  errno is already set.  */
+       return SEM_FAILED;
+
+      /* Map the sem_t structure from the file.  */
+      result = (sem_t *) mmap (NULL, sizeof (sem_t), PROT_READ | PROT_WRITE,
+                              MAP_SHARED, fd, 0);
+    }
+  else
+    {
+      /* We have to open a temporary file first since it must have the
+        correct form before we can start using it.  */
+      char *tmpfname;
+      mode_t mode;
+      unsigned int value;
+      va_list ap;
+
+      va_start (ap, oflag);
+
+      mode = va_arg (ap, mode_t);
+      value = va_arg (ap, unsigned int);
+
+      va_end (ap);
+
+      if (value > SEM_VALUE_MAX)
+       {
+         __set_errno (EINVAL);
+         return SEM_FAILED;
+       }
+
+      tmpfname = (char *) alloca (mountpoint.dirlen + 6 + 1);
+      strcpy (__mempcpy (tmpfname, mountpoint.dir, mountpoint.dirlen),
+             "XXXXXX");
+
+      fd = mkstemp (tmpfname);
+      if (fd == -1)
+       return SEM_FAILED;
+
+      /* Create the initial file content.  */
+      sem_t initsem;
+
+      struct sem *iinitsem = (struct sem *) &initsem;
+      iinitsem->count = value;
+
+      /* Initialize the remaining bytes as well.  */
+      memset ((char *) &initsem + sizeof (struct sem), '\0',
+             sizeof (sem_t) - sizeof (struct sem));
+
+      if (TEMP_FAILURE_RETRY (write (fd, &initsem, sizeof (sem_t)))
+         != sizeof (sem_t)
+         /* Adjust the permission.  */
+         || fchmod (fd, mode) != 0)
+       {
+       unlink_return:
+         unlink (tmpfname);
+         return SEM_FAILED;
+       }
+
+      /* Map the sem_t structure from the file.  */
+      result = (sem_t *) mmap (NULL, sizeof (sem_t), PROT_READ | PROT_WRITE,
+                              MAP_SHARED, fd, 0);
+      if (result == MAP_FAILED)
+       goto unlink_return;
+
+      /* Create or overwrite the file.  Depending on what is wanted we
+        use rename or link.  */
+      if ((oflag & O_EXCL) == 0)
+       {
+         /* An existing file gets overwritten.  */
+         if (rename (tmpfname, finalname) != 0)
+           {
+           unmap_unlink_return:
+             munmap (result, sizeof (sem_t));
+             goto unlink_return;
+           }
+       }
+      else
+       {
+         /* Don't overwrite an existing file.  */
+         if (link (tmpfname, finalname) != 0)
+           goto unmap_unlink_return;
+
+         /* This went well.  Now remove the temporary name.  This
+            should never fail.  If it fails we leak a file name.
+            Better fix the kernel.  */
+         (void) unlink (tmpfname);
+       }
+    }
+
+  /* We don't need the file descriptor anymore.  */
+  close (fd);
+
+  return result;
+}
diff --git a/nptl/sem_unlink.c b/nptl/sem_unlink.c
new file mode 100644 (file)
index 0000000..b8e3de1
--- /dev/null
@@ -0,0 +1,64 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <semaphore.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "semaphoreP.h"
+
+
+int
+sem_unlink (name)
+     const char *name;
+{
+  char *fname;
+  size_t namelen;
+
+  /* Determine where the shmfs is mounted.  */
+  pthread_once (&__namedsem_once, __where_is_shmfs);
+
+  /* If we don't know the mount points there is nothing we can do.  Ever.  */
+  if (mountpoint.dir == NULL)
+    {
+      __set_errno (ENOSYS);
+      return -1;
+    }
+
+  /* Construct the filename.  */
+  while (name[0] == '/')
+    ++name;
+
+  if (name[0] == '\0')
+    {
+      /* The name "/" is not supported.  */
+      __set_errno (ENOENT);
+      return -1;
+    }
+  namelen = strlen (name);
+
+  /* Create the name of the file.  */
+  fname = (char *) alloca (mountpoint.dirlen + namelen + 1);
+  __mempcpy (__mempcpy (fname, mountpoint.dir, mountpoint.dirlen),
+            name, namelen + 1);
+
+  /* Now try removing it.  */
+  return unlink (fname);
+}
diff --git a/nptl/semaphore.h b/nptl/semaphore.h
new file mode 100644 (file)
index 0000000..b8861e5
--- /dev/null
@@ -0,0 +1,74 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _SEMAPHORE_H
+#define _SEMAPHORE_H   1
+
+#include <features.h>
+#include <sys/types.h>
+#ifdef __USE_XOPEN2K
+# define __need_timespec
+# include <time.h>
+#endif
+
+/* Get the definition for sem_t.  */
+#include <bits/semaphore.h>
+
+
+__BEGIN_DECLS
+
+/* Initialize semaphore object SEM to VALUE.  If PSHARED then share it
+   with other processes.  */
+extern int sem_init (sem_t *__sem, int __pshared, unsigned int __value)
+     __THROW;
+/* Free resources associated with semaphore object SEM.  */
+extern int sem_destroy (sem_t *__sem) __THROW;
+
+/* Open a named semaphore NAME with open flaot OFLAG.  */
+extern sem_t *sem_open (__const char *__name, int __oflag, ...) __THROW;
+
+/* Close descriptor for named semaphore SEM.  */
+extern int sem_close (sem_t *__sem) __THROW;
+
+/* Remove named semaphore NAME.  */
+extern int sem_unlink (__const char *__name) __THROW;
+
+/* Wait for SEM being posted.  */
+extern int sem_wait (sem_t *__sem) __THROW;
+
+#ifdef __USE_XOPEN2K
+/* Similar to `sem_wait' but wait only until ABSTIME.  */
+extern int sem_timedwait (sem_t *__restrict __sem,
+                         __const struct timespec *__restrict __abstime)
+     __THROW;
+#endif
+
+/* Test whether SEM is posted.  */
+extern int sem_trywait (sem_t *__sem) __THROW;
+
+/* Post SEM.  */
+extern int sem_post (sem_t *__sem) __THROW;
+
+/* Get current value of SEM and store it in *SVAL.  */
+extern int sem_getvalue (sem_t *__restrict __sem, int *__restrict __sval)
+     __THROW;
+
+
+__END_DECLS
+
+#endif /* semaphore.h */
diff --git a/nptl/semaphoreP.h b/nptl/semaphoreP.h
new file mode 100644 (file)
index 0000000..0d3f6e5
--- /dev/null
@@ -0,0 +1,46 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+
+/* Mount point of the shared memory filesystem.  */
+struct mountpoint_info
+{
+  char *dir;
+  size_t dirlen;
+};
+
+
+/* Variables used in multiple interfaces.  */
+extern struct mountpoint_info mountpoint attribute_hidden;
+
+extern pthread_once_t __namedsem_once attribute_hidden;
+
+
+/* Initializer for mountpoint.  */
+extern void __where_is_shmfs (void) attribute_hidden;
+
+
+/* Prototypes of functions with multiple interfaces.  */
+extern int __new_sem_init (sem_t *sem, int pshared, unsigned int value);
+extern int __new_sem_destroy (sem_t *sem);
+extern int __new_sem_post (sem_t *sem);
+extern int __new_sem_wait (sem_t *sem);
+extern int __new_sem_trywait (sem_t *sem);
+extern int __new_sem_getvalue (sem_t *sem, int *sval);
diff --git a/nptl/shlib-versions b/nptl/shlib-versions
new file mode 100644 (file)
index 0000000..9493a31
--- /dev/null
@@ -0,0 +1,9 @@
+mips.*-.*-linux.*      libpthread=0            GLIBC_2.0 GLIBC_2.2
+sparc64-.*-linux.*     libpthread=0            GLIBC_2.2
+sh.*-.*-linux.*                libpthread=0            GLIBC_2.2
+ia64.*-.*-linux.*      libpthread=0            GLIBC_2.2
+hppa.*-.*-linux.*      libpthread=0            GLIBC_2.2
+s390x-.*-linux.*       libpthread=0            GLIBC_2.2
+cris-.*-linux.*                libpthread=0            GLIBC_2.2
+x86_64-.*-linux.*      libpthread=0            GLIBC_2.2.5
+.*-.*-linux.*          libpthread=0
diff --git a/nptl/sockperf.c b/nptl/sockperf.c
new file mode 100644 (file)
index 0000000..d29a6ee
--- /dev/null
@@ -0,0 +1,594 @@
+#define _GNU_SOURCE
+#include <argp.h>
+#include <complex.h>
+#include <errno.h>
+#include <error.h>
+#include <fcntl.h>
+#include <gd.h>
+#include <inttypes.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <sys/poll.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+
+#define size_x 320
+#define size_y 240
+
+
+#define PATH "/tmp/s.sockperf"
+
+
+struct thread_param
+{
+  unsigned int from;
+  unsigned int to;
+  unsigned int nserv;
+};
+
+struct coord
+{
+  unsigned int x;
+  unsigned int y;
+  complex double z;
+};
+
+
+/* We use 64bit values for the times.  */
+typedef unsigned long long int hp_timing_t;
+
+
+static unsigned int nclients = 2;
+static unsigned int nservers = 2;
+
+static bool timing;
+static int points;
+
+
+static complex double top_left = -0.7 + 0.2i;
+static complex double bottom_right = -0.5 - 0.0i;
+
+
+static int colors[256];
+static gdImagePtr image;
+static pthread_mutex_t image_lock;
+
+static int sock;
+
+
+static void *
+client (void *arg)
+{
+  struct thread_param *param = arg;
+  unsigned int cnt;
+  unsigned int nserv = param->nserv;
+  int clisock[nserv];
+  struct pollfd servpoll[nserv];
+  struct sockaddr_un servaddr;
+  socklen_t servlen;
+  struct coord c;
+
+  bool new_coord (void)
+    {
+      if (cnt >= param->to)
+       return false;
+
+      unsigned int row = cnt / size_x;
+      unsigned int col = cnt % size_x;
+
+      c.x = col;
+      c.y = row;
+      c.z = (top_left
+            + ((col
+                * (creal (bottom_right) - creal (top_left))) / size_x)
+            + (_Complex_I * (row * (cimag (bottom_right) - cimag (top_left)))
+               / size_y));
+
+      ++cnt;
+
+      return true;
+    }
+
+
+  for (cnt = 0; cnt < nserv; ++cnt)
+    {
+      servpoll[cnt].fd = socket (AF_UNIX, SOCK_STREAM, 0);
+      if (clisock < 0)
+       {
+         puts ("cannot create socket in client");
+         return NULL;
+       }
+
+      memset (&servaddr, '\0', sizeof (servaddr));
+      servaddr.sun_family = AF_UNIX;
+      strncpy (servaddr.sun_path, PATH, sizeof (servaddr.sun_path));
+      servlen = offsetof (struct sockaddr_un, sun_path) + strlen (PATH) + 1;
+
+
+      int err;
+      while (1)
+       {
+         err = TEMP_FAILURE_RETRY (connect (servpoll[cnt].fd, &servaddr,
+                                            servlen));
+         if (err != -1 || errno != ECONNREFUSED)
+           break;
+
+         pthread_yield ();
+       }
+
+      if (err == -1)
+       {
+         printf ("cannot connect: %m (%d)\n", errno);
+         exit (1);
+       }
+
+      servpoll[cnt].events = POLLOUT;
+      servpoll[cnt].revents = 0;
+    }
+
+  cnt = param->from;
+
+  new_coord ();
+  bool z_valid = true;
+
+  while (1)
+    {
+      int i;
+      int n = poll (servpoll, nserv, -1);
+      if (n == -1)
+       {
+         puts ("poll returned error");
+         break;
+       }
+
+      bool cont = false;
+      for (i = 0; i < nserv && n > 0; ++i)
+       if (servpoll[i].revents != 0)
+         {
+           if (servpoll[i].revents == POLLIN)
+             {
+               unsigned int vals[3];
+               if (TEMP_FAILURE_RETRY (read (servpoll[i].fd, &vals,
+                                             sizeof (vals)))
+                   != sizeof (vals))
+                 {
+                   puts ("read error in client");
+                   return NULL;
+                 }
+
+               pthread_mutex_lock (&image_lock);
+
+               gdImageSetPixel (image, vals[0], vals[1], vals[2]);
+               ++points;
+
+               pthread_mutex_unlock (&image_lock);
+
+               servpoll[i].events = POLLOUT;
+             }
+           else
+             {
+               if (servpoll[i].revents != POLLOUT)
+                 printf ("revents: %hd != POLLOUT ???\n",
+                         servpoll[i].revents);
+
+               if (z_valid)
+                 {
+                   if (TEMP_FAILURE_RETRY (write (servpoll[i].fd, &c,
+                                                  sizeof (c))) != sizeof (c))
+                     {
+                       puts ("write error in client");
+                       return NULL;
+                     }
+                   cont = true;
+                   servpoll[i].events = POLLIN;
+
+                   z_valid = new_coord ();
+                   if (! z_valid)
+                     /* No more to do.  Clear the event fields.  */
+                     for (i = 0; i < nserv; ++i)
+                       if (servpoll[i].events == POLLOUT)
+                         servpoll[i].events = servpoll[i].revents = 0;
+                 }
+               else
+                 servpoll[i].events = servpoll[i].revents = 0;
+             }
+
+           --n;
+         }
+       else if (servpoll[i].events != 0)
+         cont = true;
+
+      if (! cont && ! z_valid)
+       break;
+    }
+
+  c.x = 0xffffffff;
+  c.y = 0xffffffff;
+  for (cnt = 0; cnt < nserv; ++cnt)
+    {
+      TEMP_FAILURE_RETRY (write (servpoll[cnt].fd, &c, sizeof (c)));
+      close (servpoll[cnt].fd);
+    }
+
+  return NULL;
+}
+
+
+static void *
+server (void *arg)
+{
+  struct sockaddr_un cliaddr;
+  socklen_t clilen;
+  int clisock = TEMP_FAILURE_RETRY (accept (sock, &cliaddr, &clilen));
+
+  if (clisock == -1)
+    {
+      puts ("accept failed");
+      return NULL;
+    }
+
+  while (1)
+    {
+      struct coord c;
+
+      if (TEMP_FAILURE_RETRY (read (clisock, &c, sizeof (c))) != sizeof (c))
+       {
+         printf ("server read failed: %m (%d)\n", errno);
+         break;
+       }
+
+      if (c.x == 0xffffffff && c.y == 0xffffffff)
+       break;
+
+      unsigned int rnds = 0;
+      complex double z = c.z;
+      while (cabs (z) < 4.0)
+       {
+         z = z * z - 1;
+         if (++rnds == 255)
+           break;
+       }
+
+      unsigned int vals[3] = { c.x, c.y, rnds };
+      if (TEMP_FAILURE_RETRY (write (clisock, vals, sizeof (vals)))
+         != sizeof (vals))
+       {
+         puts ("server write error");
+         return NULL;
+       }
+    }
+
+  close (clisock);
+
+  return NULL;
+}
+
+
+static const char *outfilename = "test.png";
+
+
+static const struct argp_option options[] =
+  {
+    { "clients", 'c', "NUMBER", 0, "Number of client threads" },
+    { "servers", 's', "NUMBER", 0, "Number of server threads per client" },
+    { "timing", 'T', NULL, 0,
+      "Measure time from startup to the last thread finishing" },
+    { NULL, 0, NULL, 0, NULL }
+  };
+
+/* Prototype for option handler.  */
+static error_t parse_opt (int key, char *arg, struct argp_state *state);
+
+/* Data structure to communicate with argp functions.  */
+static struct argp argp =
+{
+  options, parse_opt
+};
+
+
+int
+main (int argc, char *argv[])
+{
+  int cnt;
+  FILE *outfile;
+  struct sockaddr_un servaddr;
+  socklen_t servlen;
+  int remaining;
+
+  /* Parse and process arguments.  */
+  argp_parse (&argp, argc, argv, 0, &remaining, NULL);
+
+
+  pthread_t servth[nservers * nclients];
+  pthread_t clntth[nclients];
+  struct thread_param clntparam[nclients];
+
+
+  image = gdImageCreate (size_x, size_y);
+  if (image == NULL)
+    {
+      puts ("gdImageCreate failed");
+      return 1;
+    }
+
+  for (cnt = 0; cnt < 255; ++cnt)
+    colors[cnt] = gdImageColorAllocate (image, 256 - cnt, 256 - cnt,
+                                       256 - cnt);
+  /* Black.  */
+  colors[cnt] = gdImageColorAllocate (image, 0, 0, 0);
+
+
+  sock = socket (AF_UNIX, SOCK_STREAM, 0);
+  if (sock < 0)
+    error (EXIT_FAILURE, errno, "cannot create socket");
+
+  memset (&servaddr, '\0', sizeof (servaddr));
+  servaddr.sun_family = AF_UNIX;
+  strncpy (servaddr.sun_path, PATH, sizeof (servaddr.sun_path));
+  servlen = offsetof (struct sockaddr_un, sun_path) + strlen (PATH) + 1;
+
+  if (bind (sock, &servaddr, servlen) == -1)
+    error (EXIT_FAILURE, errno, "bind failed");
+
+  listen (sock, SOMAXCONN);
+
+  pthread_mutex_init (&image_lock, NULL);
+
+
+  struct sigaction sa;
+  sa.sa_handler = SIG_IGN;
+  sigemptyset (&sa.sa_mask);
+  sa.sa_flags = 0;
+
+  clockid_t cl;
+  struct timespec start_time;
+  if (timing)
+    {
+      if (clock_getcpuclockid (0, &cl) != 0
+         || clock_gettime (cl, &start_time) != 0)
+       timing = false;
+    }
+
+  /* Start the servers.  */
+  for (cnt = 0; cnt < nservers * nclients; ++cnt)
+    {
+      if (pthread_create (&servth[cnt], NULL, server, NULL) != 0)
+       {
+         puts ("pthread_create for server failed");
+         exit (1);
+       }
+    }
+
+  for (cnt = 0; cnt < nclients; ++cnt)
+    {
+      clntparam[cnt].from = cnt * (size_x * size_y) / nclients;
+      clntparam[cnt].to = MIN ((cnt + 1) * (size_x * size_y) / nclients,
+                              size_x * size_y);
+      clntparam[cnt].nserv = nservers;
+
+      if (pthread_create (&clntth[cnt], NULL, client, &clntparam[cnt]) != 0)
+       {
+         puts ("pthread_create for client failed");
+         exit (1);
+       }
+    }
+
+
+  /* Wait for the clients.  */
+  for (cnt = 0; cnt < nclients; ++cnt)
+    if (pthread_join (clntth[cnt], NULL) != 0)
+      {
+       puts ("client pthread_join failed");
+       exit (1);
+      }
+
+  /* Wait for the servers.  */
+  for (cnt = 0; cnt < nclients * nservers; ++cnt)
+    if (pthread_join (servth[cnt], NULL) != 0)
+      {
+       puts ("server pthread_join failed");
+       exit (1);
+      }
+
+
+  if (timing)
+    {
+      struct timespec end_time;
+
+      if (clock_gettime (cl, &end_time) == 0)
+       {
+         end_time.tv_sec -= start_time.tv_sec;
+         end_time.tv_nsec -= start_time.tv_nsec;
+         if (end_time.tv_nsec < 0)
+           {
+             end_time.tv_nsec += 1000000000;
+             --end_time.tv_sec;
+           }
+
+         printf ("\nRuntime: %lu.%09lu seconds\n%d points computed\n",
+                 (unsigned long int) end_time.tv_sec,
+                 (unsigned long int) end_time.tv_nsec,
+                 points);
+       }
+    }
+
+
+  outfile = fopen (outfilename, "w");
+  if (outfile == NULL)
+    error (EXIT_FAILURE, errno, "cannot open output file '%s'", outfilename);
+
+  gdImagePng (image, outfile);
+
+  fclose (outfile);
+
+  unlink (PATH);
+
+  return 0;
+}
+
+
+/* Handle program arguments.  */
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+  switch (key)
+    {
+    case 'c':
+      nclients = strtoul (arg, NULL, 0);
+      break;
+
+    case 's':
+      nservers = strtoul (arg, NULL, 0);
+      break;
+
+    case 'T':
+      timing = true;
+      break;
+
+    default:
+      return ARGP_ERR_UNKNOWN;
+    }
+
+  return 0;
+}
+
+
+static hp_timing_t
+get_clockfreq (void)
+{
+  /* We read the information from the /proc filesystem.  It contains at
+     least one line like
+       cpu MHz         : 497.840237
+     or also
+       cpu MHz         : 497.841
+     We search for this line and convert the number in an integer.  */
+  static hp_timing_t result;
+  int fd;
+
+  /* If this function was called before, we know the result.  */
+  if (result != 0)
+    return result;
+
+  fd = open ("/proc/cpuinfo", O_RDONLY);
+  if (__builtin_expect (fd != -1, 1))
+    {
+      /* XXX AFAIK the /proc filesystem can generate "files" only up
+         to a size of 4096 bytes.  */
+      char buf[4096];
+      ssize_t n;
+
+      n = read (fd, buf, sizeof buf);
+      if (__builtin_expect (n, 1) > 0)
+       {
+         char *mhz = memmem (buf, n, "cpu MHz", 7);
+
+         if (__builtin_expect (mhz != NULL, 1))
+           {
+             char *endp = buf + n;
+             int seen_decpoint = 0;
+             int ndigits = 0;
+
+             /* Search for the beginning of the string.  */
+             while (mhz < endp && (*mhz < '0' || *mhz > '9') && *mhz != '\n')
+               ++mhz;
+
+             while (mhz < endp && *mhz != '\n')
+               {
+                 if (*mhz >= '0' && *mhz <= '9')
+                   {
+                     result *= 10;
+                     result += *mhz - '0';
+                     if (seen_decpoint)
+                       ++ndigits;
+                   }
+                 else if (*mhz == '.')
+                   seen_decpoint = 1;
+
+                 ++mhz;
+               }
+
+             /* Compensate for missing digits at the end.  */
+             while (ndigits++ < 6)
+               result *= 10;
+           }
+       }
+
+      close (fd);
+    }
+
+  return result;
+}
+
+
+int
+clock_getcpuclockid (pid_t pid, clockid_t *clock_id)
+{
+  /* We don't allow any process ID but our own.  */
+  if (pid != 0 && pid != getpid ())
+    return EPERM;
+
+#ifdef CLOCK_PROCESS_CPUTIME_ID
+  /* Store the number.  */
+  *clock_id = CLOCK_PROCESS_CPUTIME_ID;
+
+  return 0;
+#else
+  /* We don't have a timer for that.  */
+  return ENOENT;
+#endif
+}
+
+
+#define HP_TIMING_NOW(Var)     __asm__ __volatile__ ("rdtsc" : "=A" (Var))
+
+/* Get current value of CLOCK and store it in TP.  */
+int
+clock_gettime (clockid_t clock_id, struct timespec *tp)
+{
+  int retval = -1;
+
+  switch (clock_id)
+    {
+    case CLOCK_PROCESS_CPUTIME_ID:
+      {
+
+       static hp_timing_t freq;
+       hp_timing_t tsc;
+
+       /* Get the current counter.  */
+       HP_TIMING_NOW (tsc);
+
+       if (freq == 0)
+         {
+           freq = get_clockfreq ();
+           if (freq == 0)
+             return EINVAL;
+         }
+
+       /* Compute the seconds.  */
+       tp->tv_sec = tsc / freq;
+
+       /* And the nanoseconds.  This computation should be stable until
+          we get machines with about 16GHz frequency.  */
+       tp->tv_nsec = ((tsc % freq) * UINT64_C (1000000000)) / freq;
+
+       retval = 0;
+      }
+    break;
+
+    default:
+      errno = EINVAL;
+      break;
+    }
+
+  return retval;
+}
diff --git a/nptl/sysdeps/generic/lowlevellock.h b/nptl/sysdeps/generic/lowlevellock.h
new file mode 100644 (file)
index 0000000..9cffca8
--- /dev/null
@@ -0,0 +1,89 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <atomic.h>
+
+
+/* Implement generic mutex.  Basic futex syscall support is required:
+
+     lll_futex_wait(futex, value) - call sys_futex with FUTEX_WAIT
+                                   and third parameter VALUE
+
+     lll_futex_wake(futex, value) - call sys_futex with FUTEX_WAKE
+                                   and third parameter VALUE
+*/
+
+
+/* Mutex lock counter:
+   bit 31 clear means unlocked;
+   bit 31 set means locked.
+
+   All code that looks at bit 31 first increases the 'number of
+   interested threads' usage counter, which is in bits 0-30.
+
+   All negative mutex values indicate that the mutex is still locked.  */
+
+
+static inline void
+__generic_mutex_lock (int *mutex)
+{
+  unsigned int v;
+
+  /* Bit 31 was clear, we got the mutex.  (this is the fastpath).  */
+  if (atomic_bit_test_set (mutex, 31) == 0)
+    return;
+
+  atomic_increment (mutex);
+
+  while (1)
+    {
+      if (atomic_bit_test_set (mutex, 31) == 0)
+       {
+         atomic_decrement (mutex);
+         return;
+       }
+
+      /* We have to wait now. First make sure the futex value we are
+        monitoring is truly negative (i.e. locked). */
+      v = *mutex;
+      if (v >= 0)
+       continue;
+
+      lll_futex_wait (mutex, v);
+    }
+}
+
+
+static inline void
+__generic_mutex_unlock (int *mutex)
+{
+  /* Adding 0x80000000 to the counter results in 0 if and only if
+     there are not other interested threads - we can return (this is
+     the fastpath).  */
+  if (atomic_add_zero (0x80000000, mutex))
+    return;
+
+  /* There are other threads waiting for this mutex, wake one of them
+     up.  */
+  lll_futex_wake (mutex, 1);
+}
+
+
+#define lll_mutex_lock(futex) __generic_mutex_lock (&(futex))
+#define lll_mutex_unlock(futex) __generic_mutex_unlock (&(futex))
diff --git a/nptl/sysdeps/generic/pt-raise.c b/nptl/sysdeps/generic/pt-raise.c
new file mode 100644 (file)
index 0000000..59d9590
--- /dev/null
@@ -0,0 +1,30 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <signal.h>
+
+
+int
+raise (sig)
+     int sig;
+{
+  /* This is what POSIX says must happen.  */
+  return pthread_kill (pthread_self (), sig);
+}
diff --git a/nptl/sysdeps/i386/i686/bits/atomic.h b/nptl/sysdeps/i386/i686/bits/atomic.h
new file mode 100644 (file)
index 0000000..7eb7573
--- /dev/null
@@ -0,0 +1,340 @@
+/* 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 <stdint.h>
+
+
+typedef int8_t atomic8_t;
+typedef uint8_t uatomic8_t;
+typedef int_fast8_t atomic_fast8_t;
+typedef uint_fast8_t uatomic_fast8_t;
+
+typedef int16_t atomic16_t;
+typedef uint16_t uatomic16_t;
+typedef int_fast16_t atomic_fast16_t;
+typedef uint_fast16_t uatomic_fast16_t;
+
+typedef int32_t atomic32_t;
+typedef uint32_t uatomic32_t;
+typedef int_fast32_t atomic_fast32_t;
+typedef uint_fast32_t uatomic_fast32_t;
+
+typedef int64_t atomic64_t;
+typedef uint64_t uatomic64_t;
+typedef int_fast64_t atomic_fast64_t;
+typedef uint_fast64_t uatomic_fast64_t;
+
+typedef intptr_t atomicptr_t;
+typedef uintptr_t uatomicptr_t;
+typedef intmax_t atomic_max_t;
+typedef uintmax_t uatomic_max_t;
+
+
+#ifndef LOCK
+# ifdef UP
+#  define LOCK /* nothing */
+# else
+#  define LOCK "lock;"
+# endif
+#endif
+
+
+#define __arch_compare_and_exchange_8_acq(mem, newval, oldval) \
+  ({ unsigned char ret;                                                              \
+     __asm __volatile (LOCK "cmpxchgb %2, %1; setne %0"                              \
+                      : "=a" (ret), "=m" (*mem)                              \
+                      : "q" (newval), "1" (*mem), "0" (oldval));             \
+     ret; })
+
+#define __arch_compare_and_exchange_16_acq(mem, newval, oldval) \
+  ({ unsigned char ret;                                                              \
+     __asm __volatile (LOCK "cmpxchgw %2, %1; setne %0"                              \
+                      : "=a" (ret), "=m" (*mem)                              \
+                      : "r" (newval), "1" (*mem), "0" (oldval));             \
+     ret; })
+
+#define __arch_compare_and_exchange_32_acq(mem, newval, oldval) \
+  ({ unsigned char ret;                                                              \
+     __asm __volatile (LOCK "cmpxchgl %2, %1; setne %0"                              \
+                      : "=a" (ret), "=m" (*mem)                              \
+                      : "r" (newval), "1" (*mem), "0" (oldval));             \
+     ret; })
+
+/* XXX We do not really need 64-bit compare-and-exchange.  At least
+   not in the moment.  Using it would mean causing portability
+   problems since not many other 32-bit architectures have support for
+   such an operation.  So don't define any code for now.  If it is
+   really going to be used the code below can be used.  */
+#if 1
+# define __arch_compare_and_exchange_64_acq(mem, newval, oldval) \
+  (abort (), 0)
+#else
+# ifdef __PIC__
+#  define __arch_compare_and_exchange_64_acq(mem, newval, oldval) \
+  ({ unsigned char ret;                                                              \
+     int ignore;                                                             \
+     __asm __volatile ("xchgl %3, %%ebx\n\t"                                 \
+                      LOCK "cmpxchg8b %2, %1\n\t"                            \
+                      "setne %0\n\t"                                         \
+                      "xchgl %3, %%ebx"                                      \
+                      : "=a" (ret), "=m" (*mem), "=d" (ignore)               \
+                      : "DS" (((unsigned long long int) (newval))            \
+                              & 0xffffffff),                                 \
+                        "c" (((unsigned long long int) (newval)) >> 32),     \
+                        "1" (*mem), "0" (((unsigned long long int) (oldval)) \
+                                         & 0xffffffff),                      \
+                        "2" (((unsigned long long int) (oldval)) >> 32));    \
+     ret; })
+# else
+#  define __arch_compare_and_exchange_64_acq(mem, newval, oldval) \
+  ({ unsigned char ret;                                                              \
+     int ignore;                                                             \
+     __asm __volatile (LOCK "cmpxchg8b %2, %1; setne %0"                     \
+                      : "=a" (ret), "=m" (*mem), "=d" (ignore)               \
+                      : "b" (((unsigned long long int) (newval))             \
+                             & 0xffffffff),                                  \
+                         "c" (((unsigned long long int) (newval)) >> 32),    \
+                        "1" (*mem), "0" (((unsigned long long int) (oldval)) \
+                                         & 0xffffffff),                      \
+                        "2" (((unsigned long long int) (oldval)) >> 32));    \
+     ret; })
+# endif
+#endif
+
+
+#define atomic_exchange_and_add(mem, value) \
+  ({ __typeof (*mem) result;                                                 \
+     if (sizeof (*mem) == 1)                                                 \
+       __asm __volatile (LOCK "xaddb %0, %1"                                 \
+                        : "=r" (result), "=m" (*mem)                         \
+                        : "0" (value), "1" (*mem));                          \
+     else if (sizeof (*mem) == 2)                                            \
+       __asm __volatile (LOCK "xaddw %0, %1"                                 \
+                        : "=r" (result), "=m" (*mem)                         \
+                        : "0" (value), "1" (*mem));                          \
+     else if (sizeof (*mem) == 4)                                            \
+       __asm __volatile (LOCK "xaddl %0, %1"                                 \
+                        : "=r" (result), "=m" (*mem)                         \
+                        : "0" (value), "1" (*mem));                          \
+     else                                                                    \
+       {                                                                     \
+        __typeof (value) addval = (value);                                   \
+        __typeof (*mem) oldval;                                              \
+        __typeof (mem) memp = (mem);                                         \
+        do                                                                   \
+          result = (oldval = *memp) + addval;                                \
+        while (! __arch_compare_and_exchange_64_acq (memp, result, oldval)); \
+       }                                                                     \
+     result; })
+
+
+#define atomic_add(mem, value) \
+  (void) ({ if (__builtin_constant_p (value) && (value) == 1)                \
+             atomic_increment (mem);                                         \
+           else if (__builtin_constant_p (value) && (value) == 1)            \
+             atomic_decrement (mem);                                         \
+           else if (sizeof (*mem) == 1)                                      \
+             __asm __volatile (LOCK "addb %1, %0"                            \
+                               : "=m" (*mem)                                 \
+                               : "ir" (value), "0" (*mem));                  \
+           else if (sizeof (*mem) == 2)                                      \
+             __asm __volatile (LOCK "addw %1, %0"                            \
+                               : "=m" (*mem)                                 \
+                               : "ir" (value), "0" (*mem));                  \
+           else if (sizeof (*mem) == 4)                                      \
+             __asm __volatile (LOCK "addl %1, %0"                            \
+                               : "=m" (*mem)                                 \
+                               : "ir" (value), "0" (*mem));                  \
+           else                                                              \
+             {                                                               \
+               __typeof (value) addval = (value);                            \
+               __typeof (*mem) oldval;                                       \
+               __typeof (mem) memp = (mem);                                  \
+               do                                                            \
+                 oldval = *memp;                                             \
+               while (! __arch_compare_and_exchange_64_acq (memp,            \
+                                                            oldval + addval, \
+                                                            oldval));        \
+             }                                                               \
+           })
+
+
+#define atomic_add_negative(mem, value) \
+  ({ unsigned char __result;                                                 \
+     if (sizeof (*mem) == 1)                                                 \
+       __asm __volatile (LOCK "addb %2, %0; sets %1"                         \
+                        : "=m" (*mem), "=qm" (__result)                      \
+                        : "ir" (value), "0" (*mem));                         \
+     else if (sizeof (*mem) == 2)                                            \
+       __asm __volatile (LOCK "addw %2, %0; sets %1"                         \
+                        : "=m" (*mem), "=qm" (__result)                      \
+                        : "ir" (value), "0" (*mem));                         \
+     else if (sizeof (*mem) == 4)                                            \
+       __asm __volatile (LOCK "addl %2, %0; sets %1"                         \
+                        : "=m" (*mem), "=qm" (__result)                      \
+                        : "ir" (value), "0" (*mem));                         \
+     else                                                                    \
+       abort ();                                                             \
+     __result; })
+
+
+#define atomic_add_zero(mem, value) \
+  ({ unsigned char __result;                                                 \
+     if (sizeof (*mem) == 1)                                                 \
+       __asm __volatile (LOCK "addb %2, %0; setz %1"                         \
+                        : "=m" (*mem), "=qm" (__result)                      \
+                        : "ir" (value), "0" (*mem));                         \
+     else if (sizeof (*mem) == 2)                                            \
+       __asm __volatile (LOCK "addw %2, %0; setz %1"                         \
+                        : "=m" (*mem), "=qm" (__result)                      \
+                        : "ir" (value), "0" (*mem));                         \
+     else if (sizeof (*mem) == 4)                                            \
+       __asm __volatile (LOCK "addl %2, %0; setz %1"                         \
+                        : "=m" (*mem), "=qm" (__result)                      \
+                        : "ir" (value), "0" (*mem));                         \
+     else                                                                    \
+       abort ();                                                             \
+     __result; })
+
+
+#define atomic_increment(mem) \
+  (void) ({ if (sizeof (*mem) == 1)                                          \
+             __asm __volatile (LOCK "incb %0"                                \
+                               : "=m" (*mem)                                 \
+                               : "0" (*mem));                                \
+           else if (sizeof (*mem) == 2)                                      \
+             __asm __volatile (LOCK "incw %0"                                \
+                               : "=m" (*mem)                                 \
+                               : "0" (*mem));                                \
+           else if (sizeof (*mem) == 4)                                      \
+             __asm __volatile (LOCK "incl %0"                                \
+                               : "=m" (*mem)                                 \
+                               : "0" (*mem));                                \
+           else                                                              \
+             {                                                               \
+               __typeof (*mem) oldval;                                       \
+               __typeof (mem) memp = (mem);                                  \
+               do                                                            \
+                 oldval = *memp;                                             \
+               while (! __arch_compare_and_exchange_64_acq (memp,            \
+                                                            oldval + 1,      \
+                                                            oldval));        \
+             }                                                               \
+           })
+
+
+#define atomic_increment_and_test(mem) \
+  ({ unsigned char __result;                                                 \
+     if (sizeof (*mem) == 1)                                                 \
+       __asm __volatile (LOCK "incb %0; sete %1"                             \
+                        : "=m" (*mem), "=qm" (__result)                      \
+                        : "0" (*mem));                                       \
+     else if (sizeof (*mem) == 2)                                            \
+       __asm __volatile (LOCK "incw %0; sete %1"                             \
+                        : "=m" (*mem), "=qm" (__result)                      \
+                        : "0" (*mem));                                       \
+     else if (sizeof (*mem) == 4)                                            \
+       __asm __volatile (LOCK "incl %0; sete %1"                             \
+                        : "=m" (*mem), "=qm" (__result)                      \
+                        : "0" (*mem));                                       \
+     else                                                                    \
+       abort ();                                                             \
+     __result; })
+
+
+#define atomic_decrement(mem) \
+  (void) ({ if (sizeof (*mem) == 1)                                          \
+             __asm __volatile (LOCK "decb %0"                                \
+                               : "=m" (*mem)                                 \
+                               : "0" (*mem));                                \
+           else if (sizeof (*mem) == 2)                                      \
+             __asm __volatile (LOCK "decw %0"                                \
+                               : "=m" (*mem)                                 \
+                               : "0" (*mem));                                \
+           else if (sizeof (*mem) == 4)                                      \
+             __asm __volatile (LOCK "decl %0"                                \
+                               : "=m" (*mem)                                 \
+                               : "0" (*mem));                                \
+           else                                                              \
+             {                                                               \
+               __typeof (*mem) oldval;                                       \
+               __typeof (mem) memp = (mem);                                  \
+               do                                                            \
+                 oldval = *memp;                                             \
+               while (! __arch_compare_and_exchange_64_acq (memp,            \
+                                                            oldval - 1,      \
+                                                            oldval));        \
+             }                                                               \
+           })
+
+
+#define atomic_decrement_and_test(mem) \
+  ({ unsigned char __result;                                                 \
+     if (sizeof (*mem) == 1)                                                 \
+       __asm __volatile (LOCK "decb %0; sete %1"                             \
+                        : "=m" (*mem), "=qm" (__result)                      \
+                        : "0" (*mem));                                       \
+     else if (sizeof (*mem) == 2)                                            \
+       __asm __volatile (LOCK "decw %0; sete %1"                             \
+                        : "=m" (*mem), "=qm" (__result)                      \
+                        : "0" (*mem));                                       \
+     else if (sizeof (*mem) == 4)                                            \
+       __asm __volatile (LOCK "decl %0; sete %1"                             \
+                        : "=m" (*mem), "=qm" (__result)                      \
+                        : "0" (*mem));                                       \
+     else                                                                    \
+       abort ();                                                             \
+     __result; })
+
+
+#define atomic_bit_set(mem, bit) \
+  (void) ({ if (sizeof (*mem) == 1)                                          \
+             __asm __volatile (LOCK "orb %2, %0"                             \
+                               : "=m" (*mem)                                 \
+                               : "0" (*mem), "i" (1 << (bit)));              \
+           else if (sizeof (*mem) == 2)                                      \
+             __asm __volatile (LOCK "orw %2, %0"                             \
+                               : "=m" (*mem)                                 \
+                               : "0" (*mem), "i" (1 << (bit)));              \
+           else if (sizeof (*mem) == 4)                                      \
+             __asm __volatile (LOCK "orl %2, %0"                             \
+                               : "=m" (*mem)                                 \
+                               : "0" (*mem), "i" (1 << (bit)));              \
+           else                                                              \
+             abort ();                                                       \
+           })
+
+
+#define atomic_bit_test_set(mem, bit) \
+  ({ unsigned char __result;                                                 \
+     if (sizeof (*mem) == 1)                                                 \
+       __asm __volatile (LOCK "btsb %3, %1; setc %0"                         \
+                        : "=q" (__result), "=m" (*mem)                       \
+                        : "1" (*mem), "i" (bit));                            \
+     else if (sizeof (*mem) == 2)                                            \
+       __asm __volatile (LOCK "btsw %3, %1; setc %0"                         \
+                        : "=q" (__result), "=m" (*mem)                       \
+                        : "1" (*mem), "i" (bit));                            \
+     else if (sizeof (*mem) == 4)                                            \
+       __asm __volatile (LOCK "btsl %3, %1; setc %0"                         \
+                        : "=q" (__result), "=m" (*mem)                       \
+                        : "1" (*mem), "i" (bit));                            \
+     else                                                                    \
+       abort ();                                                             \
+     __result; })
diff --git a/nptl/sysdeps/i386/i686/pthread_spin_trylock.S b/nptl/sysdeps/i386/i686/pthread_spin_trylock.S
new file mode 100644 (file)
index 0000000..881976c
--- /dev/null
@@ -0,0 +1,34 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#define EBUSY  16
+
+       .globl  pthread_spin_trylock
+       .type   pthread_spin_trylock,@function
+       .align  16
+pthread_spin_trylock:
+       movl    4(%esp), %edx
+       movl    $1, %eax
+       xorl    %ecx, %ecx
+       cmpxchgl %ecx, (%edx)
+       movl    $EBUSY, %ecx
+       movl    $0, %eax
+       cmovne  %ecx, %eax
+       ret
+       .size   pthread_spin_trylock,.-pthread_spin_trylock
diff --git a/nptl/sysdeps/i386/i686/tls.h b/nptl/sysdeps/i386/i686/tls.h
new file mode 100644 (file)
index 0000000..4025ed8
--- /dev/null
@@ -0,0 +1,36 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _TLS_H
+
+/* Additional definitions for <tls.h> on i686 and up.  */
+
+
+/* Macros to load from and store into segment registers.  We can use
+   the 32-bit instructions.  */
+#define TLS_GET_GS() \
+  ({ int __seg; __asm ("movl %%gs, %0" : "=q" (__seg)); __seg; })
+#define TLS_SET_GS(val) \
+  __asm ("movl %0, %%gs" :: "q" (val))
+
+
+/* Get the full set of definitions.  */
+#include "../tls.h"
+
+#endif /* tls.h */
diff --git a/nptl/sysdeps/i386/pthread_sigmask.c b/nptl/sysdeps/i386/pthread_sigmask.c
new file mode 100644 (file)
index 0000000..2ae9198
--- /dev/null
@@ -0,0 +1,34 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <signal.h>
+#include <pthreadP.h>
+#include <tls.h>
+#include <sysdep.h>
+
+
+int
+pthread_sigmask (how, newmask, oldmask)
+     int how;
+     const sigset_t *newmask;
+     sigset_t *oldmask;
+{
+  return INLINE_SYSCALL (sigprocmask, 3, how, newmask, oldmask);
+}
diff --git a/nptl/sysdeps/i386/pthread_spin_destroy.c b/nptl/sysdeps/i386/pthread_spin_destroy.c
new file mode 100644 (file)
index 0000000..4d0109c
--- /dev/null
@@ -0,0 +1,29 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+
+
+int
+pthread_spin_destroy (lock)
+     pthread_spinlock_t *lock;
+{
+  /* Nothing to do.  */
+  return 0;
+}
diff --git a/nptl/sysdeps/i386/pthread_spin_init.c b/nptl/sysdeps/i386/pthread_spin_init.c
new file mode 100644 (file)
index 0000000..0a47981
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* Not needed.  pthread_spin_init is an alias for pthread_spin_unlock.  */
diff --git a/nptl/sysdeps/i386/pthread_spin_lock.c b/nptl/sysdeps/i386/pthread_spin_lock.c
new file mode 100644 (file)
index 0000000..43a1831
--- /dev/null
@@ -0,0 +1,48 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+
+
+#ifdef UP
+# define LOCK
+#else
+# define LOCK "lock;"
+#endif
+
+
+int
+pthread_spin_lock (lock)
+     pthread_spinlock_t *lock;
+{
+  asm ("\n"
+       "1:\t" LOCK "decl %0\n\t"
+       "jne 2f\n\t"
+       ".subsection 1\n\t"
+       ".align 16\n"
+       "2:\trep; nop\n\t"
+       "cmpl $0, %0\n\t"
+       "jg 1b\n\t"
+       "jmp 2b\n\t"
+       ".previous"
+       : "=m" (*lock)
+       : "0" (*lock));
+
+  return 0;
+}
diff --git a/nptl/sysdeps/i386/pthread_spin_unlock.S b/nptl/sysdeps/i386/pthread_spin_unlock.S
new file mode 100644 (file)
index 0000000..d94f1e7
--- /dev/null
@@ -0,0 +1,32 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+       .globl  pthread_spin_unlock
+       .type   pthread_spin_unlock,@function
+       .align  16
+pthread_spin_unlock:
+       movl    4(%esp), %eax
+       movl    $1, (%eax)
+       xorl    %eax, %eax
+       ret
+       .size   pthread_spin_unlock,.-pthread_spin_unlock
+
+       /* The implementation of pthread_spin_init is identical.  */
+       .globl  pthread_spin_init
+pthread_spin_init = pthread_spin_unlock
diff --git a/nptl/sysdeps/i386/pthreaddef.h b/nptl/sysdeps/i386/pthreaddef.h
new file mode 100644 (file)
index 0000000..6efa1b6
--- /dev/null
@@ -0,0 +1,55 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* Default stack size.  */
+#define ARCH_STACK_DEFAULT_SIZE        (2 * 1024 * 1024)
+
+/* Required stack pointer alignment at beginning.  SSE requires 16
+   bytes.  */
+#define STACK_ALIGN            16
+
+/* Minimal stack size after allocating thread descriptor and guard size.  */
+#define MINIMAL_REST_STACK     2048
+
+/* Alignment requirement for TCB.  */
+#define TCB_ALIGNMENT          16
+
+/* The signal used for asynchronous cancelation.  */
+#define SIGCANCEL              __SIGRTMIN
+
+
+/* Location of current stack frame.  */
+#define CURRENT_STACK_FRAME    __builtin_frame_address (0)
+
+
+/* XXX Until we have a better place keep the definitions here.  */
+
+/* While there is no such syscall.  */
+#define __exit_thread_inline(val) \
+  while (1) {                                                                \
+    if (__builtin_constant_p (val) && (val) == 0)                            \
+      asm volatile ("xorl %%ebx, %%ebx; int $0x80" :: "a" (__NR_exit));              \
+    else                                                                     \
+      asm volatile ("movl %1, %%ebx; int $0x80"                                      \
+                   :: "a" (__NR_exit), "r" (val));                           \
+  }
+#define gettid()                                                             \
+  ({ int tid;                                                                \
+     __asm __volatile ("int $0x80" : "=a" (tid) : "0" (__NR_gettid));        \
+     tid; })
diff --git a/nptl/sysdeps/i386/tls.h b/nptl/sysdeps/i386/tls.h
new file mode 100644 (file)
index 0000000..244a487
--- /dev/null
@@ -0,0 +1,332 @@
+/* Definition for thread-local data handling.  linuxthreads/i386 version.
+   Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _TLS_H
+#define _TLS_H 1
+
+#ifndef __ASSEMBLER__
+# include <stddef.h>
+# include <stdint.h>
+
+
+/* Type for the dtv.  */
+typedef union dtv
+{
+  size_t counter;
+  void *pointer;
+} dtv_t;
+
+
+typedef struct
+{
+  void *tcb;           /* Pointer to the TCB.  Not necessary the
+                          thread descriptor used by libpthread.  */
+  dtv_t *dtv;
+  void *self;          /* Pointer to the thread descriptor.  */
+} tcbhead_t;
+#endif
+
+
+/* We require TLS support in the tools.  */
+#ifndef HAVE_TLS_SUPPORT
+# error "TLS support is required."
+#endif
+
+/* Signal that TLS support is available.  */
+#define USE_TLS        1
+
+/* Alignment requirement for the stack.  For IA-32 this is govern by
+   the SSE memory functions.  */
+#define STACK_ALIGN    16
+
+
+#ifndef __ASSEMBLER__
+/* Get system call information.  */
+# include <sysdep.h>
+
+/* The old way: using LDT.  */
+
+/* Structure passed to `modify_ldt', 'set_thread_area', and 'clone' calls.  */
+struct user_desc
+{
+  unsigned int entry_number;
+  unsigned long int base_addr;
+  unsigned int limit;
+  unsigned int seg_32bit:1;
+  unsigned int contents:2;
+  unsigned int read_exec_only:1;
+  unsigned int limit_in_pages:1;
+  unsigned int seg_not_present:1;
+  unsigned int useable:1;
+  unsigned int empty:25;
+};
+
+/* Initializing bit fields is slow.  We speed it up by using a union.  */
+union user_desc_init
+{
+  struct user_desc desc;
+  unsigned int vals[4];
+};
+
+
+/* Get the thread descriptor definition.  */
+# include <nptl/descr.h>
+
+/* This is the size of the initial TCB.  */
+# define TLS_INIT_TCB_SIZE sizeof (tcbhead_t)
+
+/* Alignment requirements for the initial TCB.  */
+# define TLS_INIT_TCB_ALIGN __alignof__ (tcbhead_t)
+
+/* This is the size of the TCB.  */
+# define TLS_TCB_SIZE sizeof (struct pthread)
+
+/* Alignment requirements for the TCB.  */
+# define TLS_TCB_ALIGN __alignof__ (struct pthread)
+
+/* The TCB can have any size and the memory following the address the
+   thread pointer points to is unspecified.  Allocate the TCB there.  */
+# define TLS_TCB_AT_TP 1
+
+
+/* Install the dtv pointer.  The pointer passed is to the element with
+   index -1 which contain the length.  */
+# define INSTALL_DTV(descr, dtvp) \
+  ((tcbhead_t *) (descr))->dtv = dtvp + 1
+
+/* Install new dtv for current thread.  */
+# define INSTALL_NEW_DTV(dtv) \
+  ({ struct pthread *__pd;                                                   \
+     THREAD_SETMEM (__pd, header.data.dtvp, dtv); })
+
+/* Return dtv of given thread descriptor.  */
+# define GET_DTV(descr) \
+  (((tcbhead_t *) (descr))->dtv)
+
+
+/* Macros to load from and store into segment registers.  */
+# ifndef TLS_GET_GS
+#  define TLS_GET_GS() \
+  ({ int __seg; __asm ("movw %%gs, %w0" : "=q" (__seg)); __seg & 0xffff; })
+# endif
+# ifndef TLS_SET_GS
+#  define TLS_SET_GS(val) \
+  __asm ("movw %w0, %%gs" :: "q" (val))
+# endif
+
+
+# ifndef __NR_set_thread_area
+#  define __NR_set_thread_area 243
+# endif
+# ifndef TLS_FLAG_WRITABLE
+#  define TLS_FLAG_WRITABLE            0x00000001
+# endif
+
+// XXX Enable for the real world.
+#if 0
+# ifndef __ASSUME_SET_THREAD_AREA
+#  error "we need set_thread_area"
+# endif
+#endif
+
+# ifdef __PIC__
+#  define TLS_EBX_ARG "r"
+#  define TLS_LOAD_EBX "xchgl %3, %%ebx\n\t"
+# else
+#  define TLS_EBX_ARG "b"
+#  define TLS_LOAD_EBX
+# endif
+
+/* Code to initially initialize the thread pointer.  This might need
+   special attention since 'errno' is not yet available and if the
+   operation can cause a failure 'errno' must not be touched.  */
+# define TLS_INIT_TP(thrdescr, secondcall) \
+  ({ void *_thrdescr = (thrdescr);                                           \
+     tcbhead_t *_head = _thrdescr;                                           \
+     union user_desc_init _segdescr;                                         \
+     int _result;                                                            \
+                                                                             \
+     _head->tcb = _thrdescr;                                                 \
+     /* For now the thread descriptor is at the same address.  */            \
+     _head->self = _thrdescr;                                                \
+                                                                             \
+     /* The 'entry_number' field.  Let the kernel pick a value.  */          \
+     if (secondcall)                                                         \
+       _segdescr.vals[0] = TLS_GET_GS () >> 3;                               \
+     else                                                                    \
+       _segdescr.vals[0] = -1;                                               \
+     /* The 'base_addr' field.  Pointer to the TCB.  */                              \
+     _segdescr.vals[1] = (unsigned long int) _thrdescr;                              \
+     /* The 'limit' field.  We use 4GB which is 0xfffff pages.  */           \
+     _segdescr.vals[2] = 0xfffff;                                            \
+     /* Collapsed value of the bitfield:                                     \
+         .seg_32bit = 1                                                      \
+         .contents = 0                                                       \
+         .read_exec_only = 0                                                 \
+         .limit_in_pages = 1                                                 \
+         .seg_not_present = 0                                                \
+         .useable = 1 */                                                     \
+     _segdescr.vals[3] = 0x51;                                               \
+                                                                             \
+     /* Install the TLS.  */                                                 \
+     asm volatile (TLS_LOAD_EBX                                                      \
+                  "int $0x80\n\t"                                            \
+                  TLS_LOAD_EBX                                               \
+                  : "=a" (_result), "=m" (_segdescr.desc.entry_number)       \
+                  : "0" (__NR_set_thread_area),                              \
+                    TLS_EBX_ARG (&_segdescr.desc), "m" (_segdescr.desc));    \
+                                                                             \
+     if (_result == 0)                                                       \
+       /* We know the index in the GDT, now load the segment register.       \
+         The use of the GDT is described by the value 3 in the lower         \
+         three bits of the segment descriptor value.                         \
+                                                                             \
+         Note that we have to do this even if the numeric value of           \
+         the descriptor does not change.  Loading the segment register       \
+         causes the segment information from the GDT to be loaded            \
+         which is necessary since we have changed it.   */                   \
+       TLS_SET_GS (_segdescr.desc.entry_number * 8 + 3);                     \
+                                                                             \
+     _result; })
+
+
+/* Return the address of the dtv for the current thread.  */
+# define THREAD_DTV() \
+  ({ struct pthread *__pd;                                                   \
+     THREAD_GETMEM (__pd, header.data.dtvp); })
+
+
+/* Return the thread descriptor for the current thread.
+
+   The contained asm must *not* be marked volatile since otherwise
+   assignments like
+        pthread_descr self = thread_self();
+   do not get optimized away.  */
+# define THREAD_SELF \
+  ({ struct pthread *__self;                                                 \
+     asm ("movl %%gs:%c1,%0" : "=r" (__self)                                 \
+         : "i" (offsetof (struct pthread, header.data.self)));               \
+     __self;})
+
+
+/* Read member of the thread descriptor directly.  */
+# define THREAD_GETMEM(descr, member) \
+  ({ __typeof (descr->member) __value;                                       \
+     if (sizeof (__value) == 1)                                                      \
+       asm ("movb %%gs:%P2,%b0"                                                      \
+           : "=q" (__value)                                                  \
+           : "0" (0), "i" (offsetof (struct pthread, member)));              \
+     else if (sizeof (__value) == 4)                                         \
+       asm ("movl %%gs:%P1,%0"                                               \
+           : "=r" (__value)                                                  \
+           : "i" (offsetof (struct pthread, member)));                       \
+     else                                                                    \
+       {                                                                     \
+        if (sizeof (__value) != 8)                                           \
+          /* There should not be any value with a size other than 1,         \
+             4 or 8.  */                                                     \
+          abort ();                                                          \
+                                                                             \
+        asm ("movl %%gs:%P1,%%eax\n\t"                                       \
+             "movl %%gs:%P2,%%edx"                                           \
+             : "=A" (__value)                                                \
+             : "i" (offsetof (struct pthread, member)),                      \
+               "i" (offsetof (struct pthread, member) + 4));                 \
+       }                                                                     \
+     __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 ("movb %%gs:(%2),%b0"                                             \
+           : "=q" (__value)                                                  \
+           : "0" (0), "r" (offsetof (struct pthread, member)));              \
+     else if (sizeof (__value) == 4)                                         \
+       asm ("movl %%gs:(%1),%0"                                                      \
+           : "=r" (__value)                                                  \
+           : "r" (offsetof (struct pthread, member)));                       \
+     else                                                                    \
+       {                                                                     \
+        if (sizeof (__value) != 8)                                           \
+          /* There should not be any value with a size other than 1,         \
+             4 or 8.  */                                                     \
+          abort ();                                                          \
+                                                                             \
+        asm ("movl %%gs:(%1),%%eax\n\t"                                      \
+             "movl %%gs:4(%1),%%edx"                                         \
+             : "=&A" (__value)                                               \
+             : "r" (offsetof (struct pthread, member)));                     \
+       }                                                                     \
+     __value; })
+
+
+/* Same as THREAD_SETMEM, but the member offset can be non-constant.  */
+# define THREAD_SETMEM(descr, member, value) \
+  ({ if (sizeof (value) == 1)                                                \
+       asm volatile ("movb %0,%%gs:%P1" :                                    \
+                    : "iq" (value),                                          \
+                      "i" (offsetof (struct pthread, member)));              \
+     else if (sizeof (value) == 4)                                           \
+       asm volatile ("movl %0,%%gs:%P1" :                                    \
+                    : "ir" (value),                                          \
+                      "i" (offsetof (struct pthread, member)));              \
+     else                                                                    \
+       {                                                                     \
+        if (sizeof (value) != 8)                                             \
+          /* There should not be any value with a size other than 1,         \
+             4 or 8.  */                                                     \
+          abort ();                                                          \
+                                                                             \
+        asm volatile ("movl %%eax,%%gs:%P1\n\n"                              \
+                      "movl %%edx,%%gs:%P2" :                                \
+                      : "A" (value),                                         \
+                        "i" (offsetof (struct pthread, member)),             \
+                        "i" (offsetof (struct pthread, member) + 4));        \
+       }})
+
+
+/* Set member of the thread descriptor directly.  */
+# define THREAD_SETMEM_NC(descr, member, value) \
+  ({ if (sizeof (value) == 1)                                                \
+       asm volatile ("movb %0,%%gs:(%1)" :                                   \
+                    : "iq" (value),                                          \
+                      "r" (offsetof (struct pthread, member)));              \
+     else if (sizeof (value) == 4)                                           \
+       asm volatile ("movl %0,%%gs:(%1)" :                                   \
+                    : "ir" (value),                                          \
+                      "r" (offsetof (struct pthread, member)));              \
+     else                                                                    \
+       {                                                                     \
+        if (sizeof (value) != 8)                                             \
+          /* There should not be any value with a size other than 1,         \
+             4 or 8.  */                                                     \
+          abort ();                                                          \
+                                                                             \
+        asm volatile ("movl %%eax,%%gs:(%1)\n\t"                             \
+                      "movl %%edx,%%gs:4(%1)" :                              \
+                      : "A" (value),                                         \
+                        "r" (offsetof (struct pthread, member)));            \
+       }})
+
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* tls.h */
diff --git a/nptl/sysdeps/pthread/Makefile b/nptl/sysdeps/pthread/Makefile
new file mode 100644 (file)
index 0000000..fade787
--- /dev/null
@@ -0,0 +1,33 @@
+# Copyright (C) 2002 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+# Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+# The GNU C Library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+
+# The GNU C Library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public
+# License along with the GNU C Library; if not, write to the Free
+# Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+# 02111-1307 USA.
+
+ifeq ($(subdir),nptl)
+libpthread-sysdep_routines += errno-loc
+endif
+
+ifeq ($(subdir),rt)
+librt-sysdep_routines += timer_routines
+CPPFLAGS-timer_routines.c = -I../nptl
+
+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
diff --git a/nptl/sysdeps/pthread/Subdirs b/nptl/sysdeps/pthread/Subdirs
new file mode 100644 (file)
index 0000000..4d1f4d8
--- /dev/null
@@ -0,0 +1 @@
+nptl_db
diff --git a/nptl/sysdeps/pthread/allocalim.h b/nptl/sysdeps/pthread/allocalim.h
new file mode 100644 (file)
index 0000000..2d666c0
--- /dev/null
@@ -0,0 +1,29 @@
+/* Determine whether block of given size can be allocated on the stack or not.
+   Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU 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 <alloca.h>
+#include <limits.h>
+
+
+extern inline int
+__libc_use_alloca (size_t size)
+{
+  return (__builtin_expect (size <= PTHREAD_STACK_MIN / 4, 1)
+         || __libc_alloca_cutoff (size));
+}
diff --git a/nptl/sysdeps/pthread/bits/libc-lock.h b/nptl/sysdeps/pthread/bits/libc-lock.h
new file mode 100644 (file)
index 0000000..0001676
--- /dev/null
@@ -0,0 +1,335 @@
+/* libc-internal interface for mutex locks.  LinuxThreads version.
+   Copyright (C) 1996-2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU 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.  */
+
+#ifndef _BITS_LIBC_LOCK_H
+#define _BITS_LIBC_LOCK_H 1
+
+#include <pthread.h>
+#define __need_NULL
+#include <stddef.h>
+
+/* 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
+#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 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}
+
+/* Initialize the named lock variable, leaving it in a consistent, unlocked
+   state.  */
+#define __libc_lock_init(NAME) \
+  (__pthread_mutex_init != NULL ? __pthread_mutex_init (&(NAME), NULL) : 0);
+#define __libc_rwlock_init(NAME) \
+  (__pthread_rwlock_init != NULL ? __pthread_rwlock_init (&(NAME), NULL) : 0);
+
+/* Same as last but this time we initialize a recursive mutex.  */
+#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);
+
+/* 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) \
+  (__pthread_mutex_destroy != NULL ? __pthread_mutex_destroy (&(NAME)) : 0);
+#define __libc_rwlock_fini(NAME) \
+  (__pthread_rwlock_destroy != NULL ? __pthread_rwlock_destroy (&(NAME)) : 0);
+
+/* Finalize recursive named lock.  */
+#define __libc_lock_fini_recursive(NAME) __libc_lock_fini ((NAME).mutex)
+
+/* Lock the named lock variable.  */
+#define __libc_lock_lock(NAME) \
+  (__pthread_mutex_lock != NULL ? __pthread_mutex_lock (&(NAME)) : 0);
+#define __libc_rwlock_rdlock(NAME) \
+  (__pthread_rwlock_rdlock != NULL ? __pthread_rwlock_rdlock (&(NAME)) : 0);
+#define __libc_rwlock_wrlock(NAME) \
+  (__pthread_rwlock_wrlock != NULL ? __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) \
+  (__pthread_mutex_trylock != NULL ? __pthread_mutex_trylock (&(NAME)) : 0)
+#define __libc_rwlock_tryrdlock(NAME) \
+  (__pthread_rwlock_tryrdlock != NULL \
+   ? __pthread_rwlock_tryrdlock (&(NAME)) : 0)
+#define __libc_rwlock_trywrlock(NAME) \
+  (__pthread_rwlock_trywrlock != NULL \
+   ? __pthread_rwlock_trywrlock (&(NAME)) : 0)
+
+/* Try to lock the recursive named lock variable.  */
+#define __libc_lock_trylock_recursive(NAME) __libc_lock_trylock ((NAME).mutex)
+
+/* Unlock the named lock variable.  */
+#define __libc_lock_unlock(NAME) \
+  (__pthread_mutex_unlock != NULL ? __pthread_mutex_unlock (&(NAME)) : 0);
+#define __libc_rwlock_unlock(NAME) \
+  (__pthread_rwlock_unlock != NULL ? __pthread_rwlock_unlock (&(NAME)) : 0);
+
+/* Unlock the recursive named lock variable.  */
+#define __libc_lock_unlock_recursive(NAME) __libc_lock_unlock ((NAME).mutex)
+
+
+/* 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) = !PTHREAD_ONCE_INIT;                                   \
+    }                                                                        \
+  } 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));                       \
+    }
+
+/* Create thread-specific key.  */
+#define __libc_key_create(KEY, DESTRUCTOR) \
+  (__pthread_key_create != NULL ? __pthread_key_create (KEY, DESTRUCTOR) : 1)
+
+/* Get thread-specific data.  */
+#define __libc_getspecific(KEY) \
+  (__pthread_getspecific != NULL ? __pthread_getspecific (KEY) : NULL)
+
+/* Set thread-specific data.  */
+#define __libc_setspecific(KEY, VALUE) \
+  (__pthread_setspecific != NULL ? __pthread_setspecific (KEY, VALUE) : 0)
+
+
+/* Register handlers to execute before and after `fork'.  Note that the
+   last parameter is NULL.  The handlers registered by the libc are
+   never removed so this is OK.  */
+#define __libc_atfork(PREPARE, PARENT, CHILD) \
+  __register_atfork (PREPARE, PARENT, CHILD, NULL)
+extern int __register_atfork (void (*__prepare) (void),
+                             void (*__parent) (void),
+                             void (*__child) (void),
+                             void *__dso_handle);
+
+/* Functions that are used by this file and are internal to the GNU C
+   library.  */
+
+extern int __pthread_mutex_init (pthread_mutex_t *__mutex,
+                                __const pthread_mutexattr_t *__mutex_attr);
+
+extern int __pthread_mutex_destroy (pthread_mutex_t *__mutex);
+
+extern int __pthread_mutex_trylock (pthread_mutex_t *__mutex);
+
+extern int __pthread_mutex_lock (pthread_mutex_t *__mutex);
+
+extern int __pthread_mutex_unlock (pthread_mutex_t *__mutex);
+
+extern int __pthread_mutexattr_init (pthread_mutexattr_t *__attr);
+
+extern int __pthread_mutexattr_destroy (pthread_mutexattr_t *__attr);
+
+extern int __pthread_mutexattr_settype (pthread_mutexattr_t *__attr,
+                                       int __kind);
+
+#ifdef __USE_UNIX98
+extern int __pthread_rwlock_init (pthread_rwlock_t *__rwlock,
+                                 __const pthread_rwlockattr_t *__attr);
+
+extern int __pthread_rwlock_destroy (pthread_rwlock_t *__rwlock);
+
+extern int __pthread_rwlock_rdlock (pthread_rwlock_t *__rwlock);
+
+extern int __pthread_rwlock_tryrdlock (pthread_rwlock_t *__rwlock);
+
+extern int __pthread_rwlock_wrlock (pthread_rwlock_t *__rwlock);
+
+extern int __pthread_rwlock_trywrlock (pthread_rwlock_t *__rwlock);
+
+extern int __pthread_rwlock_unlock (pthread_rwlock_t *__rwlock);
+#endif
+
+extern int __pthread_key_create (pthread_key_t *__key,
+                                void (*__destr_function) (void *));
+
+extern int __pthread_setspecific (pthread_key_t __key,
+                                 __const void *__pointer);
+
+extern void *__pthread_getspecific (pthread_key_t __key);
+
+extern int __pthread_once (pthread_once_t *__once_control,
+                          void (*__init_routine) (void));
+
+extern int __pthread_atfork (void (*__prepare) (void),
+                            void (*__parent) (void),
+                            void (*__child) (void));
+
+
+
+/* Make the pthread functions weak so that we can elide them from
+   single-threaded processes.  */
+#ifndef __NO_WEAK_PTHREAD_ALIASES
+# ifdef weak_extern
+#  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_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
+# 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/nptl/sysdeps/pthread/bits/sigthread.h b/nptl/sysdeps/pthread/bits/sigthread.h
new file mode 100644 (file)
index 0000000..df2bcac
--- /dev/null
@@ -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 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.  */
+
+#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/nptl/sysdeps/pthread/list.h b/nptl/sysdeps/pthread/list.h
new file mode 100644 (file)
index 0000000..1d6a4cf
--- /dev/null
@@ -0,0 +1,116 @@
+/* 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
+
+#include <assert.h>
+
+/* 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/nptl/sysdeps/pthread/posix-timer.h b/nptl/sysdeps/pthread/posix-timer.h
new file mode 100644 (file)
index 0000000..6710291
--- /dev/null
@@ -0,0 +1,210 @@
+/* Definitions for POSIX timer implementation on top of LinuxThreads.
+   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 <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;
+#ifdef _POSIX_CPUTIME
+extern struct thread_node __timer_signal_thread_pclk;
+#endif
+#ifdef _POSIX_THREAD_CPUTIME
+extern struct thread_node __timer_signal_thread_tclk;
+#endif
+
+
+/* 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/nptl/sysdeps/pthread/pt-initfini.c b/nptl/sysdeps/pthread/pt-initfini.c
new file mode 100644 (file)
index 0000000..55d9f31
--- /dev/null
@@ -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 Library General Public
+   License as published by the Free Software Foundation; either
+   version 2 of the License, or (at your option) any later version.
+
+   In addition to the permissions in the GNU Library General Public
+   License, the Free Software Foundation gives you unlimited
+   permission to link the compiled version of this file with other
+   programs, and to distribute those programs without any restriction
+   coming from the use of this file.  (The Library General Public
+   License restrictions do apply in other respects; for example, they
+   cover modification of the file, and distribution when not linked
+   into another program.)
+
+   The GNU C Library is distributed in the hope that it will be
+   useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+   of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+/* This file is compiled into assembly code which is then munged by a sed
+   script into two files: crti.s and crtn.s.
+
+   * crti.s puts a function prologue at the beginning of the
+   .init and .fini sections and defines global symbols for
+   those addresses, so they can be called as functions.
+
+   * crtn.s puts the corresponding function epilogues
+   in the .init and .fini sections. */
+
+#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/nptl/sysdeps/pthread/pthread.h b/nptl/sysdeps/pthread/pthread.h
new file mode 100644 (file)
index 0000000..d6b0966
--- /dev/null
@@ -0,0 +1,743 @@
+/* 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 _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>
+
+
+/* Detach state.  */
+enum
+{
+  PTHREAD_CREATE_JOINABLE,
+#define PTHREAD_CREATE_JOINABLE        PTHREAD_CREATE_JOINABLE
+  PTHREAD_CREATE_DETACHED
+#define PTHREAD_CREATE_DETACHED        PTHREAD_CREATE_DETACHED
+};
+
+
+/* Mutex handling.  */
+
+#define PTHREAD_MUTEX_INITIALIZER \
+  { }
+
+#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP \
+  { .__data = { .__kind = PTHREAD_MUTEX_RECURSIVE_NP } }
+
+#define PTHREAD_RWLOCK_INITIALIZER \
+  { }
+
+#define PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP \
+  { .__data = { .__flags = PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP } }
+
+enum
+{
+  PTHREAD_MUTEX_TIMED_NP,
+  PTHREAD_MUTEX_RECURSIVE_NP,
+  PTHREAD_MUTEX_ERRORCHECK_NP,
+  PTHREAD_MUTEX_ADAPTIVE_NP
+#ifdef __USE_UNIX98
+  ,
+  PTHREAD_MUTEX_NORMAL = PTHREAD_MUTEX_TIMED_NP,
+  PTHREAD_MUTEX_RECURSIVE = PTHREAD_MUTEX_RECURSIVE_NP,
+  PTHREAD_MUTEX_ERRORCHECK = PTHREAD_MUTEX_ERRORCHECK_NP,
+  PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL
+#endif
+#ifdef __USE_GNU
+  /* For compatibility.  */
+  , PTHREAD_MUTEX_FAST_NP = PTHREAD_MUTEX_TIMED_NP
+#endif
+};
+
+
+/* Read-write lock types.  */
+#ifdef __USE_UNIX98
+enum
+{
+  PTHREAD_RWLOCK_PREFER_READER_NP,
+  PTHREAD_RWLOCK_PREFER_WRITER_NP,
+  PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP,
+  PTHREAD_RWLOCK_DEFAULT_NP = PTHREAD_RWLOCK_PREFER_READER_NP
+};
+#endif  /* Unix98 */
+
+
+/* Scheduler inheritance.  */
+enum
+{
+  PTHREAD_INHERIT_SCHED,
+#define PTHREAD_INHERIT_SCHED   PTHREAD_INHERIT_SCHED
+  PTHREAD_EXPLICIT_SCHED
+#define PTHREAD_EXPLICIT_SCHED  PTHREAD_EXPLICIT_SCHED
+};
+
+
+/* Scope handling.  */
+enum
+{
+  PTHREAD_SCOPE_SYSTEM,
+#define PTHREAD_SCOPE_SYSTEM    PTHREAD_SCOPE_SYSTEM
+  PTHREAD_SCOPE_PROCESS
+#define PTHREAD_SCOPE_PROCESS   PTHREAD_SCOPE_PROCESS
+};
+
+
+/* Process shared or private flag.  */
+enum
+{
+  PTHREAD_PROCESS_PRIVATE,
+#define PTHREAD_PROCESS_PRIVATE PTHREAD_PROCESS_PRIVATE
+  PTHREAD_PROCESS_SHARED
+#define PTHREAD_PROCESS_SHARED  PTHREAD_PROCESS_SHARED
+};
+
+
+
+/* Conditional variable handling.  */
+#define PTHREAD_COND_INITIALIZER { }
+
+
+/* Cleanup buffers */
+struct _pthread_cleanup_buffer
+{
+  void (*__routine) (void *);             /* Function to call.  */
+  void *__arg;                            /* Its argument.  */
+  int __canceltype;                       /* Saved cancellation type. */
+  struct _pthread_cleanup_buffer *__prev; /* Chaining of cleanup functions.  */
+};
+
+/* Cancellation */
+enum
+{
+  PTHREAD_CANCEL_ENABLE,
+#define PTHREAD_CANCEL_ENABLE   PTHREAD_CANCEL_ENABLE
+  PTHREAD_CANCEL_DISABLE
+#define PTHREAD_CANCEL_DISABLE  PTHREAD_CANCEL_DISABLE
+};
+enum
+{
+  PTHREAD_CANCEL_DEFERRED,
+#define PTHREAD_CANCEL_DEFERRED        PTHREAD_CANCEL_DEFERRED
+  PTHREAD_CANCEL_ASYNCHRONOUS
+#define PTHREAD_CANCEL_ASYNCHRONOUS    PTHREAD_CANCEL_ASYNCHRONOUS
+};
+#define PTHREAD_CANCELED ((void *) -1)
+
+
+/* Single execution handling.  */
+#define PTHREAD_ONCE_INIT 0
+
+
+#ifdef __USE_XOPEN2K
+/* Value returned by 'pthread_barrier_wait' for one of the threads after
+   the required number of threads have called this function.
+   -1 is distinct from 0 and all errno constants */
+# define PTHREAD_BARRIER_SERIAL_THREAD -1
+#endif
+
+
+__BEGIN_DECLS
+
+/* Create a new thread, starting with execution of START-ROUTINE
+   getting passed ARG.  Creation attributed come from ATTR.  The new
+   handle is stored in *NEWTHREAD.  */
+extern int pthread_create (pthread_t *__restrict __newthread,
+                          __const pthread_attr_t *__restrict __attr,
+                          void *(*__start_routine) (void *),
+                          void *__restrict __arg) __THROW;
+
+/* Terminate calling thread.  */
+extern void pthread_exit (void *__retval)
+     __THROW __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) __THROW;
+
+#ifdef __USE_GNU
+/* Check whether thread TH has terminated.  If yes return the status of
+   the thread in *THREAD_RETURN, if THREAD_RETURN is not NULL.  */
+extern int pthread_tryjoin_np (pthread_t __th, void **__thread_return) __THROW;
+
+/* Make calling thread wait for termination of the thread TH, but only
+   until TIMEOUT.  The exit status of the thread is stored in
+   *THREAD_RETURN, if THREAD_RETURN is not NULL.  */
+extern int pthread_timedjoin_np (pthread_t __th, void **__thread_return,
+                                __const struct timespec *__abstime) __THROW;
+#endif
+
+/* Indicate that the thread TH is never to be joined with PTHREAD_JOIN.
+   The resources of TH will therefore be freed immediately when it
+   terminates, instead of waiting for another thread to perform PTHREAD_JOIN
+   on it.  */
+extern int pthread_detach (pthread_t __th) __THROW;
+
+
+/* Obtain the identifier of the current thread.  */
+extern pthread_t pthread_self (void) __THROW __attribute__ ((__const__));
+
+/* Compare two thread identifiers.  */
+extern int pthread_equal (pthread_t __thread1, pthread_t __thread2) __THROW;
+
+
+/* Thread attribute handling.  */
+
+/* Initialize thread attribute *ATTR with default attributes
+   (detachstate is PTHREAD_JOINABLE, scheduling policy is SCHED_OTHER,
+    no user-provided stack).  */
+extern int pthread_attr_init (pthread_attr_t *__attr) __THROW;
+
+/* Destroy thread attribute *ATTR.  */
+extern int pthread_attr_destroy (pthread_attr_t *__attr) __THROW;
+
+/* Get detach state attribute.  */
+extern int pthread_attr_getdetachstate (__const pthread_attr_t *__attr,
+                                       int *__detachstate) __THROW;
+
+/* Set detach state attribute.  */
+extern int pthread_attr_setdetachstate (pthread_attr_t *__attr,
+                                       int __detachstate) __THROW;
+
+
+/* Get the size of the guard area created for stack overflow protection.  */
+extern int pthread_attr_getguardsize (__const pthread_attr_t *__attr,
+                                     size_t *__guardsize) __THROW;
+
+/* Set the size of the guard area created for stack overflow protection.  */
+extern int pthread_attr_setguardsize (pthread_attr_t *__attr,
+                                     size_t __guardsize) __THROW;
+
+
+/* Return in *PARAM the scheduling parameters of *ATTR.  */
+extern int pthread_attr_getschedparam (__const pthread_attr_t *__restrict
+                                      __attr,
+                                      struct sched_param *__restrict __param)
+     __THROW;
+
+/* Set scheduling parameters (priority, etc) in *ATTR according to PARAM.  */
+extern int pthread_attr_setschedparam (pthread_attr_t *__restrict __attr,
+                                      __const struct sched_param *__restrict
+                                      __param) __THROW;
+
+/* Return in *POLICY the scheduling policy of *ATTR.  */
+extern int pthread_attr_getschedpolicy (__const pthread_attr_t *__restrict
+                                       __attr, int *__restrict __policy)
+     __THROW;
+
+/* Set scheduling policy in *ATTR according to POLICY.  */
+extern int pthread_attr_setschedpolicy (pthread_attr_t *__attr, int __policy)
+     __THROW;
+
+/* Return in *INHERIT the scheduling inheritance mode of *ATTR.  */
+extern int pthread_attr_getinheritsched (__const pthread_attr_t *__restrict
+                                        __attr, int *__restrict __inherit)
+     __THROW;
+
+/* Set scheduling inheritance mode in *ATTR according to INHERIT.  */
+extern int pthread_attr_setinheritsched (pthread_attr_t *__attr,
+                                        int __inherit) __THROW;
+
+
+/* Return in *SCOPE the scheduling contention scope of *ATTR.  */
+extern int pthread_attr_getscope (__const pthread_attr_t *__restrict __attr,
+                                 int *__restrict __scope) __THROW;
+
+/* Set scheduling contention scope in *ATTR according to SCOPE.  */
+extern int pthread_attr_setscope (pthread_attr_t *__attr, int __scope)
+     __THROW;
+
+/* Return the previously set address for the stack.  */
+extern int pthread_attr_getstackaddr (__const pthread_attr_t *__restrict
+                                     __attr, void **__restrict __stackaddr)
+     __THROW;
+
+/* 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_SIZE.  */
+extern int pthread_attr_setstackaddr (pthread_attr_t *__attr,
+                                     void *__stackaddr) __THROW;
+
+/* Return the currently used minimal stack size.  */
+extern int pthread_attr_getstacksize (__const pthread_attr_t *__restrict
+                                     __attr, size_t *__restrict __stacksize)
+     __THROW;
+
+/* Add information about the minimum stack size needed for the thread
+   to be started.  This size must never be less than PTHREAD_STACK_SIZE
+   and must also not exceed the system limits.  */
+extern int pthread_attr_setstacksize (pthread_attr_t *__attr,
+                                     size_t __stacksize) __THROW;
+
+#ifdef __USE_XOPEN2K
+/* Return the previously set address for the stack.  */
+extern int pthread_attr_getstack (__const pthread_attr_t *__restrict __attr,
+                                 void **__restrict __stackaddr,
+                                 size_t *__restrict __stacksize) __THROW;
+
+/* The following two interfaces are intended to replace the last two.  They
+   require setting the address as well as the size since only setting the
+   address will make the implementation on some architectures impossible.  */
+extern int pthread_attr_setstack (pthread_attr_t *__attr, void *__stackaddr,
+                                 size_t __stacksize) __THROW;
+#endif
+
+#ifdef __USE_GNU
+/* Get thread attributes corresponding to the already running thread TH.  */
+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 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.  */
+extern int pthread_once (pthread_once_t *__once_control,
+                        void (*__init_routine) (void)) __THROW;
+
+
+/* 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) __THROW;
+
+/* 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) __THROW;
+
+/* Cancel THREAD immediately or at the next possibility.  */
+extern int pthread_cancel (pthread_t __th) __THROW;
+
+/* 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) __THROW;
+
+
+/* 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;
+
+#ifdef __USE_GNU
+/* Install a cleanup handler as pthread_cleanup_push does, but also
+   saves the current cancellation type and sets it to deferred
+   cancellation.  */
+# define pthread_cleanup_push_defer_np(routine,arg) \
+  { 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
+
+
+/* Mutex handling.  */
+
+/* Initialize a mutex.  */
+extern int pthread_mutex_init (pthread_mutex_t *__mutex,
+                              __const pthread_mutexattr_t *__mutexattr)
+     __THROW;
+
+/* Destroy a mutex.  */
+extern int pthread_mutex_destroy (pthread_mutex_t *__mutex) __THROW;
+
+/* Try locking a mutex.  */
+extern int pthread_mutex_trylock (pthread_mutex_t *_mutex) __THROW;
+
+/* Lock a mutex.  */
+extern int pthread_mutex_lock (pthread_mutex_t *__mutex) __THROW;
+
+#ifdef __USE_XOPEN2K
+/* Wait until lock becomes available, or specified time passes. */
+extern int pthread_mutex_timedlock (pthread_mutex_t *__restrict __mutex,
+                                    __const struct timespec *__restrict
+                                    __abstime) __THROW;
+#endif
+
+/* Unlock a mutex.  */
+extern int pthread_mutex_unlock (pthread_mutex_t *__mutex) __THROW;
+
+
+/* Functions for handling mutex attributes.  */
+
+/* Initialize mutex attribute object ATTR with default attributes
+   (kind is PTHREAD_MUTEX_TIMED_NP).  */
+extern int pthread_mutexattr_init (pthread_mutexattr_t *__attr) __THROW;
+
+/* Destroy mutex attribute object ATTR.  */
+extern int pthread_mutexattr_destroy (pthread_mutexattr_t *__attr) __THROW;
+
+/* Get the process-shared flag of the mutex attribute ATTR.  */
+extern int pthread_mutexattr_getpshared (__const pthread_mutexattr_t *
+                                        __restrict __attr,
+                                        int *__restrict __pshared) __THROW;
+
+/* Set the process-shared flag of the mutex attribute ATTR.  */
+extern int pthread_mutexattr_setpshared (pthread_mutexattr_t *__attr,
+                                        int __pshared) __THROW;
+
+#ifdef __USE_UNIX98
+/* Return in *KIND the mutex kind attribute in *ATTR.  */
+extern int pthread_mutexattr_gettype (__const pthread_mutexattr_t *__restrict
+                                     __attr, int *__restrict __kind) __THROW;
+
+/* Set the mutex kind attribute in *ATTR to KIND (either PTHREAD_MUTEX_NORMAL,
+   PTHREAD_MUTEX_RECURSIVE, PTHREAD_MUTEX_ERRORCHECK, or
+   PTHREAD_MUTEX_DEFAULT).  */
+extern int pthread_mutexattr_settype (pthread_mutexattr_t *__attr, int __kind)
+     __THROW;
+#endif
+
+
+#ifdef __USE_UNIX98
+/* Functions for handling read-write locks.  */
+
+/* Initialize read-write lock RWLOCK using attributes ATTR, or use
+   the default values if later is NULL.  */
+extern int pthread_rwlock_init (pthread_rwlock_t *__restrict __rwlock,
+                               __const pthread_rwlockattr_t *__restrict
+                               __attr) __THROW;
+
+/* Destroy read-write lock RWLOCK.  */
+extern int pthread_rwlock_destroy (pthread_rwlock_t *__rwlock) __THROW;
+
+/* Acquire read lock for RWLOCK.  */
+extern int pthread_rwlock_rdlock (pthread_rwlock_t *__rwlock) __THROW;
+
+/* Try to acquire read lock for RWLOCK.  */
+extern int pthread_rwlock_tryrdlock (pthread_rwlock_t *__rwlock) __THROW;
+
+# ifdef __USE_XOPEN2K
+/* Try to acquire read lock for RWLOCK or return after specfied time.  */
+extern int pthread_rwlock_timedrdlock (pthread_rwlock_t *__restrict __rwlock,
+                                      __const struct timespec *__restrict
+                                      __abstime) __THROW;
+# endif
+
+/* Acquire write lock for RWLOCK.  */
+extern int pthread_rwlock_wrlock (pthread_rwlock_t *__rwlock) __THROW;
+
+/* Try to acquire write lock for RWLOCK.  */
+extern int pthread_rwlock_trywrlock (pthread_rwlock_t *__rwlock) __THROW;
+
+# ifdef __USE_XOPEN2K
+/* Try to acquire write lock for RWLOCK or return after specfied time.  */
+extern int pthread_rwlock_timedwrlock (pthread_rwlock_t *__restrict __rwlock,
+                                      __const struct timespec *__restrict
+                                      __abstime) __THROW;
+# endif
+
+/* Unlock RWLOCK.  */
+extern int pthread_rwlock_unlock (pthread_rwlock_t *__rwlock) __THROW;
+
+
+/* Functions for handling read-write lock attributes.  */
+
+/* Initialize attribute object ATTR with default values.  */
+extern int pthread_rwlockattr_init (pthread_rwlockattr_t *__attr) __THROW;
+
+/* Destroy attribute object ATTR.  */
+extern int pthread_rwlockattr_destroy (pthread_rwlockattr_t *__attr) __THROW;
+
+/* Return current setting of process-shared attribute of ATTR in PSHARED.  */
+extern int pthread_rwlockattr_getpshared (__const pthread_rwlockattr_t *
+                                         __restrict __attr,
+                                         int *__restrict __pshared) __THROW;
+
+/* Set process-shared attribute of ATTR to PSHARED.  */
+extern int pthread_rwlockattr_setpshared (pthread_rwlockattr_t *__attr,
+                                         int __pshared) __THROW;
+
+/* Return current setting of reader/writer preference.  */
+extern int pthread_rwlockattr_getkind_np (__const pthread_rwlockattr_t *
+                                         __restrict __attr,
+                                         int *__restrict __pref) __THROW;
+
+/* Set reader/write preference.  */
+extern int pthread_rwlockattr_setkind_np (pthread_rwlockattr_t *__attr,
+                                         int __pref) __THROW;
+#endif
+
+
+/* Functions for handling conditional variables.  */
+
+/* Initialize condition variable COND using attributes ATTR, or use
+   the default values if later is NULL.  */
+extern int pthread_cond_init (pthread_cond_t *__restrict __cond,
+                             __const pthread_condattr_t *__restrict
+                             __cond_attr) __THROW;
+
+/* Destroy condition variable COND.  */
+extern int pthread_cond_destroy (pthread_cond_t *__cond) __THROW;
+
+/* Wake up one thread waiting for condition variable COND.  */
+extern int pthread_cond_signal (pthread_cond_t *__cond) __THROW;
+
+/* Wake up all threads waiting for condition variables COND.  */
+extern int pthread_cond_broadcast (pthread_cond_t *__cond) __THROW;
+
+/* Wait for condition variable COND to be signaled or broadcast.
+   MUTEX is assumed to be locked before.  */
+extern int pthread_cond_wait (pthread_cond_t *__restrict __cond,
+                             pthread_mutex_t *__restrict __mutex) __THROW;
+
+/* 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) __THROW;
+
+/* Functions for handling condition variable attributes.  */
+
+/* Initialize condition variable attribute ATTR.  */
+extern int pthread_condattr_init (pthread_condattr_t *__attr) __THROW;
+
+/* Destroy condition variable attribute ATTR.  */
+extern int pthread_condattr_destroy (pthread_condattr_t *__attr) __THROW;
+
+/* Get the process-shared flag of the condition variable attribute ATTR.  */
+extern int pthread_condattr_getpshared (__const pthread_condattr_t *
+                                        __restrict __attr,
+                                        int *__restrict __pshared) __THROW;
+
+/* Set the process-shared flag of the condition variable attribute ATTR.  */
+extern int pthread_condattr_setpshared (pthread_condattr_t *__attr,
+                                        int __pshared) __THROW;
+
+
+
+#ifdef __USE_XOPEN2K
+/* Functions to handle spinlocks.  */
+
+/* Initialize the spinlock LOCK.  If PSHARED is nonzero the spinlock can
+   be shared between different processes.  */
+extern int pthread_spin_init (pthread_spinlock_t *__lock, int __pshared)
+     __THROW;
+
+/* Destroy the spinlock LOCK.  */
+extern int pthread_spin_destroy (pthread_spinlock_t *__lock) __THROW;
+
+/* Wait until spinlock LOCK is retrieved.  */
+extern int pthread_spin_lock (pthread_spinlock_t *__lock) __THROW;
+
+/* Try to lock spinlock LOCK.  */
+extern int pthread_spin_trylock (pthread_spinlock_t *__lock) __THROW;
+
+/* Release spinlock LOCK.  */
+extern int pthread_spin_unlock (pthread_spinlock_t *__lock) __THROW;
+
+
+/* Functions to handle barriers.  */
+
+/* Initialize BARRIER with the attributes in ATTR.  The barrier is
+   opened when COUNT waiters arrived.  */
+extern int pthread_barrier_init (pthread_barrier_t *__restrict __barrier,
+                                __const pthread_barrierattr_t *__restrict
+                                __attr, unsigned int __count) __THROW;
+
+/* Destroy a previously dynamically initialized barrier BARRIER.  */
+extern int pthread_barrier_destroy (pthread_barrier_t *__barrier) __THROW;
+
+/* Wait on barrier BARRIER.  */
+extern int pthread_barrier_wait (pthread_barrier_t *__barrier) __THROW;
+
+
+/* Initialize barrier attribute ATTR.  */
+extern int pthread_barrierattr_init (pthread_barrierattr_t *__attr) __THROW;
+
+/* Destroy previously dynamically initialized barrier attribute ATTR.  */
+extern int pthread_barrierattr_destroy (pthread_barrierattr_t *__attr) __THROW;
+
+/* Get the process-shared flag of the barrier attribute ATTR.  */
+extern int pthread_barrierattr_getpshared (__const pthread_barrierattr_t *
+                                          __restrict __attr,
+                                          int *__restrict __pshared) __THROW;
+
+/* Set the process-shared flag of the barrier attribute ATTR.  */
+extern int pthread_barrierattr_setpshared (pthread_barrierattr_t *__attr,
+                                           int __pshared) __THROW;
+#endif
+
+
+/* Functions for handling thread-specific data.  */
+
+/* Create a key value identifying a location in the thread-specific
+   data area.  Each thread maintains a distinct thread-specific data
+   area.  DESTR_FUNCTION, if non-NULL, is called with the value
+   associated to that key when the key is destroyed.
+   DESTR_FUNCTION is not called if the value associated is NULL when
+   the key is destroyed.  */
+extern int pthread_key_create (pthread_key_t *__key,
+                              void (*__destr_function) (void *)) __THROW;
+
+/* Destroy KEY.  */
+extern int pthread_key_delete (pthread_key_t __key) __THROW;
+
+/* Return current value of the thread-specific data slot identified by KEY.  */
+extern void *pthread_getspecific (pthread_key_t __key) __THROW;
+
+/* Store POINTER in the thread-specific data slot identified by KEY. */
+extern int pthread_setspecific (pthread_key_t __key,
+                               __const void *__pointer) __THROW;
+
+
+/* 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;
+
+
+#ifdef __USE_GNU
+/* Install a cleanup handler as pthread_cleanup_push does, but also
+   saves the current cancellation type and set it to deferred cancellation.  */
+# 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
+
+
+/* Install handlers to be called when a new process is created with FORK.
+   The PREPARE handler is called in the parent process just before performing
+   FORK. The PARENT handler is called in the parent process just after FORK.
+   The CHILD handler is called in the child process.  Each of the three
+   handlers can be NULL, meaning that no handler needs to be called at that
+   point.
+   PTHREAD_ATFORK can be called several times, in which case the PREPARE
+   handlers are called in LIFO order (last added with PTHREAD_ATFORK,
+   first called before FORK), and the PARENT and CHILD handlers are called
+   in FIFO (first added, first called).  */
+
+extern int pthread_atfork (void (*__prepare) (void),
+                          void (*__parent) (void),
+                          void (*__child) (void)) __THROW;
+
+__END_DECLS
+
+#endif /* pthread.h */
diff --git a/nptl/sysdeps/pthread/pthread_getcpuclockid.c b/nptl/sysdeps/pthread/pthread_getcpuclockid.c
new file mode 100644 (file)
index 0000000..62761f9
--- /dev/null
@@ -0,0 +1,43 @@
+/* Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General 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 <tls.h>
+
+
+int
+pthread_getcpuclockid (thread_id, clock_id)
+     pthread_t thread_id;
+     clockid_t *clock_id;
+{
+  /* We don't allow any process ID but our own.  */
+  if ((struct pthread *) thread_id != THREAD_SELF)
+    return EPERM;
+
+#ifdef CLOCK_THREAD_CPUTIME_ID
+  /* Store the number.  */
+  *clock_id = CLOCK_THREAD_CPUTIME_ID;
+
+  return 0;
+#else
+  /* We don't have a timer for that.  */
+  return ENOENT;
+#endif
+}
diff --git a/nptl/sysdeps/pthread/pthread_once.c b/nptl/sysdeps/pthread/pthread_once.c
new file mode 100644 (file)
index 0000000..9b2cef8
--- /dev/null
@@ -0,0 +1,54 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+#include <lowlevellock.h>
+
+
+
+static lll_lock_t once_lock = LLL_LOCK_INITIALIZER;
+
+
+int
+__pthread_once (once_control, init_routine)
+     pthread_once_t *once_control;
+     void (*init_routine) (void);
+{
+  /* XXX Depending on whether the LOCK_IN_ONCE_T is defined use a
+     global lock variable or one which is part of the pthread_once_t
+     object.  */
+  if (*once_control == PTHREAD_ONCE_INIT)
+    {
+      lll_lock (once_lock);
+
+      /* XXX This implementation is not complete.  It doesn't take
+        cancelation and fork into account.  */
+      if (*once_control == PTHREAD_ONCE_INIT)
+       {
+         init_routine ();
+
+         *once_control = !PTHREAD_ONCE_INIT;
+       }
+
+      lll_unlock (once_lock);
+    }
+
+  return 0;
+}
+strong_alias (__pthread_once, pthread_once)
diff --git a/nptl/sysdeps/pthread/pthread_sigmask.c b/nptl/sysdeps/pthread/pthread_sigmask.c
new file mode 100644 (file)
index 0000000..8ec7cf8
--- /dev/null
@@ -0,0 +1,44 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <signal.h>
+#include <pthreadP.h>
+
+
+int
+pthread_sigmask (how, newmask, oldmask)
+     int how;
+     const sigset_t *newmask;
+     sigset_t *oldmask;
+{
+  sigset_t local_newmask;
+
+  /* The only thing we have to make sure here is that SIGCANCEL is not
+     blocked.  */
+  if (newmask != NULL
+      && (how == SIG_SETMASK || how == SIG_BLOCK)
+      && sigismember (newmask, SIGCANCEL))
+    {
+      local_newmask = *newmask;
+      sigdelset (&local_newmask, SIGCANCEL);
+      newmask = &local_newmask;
+    }
+
+  return sigprocmask (how, newmask, oldmask);
+}
diff --git a/nptl/sysdeps/pthread/sigaction.c b/nptl/sysdeps/pthread/sigaction.c
new file mode 100644 (file)
index 0000000..c3f6f43
--- /dev/null
@@ -0,0 +1,24 @@
+/* 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.  */
+
+/* We use the libc implementation but we tell it to not allow
+   SIGCANCEL to be handled.  */
+#define SIGCANCEL __SIGRTMIN
+
+#include_next <sigaction.c>
diff --git a/nptl/sysdeps/pthread/timer_create.c b/nptl/sysdeps/pthread/timer_create.c
new file mode 100644 (file)
index 0000000..b34f70e
--- /dev/null
@@ -0,0 +1,179 @@
+/* Copyright (C) 2000 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 (clock_id != CLOCK_REALTIME
+#ifdef _POSIX_CPUTIME
+      && clock_id != CLOCK_PROCESS_CPUTIME_ID
+#endif
+#ifdef _POSIX_THREAD_CPUTIME
+      && clock_id != CLOCK_THREAD_CPUTIME_ID
+#endif
+      )
+    {
+      __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:
+      /* This is a strange choice!  */
+      break;
+
+    case SIGEV_SIGNAL:
+      /* We have a global thread for delivering timed signals.
+        If it is not running, try to start it up.  */
+      switch (clock_id)
+       {
+       case CLOCK_REALTIME:
+       default:
+         thread = &__timer_signal_thread_rclk;
+         break;
+#ifdef _POSIX_CPUTIME
+       case CLOCK_PROCESS_CPUTIME_ID:
+         thread = &__timer_signal_thread_pclk;
+         break;
+#endif
+#ifdef _POSIX_THREAD_CPUTIME
+       case CLOCK_THREAD_CPUTIME_ID:
+         thread = &__timer_signal_thread_tclk;
+         break;
+#endif
+       }
+
+      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_dealloc (newtimer);
+    }
+
+  pthread_mutex_unlock (&__timer_mutex);
+
+  return retval;
+}
diff --git a/nptl/sysdeps/pthread/timer_delete.c b/nptl/sysdeps/pthread/timer_delete.c
new file mode 100644 (file)
index 0000000..48ba1f2
--- /dev/null
@@ -0,0 +1,70 @@
+/* Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Kaz Kylheku <kaz@ashi.footprints.net>.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <assert.h>
+#include <errno.h>
+#include <pthread.h>
+#include <time.h>
+
+#include "posix-timer.h"
+
+
+/* Delete timer TIMERID.  */
+int
+timer_delete (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/nptl/sysdeps/pthread/timer_getoverr.c b/nptl/sysdeps/pthread/timer_getoverr.c
new file mode 100644 (file)
index 0000000..f3e2221
--- /dev/null
@@ -0,0 +1,45 @@
+/* Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Kaz Kylheku <kaz@ashi.footprints.net>.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <time.h>
+
+#include "posix-timer.h"
+
+
+/* Get expiration overrun for timer TIMERID.  */
+int
+timer_getoverrun (timerid)
+     timer_t timerid;
+{
+  struct timer_node *timer;
+  int retval = -1;
+
+  pthread_mutex_lock (&__timer_mutex);
+
+  if (! timer_valid (timer = timer_id2ptr (timerid)))
+    __set_errno (EINVAL);
+  else
+    retval = timer->overrun_count;
+
+  pthread_mutex_unlock (&__timer_mutex);
+
+  return retval;
+}
diff --git a/nptl/sysdeps/pthread/timer_gettime.c b/nptl/sysdeps/pthread/timer_gettime.c
new file mode 100644 (file)
index 0000000..99a0803
--- /dev/null
@@ -0,0 +1,71 @@
+/* Copyright (C) 2000 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);
+         timespec_sub (&value->it_value, &expiry, &now);
+       }
+      else
+       {
+         value->it_value.tv_sec = 0;
+         value->it_value.tv_nsec = 0;
+       }
+
+      retval = 0;
+    }
+  else
+    __set_errno (EINVAL);
+
+  return retval;
+}
diff --git a/nptl/sysdeps/pthread/timer_routines.c b/nptl/sysdeps/pthread/timer_routines.c
new file mode 100644 (file)
index 0000000..ddd8afe
--- /dev/null
@@ -0,0 +1,592 @@
+/* Helper code for POSIX timer implementation on LinuxThreads.
+   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 <assert.h>
+#include <errno.h>
+#include <pthread.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysdep.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+
+#include "posix-timer.h"
+#include <pthreadP.h>
+
+
+/* Number of threads used.  */
+#define THREAD_MAXNODES        16
+
+/* Array containing the descriptors for the used threads.  */
+static struct thread_node thread_array[THREAD_MAXNODES];
+
+/* Static array with the structures for all the timers.  */
+struct timer_node __timer_array[TIMER_MAX];
+
+/* Global lock to protect operation on the lists.  */
+pthread_mutex_t __timer_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/* Variable to protext initialization.  */
+pthread_once_t __timer_init_once_control = PTHREAD_ONCE_INIT;
+
+/* Nonzero if initialization of timer implementation failed.  */
+int __timer_init_failed;
+
+/* Node for the thread used to deliver signals.  */
+struct thread_node __timer_signal_thread_rclk;
+#ifdef _POSIX_CPUTIME
+struct thread_node __timer_signal_thread_pclk;
+#endif
+#ifdef _POSIX_THREAD_CPUTIME
+struct thread_node __timer_signal_thread_tclk;
+#endif
+
+/* 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);
+#ifdef _POSIX_CPUTIME
+  thread_init (&__timer_signal_thread_pclk, 0, CLOCK_PROCESS_CPUTIME_ID);
+#endif
+#ifdef _POSIX_THREAD_CPUTIME
+  thread_init (&__timer_signal_thread_tclk, 0, CLOCK_THREAD_CPUTIME_ID);
+#endif
+}
+
+
+/* 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);
+#ifdef _POSIX_CPUTIME
+      assert (thread != &__timer_signal_thread_pclk);
+#endif
+#ifdef _POSIX_THREAD_CPUTIME
+      assert (thread != &__timer_signal_thread_tclk);
+#endif
+
+      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:
+      assert (! "timer_create should never have created such a timer");
+      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)
+{
+  struct pthread_attr *ileft = (struct pthread_attr *) left;
+  struct pthread_attr *iright = (struct pthread_attr *) right;
+
+  return (ileft->flags == iright->flags
+         && ileft->schedpolicy == iright->schedpolicy
+         && (ileft->schedparam.sched_priority
+             == iright->schedparam.sched_priority));
+}
+
+
+/* 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)
+       {
+         list_unlink (iter);
+         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/nptl/sysdeps/pthread/timer_settime.c b/nptl/sysdeps/pthread/timer_settime.c
new file mode 100644 (file)
index 0000000..592b527
--- /dev/null
@@ -0,0 +1,137 @@
+/* Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Kaz Kylheku <kaz@ashi.footprints.net>.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <time.h>
+
+#include "posix-timer.h"
+
+
+/* Set timer TIMERID to VALUE, returning old value in OVLAUE.  */
+int
+timer_settime (timerid, flags, value, ovalue)
+     timer_t timerid;
+     int flags;
+     const struct itimerspec *value;
+     struct itimerspec *ovalue;
+{
+  struct timer_node *timer;
+  struct thread_node *thread = NULL;
+  struct timespec now;
+  int have_now = 0, need_wakeup = 0;
+  int retval = -1;
+
+  timer = timer_id2ptr (timerid);
+  if (timer == NULL)
+    {
+      __set_errno (EINVAL);
+      goto bail;
+    }
+
+  if (value->it_interval.tv_nsec < 0
+      || value->it_interval.tv_nsec >= 1000000000
+      || value->it_value.tv_nsec < 0
+      || value->it_value.tv_nsec >= 1000000000)
+    {
+      __set_errno (EINVAL);
+      goto bail;
+    }
+
+  /* Will need to know current time since this is a relative timer;
+     might as well make the system call outside of the lock now! */
+
+  if ((flags & TIMER_ABSTIME) == 0)
+    {
+      clock_gettime (timer->clock, &now);
+      have_now = 1;
+    }
+
+  pthread_mutex_lock (&__timer_mutex);
+  timer_addref (timer);
+
+  /* One final check of timer validity; this one is possible only
+     until we have the mutex, because it accesses the inuse flag. */
+
+  if (! timer_valid(timer))
+    {
+      __set_errno (EINVAL);
+      goto unlock_bail;
+    }
+
+  if (ovalue != NULL)
+    {
+      ovalue->it_interval = timer->value.it_interval;
+
+      if (timer->armed)
+       {
+         if (! have_now)
+           {
+             pthread_mutex_unlock (&__timer_mutex);
+             clock_gettime (timer->clock, &now);
+             have_now = 1;
+             pthread_mutex_lock (&__timer_mutex);
+             timer_addref (timer);
+           }
+
+         timespec_sub (&ovalue->it_value, &timer->expirytime, &now);
+       }
+      else
+       {
+         ovalue->it_value.tv_sec = 0;
+         ovalue->it_value.tv_nsec = 0;
+       }
+    }
+
+  timer->value = *value;
+
+  list_unlink_ip (&timer->links);
+  timer->armed = 0;
+
+  thread = timer->thread;
+
+  /* A value of { 0, 0 } causes the timer to be stopped. */
+  if (value->it_value.tv_sec != 0
+      || __builtin_expect (value->it_value.tv_nsec != 0, 1))
+    {
+      if ((flags & TIMER_ABSTIME) != 0)
+       /* The user specified the expiration time.  */
+       timer->expirytime = value->it_value;
+      else
+       timespec_add (&timer->expirytime, &now, &value->it_value);
+
+      /* Only need to wake up the thread if timer is inserted
+        at the head of the queue. */
+      if (thread != NULL)
+       need_wakeup = __timer_thread_queue_timer (thread, timer);
+      timer->armed = 1;
+    }
+
+  retval = 0;
+
+unlock_bail:
+  timer_delref (timer);
+  pthread_mutex_unlock (&__timer_mutex);
+
+bail:
+  if (thread != NULL && need_wakeup)
+    __timer_thread_wakeup (thread);
+
+  return retval;
+}
diff --git a/nptl/sysdeps/pthread/tst-timer.c b/nptl/sysdeps/pthread/tst-timer.c
new file mode 100644 (file)
index 0000000..7417bcd
--- /dev/null
@@ -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/nptl/sysdeps/unix/sysv/linux/Implies b/nptl/sysdeps/unix/sysv/linux/Implies
new file mode 100644 (file)
index 0000000..f1b3e89
--- /dev/null
@@ -0,0 +1 @@
+pthread
diff --git a/nptl/sysdeps/unix/sysv/linux/Makefile b/nptl/sysdeps/unix/sysv/linux/Makefile
new file mode 100644 (file)
index 0000000..efe4ba4
--- /dev/null
@@ -0,0 +1,24 @@
+# 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.  */
+
+ifeq ($(subdir),nptl)
+sysdep_routines += register-atfork unregister-atfork fork-gen lowlevellock
+
+libpthread-sysdep_routines += pt-fork
+endif
diff --git a/nptl/sysdeps/unix/sysv/linux/Versions b/nptl/sysdeps/unix/sysv/linux/Versions
new file mode 100644 (file)
index 0000000..117598c
--- /dev/null
@@ -0,0 +1,12 @@
+libc {
+  GLIBC_PRIVATE {
+    __register_atfork; __register_pthread_fork_handler;
+    __libc_current_sigrtmin_private; __libc_current_sigrtmax_private;
+    __libc_allocate_rtsig_private;
+  }
+}
+libpthread {
+  GLIBC_2.0 {
+    fork; __fork;
+  }
+}
diff --git a/nptl/sysdeps/unix/sysv/linux/allocrtsig.c b/nptl/sysdeps/unix/sysv/linux/allocrtsig.c
new file mode 100644 (file)
index 0000000..5badaea
--- /dev/null
@@ -0,0 +1,54 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <signal.h>
+
+
+static int current_rtmin = __SIGRTMIN + 1;
+static int current_rtmax = __SIGRTMAX;
+
+
+/* We reserve __SIGRTMIN for use as the cancelation signal.  This
+   signal is used internally.  */
+int
+__libc_current_sigrtmin (void)
+{
+  return current_rtmin;
+}
+strong_alias (__libc_current_sigrtmin, __libc_current_sigrtmin_private)
+
+
+int
+__libc_current_sigrtmax (void)
+{
+  return current_rtmax;
+}
+strong_alias (__libc_current_sigrtmax, __libc_current_sigrtmax_private)
+
+
+int
+__libc_allocate_rtsig (int high)
+{
+  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/nptl/sysdeps/unix/sysv/linux/bits/local_lim.h b/nptl/sysdeps/unix/sysv/linux/bits/local_lim.h
new file mode 100644 (file)
index 0000000..63de09a
--- /dev/null
@@ -0,0 +1,80 @@
+/* Minimum guaranteed maximum values for system limits.  Linux version.
+   Copyright (C) 1993,94,95,96,97,98,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 Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+/* The kernel header pollutes the namespace with the NR_OPEN symbol
+   and defines LINK_MAX although filesystems have different maxima.  A
+   similar thing is true for OPEN_MAX: the limit can be changed at
+   runtime and therefore the macro must not be defined.  Remove this
+   after including the header if necessary.  */
+#ifndef NR_OPEN
+# define __undef_NR_OPEN
+#endif
+#ifndef LINK_MAX
+# define __undef_LINK_MAX
+#endif
+#ifndef OPEN_MAX
+# define __undef_OPEN_MAX
+#endif
+
+/* The kernel sources contain a file with all the needed information.  */
+#include <linux/limits.h>
+
+/* Have to remove NR_OPEN?  */
+#ifdef __undef_NR_OPEN
+# undef NR_OPEN
+# undef __undef_NR_OPEN
+#endif
+/* Have to remove LINK_MAX?  */
+#ifdef __undef_LINK_MAX
+# undef LINK_MAX
+# undef __undef_LINK_MAX
+#endif
+/* Have to remove OPEN_MAX?  */
+#ifdef __undef_OPEN_MAX
+# undef OPEN_MAX
+# undef __undef_OPEN_MAX
+#endif
+
+/* The number of data keys per process.  */
+#define _POSIX_THREAD_KEYS_MAX 128
+/* This is the value this implementation supports.  */
+#define PTHREAD_KEYS_MAX       1024
+
+/* Controlling the iterations of destructors for thread-specific data.  */
+#define _POSIX_THREAD_DESTRUCTOR_ITERATIONS    4
+/* Number of iterations this implementation does.  */
+#define PTHREAD_DESTRUCTOR_ITERATIONS  _POSIX_THREAD_DESTRUCTOR_ITERATIONS
+
+/* The number of threads per process.  */
+#define _POSIX_THREAD_THREADS_MAX      64
+/* This is the value this implementation supports.  */
+#define PTHREAD_THREADS_MAX    1024
+
+/* 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
diff --git a/nptl/sysdeps/unix/sysv/linux/bits/posix_opt.h b/nptl/sysdeps/unix/sysv/linux/bits/posix_opt.h
new file mode 100644 (file)
index 0000000..8274f51
--- /dev/null
@@ -0,0 +1,144 @@
+/* Define POSIX options for Linux.
+   Copyright (C) 1996-2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU 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.  */
+
+#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
+
+/* Implementation supports `poll' function.  */
+#define        _POSIX_POLL     1
+
+/* Implementation supports `select' and `pselect' functions.  */
+#define        _POSIX_SELECT   1
+
+/* 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      1
+
+/* Real-time signals are supported.  */
+#define _POSIX_REALTIME_SIGNALS        1
+
+/* We support asynchronous I/O.  */
+#define _POSIX_ASYNCHRONOUS_IO 1
+#define _POSIX_ASYNC_IO                1
+/* Alternative name for Unix98.  */
+#define _LFS_ASYNCHRONOUS_IO   1
+
+/* 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
+
+/* 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  1
+
+/* The barrier functions are available.  */
+#define _POSIX_BARRIERS        200112L
+
+/* POSIX message queues are not yet supported.  */
+#undef _POSIX_MESSAGE_PASSING
+
+/* Thread process-shared synchronization is supported.  */
+#define _POSIX_THREAD_PROCESS_SHARED   200112L
+
+#endif /* posix_opt.h */
diff --git a/nptl/sysdeps/unix/sysv/linux/configure b/nptl/sysdeps/unix/sysv/linux/configure
new file mode 100644 (file)
index 0000000..229414d
--- /dev/null
@@ -0,0 +1,3 @@
+# Local configure fragment for sysdeps/unix/sysv/linux.
+
+DEFINES="$DEFINES -D_LIBC_REENTRANT"
diff --git a/nptl/sysdeps/unix/sysv/linux/fork-gen.c b/nptl/sysdeps/unix/sysv/linux/fork-gen.c
new file mode 100644 (file)
index 0000000..ff00261
--- /dev/null
@@ -0,0 +1,37 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <list.h>
+#include "fork.h"
+
+
+static struct fork_handler pthread_child_handler;
+
+
+void
+__register_pthread_fork_handler (ptr, reclaim)
+     unsigned long int *ptr;
+     void (*reclaim) (void);
+{
+  __fork_generation_pointer = ptr;
+
+  pthread_child_handler.handler = reclaim;
+
+  list_add_tail (&pthread_child_handler.list, &__fork_child_list);
+}
diff --git a/nptl/sysdeps/unix/sysv/linux/fork.c b/nptl/sysdeps/unix/sysv/linux/fork.c
new file mode 100644 (file)
index 0000000..c1aa23c
--- /dev/null
@@ -0,0 +1,124 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sysdep.h>
+#include <libio/libioP.h>
+#include <tls.h>
+#include "fork.h"
+
+
+unsigned long int *__fork_generation_pointer;
+
+
+lll_lock_t __fork_lock = LLL_LOCK_INITIALIZER;
+LIST_HEAD (__fork_prepare_list);
+LIST_HEAD (__fork_parent_list);
+LIST_HEAD (__fork_child_list);
+
+
+static void
+fresetlockfiles (void)
+{
+  _IO_ITER i;
+
+  for (i = _IO_iter_begin(); i != _IO_iter_end(); i = _IO_iter_next(i))
+    *((pthread_mutex_t *) _IO_iter_file(i)->_lock)
+      = (pthread_mutex_t) PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
+}
+
+
+pid_t
+__libc_fork (void)
+{
+  pid_t pid;
+  list_t *runp;
+
+  /* Get the lock so that the set of registered handlers is not
+     inconsistent or changes beneath us.  */
+  lll_lock (__fork_lock);
+
+  /* Run all the registered preparation handlers.  In reverse order.  */
+  list_for_each_prev (runp, &__fork_prepare_list)
+    {
+      struct fork_handler *curp;
+
+      curp = list_entry (runp, struct fork_handler, list);
+
+      curp->handler ();
+    }
+
+  _IO_list_lock ();
+
+#ifdef ARCH_FORK
+  pid = ARCH_FORK ();
+#else
+# error "ARCH_FORK must be defined so that the CLONE_SETTID flag is used"
+  pid = INLINE_SYSCALL (fork, 0);
+#endif
+
+  if (pid == 0)
+    {
+      if (__fork_generation_pointer != NULL)
+       *__fork_generation_pointer += 4;
+
+      /* Reset the file list.  These are recursive mutexes.  */
+      fresetlockfiles ();
+
+      /* We execute this even if the 'fork' call failed.  */
+      _IO_list_resetlock ();
+
+      /* Run the handlers registered for the child.  */
+      list_for_each (runp, &__fork_child_list)
+       {
+         struct fork_handler *curp;
+
+         curp = list_entry (runp, struct fork_handler, list);
+
+         curp->handler ();
+       }
+
+      /* Initialize the fork lock.  */
+      __fork_lock = (lll_lock_t) LLL_LOCK_INITIALIZER;
+    }
+  else
+    {
+      /* We execute this even if the 'fork' call failed.  */
+      _IO_list_unlock ();
+
+      /* Run the handlers registered for the parent.  */
+      list_for_each (runp, &__fork_parent_list)
+       {
+         struct fork_handler *curp;
+
+         curp = list_entry (runp, struct fork_handler, list);
+
+         curp->handler ();
+       }
+
+      /* Release the for lock.  */
+      lll_unlock (__fork_lock);
+    }
+
+  return pid;
+}
+weak_alias (__libc_fork, __fork)
+weak_alias (__libc_fork, fork)
diff --git a/nptl/sysdeps/unix/sysv/linux/fork.h b/nptl/sysdeps/unix/sysv/linux/fork.h
new file mode 100644 (file)
index 0000000..85722a5
--- /dev/null
@@ -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 <lowlevellock.h>
+
+/* The fork generation counter, defined in libpthread.  */
+extern unsigned long int __fork_generation attribute_hidden;
+
+/* Pointer to the fork generation counter in the thread library.  */
+extern unsigned long int *__fork_generation_pointer attribute_hidden;
+
+/* Lock to protect handling of fork handlers.  */
+extern lll_lock_t __fork_lock attribute_hidden;
+
+/* Lists of registered fork handlers.  */
+extern list_t __fork_prepare_list attribute_hidden;
+extern list_t __fork_parent_list attribute_hidden;
+extern list_t __fork_child_list 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);
+
+/* Register the generation counter in the libpthread with the libc.  */
+extern void __register_pthread_fork_handler (unsigned long int *__ptr,
+                                            void (*reclaim) (void));
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h b/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h
new file mode 100644 (file)
index 0000000..2167bbb
--- /dev/null
@@ -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.  */
+
+#ifndef _BITS_PTHREADTYPES_H
+#define _BITS_PTHREADTYPES_H   1
+
+#define __SIZEOF_PTHREAD_ATTR_T 36
+#define __SIZEOF_PTHREAD_MUTEX_T 24
+#define __SIZEOF_PTHREAD_MUTEXATTR_T 4
+#define __SIZEOF_PTHREAD_COND_T 12
+#define __SIZEOF_PTHREAD_CONDATTR_T 4
+#define __SIZEOF_PTHREAD_RWLOCK_T 32
+#define __SIZEOF_PTHREAD_RWLOCKATTR_T 8
+#define __SIZEOF_PTHREAD_BARRIER_T 20
+#define __SIZEOF_PTHREAD_BARRIERATTR_T 4
+
+
+/* Thread identifiers.  The structure of the attribute type is not
+   exposed on purpose.  */
+typedef unsigned long int pthread_t;
+
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_ATTR_T];
+  long int __align;
+} pthread_attr_t;
+
+
+/* Data structures for mutex handling.  The structure of the attribute
+   type is not exposed on purpose.  */
+typedef union
+{
+  struct
+  {
+    int __lock;
+    unsigned int __count;
+    struct pthread *__owner;
+    /* KIND must stay at this position in the structure to maintain
+       binary compatibility.  */
+    int __kind;
+  } __data;
+  char __size[__SIZEOF_PTHREAD_MUTEX_T];
+  long int __align;
+} pthread_mutex_t;
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_MUTEXATTR_T];
+  long int __align;
+} pthread_mutexattr_t;
+
+
+/* Data structure for conditional variable handling.  The structure of
+   the attribute type is not exposed on purpose.  */
+typedef union
+{
+  struct
+  {
+    int __lock;
+    unsigned int __nr_wakers;
+    unsigned int __nr_sleepers;
+  } __data;
+  char __size[__SIZEOF_PTHREAD_COND_T];
+  long int __align;
+} pthread_cond_t;
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_CONDATTR_T];
+  long int __align;
+} pthread_condattr_t;
+
+
+/* Keys for thread-specific data */
+typedef unsigned int pthread_key_t;
+
+
+/* Once-only execution */
+typedef int pthread_once_t;
+
+
+#ifdef __USE_UNIX98
+/* Data structure for read-write lock variable handling.  The
+   structure of the attribute type is not exposed on purpose.  */
+typedef union
+{
+  struct
+  {
+    int __lock;
+    unsigned int __nr_readers;
+    unsigned int __readers_wakeup;
+    unsigned int __writer_wakeup;
+    unsigned int __nr_readers_queued;
+    unsigned int __nr_writers_queued;
+    /* FLAGS must stay at this position in the structure to maintain
+       binary compatibility.  */
+    unsigned int __flags;
+    pthread_t __writer;
+  } __data;
+  char __size[__SIZEOF_PTHREAD_RWLOCK_T];
+  long int __align;
+} pthread_rwlock_t;
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_RWLOCKATTR_T];
+  long int __align;
+} pthread_rwlockattr_t;
+#endif
+
+
+#ifdef __USE_XOPEN2K
+/* POSIX spinlock data type.  */
+typedef volatile int pthread_spinlock_t;
+
+
+/* POSIX barriers data type.  The structure of the type is
+   deliberately not exposed.  */
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_BARRIER_T];
+  long int __align;
+} pthread_barrier_t;
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_BARRIERATTR_T];
+  int __align;
+} pthread_barrierattr_t;
+#endif
+
+
+#endif /* bits/pthreadtypes.h */
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/bits/semaphore.h b/nptl/sysdeps/unix/sysv/linux/i386/bits/semaphore.h
new file mode 100644 (file)
index 0000000..ab46ac0
--- /dev/null
@@ -0,0 +1,39 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _SEMAPHORE_H
+# error "Never use <bits/semaphore.h> directly; include <semaphore.h> instead."
+#endif
+
+
+#define __SIZEOF_SEM_T 16
+
+
+/* Value returned if `sem_open' failed.  */
+#define SEM_FAILED      ((sem_t *) 0)
+
+/* Maximum value the semaphore can have.  */
+#define SEM_VALUE_MAX   ((int) ((~0u) >> 1))
+
+
+typedef union
+{
+  char __size[__SIZEOF_SEM_T];
+  long int __align;
+} sem_t;
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/createthread.c b/nptl/sysdeps/unix/sysv/linux/i386/createthread.c
new file mode 100644 (file)
index 0000000..3196a8c
--- /dev/null
@@ -0,0 +1,146 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sched.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <atomic.h>
+#include <ldsodefs.h>
+#include <tls.h>
+
+
+#define CLONE_SIGNAL           (CLONE_SIGHAND | CLONE_THREAD)
+
+
+static int
+create_thread (struct pthread *pd, STACK_VARIABLES_PARMS)
+{
+  union user_desc_init desc;
+
+  /* Describe the thread-local storage segment.  */
+
+  /* The 'entry_number' field.  The first three bits of the segment
+     register value select the GDT, ignore them.  We get the index
+     from the value of the %gs register in the current thread.  */
+  desc.vals[0] = TLS_GET_GS () >> 3;
+  /* The 'base_addr' field.  Pointer to the TCB.  */
+  desc.vals[1] = (unsigned long int) pd;
+  /* The 'limit' field.  We use 4GB which is 0xfffff pages.  */
+  desc.vals[2] = 0xfffff;
+  /* Collapsed value of the bitfield:
+       .seg_32bit = 1
+       .contents = 0
+       .read_exec_only = 0
+       .limit_in_pages = 1
+       .seg_not_present = 0
+       .useable = 1 */
+  desc.vals[3] = 0x51;
+
+
+  assert (pd->header.data.tcb != NULL);
+
+
+  if (__builtin_expect (THREAD_GETMEM (THREAD_SELF, report_events), 0))
+    {
+      /* The parent thread is supposed to report events.  Check whether
+        the TD_CREATE event is needed, too.  */
+      const int _idx = __td_eventword (TD_CREATE);
+      const uint32_t _mask = __td_eventmask (TD_CREATE);
+
+      if ((_mask & (__nptl_threads_events.event_bits[_idx]
+                   | pd->eventbuf.eventmask.event_bits[_idx])) != 0)
+       {
+         /* We have to report the new thread.  Make sure the thread
+            does not run far by forcing it to get a lock.  We lock it
+            here too so that the new thread cannot continue until we
+            tell it to.  */
+         lll_lock (pd->lock);
+
+         /* Create the thread.  */
+         if (__clone (start_thread_debug, STACK_VARIABLES_ARGS,
+                      CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGNAL |
+                      CLONE_SETTLS | CLONE_PARENT_SETTID |
+                      CLONE_CHILD_CLEARTID | CLONE_DETACHED | 0,
+                      pd, &pd->tid, &desc.desc, &pd->tid) == -1)
+           /* Failed.  */
+           return errno;
+
+         /* Now fill in the information about the new thread in
+            the newly created thread's data structure.  We cannot let
+            the new thread do this since we don't know whether it was
+            already scheduled when we send the event.  */
+         pd->eventbuf.eventnum = TD_CREATE;
+         pd->eventbuf.eventdata = pd;
+
+         /* Enqueue the descriptor.  */
+         do
+           pd->nextevent = __nptl_last_event;
+         while (atomic_compare_and_exchange_acq (__nptl_last_event, pd,
+                                                 pd->nextevent) != 0);
+
+         /* Now call the function which signals the event.  */
+         __nptl_create_event ();
+
+         /* And finally restart the new thread.  */
+         lll_unlock (pd->lock);
+
+         return 0;
+       }
+    }
+
+  /* We rely heavily on various flags the CLONE function understands:
+
+     CLONE_VM, CLONE_FS, CLONE_FILES
+       These flags select semantics with shared address space and
+       file descriptors according to what POSIX requires.
+
+     CLONE_SIGNAL
+       This flag selects the POSIX signal semantics.
+
+     CLONE_SETTLS
+       The sixth parameter to CLONE determines the TLS area for the
+       new thread.
+
+     CLONE_PARENT_SETTID
+       The kernels writes the thread ID of the newly created thread
+       into the location pointed to by the fifth parameters to CLONE.
+
+       Note that it would be semantically equivalent to use
+       CLONE_CHILD_SETTID but it is be more expensive in the kernel.
+
+     CLONE_CHILD_CLEARTID
+       The kernels clears the thread ID of a thread that has called
+       sys_exit() - using the same parameter as CLONE_SETTID.
+
+     CLONE_DETACHED
+       No signal is generated if the thread exists and it is
+       automatically reaped.
+
+     The termination signal is chosen to be zero which means no signal
+     is sent.  */
+  if (__clone (start_thread, STACK_VARIABLES_ARGS,
+              CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGNAL |
+              CLONE_SETTLS | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID |
+              CLONE_DETACHED | 0, pd, &pd->tid, &desc.desc, &pd->tid) == -1)
+    /* Failed.  */
+    return errno;
+
+  return 0;
+}
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/fork.c b/nptl/sysdeps/unix/sysv/linux/i386/fork.c
new file mode 100644 (file)
index 0000000..813e529
--- /dev/null
@@ -0,0 +1,31 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sched.h>
+#include <signal.h>
+#include <sysdep.h>
+#include <tls.h>
+
+
+#define ARCH_FORK() \
+  INLINE_SYSCALL (clone, 5,                                                  \
+                 CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD, 0,     \
+                 NULL, NULL, &THREAD_SELF->tid)
+
+#include "../fork.c"
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevelcond.S b/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevelcond.S
new file mode 100644 (file)
index 0000000..9e2b9fe
--- /dev/null
@@ -0,0 +1,279 @@
+/* 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 <sysdep.h>
+
+       .text
+
+#ifdef UP
+# define LOCK
+#else
+# define LOCK lock
+#endif
+
+#define SYS_gettimeofday       __NR_gettimeofday
+#define SYS_futex              240
+#define FUTEX_WAIT             0
+#define FUTEX_WAKE             1
+
+#define EWOULDBLOCK            11
+#define EINVAL                 22
+#define ETIMEDOUT              110
+
+#define cond_lock       0
+#define cond_nr_wakers  4
+#define cond_nr_sleepers 8
+
+
+       .global __lll_cond_wait
+       .type   __lll_cond_wait,@function
+       .hidden __lll_cond_wait
+       .align  16
+__lll_cond_wait:
+       pushl   %esi
+       pushl   %ebx
+
+       xorl    %esi, %esi
+
+       leal    cond_nr_wakers(%eax), %ebx
+
+4:     movl    (%ebx), %edx
+       testl   %edx, %edx
+       jne     1f
+
+       LOCK
+       decl    cond_lock-cond_nr_wakers(%ebx)
+       jne     2f
+
+3:     xorl    %ecx, %ecx
+       movl    $SYS_futex, %eax
+       int     $0x80
+
+       movl    $1, %eax
+       LOCK
+       xaddl   %eax, cond_lock-cond_nr_wakers(%ebx)
+       testl   %eax, %eax
+       je      4b
+
+       leal    cond_lock-cond_nr_wakers(%ebx), %ecx
+       /* Preserves %ebx, %edx, %edi, %esi.  */
+       call    __lll_mutex_lock_wait
+       jmp     4b
+
+1:     decl    (%ebx)
+
+       popl    %ebx
+       popl    %esi
+       ret
+
+2:     leal    cond_lock-cond_nr_wakers(%ebx), %eax
+       /* Preserves %ebx, %ecx, %edx, %edi, %esi.  */
+       call    __lll_mutex_unlock_wake
+       jmp     3b
+       .size   __lll_cond_wait,.-__lll_cond_wait
+
+
+       .global __lll_cond_timedwait
+       .type   __lll_cond_timedwait,@function
+       .hidden __lll_cond_timedwait
+       .align  16
+__lll_cond_timedwait:
+       /* Check for a valid timeout value.  */
+       cmpl    $1000000000, 4(%edx)
+       jae     1f
+
+       pushl   %ebp
+       pushl   %edi
+       pushl   %esi
+       pushl   %ebx
+
+       /* Stack frame for the timespec and timeval structs.  */
+       subl    $8, %esp
+
+       leal    cond_nr_wakers(%eax), %ebp      /* cond */
+       movl    %edx, %edi                      /* timeout */
+
+9:     movl    (%ebp), %esi
+       testl   %esi, %esi
+       jne     5f
+
+       LOCK
+       decl    cond_lock-cond_nr_wakers(%ebp)
+       jne     6f
+
+       /* Get current time.  */
+7:     movl    %esp, %ebx
+       xorl    %ecx, %ecx
+       movl    $SYS_gettimeofday, %eax
+       int     $0x80
+
+       /* Compute relative timeout.  */
+       movl    4(%esp), %eax
+       movl    $1000, %edx
+       mul     %edx            /* Milli seconds to nano seconds.  */
+       movl    (%edi), %ecx
+       movl    4(%edi), %edx
+       subl    (%esp), %ecx
+       subl    %eax, %edx
+       jns     3f
+       addl    $1000000000, %edx
+       decl    %ecx
+3:     testl   %ecx, %ecx
+       js      4f              /* Time is already up.  */
+
+       movl    %ecx, (%esp)    /* Store relative timeout.  */
+       movl    %edx, 4(%esp)
+       movl    %esi, %edx
+       movl    %esp, %esi
+       xorl    %ecx, %ecx      /* movl $FUTEX_WAIT, %ecx */
+       movl    %ebp, %ebx
+       movl    $SYS_futex, %eax
+       int     $0x80
+
+       movl    %eax, %edx
+
+       movl    $1, %eax
+       LOCK
+       xaddl   %eax, cond_lock-cond_nr_wakers(%ebp)
+       testl   %eax, %eax
+       jne     8f
+
+       cmpl    $-ETIMEDOUT, %edx
+       jne     9b
+
+4:     movl    $ETIMEDOUT, %eax
+       jmp     2f
+
+5:     decl    (%ebp)
+       xorl    %eax, %eax
+
+2:     addl    $8, %esp
+       popl    %ebx
+       popl    %esi
+       popl    %edi
+       popl    %ebp
+       ret
+
+6:     leal    cond_lock-cond_nr_wakers(%ebp), %eax
+       /* Preserves %ebx, %ecx, %edx, %edi, %esi.  */
+       call    __lll_mutex_unlock_wake
+       jmp     7b
+
+8:     leal    cond_lock-cond_nr_wakers(%ebp), %ecx
+       /* Preserves %ebx, %edx, %edi, %esi.  */
+       call    __lll_mutex_lock_wait
+       jmp     5b
+
+1:     movl    $EINVAL, %eax
+       ret
+       .size   __lll_cond_timedwait,.-__lll_cond_timedwait
+
+
+       .global __lll_cond_wake
+       .type   __lll_cond_wake,@function
+       .hidden __lll_cond_wake
+       .align  16
+__lll_cond_wake:
+       pushl   %esi
+       pushl   %ebx
+
+       movl    %eax, %ebx
+
+       movl    $1, %eax
+       LOCK
+       xaddl   %eax, (%ebx)
+       testl   %eax, %eax
+       jne     1f
+
+2:     leal    cond_nr_wakers(%ebx), %ebx
+       cmpl    $0, cond_nr_sleepers-cond_nr_wakers(%ebx)
+       je      3f
+
+       incl    (%ebx)
+       jz      5f
+
+6:     movl    $FUTEX_WAKE, %ecx
+       xorl    %esi, %esi
+       movl    %ecx, %edx      /* movl $1, %edx */
+       movl    $SYS_futex, %eax
+       int     $0x80
+
+3:     LOCK
+       decl    cond_lock-cond_nr_wakers(%ebx)
+       je,pt   4f
+
+       leal    cond_lock-cond_nr_wakers(%ebx), %eax
+       call    __lll_mutex_unlock_wake
+
+4:     popl    %ebx
+       popl    %esi
+       ret
+
+1:     movl    %ebx, %ecx
+       call    __lll_mutex_lock_wait
+       jmp     2b
+
+5:     movl    $0x80000000, (%ebx)
+       jmp     6b
+       .size   __lll_cond_wake,.-__lll_cond_wake
+
+
+       .global __lll_cond_broadcast
+       .type   __lll_cond_broadcast,@function
+       .hidden __lll_cond_broadcast
+       .align  16
+__lll_cond_broadcast:
+       pushl   %esi
+       pushl   %ebx
+
+       movl    %eax, %ebx
+       movl    $0x8000000, %edx
+
+       movl    $1, %eax
+       LOCK
+       xaddl   %eax, (%ebx)
+       testl   %eax, %eax
+       jne     1f
+
+2:     leal    cond_nr_wakers(%ebx), %ebx
+       cmpl    $0, cond_nr_sleepers-cond_nr_wakers(%ebx)
+       je      3f
+
+       orl     %edx, (%ebx)
+
+6:     movl    $FUTEX_WAKE, %ecx
+       xorl    %esi, %esi
+       movl    $SYS_futex, %eax
+       int     $0x80
+
+3:     LOCK
+       decl    cond_lock-cond_nr_wakers(%ebx)
+       je,pt   4f
+
+       leal    cond_lock-cond_nr_wakers(%ebx), %eax
+       call    __lll_mutex_unlock_wake
+
+4:     popl    %ebx
+       popl    %esi
+       ret
+
+1:     movl    %ebx, %ecx
+       call    __lll_mutex_lock_wait
+       jmp     2b
+       .size   __lll_cond_broadcast,.-__lll_cond_broadcast
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S b/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S
new file mode 100644 (file)
index 0000000..400413d
--- /dev/null
@@ -0,0 +1,180 @@
+/* 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 <sysdep.h>
+
+       .text
+
+#ifdef UP
+# define LOCK
+#else
+# define LOCK lock
+#endif
+
+#define SYS_gettimeofday       __NR_gettimeofday
+#define SYS_futex              240
+#define FUTEX_WAIT             0
+#define FUTEX_WAKE             1
+
+#define ETIMEDOUT               110
+
+
+       .globl  __lll_lock_wait
+       .type   __lll_lock_wait,@function
+       .hidden __lll_lock_wait
+       .align  16
+__lll_lock_wait:
+       pushl   %esi
+       pushl   %ebx
+       pushl   %edx
+
+       movl    %ecx, %ebx
+       xorl    %esi, %esi      /* No timeout.  */
+       xorl    %ecx, %ecx      /* movl $FUTEX_WAIT, %ecx */
+1:
+       leal    -1(%eax), %edx  /* account for the preceeded xadd.  */
+       movl    $SYS_futex, %eax
+       int     $0x80
+
+       orl     $-1, %eax       /* Load -1.  */
+       LOCK
+       xaddl   %eax, (%ebx)
+       jne     1b
+
+       movl    $-1, (%ebx)
+
+       popl    %edx
+       popl    %ebx
+       popl    %esi
+       ret
+       .size   __lll_lock_wait,.-__lll_lock_wait
+
+
+       .globl  lll_unlock_wake_cb
+       .type   lll_unlock_wake_cb,@function
+       .hidden lll_unlock_wake_cb
+       .align  16
+lll_unlock_wake_cb:
+       pushl   %esi
+       pushl   %ebx
+       pushl   %ecx
+       pushl   %edx
+
+       movl    20(%esp), %ebx
+       LOCK
+       incl    (%ebx)
+       jng     1f
+
+       popl    %edx
+       popl    %ecx
+       popl    %ebx
+       popl    %esi
+       ret
+       .size   lll_unlock_wake_cb,.-lll_unlock_wake_cb
+
+
+       .globl  __lll_unlock_wake
+       .type   __lll_unlock_wake,@function
+       .hidden __lll_unlock_wake
+__lll_unlock_wake:
+       pushl   %esi
+       pushl   %ebx
+       pushl   %ecx
+       pushl   %edx
+
+       movl    %eax, %ebx
+1:     movl    $FUTEX_WAKE, %ecx
+       movl    $1, %edx        /* Wake one thread.  */
+       xorl    %esi, %esi
+       movl    %edx, (%ebx)    /* Stores '$1'.  */
+       movl    $SYS_futex, %eax
+       int     $0x80
+
+       popl    %edx
+       popl    %ecx
+       popl    %ebx
+       popl    %esi
+       ret
+       .size   __lll_unlock_wake,.-__lll_unlock_wake
+
+
+       .globl  __lll_timedwait_tid
+       .type   __lll_timedwait_tid,@function
+       .hidden __lll_timedwait_tid
+__lll_timedwait_tid:
+       pushl   %edi
+       pushl   %esi
+       pushl   %ebx
+       pushl   %ebp
+
+       movl    %eax, %ebp
+       movl    %edx, %edi
+       subl    $8, %esp
+
+       /* Get current time.  */
+2:     movl    %esp, %ebx
+       xorl    %ecx, %ecx
+       movl    $SYS_gettimeofday, %eax
+       int     $0x80
+
+       /* Compute relative timeout.  */
+       movl    4(%esp), %eax
+       movl    $1000, %edx
+       mul     %edx            /* Milli seconds to nano seconds.  */
+       movl    (%edi), %ecx
+       movl    4(%edi), %edx
+       subl    (%esp), %ecx
+       subl    %eax, %edx
+       jns     5f
+       addl    $1000000000, %edx
+       decl    %ecx
+5:     testl   %ecx, %ecx
+       js      6f              /* Time is already up.  */
+
+       movl    %ecx, (%esp)    /* Store relative timeout.  */
+       movl    %edx, 4(%esp)
+
+       movl    (%ebp), %edx
+       testl   %edx, %edx
+       jz      4f
+
+       movl    %esp, %esi
+       xorl    %ecx, %ecx      /* movl $FUTEX_WAIT, %ecx */
+       movl    %ebp, %ebx
+       movl    $SYS_futex, %eax
+       int     $0x80
+
+       movl    %eax, %edx
+
+       cmpl    $0, (%ebx)
+       jne     1f
+4:     xorl    %eax, %eax
+
+3:     addl    $8, %esp
+       popl    %ebp
+       popl    %ebx
+       popl    %esi
+       popl    %edi
+       ret
+
+1:     cmpl    $-ETIMEDOUT, %edx
+       jne     2b
+6:     movl    $ETIMEDOUT, %eax
+       jmp     3b
+       .size   __lll_timedwait_tid,.-__lll_timedwait_tid
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevelmutex.S b/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevelmutex.S
new file mode 100644 (file)
index 0000000..a48cd88
--- /dev/null
@@ -0,0 +1,176 @@
+/* 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 <sysdep.h>
+
+       .text
+
+#ifdef UP
+# define LOCK
+#else
+# define LOCK lock
+#endif
+
+#define SYS_gettimeofday       __NR_gettimeofday
+#define SYS_futex              240
+#define FUTEX_WAIT             0
+#define FUTEX_WAKE             1
+
+#define EWOULDBLOCK            11
+#define EINVAL                 22
+#define ETIMEDOUT              110
+
+
+       .globl  __lll_mutex_lock_wait
+       .type   __lll_mutex_lock_wait,@function
+       .hidden __lll_mutex_lock_wait
+       .align  16
+__lll_mutex_lock_wait:
+       pushl   %esi
+       pushl   %ebx
+       pushl   %edx
+
+       movl    %ecx, %ebx
+       xorl    %esi, %esi      /* No timeout.  */
+       xorl    %ecx, %ecx      /* movl $FUTEX_WAIT, %ecx */
+1:
+       leal    1(%eax), %edx   /* account for the preceeded xadd.  */
+       movl    $SYS_futex, %eax
+       int     $0x80
+
+       movl    $1, %eax
+       LOCK
+       xaddl   %eax, (%ebx)
+       testl   %eax, %eax
+       jne     1b
+
+       movl    $2, (%ebx)
+
+       popl    %edx
+       popl    %ebx
+       popl    %esi
+       ret
+       .size   __lll_mutex_lock_wait,.-__lll_mutex_lock_wait
+
+
+       .globl  __lll_mutex_timedlock_wait
+       .type   __lll_mutex_timedlock_wait,@function
+       .hidden __lll_mutex_timedlock_wait
+       .align  16
+__lll_mutex_timedlock_wait:
+       /* Check for a valid timeout value.  */
+       cmpl    $1000000000, 4(%edx)
+       jae     3f
+
+       pushl   %edi
+       pushl   %esi
+       pushl   %ebx
+       pushl   %ebp
+
+       /* Stack frame for the timespec and timeval structs.  */
+       subl    $8, %esp
+
+       movl    %ecx, %ebp
+       movl    %edx, %edi
+       leal    1(%eax), %esi
+
+       /* Get current time.  */
+1:
+       movl    %esp, %ebx
+       xorl    %ecx, %ecx
+       movl    $SYS_gettimeofday, %eax
+       int     $0x80
+
+       /* Compute relative timeout.  */
+       movl    4(%esp), %eax
+       movl    $1000, %edx
+       mul     %edx            /* Milli seconds to nano seconds.  */
+       movl    (%edi), %ecx
+       movl    4(%edi), %edx
+       subl    (%esp), %ecx
+       subl    %eax, %edx
+       jns     4f
+       addl    $1000000000, %edx
+       decl    %ecx
+4:     testl   %ecx, %ecx
+       js      5f              /* Time is already up.  */
+
+       /* Futex call.  */
+       movl    %ecx, (%esp)    /* Store relative timeout.  */
+       movl    %edx, 4(%esp)
+       movl    %esi, %edx
+       movl    %esp, %esi
+       xorl    %ecx, %ecx      /* movl $FUTEX_WAIT, %ecx */
+       movl    %ebp, %ebx
+       movl    $SYS_futex, %eax
+       int     $0x80
+
+       movl    $1, %esi
+       LOCK
+       xaddl   %esi, (%ebx)
+       testl   %esi, %esi
+       jne     7f
+
+       movl    $2, (%ebx)
+       xorl    %eax, %eax
+
+6:     addl    $8, %esp
+       popl    %ebp
+       popl    %ebx
+       popl    %esi
+       popl    %edi
+       ret
+
+       /* Check whether the time expired.  */
+7:     cmpl    $-ETIMEDOUT, %eax
+       je      5f
+       jmp     1b
+
+3:     movl    $EINVAL, %eax
+       ret
+
+5:     movl    $ETIMEDOUT, %eax
+       jmp     6b
+       .size   __lll_mutex_timedlock_wait,.-__lll_mutex_timedlock_wait
+
+
+       .globl  __lll_mutex_unlock_wake
+       .type   __lll_mutex_unlock_wake,@function
+       .hidden __lll_mutex_unlock_wake
+       .align  16
+__lll_mutex_unlock_wake:
+       pushl   %esi
+       pushl   %ebx
+       pushl   %ecx
+       pushl   %edx
+
+       movl    $FUTEX_WAKE, %ecx
+       movl    %eax, %ebx
+       xorl    %esi, %esi
+       movl    $0, (%ebx)
+       movl    $1, %edx        /* Wake one thread.  */
+       movl    $SYS_futex, %eax
+       int     $0x80
+
+       popl    %edx
+       popl    %ecx
+       popl    %ebx
+       popl    %esi
+       ret
+       .size   __lll_mutex_unlock_wake,.-__lll_mutex_unlock_wake
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevelrwlock.S b/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevelrwlock.S
new file mode 100644 (file)
index 0000000..2dde246
--- /dev/null
@@ -0,0 +1,566 @@
+/* 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 <sysdep.h>
+
+       .text
+
+#define SYS_gettimeofday       __NR_gettimeofday
+#define SYS_futex              240
+#define FUTEX_WAIT             0
+#define FUTEX_WAKE             1
+
+#define EAGAIN         11
+#define EDEADLK                35
+#define ETIMEDOUT      110
+
+/* Offsets in the pthread_rwlock_t structure.  */
+#define MUTEX          0
+#define NR_READERS     4
+#define READERS_WAKEUP 8
+#define WRITERS_WAKEUP 12
+#define READERS_QUEUED 16
+#define WRITERS_QUEUED 20
+#define FLAGS          24
+#define WRITER 28
+
+#ifndef UP
+# define LOCK lock
+#else
+# define LOCK
+#endif
+
+
+       .globl  __pthread_rwlock_rdlock
+       .type   __pthread_rwlock_rdlock,@function
+       .align  16
+__pthread_rwlock_rdlock:
+       pushl   %esi
+       pushl   %ebx
+
+       xorl    %esi, %esi
+       xorl    %edx, %edx
+       movl    12(%esp), %ebx
+
+       /* Get the lock.  */
+       movl    $1, %eax
+       LOCK
+       xaddl   %eax, MUTEX(%ebx)
+       testl   %eax, %eax
+       jne     1f
+
+2:     movl    WRITER(%ebx), %eax
+       testl   %eax, %eax
+       jne     14f
+       cmp     $0, WRITERS_QUEUED(%ebx)
+       je      5f
+       cmpl    $0, FLAGS(%ebx)
+       je      5f
+
+3:     incl    READERS_QUEUED(%ebx)
+       je      4f
+
+       LOCK
+       decl    MUTEX(%ebx)
+       jne     10f
+
+11:    addl    $READERS_WAKEUP-MUTEX, %ebx
+       movl    %esi, %ecx      /* movl $FUTEX_WAIT, %ecx */
+       movl    $SYS_futex, %eax
+       int     $0x80
+
+       subl    $READERS_WAKEUP-MUTEX, %ebx
+
+       /* Reget the lock.  */
+       movl    $1, %eax
+       LOCK
+       xaddl   %eax, MUTEX(%ebx)
+       testl   %eax, %eax
+       jne     12f
+
+13:    decl    READERS_QUEUED(%ebx)
+       jne     2b
+       movl    $0, READERS_WAKEUP(%ebx)
+       jmp     2b
+
+5:     xorl    %ecx, %ecx
+       incl    NR_READERS(%ebx)
+       je      8f
+9:     LOCK
+       decl    MUTEX(%ebx)
+       jne     6f
+7:
+
+       movl    %ecx, %eax
+       popl    %ebx
+       popl    %esi
+       ret
+
+1:     movl    %ebx, %ecx
+       call    __lll_mutex_lock_wait
+       jmp     2b
+
+14:    cmpl    %gs:8, %eax
+       jne     3b
+       /* Deadlock detected.  */
+       movl    $EDEADLK, %ecx
+       jmp     9b
+
+6:     movl    %ebx, %eax
+       call    __lll_mutex_unlock_wake
+       jmp     7b
+
+       /* Overflow.  */
+8:     decl    NR_READERS(%ebx)
+       movl    $EAGAIN, %ecx
+       jmp     9b
+
+       /* Overflow.  */
+4:     decl    READERS_QUEUED(%ebx)
+       movl    $EAGAIN, %ecx
+       jmp     9b
+
+10:    movl    %ebx, %eax
+       call    __lll_mutex_unlock_wake
+       jmp     11b
+
+12:    movl    %ebx, %ecx
+       call    __lll_mutex_lock_wait
+       jmp     13b
+       .size   __pthread_rwlock_rdlock,.-__pthread_rwlock_rdlock
+
+       .globl  pthread_rwlock_rdlock
+pthread_rwlock_rdlock = __pthread_rwlock_rdlock
+
+
+       .globl  pthread_rwlock_timedrdlock
+       .type   pthread_rwlock_timedrdlock,@function
+       .align  16
+pthread_rwlock_timedrdlock:
+       pushl   %esi
+       pushl   %edi
+       pushl   %ebx
+       pushl   %ebp
+       subl    $8, %esp
+
+       movl    28(%esp), %ebp
+       movl    32(%esp), %edi
+
+       /* Get the lock.  */
+       movl    $1, %eax
+       LOCK
+       xaddl   %eax, MUTEX(%ebp)
+       testl   %eax, %eax
+       jne     1f
+
+2:     movl    WRITER(%ebp), %eax
+       testl   %eax, %eax
+       jne     14f
+       cmp     $0, WRITERS_QUEUED(%ebp)
+       je      5f
+       cmpl    $0, FLAGS(%ebp)
+       je      5f
+
+3:     incl    READERS_QUEUED(%ebp)
+       je      4f
+
+       LOCK
+       decl    MUTEX(%ebp)
+       jne     10f
+
+       /* Get current time.  */
+       movl    %esp, %ebx
+       xorl    %ecx, %ecx
+       movl    $SYS_gettimeofday, %eax
+       int     $0x80
+
+       /* Compute relative timeout.  */
+       movl    4(%esp), %eax
+       movl    $1000, %edx
+       mul     %edx            /* Milli seconds to nano seconds.  */
+       movl    (%edi), %ecx
+       movl    4(%edi), %edx
+       subl    (%esp), %ecx
+       subl    %eax, %edx
+       jns     15f
+       addl    $1000000000, %edx
+       decl    %ecx
+15:    testl   %ecx, %ecx
+       js      16f             /* Time is already up.  */
+
+       /* Futex call.  */
+       movl    %ecx, (%esp)    /* Store relative timeout.  */
+       movl    %edx, 4(%esp)
+       xorl    %ecx, %ecx      /* movl $FUTEX_WAIT, %ecx */
+       movl    %esp, %esi
+       movl    %ecx, %edx
+       leal    READERS_WAKEUP(%ebp), %ebx
+       movl    $SYS_futex, %eax
+       int     $0x80
+       movl    %eax, %edx
+17:
+
+       /* Reget the lock.  */
+       movl    $1, %eax
+       LOCK
+       xaddl   %eax, MUTEX(%ebp)
+       testl   %eax, %eax
+       jne     12f
+
+13:    cmpl    $-ETIMEDOUT, %ecx
+       je      18f
+       decl    READERS_QUEUED(%ebp)
+       jne     2b
+       movl    $0, READERS_WAKEUP(%ebp)
+       jmp     2b
+
+
+5:     xorl    %ecx, %ecx
+       incl    NR_READERS(%ebp)
+       je      8f
+9:     LOCK
+       decl    MUTEX(%ebp)
+       jne     6f
+
+7:     movl    %ecx, %eax
+
+       addl    $8, %esp
+       popl    %ebp
+       popl    %ebx
+       popl    %edi
+       popl    %esi
+       ret
+
+1:     movl    %ebp, %ecx
+       call    __lll_mutex_lock_wait
+       jmp     2b
+
+14:    cmpl    %gs:8, %eax
+       jne     3b
+       movl    $EDEADLK, %ecx
+       jmp     9b
+
+6:     movl    %ebp, %eax
+       call    __lll_mutex_unlock_wake
+       jmp     7b
+
+       /* Overflow.  */
+8:     decl    NR_READERS(%ebp)
+       movl    $EAGAIN, %ecx
+       jmp     9b
+
+       /* Overflow.  */
+4:     decl    READERS_QUEUED(%ebp)
+       movl    $EAGAIN, %ecx
+       jmp     9b
+
+10:    movl    %ebp, %eax
+       call    __lll_mutex_unlock_wake
+       jmp     11b
+
+12:    movl    %ebx, %ecx
+       call    __lll_mutex_lock_wait
+       jmp     13b
+
+16:    movl    $-ETIMEDOUT, %ecx
+       jmp     17b
+
+18:    movl    $ETIMEDOUT, %ecx
+       jmp     9b
+       .size   pthread_rwlock_timedrdlock,.-pthread_rwlock_timedrdlock
+
+
+       .globl  __pthread_rwlock_wrlock
+       .type   __pthread_rwlock_wrlock,@function
+       .align  16
+__pthread_rwlock_wrlock:
+       pushl   %esi
+       pushl   %ebx
+
+       xorl    %esi, %esi
+       xorl    %edx, %edx
+       movl    12(%esp), %ebx
+
+       /* Get the lock.  */
+       movl    $1, %eax
+       LOCK
+       xaddl   %eax, MUTEX(%ebx)
+       testl   %eax, %eax
+       jne     1f
+
+2:     movl    WRITER(%ebx), %eax
+       testl   %eax, %eax
+       jne     14f
+       cmp     $0, NR_READERS(%ebx)
+       je      5f
+
+3:     incl    WRITERS_QUEUED(%ebx)
+       je      4f
+
+       LOCK
+       decl    MUTEX(%ebx)
+       jne     10f
+
+11:    addl    $WRITERS_WAKEUP-MUTEX, %ebx
+       movl    %esi, %ecx      /* movl $FUTEX_WAIT, %ecx */
+       movl    $SYS_futex, %eax
+       int     $0x80
+
+       subl    $WRITERS_WAKEUP-MUTEX, %ebx
+
+       /* Reget the lock.  */
+       movl    $1, %eax
+       LOCK
+       xaddl   %eax, MUTEX(%ebx)
+       testl   %eax, %eax
+       jne     12f
+
+13:    decl    WRITERS_QUEUED(%ebx)
+       movl    $0, WRITERS_WAKEUP(%ebx)
+       jmp     2b
+
+5:     xorl    %ecx, %ecx
+       movl    %gs:8, %eax
+       movl    %eax, WRITER(%ebx)
+9:     LOCK
+       decl    MUTEX(%ebx)
+       jne     6f
+7:
+
+       movl    %ecx, %eax
+       popl    %ebx
+       popl    %esi
+       ret
+
+1:     movl    %ebx, %ecx
+       call    __lll_mutex_lock_wait
+       jmp     2b
+
+14:    cmpl    %gs:8, %eax
+       jne     3b
+       movl    $EDEADLK, %ecx
+       jmp     9b
+
+6:     movl    %ebx, %eax
+       call    __lll_mutex_unlock_wake
+       jmp     7b
+
+4:     decl    WRITERS_QUEUED(%ebx)
+       movl    $EAGAIN, %ecx
+       jmp     9b
+
+10:    movl    %ebx, %eax
+       call    __lll_mutex_unlock_wake
+       jmp     11b
+
+12:    movl    %ebx, %ecx
+       call    __lll_mutex_lock_wait
+       jmp     13b
+       .size   __pthread_rwlock_wrlock,.-__pthread_rwlock_wrlock
+
+       .globl  pthread_rwlock_wrlock
+pthread_rwlock_wrlock = __pthread_rwlock_wrlock
+
+
+       .globl  pthread_rwlock_timedwrlock
+       .type   pthread_rwlock_timedwrlock,@function
+       .align  16
+pthread_rwlock_timedwrlock:
+       pushl   %esi
+       pushl   %edi
+       pushl   %ebx
+       pushl   %ebp
+       subl    $8, %esp
+
+       movl    28(%esp), %ebp
+       movl    32(%esp), %edi
+
+       /* Get the lock.  */
+       movl    $1, %eax
+       LOCK
+       xaddl   %eax, MUTEX(%ebp)
+       testl   %eax, %eax
+       jne     1f
+
+2:     movl    WRITER(%ebp), %eax
+       testl   %eax, %eax
+       jne     14f
+       cmp     $0, NR_READERS(%ebp)
+       je      5f
+
+3:     incl    WRITERS_QUEUED(%ebp)
+       je      4f
+
+       LOCK
+       decl    MUTEX(%ebp)
+       jne     10f
+
+       /* Get current time.  */
+       movl    %esp, %ebx
+       xorl    %ecx, %ecx
+       movl    $SYS_gettimeofday, %eax
+       int     $0x80
+
+       /* Compute relative timeout.  */
+       movl    4(%esp), %eax
+       movl    $1000, %edx
+       mul     %edx            /* Milli seconds to nano seconds.  */
+       movl    (%edi), %ecx
+       movl    4(%edi), %edx
+       subl    (%esp), %ecx
+       subl    %eax, %edx
+       jns     15f
+       addl    $1000000000, %edx
+       decl    %ecx
+15:    testl   %ecx, %ecx
+       js      16f             /* Time is already up.  */
+
+       /* Futex call.  */
+       movl    %ecx, (%esp)    /* Store relative timeout.  */
+       movl    %edx, 4(%esp)
+       xorl    %ecx, %ecx      /* movl $FUTEX_WAIT, %ecx */
+       movl    %esp, %esi
+       movl    %ecx, %edx
+       leal    WRITERS_WAKEUP(%ebp), %ebx
+       movl    $SYS_futex, %eax
+       int     $0x80
+       movl    %eax, %edx
+17:
+
+       /* Reget the lock.  */
+       movl    $1, %eax
+       LOCK
+       xaddl   %eax, MUTEX(%ebp)
+       testl   %eax, %eax
+       jne     12f
+
+13:    cmpl    $-ETIMEDOUT, %ecx
+       je      18f
+       decl    WRITERS_QUEUED(%ebp)
+       movl    $0, WRITERS_WAKEUP(%ebp)
+       jmp     2b
+
+
+5:     xorl    %ecx, %ecx
+       movl    %gs:8, %eax
+       movl    %eax, WRITER(%ebp)
+9:     LOCK
+       decl    MUTEX(%ebp)
+       jne     6f
+
+7:     movl    %ecx, %eax
+
+       addl    $8, %esp
+       popl    %ebp
+       popl    %ebx
+       popl    %edi
+       popl    %esi
+       ret
+
+1:     movl    %ebp, %ecx
+       call    __lll_mutex_lock_wait
+       jmp     2b
+
+14:    cmpl    %gs:8, %eax
+       jne     3b
+       movl    $EDEADLK, %ecx
+       jmp     9b
+
+6:     movl    %ebp, %eax
+       call    __lll_mutex_unlock_wake
+       jmp     7b
+
+       /* Overflow.  */
+4:     decl    WRITERS_QUEUED(%ebp)
+       movl    $EAGAIN, %ecx
+       jmp     9b
+
+10:    movl    %ebp, %eax
+       call    __lll_mutex_unlock_wake
+       jmp     11b
+
+12:    movl    %ebx, %ecx
+       call    __lll_mutex_lock_wait
+       jmp     13b
+
+16:    movl    $-ETIMEDOUT, %ecx
+       jmp     17b
+
+18:    movl    $ETIMEDOUT, %ecx
+       jmp     9b
+       .size   pthread_rwlock_timedwrlock,.-pthread_rwlock_timedwrlock
+
+       .globl  __pthread_rwlock_unlock
+       .type   __pthread_rwlock_unlock,@function
+       .align  16
+__pthread_rwlock_unlock:
+       pushl   %ebx
+       pushl   %esi
+       pushl   %edi
+
+       xorl    %esi, %esi
+       xorl    %edx, %edx
+       movl    16(%esp), %edi
+
+       /* Get the lock.  */
+       movl    $1, %eax
+       LOCK
+       xaddl   %eax, MUTEX(%edi)
+       testl   %eax, %eax
+       jne     1f
+
+2:     cmpl    $0, WRITER(%edi)
+       jne     5f
+       decl    NR_READERS(%edi)
+       jnz     6f
+
+5:     movl    $0, WRITER(%edi)
+
+       movl    $0x7fffffff, %edx
+       leal    READERS_WAKEUP(%edi), %ebx
+       movl    $1, %ecx
+       leal    WRITERS_WAKEUP(%edi), %eax
+       cmpl    $0, WRITERS_QUEUED(%edi)
+       cmovne  %ecx, %edx
+       cmovne  %eax, %ebx
+       movl    $SYS_futex, %eax
+       int     $0x80
+
+6:     LOCK
+       decl    MUTEX(%edi)
+       jne     3f
+
+4:     xorl    %eax, %eax
+       popl    %edi
+       popl    %esi
+       popl    %ebx
+       ret
+
+1:     movl    %edi, %ecx
+       call    __lll_mutex_lock_wait
+       jmp     2b
+
+3:     movl    %edi, %eax
+       call    __lll_mutex_unlock_wake
+       jmp     4b
+
+       .size   __pthread_rwlock_unlock,.-__pthread_rwlock_unlock
+
+       .globl  pthread_rwlock_unlock
+pthread_rwlock_unlock = __pthread_rwlock_unlock
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevelsem.S b/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevelsem.S
new file mode 100644 (file)
index 0000000..18fb16f
--- /dev/null
@@ -0,0 +1,311 @@
+/* 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 <sysdep.h>
+#include <shlib-compat.h>
+
+       .text
+
+#ifndef UP
+# define LOCK lock
+#else
+# define
+#endif
+
+#define SYS_gettimeofday       __NR_gettimeofday
+#define SYS_futex              240
+#define FUTEX_WAKE             1
+
+#define EINTR                  4
+#define EAGAIN                 11
+#define EWOULDBLOCK            EAGAIN
+#define EINVAL                 22
+#define ETIMEDOUT              110
+
+
+       .globl  __new_sem_wait
+       .type   __new_sem_wait,@function
+       .align  16
+__new_sem_wait:
+       pushl   %ebx
+       pushl   %esi
+
+       movl    12(%esp), %ebx
+
+3:     movl    (%ebx), %eax
+2:     testl   %eax, %eax
+       je,pn   1f
+
+       leal    -1(%eax), %edx
+       LOCK
+       cmpxchgl %edx, (%ebx)
+       jne,pn  2b
+       xorl    %eax, %eax
+
+       popl    %esi
+       popl    %ebx
+       ret
+
+1:     xorl    %esi, %esi
+       movl    $SYS_futex, %eax
+       movl    %esi, %ecx
+       movl    %esi, %edx
+       int     $0x80
+
+       testl   %eax, %eax
+       je      3b
+       cmpl    $-EWOULDBLOCK, %eax
+       je      3b
+       negl    %eax
+#ifdef PIC
+       call    __i686.get_pc_thunk.bx
+#else
+       movl    $4f, %ebx
+4:
+#endif
+       addl    $_GLOBAL_OFFSET_TABLE_, %ebx
+       movl    %gs:0, %edx
+       subl    errno@gottpoff(%ebx), %edx
+       movl    %eax, (%edx)
+       orl     $-1, %eax
+       popl    %esi
+       popl    %ebx
+       ret
+       .size   __new_sem_wait,.-__new_sem_wait
+       .symver __new_sem_wait, sem_wait@@GLIBC_2.1
+#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_1)
+       .global __old_sem_wait
+__old_sem_wait = __new_sem_wait
+       .symver __old_sem_wait, sem_wait@GLIBC_2.0
+#endif
+
+
+       .globl  __new_sem_trywait
+       .type   __new_sem_trywait,@function
+       .align  16
+__new_sem_trywait:
+       movl    4(%esp), %ecx
+
+       movl    (%ecx), %eax
+2:     testl   %eax, %eax
+       jz      1f
+
+       leal    -1(%eax), %edx
+       LOCK
+       cmpxchgl %edx, (%ecx)
+       jne,pn  2b
+       xorl    %eax, %eax
+       ret
+
+1:
+#ifdef PIC
+       call    __i686.get_pc_thunk.cx
+#else
+       movl    $3f, %ecx
+3:
+#endif
+       addl    $_GLOBAL_OFFSET_TABLE_, %ecx
+       movl    %gs:0, %edx
+       subl    errno@gottpoff(%ecx), %edx
+       movl    $EAGAIN, (%edx)
+       orl     $-1, %eax
+       ret
+       .size   __new_sem_trywait,.-__new_sem_trywait
+       .symver __new_sem_trywait, sem_trywait@@GLIBC_2.1
+#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_1)
+       .global __old_sem_trywait
+__old_sem_trywait = __new_sem_trywait
+       .symver __old_sem_trywait, sem_trywait@GLIBC_2.0
+#endif
+
+
+       .globl  sem_timedwait
+       .type   sem_timedwait,@function
+       .align  16
+sem_timedwait:
+       movl    4(%esp), %ecx
+
+       movl    (%ecx), %eax
+2:     testl   %eax, %eax
+       je,pn   1f
+
+       leal    -1(%eax), %edx
+       LOCK
+       cmpxchgl %edx, (%ecx)
+       jne,pn  2b
+
+       xorl    %eax, %eax
+       ret
+
+       /* Check whether the timeout value is valid.  */
+1:     pushl   %esi
+       pushl   %edi
+       pushl   %ebx
+       subl    $8, %esp
+
+       movl    %esp, %esi
+       movl    28(%esp), %edi
+
+       /* Check for invalid nanosecond field.  */
+       cmpl    $1000000000, 4(%edi)
+       movl    $EINVAL, %eax
+       jae     6f
+
+7:     xorl    %ecx, %ecx
+       movl    %esp, %ebx
+       movl    %ecx, %edx
+       movl    $SYS_gettimeofday, %eax
+       int     $0x80
+
+       /* Compute relative timeout.  */
+       movl    4(%esp), %eax
+       movl    $1000, %edx
+       mul     %edx            /* Milli seconds to nano seconds.  */
+       movl    (%edi), %ecx
+       movl    4(%edi), %edx
+       subl    (%esp), %ecx
+       subl    %eax, %edx
+       jns     5f
+       addl    $1000000000, %edx
+       decl    %ecx
+5:     testl   %ecx, %ecx
+       movl    $ETIMEDOUT, %eax
+       js      6f              /* Time is already up.  */
+
+       movl    %ecx, (%esp)    /* Store relative timeout.  */
+       movl    %edx, 4(%esp)
+       movl    24(%esp), %ebx
+       xorl    %ecx, %ecx
+       movl    $SYS_futex, %eax
+       xorl    %edx, %edx
+       int     $0x80
+
+       testl   %eax, %eax
+       je,pt   9f
+       cmpl    $-EWOULDBLOCK, %eax
+       jne     3f
+
+9:     movl    (%ebx), %eax
+8:     testl   %eax, %eax
+       je      7b
+
+       leal    -1(%eax), %ecx
+       LOCK
+       cmpxchgl %ecx, (%ebx)
+       jne,pn  8b
+
+       addl    $8, %esp
+       xorl    %eax, %eax
+       popl    %ebx
+       popl    %edi
+       popl    %esi
+       ret
+
+3:     negl    %eax
+6:
+#ifdef PIC
+       call    __i686.get_pc_thunk.bx
+#else
+       movl    $4f, %ebx
+4:
+#endif
+       addl    $_GLOBAL_OFFSET_TABLE_, %ebx
+       movl    %gs:0, %edx
+       subl    errno@gottpoff(%ebx), %edx
+       movl    %eax, (%edx)
+
+       addl    $8, %esp
+       orl     $-1, %eax
+       popl    %ebx
+       popl    %edi
+       popl    %esi
+       ret
+       .size   sem_timedwait,.-sem_timedwait
+
+
+       .globl  __new_sem_post
+       .type   __new_sem_post,@function
+       .align  16
+__new_sem_post:
+       pushl   %esi
+       pushl   %ebx
+
+       movl    12(%esp), %ebx
+       movl    $1, %edx
+       LOCK
+       xaddl   %edx, (%ebx)
+
+       xorl    %esi, %esi
+       movl    $SYS_futex, %eax
+       movl    $FUTEX_WAKE, %ecx
+       incl    %edx
+       int     $0x80
+
+       testl   %eax, %eax
+       js      1f
+
+       popl    %ebx
+       popl    %esi
+       ret
+
+1:
+#ifdef PIC
+       call    __i686.get_pc_thunk.bx
+#else
+       movl    $4f, %ebx
+4:
+#endif
+       addl    $_GLOBAL_OFFSET_TABLE_, %ebx
+       movl    %gs:0, %edx
+       subl    errno@gottpoff(%ebx), %edx
+       movl    $EINVAL, (%edx)
+
+       orl     $-1, %eax
+       popl    %ebx
+       popl    %esi
+       ret
+       .size   __new_sem_post,.-__new_sem_post
+       .symver __new_sem_post, sem_post@@GLIBC_2.1
+#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_1)
+       .global __old_sem_post
+__old_sem_post = __new_sem_post
+       .symver __old_sem_post, sem_post@GLIBC_2.0
+#endif
+
+
+#ifdef PIC
+       .section .gnu.linkonce.t.__i686.get_pc_thunk.bx,"ax",@progbits
+       .globl  __i686.get_pc_thunk.bx
+       .hidden __i686.get_pc_thunk.bx
+       .type   __i686.get_pc_thunk.bx,@function
+__i686.get_pc_thunk.bx:
+       movl (%esp), %ebx;
+       ret
+       .size   __i686.get_pc_thunk.bx,.-__i686.get_pc_thunk.bx
+
+
+       .section .gnu.linkonce.t.__i686.get_pc_thunk.cx,"ax",@progbits
+       .globl  __i686.get_pc_thunk.cx
+       .hidden __i686.get_pc_thunk.cx
+       .type   __i686.get_pc_thunk.cx,@function
+__i686.get_pc_thunk.cx:
+       movl (%esp), %ecx;
+       ret
+       .size   __i686.get_pc_thunk.cx,.-__i686.get_pc_thunk.cx
+#endif
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_barrier_wait.S b/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_barrier_wait.S
new file mode 100644 (file)
index 0000000..a385adc
--- /dev/null
@@ -0,0 +1,122 @@
+/* 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 <sysdep.h>
+
+#define SYS_futex      240
+#define FUTEX_WAIT     0
+#define FUTEX_WAKE     1
+
+#ifndef UP
+# define LOCK lock
+#else
+# define LOCK
+#endif
+
+#define CURR_EVENT     0
+#define MUTEX          4
+#define LEFT           8
+#define        INIT_COUNT      12
+
+
+       .text
+
+       .globl  pthread_barrier_wait
+       .type   pthread_barrier_wait,@function
+       .align  16
+pthread_barrier_wait:
+       pushl   %esi
+       pushl   %ebx
+
+       movl    12(%esp), %ebx
+       xorl    %esi, %esi
+
+       /* Get the mutex.  */
+       orl     $-1, %eax
+       LOCK
+       xaddl   %eax, MUTEX(%ebx)
+       jne     1f
+
+       /* One less waiter.  If this was the last one needed wake
+          everybody.  */
+2:     decl    LEFT(%ebx)
+       je      3f
+
+       /* There are more threads to come.  */
+       movl    CURR_EVENT(%ebx), %edx
+
+       /* Release the mutex.  */
+       LOCK
+       incl    MUTEX(%ebx)
+       jng     6f
+
+       /* Wait for the remaining threads.  The call will return immediately
+          if the CURR_EVENT memory has meanwhile been changed.  */
+7:     movl    %esi, %ecx              /* movl $FUTEX_WAIT, %ecx */
+8:     movl    $SYS_futex, %eax
+       int     $0x80
+
+       /* Don't return on spurious wakeups.  The syscall does not change
+          any register except %eax so there is no need to reload any of
+          them.  */
+       cmpl    %edx, CURR_EVENT(%ebx)
+       je,pn   8b
+
+       /* Note: %esi is still zero.  */
+       movl    %esi, %eax              /* != PTHREAD_BARRIER_SERIAL_THREAD */
+
+       popl    %ebx
+       popl    %esi
+       ret
+
+       /* The necessary number of threads arrived.  */
+3:     movl    INIT_COUNT(%ebx), %eax
+       movl    %eax, LEFT(%ebx)
+       incl    CURR_EVENT(%ebx)
+
+       /* Wake up all waiters.  The count is a signed number in the kernel
+          so 0x7fffffff is the highest value.  */
+       movl    $0x7fffffff, %edx
+       movl    $FUTEX_WAKE, %ecx
+       movl    $SYS_futex, %eax
+       int     $0x80
+
+       /* Release the mutex.  */
+       LOCK
+       incl    MUTEX(%ebx)
+       jng     4f
+
+5:     orl     $-1, %eax               /* == PTHREAD_BARRIER_SERIAL_THREAD */
+
+       popl    %ebx
+       popl    %esi
+       ret
+
+1:     leal    MUTEX(%ebx), %ecx
+       call    __lll_lock_wait
+       jmp     2b
+
+4:     leal    MUTEX(%ebx), %eax
+       call    __lll_unlock_wake
+       jmp     5b
+
+6:     leal    MUTEX(%ebx), %eax
+       call    __lll_unlock_wake
+       jmp     7b
+       .size   pthread_barrier_wait,.-pthread_barrier_wait
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevelcond.S b/nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevelcond.S
new file mode 100644 (file)
index 0000000..3dc8403
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "../i486/lowlevelcond.S"
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevellock.S b/nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevellock.S
new file mode 100644 (file)
index 0000000..e60dea8
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "../i486/lowlevellock.S"
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevelmutex.S b/nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevelmutex.S
new file mode 100644 (file)
index 0000000..5048199
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "../i486/lowlevelmutex.S"
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevelrwlock.S b/nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevelrwlock.S
new file mode 100644 (file)
index 0000000..6f4a830
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "../i486/lowlevelrwlock.S"
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevelsem.S b/nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevelsem.S
new file mode 100644 (file)
index 0000000..cfaa36a
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "../i486/lowlevelsem.S"
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_barrier_wait.S b/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_barrier_wait.S
new file mode 100644 (file)
index 0000000..6d20b9a
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "../i486/pthread_barrier_wait.S"
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevelcond.S b/nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevelcond.S
new file mode 100644 (file)
index 0000000..3dc8403
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "../i486/lowlevelcond.S"
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevellock.S b/nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevellock.S
new file mode 100644 (file)
index 0000000..e60dea8
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "../i486/lowlevellock.S"
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevelmutex.S b/nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevelmutex.S
new file mode 100644 (file)
index 0000000..5048199
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "../i486/lowlevelmutex.S"
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevelrwlock.S b/nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevelrwlock.S
new file mode 100644 (file)
index 0000000..6f4a830
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "../i486/lowlevelrwlock.S"
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevelsem.S b/nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevelsem.S
new file mode 100644 (file)
index 0000000..cfaa36a
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "../i486/lowlevelsem.S"
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_barrier_wait.S b/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_barrier_wait.S
new file mode 100644 (file)
index 0000000..6d20b9a
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "../i486/pthread_barrier_wait.S"
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h b/nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h
new file mode 100644 (file)
index 0000000..71babd5
--- /dev/null
@@ -0,0 +1,257 @@
+/* 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 _LOWLEVELLOCK_H
+#define _LOWLEVELLOCK_H        1
+
+#include <time.h>
+#include <bits/pthreadtypes.h>
+
+#ifndef LOCK_INSTR
+# ifdef UP
+#  define LOCK_INSTR   /* nothing */
+# else
+#  define LOCK_INSTR "lock;"
+# endif
+#endif
+
+#define SYS_futex              240
+#define FUTEX_WAIT             0
+#define FUTEX_WAKE             1
+
+
+/* Initializer for compatibility lock.  */
+#define LLL_MUTEX_LOCK_INITIALIZER (0)
+
+
+/* Does not preserve %eax and %ecx.  */
+extern int __lll_mutex_lock_wait (int val, int *__futex)
+     __attribute ((regparm (2))) attribute_hidden;
+/* Does not preserver %eax, %ecx, and %edx.  */
+extern int __lll_mutex_timedlock_wait (int val, int *__futex,
+                                const struct timespec *abstime)
+     __attribute ((regparm (3))) attribute_hidden;
+/* Preserves all registers but %eax.  */
+extern int __lll_mutex_unlock_wait (int *__futex)
+     __attribute ((regparm (1))) attribute_hidden;
+
+
+#define lll_mutex_trylock(futex) \
+  ({ unsigned char ret;                                                              \
+     __asm __volatile (LOCK_INSTR "cmpxchgl %2, %1; setne %0"                \
+                      : "=a" (ret), "=m" (futex)                             \
+                      : "r" (1), "1" (futex), "0" (0));                      \
+     ret; })
+
+
+#define lll_mutex_lock(futex) \
+  (void) ({ int ignore1, ignore2;                                            \
+           __asm (LOCK_INSTR "xaddl %0, %2\n\t"                              \
+                  "testl %0, %0\n\t"                                         \
+                  "jne 1f\n\t"                                               \
+                  ".subsection 1\n"                                          \
+                  "1:\tleal %2, %%ecx\n\t"                                   \
+                  "call __lll_mutex_lock_wait\n\t"                           \
+                  "jmp 2f\n\t"                                               \
+                  ".previous\n"                                              \
+                  "2:"                                                       \
+                  : "=a" (ignore1), "=&c" (ignore2), "=m" (futex)            \
+                  : "0" (1), "2" (futex)); })
+
+
+#define lll_mutex_timedlock(futex, timeout) \
+  ({ int result, ignore1, ignore2;                                           \
+     __asm (LOCK_INSTR "xaddl %0, %3\n\t"                                    \
+           "testl %0, %0\n\t"                                                \
+           "jne 1f\n\t"                                                      \
+           ".subsection 1\n"                                                 \
+           "1:\tleal %3, %%ecx\n\t"                                          \
+           "movl %6, %%edx\n\t"                                              \
+           "call __lll_mutex_timedlock_wait\n\t"                             \
+           "jmp 2f\n\t"                                                      \
+           ".previous\n"                                                     \
+           "2:"                                                              \
+           : "=a" (result), "=&c" (ignore1), "=&d" (ignore2), "=m" (futex)   \
+           : "0" (1), "3" (futex), "m" (timeout));                           \
+     result; })
+
+
+#define lll_mutex_unlock(futex) \
+  (void) ({ int ignore;                                                              \
+            __asm (LOCK_INSTR "decl %0\n\t"                                  \
+                  "jne 1f\n\t"                                               \
+                  ".subsection 1\n"                                          \
+                  "1:\tleal %0, %%eax\n\t"                                   \
+                  "call __lll_mutex_unlock_wake\n\t"                         \
+                  "jmp 2f\n\t"                                               \
+                  ".previous\n"                                              \
+                  "2:"                                                       \
+                  : "=m" (futex), "=&a" (ignore)                             \
+                  : "0" (futex)); })
+
+
+#define lll_mutex_islocked(futex) \
+  (futex != 0)
+
+
+/* We have a separate internal lock implementation which is not tied
+   to binary compatibility.  */
+
+/* Type for lock object.  */
+typedef int lll_lock_t;
+
+/* Initializers for lock.  */
+#define LLL_LOCK_INITIALIZER           (1)
+#define LLL_LOCK_INITIALIZER_LOCKED    (0)
+
+
+extern int __lll_lock_wait (int val, int *__futex)
+     __attribute ((regparm (2))) attribute_hidden;
+extern int __lll_unlock_wake (int *__futex)
+     __attribute ((regparm (1))) attribute_hidden;
+extern int lll_unlock_wake_cb (int *__futex) attribute_hidden;
+
+
+/* The states of a lock are:
+    1  -  untaken
+    0  -  taken by one user
+   <0  -  taken by more users */
+
+
+#define lll_trylock(futex) \
+  ({ unsigned char ret;                                                              \
+     __asm __volatile (LOCK_INSTR "cmpxchgl %2, %1; setne %0"                \
+                      : "=a" (ret), "=m" (futex)                             \
+                      : "r" (0), "1" (futex), "0" (1));                      \
+     ret; })
+
+
+#define lll_lock(futex) \
+  (void) ({ int ignore1, ignore2;                                            \
+           __asm (LOCK_INSTR "xaddl %0, %2\n\t"                              \
+                  "jne 1f\n\t"                                               \
+                  ".subsection 1\n"                                          \
+                  "1:\tleal %2, %%ecx\n\t"                                   \
+                  "call __lll_lock_wait\n\t"                                 \
+                  "jmp 2f\n\t"                                               \
+                  ".previous\n"                                              \
+                  "2:"                                                       \
+                  : "=a" (ignore1), "=&c" (ignore2), "=m" (futex)            \
+                  : "0" (-1), "2" (futex)); })
+
+
+#define lll_unlock(futex) \
+  (void) ({ int ignore;                                                              \
+            __asm (LOCK_INSTR "incl %0\n\t"                                  \
+                  "jng 1f\n\t"                                               \
+                  ".subsection 1\n"                                          \
+                  "1:\tleal %0, %%eax\n\t"                                   \
+                  "call __lll_unlock_wake\n\t"                               \
+                  "jmp 2f\n\t"                                               \
+                  ".previous\n"                                              \
+                  "2:"                                                       \
+                  : "=m" (futex), "=&a" (ignore)                             \
+                  : "0" (futex)); })
+
+
+#define lll_islocked(futex) \
+  (futex != 0)
+
+
+/* The kernel notifies a process with uses CLONE_CLEARTID via futex
+   wakeup when the clone terminates.  The memory location contains the
+   thread ID while the clone is running and is reset to zero
+   afterwards.
+
+   The macro parameter must not have any side effect.  */
+#ifdef PIC
+# define LLL_TID_EBX_LOAD      "xchgl %2, %%ebx\n"
+# define LLL_TID_EBX_REG       "D"
+#else
+# define LLL_TID_EBX_LOAD
+# define LLL_TID_EBX_REG       "b"
+#endif
+#define lll_wait_tid(tid) \
+  do {                                                                       \
+    int __ignore;                                                            \
+    register __typeof (tid) _tid asm ("edx") = (tid);                        \
+    if (_tid != 0)                                                           \
+      __asm __volatile (LLL_TID_EBX_LOAD                                     \
+                       "1:\tmovl %1, %%eax\n\t"                              \
+                       "int $0x80\n\t"                                       \
+                       "cmpl $0, (%%ebx)\n\t"                                \
+                       "jne,pn 1b\n\t"                                       \
+                       LLL_TID_EBX_LOAD                                      \
+                       : "=&a" (__ignore)                                    \
+                       : "i" (SYS_futex), LLL_TID_EBX_REG (&tid), "S" (0),   \
+                         "c" (FUTEX_WAIT), "d" (_tid));                      \
+  } while (0)
+
+extern int __lll_timedwait_tid (int *tid, const struct timespec *abstime)
+     __attribute__ ((regparm (2))) attribute_hidden;
+#define lll_timedwait_tid(tid, abstime) \
+  ({                                                                         \
+    int __result = 0;                                                        \
+    if (tid != 0)                                                            \
+      {                                                                              \
+       if (abstime == NULL || abstime->tv_nsec >= 1000000000)                \
+         __result = EINVAL;                                                  \
+       else                                                                  \
+         __result = __lll_timedwait_tid (&tid, abstime);                     \
+      }                                                                              \
+    __result; })
+
+
+#define lll_wake_tid(tid) \
+  do {                                                                       \
+    int __ignore;                                                            \
+    (tid) = 0;                                                               \
+    __asm __volatile (LLL_TID_EBX_LOAD                                       \
+                     "\tint $0x80\n\t"                                       \
+                     LLL_TID_EBX_LOAD                                        \
+                     : "=a" (__ignore)                                       \
+                     : "0" (SYS_futex), LLL_TID_EBX_REG (&(tid)), "S" (0),   \
+                       "c" (FUTEX_WAKE), "d" (0x7fffffff));                  \
+  } while (0)
+
+
+/* Conditional variable handling.  */
+
+extern void __lll_cond_wait (pthread_cond_t *cond)
+     __attribute ((regparm (1))) attribute_hidden;
+extern int __lll_cond_timedwait (pthread_cond_t *cond,
+                                const struct timespec *abstime)
+     __attribute ((regparm (2))) attribute_hidden;
+extern void __lll_cond_wake (pthread_cond_t *cond)
+     __attribute ((regparm (1))) attribute_hidden;
+extern void __lll_cond_broadcast (pthread_cond_t *cond)
+     __attribute ((regparm (1))) attribute_hidden;
+
+
+#define lll_cond_wait(cond) \
+  __lll_cond_wait (cond)
+#define lll_cond_timedwait(cond, abstime) \
+  __lll_cond_timedwait (cond, abstime)
+#define lll_cond_wake(cond) \
+  __lll_cond_wake (cond)
+#define lll_cond_broadcast(cond) \
+  __lll_cond_broadcast (cond)
+
+
+#endif /* lowlevellock.h */
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/lowlevelsem.h b/nptl/sysdeps/unix/sysv/linux/i386/lowlevelsem.h
new file mode 100644 (file)
index 0000000..bd5f964
--- /dev/null
@@ -0,0 +1,101 @@
+/* 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 _LOWLEVELSEM_H
+#define _LOWLEVELSEM_H 1
+
+#ifndef LOCK
+# ifdef UP
+#  define LOCK /* nothing */
+# else
+#  define LOCK "lock;"
+# endif
+#endif
+
+#define SYS_futex              240
+
+
+#define lll_sem_wait(sem) \
+  ({ int result, ignore1, ignore2;                                           \
+     __asm __volatile ("1:\tincl 8(%4)\n\t"                                  \
+                      LOCK "incl (%4)\n\t"                                   \
+                      "jng 2f\n"                                             \
+                      ".subsection 1\n"                                      \
+                      "2:\tmovl %4, %%eax\n\t"                               \
+                      "call __lll_unlock_wake\n\t"                           \
+                      "jmp 3f\n\t"                                           \
+                      ".previous\n"                                          \
+                      "3:\tpushl %%ebx\n\t"                                  \
+                      "movl %%esi, %%ecx\n\t"                                \
+                      "movl %%esi, %%edx\n\t"                                \
+                      "leal 4(%4), %%ebx\n\t"                                \
+                      "movl %5, %%eax\n\t"                                   \
+                      "int $0x80\n\t"                                        \
+                      "movl %%eax, %%edx\n\t"                                \
+                      "popl %%ebx\n\t"                                       \
+                      "orl $-1, %%eax\n\t"                                   \
+                      LOCK "xaddl %%eax, (%4)\n\t"                           \
+                      "jne 4f\n\t"                                           \
+                      ".subsection 1\n"                                      \
+                      "4:\tmovl %4, %%ecx\n\t"                               \
+                      "call __lll_lock_wait\n\t"                             \
+                      "jmp 5f\n\t"                                           \
+                      ".previous\n"                                          \
+                      "5:\tdecl 8(%4)\n\t"                                   \
+                      "xorl %0, %0\n\t"                                      \
+                      "cmpl $0, 4(%4)\n\t"                                   \
+                      "jne,pt 6f\n\t"                                        \
+                      "cmpl %7, %%edx\n\t"                                   \
+                      "jne,pn 1b\n\t"                                        \
+                      "addl %8, %0\n\t" /* Shorter than movl %7, %0 */       \
+                      "6:"                                                   \
+                      : "=a" (result), "=c" (ignore1), "=d" (ignore2),       \
+                        "=m" (*sem)                                          \
+                      : "D" (sem), "i" (SYS_futex), "S" (0),                 \
+                        "i" (-EINTR), "i" (EINTR));                          \
+     result; })
+
+
+extern int __lll_sem_timedwait (struct sem *sem, const struct timespec *ts)
+     __attribute__ ((regparm (2))) attribute_hidden;
+#define lll_sem_timedwait(sem, timeout) \
+  __lll_sem_timedwait (sem, timeout)
+
+
+#define lll_sem_post(sem) \
+  (void) ({ int ignore1, ignore2, ignore3;                                   \
+           __asm __volatile ("movl $1, %%eax\n\t"                            \
+                             LOCK                                            \
+                             "xaddl %%eax, (%4)\n\t"                         \
+                             "pushl %%esi\n\t"                               \
+                             "pushl %%ebx\n\t"                               \
+                             "movl %4, %%ebx\n\t"                            \
+                             "leal 1(%%eax), %%edx\n\t"                      \
+                             "xorl %%esi, %%esi\n\t"                         \
+                             "movl %5, %%eax\n\t"                            \
+                             /* movl $FUTEX_WAKE, %ecx */                    \
+                             "movl $1, %%ecx\n\t"                            \
+                             "int $0x80\n\t"                                 \
+                             "popl %%ebx\n\t"                                \
+                             "popl %%esi"                                    \
+                             : "=&a" (ignore1), "=c" (ignore2),              \
+                               "=m" (*sem), "=d" (ignore3)                   \
+                             : "r" (sem), "i" (SYS_futex)); })
+
+#endif /* lowlevelsem.h */
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/pt-vfork.S b/nptl/sysdeps/unix/sysv/linux/i386/pt-vfork.S
new file mode 100644 (file)
index 0000000..6994c0d
--- /dev/null
@@ -0,0 +1,49 @@
+/* Copyright (C) 1999, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Andreas Schwab <schwab@gnu.org>.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#define _ERRNO_H       1
+#include <bits/errno.h>
+#include <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)
+       /* 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
+       jae     SYSCALL_ERROR_LABEL     /* Branch forward if it failed.  */
+.Lpseudo_end:
+       ret
+PSEUDO_END (__vfork)
+
+weak_alias (__vfork, vfork)
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/pthread_once.S b/nptl/sysdeps/unix/sysv/linux/i386/pthread_once.S
new file mode 100644 (file)
index 0000000..747c8ec
--- /dev/null
@@ -0,0 +1,171 @@
+/* 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 <sysdep.h>
+
+#ifndef UP
+# define LOCK lock
+#else
+# define LOCK
+#endif
+
+#define SYS_futex      240
+#define FUTEX_WAKE     1
+
+       .comm   __fork_generation, 4, 4
+
+       .text
+
+
+       .globl  __pthread_once
+       .type   __pthread_once,@function
+       .align  16
+__pthread_once:
+       movl    4(%esp), %ecx
+       testl   $2, (%ecx)
+       jz      1f
+       xorl    %eax, %eax
+       ret
+
+1:     pushl   %ebx
+       pushl   %esi
+       movl    %ecx, %ebx
+       xorl    %esi, %esi
+
+       /* Not yet initialized or initialization in progress.
+          Get the fork generation counter now.  */
+6:     movl    (%ebx), %eax
+#ifdef PIC
+       call    __i686.get_pc_thunk.cx
+       addl    $_GLOBAL_OFFSET_TABLE_, %ecx
+#endif
+
+5:     movl    %eax, %edx
+
+       testl   $2, %eax
+       jnz     4f
+
+       andl    $3, %edx
+#ifdef PIC
+       orl     __fork_generation@GOTOFF(%ecx), %edx
+#else
+       orl     __fork_generation, %edx
+#endif
+       orl     $1, %edx
+
+       LOCK
+       cmpxchgl %edx, (%ebx)
+       jnz     5b
+
+       /* Check whether another thread already runs the initializer.  */
+       testl   $1, %eax
+       jz      3f      /* No -> do it.  */
+
+       /* Check whether the initializer execution was interrupted
+          by a fork.  */
+       xorl    %edx, %eax
+       testl   $0xfffffffc, %eax
+       jnz     3f      /* Different for generation -> run initializer.  */
+
+       /* Somebody else got here first.  Wait.  */
+       movl    %esi, %ecx              /* movl $FUTEX_WAIT, %ecx */
+       movl    $SYS_futex, %eax
+       int     $0x80
+       jmp     6b
+
+3:     /* Call the initializer function after setting up the
+          cancellation handler.  */
+       subl    $16, %esp
+
+       /* Push the cleanup handler.  */
+#ifdef PIC
+       leal    clear_once_control@GOTOFF(%ecx), %eax
+#else
+       leal    clear_once_control, %eax
+#endif
+       movl    %esp, %edx
+       pushl   %ebx
+       pushl   %eax
+       pushl   %edx
+       call    _GI_pthread_cleanup_push        /* Note: no @PLT.  */
+
+       movl    44(%esp), %eax
+       call    *%eax
+
+       /* Pop the cleanup handler.  This code depends on the once
+          handler and _pthread_cleanup_push not touch the content
+          of the stack.  Otherwise the first parameter would have
+          to be reloaded.  */
+       movl    $0, 4(%esp)
+       call    _GI_pthread_cleanup_pop /* Note: no @PLT.  */
+
+       addl    $28, %esp
+
+       /* Sucessful run of the initializer.  Signal that we are done.  */
+       LOCK
+       incl    (%ebx)
+
+       /* Wake up all other threads.  */
+       movl    $0x7fffffff, %edx
+       movl    $FUTEX_WAKE, %ecx
+       movl    $SYS_futex, %eax
+       int     $0x80
+
+4:     popl    %esi
+       popl    %ebx
+       xorl    %eax, %eax
+       ret
+
+       .size   __pthread_once,.-__pthread_once
+
+       .globl  pthread_once
+pthread_once = __pthread_once
+
+
+       .type   clear_once_control,@function
+       .align  16
+clear_once_control:
+       pushl   %esi
+       pushl   %ebx
+
+       movl    4(%esp), %eax
+       movl    $0, (%eax)
+
+       xorl    %esi, %esi
+       movl    $0x7fffffff, %edx
+       movl    $FUTEX_WAKE, %ecx
+       movl    $SYS_futex, %eax
+       int     $0x80
+
+       popl    %ebx
+       popl    %esi
+       ret
+       .size   clear_once_control,.-clear_once_control
+
+
+#ifdef PIC
+       .section .gnu.linkonce.t.__i686.get_pc_thunk.cx,"ax",@progbits
+       .globl  __i686.get_pc_thunk.cx
+       .hidden __i686.get_pc_thunk.cx
+       .type   __i686.get_pc_thunk.cx,@function
+__i686.get_pc_thunk.cx:
+       movl (%esp), %ecx;
+       ret
+       .size   __i686.get_pc_thunk.cx,.-__i686.get_pc_thunk.cx
+#endif
diff --git a/nptl/sysdeps/unix/sysv/linux/internaltypes.h b/nptl/sysdeps/unix/sysv/linux/internaltypes.h
new file mode 100644 (file)
index 0000000..24ead1b
--- /dev/null
@@ -0,0 +1,130 @@
+/* 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 _INTERNALTYPES_H
+#define _INTERNALTYPES_H       1
+
+
+struct pthread_attr
+{
+  /* Scheduler parameters and priority.  */
+  struct sched_param schedparam;
+  int schedpolicy;
+  /* Various flags like detachstate, scope, etc.  */
+  int flags;
+  /* Size of guard area.  */
+  size_t guardsize;
+  /* Stack handling.  */
+  void *stackaddr;
+  size_t stacksize;
+
+  /* Chain of all initialized attributes.  Keep this last since it is
+     not always used.  */
+  struct pthread_attr *next;
+};
+
+#define ATTR_FLAG_DETACHSTATE          0x0001
+#define ATTR_FLAG_NOTINHERITSCHED      0x0002
+#define ATTR_FLAG_SCOPEPROCESS         0x0004
+#define ATTR_FLAG_STACKADDR            0x0008
+
+
+/* Mutex attribute data structure.  */
+struct pthread_mutexattr
+{
+  /* Identifier for the kind of mutex.
+
+     Bit 31 is set if the mutex is to be shared between processes.
+
+     Bit 0 to 30 contain one of the PTHREAD_MUTEX_ values to identify
+     the type of the mutex.  */
+  int mutexkind;
+};
+
+
+/* Conditional variable attribute data structure.  */
+struct pthread_condattr
+{
+  /* Flag whether coditional variable will be shareable between processes.  */
+  int pshared;
+};
+
+
+/* Read-write lock variable attribute data structure.  */
+struct pthread_rwlockattr
+{
+  int lockkind;
+  int pshared;
+};
+
+
+/* Barrier data structure.  */
+struct pthread_barrier
+{
+  unsigned int curr_event;
+  int lock;
+  unsigned int left;
+  unsigned int init_count;
+};
+
+
+/* Barrier variable attribute data structure.  */
+struct pthread_barrierattr
+{
+  int pshared;
+};
+
+
+/* Thread-local data handling.  */
+struct pthread_key_struct
+{
+  /* Sequence numbers.  Even numbers indicated vacant entries.  Note
+     that zero is even.  We use uintptr_t to not require padding on
+     32- and 64-bit machines.  On 64-bit machines it helps to avoid
+     wrapping, too.  */
+  uintptr_t seq;
+
+  /* Destructor for the data.  */
+  void (*destr) (void *);
+};
+
+/* Check whether an entry is unused.  */
+#define KEY_UNUSED(p) (((p) & 1) == 0)
+/* Check whether a key is usable.  We cannot reuse an allocated key if
+   the sequence counter would overflow after the next destroy call.
+   This would mean that we potentially free memory for a key with the
+   same sequence.  This is *very* unlikely to happen, A program would
+   have to create and destroy a key 2^31 times (on 32-bit platforms,
+   on 64-bit platforms that would be 2^63).  If it should happen we
+   simply don't use this specific key anymore.  */
+#define KEY_USABLE(p) (((uintptr_t) (p)) < ((uintptr_t) ((p) + 2)))
+
+
+/* Handling of read-write lock data.  */
+// XXX For now there is only one flag.  Maybe more in future.
+#define RWLOCK_RECURSIVE(rwlock) ((rwlock)->__data.__flags != 0)
+
+
+/* Semaphore variable structure.  */
+struct sem
+{
+  unsigned int count;
+};
+
+#endif /* internaltypes.h */
diff --git a/nptl/sysdeps/unix/sysv/linux/jmp-unwind.c b/nptl/sysdeps/unix/sysv/linux/jmp-unwind.c
new file mode 100644 (file)
index 0000000..0fd3c9a
--- /dev/null
@@ -0,0 +1,33 @@
+/* _longjmp_unwind -- Clean up stack frames unwound by longjmp.  Linux version.
+   Copyright (C) 1995, 1997, 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 <setjmp.h>
+#include <stddef.h>
+
+
+extern void __pthread_cleanup_upto (jmp_buf env, char *targetframe);
+#pragma weak __pthread_cleanup_upto
+
+
+void
+_longjmp_unwind (jmp_buf env, int val)
+{
+  if (__pthread_cleanup_upto != NULL)
+    __pthread_cleanup_upto (env, __builtin_frame_address (0));
+}
diff --git a/nptl/sysdeps/unix/sysv/linux/pt-fork.c b/nptl/sysdeps/unix/sysv/linux/pt-fork.c
new file mode 100644 (file)
index 0000000..a1e228e
--- /dev/null
@@ -0,0 +1,28 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <unistd.h>
+
+
+pid_t
+__fork (void)
+{
+  return __libc_fork ();
+}
+strong_alias (__fork, fork)
diff --git a/nptl/sysdeps/unix/sysv/linux/pt-raise.c b/nptl/sysdeps/unix/sysv/linux/pt-raise.c
new file mode 100644 (file)
index 0000000..0c68960
--- /dev/null
@@ -0,0 +1,31 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <signal.h>
+#include <sysdep.h>
+#include <tls.h>
+
+
+int
+raise (sig)
+     int sig;
+{
+  return INLINE_SYSCALL (tkill, 2, THREAD_SELF->tid, sig);
+}
diff --git a/nptl/sysdeps/unix/sysv/linux/pthread_kill.c b/nptl/sysdeps/unix/sysv/linux/pthread_kill.c
new file mode 100644 (file)
index 0000000..f5c2377
--- /dev/null
@@ -0,0 +1,36 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <signal.h>
+#include <pthreadP.h>
+#include <tls.h>
+#include <sysdep.h>
+
+
+int
+pthread_kill (threadid, signo)
+     pthread_t threadid;
+     int signo;
+{
+  struct pthread *pd = (struct pthread *) threadid;
+
+  /* We have a special syscall to do the work.  */
+  return INLINE_SYSCALL (tkill, 2, pd->tid, signo);
+}
diff --git a/nptl/sysdeps/unix/sysv/linux/pthread_yield.c b/nptl/sysdeps/unix/sysv/linux/pthread_yield.c
new file mode 100644 (file)
index 0000000..5aecffc
--- /dev/null
@@ -0,0 +1,30 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <sched.h>
+
+
+/* With the 1-on-1 model we implement this function is equivalent to
+   the 'sched_yield' function.  */
+int
+pthread_yield (void)
+{
+  return sched_yield ();
+}
diff --git a/nptl/sysdeps/unix/sysv/linux/raise.c b/nptl/sysdeps/unix/sysv/linux/raise.c
new file mode 100644 (file)
index 0000000..009f32a
--- /dev/null
@@ -0,0 +1,39 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <signal.h>
+#include <sysdep.h>
+#include <nptl/pthreadP.h>
+
+
+int
+raise (sig)
+     int sig;
+{
+  struct pthread *pd = THREAD_SELF;
+  pid_t selftid = pd->tid;
+  if (selftid == 0)
+    {
+      selftid = INLINE_SYSCALL (gettid, 0);
+      THREAD_SETMEM (pd, tid, selftid);
+    }
+
+  return INLINE_SYSCALL (tkill, 2, selftid, sig);
+}
diff --git a/nptl/sysdeps/unix/sysv/linux/register-atfork.c b/nptl/sysdeps/unix/sysv/linux/register-atfork.c
new file mode 100644 (file)
index 0000000..ef70dde
--- /dev/null
@@ -0,0 +1,87 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <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.  */
+  lll_lock (__fork_lock);
+
+  /* Now that we have all the handlers allocate enqueue them.  */
+  if (new_prepare != NULL)
+    list_add_tail (&new_prepare->list, &__fork_prepare_list);
+  if (new_parent != NULL)
+    list_add_tail (&new_parent->list, &__fork_parent_list);
+  if (new_child != NULL)
+    list_add_tail (&new_child->list, &__fork_child_list);
+
+  /* Release the lock.  */
+  lll_unlock (__fork_lock);
+
+  return 0;
+}
diff --git a/nptl/sysdeps/unix/sysv/linux/unregister-atfork.c b/nptl/sysdeps/unix/sysv/linux/unregister-atfork.c
new file mode 100644 (file)
index 0000000..470f80d
--- /dev/null
@@ -0,0 +1,49 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <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.  */
+  lll_lock (__fork_lock);
+
+  list_t *runp;
+  list_t *prevp;
+
+  list_for_each_prev_safe (runp, prevp, &__fork_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_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_child_list)
+    if (list_entry (runp, struct fork_handler, list)->dso_handle == dso_handle)
+      list_del (runp);
+
+  /* Release the lock.  */
+  lll_unlock (__fork_lock);
+}
diff --git a/nptl/tst-atfork1.c b/nptl/tst-atfork1.c
new file mode 100644 (file)
index 0000000..25bd3f2
--- /dev/null
@@ -0,0 +1,112 @@
+/* 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 int val;
+
+
+static void
+prepare1 (void)
+{
+  val *= 2;
+}
+
+static void
+prepare2 (void)
+{
+  ++val;
+}
+
+static void
+parent1 (void)
+{
+  val += 4;
+}
+
+static void
+parent2 (void)
+{
+  val *= 4;
+}
+
+static void
+child1 (void)
+{
+  val += 8;
+}
+
+static void
+child2 (void)
+{
+  val *= 8;
+}
+
+
+static int
+do_test (void)
+{
+  pid_t pid;
+
+  if (pthread_atfork (prepare1, parent1, child1) != 0)
+    {
+      puts ("1st atfork failed");
+      exit (1);
+    }
+  if (pthread_atfork (prepare2, parent2, child2) != 0)
+    {
+      puts ("2nd atfork failed");
+      exit (1);
+    }
+
+  pid = fork ();
+  if (pid == -1)
+    {
+      puts ("fork failed");
+      exit (1);
+    }
+
+  if (pid != 0)
+    {
+      /* Parent.  */
+      if (val != 24)
+       {
+         printf ("expected val=%d, got %d\n", 24, val);
+         exit (1);
+       }
+    }
+  else
+    {
+      /* Child.  */
+      if (val != 80)
+       {
+         printf ("expected val=%d, got %d\n", 80, val);
+         exit (1);
+       }
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-barrier1.c b/nptl/tst-barrier1.c
new file mode 100644 (file)
index 0000000..2859fb4
--- /dev/null
@@ -0,0 +1,71 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+
+
+static int
+do_test (void)
+{
+  pthread_barrier_t b;
+  int e;
+  int cnt;
+
+  e = pthread_barrier_init (&b, NULL, 0);
+  if (e == 0)
+    {
+      puts ("barrier_init with count 0 succeeded");
+      return 1;
+    }
+  if (e != EINVAL)
+    {
+      puts ("barrier_init with count 0 didn't return EINVAL");
+      return 1;
+    }
+
+  if (pthread_barrier_init (&b, NULL, 1) != 0)
+    {
+      puts ("real barrier_init failed");
+      return 1;
+    }
+
+  for (cnt = 0; cnt < 10; ++cnt)
+    {
+      e = pthread_barrier_wait (&b);
+
+      if (e != PTHREAD_BARRIER_SERIAL_THREAD)
+       {
+         puts ("barrier_wait didn't return PTHREAD_BARRIER_SERIAL_THREAD");
+         return 1;
+       }
+    }
+
+  if (pthread_barrier_destroy (&b) != 0)
+    {
+      puts ("barrier_destroy failed");
+      return 1;
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-barrier2.c b/nptl/tst-barrier2.c
new file mode 100644 (file)
index 0000000..5b620b7
--- /dev/null
@@ -0,0 +1,182 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+
+
+int
+main (void)
+{
+  size_t ps = sysconf (_SC_PAGESIZE);
+  char tmpfname[] = "/tmp/tst-barrier2.XXXXXX";
+  char data[ps];
+  void *mem;
+  int fd;
+  pthread_barrier_t *b;
+  pthread_barrierattr_t a;
+  pid_t pid;
+  int serials = 0;
+  int cnt;
+  int status;
+  int p;
+
+  fd = mkstemp (tmpfname);
+  if (fd == -1)
+    {
+      printf ("cannot open temporary file: %m\n");
+      exit (1);
+    }
+
+  /* Make sure it is always removed.  */
+  unlink (tmpfname);
+
+  /* Create one page of data.  */
+  memset (data, '\0', ps);
+
+  /* Write the data to the file.  */
+  if (write (fd, data, ps) != ps)
+    {
+      puts ("short write");
+      exit (1);
+    }
+
+  mem = mmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+  if (mem == MAP_FAILED)
+    {
+      printf ("mmap failed: %m\n");
+      exit (1);
+    }
+
+  b = (pthread_barrier_t *) (((uintptr_t) mem + __alignof (pthread_barrier_t))
+                            & ~(__alignof (pthread_barrier_t) - 1));
+
+  if (pthread_barrierattr_init (&a) != 0)
+    {
+      puts ("barrierattr_init failed");
+      exit (1);
+    }
+
+  if (pthread_barrierattr_getpshared (&a, &p) != 0)
+    {
+      puts ("1st barrierattr_getpshared failed");
+      exit (1);
+    }
+
+  if (p != PTHREAD_PROCESS_PRIVATE)
+    {
+      puts ("default pshared value wrong");
+      exit (1);
+    }
+
+  if (pthread_barrierattr_setpshared (&a, PTHREAD_PROCESS_SHARED) != 0)
+    {
+      puts ("barrierattr_setpshared failed");
+      exit (1);
+    }
+
+  if (pthread_barrierattr_getpshared (&a, &p) != 0)
+    {
+      puts ("2nd barrierattr_getpshared failed");
+      exit (1);
+    }
+
+  if (p != PTHREAD_PROCESS_SHARED)
+    {
+      puts ("pshared value after setpshared call wrong");
+      exit (1);
+    }
+
+  if (pthread_barrier_init (b, &a, 2) != 0)
+    {
+      puts ("barrier_init failed");
+      exit (1);
+    }
+
+  if (pthread_barrierattr_destroy (&a) != 0)
+    {
+      puts ("barrierattr_destroy failed");
+      exit (1);
+    }
+
+  puts ("going to fork now");
+  pid = fork ();
+  if (pid == -1)
+    {
+      puts ("fork failed");
+      exit (1);
+    }
+
+  /* Just to be sure we don't hang forever.  */
+  alarm (4);
+
+#define N 30
+  for (cnt = 0; cnt < N; ++cnt)
+    {
+      int e;
+
+      e = pthread_barrier_wait (b);
+      if (e == PTHREAD_BARRIER_SERIAL_THREAD)
+       ++serials;
+      else if (e != 0)
+       {
+         printf ("%s: barrier_wait returned value %d != 0 and PTHREAD_BARRIER_SERIAL_THREAD\n",
+                 pid == 0 ? "child" : "parent", e);
+         exit (1);
+       }
+    }
+
+  alarm (0);
+
+  printf ("%s: was %d times the serial thread\n",
+         pid == 0 ? "child" : "parent", serials);
+
+  if (pid == 0)
+    /* The child.  Pass the number of times we had the serializing
+       thread back to the parent.  */
+    exit (serials);
+
+  if (waitpid (pid, &status, 0) != pid)
+    {
+      puts ("waitpid failed");
+      return 1;
+    }
+
+  if (!WIFEXITED (status))
+    {
+      puts ("child exited abnormally");
+      return 1;
+    }
+
+  if (WEXITSTATUS (status) + serials != N)
+    {
+      printf ("total number of serials is %d, expected %d\n",
+             WEXITSTATUS (status) + serials, N);
+      return 1;
+    }
+
+  exit (0);
+}
diff --git a/nptl/tst-barrier3.c b/nptl/tst-barrier3.c
new file mode 100644 (file)
index 0000000..b5478f8
--- /dev/null
@@ -0,0 +1,154 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* Test of POSIX barriers.  */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define NTHREADS 20
+
+#define ROUNDS 20
+
+static pthread_barrier_t barriers[NTHREADS];
+
+static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+static int counters[NTHREADS];
+static int serial[NTHREADS];
+
+static void *
+worker (void *arg)
+{
+  void *result = NULL;
+  int nr = (long int) arg;
+  int i;
+
+  for (i = 0; i < ROUNDS; ++i)
+    {
+      int j;
+      int retval;
+
+      if (nr == 0)
+       {
+         memset (counters, '\0', sizeof (counters));
+         memset (serial, '\0', sizeof (serial));
+       }
+
+      retval = pthread_barrier_wait (&barriers[NTHREADS - 1]);
+      if (retval != 0 && retval != PTHREAD_BARRIER_SERIAL_THREAD)
+       {
+         printf ("thread %d failed to wait for all the others\n", nr);
+         result = (void *) 1;
+       }
+
+      for (j = nr; j < NTHREADS; ++j)
+       {
+         /* Increment the counter for this round.  */
+         pthread_mutex_lock (&lock);
+         ++counters[j];
+         pthread_mutex_unlock (&lock);
+
+         /* Wait for the rest.  */
+         retval = pthread_barrier_wait (&barriers[j]);
+
+         /* Test the result.  */
+         if (nr == 0 && counters[j] != j + 1)
+           {
+             printf ("barrier in round %d released but count is %d\n",
+                     j, counters[j]);
+             result = (void *) 1;
+           }
+
+         if (retval != 0)
+           {
+             if (retval != PTHREAD_BARRIER_SERIAL_THREAD)
+               {
+                 printf ("thread %d in round %d has nonzero return value != PTHREAD_BARRIER_SERIAL_THREAD\n",
+                         nr, j);
+                 result = (void *) 1;
+               }
+             else
+               {
+                 pthread_mutex_lock (&lock);
+                 ++serial[j];
+                 pthread_mutex_unlock (&lock);
+               }
+           }
+
+         /* Wait for the rest again.  */
+         retval = pthread_barrier_wait (&barriers[j]);
+
+         /* Now we can check whether exactly one thread was serializing.  */
+         if (nr == 0 && serial[j] != 1)
+           {
+             printf ("not exactly one serial thread in round %d\n", j);
+             result = (void *) 1;
+           }
+       }
+    }
+
+  return result;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#define TIMEOUT 60
+static int
+do_test (void)
+{
+  pthread_t threads[NTHREADS];
+  int i;
+  void *res;
+  int result = 0;
+
+  /* Initialized the barrier variables.  */
+  for (i = 0; i < NTHREADS; ++i)
+    if (pthread_barrier_init (&barriers[i], NULL, i + 1) != 0)
+      {
+       printf ("Failed to initialize barrier %d\n", i);
+       exit (1);
+      }
+
+  /* Start the threads.  */
+  for (i = 0; i < NTHREADS; ++i)
+    if (pthread_create (&threads[i], NULL, worker, (void *) (long int) i) != 0)
+      {
+       printf ("Failed to start thread %d\n", i);
+       exit (1);
+      }
+
+  /* And wait for them.  */
+  for (i = 0; i < NTHREADS; ++i)
+    if (pthread_join (threads[i], &res) != 0 || res != NULL)
+      {
+       printf ("thread %d returned a failure\n", i);
+       result = 1;
+      }
+    else
+      printf ("joined threads %d\n", i);
+
+  if (result == 0)
+    puts ("all OK");
+
+  return result;
+}
+
+#include "../test-skeleton.c"
diff --git a/nptl/tst-basic1.c b/nptl/tst-basic1.c
new file mode 100644 (file)
index 0000000..36ae767
--- /dev/null
@@ -0,0 +1,70 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+
+static void *tf (void *a)
+{
+  return a;
+}
+
+
+int
+do_test (void)
+{
+#define N 2
+  pthread_t t[N];
+  int i;
+
+  for (i = 0; i < N; ++i)
+    if (pthread_create (&t[i], NULL, tf, (void *) (i + 1)) != 0)
+      {
+       write (2, "create failed\n", 14);
+       _exit (1);
+      }
+    else
+      printf ("created thread %d\n", i);
+
+  for (i = 0; i < N; ++i)
+    {
+      void *r;
+      int e;
+      if ((e = pthread_join (t[i], &r)) != 0)
+       {
+         printf ("join failed: %d\n", e);
+         _exit (1);
+       }
+      else if (r != (void *) (i + 1))
+       {
+         write (2, "result wrong\n", 13);
+         _exit (1);
+       }
+      else
+       printf ("joined thread %d\n", i);
+    }
+
+  return 0;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-basic2.c b/nptl/tst-basic2.c
new file mode 100644 (file)
index 0000000..ffb1928
--- /dev/null
@@ -0,0 +1,95 @@
+/* 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 <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+
+#define N 20
+
+static pthread_t th[N];
+static pthread_mutex_t lock[N];
+
+
+static void *tf (void *a)
+{
+  uintptr_t idx = (uintptr_t) a;
+
+  pthread_mutex_lock (&lock[idx]);
+
+  return pthread_equal (pthread_self (), th[idx]) ? NULL : (void *) 1l;
+}
+
+
+int
+do_test (void)
+{
+  if (pthread_equal (pthread_self (), pthread_self ()) == 0)
+    {
+      puts ("pthread_equal (pthread_self (), pthread_self ()) failed");
+      exit (1);
+    }
+
+  int i;
+  for (i = 0; i < N; ++i)
+    {
+      if (pthread_mutex_init (&lock[i], NULL) != 0)
+       {
+         puts ("mutex_init failed");
+         exit (1);
+       }
+
+      if (pthread_create (&th[i], NULL, tf, (void *) i) != 0)
+       {
+         puts ("create failed");
+         exit (1);
+       }
+
+      if (pthread_mutex_unlock (&lock[i]) != 0)
+       {
+         puts ("mutex_unlock failed");
+         exit (1);
+       }
+
+      printf ("created thread %d\n", i);
+    }
+
+  int result = 0;
+  for (i = 0; i < N; ++i)
+    {
+      void *r;
+      int e;
+      if ((e = pthread_join (th[i], &r)) != 0)
+       {
+         printf ("join failed: %d\n", e);
+         _exit (1);
+       }
+      else if (r != NULL)
+       result = 1;
+    }
+
+  return 0;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-cancel1.c b/nptl/tst-cancel1.c
new file mode 100644 (file)
index 0000000..99a8339
--- /dev/null
@@ -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/nptl/tst-cancel2.c b/nptl/tst-cancel2.c
new file mode 100644 (file)
index 0000000..6d80f8a
--- /dev/null
@@ -0,0 +1,100 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <unistd.h>
+
+
+static int fd[2];
+
+
+static void *
+tf (void *arg)
+{
+  /* The buffer size must be larger than the pipe size so that the
+     write blocks.  */
+  char buf[100000];
+
+  if (write (fd[1], buf, sizeof (buf)) == sizeof (buf))
+    {
+      puts ("write succeeded");
+      return (void *) 1l;
+    }
+
+  return (void *) 42l;
+}
+
+
+static int
+do_test (void)
+{
+  pthread_t th;
+  void *r;
+  struct sigaction sa;
+
+  sa.sa_handler = SIG_IGN;
+  sigemptyset (&sa.sa_mask);
+  sa.sa_flags = 0;
+
+  if (sigaction (SIGPIPE, &sa, NULL) != 0)
+    {
+      puts ("sigaction failed");
+      return 1;
+    }
+
+  if (pipe (fd) != 0)
+    {
+      puts ("pipe failed");
+      return 1;
+    }
+
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("create failed");
+      return 1;
+    }
+
+  if (pthread_cancel (th) != 0)
+    {
+      puts ("cancel failed");
+      return 1;
+    }
+
+  /* This will cause the write in the child to return.  */
+  close (fd[0]);
+
+  if (pthread_join (th, &r) != 0)
+    {
+      puts ("join failed");
+      return 1;
+    }
+
+  if (r != PTHREAD_CANCELED)
+    {
+      printf ("result is wrong: expected %p, got %p\n", PTHREAD_CANCELED, r);
+      return 1;
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-cancel3.c b/nptl/tst-cancel3.c
new file mode 100644 (file)
index 0000000..86c482b
--- /dev/null
@@ -0,0 +1,98 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <unistd.h>
+
+
+static int fd[2];
+
+
+static void *
+tf (void *arg)
+{
+  char buf[100];
+
+  if (read (fd[0], buf, sizeof (buf)) == sizeof (buf))
+    {
+      puts ("read succeeded");
+      return (void *) 1l;
+    }
+
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  pthread_t th;
+  void *r;
+  struct sigaction sa;
+
+  sa.sa_handler = SIG_IGN;
+  sigemptyset (&sa.sa_mask);
+  sa.sa_flags = 0;
+
+  if (sigaction (SIGPIPE, &sa, NULL) != 0)
+    {
+      puts ("sigaction failed");
+      return 1;
+    }
+
+  if (pipe (fd) != 0)
+    {
+      puts ("pipe failed");
+      return 1;
+    }
+
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("create failed");
+      return 1;
+    }
+
+  if (pthread_cancel (th) != 0)
+    {
+      puts ("cancel failed");
+      return 1;
+    }
+
+  /* This will cause the read in the child to return.  */
+  close (fd[0]);
+
+  if (pthread_join (th, &r) != 0)
+    {
+      puts ("join failed");
+      return 1;
+    }
+
+  if (r != PTHREAD_CANCELED)
+    {
+      puts ("result is wrong");
+      return 1;
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-cancel4.c b/nptl/tst-cancel4.c
new file mode 100644 (file)
index 0000000..371f2f7
--- /dev/null
@@ -0,0 +1,461 @@
+/* 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.  */
+
+/* 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[10000];
+  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[10000];
+  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 (10000000);
+
+  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 (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);
+    }
+
+  siginfo_t si;
+  int s = waitid (P_PID, pid, &si, 0);
+
+  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)
+    {
+      if (pthread_barrier_init (&b2, NULL, tests[cnt].nb) != 0)
+       {
+         puts ("b2 init failed");
+         exit (1);
+       }
+
+      /* read(2) test.  */
+      pthread_t th;
+      if (pthread_create (&th, NULL, tests[cnt].tf, NULL) != 0)
+       {
+         printf ("create for round %d test failed\n", cnt);
+         exit (1);
+       }
+
+      int r = pthread_barrier_wait (&b2);
+      if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+       {
+         printf ("%s: barrier_wait failed\n", __FUNCTION__);
+         exit (1);
+       }
+
+      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/nptl/tst-cond1.c b/nptl/tst-cond1.c
new file mode 100644 (file)
index 0000000..46085c2
--- /dev/null
@@ -0,0 +1,94 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <error.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
+static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
+
+
+static void *
+tf (void *p)
+{
+  int err;
+
+  err = pthread_mutex_lock (&mut);
+  if (err != 0)
+    error (EXIT_FAILURE, err, "child: cannot get mutex");
+
+  puts ("child: got mutex; signalling");
+
+  pthread_cond_signal (&cond);
+
+  puts ("child: unlock");
+
+  err = pthread_mutex_unlock (&mut);
+  if (err != 0)
+    error (EXIT_FAILURE, err, "child: cannot unlock");
+
+  puts ("child: done");
+
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  pthread_t th;
+  int err;
+
+  printf ("&cond = %p\n&mut = %p\n", &cond, &mut);
+
+  puts ("parent: get mutex");
+
+  err = pthread_mutex_lock (&mut);
+  if (err != 0)
+    error (EXIT_FAILURE, err, "parent: cannot get mutex");
+
+  puts ("parent: create child");
+
+  err = pthread_create (&th, NULL, tf, NULL);
+  if (err != 0)
+    error (EXIT_FAILURE, err, "parent: cannot create thread");
+
+  puts ("parent: wait for condition");
+
+  err = pthread_cond_wait (&cond, &mut);
+  if (err != 0)
+    error (EXIT_FAILURE, err, "parent: cannot wait fir signal");
+
+  puts ("parent: got signal");
+
+  err = pthread_join (th, NULL);
+  if (err != 0)
+    error (EXIT_FAILURE, err, "parent: failed to join");
+
+  puts ("done");
+
+  return 0;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-cond2.c b/nptl/tst-cond2.c
new file mode 100644 (file)
index 0000000..d1f3d0f
--- /dev/null
@@ -0,0 +1,118 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <error.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
+
+
+static void *
+tf (void *a)
+{
+  int i = (long int) a;
+  int err;
+
+  printf ("child %d: wait\n", i);
+
+  err = pthread_cond_wait (&cond, &mut);
+  if (err != 0)
+    error (EXIT_FAILURE, err, "child %d: failed to wait", i);
+
+  printf ("child %d: woken up\n", i);
+
+  err = pthread_mutex_unlock (&mut);
+  if (err != 0)
+    error (EXIT_FAILURE, err, "child %d: unlock failed", i);
+
+  printf ("child %d: done\n", i);
+
+  return NULL;
+}
+
+
+#define N 10
+
+
+static int
+do_test (void)
+{
+  pthread_t th[N];
+  int i;
+  int err;
+
+  printf ("&cond = %p\n&mut = %p\n", &cond, &mut);
+
+  puts ("first lock");
+
+  err = pthread_mutex_lock (&mut);
+  if (err != 0)
+    error (EXIT_FAILURE, err, "initial locking failed");
+
+  for (i = 0; i < N; ++i)
+    {
+      printf ("create thread %d\n", i);
+
+      err = pthread_create (&th[i], NULL, tf, (void *) (long int) i);
+      if (err != 0)
+       error (EXIT_FAILURE, err, "cannot create thread %d", i);
+
+      printf ("wait for child %d\n", i);
+
+      /* Lock and thereby wait for the child to start up and get the
+        conditional variable.  */
+      pthread_mutex_lock (&mut);
+    }
+
+  puts ("final unlock");
+
+  /* Unlock in preparation of the broadcast.  */
+  err = pthread_mutex_unlock (&mut);
+  if (err != 0)
+    error (EXIT_FAILURE, err, "parent: unlock failed");
+
+  puts ("broadcast");
+
+  /* Wake up all threads.  */
+  err = pthread_cond_broadcast (&cond);
+  if (err != 0)
+    error (EXIT_FAILURE, err, "parent: broadcast failed");
+
+  /* Join all threads.  */
+  for (i = 0; i < N; ++i)
+    {
+      printf ("join thread %d\n", i);
+
+      err = pthread_join (th[i], NULL);
+      if (err != 0)
+       error (EXIT_FAILURE, err, "join of child %d failed", i);
+    }
+
+  puts ("done");
+
+  return 0;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-cond3.c b/nptl/tst-cond3.c
new file mode 100644 (file)
index 0000000..cb9eb85
--- /dev/null
@@ -0,0 +1,113 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+
+/* Note that this test requires more than the standard.  It is
+   required that there are no spurious wakeups if only more readers
+   are added.  This is a reasonable demand.  */
+
+
+static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
+static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
+
+
+#define N 10
+
+
+static void *
+tf (void *arg)
+{
+  int i = (long int) arg;
+  int err;
+
+  /* Get the mutex.  */
+  err = pthread_mutex_lock (&mut);
+  if (err != 0)
+    {
+      printf ("child %d mutex_lock failed: %s\n", i, strerror (err));
+      exit (1);
+    }
+
+  /* This call should never return.  */
+  pthread_cond_wait (&cond, &mut);
+
+  /* We should never get here.  */
+  exit (1);
+
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  int err;
+  int i;
+
+  for (i = 0; i < N; ++i)
+    {
+      pthread_t th;
+
+      if (i != 0)
+       {
+         /* Release the mutex.  */
+         err = pthread_mutex_unlock (&mut);
+         if (err != 0)
+           {
+             printf ("mutex_unlock %d failed: %s\n", i, strerror (err));
+             return 1;
+           }
+       }
+
+      err = pthread_create (&th, NULL, tf, (void *) (long int) i);
+      if (err != 0)
+       {
+         printf ("create %d failed: %s\n", i, strerror (err));
+         return 1;
+       }
+
+      /* Get the mutex.  */
+      err = pthread_mutex_lock (&mut);
+      if (err != 0)
+       {
+         printf ("mutex_lock %d failed: %s\n", i, strerror (err));
+         return 1;
+       }
+    }
+
+  /* Set an alarm for 1 second.  The wrapper will expect this.  */
+  alarm (1);
+
+  /* This call should never return.  */
+  pthread_cond_wait (&cond, &mut);
+
+  puts ("cond_wait returned");
+  return 1;
+}
+
+
+#define EXPECTED_SIGNAL SIGALRM
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-cond4.c b/nptl/tst-cond4.c
new file mode 100644 (file)
index 0000000..ffc83c7
--- /dev/null
@@ -0,0 +1,237 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+
+
+int *condition;
+
+
+int
+main (void)
+{
+  size_t ps = sysconf (_SC_PAGESIZE);
+  char tmpfname[] = "/tmp/tst-cond4.XXXXXX";
+  char data[ps];
+  void *mem;
+  int fd;
+  pthread_mutexattr_t ma;
+  pthread_mutex_t *mut1;
+  pthread_mutex_t *mut2;
+  pthread_condattr_t ca;
+  pthread_cond_t *cond;
+  pid_t pid;
+  int result = 0;
+  int p;
+
+  fd = mkstemp (tmpfname);
+  if (fd == -1)
+    {
+      printf ("cannot open temporary file: %m\n");
+      exit (1);
+    }
+
+  /* Make sure it is always removed.  */
+  unlink (tmpfname);
+
+  /* Create one page of data.  */
+  memset (data, '\0', ps);
+
+  /* Write the data to the file.  */
+  if (write (fd, data, ps) != ps)
+    {
+      puts ("short write");
+      exit (1);
+    }
+
+  mem = mmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+  if (mem == MAP_FAILED)
+    {
+      printf ("mmap failed: %m\n");
+      exit (1);
+    }
+
+  mut1 = (pthread_mutex_t *) (((uintptr_t) mem
+                              + __alignof (pthread_mutex_t))
+                             & ~(__alignof (pthread_mutex_t) - 1));
+  mut2 = mut1 + 1;
+
+  cond = (pthread_cond_t *) (((uintptr_t) (mut2 + 1)
+                             + __alignof (pthread_cond_t))
+                            & ~(__alignof (pthread_cond_t) - 1));
+
+  condition = (int *) (((uintptr_t) (cond + 1) + __alignof (int))
+                      & ~(__alignof (int) - 1));
+
+  if (pthread_mutexattr_init (&ma) != 0)
+    {
+      puts ("mutexattr_init failed");
+      exit (1);
+    }
+
+  if (pthread_mutexattr_getpshared (&ma, &p) != 0)
+    {
+      puts ("1st mutexattr_getpshared failed");
+      exit (1);
+    }
+
+  if (p != PTHREAD_PROCESS_PRIVATE)
+    {
+      puts ("default pshared value wrong");
+      exit (1);
+    }
+
+  if (pthread_mutexattr_setpshared (&ma, PTHREAD_PROCESS_SHARED) != 0)
+    {
+      puts ("mutexattr_setpshared failed");
+      exit (1);
+    }
+
+  if (pthread_mutexattr_getpshared (&ma, &p) != 0)
+    {
+      puts ("2nd mutexattr_getpshared failed");
+      exit (1);
+    }
+
+  if (p != PTHREAD_PROCESS_SHARED)
+    {
+      puts ("pshared value after setpshared call wrong");
+      exit (1);
+    }
+
+  if (pthread_mutex_init (mut1, &ma) != 0)
+    {
+      puts ("1st mutex_init failed");
+      exit (1);
+    }
+
+  if (pthread_mutex_init (mut2, &ma) != 0)
+    {
+      puts ("2nd mutex_init failed");
+      exit (1);
+    }
+
+  if (pthread_condattr_init (&ca) != 0)
+    {
+      puts ("condattr_init failed");
+      exit (1);
+    }
+
+  if (pthread_condattr_setpshared (&ca, PTHREAD_PROCESS_SHARED) != 0)
+    {
+      puts ("condattr_setpshared failed");
+      exit (1);
+    }
+
+  if (pthread_cond_init (cond, &ca) != 0)
+    {
+      puts ("cond_init failed");
+      exit (1);
+    }
+
+  if (pthread_mutex_lock (mut1) != 0)
+    {
+      puts ("parent: 1st mutex_lock failed");
+      exit (1);
+    }
+
+  puts ("going to fork now");
+  pid = fork ();
+  if (pid == -1)
+    {
+      puts ("fork failed");
+      exit (1);
+    }
+  else if (pid == 0)
+    {
+      if (pthread_mutex_lock (mut2) != 0)
+       {
+         puts ("child: mutex_lock failed");
+         exit (1);
+       }
+
+      if (pthread_mutex_unlock (mut1) != 0)
+       {
+         puts ("child: 1st mutex_unlock failed");
+         exit (1);
+       }
+
+      do
+       if (pthread_cond_wait (cond, mut2) != 0)
+         {
+           puts ("child: cond_wait failed");
+           exit (1);
+         }
+      while (*condition == 0);
+
+      if (pthread_mutex_unlock (mut2) != 0)
+       {
+         puts ("child: 2nd mutex_unlock failed");
+         exit (1);
+       }
+
+      puts ("child done");
+    }
+  else
+    {
+      int status;
+
+      if (pthread_mutex_lock (mut1) != 0)
+       {
+         puts ("parent: 2nd mutex_lock failed");
+         exit (1);
+       }
+
+      if (pthread_mutex_lock (mut2) != 0)
+       {
+         puts ("parent: 3rd mutex_lock failed");
+         exit (1);
+       }
+
+      if (pthread_cond_signal (cond) != 0)
+       {
+         puts ("parent: cond_signal failed");
+         exit (1);
+       }
+
+      *condition = 1;
+
+      if (pthread_mutex_unlock (mut2) != 0)
+       {
+         puts ("parent: mutex_unlock failed");
+         exit (1);
+       }
+
+      puts ("waiting for child");
+
+      waitpid (pid, &status, 0);
+      result |= status;
+
+      puts ("parent done");
+    }
+
+ return result;
+}
diff --git a/nptl/tst-cond5.c b/nptl/tst-cond5.c
new file mode 100644 (file)
index 0000000..efa207b
--- /dev/null
@@ -0,0 +1,106 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <sys/time.h>
+
+
+static pthread_mutex_t mut;
+static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
+
+
+static int
+do_test (void)
+{
+  pthread_mutexattr_t ma;
+  int err;
+  struct timespec ts;
+  struct timeval tv;
+
+  if (pthread_mutexattr_init (&ma) != 0)
+    {
+      puts ("mutexattr_init failed");
+      exit (1);
+    }
+
+  if (pthread_mutexattr_settype (&ma, PTHREAD_MUTEX_ERRORCHECK) != 0)
+    {
+      puts ("mutexattr_settype failed");
+      exit (1);
+    }
+
+  if (pthread_mutex_init (&mut, &ma) != 0)
+    {
+      puts ("mutex_init failed");
+      exit (1);
+    }
+
+  /* Get the mutex.  */
+  if (pthread_mutex_lock (&mut) != 0)
+    {
+      puts ("mutex_lock failed");
+      exit (1);
+    }
+
+  /* Waiting for the condition will fail.  But we want the timeout here.  */
+  if (gettimeofday (&tv, NULL) != 0)
+    {
+      puts ("gettimeofday failed");
+      exit (1);
+    }
+
+  TIMEVAL_TO_TIMESPEC (&tv, &ts);
+  ts.tv_nsec += 500000000;
+  if (ts.tv_nsec >= 1000000000)
+    {
+      ts.tv_nsec -= 1000000000;
+      ++ts.tv_sec;
+    }
+  err = pthread_cond_timedwait (&cond, &mut, &ts);
+  if (err == 0)
+    {
+      /* This could in theory happen but here without any signal and
+        additional waiter it should not.  */
+      puts ("cond_timedwait succeeded");
+      exit (1);
+    }
+  else if (err != ETIMEDOUT)
+    {
+      printf ("cond_timedwait returned with %s\n", strerror (err));
+      exit (1);
+    }
+
+  err = pthread_mutex_unlock (&mut);
+  if (err != 0)
+    {
+      printf ("mutex_unlock failed: %s\n", strerror (err));
+      exit (1);
+    }
+
+  return 0;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-cond6.c b/nptl/tst-cond6.c
new file mode 100644 (file)
index 0000000..63c5470
--- /dev/null
@@ -0,0 +1,233 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+
+
+int *condition;
+
+
+int
+main (void)
+{
+  size_t ps = sysconf (_SC_PAGESIZE);
+  char tmpfname[] = "/tmp/tst-cond6.XXXXXX";
+  char data[ps];
+  void *mem;
+  int fd;
+  pthread_mutexattr_t ma;
+  pthread_mutex_t *mut1;
+  pthread_mutex_t *mut2;
+  pthread_condattr_t ca;
+  pthread_cond_t *cond;
+  pid_t pid;
+  int result = 0;
+
+  fd = mkstemp (tmpfname);
+  if (fd == -1)
+    {
+      printf ("cannot open temporary file: %m\n");
+      exit (1);
+    }
+
+  /* Make sure it is always removed.  */
+  unlink (tmpfname);
+
+  /* Create one page of data.  */
+  memset (data, '\0', ps);
+
+  /* Write the data to the file.  */
+  if (write (fd, data, ps) != ps)
+    {
+      puts ("short write");
+      exit (1);
+    }
+
+  mem = mmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+  if (mem == MAP_FAILED)
+    {
+      printf ("mmap failed: %m\n");
+      exit (1);
+    }
+
+  mut1 = (pthread_mutex_t *) (((uintptr_t) mem
+                              + __alignof (pthread_mutex_t))
+                             & ~(__alignof (pthread_mutex_t) - 1));
+  mut2 = mut1 + 1;
+
+  cond = (pthread_cond_t *) (((uintptr_t) (mut2 + 1)
+                             + __alignof (pthread_cond_t))
+                            & ~(__alignof (pthread_cond_t) - 1));
+
+  condition = (int *) (((uintptr_t) (cond + 1) + __alignof (int))
+                      & ~(__alignof (int) - 1));
+
+  if (pthread_mutexattr_init (&ma) != 0)
+    {
+      puts ("mutexattr_init failed");
+      exit (1);
+    }
+
+  if (pthread_mutexattr_setpshared (&ma, PTHREAD_PROCESS_SHARED) != 0)
+    {
+      puts ("mutexattr_setpshared failed");
+      exit (1);
+    }
+
+  if (pthread_mutex_init (mut1, &ma) != 0)
+    {
+      puts ("1st mutex_init failed");
+      exit (1);
+    }
+
+  if (pthread_mutex_init (mut2, &ma) != 0)
+    {
+      puts ("2nd mutex_init failed");
+      exit (1);
+    }
+
+  if (pthread_condattr_init (&ca) != 0)
+    {
+      puts ("condattr_init failed");
+      exit (1);
+    }
+
+  if (pthread_condattr_setpshared (&ca, PTHREAD_PROCESS_SHARED) != 0)
+    {
+      puts ("condattr_setpshared failed");
+      exit (1);
+    }
+
+  if (pthread_cond_init (cond, &ca) != 0)
+    {
+      puts ("cond_init failed");
+      exit (1);
+    }
+
+  if (pthread_mutex_lock (mut1) != 0)
+    {
+      puts ("parent: 1st mutex_lock failed");
+      exit (1);
+    }
+
+  puts ("going to fork now");
+  pid = fork ();
+  if (pid == -1)
+    {
+      puts ("fork failed");
+      exit (1);
+    }
+  else if (pid == 0)
+    {
+      struct timespec ts;
+      struct timeval tv;
+
+      if (pthread_mutex_lock (mut2) != 0)
+       {
+         puts ("child: mutex_lock failed");
+         exit (1);
+       }
+
+      if (pthread_mutex_unlock (mut1) != 0)
+       {
+         puts ("child: 1st mutex_unlock failed");
+         exit (1);
+       }
+
+      /* Waiting for the condition will fail.  But we want the timeout
+        here.  */
+      if (gettimeofday (&tv, NULL) != 0)
+       {
+         puts ("gettimeofday failed");
+         exit (1);
+       }
+
+      TIMEVAL_TO_TIMESPEC (&tv, &ts);
+      ts.tv_nsec += 500000000;
+      if (ts.tv_nsec >= 1000000000)
+       {
+         ts.tv_nsec -= 1000000000;
+         ++ts.tv_sec;
+       }
+
+      do
+       if (pthread_cond_timedwait (cond, mut2, &ts) != 0)
+         {
+           puts ("child: cond_wait failed");
+           exit (1);
+         }
+      while (*condition == 0);
+
+      if (pthread_mutex_unlock (mut2) != 0)
+       {
+         puts ("child: 2nd mutex_unlock failed");
+         exit (1);
+       }
+
+      puts ("child done");
+    }
+  else
+    {
+      int status;
+
+      if (pthread_mutex_lock (mut1) != 0)
+       {
+         puts ("parent: 2nd mutex_lock failed");
+         exit (1);
+       }
+
+      if (pthread_mutex_lock (mut2) != 0)
+       {
+         puts ("parent: 3rd mutex_lock failed");
+         exit (1);
+       }
+
+      if (pthread_cond_signal (cond) != 0)
+       {
+         puts ("parent: cond_signal failed");
+         exit (1);
+       }
+
+      *condition = 1;
+
+      if (pthread_mutex_unlock (mut2) != 0)
+       {
+         puts ("parent: mutex_unlock failed");
+         exit (1);
+       }
+
+      puts ("waiting for child");
+
+      waitpid (pid, &status, 0);
+      result |= status;
+
+      puts ("parent done");
+    }
+
+ return result;
+}
diff --git a/nptl/tst-exec1.c b/nptl/tst-exec1.c
new file mode 100644 (file)
index 0000000..0448a05
--- /dev/null
@@ -0,0 +1,160 @@
+/* Simple exec test, only a thread in the parent.
+   Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <paths.h>
+#include <pthread.h>
+#include <signal.h>
+#include <spawn.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+
+static void *
+tf (void *arg)
+{
+  pthread_t th = (pthread_t) arg;
+
+  if (pthread_join (th, NULL) == 0)
+    {
+      puts ("thread in parent joined!?");
+      exit (1);
+    }
+
+  puts ("join in thread in parent returned!?");
+  exit (1);
+}
+
+
+static int
+do_test (void)
+{
+  int fd[2];
+  if (pipe (fd) != 0)
+    {
+      puts ("pipe failed");
+      exit (1);
+    }
+
+  /* Not interested in knowing when the pipe is closed.  */
+  if (sigignore (SIGPIPE) != 0)
+    {
+      puts ("sigignore failed");
+      exit (1);
+    }
+
+  posix_spawn_file_actions_t a;
+  if (posix_spawn_file_actions_init (&a) != 0)
+    {
+      puts ("spawn_file_actions_init failed");
+      exit (1);
+    }
+
+  if (posix_spawn_file_actions_adddup2 (&a, fd[1], STDOUT_FILENO) != 0)
+    {
+      puts ("spawn_file_actions_adddup2 failed");
+      exit (1);
+    }
+
+  if (posix_spawn_file_actions_addclose (&a, fd[0]) != 0)
+    {
+      puts ("spawn_file_actions_addclose");
+      exit (1);
+    }
+
+  pthread_t th;
+  if (pthread_create (&th, NULL, tf, (void *) pthread_self ()) != 0)
+    {
+      puts ("create failed");
+      exit (1);
+    }
+
+  pid_t pid;
+  char *argv[] = { (char *) _PATH_BSHELL, (char *) "-c", (char *) "echo $$",
+                  NULL };
+  if (posix_spawn (&pid, _PATH_BSHELL, &a, NULL, argv, NULL) != 0)
+    {
+      puts ("spawn failed");
+      exit (1);
+    }
+
+  close (fd[1]);
+
+  char buf[200];
+  ssize_t n;
+  bool seen_pid = false;
+  while (TEMP_FAILURE_RETRY ((n = read (fd[0], buf, sizeof (buf)))) > 0)
+    {
+      /* We only expect to read the PID.  */
+      char *endp;
+      long int rpid = strtol (buf, &endp, 10);
+
+      if (*endp != '\n')
+       {
+         printf ("didn't parse whole line: \"%s\"\n", buf);
+         exit (1);
+       }
+      if (endp == buf)
+       {
+         puts ("read empty line");
+         exit (1);
+       }
+
+      if (rpid != pid)
+       {
+         printf ("found \"%s\", expected PID %ld\n", buf, (long int) pid);
+         exit (1);
+       }
+
+      if (seen_pid)
+       {
+         puts ("found more than one PID line");
+         exit (1);
+       }
+
+      seen_pid = true;
+    }
+
+  close (fd[0]);
+
+  int status;
+  int err = waitpid (pid, &status, 0);
+  if (err != pid)
+    {
+      puts ("waitpid failed");
+      exit (1);
+    }
+
+  if (!seen_pid)
+    {
+      puts ("didn't get PID");
+      exit (1);
+    }
+
+  puts ("read correct PID");
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-exec2.c b/nptl/tst-exec2.c
new file mode 100644 (file)
index 0000000..0fa80ef
--- /dev/null
@@ -0,0 +1,155 @@
+/* Thread with running thread calls exec.
+   Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <paths.h>
+#include <pthread.h>
+#include <signal.h>
+#include <spawn.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+
+static void *
+tf (void *arg)
+{
+  pthread_t th = (pthread_t) arg;
+
+  if (pthread_join (th, NULL) == 0)
+    {
+      puts ("thread in parent joined!?");
+      exit (1);
+    }
+
+  puts ("join in thread in parent returned!?");
+  exit (1);
+}
+
+
+static int
+do_test (void)
+{
+  int fd[2];
+  if (pipe (fd) != 0)
+    {
+      puts ("pipe failed");
+      exit (1);
+    }
+
+  /* Not interested in knowing when the pipe is closed.  */
+  if (sigignore (SIGPIPE) != 0)
+    {
+      puts ("sigignore failed");
+      exit (1);
+    }
+
+  pid_t pid = fork ();
+  if (pid == -1)
+    {
+      puts ("fork failed");
+      exit (1);
+    }
+
+  if (pid == 0)
+    {
+      /* Use the fd for stdout.  This is kind of ugly because it
+        substitutes the fd of stdout but we know what we are doing
+        here...  */
+      if (dup2 (fd[1], STDOUT_FILENO) != STDOUT_FILENO)
+       {
+         puts ("dup2 failed");
+         exit (1);
+       }
+
+      close (fd[0]);
+
+      pthread_t th;
+      if (pthread_create (&th, NULL, tf, (void *) pthread_self ()) != 0)
+       {
+         puts ("create failed");
+         exit (1);
+       }
+
+      execl (_PATH_BSHELL, _PATH_BSHELL, "-c", "echo $$", NULL);
+
+      puts ("execl failed");
+      exit (1);
+    }
+
+  close (fd[1]);
+
+  char buf[200];
+  ssize_t n;
+  bool seen_pid = false;
+  while (TEMP_FAILURE_RETRY ((n = read (fd[0], buf, sizeof (buf)))) > 0)
+    {
+      /* We only expect to read the PID.  */
+      char *endp;
+      long int rpid = strtol (buf, &endp, 10);
+
+      if (*endp != '\n')
+       {
+         printf ("didn't parse whole line: \"%s\"\n", buf);
+         exit (1);
+       }
+      if (endp == buf)
+       {
+         puts ("read empty line");
+         exit (1);
+       }
+
+      if (rpid != pid)
+       {
+         printf ("found \"%s\", expected PID %ld\n", buf, (long int) pid);
+         exit (1);
+       }
+
+      if (seen_pid)
+       {
+         puts ("found more than one PID line");
+         exit (1);
+       }
+      seen_pid = true;
+    }
+
+  close (fd[0]);
+
+  int status;
+  int err = waitpid (pid, &status, 0);
+  if (err != pid)
+    {
+      puts ("waitpid failed");
+      exit (1);
+    }
+
+  if (!seen_pid)
+    {
+      puts ("didn't get PID");
+      exit (1);
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-exec3.c b/nptl/tst-exec3.c
new file mode 100644 (file)
index 0000000..eb9c721
--- /dev/null
@@ -0,0 +1,153 @@
+/* Thread calls exec.
+   Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <paths.h>
+#include <pthread.h>
+#include <signal.h>
+#include <spawn.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+
+static void *
+tf (void *arg)
+{
+  execl (_PATH_BSHELL, _PATH_BSHELL, "-c", "echo $$", NULL);
+
+  puts ("execl failed");
+  exit (1);
+}
+
+
+static int
+do_test (void)
+{
+  int fd[2];
+  if (pipe (fd) != 0)
+    {
+      puts ("pipe failed");
+      exit (1);
+    }
+
+  /* Not interested in knowing when the pipe is closed.  */
+  if (sigignore (SIGPIPE) != 0)
+    {
+      puts ("sigignore failed");
+      exit (1);
+    }
+
+  pid_t pid = fork ();
+  if (pid == -1)
+    {
+      puts ("fork failed");
+      exit (1);
+    }
+
+  if (pid == 0)
+    {
+      /* Use the fd for stdout.  This is kind of ugly because it
+        substitutes the fd of stdout but we know what we are doing
+        here...  */
+      if (dup2 (fd[1], STDOUT_FILENO) != STDOUT_FILENO)
+       {
+         puts ("dup2 failed");
+         exit (1);
+       }
+
+      close (fd[0]);
+
+      pthread_t th;
+      if (pthread_create (&th, NULL, tf, NULL) != 0)
+       {
+         puts ("create failed");
+         exit (1);
+       }
+
+      if (pthread_join (th, NULL) == 0)
+       {
+         puts ("join succeeded!?");
+         exit (1);
+       }
+
+      puts ("join returned!?");
+      exit (1);
+    }
+
+  close (fd[1]);
+
+  char buf[200];
+  ssize_t n;
+  bool seen_pid = false;
+  while (TEMP_FAILURE_RETRY ((n = read (fd[0], buf, sizeof (buf)))) > 0)
+    {
+      /* We only expect to read the PID.  */
+      char *endp;
+      long int rpid = strtol (buf, &endp, 10);
+
+      if (*endp != '\n')
+       {
+         printf ("didn't parse whole line: \"%s\"\n", buf);
+         exit (1);
+       }
+      if (endp == buf)
+       {
+         puts ("read empty line");
+         exit (1);
+       }
+
+      if (rpid != pid)
+       {
+         printf ("found \"%s\", expected PID %ld\n", buf, (long int) pid);
+         exit (1);
+       }
+
+      if (seen_pid)
+       {
+         puts ("found more than one PID line");
+         exit (1);
+       }
+      seen_pid = true;
+    }
+
+  close (fd[0]);
+
+  int status;
+  int err = waitpid (pid, &status, 0);
+  if (err != pid)
+    {
+      puts ("waitpid failed");
+      exit (1);
+    }
+
+  if (!seen_pid)
+    {
+      puts ("didn't get PID");
+      exit (1);
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-exit1.c b/nptl/tst-exit1.c
new file mode 100644 (file)
index 0000000..5113f2d
--- /dev/null
@@ -0,0 +1,83 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* NOTE: this tests functionality beyond POSIX.  POSIX does not allow
+   exit to be called more than once.  */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define N 20
+
+static pthread_barrier_t b;
+
+
+static void *
+tf (void *arg)
+{
+  int r = pthread_barrier_wait (&b);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("barrier_wait failed");
+      exit (1);
+    }
+
+  exit (0);
+}
+
+
+static int
+do_test (void)
+{
+  if (pthread_barrier_init (&b, NULL, N + 1) != 0)
+    {
+      puts ("barrier_init failed");
+      exit (1);
+    }
+
+  pthread_t th[N];
+  int i;
+  for (i = 0; i < N; ++i)
+    if (pthread_create (&th[i], NULL, tf, NULL) != 0)
+      {
+       puts ("create failed");
+       exit (1);
+      }
+
+  int r = pthread_barrier_wait (&b);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("barrier_wait failed");
+      exit (1);
+    }
+
+  /* Do nothing.  */
+  if (pthread_join (th[0], NULL) == 0)
+    {
+      puts ("join succeeded!?");
+      exit (1);
+    }
+
+  puts ("join returned!?");
+  exit (1);
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-flock1.c b/nptl/tst-flock1.c
new file mode 100644 (file)
index 0000000..ed2472d
--- /dev/null
@@ -0,0 +1,93 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/file.h>
+
+
+static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+
+static int fd;
+
+
+static void *
+tf (void *arg)
+{
+  if (flock (fd, LOCK_SH | LOCK_NB) != 0)
+    {
+      puts ("second flock failed");
+      exit (1);
+    }
+
+  pthread_mutex_unlock (&lock);
+
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  char tmp[] = "/tmp/tst-flock1-XXXXXX";
+
+  fd = mkstemp (tmp);
+  if (fd == -1)
+    {
+      puts ("mkstemp failed");
+      exit (1);
+    }
+
+  unlink (tmp);
+
+  write (fd, "foobar xyzzy", 12);
+
+  if (flock (fd, LOCK_EX | LOCK_NB) != 0)
+    {
+      puts ("first flock failed");
+      exit (1);
+    }
+
+  pthread_mutex_lock (&lock);
+
+  pthread_t th;
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("pthread_create failed");
+      exit (1);
+    }
+
+  pthread_mutex_lock (&lock);
+
+  void *result;
+  if (pthread_join (th, &result) != 0)
+    {
+      puts ("pthread_join failed");
+      exit (1);
+    }
+
+  close (fd);
+
+  return result != NULL;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-flock2.c b/nptl/tst-flock2.c
new file mode 100644 (file)
index 0000000..52d02dc
--- /dev/null
@@ -0,0 +1,260 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/file.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+
+
+static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t lock2 = PTHREAD_MUTEX_INITIALIZER;
+static int fd;
+
+
+static void *
+tf (void *arg)
+{
+  struct flock fl =
+    {
+      .l_type = F_WRLCK,
+      .l_start = 0,
+      .l_whence = SEEK_SET,
+      .l_len = 10
+    };
+  if (TEMP_FAILURE_RETRY (fcntl (fd, F_SETLKW, &fl)) != 0)
+    {
+      puts ("fourth fcntl failed");
+      exit (1);
+    }
+
+  pthread_mutex_unlock (&lock);
+
+  pthread_mutex_lock (&lock2);
+
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  char tmp[] = "/tmp/tst-flock2-XXXXXX";
+
+  fd = mkstemp (tmp);
+  if (fd == -1)
+    {
+      puts ("mkstemp failed");
+      exit (1);
+    }
+
+  unlink (tmp);
+
+  int i;
+  for (i = 0; i < 20; ++i)
+    write (fd, "foobar xyzzy", 12);
+
+  pthread_barrier_t *b;
+  b = mmap (NULL, sizeof (pthread_barrier_t), PROT_READ | PROT_WRITE,
+           MAP_SHARED, fd, 0);
+  if (b == MAP_FAILED)
+    {
+      puts ("mmap failed");
+      exit (1);
+    }
+
+  pthread_barrierattr_t ba;
+  if (pthread_barrierattr_init (&ba) != 0)
+    {
+      puts ("barrierattr_init failed");
+      exit (1);
+    }
+
+  if (pthread_barrierattr_setpshared (&ba, PTHREAD_PROCESS_SHARED) != 0)
+    {
+      puts ("barrierattr_setpshared failed");
+      exit (1);
+    }
+
+  if (pthread_barrier_init (b, &ba, 2) != 0)
+    {
+      puts ("barrier_init failed");
+      exit (1);
+    }
+
+  if (pthread_barrierattr_destroy (&ba) != 0)
+    {
+      puts ("barrierattr_destroy failed");
+      exit (1);
+    }
+
+  struct flock fl =
+    {
+      .l_type = F_WRLCK,
+      .l_start = 0,
+      .l_whence = SEEK_SET,
+      .l_len = 10
+    };
+  if (TEMP_FAILURE_RETRY (fcntl (fd, F_SETLKW, &fl)) != 0)
+    {
+      puts ("first fcntl failed");
+      exit (1);
+    }
+
+  pid_t pid = fork ();
+  if (pid == -1)
+    {
+      puts ("fork failed");
+      exit (1);
+    }
+
+  if (pid == 0)
+    {
+      /* Make sure the child does not stay around indefinitely.  */
+      alarm (10);
+
+      /* Try to get the lock.  */
+      if (TEMP_FAILURE_RETRY (fcntl (fd, F_SETLK, &fl)) == 0)
+       {
+         puts ("child:  second flock succeeded");
+         exit (1);
+       }
+    }
+
+  pthread_barrier_wait (b);
+
+  if (pid != 0)
+    {
+      fl.l_type = F_UNLCK;
+      if (TEMP_FAILURE_RETRY (fcntl (fd, F_SETLKW, &fl)) != 0)
+       {
+         puts ("third fcntl failed");
+         exit (1);
+       }
+    }
+
+  pthread_barrier_wait (b);
+
+  pthread_t th;
+  if (pid == 0)
+    {
+      if (pthread_mutex_lock (&lock) != 0)
+       {
+         puts ("1st locking of lock failed");
+         exit (1);
+       }
+
+      if (pthread_mutex_lock (&lock2) != 0)
+       {
+         puts ("1st locking of lock2 failed");
+         exit (1);
+       }
+
+      if (pthread_create (&th, NULL, tf, NULL) != 0)
+       {
+         puts ("pthread_create failed");
+         exit (1);
+       }
+
+      if (pthread_mutex_lock (&lock) != 0)
+       {
+         puts ("2nd locking of lock failed");
+         exit (1);
+       }
+
+      puts ("child locked file");
+    }
+
+  pthread_barrier_wait (b);
+
+  if (pid != 0)
+    {
+      fl.l_type = F_WRLCK;
+      if (TEMP_FAILURE_RETRY (fcntl (fd, F_SETLK, &fl)) == 0)
+       {
+         puts ("fifth fcntl succeeded");
+         exit (1);
+       }
+
+      puts ("file locked by child");
+    }
+
+  pthread_barrier_wait (b);
+
+  if (pid == 0)
+    {
+      if (pthread_mutex_unlock (&lock2) != 0)
+       {
+         puts ("unlock of lock2 failed");
+         exit (1);
+       }
+
+      if (pthread_join (th, NULL) != 0)
+       {
+         puts ("join failed");
+         exit (1);
+       }
+
+      puts ("child's thread terminated");
+    }
+
+  pthread_barrier_wait (b);
+
+  if (pid != 0)
+    {
+      fl.l_type = F_WRLCK;
+      if (TEMP_FAILURE_RETRY (fcntl (fd, F_SETLK, &fl)) == 0)
+       {
+         puts ("fifth fcntl succeeded");
+         exit (1);
+       }
+
+      puts ("file still locked");
+    }
+
+  pthread_barrier_wait (b);
+
+  if (pid == 0)
+    {
+      _exit (0);
+    }
+
+  int status;
+  if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid)
+    {
+      puts ("waitpid failed");
+      exit (1);
+    }
+  puts ("child terminated");
+
+  if (TEMP_FAILURE_RETRY (fcntl (fd, F_SETLKW, &fl)) != 0)
+    {
+      puts ("sixth fcntl failed");
+      exit (1);
+    }
+
+  return status;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-fork1.c b/nptl/tst-fork1.c
new file mode 100644 (file)
index 0000000..56ffe50
--- /dev/null
@@ -0,0 +1,101 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Roland McGrath <roland@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+static void *
+thread_function (void * arg)
+{
+  int i = (intptr_t) arg;
+  int status;
+  pid_t pid;
+  pid_t pid2;
+
+  pid = fork ();
+  switch (pid)
+    {
+    case 0:
+      printf ("%ld for %d\n", (long int) getpid (), i);
+      struct timespec ts = { .tv_sec = 0, .tv_nsec = 100000000 * i };
+      nanosleep (&ts, NULL);
+      _exit (i);
+      break;
+    case -1:
+      printf ("fork: %m\n");
+      return (void *) 1l;
+      break;
+    }
+
+  pid2 = TEMP_FAILURE_RETRY (waitpid (pid, &status, 0));
+  if (pid2 != pid)
+    {
+      printf ("waitpid returned %ld, expected %ld\n",
+             (long int) pid2, (long int) pid);
+      return (void *) 1l;
+    }
+
+  printf ("%ld with %d, expected %d\n",
+         (long int) pid, WEXITSTATUS (status), i);
+
+  return WEXITSTATUS (status) == i ? NULL : (void *) 1l;
+}
+
+#define N 5
+static const int t[N] = { 7, 6, 5, 4, 3 };
+
+int
+main (void)
+{
+  pthread_t th[N];
+  int i;
+  int result = 0;
+
+  for (i = 0; i < N; ++i)
+    if (pthread_create (&th[i], NULL, thread_function,
+                       (void *) (intptr_t) t[i]) != 0)
+      {
+       printf ("creation of thread %d failed\n", i);
+       exit (1);
+      }
+
+  for (i = 0; i < N; ++i)
+    {
+      void *v;
+      if (pthread_join (th[i], &v) != 0)
+       {
+         printf ("join of thread %d failed\n", i);
+         result = 1;
+       }
+      else if (v != NULL)
+       {
+         printf ("join %d successful, but child failed\n", i);
+         result = 1;
+       }
+      else
+       printf ("join %d successful\n", i);
+    }
+
+  return result;
+}
diff --git a/nptl/tst-join1.c b/nptl/tst-join1.c
new file mode 100644 (file)
index 0000000..95a78ba
--- /dev/null
@@ -0,0 +1,83 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+
+
+static void *
+tf (void *arg)
+{
+  pthread_t mh = (pthread_t) arg;
+  void *result;
+
+  if (pthread_mutex_unlock (&lock) != 0)
+    {
+      puts ("unlock failed");
+      exit (1);
+    }
+
+  if (pthread_join (mh, &result) != 0)
+    {
+      puts ("join failed");
+      exit (1);
+    }
+
+  if (result != (void *) 42l)
+    {
+      printf ("result wrong: expected %p, got %p\n", (void *) 42, result);
+      exit (1);
+    }
+
+  exit (0);
+}
+
+
+static int
+do_test (void)
+{
+  pthread_t th;
+
+  if (pthread_mutex_lock (&lock) != 0)
+    {
+      puts ("1st lock failed");
+      exit (1);
+    }
+
+  if (pthread_create (&th, NULL, tf, (void *) pthread_self ()) != 0)
+    {
+      puts ("create failed");
+      exit (1);
+    }
+
+  if (pthread_mutex_lock (&lock) != 0)
+    {
+      puts ("2nd lock failed");
+      exit (1);
+    }
+
+  pthread_exit ((void *) 42);
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-join2.c b/nptl/tst-join2.c
new file mode 100644 (file)
index 0000000..2cfab8b
--- /dev/null
@@ -0,0 +1,104 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+
+static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+
+
+static void *
+tf (void *arg)
+{
+  if (pthread_mutex_lock (&lock) != 0)
+    {
+      puts ("child: mutex_lock failed");
+      return NULL;
+    }
+
+  return (void *) 42l;
+}
+
+
+static int
+do_test (void)
+{
+  pthread_t th;
+
+  if (pthread_mutex_lock (&lock) != 0)
+    {
+      puts ("mutex_lock failed");
+      exit (1);
+    }
+
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("mutex_create failed");
+      exit (1);
+    }
+
+  void *status;
+  int val = pthread_tryjoin_np (th, &status);
+  if (val == 0)
+    {
+      puts ("1st tryjoin succeeded");
+      exit (1);
+    }
+  else if (val != EBUSY)
+    {
+      puts ("1st tryjoin didn't return EBUSY");
+      exit (1);
+    }
+
+  if (pthread_mutex_unlock (&lock) != 0)
+    {
+      puts ("mutex_unlock failed");
+      exit (1);
+    }
+
+  while ((val = pthread_tryjoin_np (th, &status)) != 0)
+    {
+      if (val != EBUSY)
+       {
+         printf ("tryjoin returned %s (%d), expected only 0 or EBUSY\n",
+                 strerror (val), val);
+         exit (1);
+       }
+
+      /* Delay minimally.  */
+      struct timespec ts = { .tv_sec = 0, .tv_nsec = 10000000 };
+      nanosleep (&ts, NULL);
+    }
+
+  if (status != (void *) 42l)
+    {
+      printf ("return value %p, expected %p\n", status, (void *) 42l);
+      exit (1);
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-join3.c b/nptl/tst-join3.c
new file mode 100644 (file)
index 0000000..df1135f
--- /dev/null
@@ -0,0 +1,123 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+
+
+static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+
+
+static void *
+tf (void *arg)
+{
+  if (pthread_mutex_lock (&lock) != 0)
+    {
+      puts ("child: mutex_lock failed");
+      return NULL;
+    }
+
+  return (void *) 42l;
+}
+
+
+static int
+do_test (void)
+{
+  pthread_t th;
+
+  if (pthread_mutex_lock (&lock) != 0)
+    {
+      puts ("mutex_lock failed");
+      exit (1);
+    }
+
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("mutex_create failed");
+      exit (1);
+    }
+
+  void *status;
+  struct timespec ts;
+  struct timeval tv;
+  (void) gettimeofday (&tv, NULL);
+  TIMEVAL_TO_TIMESPEC (&tv, &ts);
+  ts.tv_nsec += 200000000;
+  if (ts.tv_nsec >= 1000000000)
+    {
+      ts.tv_nsec -= 1000000000;
+      ++ts.tv_sec;
+    }
+  int val = pthread_timedjoin_np (th, &status, &ts);
+  if (val == 0)
+    {
+      puts ("1st timedjoin succeeded");
+      exit (1);
+    }
+  else if (val != ETIMEDOUT)
+    {
+      puts ("1st timedjoin didn't return ETIMEDOUT");
+      exit (1);
+    }
+
+  if (pthread_mutex_unlock (&lock) != 0)
+    {
+      puts ("mutex_unlock failed");
+      exit (1);
+    }
+
+  while (1)
+    {
+      (void) gettimeofday (&tv, NULL);
+      TIMEVAL_TO_TIMESPEC (&tv, &ts);
+      ts.tv_nsec += 200000000;
+      if (ts.tv_nsec >= 1000000000)
+       {
+         ts.tv_nsec -= 1000000000;
+         ++ts.tv_sec;
+       }
+
+      val = pthread_timedjoin_np (th, &status, &ts);
+      if (val == 0)
+       break;
+
+      if (val != ETIMEDOUT)
+       {
+         printf ("timedjoin returned %s (%d), expected only 0 or ETIMEDOUT\n",
+                 strerror (val), val);
+         exit (1);
+       }
+    }
+
+  if (status != (void *) 42l)
+    {
+      printf ("return value %p, expected %p\n", status, (void *) 42l);
+      exit (1);
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-key1.c b/nptl/tst-key1.c
new file mode 100644 (file)
index 0000000..dfbe584
--- /dev/null
@@ -0,0 +1,89 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <limits.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+
+int
+do_test (void)
+{
+  int max;
+#ifdef PTHREAD_KEYS_MAX
+  max = PTHREAD_KEYS_MAX;
+#else
+  max = _POSIX_THREAD_KEYS_MAX;
+#endif
+  pthread_key_t *keys = alloca (max * sizeof (pthread_key_t));
+
+  int i;
+  for (i = 0; i < max; ++i)
+    if (pthread_key_create (&keys[i], NULL) != 0)
+      {
+       write (2, "key_create failed\n", 18);
+       _exit (1);
+      }
+    else
+      {
+       printf ("created key %d\n", i);
+
+       if (pthread_setspecific (keys[i], (const void *) (i + 100l)) != 0)
+         {
+           write (2, "setspecific failed\n", 19);
+           _exit (1);
+         }
+      }
+
+  for (i = 0; i < max; ++i)
+    {
+      if (pthread_getspecific (keys[i]) != (void *) (i + 100l))
+       {
+         write (2, "getspecific failed\n", 19);
+         _exit (1);
+       }
+
+      if (pthread_key_delete (keys[i]) != 0)
+       {
+         write (2, "key_delete failed\n", 18);
+         _exit (1);
+       }
+    }
+
+  /* Now it must be once again possible to allocate keys.  */
+  if (pthread_key_create (&keys[0], NULL) != 0)
+    {
+      write (2, "2nd key_create failed\n", 22);
+      _exit (1);
+    }
+
+  if (pthread_key_delete (keys[0]) != 0)
+    {
+      write (2, "2nd key_delete failed\n", 22);
+      _exit (1);
+    }
+
+  return 0;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-key2.c b/nptl/tst-key2.c
new file mode 100644 (file)
index 0000000..c549332
--- /dev/null
@@ -0,0 +1,115 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#define N 2
+
+
+static int cnt0;
+static void
+f0 (void *p)
+{
+  ++cnt0;
+}
+
+
+static int cnt1;
+static void
+f1 (void *p)
+{
+  ++cnt1;
+}
+
+
+static void (*fcts[N]) (void *) =
+{
+  f0,
+  f1
+};
+
+
+static void *
+tf (void *arg)
+{
+  pthread_key_t *key = (pthread_key_t *) arg;
+
+  if (pthread_setspecific (*key, (void *) -1l) != 0)
+    {
+      write (2, "setspecific failed\n", 19);
+      _exit (1);
+    }
+
+  return NULL;
+}
+
+
+int
+do_test (void)
+{
+  pthread_key_t keys[N];
+
+  int i;
+  for (i = 0; i < N; ++i)
+    if (pthread_key_create (&keys[i], fcts[i]) != 0)
+      {
+       write (2, "key_create failed\n", 18);
+       _exit (1);
+      }
+
+  pthread_t th;
+  if (pthread_create (&th, NULL, tf, &keys[1]) != 0)
+    {
+      write (2, "create failed\n", 14);
+      _exit (1);
+    }
+
+  if (pthread_join (th, NULL) != 0)
+    {
+      write (2, "join failed\n", 12);
+      _exit (1);
+    }
+
+  if (cnt0 != 0)
+    {
+      write (2, "cnt0 != 0\n", 10);
+      _exit (1);
+    }
+
+  if (cnt1 != 1)
+    {
+      write (2, "cnt1 != 1\n", 10);
+      _exit (1);
+    }
+
+  for (i = 0; i < N; ++i)
+    if (pthread_key_delete (keys[i]) != 0)
+      {
+       write (2, "key_delete failed\n", 18);
+       _exit (1);
+      }
+
+  return 0;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-key3.c b/nptl/tst-key3.c
new file mode 100644 (file)
index 0000000..73cb741
--- /dev/null
@@ -0,0 +1,156 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#define N 2
+
+
+static int cnt0;
+static void
+f0 (void *p)
+{
+  ++cnt0;
+}
+
+
+static int cnt1;
+static void
+f1 (void *p)
+{
+  ++cnt1;
+}
+
+
+static void (*fcts[N]) (void *) =
+{
+  f0,
+  f1
+};
+
+
+static pthread_barrier_t b;
+
+
+static void *
+tf (void *arg)
+{
+  pthread_key_t *key = (pthread_key_t *) arg;
+
+  if (pthread_setspecific (*key, (void *) -1l) != 0)
+    {
+      write (2, "setspecific failed\n", 19);
+      _exit (1);
+    }
+
+  pthread_barrier_wait (&b);
+
+  const struct timespec t = { .tv_sec = 1000, .tv_nsec = 0 };
+  while (1)
+    nanosleep (&t, NULL);
+
+  /* NOTREACHED */
+  return NULL;
+}
+
+
+int
+do_test (void)
+{
+  pthread_key_t keys[N];
+
+  int i;
+  for (i = 0; i < N; ++i)
+    if (pthread_key_create (&keys[i], fcts[i]) != 0)
+      {
+       write (2, "key_create failed\n", 18);
+       _exit (1);
+      }
+
+  if (pthread_barrier_init (&b, NULL, 2) != 0)
+    {
+      write (2, "barrier_init failed\n", 20);
+      _exit (1);
+    }
+
+  pthread_t th;
+  if (pthread_create (&th, NULL, tf, &keys[1]) != 0)
+    {
+      write (2, "create failed\n", 14);
+      _exit (1);
+    }
+
+  pthread_barrier_wait (&b);
+
+  if (pthread_cancel (th) != 0)
+    {
+      write (2, "cancel failed\n", 14);
+      _exit (1);
+    }
+
+  void *status;
+  if (pthread_join (th, &status) != 0)
+    {
+      write (2, "join failed\n", 12);
+      _exit (1);
+    }
+
+  if (status != PTHREAD_CANCELED)
+    {
+      write (2, "thread not canceled\n", 20);
+      _exit (1);
+    }
+
+  /* Note that the TSD destructors not necessarily have to have
+     finished by the time pthread_join returns.  At least according to
+     POSIX.  We implement the stronger requirement that they indeed
+     have run and therefore these tests succeed.  */
+  if (cnt0 != 0)
+    {
+      write (2, "cnt0 != 0\n", 10);
+      _exit (1);
+    }
+
+  if (cnt1 != 1)
+    {
+      write (2, "cnt1 != 1\n", 10);
+      _exit (1);
+    }
+
+  for (i = 0; i < N; ++i)
+    if (pthread_key_delete (keys[i]) != 0)
+      {
+       write (2, "key_delete failed\n", 18);
+       _exit (1);
+      }
+
+  if (pthread_barrier_destroy (&b) != 0)
+    {
+      write (2, "barrier_destroy failed\n", 23);
+      _exit (1);
+    }
+
+  return 0;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-mutex1.c b/nptl/tst-mutex1.c
new file mode 100644 (file)
index 0000000..50b5cca
--- /dev/null
@@ -0,0 +1,57 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <stdio.h>
+
+
+static int
+do_test (void)
+{
+  pthread_mutex_t m;
+
+  if (pthread_mutex_init (&m, NULL) != 0)
+    {
+      puts ("mutex_init failed");
+      return 1;
+    }
+
+  if (pthread_mutex_lock (&m) != 0)
+    {
+      puts ("mutex_lock failed");
+      return 1;
+    }
+
+  if (pthread_mutex_unlock (&m) != 0)
+    {
+      puts ("mutex_unlock failed");
+      return 1;
+    }
+
+  if (pthread_mutex_destroy (&m) != 0)
+    {
+      puts ("mutex_destroy failed");
+      return 1;
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-mutex2.c b/nptl/tst-mutex2.c
new file mode 100644 (file)
index 0000000..21948a9
--- /dev/null
@@ -0,0 +1,100 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+
+
+static int
+do_test (void)
+{
+  pthread_mutex_t m;
+  pthread_mutexattr_t a;
+  int e;
+
+  if (pthread_mutexattr_init (&a) != 0)
+    {
+      puts ("mutexattr_init failed");
+      return 1;
+    }
+
+  if (pthread_mutexattr_settype (&a, PTHREAD_MUTEX_ERRORCHECK) != 0)
+    {
+      puts ("mutexattr_settype failed");
+      return 1;
+    }
+
+  if (pthread_mutex_init (&m, &a) != 0)
+    {
+      puts ("mutex_init failed");
+      return 1;
+    }
+
+  if (pthread_mutex_lock (&m) != 0)
+    {
+      puts ("mutex_lock failed");
+      return 1;
+    }
+
+  if ((e = pthread_mutex_lock (&m)) == 0)
+    {
+      puts ("2nd mutex_lock succeeded");
+      return 1;
+    }
+  else if (e != EDEADLK)
+    {
+      puts ("2nd mutex_lock error != EDEADLK");
+      return 1;
+    }
+
+  if (pthread_mutex_unlock (&m) != 0)
+    {
+      puts ("mutex_unlock failed");
+      return 1;
+    }
+
+  if ((e = pthread_mutex_unlock (&m)) == 0)
+    {
+      puts ("2nd mutex_unlock succeeded");
+      return 1;
+    }
+  else if (e != EPERM)
+    {
+      puts ("2nd mutex_unlock error != EPERM");
+      return 1;
+    }
+
+  if (pthread_mutex_destroy (&m) != 0)
+    {
+      puts ("mutex_destroy failed");
+      return 1;
+    }
+
+  if (pthread_mutexattr_destroy (&a) != 0)
+    {
+      puts ("mutexattr_destroy failed");
+      return 1;
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-mutex3.c b/nptl/tst-mutex3.c
new file mode 100644 (file)
index 0000000..c6c75ca
--- /dev/null
@@ -0,0 +1,89 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+
+
+static int
+do_test (void)
+{
+  pthread_mutex_t m;
+  pthread_mutexattr_t a;
+
+  if (pthread_mutexattr_init (&a) != 0)
+    {
+      puts ("mutexattr_init failed");
+      return 1;
+    }
+
+  if (pthread_mutexattr_settype (&a, PTHREAD_MUTEX_RECURSIVE) != 0)
+    {
+      puts ("mutexattr_settype failed");
+      return 1;
+    }
+
+  if (pthread_mutex_init (&m, &a) != 0)
+    {
+      puts ("mutex_init failed");
+      return 1;
+    }
+
+  if (pthread_mutex_lock (&m) != 0)
+    {
+      puts ("mutex_lock failed");
+      return 1;
+    }
+
+  if (pthread_mutex_lock (&m) != 0)
+    {
+      puts ("2nd mutex_lock failed");
+      return 1;
+    }
+
+  if (pthread_mutex_unlock (&m) != 0)
+    {
+      puts ("mutex_unlock failed");
+      return 1;
+    }
+
+  if (pthread_mutex_unlock (&m) != 0)
+    {
+      puts ("2nd mutex_unlock failed");
+      return 1;
+    }
+
+  if (pthread_mutex_destroy (&m) != 0)
+    {
+      puts ("mutex_destroy failed");
+      return 1;
+    }
+
+  if (pthread_mutexattr_destroy (&a) != 0)
+    {
+      puts ("mutexattr_destroy failed");
+      return 1;
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-mutex4.c b/nptl/tst-mutex4.c
new file mode 100644 (file)
index 0000000..5e71d9f
--- /dev/null
@@ -0,0 +1,187 @@
+/* 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 <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+
+
+int
+main (void)
+{
+  size_t ps = sysconf (_SC_PAGESIZE);
+  char tmpfname[] = "/tmp/tst-mutex4.XXXXXX";
+  char data[ps];
+  void *mem;
+  int fd;
+  pthread_mutex_t *m;
+  pthread_mutexattr_t a;
+  pid_t pid;
+  char *p;
+  int err;
+  int s;
+
+  fd = mkstemp (tmpfname);
+  if (fd == -1)
+    {
+      printf ("cannot open temporary file: %m\n");
+      exit (1);
+    }
+
+  /* Make sure it is always removed.  */
+  unlink (tmpfname);
+
+  /* Create one page of data.  */
+  memset (data, '\0', ps);
+
+  /* Write the data to the file.  */
+  if (write (fd, data, ps) != ps)
+    {
+      puts ("short write");
+      exit (1);
+    }
+
+  mem = mmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+  if (mem == MAP_FAILED)
+    {
+      printf ("mmap failed: %m\n");
+      exit (1);
+    }
+
+  m = (pthread_mutex_t *) (((uintptr_t) mem + __alignof (pthread_mutex_t))
+                          & ~(__alignof (pthread_mutex_t) - 1));
+  p = (char *) (m + 1);
+
+  if (pthread_mutexattr_init (&a) != 0)
+    {
+      puts ("mutexattr_init failed");
+      exit (1);
+    }
+
+  if (pthread_mutexattr_getpshared (&a, &s) != 0)
+    {
+      puts ("1st mutexattr_getpshared failed");
+      exit (1);
+    }
+
+  if (s != PTHREAD_PROCESS_PRIVATE)
+    {
+      puts ("default pshared value wrong");
+      exit (1);
+    }
+
+  if (pthread_mutexattr_setpshared (&a, PTHREAD_PROCESS_SHARED) != 0)
+    {
+      puts ("mutexattr_setpshared failed");
+      exit (1);
+    }
+
+  if (pthread_mutexattr_getpshared (&a, &s) != 0)
+    {
+      puts ("2nd mutexattr_getpshared failed");
+      exit (1);
+    }
+
+  if (s != PTHREAD_PROCESS_SHARED)
+    {
+      puts ("pshared value after setpshared call wrong");
+      exit (1);
+    }
+
+  if (pthread_mutex_init (m, &a) != 0)
+    {
+      puts ("mutex_init failed");
+      exit (1);
+    }
+
+  if (pthread_mutex_lock (m) != 0)
+    {
+      puts ("mutex_lock failed");
+      exit (1);
+    }
+
+  if (pthread_mutexattr_destroy (&a) != 0)
+    {
+      puts ("mutexattr_destroy failed");
+      exit (1);
+    }
+
+  err = pthread_mutex_trylock (m);
+  if (err == 0)
+    {
+      puts ("mutex_trylock succeeded");
+      exit (1);
+    }
+  else if (err != EBUSY)
+    {
+      puts ("mutex_trylock didn't return EBUSY");
+      exit (1);
+    }
+
+  *p = 0;
+
+  puts ("going to fork now");
+  pid = fork ();
+  if (pid == -1)
+    {
+      puts ("fork failed");
+      exit (1);
+    }
+  else if (pid == 0)
+    {
+      /* Play some lock ping-pong.  It's our turn to unlock first.  */
+      if ((*p)++ != 0)
+       {
+         puts ("child: *p != 0");
+         exit (1);
+       }
+
+      if (pthread_mutex_unlock (m) != 0)
+       {
+         puts ("child: 1st mutex_unlock failed");
+         exit (1);
+       }
+
+      puts ("child done");
+    }
+  else
+    {
+      if (pthread_mutex_lock (m) != 0)
+       {
+         puts ("parent: 2nd mutex_lock failed");
+         exit (1);
+       }
+
+      if (*p != 1)
+       {
+         puts ("*p != 1");
+         exit (1);
+       }
+
+      puts ("parent done");
+    }
+
+  exit (0);
+}
diff --git a/nptl/tst-mutex5.c b/nptl/tst-mutex5.c
new file mode 100644 (file)
index 0000000..cfa8d31
--- /dev/null
@@ -0,0 +1,118 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/time.h>
+
+
+static int
+do_test (void)
+{
+  pthread_mutex_t m;
+  struct timespec ts;
+  struct timeval tv;
+  struct timeval tv2;
+  int err;
+
+  if (pthread_mutex_init (&m, NULL) != 0)
+    {
+      puts ("mutex_init failed");
+      return 1;
+    }
+
+  if (pthread_mutex_lock (&m) != 0)
+    {
+      puts ("mutex_lock failed");
+      return 1;
+    }
+
+  if (pthread_mutex_trylock (&m) == 0)
+    {
+      puts ("mutex_trylock succeeded");
+      return 1;
+    }
+
+  gettimeofday (&tv, NULL);
+  TIMEVAL_TO_TIMESPEC (&tv, &ts);
+
+  ts.tv_sec += 2;      /* Wait 2 seconds.  */
+
+  err = pthread_mutex_timedlock (&m, &ts);
+  if (err == 0)
+    {
+      puts ("timed_lock succeeded");
+      return 1;
+    }
+  else if (err != ETIMEDOUT)
+    {
+      printf ("timed_lock error != ETIMEDOUT: %d\n", err);
+      return 1;
+    }
+  else
+    {
+      int clk_tck = sysconf (_SC_CLK_TCK);
+
+      gettimeofday (&tv2, NULL);
+
+      tv2.tv_sec -= tv.tv_sec;
+      tv2.tv_usec -= tv.tv_usec;
+      if (tv2.tv_usec < 0)
+       {
+         tv2.tv_usec += 1000000;
+         tv2.tv_sec -= 1;
+       }
+
+      /* Be a bit tolerant, add one CLK_TCK.  */
+      tv2.tv_usec += 1000000 / clk_tck;
+      if (tv2.tv_usec >= 1000000)
+       {
+         tv2.tv_usec -= 1000000;
+         ++tv2.tv_sec;
+       }
+
+      if (tv2.tv_sec < 2)
+       {
+         printf ("premature timeout: %ld.%06ld difference\n",
+                 tv2.tv_sec, tv2.tv_usec);
+         return 1;
+       }
+    }
+
+  if (pthread_mutex_unlock (&m) != 0)
+    {
+      puts ("mutex_unlock failed");
+      return 1;
+    }
+
+  if (pthread_mutex_destroy (&m) != 0)
+    {
+      puts ("mutex_destroy failed");
+      return 1;
+    }
+
+  return 0;
+}
+
+#define TIMEOUT 4
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-mutex6.c b/nptl/tst-mutex6.c
new file mode 100644 (file)
index 0000000..f066c62
--- /dev/null
@@ -0,0 +1,55 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <unistd.h>
+
+
+static int
+do_test (void)
+{
+  pthread_mutex_t m;
+
+  if (pthread_mutex_init (&m, NULL) != 0)
+    {
+      puts ("mutex_init failed");
+      return 1;
+    }
+
+  if (pthread_mutex_lock (&m) != 0)
+    {
+      puts ("1st mutex_lock failed");
+      return 1;
+    }
+
+  /* Set an alarm for 1 second.  The wrapper will expect this.  */
+  alarm (1);
+
+  /* This call should never return.  */
+  pthread_mutex_lock (&m);
+
+  puts ("2nd mutex_lock returned");
+  return 1;
+}
+
+#define EXPECTED_SIGNAL SIGALRM
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-mutex7.c b/nptl/tst-mutex7.c
new file mode 100644 (file)
index 0000000..9ee8ece
--- /dev/null
@@ -0,0 +1,97 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <time.h>
+
+
+static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+
+
+#define ROUNDS 1000
+#define N 100
+
+
+static void *
+tf (void *arg)
+{
+  int nr = (long int) arg;
+  int cnt;
+  struct timespec ts = { .tv_sec = 0, .tv_nsec = 11000 };
+
+  for (cnt = 0; cnt < ROUNDS; ++cnt)
+    {
+      if (pthread_mutex_lock (&lock) != 0)
+       {
+         printf ("thread %d: failed to get the lock\n", nr);
+         return (void *) 1l;
+       }
+
+      if (pthread_mutex_unlock (&lock) != 0)
+       {
+         printf ("thread %d: failed to release the lock\n", nr);
+         return (void *) 1l;
+       }
+
+      nanosleep (&ts, NULL);
+    }
+
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  pthread_t th[N];
+  int cnt;
+
+  if (pthread_mutex_lock (&lock) != 0)
+    {
+      puts ("locking in parent failed");
+      return 1;
+    }
+
+  for (cnt = 0; cnt < N; ++cnt)
+    if (pthread_create (&th[cnt], NULL, tf, (void *) (long int) cnt) != 0)
+      {
+       printf ("creating thread %d failed\n", cnt);
+       return 1;
+      }
+
+  if (pthread_mutex_unlock (&lock) != 0)
+    {
+      puts ("unlocking in parent failed");
+      return 1;
+    }
+
+  for (cnt = 0; cnt < N; ++cnt)
+    if (pthread_join (th[cnt], NULL) != 0)
+      {
+       printf ("joining thread %d failed\n", cnt);
+       return 1;
+      }
+
+  return 0;
+}
+
+#define TIMEOUT 60
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-once1.c b/nptl/tst-once1.c
new file mode 100644 (file)
index 0000000..87ed51c
--- /dev/null
@@ -0,0 +1,51 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <stdio.h>
+
+
+static pthread_once_t once = PTHREAD_ONCE_INIT;
+
+static int global;
+
+static void
+once_handler (void)
+{
+  ++global;
+}
+
+
+static int
+do_test (void)
+{
+  pthread_once (&once, once_handler);
+  pthread_once (&once, once_handler);
+
+  if (global != 1)
+    {
+      printf ("global = %d, expected 1\n", global);
+      return 1;
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-once2.c b/nptl/tst-once2.c
new file mode 100644 (file)
index 0000000..3fbc4a9
--- /dev/null
@@ -0,0 +1,85 @@
+/* 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 <time.h>
+
+
+#define N 100
+
+static pthread_once_t once = PTHREAD_ONCE_INIT;
+
+static int global;
+
+static void
+once_handler (void)
+{
+  struct timespec ts;
+
+  ++global;
+
+  ts.tv_sec = 2;
+  ts.tv_nsec = 0;
+  nanosleep (&ts, NULL);
+}
+
+
+static void *
+tf (void *arg)
+{
+  pthread_once (&once, once_handler);
+
+  if (global != 1)
+    {
+      printf ("thread %ld: global == %d\n", (long int) arg, global);
+      exit (1);
+    }
+
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  pthread_t th[N];
+  int cnt;
+
+  for (cnt = 0; cnt < N; ++cnt)
+    if (pthread_create (&th[cnt], NULL, tf, (void *) (long int) cnt) != 0)
+      {
+       printf ("creation of thread %d failed\n", cnt);
+       return 1;
+      }
+
+  for (cnt = 0; cnt < N; ++cnt)
+    if (pthread_join (th[cnt], NULL) != 0)
+      {
+       printf ("join of thread %d failed\n", cnt);
+       return 1;
+      }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#define TIMEOUT 4
+#include "../test-skeleton.c"
diff --git a/nptl/tst-rwlock1.c b/nptl/tst-rwlock1.c
new file mode 100644 (file)
index 0000000..c97e0e6
--- /dev/null
@@ -0,0 +1,117 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <stdio.h>
+
+
+static int
+do_test (void)
+{
+  pthread_rwlock_t r;
+
+  if (pthread_rwlock_init (&r, NULL) != 0)
+    {
+      puts ("rwlock_init failed");
+      return 1;
+    }
+  puts ("rwlock_init succeeded");
+
+  if (pthread_rwlock_rdlock (&r) != 0)
+    {
+      puts ("1st rwlock_rdlock failed");
+      return 1;
+    }
+  puts ("1st rwlock_rdlock succeeded");
+
+  if (pthread_rwlock_rdlock (&r) != 0)
+    {
+      puts ("2nd rwlock_rdlock failed");
+      return 1;
+    }
+  puts ("2nd rwlock_rdlock succeeded");
+
+  if (pthread_rwlock_unlock (&r) != 0)
+    {
+      puts ("1st rwlock_unlock failed");
+      return 1;
+    }
+  puts ("1st rwlock_unlock succeeded");
+
+  if (pthread_rwlock_unlock (&r) != 0)
+    {
+      puts ("2nd rwlock_unlock failed");
+      return 1;
+    }
+  puts ("2nd rwlock_unlock succeeded");
+
+  if (pthread_rwlock_wrlock (&r) != 0)
+    {
+      puts ("1st rwlock_wrlock failed");
+      return 1;
+    }
+  puts ("1st rwlock_wrlock succeeded");
+
+  if (pthread_rwlock_unlock (&r) != 0)
+    {
+      puts ("3rd rwlock_unlock failed");
+      return 1;
+    }
+  puts ("3rd rwlock_unlock succeeded");
+
+  if (pthread_rwlock_wrlock (&r) != 0)
+    {
+      puts ("2nd rwlock_wrlock failed");
+      return 1;
+    }
+  puts ("2nd rwlock_wrlock succeeded");
+
+  if (pthread_rwlock_unlock (&r) != 0)
+    {
+      puts ("4th rwlock_unlock failed");
+      return 1;
+    }
+  puts ("4th rwlock_unlock succeeded");
+
+  if (pthread_rwlock_rdlock (&r) != 0)
+    {
+      puts ("3rd rwlock_rdlock failed");
+      return 1;
+    }
+  puts ("3rd rwlock_rdlock succeeded");
+
+  if (pthread_rwlock_unlock (&r) != 0)
+    {
+      puts ("5th rwlock_unlock failed");
+      return 1;
+    }
+  puts ("5th rwlock_unlock succeeded");
+
+  if (pthread_rwlock_destroy (&r) != 0)
+    {
+      puts ("rwlock_destroy failed");
+      return 1;
+    }
+  puts ("rwlock_destroy succeeded");
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-rwlock2.c b/nptl/tst-rwlock2.c
new file mode 100644 (file)
index 0000000..6f38682
--- /dev/null
@@ -0,0 +1,143 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+
+
+static int
+do_test (void)
+{
+  pthread_rwlock_t r;
+  int e;
+
+  if (pthread_rwlock_init (&r, NULL) != 0)
+    {
+      puts ("rwlock_init failed");
+      return 1;
+    }
+  puts ("rwlock_init succeeded");
+
+  if (pthread_rwlock_wrlock (&r) != 0)
+    {
+      puts ("1st rwlock_wrlock failed");
+      return 1;
+    }
+  puts ("1st rwlock_wrlock succeeded");
+
+  e = pthread_rwlock_tryrdlock (&r);
+  if (e == 0)
+    {
+      puts ("rwlock_tryrdlock on rwlock with writer succeeded");
+      return 1;
+    }
+  if (e != EBUSY)
+    {
+      puts ("rwlock_tryrdlock on rwlock with writer return value != EBUSY");
+      return 1;
+    }
+  puts ("rwlock_tryrdlock on rwlock with writer failed with EBUSY");
+
+  e = pthread_rwlock_trywrlock (&r);
+  if (e == 0)
+    {
+      puts ("rwlock_trywrlock on rwlock with writer succeeded");
+      return 1;
+    }
+  if (e != EBUSY)
+    {
+      puts ("rwlock_trywrlock on rwlock with writer return value != EBUSY");
+      return 1;
+    }
+  puts ("rwlock_trywrlock on rwlock with writer failed with EBUSY");
+
+  if (pthread_rwlock_unlock (&r) != 0)
+    {
+      puts ("1st rwlock_unlock failed");
+      return 1;
+    }
+  puts ("1st rwlock_unlock succeeded");
+
+  if (pthread_rwlock_tryrdlock (&r) != 0)
+    {
+      puts ("rwlock_tryrdlock on unlocked rwlock failed");
+      return 1;
+    }
+  puts ("rwlock_tryrdlock on unlocked rwlock succeeded");
+
+  e = pthread_rwlock_trywrlock (&r);
+  if (e == 0)
+    {
+      puts ("rwlock_trywrlock on rwlock with reader succeeded");
+      return 1;
+    }
+  if (e != EBUSY)
+    {
+      puts ("rwlock_trywrlock on rwlock with reader return value != EBUSY");
+      return 1;
+    }
+  puts ("rwlock_trywrlock on rwlock with reader failed with EBUSY");
+
+  if (pthread_rwlock_unlock (&r) != 0)
+    {
+      puts ("2nd rwlock_unlock failed");
+      return 1;
+    }
+  puts ("2nd rwlock_unlock succeeded");
+
+  if (pthread_rwlock_trywrlock (&r) != 0)
+    {
+      puts ("rwlock_trywrlock on unlocked rwlock failed");
+      return 1;
+    }
+  puts ("rwlock_trywrlock on unlocked rwlock succeeded");
+
+  e = pthread_rwlock_tryrdlock (&r);
+  if (e == 0)
+    {
+      puts ("rwlock_tryrdlock on rwlock with writer succeeded");
+      return 1;
+    }
+  if (e != EBUSY)
+    {
+      puts ("rwlock_tryrdlock on rwlock with writer return value != EBUSY");
+      return 1;
+    }
+  puts ("rwlock_tryrdlock on rwlock with writer failed with EBUSY");
+
+  if (pthread_rwlock_unlock (&r) != 0)
+    {
+      puts ("3rd rwlock_unlock failed");
+      return 1;
+    }
+  puts ("3rd rwlock_unlock succeeded");
+
+  if (pthread_rwlock_destroy (&r) != 0)
+    {
+      puts ("rwlock_destroy failed");
+      return 1;
+    }
+  puts ("rwlock_destroy succeeded");
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-rwlock3.c b/nptl/tst-rwlock3.c
new file mode 100644 (file)
index 0000000..c1cac87
--- /dev/null
@@ -0,0 +1,93 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* This test case checks more than standard compliance.  An
+   implementation may provide this service but it is not required to
+   do so.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+
+
+static int
+do_test (void)
+{
+  pthread_rwlock_t r;
+  int e;
+
+  if (pthread_rwlock_init (&r, NULL) != 0)
+    {
+      puts ("rwlock_init failed");
+      return 1;
+    }
+  puts ("rwlock_init succeeded");
+
+  if (pthread_rwlock_trywrlock (&r) != 0)
+    {
+      puts ("rwlock_trywrlock on unlocked rwlock failed");
+      return 1;
+    }
+  puts ("rwlock_trywrlock on unlocked rwlock succeeded");
+
+  e = pthread_rwlock_rdlock (&r);
+  if (e == 0)
+    {
+      puts ("rwlock_rdlock on rwlock with writer succeeded");
+      return 1;
+    }
+  if (e != EDEADLK)
+    {
+      puts ("rwlock_rdlock on rwlock with writer failed != EDEADLK");
+      return 1;
+    }
+  puts ("rwlock_rdlock on rwlock with writer failed with EDEADLK");
+
+  e = pthread_rwlock_wrlock (&r);
+  if (e == 0)
+    {
+      puts ("rwlock_wrlock on rwlock with writer succeeded");
+      return 1;
+    }
+  if (e != EDEADLK)
+    {
+      puts ("rwlock_wrlock on rwlock with writer failed != EDEADLK");
+      return 1;
+    }
+  puts ("rwlock_wrlock on rwlock with writer failed with EDEADLK");
+
+  if (pthread_rwlock_unlock (&r) != 0)
+    {
+      puts ("rwlock_unlock failed");
+      return 1;
+    }
+  puts ("rwlock_unlock succeeded");
+
+  if (pthread_rwlock_destroy (&r) != 0)
+    {
+      puts ("rwlock_destroy failed");
+      return 1;
+    }
+  puts ("rwlock_destroy succeeded");
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-rwlock4.c b/nptl/tst-rwlock4.c
new file mode 100644 (file)
index 0000000..2bf5416
--- /dev/null
@@ -0,0 +1,187 @@
+/* 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 <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+
+
+int
+main (void)
+{
+  size_t ps = sysconf (_SC_PAGESIZE);
+  char tmpfname[] = "/tmp/tst-rwlock4.XXXXXX";
+  char data[ps];
+  void *mem;
+  int fd;
+  pthread_rwlock_t *r;
+  pthread_rwlockattr_t a;
+  pid_t pid;
+  char *p;
+  int err;
+  int s;
+
+  fd = mkstemp (tmpfname);
+  if (fd == -1)
+    {
+      printf ("cannot open temporary file: %m\n");
+      exit (1);
+    }
+
+  /* Make sure it is always removed.  */
+  unlink (tmpfname);
+
+  /* Create one page of data.  */
+  memset (data, '\0', ps);
+
+  /* Write the data to the file.  */
+  if (write (fd, data, ps) != ps)
+    {
+      puts ("short write");
+      exit (1);
+    }
+
+  mem = mmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+  if (mem == MAP_FAILED)
+    {
+      printf ("mmap failed: %m\n");
+      exit (1);
+    }
+
+  r = (pthread_rwlock_t *) (((uintptr_t) mem + __alignof (pthread_rwlock_t))
+                           & ~(__alignof (pthread_rwlock_t) - 1));
+  p = (char *) (r + 1);
+
+  if (pthread_rwlockattr_init (&a) != 0)
+    {
+      puts ("rwlockattr_init failed");
+      exit (1);
+    }
+
+  if (pthread_rwlockattr_getpshared (&a, &s) != 0)
+    {
+      puts ("1st rwlockattr_getpshared failed");
+      exit (1);
+    }
+
+  if (s != PTHREAD_PROCESS_PRIVATE)
+    {
+      puts ("default pshared value wrong");
+      exit (1);
+    }
+
+  if (pthread_rwlockattr_setpshared (&a, PTHREAD_PROCESS_SHARED) != 0)
+    {
+      puts ("rwlockattr_setpshared failed");
+      exit (1);
+    }
+
+  if (pthread_rwlockattr_getpshared (&a, &s) != 0)
+    {
+      puts ("2nd rwlockattr_getpshared failed");
+      exit (1);
+    }
+
+  if (s != PTHREAD_PROCESS_SHARED)
+    {
+      puts ("pshared value after setpshared call wrong");
+      exit (1);
+    }
+
+  if (pthread_rwlock_init (r, &a) != 0)
+    {
+      puts ("rwlock_init failed");
+      exit (1);
+    }
+
+  if (pthread_rwlock_rdlock (r) != 0)
+    {
+      puts ("rwlock_rdlock failed");
+      exit (1);
+    }
+
+  if (pthread_rwlockattr_destroy (&a) != 0)
+    {
+      puts ("rwlockattr_destroy failed");
+      exit (1);
+    }
+
+  err = pthread_rwlock_trywrlock (r);
+  if (err == 0)
+    {
+      puts ("rwlock_trywrlock succeeded");
+      exit (1);
+    }
+  else if (err != EBUSY)
+    {
+      puts ("rwlock_trywrlock didn't return EBUSY");
+      exit (1);
+    }
+
+  *p = 0;
+
+  puts ("going to fork now");
+  pid = fork ();
+  if (pid == -1)
+    {
+      puts ("fork failed");
+      exit (1);
+    }
+  else if (pid == 0)
+    {
+      /* Play some lock ping-pong.  It's our turn to unlock first.  */
+      if ((*p)++ != 0)
+       {
+         puts ("child: *p != 0");
+         exit (1);
+       }
+
+      if (pthread_rwlock_unlock (r) != 0)
+       {
+         puts ("child: 1st rwlock_unlock failed");
+         exit (1);
+       }
+
+      puts ("child done");
+    }
+  else
+    {
+      if (pthread_rwlock_wrlock (r) != 0)
+       {
+         puts ("parent: rwlock_wrlock failed");
+         exit (1);
+       }
+
+      if (*p != 1)
+       {
+         puts ("*p != 1");
+         exit (1);
+       }
+
+      puts ("parent done");
+    }
+
+  exit (0);
+}
diff --git a/nptl/tst-rwlock5.c b/nptl/tst-rwlock5.c
new file mode 100644 (file)
index 0000000..a04eb26
--- /dev/null
@@ -0,0 +1,87 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+
+static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
+static pthread_rwlock_t r;
+
+
+static void *
+tf (void *arg)
+{
+  if (pthread_rwlock_wrlock (&r) == 0)
+    {
+      puts ("child: rwlock_wrlock succeeded");
+      exit (1);
+    }
+
+  puts ("child: rwlock_wrlock returned");
+
+  exit (1);
+}
+
+
+static int
+do_test (void)
+{
+  pthread_t th;
+
+  if (pthread_rwlock_init (&r, NULL) != 0)
+    {
+      puts ("rwlock_init failed");
+      return 1;
+    }
+
+  if (pthread_rwlock_wrlock (&r) != 0)
+    {
+      puts ("rwlock_wrlock failed");
+      return 1;
+    }
+
+  if (pthread_mutex_lock (&m) != 0)
+    {
+      puts ("mutex_lock failed");
+      return 1;
+    }
+
+  /* Set an alarm for 1 second.  The wrapper will expect this.  */
+  alarm (1);
+
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("create failed");
+      return 1;
+    }
+
+  /* This call should never return.  */
+  pthread_mutex_lock (&m);
+
+  puts ("2nd mutex_lock returned");
+  return 1;
+}
+
+#define EXPECTED_SIGNAL SIGALRM
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-rwlock6.c b/nptl/tst-rwlock6.c
new file mode 100644 (file)
index 0000000..f0a96e8
--- /dev/null
@@ -0,0 +1,161 @@
+/* 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+
+
+static int kind[] =
+  {
+    PTHREAD_RWLOCK_PREFER_READER_NP,
+    PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP,
+    PTHREAD_RWLOCK_PREFER_WRITER_NP,
+  };
+
+
+static void *
+tf (void *arg)
+{
+  pthread_rwlock_t *r = arg;
+
+  /* Timeout: 0.3 secs.  */
+  struct timeval tv;
+  (void) gettimeofday (&tv, NULL);
+
+  struct timespec ts;
+  TIMEVAL_TO_TIMESPEC (&tv, &ts);
+  ts.tv_nsec += 300000000;
+  if (ts.tv_nsec >= 1000000000)
+    {
+      ts.tv_nsec -= 1000000000;
+      ++ts.tv_sec;
+    }
+
+  int err = pthread_rwlock_timedrdlock (r, &ts);
+  if (err == 0)
+    {
+      puts ("rwlock_timedrdlock returned");
+      pthread_exit ((void *) 1l);
+    }
+
+  if (err != ETIMEDOUT)
+    {
+      printf ("err = %s (%d), expected %s (%d)\n",
+             strerror (err), err, strerror (ETIMEDOUT), ETIMEDOUT);
+      pthread_exit ((void *) 1l);
+    }
+
+  struct timeval tv2;
+  (void) gettimeofday (&tv2, NULL);
+
+  timersub (&tv2, &tv, &tv);
+
+  if (tv.tv_usec < 200000)
+    {
+      puts ("timeout too short");
+      pthread_exit ((void *) 1l);
+    }
+
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  int cnt;
+  for (cnt = 0; cnt < sizeof (kind) / sizeof (kind[0]); ++cnt)
+    {
+      pthread_rwlock_t r;
+      pthread_rwlockattr_t a;
+
+      if (pthread_rwlockattr_init (&a) != 0)
+       {
+         printf ("round %d: rwlockattr_t failed\n", cnt);
+         exit (1);
+       }
+
+      if (pthread_rwlockattr_setkind_np (&a, kind[cnt]) != 0)
+       {
+         printf ("round %d: rwlockattr_setkind failed\n", cnt);
+         exit (1);
+       }
+
+      if (pthread_rwlock_init (&r, &a) != 0)
+       {
+         printf ("round %d: rwlock_init failed\n", cnt);
+         exit (1);
+       }
+
+      if (pthread_rwlockattr_destroy (&a) != 0)
+       {
+         printf ("round %d: rwlockattr_destroy failed\n", cnt);
+         exit (1);
+       }
+
+      struct timeval tv;
+      (void) gettimeofday (&tv, NULL);
+
+      struct timespec ts;
+      TIMEVAL_TO_TIMESPEC (&tv, &ts);
+
+      ++ts.tv_sec;
+
+      /* Get a write lock.  */
+      if (pthread_rwlock_timedwrlock (&r, &ts) != 0)
+       {
+         printf ("round %d: rwlock_wrlock failed\n", cnt);
+         exit (1);
+       }
+
+      pthread_t th;
+      if (pthread_create (&th, NULL, tf, &r) != 0)
+       {
+         printf ("round %d: create failed\n", cnt);
+         exit (1);
+       }
+
+      void *status;
+      if (pthread_join (th, &status) != 0)
+       {
+         printf ("round %d: join failed\n", cnt);
+         exit (1);
+       }
+      if (status != NULL)
+       {
+         printf ("failure in round %d\n", cnt);
+         exit (1);
+       }
+
+      if (pthread_rwlock_destroy (&r) != 0)
+       {
+         printf ("round %d: rwlock_destroy failed\n", cnt);
+         exit (1);
+       }
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-rwlock7.c b/nptl/tst-rwlock7.c
new file mode 100644 (file)
index 0000000..41e5af3
--- /dev/null
@@ -0,0 +1,161 @@
+/* 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+
+
+static int kind[] =
+  {
+    PTHREAD_RWLOCK_PREFER_READER_NP,
+    PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP,
+    PTHREAD_RWLOCK_PREFER_WRITER_NP,
+  };
+
+
+static void *
+tf (void *arg)
+{
+  pthread_rwlock_t *r = arg;
+
+  /* Timeout: 0.3 secs.  */
+  struct timeval tv;
+  (void) gettimeofday (&tv, NULL);
+
+  struct timespec ts;
+  TIMEVAL_TO_TIMESPEC (&tv, &ts);
+  ts.tv_nsec += 300000000;
+  if (ts.tv_nsec >= 1000000000)
+    {
+      ts.tv_nsec -= 1000000000;
+      ++ts.tv_sec;
+    }
+
+  int err = pthread_rwlock_timedwrlock (r, &ts);
+  if (err == 0)
+    {
+      puts ("rwlock_timedwrlock returned");
+      pthread_exit ((void *) 1l);
+    }
+
+  if (err != ETIMEDOUT)
+    {
+      printf ("err = %s (%d), expected %s (%d)\n",
+             strerror (err), err, strerror (ETIMEDOUT), ETIMEDOUT);
+      pthread_exit ((void *) 1l);
+    }
+
+  struct timeval tv2;
+  (void) gettimeofday (&tv2, NULL);
+
+  timersub (&tv2, &tv, &tv);
+
+  if (tv.tv_usec < 200000)
+    {
+      puts ("timeout too short");
+      pthread_exit ((void *) 1l);
+    }
+
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  int cnt;
+  for (cnt = 0; cnt < sizeof (kind) / sizeof (kind[0]); ++cnt)
+    {
+      pthread_rwlock_t r;
+      pthread_rwlockattr_t a;
+
+      if (pthread_rwlockattr_init (&a) != 0)
+       {
+         printf ("round %d: rwlockattr_t failed\n", cnt);
+         exit (1);
+       }
+
+      if (pthread_rwlockattr_setkind_np (&a, kind[cnt]) != 0)
+       {
+         printf ("round %d: rwlockattr_setkind failed\n", cnt);
+         exit (1);
+       }
+
+      if (pthread_rwlock_init (&r, &a) != 0)
+       {
+         printf ("round %d: rwlock_init failed\n", cnt);
+         exit (1);
+       }
+
+      if (pthread_rwlockattr_destroy (&a) != 0)
+       {
+         printf ("round %d: rwlockattr_destroy failed\n", cnt);
+         exit (1);
+       }
+
+      struct timeval tv;
+      (void) gettimeofday (&tv, NULL);
+
+      struct timespec ts;
+      TIMEVAL_TO_TIMESPEC (&tv, &ts);
+
+      ++ts.tv_sec;
+
+      /* Get a read lock.  */
+      if (pthread_rwlock_timedrdlock (&r, &ts) != 0)
+       {
+         printf ("round %d: rwlock_wrlock failed\n", cnt);
+         exit (1);
+       }
+
+      pthread_t th;
+      if (pthread_create (&th, NULL, tf, &r) != 0)
+       {
+         printf ("round %d: create failed\n", cnt);
+         exit (1);
+       }
+
+      void *status;
+      if (pthread_join (th, &status) != 0)
+       {
+         printf ("round %d: join failed\n", cnt);
+         exit (1);
+       }
+      if (status != NULL)
+       {
+         printf ("failure in round %d\n", cnt);
+         exit (1);
+       }
+
+      if (pthread_rwlock_destroy (&r) != 0)
+       {
+         printf ("round %d: rwlock_destroy failed\n", cnt);
+         exit (1);
+       }
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-sem1.c b/nptl/tst-sem1.c
new file mode 100644 (file)
index 0000000..32d59eb
--- /dev/null
@@ -0,0 +1,89 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <semaphore.h>
+#include <stdio.h>
+#include <unistd.h>
+
+
+static int
+do_test (void)
+{
+  sem_t s;
+
+  if (sem_init (&s, 0, 1) == -1)
+    {
+      puts ("init failed");
+      return 1;
+    }
+
+  if (TEMP_FAILURE_RETRY (sem_wait (&s)) == -1)
+    {
+      puts ("1st wait failed");
+      return 1;
+    }
+
+  if (sem_post (&s) == -1)
+    {
+      puts ("1st post failed");
+      return 1;
+    }
+
+  if (TEMP_FAILURE_RETRY (sem_trywait (&s)) == -1)
+    {
+      puts ("1st trywait failed");
+      return 1;
+    }
+
+  errno = 0;
+  if (TEMP_FAILURE_RETRY (sem_trywait (&s)) != -1)
+    {
+      puts ("2nd trywait succeeded");
+      return 1;
+    }
+  else if (errno != EAGAIN)
+    {
+      puts ("2nd trywait did not set errno to EAGAIN");
+      return 1;
+    }
+
+  if (sem_post (&s) == -1)
+    {
+      puts ("2nd post failed");
+      return 1;
+    }
+
+  if (TEMP_FAILURE_RETRY (sem_wait (&s)) == -1)
+    {
+      puts ("2nd wait failed");
+      return 1;
+    }
+
+  if (sem_destroy (&s) == -1)
+    {
+      puts ("destroy failed");
+      return 1;
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-sem2.c b/nptl/tst-sem2.c
new file mode 100644 (file)
index 0000000..026939e
--- /dev/null
@@ -0,0 +1,54 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <semaphore.h>
+#include <signal.h>
+#include <stdio.h>
+#include <unistd.h>
+
+
+static int
+do_test (void)
+{
+  sem_t s;
+
+  if (sem_init (&s, 0, 0) == -1)
+    {
+      puts ("init failed");
+      return 1;
+    }
+
+  /* Set an alarm for 1 second.  The wrapper will expect this.  */
+  alarm (1);
+
+  if (TEMP_FAILURE_RETRY (sem_wait (&s)) == -1)
+    {
+      puts ("wait failed");
+      return 1;
+    }
+
+  /* We should never get here.  */
+  puts ("wait succeeded");
+  return 1;
+}
+
+#define EXPECTED_SIGNAL SIGALRM
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-sem3.c b/nptl/tst-sem3.c
new file mode 100644 (file)
index 0000000..7d3f68f
--- /dev/null
@@ -0,0 +1,142 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <semaphore.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+
+
+int
+main (void)
+{
+  size_t ps = sysconf (_SC_PAGESIZE);
+  char tmpfname[] = "/tmp/tst-sem3.XXXXXX";
+  char data[ps];
+  void *mem;
+  int fd;
+  sem_t *s;
+  pid_t pid;
+  char *p;
+
+  fd = mkstemp (tmpfname);
+  if (fd == -1)
+    {
+      printf ("cannot open temporary file: %m\n");
+      exit (1);
+    }
+
+  /* Make sure it is always removed.  */
+  unlink (tmpfname);
+
+  /* Create one page of data.  */
+  memset (data, '\0', ps);
+
+  /* Write the data to the file.  */
+  if (write (fd, data, ps) != ps)
+    {
+      puts ("short write");
+      exit (1);
+    }
+
+  mem = mmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+  if (mem == MAP_FAILED)
+    {
+      printf ("mmap failed: %m\n");
+      exit (1);
+    }
+
+  s = (sem_t *) (((uintptr_t) mem + __alignof (sem_t))
+                & ~(__alignof (sem_t) - 1));
+  p = (char *) (s + 1);
+
+  if (sem_init (s, 1, 1) == -1)
+    {
+      puts ("init failed");
+      exit (1);
+    }
+
+  if (TEMP_FAILURE_RETRY (sem_wait (s)) == -1)
+    {
+      puts ("1st wait failed");
+      exit (1);
+    }
+
+  errno = 0;
+  if (TEMP_FAILURE_RETRY (sem_trywait (s)) != -1)
+    {
+      puts ("trywait succeeded");
+      exit (1);
+    }
+  else if (errno != EAGAIN)
+    {
+      puts ("trywait didn't return EAGAIN");
+      exit (1);
+    }
+
+  *p = 0;
+
+  puts ("going to fork now");
+  pid = fork ();
+  if (pid == -1)
+    {
+      puts ("fork failed");
+      exit (1);
+    }
+  else if (pid == 0)
+    {
+      /* Play some lock ping-pong.  It's our turn to unlock first.  */
+      if ((*p)++ != 0)
+       {
+         puts ("child: *p != 0");
+         exit (1);
+       }
+
+      if (sem_post (s) == -1)
+       {
+         puts ("child: 1st post failed");
+         exit (1);
+       }
+
+      puts ("child done");
+    }
+  else
+    {
+      if (TEMP_FAILURE_RETRY (sem_wait (s)) == -1)
+       {
+         printf ("parent: 2nd wait failed: %m\n");
+         exit (1);
+       }
+
+      if (*p != 1)
+       {
+         puts ("*p != 1");
+         exit (1);
+       }
+
+      puts ("parent done");
+    }
+
+  exit (0);
+}
diff --git a/nptl/tst-sem4.c b/nptl/tst-sem4.c
new file mode 100644 (file)
index 0000000..ccffbdd
--- /dev/null
@@ -0,0 +1,147 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <semaphore.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+
+static void
+remove_sem (int status, void *arg)
+{
+  sem_unlink (arg);
+}
+
+
+int
+main (void)
+{
+  sem_t *s;
+  sem_t *s2;
+  pid_t pid;
+  int val;
+
+  s = sem_open ("/glibc-tst-sem4", O_CREAT, 0600, 1);
+  if (s == SEM_FAILED)
+    {
+      if (errno == ENOSYS)
+       {
+         puts ("sem_open not supported.  Oh well.");
+         return 0;
+       }
+
+      /* Maybe the shm filesystem has strict permissions.  */
+      if (errno == EACCES)
+       {
+         puts ("sem_open not allowed.  Oh well.");
+         return 0;
+       }
+
+      printf ("sem_open: %m\n");
+      return 1;
+    }
+
+  on_exit (remove_sem, (void *) "/glibc-tst-sem4");
+
+  /* We have the semaphore object.  Now try again with O_EXCL, this
+     should fail.  */
+  s2 = sem_open ("/glibc-tst-sem4", O_CREAT | O_EXCL, 0600, 1);
+  if (s2 != SEM_FAILED)
+    {
+      puts ("2nd sem_open didn't fail");
+      return 1;
+    }
+  if (errno != EEXIST)
+    {
+      puts ("2nd sem_open returned wrong error");
+      return 1;
+    }
+
+  /* Check the value.  */
+  if (sem_getvalue (s, &val) == -1)
+    {
+      puts ("getvalue failed");
+      return 1;
+    }
+  if (val != 1)
+    {
+      printf ("initial value wrong: got %d, expected 1\n", val);
+      return 1;
+    }
+
+  if (TEMP_FAILURE_RETRY (sem_wait (s)) == -1)
+    {
+      puts ("1st sem_wait failed");
+      return 1;
+    }
+
+  pid = fork ();
+  if (pid == -1)
+    {
+      printf ("fork failed: %m\n");
+      return 1;
+    }
+
+  if (pid == 0)
+    {
+      /* Child.  */
+
+      /* Check the value.  */
+      if (sem_getvalue (s, &val) == -1)
+       {
+         puts ("child: getvalue failed");
+         return 1;
+       }
+      if (val != 0)
+       {
+         printf ("child: value wrong: got %d, expect 0\n", val);
+         return 1;
+       }
+
+      if (sem_post (s) == -1)
+       {
+         puts ("child: post failed");
+         return 1;
+       }
+    }
+  else
+    {
+      if (TEMP_FAILURE_RETRY (sem_wait (s)) == -1)
+       {
+         puts ("2nd sem_wait failed");
+         return 1;
+       }
+
+      if (sem_getvalue (s, &val) == -1)
+       {
+         puts ("parent: 2nd getvalue failed");
+         return 1;
+       }
+      if (val != 0)
+       {
+         printf ("parent: value wrong: got %d, expected 0\n", val);
+         return 1;
+       }
+    }
+
+  return 0;
+}
diff --git a/nptl/tst-sem5.c b/nptl/tst-sem5.c
new file mode 100644 (file)
index 0000000..d76c265
--- /dev/null
@@ -0,0 +1,80 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <semaphore.h>
+#include <stdio.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/time.h>
+
+
+static int
+do_test (void)
+{
+  sem_t s;
+  struct timespec ts;
+  struct timeval tv;
+
+  if (sem_init (&s, 0, 1) == -1)
+    {
+      puts ("sem_init failed");
+      return 1;
+    }
+
+  if (sem_wait (&s) == -1)
+    {
+      puts ("sem_wait failed");
+      return 1;
+    }
+
+  if (gettimeofday (&tv, NULL) != 0)
+    {
+      puts ("gettimeofday failed");
+      return 1;
+    }
+
+  TIMEVAL_TO_TIMESPEC (&tv, &ts);
+
+  /* We wait for half a second.  */
+  ts.tv_nsec += 500000000;
+  if (ts.tv_nsec >= 1000000000)
+    {
+      ++ts.tv_sec;
+      ts.tv_nsec -= 1000000000;
+    }
+
+  errno = 0;
+  if (TEMP_FAILURE_RETRY (sem_timedwait (&s, &ts)) != -1)
+    {
+      puts ("sem_timedwait succeeded");
+      return 1;
+    }
+  if (errno != ETIMEDOUT)
+    {
+      printf ("sem_timedwait return errno = %d instead of ETIMEDOUT\n",
+             errno);
+      return 1;
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-signal1.c b/nptl/tst-signal1.c
new file mode 100644 (file)
index 0000000..e7480f5
--- /dev/null
@@ -0,0 +1,189 @@
+/* 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 <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+
+
+static sigset_t ss;
+static pthread_barrier_t *b;
+
+
+static void *
+tf (void *arg)
+{
+  sigdelset (&ss, SIGINT);
+
+  if (pthread_sigmask (SIG_SETMASK, &ss, NULL) != 0)
+    {
+      puts ("2nd pthread_sigmask failed");
+      exit (1);
+    }
+
+  pthread_barrier_wait (b);
+
+  int sig;
+  int res = sigwait (&ss, &sig);
+  if (res == 0)
+    {
+      printf ("sigwait returned successfully with signal %d\n", sig);
+      exit (1);
+    }
+
+  printf ("sigwait returned with %s (%d)\n", strerror (res), res);
+
+  return NULL;
+}
+
+
+static void
+receiver (void)
+{
+  pthread_t th;
+
+  /* Make sure the process doesn't run forever.  */
+  alarm (10);
+
+  sigfillset (&ss);
+
+  if (pthread_sigmask (SIG_SETMASK, &ss, NULL) != 0)
+    {
+      puts ("1st pthread_sigmask failed");
+      exit (1);
+    }
+
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("pthread_create failed");
+      exit (1);
+    }
+
+  if (pthread_join (th, NULL) == 0)
+    {
+      puts ("thread joined?!");
+      exit (1);
+    }
+
+  _exit (0);
+}
+
+
+static int
+do_test (void)
+{
+  char tmp[] = "/tmp/tst-signal1-XXXXXX";
+
+  int fd = mkstemp (tmp);
+  if (fd == -1)
+    {
+      puts ("mkstemp failed");
+      exit (1);
+    }
+
+  unlink (tmp);
+
+  int i;
+  for (i = 0; i < 20; ++i)
+    write (fd, "foobar xyzzy", 12);
+
+  b = mmap (NULL, sizeof (pthread_barrier_t), PROT_READ | PROT_WRITE,
+           MAP_SHARED, fd, 0);
+  if (b == MAP_FAILED)
+    {
+      puts ("mmap failed");
+      exit (1);
+    }
+
+  pthread_barrierattr_t ba;
+  if (pthread_barrierattr_init (&ba) != 0)
+    {
+      puts ("barrierattr_init failed");
+      exit (1);
+    }
+
+  if (pthread_barrierattr_setpshared (&ba, PTHREAD_PROCESS_SHARED) != 0)
+    {
+      puts ("barrierattr_setpshared failed");
+      exit (1);
+    }
+
+  if (pthread_barrier_init (b, &ba, 2) != 0)
+    {
+      puts ("barrier_init failed");
+      exit (1);
+    }
+
+  if (pthread_barrierattr_destroy (&ba) != 0)
+    {
+      puts ("barrierattr_destroy failed");
+      exit (1);
+    }
+
+  pid_t pid = fork ();
+  if (pid == -1)
+    {
+      puts ("fork failed");
+      exit (1);
+    }
+
+  if (pid == 0)
+    receiver ();
+
+  pthread_barrier_wait (b);
+
+  /* Wait a bit more.  */
+  struct timespec ts = { .tv_sec = 0, .tv_nsec = 10000000 };
+  nanosleep (&ts, NULL);
+
+  /* Send the signal.  */
+  puts ("sending the signal now");
+  kill (pid, SIGINT);
+
+  /* Wait for the process to terminate.  */
+  int status;
+  if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid)
+    {
+      puts ("wrong child reported terminated");
+      exit (1);
+    }
+
+  if (!WIFSIGNALED (status))
+    {
+      puts ("child wasn't signalled");
+      exit (1);
+    }
+
+  if (WTERMSIG (status) != SIGINT)
+    {
+      puts ("child not terminated with SIGINT");
+      exit (1);
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-signal2.c b/nptl/tst-signal2.c
new file mode 100644 (file)
index 0000000..1c0a411
--- /dev/null
@@ -0,0 +1,197 @@
+/* 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 <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+
+
+static sigset_t ss;
+static pthread_barrier_t *b;
+
+
+static void *
+tf (void *arg)
+{
+  pthread_barrier_wait (b);
+
+  puts ("child: calling sigwait now");
+
+  int sig;
+  int err;
+  err = sigwait (&ss, &sig);
+  if (err != 0)
+    {
+      printf ("sigwait returned unsuccessfully: %s (%d)\n",
+             strerror (err), err);
+      _exit (1);
+    }
+
+  puts ("sigwait returned");
+
+  if (sig != SIGINT)
+    {
+      printf ("caught signal %d, expected %d (SIGINT)\n", sig, SIGINT);
+      _exit (1);
+    }
+
+  puts ("child thread terminating now");
+
+  return NULL;
+}
+
+
+static void
+receiver (void)
+{
+  pthread_t th;
+
+  /* Make sure the process doesn't run forever.  */
+  alarm (10);
+
+  sigfillset (&ss);
+
+  if (pthread_sigmask (SIG_SETMASK, &ss, NULL) != 0)
+    {
+      puts ("1st pthread_sigmask failed");
+      _exit (1);
+    }
+
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("pthread_create failed");
+      _exit (1);
+    }
+
+  if (pthread_join (th, NULL) != 0)
+    {
+      puts ("thread didn't join");
+      _exit (1);
+    }
+
+  puts ("join succeeded");
+
+  _exit (0);
+}
+
+
+static int
+do_test (void)
+{
+  char tmp[] = "/tmp/tst-signal1-XXXXXX";
+
+  int fd = mkstemp (tmp);
+  if (fd == -1)
+    {
+      puts ("mkstemp failed");
+      exit (1);
+    }
+
+  unlink (tmp);
+
+  int i;
+  for (i = 0; i < 20; ++i)
+    write (fd, "foobar xyzzy", 12);
+
+  b = mmap (NULL, sizeof (pthread_barrier_t), PROT_READ | PROT_WRITE,
+           MAP_SHARED, fd, 0);
+  if (b == MAP_FAILED)
+    {
+      puts ("mmap failed");
+      exit (1);
+    }
+
+  pthread_barrierattr_t ba;
+  if (pthread_barrierattr_init (&ba) != 0)
+    {
+      puts ("barrierattr_init failed");
+      exit (1);
+    }
+
+  if (pthread_barrierattr_setpshared (&ba, PTHREAD_PROCESS_SHARED) != 0)
+    {
+      puts ("barrierattr_setpshared failed");
+      exit (1);
+    }
+
+  if (pthread_barrier_init (b, &ba, 2) != 0)
+    {
+      puts ("barrier_init failed");
+      exit (1);
+    }
+
+  if (pthread_barrierattr_destroy (&ba) != 0)
+    {
+      puts ("barrierattr_destroy failed");
+      exit (1);
+    }
+
+  pid_t pid = fork ();
+  if (pid == -1)
+    {
+      puts ("fork failed");
+      exit (1);
+    }
+
+  if (pid == 0)
+    receiver ();
+
+  pthread_barrier_wait (b);
+
+  /* Wait a bit more.  */
+  struct timespec ts = { .tv_sec = 0, .tv_nsec = 10000000 };
+  nanosleep (&ts, NULL);
+
+  /* Send the signal.  */
+  puts ("sending the signal now");
+  kill (pid, SIGINT);
+
+  /* Wait for the process to terminate.  */
+  int status;
+  if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid)
+    {
+      puts ("wrong child reported terminated");
+      exit (1);
+    }
+
+  if (!WIFEXITED (status))
+    {
+      if (WIFSIGNALED (status))
+       printf ("child exited with signal %d\n", WTERMSIG (status));
+      else
+       puts ("child didn't exit normally");
+      exit (1);
+    }
+
+  if (WEXITSTATUS (status) != 0)
+    {
+      printf ("exit status %d != 0\n", WEXITSTATUS (status));
+      exit (1);
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-signal3.c b/nptl/tst-signal3.c
new file mode 100644 (file)
index 0000000..3de2887
--- /dev/null
@@ -0,0 +1,240 @@
+/* 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 <semaphore.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+
+/* Number of different signalss to use.  Also is the number of
+   threads.  */
+#define N 10
+/* Maximum number of threads in flight at any one time.  */
+#define INFLIGHT 5
+/* Number of signals sent in total.  */
+#define ROUNDS 10000
+
+
+static int received[N][N];
+static int nsig[N];
+static pthread_t th[N];
+static sem_t sem;
+static pthread_mutex_t lock[N];
+static pthread_t th_main;
+static int sig0;
+
+static void
+handler (int sig)
+{
+  int i;
+  for (i = 0; i < N; ++i)
+    if (pthread_equal (pthread_self (), th[i]))
+      break;
+
+  if (i == N)
+    {
+      if (pthread_equal (pthread_self (), th_main))
+       puts ("signal received by main thread");
+      else
+       printf ("signal received by unknown thread (%lx)\n",
+               (unsigned long int) pthread_self ());
+      exit (1);
+    }
+
+  ++received[i][sig - sig0];
+
+  sem_post (&sem);
+}
+
+
+static void *
+tf (void *arg)
+{
+  int idx = (long int) arg;
+
+  sigset_t ss;
+  sigemptyset (&ss);
+
+  int i;
+  for (i = 0; i <= idx; ++i)
+    sigaddset (&ss, sig0 + i);
+
+  if (pthread_sigmask (SIG_UNBLOCK, &ss, NULL) != 0)
+    {
+      printf ("thread %d: pthread_sigmask failed\n", i);
+      exit (1);
+    }
+
+  pthread_mutex_lock (&lock[idx]);
+
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  /* Block all signals.  */
+  sigset_t ss;
+  sigfillset (&ss);
+
+  th_main = pthread_self ();
+
+  sig0 = SIGRTMIN;
+
+  if (pthread_sigmask (SIG_SETMASK, &ss, NULL) != 0)
+    {
+      puts ("1st pthread_sigmask failed");
+      exit (1);
+    }
+
+  /* Install the handler.  */
+  int i;
+  for (i = 0; i < N; ++i)
+    {
+      struct sigaction sa =
+       {
+         .sa_handler = handler,
+         .sa_flags = 0
+       };
+      sigfillset (&sa.sa_mask);
+
+      if (sigaction (sig0 + i, &sa, NULL) != 0)
+       {
+         printf ("sigaction for signal %d failed\n", i);
+         exit (1);
+       }
+    }
+
+  if (sem_init (&sem, 0, INFLIGHT) != 0)
+    {
+      puts ("sem_init failed");
+      exit (1);
+    }
+
+  for (i = 0; i < N; ++i)
+    {
+      if (pthread_mutex_init (&lock[i], NULL) != 0)
+       {
+         printf ("mutex_init[%d] failed\n", i);
+       }
+
+      if (pthread_mutex_lock (&lock[i]) != 0)
+       {
+         printf ("mutex_lock[%d] failed\n", i);
+       }
+
+      if (pthread_create (&th[i], NULL, tf, (void *) (long int) i) != 0)
+       {
+         printf ("create of thread %d failed\n", i);
+         exit (1);
+       }
+    }
+
+  int result = 0;
+  unsigned int r = 42;
+  pid_t pid = getpid ();
+
+  for (i = 0; i < ROUNDS; ++i)
+    {
+      if (sem_wait (&sem) != 0)
+       {
+         printf ("sem_wait round %d failed: %m\n", i);
+         exit (1);
+       }
+
+      int s = rand_r (&r) % N;
+
+      kill (pid, sig0 + s);
+    }
+
+  void *status;
+  for (i = 0; i < N; ++i)
+    {
+      if (pthread_mutex_unlock (&lock[i]) != 0)
+       {
+         printf ("unlock %d failed\n", i);
+         exit (1);
+       }
+
+      if (pthread_join (th[i], &status) != 0)
+       {
+         printf ("join %d failed\n", i);
+         result = 1;
+       }
+      else if (status != NULL)
+       {
+         printf ("%d: result != NULL\n", i);
+         result = 1;
+       }
+    }
+
+  int total = 0;
+  for (i = 0; i < N; ++i)
+    {
+      int j;
+
+      for (j = 0; j <= i; ++j)
+       total += received[i][j];
+
+      for (j = i + 1; j < N; ++j)
+       if (received[i][j] != 0)
+         {
+           printf ("thread %d received signal SIGRTMIN+%d\n", i, j);
+           result = 1;
+         }
+    }
+
+  if (total != ROUNDS)
+    {
+      printf ("total number of handled signals is %d, expected %d\n",
+             total, ROUNDS);
+      result = 1;
+    }
+
+  printf ("A total of %d signals sent and received\n", total);
+  for (i = 0; i < N; ++i)
+    {
+      printf ("thread %2d:", i);
+
+      int j;
+      for (j = 0; j <= i; ++j)
+       {
+         printf (" %5d", received[i][j]);
+         nsig[j] += received[i][j];
+       }
+
+      putchar ('\n');
+
+    }
+
+  printf ("\nTotal    :");
+  for (i = 0; i < N; ++i)
+    printf (" %5d", nsig[i]);
+  putchar ('\n');
+
+  return result;
+}
+
+#define TIMEOUT 10
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-spin1.c b/nptl/tst-spin1.c
new file mode 100644 (file)
index 0000000..259b4b4
--- /dev/null
@@ -0,0 +1,57 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <stdio.h>
+
+
+static int
+do_test (void)
+{
+  pthread_spinlock_t s;
+
+  if (pthread_spin_init (&s, PTHREAD_PROCESS_PRIVATE) != 0)
+    {
+      puts ("spin_init failed");
+      return 1;
+    }
+
+  if (pthread_spin_lock (&s) != 0)
+    {
+      puts ("spin_lock failed");
+      return 1;
+    }
+
+  if (pthread_spin_unlock (&s) != 0)
+    {
+      puts ("spin_unlock failed");
+      return 1;
+    }
+
+  if (pthread_spin_destroy (&s) != 0)
+    {
+      puts ("spin_destroy failed");
+      return 1;
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-spin2.c b/nptl/tst-spin2.c
new file mode 100644 (file)
index 0000000..ff7421a
--- /dev/null
@@ -0,0 +1,142 @@
+/* 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 <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+
+
+int
+main (void)
+{
+  size_t ps = sysconf (_SC_PAGESIZE);
+  char tmpfname[] = "/tmp/tst-spin2.XXXXXX";
+  char data[ps];
+  void *mem;
+  int fd;
+  pthread_spinlock_t *s;
+  pid_t pid;
+  char *p;
+  int err;
+
+  fd = mkstemp (tmpfname);
+  if (fd == -1)
+    {
+      printf ("cannot open temporary file: %m\n");
+      exit (1);
+    }
+
+  /* Make sure it is always removed.  */
+  unlink (tmpfname);
+
+  /* Create one page of data.  */
+  memset (data, '\0', ps);
+
+  /* Write the data to the file.  */
+  if (write (fd, data, ps) != ps)
+    {
+      puts ("short write");
+      exit (1);
+    }
+
+  mem = mmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+  if (mem == MAP_FAILED)
+    {
+      printf ("mmap failed: %m\n");
+      exit (1);
+    }
+
+  s = (pthread_spinlock_t *) (((uintptr_t) mem
+                              + __alignof (pthread_spinlock_t))
+                             & ~(__alignof (pthread_spinlock_t) - 1));
+  p = (char *) (s + 1);
+
+  if (pthread_spin_init (s, PTHREAD_PROCESS_SHARED) != 0)
+    {
+      puts ("spin_init failed");
+      exit (1);
+    }
+
+  if (pthread_spin_lock (s) != 0)
+    {
+      puts ("spin_lock failed");
+      exit (1);
+    }
+
+  err = pthread_spin_trylock (s);
+  if (err == 0)
+    {
+      puts ("spin_trylock succeeded");
+      exit (1);
+    }
+  else if (err != EBUSY)
+    {
+      puts ("spin_trylock didn't return EBUSY");
+      exit (1);
+    }
+
+  *p = 0;
+
+  puts ("going to fork now");
+  pid = fork ();
+  if (pid == -1)
+    {
+      puts ("fork failed");
+      exit (1);
+    }
+  else if (pid == 0)
+    {
+      /* Play some lock ping-pong.  It's our turn to unlock first.  */
+      if ((*p)++ != 0)
+       {
+         puts ("child: *p != 0");
+         exit (1);
+       }
+
+      if (pthread_spin_unlock (s) != 0)
+       {
+         puts ("child: 1st spin_unlock failed");
+         exit (1);
+       }
+
+      puts ("child done");
+    }
+  else
+    {
+      if (pthread_spin_lock (s) != 0)
+       {
+         puts ("parent: 2nd spin_lock failed");
+         exit (1);
+       }
+
+      puts ("waiting for child");
+
+      waitpid (pid, NULL, 0);
+
+      puts ("parent done");
+    }
+
+  exit (0);
+}
diff --git a/nptl/tst-spin3.c b/nptl/tst-spin3.c
new file mode 100644 (file)
index 0000000..4437740
--- /dev/null
@@ -0,0 +1,55 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <unistd.h>
+
+
+static int
+do_test (void)
+{
+  pthread_spinlock_t s;
+
+  if (pthread_spin_init (&s, PTHREAD_PROCESS_PRIVATE) != 0)
+    {
+      puts ("spin_init failed");
+      return 1;
+    }
+
+  if (pthread_spin_lock (&s) != 0)
+    {
+      puts ("1st spin_lock failed");
+      return 1;
+    }
+
+  /* Set an alarm for 1 second.  The wrapper will expect this.  */
+  alarm (1);
+
+  /* This call should never return.  */
+  pthread_spin_lock (&s);
+
+  puts ("2nd spin_lock returned");
+  return 1;
+}
+
+#define EXPECTED_SIGNAL SIGALRM
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-stack1.c b/nptl/tst-stack1.c
new file mode 100644 (file)
index 0000000..471e675
--- /dev/null
@@ -0,0 +1,144 @@
+/* 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 *stack;
+static size_t size;
+
+
+static void *
+tf (void *a)
+{
+  int result = 0;
+
+  puts ("child start");
+
+  pthread_attr_t attr;
+  if (pthread_getattr_np (pthread_self (), &attr) != 0)
+    {
+      puts ("getattr_np failed");
+      exit (1);
+    }
+
+  size_t test_size;
+  void *test_stack;
+  if (pthread_attr_getstack (&attr, &test_stack, &test_size) != 0)
+    {
+      puts ("attr_getstack failed");
+      exit (1);
+    }
+
+  if (test_size != size)
+    {
+      printf ("child: reported size differs: is %zu, expected %zu\n",
+             test_size, size);
+      result = 1;
+    }
+
+  if (test_stack != stack)
+    {
+      printf ("child: reported stack address differs: is %p, expected %p\n",
+             test_stack, stack);
+      result = 1;
+    }
+
+  puts ("child OK");
+
+  return result ? (void *) 1l : NULL;
+}
+
+
+int
+do_test (void)
+{
+  int result = 0;
+
+  size = 4 * getpagesize ();
+  if (posix_memalign (&stack, getpagesize (), size) != 0)
+    {
+      puts ("out of memory while allocating the stack memory");
+      exit (1);
+    }
+
+  pthread_attr_t attr;
+  if (pthread_attr_init (&attr) != 0)
+    {
+      puts ("attr_init failed");
+      exit (1);
+    }
+
+  puts ("attr_setstack");
+  if (pthread_attr_setstack (&attr, stack, size) != 0)
+    {
+      puts ("attr_setstack failed");
+      exit (1);
+    }
+
+  size_t test_size;
+  void *test_stack;
+  puts ("attr_getstack");
+  if (pthread_attr_getstack (&attr, &test_stack, &test_size) != 0)
+    {
+      puts ("attr_getstack failed");
+      exit (1);
+    }
+
+  if (test_size != size)
+    {
+      printf ("reported size differs: is %zu, expected %zu\n",
+             test_size, size);
+      result = 1;
+    }
+
+  if (test_stack != stack)
+    {
+      printf ("reported stack address differs: is %p, expected %p\n",
+             test_stack, stack);
+      result = 1;
+    }
+
+  puts ("create");
+
+  pthread_t th;
+  if (pthread_create (&th, &attr, tf, NULL) != 0)
+    {
+      puts ("failed to create thread");
+      exit (1);
+    }
+
+  void *status;
+  if (pthread_join (th, &status) != 0)
+    {
+      puts ("join failed");
+      exit (1);
+    }
+
+  result |= status != NULL;
+
+  return result;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-tsd1.c b/nptl/tst-tsd1.c
new file mode 100644 (file)
index 0000000..51b2d0c
--- /dev/null
@@ -0,0 +1,118 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <string.h>
+
+
+static int
+do_test (void)
+{
+  pthread_key_t key1;
+  pthread_key_t key2;
+  void *value;
+  int result = 0;
+  int err;
+
+  err = pthread_key_create (&key1, NULL);
+  if (err != 0)
+    {
+      printf ("1st key_create failed: %s\n", strerror (err));
+      return 1;
+    }
+
+  /* Initial value must be NULL.  */
+  value = pthread_getspecific (key1);
+  if (value != NULL)
+    {
+      puts ("1st getspecific != NULL");
+      result = 1;
+    }
+
+  err = pthread_setspecific (key1, (void *) -2l);
+  if (err != 0)
+    {
+      printf ("1st setspecific failed: %s\n", strerror (err));
+      return 1;
+    }
+
+  value = pthread_getspecific (key1);
+  if (value == NULL)
+    {
+      puts ("2nd getspecific == NULL\n");
+      result = 1;
+    }
+  else if (value != (void *) -2l)
+    {
+      puts ("2nd getspecific != -2l\n");
+      result = 1;
+    }
+
+  err = pthread_setspecific (key1, (void *) -3l);
+  if (err != 0)
+    {
+      printf ("2nd setspecific failed: %s\n", strerror (err));
+      return 1;
+    }
+
+  value = pthread_getspecific (key1);
+  if (value == NULL)
+    {
+      puts ("3rd getspecific == NULL\n");
+      result = 1;
+    }
+  else if (value != (void *) -3l)
+    {
+      puts ("3rd getspecific != -2l\n");
+      result = 1;
+    }
+
+  err = pthread_key_delete (key1);
+  if (err != 0)
+    {
+      printf ("key_delete failed: %s\n", strerror (err));
+      result = 1;
+    }
+
+
+  err = pthread_key_create (&key2, NULL);
+  if (err != 0)
+    {
+      printf ("2nd key_create failed: %s\n", strerror (err));
+      return 1;
+    }
+
+  if (key1 != key2)
+    puts ("key1 != key2; no more tests performed");
+  else
+    {
+      value = pthread_getspecific (key2);
+      if (value != NULL)
+       {
+         puts ("4th getspecific != NULL");
+         result = 1;
+       }
+    }
+
+  return result;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-tsd2.c b/nptl/tst-tsd2.c
new file mode 100644 (file)
index 0000000..66a1128
--- /dev/null
@@ -0,0 +1,97 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <string.h>
+
+
+static int result;
+
+
+static void
+destr (void *arg)
+{
+  if (arg != (void *) -2l)
+    result = 2;
+  else
+    result = 0;
+}
+
+
+static void *
+tf (void *arg)
+{
+  pthread_key_t key = (pthread_key_t) arg;
+  int err;
+
+  err = pthread_setspecific (key, (void *) -2l);
+  if (err != 0)
+    result = 3;
+
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  pthread_key_t key;
+  pthread_t th;
+  int err;
+
+  err = pthread_key_create (&key, destr);
+  if (err != 0)
+    {
+      printf ("key_create failed: %s\n", strerror (err));
+      return 1;
+    }
+
+  result = 1;
+
+  err = pthread_create (&th, NULL, tf, (void *) key);
+  if (err != 0)
+    {
+      printf ("create failed: %s\n", strerror (err));
+      return 1;
+    }
+
+  /* Wait for the thread to terminate.  */
+  err = pthread_join (th, NULL);
+  if (err != 0)
+    {
+      printf ("join failed: %s\n", strerror (err));
+      return 1;
+    }
+
+  if (result == 1)
+    puts ("destructor not called");
+  else if (result == 2)
+    puts ("destructor got passed a wrong value");
+  else if (result == 3)
+    puts ("setspecific in child failed");
+  else if (result != 0)
+    puts ("result != 0");
+
+  return result;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-unload.c b/nptl/tst-unload.c
new file mode 100644 (file)
index 0000000..4494ce8
--- /dev/null
@@ -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 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 <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)
+    {
+      puts ("failed to load " LIBPTHREAD_SO);
+      exit (1);
+    }
+
+  if (dlclose (p) != 0)
+    {
+      puts ("dlclose (" LIBPTHREAD_SO ") failed");
+      exit (1);
+    }
+
+  puts ("seems to work");
+
+  exit (0);
+}
diff --git a/nptl_db/Makefile b/nptl_db/Makefile
new file mode 100644 (file)
index 0000000..4812cd2
--- /dev/null
@@ -0,0 +1,57 @@
+# 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.
+
+# Makefile for NPTL debug library subdirectory of GNU C Library.
+
+subdir          := nptl_db
+
+nptl_db-version = 1.0
+
+extra-libs = libthread_db
+extra-libs-others := $(extra-libs)
+
+headers         = thread_db.h
+
+libthread_db-routines = td_init td_log td_ta_new td_ta_delete \
+                       td_ta_get_nthreads td_ta_get_ph \
+                       td_ta_map_id2thr td_ta_map_lwp2thr \
+                       td_ta_thr_iter td_ta_tsd_iter \
+                       td_thr_get_info td_thr_getfpregs td_thr_getgregs \
+                       td_thr_getxregs td_thr_getxregsize td_thr_setfpregs \
+                       td_thr_setgregs td_thr_setprio td_thr_setsigpending \
+                       td_thr_setxregs td_thr_sigsetmask td_thr_tsd \
+                       td_thr_validate td_thr_dbsuspend td_thr_dbresume \
+                       td_ta_setconcurrency td_ta_enable_stats \
+                       td_ta_reset_stats td_ta_get_stats td_ta_event_addr \
+                       td_thr_event_enable td_thr_set_event \
+                       td_thr_clear_event td_thr_event_getmsg \
+                       td_ta_set_event td_ta_event_getmsg \
+                       td_ta_clear_event td_symbol_list td_thr_tls_get_addr
+
+
+
+libthread_db-inhibit-o = $(filter-out .os,$(object-suffixes))
+
+distribute = thread_dbP.h shlib-versions proc_service.h
+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.
+$(objpfx)libthread_db.so: $(common-objpfx)libc.so \
+                         $(common-objpfx)libc_nonshared.a
diff --git a/nptl_db/Versions b/nptl_db/Versions
new file mode 100644 (file)
index 0000000..4ca8042
--- /dev/null
@@ -0,0 +1,21 @@
+libthread_db {
+  GLIBC_2.1.3 {
+    # t*
+    td_init; td_log; td_ta_clear_event; td_ta_delete; td_ta_enable_stats;
+    td_ta_event_addr; td_ta_event_getmsg; td_ta_get_nthreads; td_ta_get_ph;
+    td_ta_get_stats; td_ta_map_id2thr; td_ta_map_lwp2thr; td_ta_new;
+    td_ta_reset_stats; td_ta_set_event; td_ta_setconcurrency;
+    td_ta_thr_iter; td_ta_tsd_iter; td_thr_clear_event; td_thr_dbresume;
+    td_thr_dbsuspend; td_thr_event_enable; td_thr_event_getmsg;
+    td_thr_get_info; td_thr_getfpregs; td_thr_getgregs; td_thr_getxregs;
+    td_thr_getxregsize; td_thr_set_event; td_thr_setfpregs; td_thr_setgregs;
+    td_thr_setprio; td_thr_setsigpending; td_thr_setxregs; td_thr_sigsetmask;
+    td_thr_tsd; td_thr_validate;
+  }
+  GLIBC_2.2.3 {
+    td_symbol_list;
+  }
+  GLIBC_2.3 {
+    td_thr_tls_get_addr;
+  }
+}
diff --git a/nptl_db/proc_service.h b/nptl_db/proc_service.h
new file mode 100644 (file)
index 0000000..9963c3a
--- /dev/null
@@ -0,0 +1,73 @@
+/* Copyright (C) 1999, 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.  */
+
+/* The definitions in this file must correspond to those in the debugger.  */
+#include <sys/procfs.h>
+
+typedef enum
+{
+  PS_OK,          /* generic "call succeeded" */
+  PS_ERR,         /* generic. */
+  PS_BADPID,      /* bad process handle */
+  PS_BADLID,      /* bad lwp identifier */
+  PS_BADADDR,     /* bad address */
+  PS_NOSYM,       /* p_lookup() could not find given symbol */
+        PS_NOFREGS
+  /*
+   * FPU register set not available for given
+   * lwp
+   */
+}       ps_err_e;
+
+
+struct ps_prochandle;          /* user defined. */
+
+
+extern ps_err_e ps_pdread(struct ps_prochandle *,
+                        psaddr_t, void *, size_t);
+extern ps_err_e ps_pdwrite(struct ps_prochandle *,
+                        psaddr_t, const void *, size_t);
+extern ps_err_e ps_ptread(struct ps_prochandle *,
+                        psaddr_t, void *, size_t);
+extern ps_err_e ps_ptwrite(struct ps_prochandle *,
+                        psaddr_t, const void *, size_t);
+
+extern ps_err_e ps_pglobal_lookup(struct ps_prochandle *,
+        const char *object_name, const char *sym_name, psaddr_t *sym_addr);
+
+
+extern ps_err_e ps_lgetregs(struct ps_prochandle *,
+                        lwpid_t, prgregset_t);
+extern ps_err_e ps_lsetregs(struct ps_prochandle *,
+                        lwpid_t, const prgregset_t);
+extern ps_err_e ps_lgetfpregs(struct ps_prochandle *,
+                        lwpid_t, prfpregset_t *);
+extern ps_err_e ps_lsetfpregs(struct ps_prochandle *,
+                        lwpid_t, const prfpregset_t *);
+
+extern pid_t ps_getpid (struct ps_prochandle *);
+
+
+extern ps_err_e ps_pstop (const struct ps_prochandle *);
+extern ps_err_e ps_pcontinue (const struct ps_prochandle *);
+
+extern ps_err_e ps_lstop (const struct ps_prochandle *, lwpid_t);
+extern ps_err_e ps_lcontinue (const struct ps_prochandle *, lwpid_t);
+
+extern ps_err_e ps_get_thread_area (const struct ps_prochandle *, lwpid_t,
+                                   int, psaddr_t *);
diff --git a/nptl_db/shlib-versions b/nptl_db/shlib-versions
new file mode 100644 (file)
index 0000000..592f7fa
--- /dev/null
@@ -0,0 +1,2 @@
+# The thread debug library
+.*-.*-linux.*          libthread_db=1
diff --git a/nptl_db/td_init.c b/nptl_db/td_init.c
new file mode 100644 (file)
index 0000000..946ff72
--- /dev/null
@@ -0,0 +1,32 @@
+/* Initialization function of thread debugger support library.
+   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+
+int __td_debug;
+
+
+td_err_e
+td_init (void)
+{
+  /* XXX We have to figure out what has to be done.  */
+  LOG ("td_init");
+  return TD_OK;
+}
diff --git a/nptl_db/td_log.c b/nptl_db/td_log.c
new file mode 100644 (file)
index 0000000..52212a0
--- /dev/null
@@ -0,0 +1,32 @@
+/* Noop, left for historical reasons.
+   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_log (void)
+{
+  /* This interface is deprecated in the Sun interface.  We provide it
+     for compatibility but don't do anything ourself.  We might in
+     future do some logging if this seems reasonable.  */
+  LOG ("td_log");
+  return TD_OK;
+}
diff --git a/nptl_db/td_symbol_list.c b/nptl_db/td_symbol_list.c
new file mode 100644 (file)
index 0000000..1be7001
--- /dev/null
@@ -0,0 +1,55 @@
+/* Return list of symbols the library can request.
+   Copyright (C) 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2001.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <assert.h>
+#include <gnu/lib-names.h>
+#include "thread_dbP.h"
+
+
+static const char *symbol_list_arr[] =
+{
+  [SYM_PTHREAD_THREADS_EVENTS] = "__nptl_threads_events",
+  [SYM_PTHREAD_LAST_EVENT] = "__nptl_last_event",
+  [SYM_PTHREAD_NTHREADS] = "nptl_nthreads",
+  [SYM_PTHREAD_STACK_USED] = "stack_used",
+  [SYM_PTHREAD_STACK_USER] = "__stack_user",
+  [SYM_PTHREAD_KEYS] = "pthread_keys",
+  [SYM_PTHREAD_KEYS_MAX] = "__pthread_pthread_keys_max",
+  [SYM_PTHREAD_SIZEOF_DESCR] = "__pthread_pthread_sizeof_descr",
+  [SYM_PTHREAD_CREATE_EVENT] = "__nptl_create_event",
+  [SYM_PTHREAD_DEATH_EVENT] = "__nptl_death_event",
+  [SYM_PTHREAD_VERSION] = "nptl_version",
+  [SYM_NUM_MESSAGES] = NULL
+};
+
+
+const char **
+td_symbol_list (void)
+{
+  return symbol_list_arr;
+}
+
+
+int
+td_lookup (struct ps_prochandle *ps, int idx, psaddr_t *sym_addr)
+{
+  assert (idx >= 0 && idx < SYM_NUM_MESSAGES);
+  return ps_pglobal_lookup (ps, LIBPTHREAD_SO, symbol_list_arr[idx], sym_addr);
+}
diff --git a/nptl_db/td_ta_clear_event.c b/nptl_db/td_ta_clear_event.c
new file mode 100644 (file)
index 0000000..611281f
--- /dev/null
@@ -0,0 +1,52 @@
+/* Globally disable events.
+   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_ta_clear_event (ta, event)
+     const td_thragent_t *ta;
+     td_thr_events_t *event;
+{
+  LOG ("td_ta_clear_event");
+
+  /* Test whether the TA parameter is ok.  */
+  if (! ta_ok (ta))
+    return TD_BADTA;
+
+  /* Write the new value into the thread data structure.  */
+  td_thr_events_t old_event;
+  if (ps_pdread (ta->ph, ta->pthread_threads_eventsp,
+                &old_event, sizeof (td_thrhandle_t)) != PS_OK)
+    return TD_ERR;     /* XXX Other error value?  */
+
+  /* Remove the set bits in.  */
+  int i;
+  for (i = 0; i < TD_EVENTSIZE; ++i)
+    old_event.event_bits[i] &= ~event->event_bits[i];
+
+  /* Write the new value into the thread data structure.  */
+  if (ps_pdwrite (ta->ph, ta->pthread_threads_eventsp,
+                 &old_event, sizeof (td_thrhandle_t)) != PS_OK)
+    return TD_ERR;     /* XXX Other error value?  */
+
+  return TD_OK;
+}
diff --git a/nptl_db/td_ta_delete.c b/nptl_db/td_ta_delete.c
new file mode 100644 (file)
index 0000000..57b90e5
--- /dev/null
@@ -0,0 +1,42 @@
+/* Detach to target process.
+   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stdlib.h>
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_ta_delete (td_thragent_t *ta)
+{
+  LOG ("td_ta_delete");
+
+  /* Safety check.  Note that the test will also fail for TA == NULL.  */
+  if (!ta_ok (ta))
+    return TD_BADTA;
+
+  /* Remove the handle from the list.  */
+  list_del (&ta->list);
+
+  /* The handle was allocated in `td_ta_new'.  */
+  free (ta);
+
+  return TD_OK;
+}
diff --git a/nptl_db/td_ta_enable_stats.c b/nptl_db/td_ta_enable_stats.c
new file mode 100644 (file)
index 0000000..ec7014a
--- /dev/null
@@ -0,0 +1,35 @@
+/* Enable collection of statistics for process.
+   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_ta_enable_stats (const td_thragent_t *ta, int enable)
+{
+  /* XXX We have to figure out what has to be done.  */
+  LOG ("td_ta_enable_stats");
+
+  /* Test whether the TA parameter is ok.  */
+  if (! ta_ok (ta))
+    return TD_BADTA;
+
+  return TD_OK;
+}
diff --git a/nptl_db/td_ta_event_addr.c b/nptl_db/td_ta_event_addr.c
new file mode 100644 (file)
index 0000000..906835d
--- /dev/null
@@ -0,0 +1,69 @@
+/* Get event address.
+   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_ta_event_addr (const td_thragent_t *ta, td_event_e event, td_notify_t *addr)
+{
+  td_err_e res = TD_NOEVENT;
+  int idx = -1;
+
+  LOG ("td_ta_event_addr");
+
+  /* Test whether the TA parameter is ok.  */
+  if (! ta_ok (ta))
+    return TD_BADTA;
+
+  switch (event)
+    {
+    case TD_CREATE:
+      idx = SYM_PTHREAD_CREATE_EVENT;
+      break;
+
+    case TD_DEATH:
+      idx = SYM_PTHREAD_DEATH_EVENT;
+      break;
+
+    default:
+      /* Event cannot be handled.  */
+      break;
+    }
+
+  /* Now get the address.  */
+  if (idx != -1)
+    {
+      psaddr_t taddr;
+
+      if (td_lookup (ta->ph, idx, &taddr) == PS_OK)
+       {
+         /* Success, we got the address.  */
+         addr->type = NOTIFY_BPT;
+         addr->u.bptaddr = taddr;
+
+         res = TD_OK;
+       }
+      else
+       res = TD_ERR;
+    }
+
+  return res;
+}
diff --git a/nptl_db/td_ta_event_getmsg.c b/nptl_db/td_ta_event_getmsg.c
new file mode 100644 (file)
index 0000000..4e3245d
--- /dev/null
@@ -0,0 +1,85 @@
+/* Retrieve event.
+   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stddef.h>
+#include <string.h>
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_ta_event_getmsg (const td_thragent_t *ta, td_event_msg_t *msg)
+{
+  /* XXX I cannot think of another way but using a static variable.  */
+  /* XXX Use at least __thread once it is possible.  */
+  static td_thrhandle_t th;
+
+  LOG ("td_ta_event_getmsg");
+
+  /* Test whether the TA parameter is ok.  */
+  if (! ta_ok (ta))
+    return TD_BADTA;
+
+  /* Get the pointer to the thread descriptor with the last event.  */
+  psaddr_t addr;
+  if (ps_pdread (ta->ph, ta->pthread_last_event,
+                &addr, sizeof (struct pthread *)) != PS_OK)
+    return TD_ERR;     /* XXX Other error value?  */
+
+  /* Read the even structure from the target.  */
+  if (addr == 0)
+    return TD_NOMSG;
+
+  /* Read the even structure from the target.  */
+  td_eventbuf_t event;
+  if (ps_pdread (ta->ph, (char *) addr + offsetof (struct pthread, eventbuf),
+                &event, sizeof (td_eventbuf_t)) != PS_OK)
+    return TD_ERR;     /* XXX Other error value?  */
+
+  /* If the structure is on the list there better be an event recorded.  */
+  assert (event.eventnum != TD_EVENT_NONE);
+
+  /* Generate the thread descriptor.  */
+  th.th_ta_p = (td_thragent_t *) ta;
+  th.th_unique = addr;
+
+  /* Fill the user's data structure.  */
+  msg->event = event.eventnum;
+  msg->th_p = &th;
+  msg->msg.data = (uintptr_t) event.eventdata;
+
+  /* Get the pointer to the next descriptor with an event.  */
+  psaddr_t next;
+  if (ps_pdread (ta->ph, (char *) addr + offsetof (struct pthread, nextevent),
+                &next, sizeof (struct pthread *)) != PS_OK)
+    return TD_ERR;     /* XXX Other error value?  */
+
+  /* Store the pointer in the list head variable.  */
+  if (ps_pdwrite (ta->ph, ta->pthread_last_event,
+                addr, sizeof (struct pthread *)) != PS_OK)
+    return TD_ERR;     /* XXX Other error value?  */
+
+  /* Clear the next pointer in the current descriptor.  */
+  if (ps_pdwrite (ta->ph, (char *) addr + offsetof (struct pthread, nextevent),
+                 NULL, sizeof (struct pthread *)) != PS_OK)
+    return TD_ERR;     /* XXX Other error value?  */
+
+  return TD_OK;
+}
diff --git a/nptl_db/td_ta_get_nthreads.c b/nptl_db/td_ta_get_nthreads.c
new file mode 100644 (file)
index 0000000..cfe93d1
--- /dev/null
@@ -0,0 +1,41 @@
+/* Get the number of threads in the process.
+   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+
+td_err_e
+td_ta_get_nthreads (const td_thragent_t *ta, int *np)
+{
+  LOG ("td_ta_get_nthreads");
+
+  /* Test whether the TA parameter is ok.  */
+  if (! ta_ok (ta))
+    return TD_BADTA;
+
+  /* Access the variable `__pthread_handles_num'.  */
+  psaddr_t addr;
+  if (td_lookup (ta->ph, SYM_PTHREAD_NTHREADS, &addr) != PS_OK)
+     return TD_ERR;    /* XXX Other error value?  */
+
+  if (ps_pdread (ta->ph, addr, np, sizeof (int)) != PS_OK)
+     return TD_ERR;    /* XXX Other error value?  */
+
+  return TD_OK;
+}
diff --git a/nptl_db/td_ta_get_ph.c b/nptl_db/td_ta_get_ph.c
new file mode 100644 (file)
index 0000000..04e01fb
--- /dev/null
@@ -0,0 +1,36 @@
+/* Get external process handle.
+   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_ta_get_ph (const td_thragent_t *ta, struct ps_prochandle **ph)
+{
+  LOG ("td_ta_get_ph");
+
+  /* Test whether the TA parameter is ok.  */
+  if (! ta_ok (ta))
+    return TD_BADTA;
+
+  *ph = ta->ph;
+
+  return TD_OK;
+}
diff --git a/nptl_db/td_ta_get_stats.c b/nptl_db/td_ta_get_stats.c
new file mode 100644 (file)
index 0000000..d5d879c
--- /dev/null
@@ -0,0 +1,35 @@
+/* Retrieve statistics for process.
+   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_ta_get_stats (const td_thragent_t *ta, td_ta_stats_t *statsp)
+{
+  /* XXX We have to figure out what has to be done.  */
+  LOG ("td_ta_get_stats");
+
+  /* Test whether the TA parameter is ok.  */
+  if (! ta_ok (ta))
+    return TD_BADTA;
+
+  return TD_OK;
+}
diff --git a/nptl_db/td_ta_map_id2thr.c b/nptl_db/td_ta_map_id2thr.c
new file mode 100644 (file)
index 0000000..189a671
--- /dev/null
@@ -0,0 +1,38 @@
+/* Map thread ID to thread handle.
+   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_ta_map_id2thr (const td_thragent_t *ta, pthread_t pt, td_thrhandle_t *th)
+{
+  LOG ("td_ta_map_id2thr");
+
+  /* Test whether the TA parameter is ok.  */
+  if (! ta_ok (ta))
+    return TD_BADTA;
+
+  /* Create the `td_thrhandle_t' object.  */
+  th->th_ta_p = (td_thragent_t *) ta;
+  th->th_unique = (psaddr_t) pt;
+
+  return TD_OK;
+}
diff --git a/nptl_db/td_ta_map_lwp2thr.c b/nptl_db/td_ta_map_lwp2thr.c
new file mode 100644 (file)
index 0000000..326b9ee
--- /dev/null
@@ -0,0 +1,43 @@
+/* Which thread is running on an lwp?
+   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+#include <tls.h>
+
+
+td_err_e
+td_ta_map_lwp2thr (const td_thragent_t *ta, lwpid_t lwpid, td_thrhandle_t *th)
+{
+  LOG ("td_ta_map_lwp2thr");
+
+  /* Test whether the TA parameter is ok.  */
+  if (! ta_ok (ta))
+    return TD_BADTA;
+
+  /* Get the thread area for the addressed thread.  */
+  if (ps_get_thread_area (ta->ph, lwpid, TLS_GET_GS () >> 3, &th->th_unique)
+      != PS_OK)
+    return TD_ERR;     /* XXX Other error value?  */
+
+  /* Found it.  Now complete the `td_thrhandle_t' object.  */
+  th->th_ta_p = (td_thragent_t *) ta;
+
+  return TD_OK;
+}
diff --git a/nptl_db/td_ta_new.c b/nptl_db/td_ta_new.c
new file mode 100644 (file)
index 0000000..de564ed
--- /dev/null
@@ -0,0 +1,115 @@
+/* Attach to target process.
+   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <version.h>
+
+#include "thread_dbP.h"
+
+
+/* Datatype for the list of known thread agents.  Normally there will
+   be exactly one so we don't spend much though on making it fast.  */
+LIST_HEAD (__td_agent_list);
+
+
+td_err_e
+td_ta_new (struct ps_prochandle *ps, td_thragent_t **ta)
+{
+  psaddr_t addr;
+  psaddr_t versaddr;
+  char versbuf[sizeof (VERSION)];
+
+  LOG ("td_ta_new");
+
+  /* Get the global event mask.  This is one of the variables which
+     are new in the thread library to enable debugging.  If it is
+     not available we cannot debug.  */
+  if (td_lookup (ps, SYM_PTHREAD_THREADS_EVENTS, &addr) != PS_OK)
+    return TD_NOLIBTHREAD;
+
+  /* Check whether the versions match.  */
+  if (td_lookup (ps, SYM_PTHREAD_VERSION, &versaddr) != PS_OK)
+    return TD_VERSION;
+  if (ps_pdread (ps, versaddr, versbuf, sizeof (versbuf)) != PS_OK)
+    return TD_ERR;
+
+  if (versbuf[sizeof (versbuf) - 1] != '\0' || strcmp (versbuf, VERSION) != 0)
+    /* Not the right version.  */
+    return TD_VERSION;
+
+  /* Fill in the appropriate information.  */
+  *ta = (td_thragent_t *) malloc (sizeof (td_thragent_t));
+  if (*ta == NULL)
+    return TD_MALLOC;
+
+  /* Store the proc handle which we will pass to the callback functions
+     back into the debugger.  */
+  (*ta)->ph = ps;
+
+  /* Remember the address.  */
+  (*ta)->pthread_threads_eventsp = (td_thr_events_t *) addr;
+
+  /* Get the pointer to the variable pointing to the thread descriptor
+     with the last event.  */
+  if (td_lookup (ps, SYM_PTHREAD_LAST_EVENT, &(*ta)->pthread_last_event)
+      != PS_OK)
+    {
+    free_return:
+      free (*ta);
+      return TD_ERR;
+    }
+
+
+  if (td_lookup (ps, SYM_PTHREAD_STACK_USER, &addr) != PS_OK)
+    goto free_return;
+  /* Cast to the right type.  */
+  (*ta)->stack_user = (list_t *) addr;
+
+  if (td_lookup (ps, SYM_PTHREAD_STACK_USED, &addr) != PS_OK)
+    goto free_return;
+  /* Cast to the right type.  */
+  (*ta)->stack_used = (list_t *) addr;
+
+
+  if (td_lookup (ps, SYM_PTHREAD_KEYS, &addr) != PS_OK)
+    goto free_return;
+  /* Cast to the right type.  */
+  (*ta)->keys = (struct pthread_key_struct *) addr;
+
+
+  /* Similarly for the maximum number of thread local data keys.  */
+  if (td_lookup (ps, SYM_PTHREAD_KEYS_MAX, &addr) != PS_OK
+      || ps_pdread (ps, addr, &(*ta)->pthread_keys_max, sizeof (int)) != PS_OK)
+    goto free_return;
+
+
+  /* And for the size of the second level arrays for the keys.  */
+  if (td_lookup (ps, SYM_PTHREAD_SIZEOF_DESCR, &addr) != PS_OK
+      || ps_pdread (ps, addr, &(*ta)->sizeof_descr, sizeof (int)) != PS_OK)
+    goto free_return;
+
+
+  /* Now add the new agent descriptor to the list.  */
+  list_add (&(*ta)->list, &__td_agent_list);
+
+  return TD_OK;
+}
diff --git a/nptl_db/td_ta_reset_stats.c b/nptl_db/td_ta_reset_stats.c
new file mode 100644 (file)
index 0000000..ea59d2c
--- /dev/null
@@ -0,0 +1,35 @@
+/* Reset statistics.
+   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_ta_reset_stats (const td_thragent_t *ta)
+{
+  /* XXX We have to figure out what has to be done.  */
+  LOG ("td_ta_reset_stats");
+
+  /* Test whether the TA parameter is ok.  */
+  if (! ta_ok (ta))
+    return TD_BADTA;
+
+  return TD_OK;
+}
diff --git a/nptl_db/td_ta_set_event.c b/nptl_db/td_ta_set_event.c
new file mode 100644 (file)
index 0000000..5e2cca7
--- /dev/null
@@ -0,0 +1,52 @@
+/* Globally enable events.
+   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_ta_set_event (ta, event)
+     const td_thragent_t *ta;
+     td_thr_events_t *event;
+{
+  LOG ("td_ta_set_event");
+
+  /* Test whether the TA parameter is ok.  */
+  if (! ta_ok (ta))
+    return TD_BADTA;
+
+  /* Write the new value into the thread data structure.  */
+  td_thr_events_t old_event;
+  if (ps_pdread (ta->ph, ta->pthread_threads_eventsp,
+                &old_event, sizeof (td_thrhandle_t)) != PS_OK)
+    return TD_ERR;     /* XXX Other error value?  */
+
+  /* Or the new bits in.  */
+  int i;
+  for (i = 0; i < TD_EVENTSIZE; ++i)
+    old_event.event_bits[i] |= event->event_bits[i];
+
+  /* Write the new value into the thread data structure.  */
+  if (ps_pdwrite (ta->ph, ta->pthread_threads_eventsp,
+                 &old_event, sizeof (td_thrhandle_t)) != PS_OK)
+    return TD_ERR;     /* XXX Other error value?  */
+
+  return TD_OK;
+}
diff --git a/nptl_db/td_ta_setconcurrency.c b/nptl_db/td_ta_setconcurrency.c
new file mode 100644 (file)
index 0000000..8552ffb
--- /dev/null
@@ -0,0 +1,35 @@
+/* Set suggested concurrency level for process.
+   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_ta_setconcurrency (const td_thragent_t *ta, int level)
+{
+  /* This is something LinuxThreads does not need to support.  */
+  LOG ("td_ta_setconcurrency");
+
+  /* Test whether the TA parameter is ok.  */
+  if (! ta_ok (ta))
+    return TD_BADTA;
+
+  return TD_NOCAPAB;
+}
diff --git a/nptl_db/td_ta_thr_iter.c b/nptl_db/td_ta_thr_iter.c
new file mode 100644 (file)
index 0000000..ca1c82d
--- /dev/null
@@ -0,0 +1,125 @@
+/* Iterate over a process's threads.
+   Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+#include <nptl/descr.h>
+
+
+static td_err_e
+iterate_thread_list (const td_thragent_t *ta, td_thr_iter_f *callback,
+                    void *cbdata_p, td_thr_state_e state, int ti_pri,
+                    psaddr_t head)
+{
+  list_t list;
+  td_err_e result = TD_OK;
+
+  /* Test the state.
+     XXX This is incomplete.  Normally this test should be in the loop.  */
+  if (state != TD_THR_ANY_STATE)
+    return TD_OK;
+
+  if (ps_pdread (ta->ph, head, &list, sizeof (list_t)) != PS_OK)
+    return TD_ERR;     /* XXX Other error value?  */
+
+  while (list.next != head)
+    {
+      psaddr_t addr = ((psaddr_t) list.next
+                      - offsetof (struct pthread, header.data.list));
+
+      int schedpolicy;
+      if (ps_pdread (ta->ph, &((struct pthread *) addr)->schedpolicy,
+                    &schedpolicy, sizeof (int)) != PS_OK)
+       {
+         result = TD_ERR;      /* XXX Other error value?  */
+         break;
+       }
+
+      struct sched_param schedparam;
+      if (ps_pdread (ta->ph, &((struct pthread *) addr)->schedparam,
+                    &schedparam, sizeof (struct sched_param)) != PS_OK)
+       {
+         result = TD_ERR;      /* XXX Other error value?  */
+         break;
+       }
+
+      /* Now test whether this thread matches the specified
+        conditions.  */
+
+      /* Only if the priority level is as high or higher.  */
+      int descr_pri = (schedpolicy == SCHED_OTHER
+                      ? 0 : schedparam.sched_priority);
+      if (descr_pri >= ti_pri)
+       {
+         /* XXX For now we ignore threads which are not running anymore.
+            The reason is that gdb tries to get the registers and fails.
+            In future we should have a special mode of the thread library
+            in which we keep the process around until the actual join
+            operation happened.  */
+         int cancelhandling;
+         if (ps_pdread (ta->ph, &((struct pthread *) addr)->cancelhandling,
+                        &cancelhandling, sizeof (int)) != PS_OK)
+           {
+             result = TD_ERR;  /* XXX Other error value?  */
+             break;
+           }
+
+         if ((cancelhandling & TERMINATED_BIT) == 0)
+           {
+             /* Yep, it matches.  Call the callback function.  */
+             td_thrhandle_t th;
+             th.th_ta_p = (td_thragent_t *) ta;
+             th.th_unique = addr;
+             if (callback (&th, cbdata_p) != 0)
+               return TD_DBERR;
+           }
+       }
+    }
+
+  return result;
+}
+
+
+td_err_e
+td_ta_thr_iter (const td_thragent_t *ta, td_thr_iter_f *callback,
+               void *cbdata_p, td_thr_state_e state, int ti_pri,
+               sigset_t *ti_sigmask_p, unsigned int ti_user_flags)
+{
+  LOG ("td_ta_thr_iter");
+
+  /* Test whether the TA parameter is ok.  */
+  if (! ta_ok (ta))
+    return TD_BADTA;
+
+  /* The thread library keeps two lists for the running threads.  One
+     list contains the thread which are using user-provided stacks
+     (this includes the main thread) and the other includes the
+     threads for which the thread library allocated the stacks.  We
+     have to iterate over both lists separately.  We start with the
+     list of threads with user-defined stacks.  */
+  td_err_e result = iterate_thread_list (ta, callback, cbdata_p, state, ti_pri,
+                                        ta->stack_user);
+
+  /* And the threads with stacks allocated by the implementation.  */
+  if (result == TD_OK)
+    result = iterate_thread_list (ta, callback, cbdata_p, state, ti_pri,
+                                 ta->stack_used);
+
+  return result;
+}
diff --git a/nptl_db/td_ta_tsd_iter.c b/nptl_db/td_ta_tsd_iter.c
new file mode 100644 (file)
index 0000000..cbc2f37
--- /dev/null
@@ -0,0 +1,53 @@
+/* Iterate over a process's thread-specific data.
+   Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+#include <alloca.h>
+
+td_err_e
+td_ta_tsd_iter (const td_thragent_t *ta, td_key_iter_f *callback,
+               void *cbdata_p)
+{
+  LOG ("td_ta_tsd_iter");
+
+  /* Test whether the TA parameter is ok.  */
+  if (! ta_ok (ta))
+    return TD_BADTA;
+
+  int pthread_keys_max = ta->pthread_keys_max;
+  struct pthread_key_struct *keys;
+  keys = (struct pthread_key_struct *) alloca (sizeof (keys[0])
+                                              * pthread_keys_max);
+
+  /* Read all the information about the keys.  */
+  if (ps_pdread (ta->ph, ta->keys, keys,
+                sizeof (keys[0]) * pthread_keys_max) != PS_OK)
+       return TD_ERR;  /* XXX Other error value?  */
+
+  /* Now get all descriptors, one after the other.  */
+  int cnt;
+  for (cnt = 0; cnt < pthread_keys_max; ++cnt)
+    if (!KEY_UNUSED (keys[cnt].seq)
+       /* Return with an error if the callback returns a nonzero value.  */
+       && callback (cnt, keys[cnt].destr, cbdata_p) != 0)
+      return TD_DBERR;
+
+  return TD_OK;
+}
diff --git a/nptl_db/td_thr_clear_event.c b/nptl_db/td_thr_clear_event.c
new file mode 100644 (file)
index 0000000..e729b52
--- /dev/null
@@ -0,0 +1,54 @@
+/* Disable specific event for thread.
+   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stddef.h>
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_thr_clear_event (th, event)
+     const td_thrhandle_t *th;
+     td_thr_events_t *event;
+{
+  LOG ("td_thr_clear_event");
+
+  /* Write the new value into the thread data structure.  */
+  td_thr_events_t old_event;
+  if (ps_pdread (th->th_ta_p->ph,
+                ((char *) th->th_unique
+                 + offsetof (struct pthread, eventbuf.eventmask)),
+                &old_event, sizeof (td_thrhandle_t)) != PS_OK)
+    return TD_ERR;     /* XXX Other error value?  */
+
+  /* Remove the set bits in.  */
+  int i;
+  for (i = 0; i < TD_EVENTSIZE; ++i)
+    old_event.event_bits[i] &= ~event->event_bits[i];
+
+  /* Write the new value into the thread data structure.  */
+  if (ps_pdwrite (th->th_ta_p->ph,
+                 ((char *) th->th_unique
+                  + offsetof (struct pthread, eventbuf.eventmask)),
+                 &old_event, sizeof (td_thrhandle_t)) != PS_OK)
+    return TD_ERR;     /* XXX Other error value?  */
+
+  return TD_OK;
+}
diff --git a/nptl_db/td_thr_dbresume.c b/nptl_db/td_thr_dbresume.c
new file mode 100644 (file)
index 0000000..3fd7943
--- /dev/null
@@ -0,0 +1,30 @@
+/* Resume execution of given thread.
+   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_thr_dbresume (const td_thrhandle_t *th)
+{
+  /* XXX We have to figure out what has to be done.  */
+  LOG ("td_thr_dbresume");
+  return TD_NOCAPAB;
+}
diff --git a/nptl_db/td_thr_dbsuspend.c b/nptl_db/td_thr_dbsuspend.c
new file mode 100644 (file)
index 0000000..6ef82ad
--- /dev/null
@@ -0,0 +1,30 @@
+/* Suspend execution of given thread.
+   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_thr_dbsuspend (const td_thrhandle_t *th)
+{
+  /* XXX We have to figure out what has to be done.  */
+  LOG ("td_thr_dbsuspend");
+  return TD_NOCAPAB;
+}
diff --git a/nptl_db/td_thr_event_enable.c b/nptl_db/td_thr_event_enable.c
new file mode 100644 (file)
index 0000000..e822453
--- /dev/null
@@ -0,0 +1,41 @@
+/* Enable event process-wide.
+   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stddef.h>
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_thr_event_enable (th, onoff)
+     const td_thrhandle_t *th;
+     int onoff;
+{
+  LOG ("td_thr_event_enable");
+
+  /* Write the new value into the thread data structure.  */
+  if (ps_pdwrite (th->th_ta_p->ph,
+                 ((char *) th->th_unique
+                  + offsetof (struct pthread, report_events)),
+                 &onoff, sizeof (int)) != PS_OK)
+    return TD_ERR;     /* XXX Other error value?  */
+
+  return TD_OK;
+}
diff --git a/nptl_db/td_thr_event_getmsg.c b/nptl_db/td_thr_event_getmsg.c
new file mode 100644 (file)
index 0000000..ffd0baa
--- /dev/null
@@ -0,0 +1,60 @@
+/* Retrieve event.
+   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stddef.h>
+#include <string.h>
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_thr_event_getmsg (const td_thrhandle_t *th, td_event_msg_t *msg)
+{
+  td_eventbuf_t event;
+
+  LOG ("td_thr_event_getmsg");
+
+  /* Read the even structure from the target.  */
+  if (ps_pdread (th->th_ta_p->ph,
+                ((char *) th->th_unique
+                 + offsetof (struct pthread, eventbuf)),
+                &event, sizeof (td_eventbuf_t)) != PS_OK)
+    return TD_ERR;     /* XXX Other error value?  */
+
+  /* Check whether an event occurred.  */
+  if (event.eventnum == TD_EVENT_NONE)
+    /* Nothing.  */
+    return TD_NOMSG;
+
+  /* Fill the user's data structure.  */
+  msg->event = event.eventnum;
+  msg->th_p = th;
+  msg->msg.data = (uintptr_t) event.eventdata;
+
+  /* And clear the event message in the target.  */
+  memset (&event, '\0', sizeof (td_eventbuf_t));
+  if (ps_pdwrite (th->th_ta_p->ph,
+                 ((char *) th->th_unique
+                  + offsetof (struct pthread, eventbuf)),
+                 &event, sizeof (td_eventbuf_t)) != PS_OK)
+    return TD_ERR;     /* XXX Other error value?  */
+
+  return TD_OK;
+}
diff --git a/nptl_db/td_thr_get_info.c b/nptl_db/td_thr_get_info.c
new file mode 100644 (file)
index 0000000..0686649
--- /dev/null
@@ -0,0 +1,64 @@
+/* Get thread information.
+   Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stddef.h>
+#include <string.h>
+#include "thread_dbP.h"
+
+
+td_err_e
+td_thr_get_info (const td_thrhandle_t *th, td_thrinfo_t *infop)
+{
+  LOG ("td_thr_get_info");
+
+  /* Get the thread descriptor.  */
+  struct pthread pds;
+  if (ps_pdread (th->th_ta_p->ph, th->th_unique, &pds,
+                sizeof (struct pthread)) != PS_OK)
+    return TD_ERR;     /* XXX Other error value?  */
+
+  /* Fill in information.  Clear first to provide reproducable
+     results for the fields we do not fill in.  */
+  memset (infop, '\0', sizeof (td_thrinfo_t));
+
+  infop->ti_tid = pds.tid;
+  infop->ti_tls = (char *) pds.specific;
+  infop->ti_pri = (pds.schedpolicy == SCHED_OTHER
+                  ? 0 : pds.schedparam.sched_priority);
+  infop->ti_type = TD_THR_USER;
+
+  if ((pds.cancelhandling & EXITING_BIT) == 0)
+    /* XXX For now there is no way to get more information.  */
+    infop->ti_state = TD_THR_ACTIVE;
+  else if ((pds.cancelhandling & TERMINATED_BIT) == 0)
+    infop->ti_state = TD_THR_ZOMBIE;
+  else
+    infop->ti_state = TD_THR_UNKNOWN;
+
+  /* Initialization which are the same in both cases.  */
+  infop->ti_lid = ps_getpid (th->th_ta_p->ph);
+  infop->ti_ta_p = th->th_ta_p;
+  infop->ti_startfunc = pds.start_routine;
+  memcpy (&infop->ti_events, &pds.eventbuf.eventmask,
+         sizeof (td_thr_events_t));
+  infop->ti_traceme = pds.report_events != false;
+
+  return TD_OK;
+}
diff --git a/nptl_db/td_thr_getfpregs.c b/nptl_db/td_thr_getfpregs.c
new file mode 100644 (file)
index 0000000..360e1d2
--- /dev/null
@@ -0,0 +1,52 @@
+/* Get a thread's floating-point register set.
+   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_thr_getfpregs (const td_thrhandle_t *th, prfpregset_t *regset)
+{
+  LOG ("td_thr_getfpregs");
+
+  /* We have to get the state and the PID for this thread.  */
+  int cancelhandling;
+  if (ps_pdread (th->th_ta_p->ph,
+                &((struct pthread *) th->th_unique)->cancelhandling,
+                &cancelhandling, sizeof (int)) != PS_OK)
+    return TD_ERR;
+
+  /* If the thread already terminated we return all zeroes.  */
+  if (cancelhandling & TERMINATED_BIT)
+    memset (regset, '\0', sizeof (*regset));
+  /* Otherwise get the register content through the callback.  */
+  else
+    {
+      pid_t tid;
+
+      if (ps_pdread (th->th_ta_p->ph,
+                    &((struct pthread *) th->th_unique)->tid,
+                    &tid, sizeof (pid_t)) != PS_OK
+         || ps_lgetfpregs (th->th_ta_p->ph, tid, regset) != PS_OK)
+       return TD_ERR;
+    }
+
+  return TD_OK;
+}
diff --git a/nptl_db/td_thr_getgregs.c b/nptl_db/td_thr_getgregs.c
new file mode 100644 (file)
index 0000000..2485e5d
--- /dev/null
@@ -0,0 +1,52 @@
+/* Get a thread's general register set.
+   Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_thr_getgregs (const td_thrhandle_t *th, prgregset_t gregs)
+{
+  LOG ("td_thr_getgregs");
+
+  /* We have to get the state and the PID for this thread.  */
+  int cancelhandling;
+  if (ps_pdread (th->th_ta_p->ph,
+                &((struct pthread *) th->th_unique)->cancelhandling,
+                &cancelhandling, sizeof (int)) != PS_OK)
+    return TD_ERR;
+
+  /* If the thread already terminated we return all zeroes.  */
+  if (cancelhandling & TERMINATED_BIT)
+    memset (gregs, '\0', sizeof (prgregset_t));
+  /* Otherwise get the register content through the callback.  */
+  else
+    {
+      pid_t tid;
+
+      if (ps_pdread (th->th_ta_p->ph,
+                    &((struct pthread *) th->th_unique)->tid,
+                    &tid, sizeof (pid_t)) != PS_OK
+         || ps_lgetregs (th->th_ta_p->ph, tid, gregs) != PS_OK)
+       return TD_ERR;
+    }
+
+  return TD_OK;
+}
diff --git a/nptl_db/td_thr_getxregs.c b/nptl_db/td_thr_getxregs.c
new file mode 100644 (file)
index 0000000..3c77ab6
--- /dev/null
@@ -0,0 +1,30 @@
+/* Get a thread's extra state register set.
+   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_thr_getxregs (const td_thrhandle_t *th, void *xregs)
+{
+  /* XXX This might be platform specific.  */
+  LOG ("td_thr_getxregs");
+  return TD_NOXREGS;
+}
diff --git a/nptl_db/td_thr_getxregsize.c b/nptl_db/td_thr_getxregsize.c
new file mode 100644 (file)
index 0000000..1704e4b
--- /dev/null
@@ -0,0 +1,30 @@
+/* Get the size of the extra state register set for this architecture.
+   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_thr_getxregsize (const td_thrhandle_t *th, int *sizep)
+{
+  /* XXX This might be platform specific.  */
+  LOG ("td_thr_getxregsize");
+  return TD_NOXREGS;
+}
diff --git a/nptl_db/td_thr_set_event.c b/nptl_db/td_thr_set_event.c
new file mode 100644 (file)
index 0000000..656728c
--- /dev/null
@@ -0,0 +1,54 @@
+/* Enable specific event for thread.
+   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stddef.h>
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_thr_set_event (th, event)
+     const td_thrhandle_t *th;
+     td_thr_events_t *event;
+{
+  LOG ("td_thr_set_event");
+
+  /* Write the new value into the thread data structure.  */
+  td_thr_events_t old_event;
+  if (ps_pdread (th->th_ta_p->ph,
+                ((char *) th->th_unique
+                 + offsetof (struct pthread, eventbuf.eventmask)),
+                &old_event, sizeof (td_thrhandle_t)) != PS_OK)
+    return TD_ERR;     /* XXX Other error value?  */
+
+  /* Or the new bits in.  */
+  int i;
+  for (i = 0; i < TD_EVENTSIZE; ++i)
+    old_event.event_bits[i] |= event->event_bits[i];
+
+  /* Write the new value into the thread data structure.  */
+  if (ps_pdwrite (th->th_ta_p->ph,
+                 ((char *) th->th_unique
+                  + offsetof (struct pthread, eventbuf.eventmask)),
+                 &old_event, sizeof (td_thrhandle_t)) != PS_OK)
+    return TD_ERR;     /* XXX Other error value?  */
+
+  return TD_OK;
+}
diff --git a/nptl_db/td_thr_setfpregs.c b/nptl_db/td_thr_setfpregs.c
new file mode 100644 (file)
index 0000000..e1ec9be
--- /dev/null
@@ -0,0 +1,49 @@
+/* Set a thread's floating-point register set.
+   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_thr_setfpregs (const td_thrhandle_t *th, const prfpregset_t *fpregs)
+{
+  LOG ("td_thr_setfpregs");
+
+  /* We have to get the state and the PID for this thread.  */
+  int cancelhandling;
+  if (ps_pdread (th->th_ta_p->ph,
+                &((struct pthread *) th->th_unique)->cancelhandling,
+                &cancelhandling, sizeof (int)) != PS_OK)
+    return TD_ERR;
+
+  /* Only set the registers if the thread hasn't yet terminated.  */
+  if ((cancelhandling & TERMINATED_BIT) == 0)
+    {
+      pid_t tid;
+
+      if (ps_pdread (th->th_ta_p->ph,
+                    &((struct pthread *) th->th_unique)->tid,
+                    &tid, sizeof (pid_t)) != PS_OK
+         || ps_lsetfpregs (th->th_ta_p->ph, tid, fpregs) != PS_OK)
+       return TD_ERR;
+    }
+
+  return TD_OK;
+}
diff --git a/nptl_db/td_thr_setgregs.c b/nptl_db/td_thr_setgregs.c
new file mode 100644 (file)
index 0000000..d46e32a
--- /dev/null
@@ -0,0 +1,49 @@
+/* Set a thread's general register set.
+   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_thr_setgregs (const td_thrhandle_t *th, prgregset_t gregs)
+{
+  LOG ("td_thr_setgregs");
+
+  /* We have to get the state and the PID for this thread.  */
+  int cancelhandling;
+  if (ps_pdread (th->th_ta_p->ph,
+                &((struct pthread *) th->th_unique)->cancelhandling,
+                &cancelhandling, sizeof (int)) != PS_OK)
+    return TD_ERR;
+
+  /* Only set the registers if the thread hasn't yet terminated.  */
+  if ((cancelhandling & TERMINATED_BIT) == 0)
+    {
+      pid_t tid;
+
+      if (ps_pdread (th->th_ta_p->ph,
+                    &((struct pthread *) th->th_unique)->tid,
+                    &tid, sizeof (pid_t)) != PS_OK
+         || ps_lsetregs (th->th_ta_p->ph, tid, gregs) != PS_OK)
+       return TD_ERR;
+    }
+
+  return TD_OK;
+}
diff --git a/nptl_db/td_thr_setprio.c b/nptl_db/td_thr_setprio.c
new file mode 100644 (file)
index 0000000..6032b0e
--- /dev/null
@@ -0,0 +1,30 @@
+/* Set a thread's priority.
+   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_thr_setprio (const td_thrhandle_t *th, int prio)
+{
+  /* XXX We have to figure out what has to be done.  */
+  LOG ("td_thr_setprio");
+  return TD_OK;
+}
diff --git a/nptl_db/td_thr_setsigpending.c b/nptl_db/td_thr_setsigpending.c
new file mode 100644 (file)
index 0000000..e2c9d7a
--- /dev/null
@@ -0,0 +1,31 @@
+/* Raise a signal for a thread.
+   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_thr_setsigpending (const td_thrhandle_t *th, unsigned char n,
+                     const sigset_t *ss)
+{
+  /* XXX We have to figure out what has to be done.  */
+  LOG ("td_thr_setsigpending");
+  return TD_OK;
+}
diff --git a/nptl_db/td_thr_setxregs.c b/nptl_db/td_thr_setxregs.c
new file mode 100644 (file)
index 0000000..f48877c
--- /dev/null
@@ -0,0 +1,30 @@
+/* Set a thread's extra state register set.
+   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_thr_setxregs (const td_thrhandle_t *ta, const void *addr)
+{
+  /* XXX This might have to be platform specific.  */
+  LOG ("td_thr_setxregs");
+  return TD_NOXREGS;
+}
diff --git a/nptl_db/td_thr_sigsetmask.c b/nptl_db/td_thr_sigsetmask.c
new file mode 100644 (file)
index 0000000..3a68aec
--- /dev/null
@@ -0,0 +1,30 @@
+/* Set a thread's signal mask.
+   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_thr_sigsetmask (const td_thrhandle_t *th, const sigset_t *ss)
+{
+  /* XXX We have to figure out what has to be done.  */
+  LOG ("td_thr_sigsetmask");
+  return TD_OK;
+}
diff --git a/nptl_db/td_thr_tls_get_addr.c b/nptl_db/td_thr_tls_get_addr.c
new file mode 100644 (file)
index 0000000..5bbdc50
--- /dev/null
@@ -0,0 +1,70 @@
+/* Get address of thread local variable.
+   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 "link.h"
+#include "thread_dbP.h"
+
+/* Value used for dtv entries for which the allocation is delayed.  */
+# define TLS_DTV_UNALLOCATED   ((void *) -1l)
+
+
+td_err_e
+td_thr_tls_get_addr (const td_thrhandle_t *th __attribute__ ((unused)),
+                    void *map_address __attribute__ ((unused)),
+                    size_t offset __attribute__ ((unused)),
+                    void **address __attribute__ ((unused)))
+{
+#if USE_TLS
+  size_t modid;
+  union dtv pdtv, *dtvp;
+
+  LOG ("td_thr_tls_get_addr");
+
+  /* Get the DTV pointer from the thread descriptor.  */
+  if (ps_pdread (th->th_ta_p->ph,
+                &((struct pthread *) th->th_unique)->header.data.dtvp,
+                &dtvp, sizeof dtvp) != PS_OK)
+    return TD_ERR;     /* XXX Other error value?  */
+
+  /* Read the module ID from the link_map.  */
+  if (ps_pdread (th->th_ta_p->ph,
+                &((struct link_map *) map_address)->l_tls_modid,
+                &modid, sizeof modid) != PS_OK)
+    return TD_ERR;     /* XXX Other error value?  */
+
+  /* Get the corresponding entry in the DTV.  */
+  if (ps_pdread (th->th_ta_p->ph, dtvp + modid,
+                &pdtv, sizeof (union dtv)) != PS_OK)
+    return TD_ERR;     /* XXX Other error value?  */
+
+  /* It could be that the memory for this module is not allocated for
+     the given thread.  */
+  if (pdtv.pointer == TLS_DTV_UNALLOCATED)
+    /* There is not much we can do.  */
+    return TD_NOTALLOC;
+
+  *address = (char *) pdtv.pointer + offset;
+
+  return TD_OK;
+#else
+  return TD_ERR;
+#endif
+}
diff --git a/nptl_db/td_thr_tsd.c b/nptl_db/td_thr_tsd.c
new file mode 100644 (file)
index 0000000..d1a5453
--- /dev/null
@@ -0,0 +1,71 @@
+/* Get a thread-specific data pointer for a thread.
+   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_thr_tsd (const td_thrhandle_t *th, const thread_key_t tk, void **data)
+{
+  LOG ("td_thr_tsd");
+
+  /* Check correct value of key.  */
+  if (tk >= th->th_ta_p->pthread_keys_max)
+    return TD_BADKEY;
+
+  /* Get the key entry.  */
+  uintptr_t seq;
+  if (ps_pdread (th->th_ta_p->ph, &th->th_ta_p->keys[tk].seq, &seq,
+                sizeof (uintptr_t)) != PS_OK)
+    return TD_ERR;     /* XXX Other error value?  */
+
+  /* Fail if this key is not at all used.  */
+  if (KEY_UNUSED (seq))
+    return TD_BADKEY;
+
+  /* Compute the indeces.  */
+  int pthread_key_2ndlevel_size = th->th_ta_p->pthread_key_2ndlevel_size;
+  unsigned int idx1st = tk / pthread_key_2ndlevel_size;
+  unsigned int idx2nd = tk % pthread_key_2ndlevel_size;
+
+  struct pthread_key_data *level1;
+  if (ps_pdread (th->th_ta_p->ph,
+                &((struct pthread *) th->th_unique)->specific[idx1st],
+                &level1, sizeof (level1)) != PS_OK)
+    return TD_ERR;     /* XXX Other error value?  */
+
+  /* Check the pointer to the second level array.  */
+  if (level1 == NULL)
+    return TD_NOTSD;
+
+  struct pthread_key_data level2;
+  if (ps_pdread (th->th_ta_p->ph, &level1[idx2nd], &level2,
+                sizeof (level2)) != PS_OK)
+    return TD_ERR;     /* XXX Other error value?  */
+
+  /* Check whether the data is valid.  */
+  if (level2.seq != seq)
+    return TD_NOTSD;
+
+  if (level2.data != NULL)
+    *data = level2.data;
+
+  return TD_OK;
+}
diff --git a/nptl_db/td_thr_validate.c b/nptl_db/td_thr_validate.c
new file mode 100644 (file)
index 0000000..76cbad3
--- /dev/null
@@ -0,0 +1,66 @@
+/* Validate a thread handle.
+   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+
+
+static td_err_e
+check_thread_list (const td_thrhandle_t *th, psaddr_t head)
+{
+  list_t list;
+  td_err_e result = TD_NOTHR;
+
+  if (ps_pdread (th->th_ta_p->ph, head, &list.next, sizeof (list.next))
+      != PS_OK)
+    return TD_ERR;     /* XXX Other error value?  */
+
+  while (list.next != head)
+    if ((psaddr_t) list.next - offsetof (struct pthread, header.data.list)
+       == th->th_unique)
+      {
+       result = TD_OK;
+       break;
+      }
+    else if (ps_pdread (th->th_ta_p->ph, list.next, &list.next,
+                       sizeof (list.next)) != PS_OK)
+      {
+       result = TD_ERR;        /* XXX Other error value?  */
+       break;
+      }
+
+  return result;
+}
+
+
+td_err_e
+td_thr_validate (const td_thrhandle_t *th)
+{
+  LOG ("td_thr_validate");
+
+  /* First check the list with threads using user allocated stacks.  */
+  td_err_e result = check_thread_list (th, th->th_ta_p->stack_user);
+
+  /* If our thread is not on this list search the list with stack
+     using implementation allocated stacks.  */
+  if (result == TD_NOTHR)
+    result = check_thread_list (th, th->th_ta_p->stack_used);
+
+  return result;
+}
diff --git a/nptl_db/thread_db.h b/nptl_db/thread_db.h
new file mode 100644 (file)
index 0000000..acb0607
--- /dev/null
@@ -0,0 +1,451 @@
+/* Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _THREAD_DB_H
+#define _THREAD_DB_H   1
+
+/* This is the debugger interface for the NPTL library.  It is
+   modelled closely after the interface with same names in Solaris
+   with the goal to share the same code in the debugger.  */
+#include <pthread.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/procfs.h>
+
+
+/* Error codes of the library.  */
+typedef enum
+{
+  TD_OK,         /* No error.  */
+  TD_ERR,        /* No further specified error.  */
+  TD_NOTHR,      /* No matching thread found.  */
+  TD_NOSV,       /* No matching synchronization handle found.  */
+  TD_NOLWP,      /* No matching light-weighted process found.  */
+  TD_BADPH,      /* Invalid process handle.  */
+  TD_BADTH,      /* Invalid thread handle.  */
+  TD_BADSH,      /* Invalid synchronization handle.  */
+  TD_BADTA,      /* Invalid thread agent.  */
+  TD_BADKEY,     /* Invalid key.  */
+  TD_NOMSG,      /* No event available.  */
+  TD_NOFPREGS,   /* No floating-point register content available.  */
+  TD_NOLIBTHREAD, /* Application not linked with thread library.  */
+  TD_NOEVENT,    /* Requested event is not supported.  */
+  TD_NOCAPAB,    /* Capability not available.  */
+  TD_DBERR,      /* Internal debug library error.  */
+  TD_NOAPLIC,    /* Operation is not applicable.  */
+  TD_NOTSD,      /* No thread-specific data available.  */
+  TD_MALLOC,     /* Out of memory.  */
+  TD_PARTIALREG,  /* Not entire register set was read or written.  */
+  TD_NOXREGS,    /* X register set not available for given thread.  */
+  TD_NOTALLOC,   /* TLS memory not yet allocated.  */
+  TD_VERSION     /* Version if libpthread and libthread_db do not match.  */
+} td_err_e;
+
+
+/* Possible thread states.  TD_THR_ANY_STATE is a pseudo-state used to
+   select threads regardless of state in td_ta_thr_iter().  */
+typedef enum
+{
+  TD_THR_ANY_STATE,
+  TD_THR_UNKNOWN,
+  TD_THR_STOPPED,
+  TD_THR_RUN,
+  TD_THR_ACTIVE,
+  TD_THR_ZOMBIE,
+  TD_THR_SLEEP,
+  TD_THR_STOPPED_ASLEEP
+} td_thr_state_e;
+
+/* Thread type: user or system.  TD_THR_ANY_TYPE is a pseudo-type used
+   to select threads regardless of type in td_ta_thr_iter().  */
+typedef enum
+{
+  TD_THR_ANY_TYPE,
+  TD_THR_USER,
+  TD_THR_SYSTEM
+} td_thr_type_e;
+
+
+/* Types of the debugging library.  */
+
+/* Handle for a process.  This type is opaque.  */
+typedef struct td_thragent td_thragent_t;
+
+/* The actual thread handle type.  This is also opaque.  */
+typedef struct td_thrhandle
+{
+  td_thragent_t *th_ta_p;
+  psaddr_t th_unique;
+} td_thrhandle_t;
+
+
+/* Forward declaration of a type defined by and for the dynamic linker.  */
+struct link_map;
+
+
+/* Flags for `td_ta_thr_iter'.  */
+#define TD_THR_ANY_USER_FLAGS  0xffffffff
+#define TD_THR_LOWEST_PRIORITY -20
+#define TD_SIGNO_MASK          NULL
+
+
+#define TD_EVENTSIZE   2
+#define BT_UISHIFT     5 /* log base 2 of BT_NBIPUI, to extract word index */
+#define BT_NBIPUI      (1 << BT_UISHIFT)       /* n bits per uint */
+#define BT_UIMASK      (BT_NBIPUI - 1)         /* to extract bit index */
+
+/* Bitmask of enabled events. */
+typedef struct td_thr_events
+{
+  uint32_t event_bits[TD_EVENTSIZE];
+} td_thr_events_t;
+
+/* Event set manipulation macros. */
+#define __td_eventmask(n) \
+  (UINT32_C (1) << (((n) - 1) & BT_UIMASK))
+#define __td_eventword(n) \
+  ((UINT32_C ((n) - 1)) >> BT_UISHIFT)
+
+#define td_event_emptyset(setp) \
+  do {                                                                       \
+    int __i;                                                                 \
+    for (__i = TD_EVENTSIZE; __i > 0; --__i)                                 \
+      (setp)->event_bits[__i - 1] = 0;                                       \
+  } while (0)
+
+#define td_event_fillset(setp) \
+  do {                                                                       \
+    int __i;                                                                 \
+    for (__i = TD_EVENTSIZE; __i > 0; --__i)                                 \
+      (setp)->event_bits[__i - 1] = UINT32_C (0xffffffff);                   \
+  } while (0)
+
+#define td_event_addset(setp, n) \
+  (((setp)->event_bits[__td_eventword (n)]) |= __td_eventmask (n))
+#define td_event_delset(setp, n) \
+  (((setp)->event_bits[__td_eventword (n)]) &= ~__td_eventmask (n))
+#define td_eventismember(setp, n) \
+  (__td_eventmask (n) & ((setp)->event_bits[__td_eventword (n)]))
+#if TD_EVENTSIZE == 2
+# define td_eventisempty(setp) \
+  (!((setp)->event_bits[0]) && !((setp)->event_bits[1]))
+#else
+# error "td_eventisempty must be changed to match TD_EVENTSIZE"
+#endif
+
+/* Events reportable by the thread implementation.  */
+typedef enum
+{
+  TD_ALL_EVENTS,                /* Pseudo-event number.  */
+  TD_EVENT_NONE = TD_ALL_EVENTS, /* Depends on context.  */
+  TD_READY,                     /* Is executable now. */
+  TD_SLEEP,                     /* Blocked in a synchronization obj.  */
+  TD_SWITCHTO,                  /* Now assigned to a process.  */
+  TD_SWITCHFROM,                /* Not anymore assigned to a process.  */
+  TD_LOCK_TRY,                  /* Trying to get an unavailable lock.  */
+  TD_CATCHSIG,                  /* Signal posted to the thread.  */
+  TD_IDLE,                      /* Process getting idle.  */
+  TD_CREATE,                    /* New thread created.  */
+  TD_DEATH,                     /* Thread terminated.  */
+  TD_PREEMPT,                   /* Preempted.  */
+  TD_PRI_INHERIT,               /* Inherited elevated priority.  */
+  TD_REAP,                      /* Reaped.  */
+  TD_CONCURRENCY,               /* Number of processes changing.  */
+  TD_TIMEOUT,                   /* Conditional variable wait timed out.  */
+  TD_MIN_EVENT_NUM = TD_READY,
+  TD_MAX_EVENT_NUM = TD_TIMEOUT,
+  TD_EVENTS_ENABLE = 31                /* Event reporting enabled.  */
+} td_event_e;
+
+/* Values representing the different ways events are reported.  */
+typedef enum
+{
+  NOTIFY_BPT,                  /* User must insert breakpoint at u.bptaddr. */
+  NOTIFY_AUTOBPT,              /* Breakpoint at u.bptaddr is automatically
+                                  inserted.  */
+  NOTIFY_SYSCALL               /* System call u.syscallno will be invoked.  */
+} td_notify_e;
+
+/* Description how event type is reported.  */
+typedef struct td_notify
+{
+  td_notify_e type;            /* Way the event is reported.  */
+  union
+  {
+    psaddr_t bptaddr;          /* Address of breakpoint.  */
+    int syscallno;             /* Number of system call used.  */
+  } u;
+} td_notify_t;
+
+/* Structure used to report event.  */
+typedef struct td_event_msg
+{
+  td_event_e event;            /* Event type being reported.  */
+  const td_thrhandle_t *th_p;  /* Thread reporting the event.  */
+  union
+  {
+# if 0
+    td_synchandle_t *sh;       /* Handle of synchronization object.  */
+#endif
+    uintptr_t data;            /* Event specific data.  */
+  } msg;
+} td_event_msg_t;
+
+/* Structure containing event data available in each thread structure.  */
+typedef struct
+{
+  td_thr_events_t eventmask;   /* Mask of enabled events.  */
+  td_event_e eventnum;         /* Number of last event.  */
+  void *eventdata;             /* Data associated with event.  */
+} td_eventbuf_t;
+
+
+/* Gathered statistics about the process.  */
+typedef struct td_ta_stats
+{
+  int nthreads;                /* Total number of threads in use.  */
+  int r_concurrency;           /* Concurrency level requested by user.  */
+  int nrunnable_num;           /* Average runnable threads, numerator.  */
+  int nrunnable_den;           /* Average runnable threads, denominator.  */
+  int a_concurrency_num;       /* Achieved concurrency level, numerator.  */
+  int a_concurrency_den;       /* Achieved concurrency level, denominator.  */
+  int nlwps_num;               /* Average number of processes in use,
+                                  numerator.  */
+  int nlwps_den;               /* Average number of processes in use,
+                                  denominator.  */
+  int nidle_num;               /* Average number of idling processes,
+                                  numerator.  */
+  int nidle_den;               /* Average number of idling processes,
+                                  denominator.  */
+} td_ta_stats_t;
+
+
+/* Since Sun's library is based on Solaris threads we have to define a few
+   types to map them to POSIX threads.  */
+typedef pthread_t thread_t;
+typedef pthread_key_t thread_key_t;
+
+
+/* Callback for iteration over threads.  */
+typedef int td_thr_iter_f (const td_thrhandle_t *, void *);
+
+/* Callback for iteration over thread local data.  */
+typedef int td_key_iter_f (thread_key_t, void (*) (void *), void *);
+
+
+
+/* Forward declaration.  This has to be defined by the user.  */
+struct ps_prochandle;
+
+
+/* Information about the thread.  */
+typedef struct td_thrinfo
+{
+  td_thragent_t *ti_ta_p;              /* Process handle.  */
+  unsigned int ti_user_flags;          /* Unused.  */
+  thread_t ti_tid;                     /* Thread ID returned by
+                                          pthread_create().  */
+  char *ti_tls;                                /* Pointer to thread-local data.  */
+  psaddr_t ti_startfunc;               /* Start function passed to
+                                          pthread_create().  */
+  psaddr_t ti_stkbase;                 /* Base of thread's stack.  */
+  long int ti_stksize;                 /* Size of thread's stack.  */
+  psaddr_t ti_ro_area;                 /* Unused.  */
+  int ti_ro_size;                      /* Unused.  */
+  td_thr_state_e ti_state;             /* Thread state.  */
+  unsigned char ti_db_suspended;       /* Nonzero if suspended by debugger. */
+  td_thr_type_e ti_type;               /* Type of the thread (system vs
+                                          user thread).  */
+  intptr_t ti_pc;                      /* Unused.  */
+  intptr_t ti_sp;                      /* Unused.  */
+  short int ti_flags;                  /* Unused.  */
+  int ti_pri;                          /* Thread priority.  */
+  lwpid_t ti_lid;                      /* Unused.  */
+  sigset_t ti_sigmask;                 /* Signal mask.  */
+  unsigned char ti_traceme;            /* Nonzero if event reporting
+                                          enabled.  */
+  unsigned char ti_preemptflag;                /* Unused.  */
+  unsigned char ti_pirecflag;          /* Unused.  */
+  sigset_t ti_pending;                 /* Set of pending signals.  */
+  td_thr_events_t ti_events;           /* Set of enabled events.  */
+} td_thrinfo_t;
+
+
+
+/* Prototypes for exported library functions.  */
+
+/* Initialize the thread debug support library.  */
+extern td_err_e td_init (void);
+
+/* Historical relict.  Should not be used anymore.  */
+extern td_err_e td_log (void);
+
+/* Return list of symbols the library can request.  */
+extern const char **td_symbol_list (void);
+
+/* Generate new thread debug library handle for process PS.  */
+extern td_err_e td_ta_new (struct ps_prochandle *__ps, td_thragent_t **__ta);
+
+/* Free resources allocated for TA.  */
+extern td_err_e td_ta_delete (td_thragent_t *__ta);
+
+/* Get number of currently running threads in process associated with TA.  */
+extern td_err_e td_ta_get_nthreads (const td_thragent_t *__ta, int *__np);
+
+/* Return process handle passed in `td_ta_new' for process associated with
+   TA.  */
+extern td_err_e td_ta_get_ph (const td_thragent_t *__ta,
+                             struct ps_prochandle **__ph);
+
+/* Map thread library handle PT to thread debug library handle for process
+   associated with TA and store result in *TH.  */
+extern td_err_e td_ta_map_id2thr (const td_thragent_t *__ta, pthread_t __pt,
+                                 td_thrhandle_t *__th);
+
+/* Map process ID LWPID to thread debug library handle for process
+   associated with TA and store result in *TH.  */
+extern td_err_e td_ta_map_lwp2thr (const td_thragent_t *__ta, lwpid_t __lwpid,
+                                  td_thrhandle_t *__th);
+
+
+/* Call for each thread in a process associated with TA the callback function
+   CALLBACK.  */
+extern td_err_e td_ta_thr_iter (const td_thragent_t *__ta,
+                               td_thr_iter_f *__callback, void *__cbdata_p,
+                               td_thr_state_e __state, int __ti_pri,
+                               sigset_t *__ti_sigmask_p,
+                               unsigned int __ti_user_flags);
+
+/* Call for each defined thread local data entry the callback function KI.  */
+extern td_err_e td_ta_tsd_iter (const td_thragent_t *__ta, td_key_iter_f *__ki,
+                               void *__p);
+
+
+/* Get event address for EVENT.  */
+extern td_err_e td_ta_event_addr (const td_thragent_t *__ta,
+                                 td_event_e __event, td_notify_t *__ptr);
+
+/* Enable EVENT in global mask.  */
+extern td_err_e td_ta_set_event (const td_thragent_t *__ta,
+                                td_thr_events_t *__event);
+
+/* Disable EVENT in global mask.  */
+extern td_err_e td_ta_clear_event (const td_thragent_t *__ta,
+                                  td_thr_events_t *__event);
+
+/* Return information about last event.  */
+extern td_err_e td_ta_event_getmsg (const td_thragent_t *__ta,
+                                   td_event_msg_t *__msg);
+
+
+/* Set suggested concurrency level for process associated with TA.  */
+extern td_err_e td_ta_setconcurrency (const td_thragent_t *__ta, int __level);
+
+
+/* Enable collecting statistics for process associated with TA.  */
+extern td_err_e td_ta_enable_stats (const td_thragent_t *__ta, int __enable);
+
+/* Reset statistics.  */
+extern td_err_e td_ta_reset_stats (const td_thragent_t *__ta);
+
+/* Retrieve statistics from process associated with TA.  */
+extern td_err_e td_ta_get_stats (const td_thragent_t *__ta,
+                                td_ta_stats_t *__statsp);
+
+
+/* Validate that TH is a thread handle.  */
+extern td_err_e td_thr_validate (const td_thrhandle_t *__th);
+
+/* Return information about thread TH.  */
+extern td_err_e td_thr_get_info (const td_thrhandle_t *__th,
+                                td_thrinfo_t *__infop);
+
+/* Retrieve floating-point register contents of process running thread TH.  */
+extern td_err_e td_thr_getfpregs (const td_thrhandle_t *__th,
+                                 prfpregset_t *__regset);
+
+/* Retrieve general register contents of process running thread TH.  */
+extern td_err_e td_thr_getgregs (const td_thrhandle_t *__th,
+                                prgregset_t __gregs);
+
+/* Retrieve extended register contents of process running thread TH.  */
+extern td_err_e td_thr_getxregs (const td_thrhandle_t *__th, void *__xregs);
+
+/* Get size of extended register set of process running thread TH.  */
+extern td_err_e td_thr_getxregsize (const td_thrhandle_t *__th, int *__sizep);
+
+/* Set floating-point register contents of process running thread TH.  */
+extern td_err_e td_thr_setfpregs (const td_thrhandle_t *__th,
+                                 const prfpregset_t *__fpregs);
+
+/* Set general register contents of process running thread TH.  */
+extern td_err_e td_thr_setgregs (const td_thrhandle_t *__th,
+                                prgregset_t __gregs);
+
+/* Set extended register contents of process running thread TH.  */
+extern td_err_e td_thr_setxregs (const td_thrhandle_t *__th,
+                                const void *__addr);
+
+
+/* Get address of thread local variable.  */
+extern td_err_e td_thr_tls_get_addr (const td_thrhandle_t *__th,
+                                    void *__map_address, size_t __offset,
+                                    void **__address);
+
+
+/* Enable reporting for EVENT for thread TH.  */
+extern td_err_e td_thr_event_enable (const td_thrhandle_t *__th, int __event);
+
+/* Enable EVENT for thread TH.  */
+extern td_err_e td_thr_set_event (const td_thrhandle_t *__th,
+                                 td_thr_events_t *__event);
+
+/* Disable EVENT for thread TH.  */
+extern td_err_e td_thr_clear_event (const td_thrhandle_t *__th,
+                                   td_thr_events_t *__event);
+
+/* Get event message for thread TH.  */
+extern td_err_e td_thr_event_getmsg (const td_thrhandle_t *__th,
+                                    td_event_msg_t *__msg);
+
+
+/* Set priority of thread TH.  */
+extern td_err_e td_thr_setprio (const td_thrhandle_t *__th, int __prio);
+
+
+/* Set pending signals for thread TH.  */
+extern td_err_e td_thr_setsigpending (const td_thrhandle_t *__th,
+                                     unsigned char __n, const sigset_t *__ss);
+
+/* Set signal mask for thread TH.  */
+extern td_err_e td_thr_sigsetmask (const td_thrhandle_t *__th,
+                                  const sigset_t *__ss);
+
+
+/* Return thread local data associated with key TK in thread TH.  */
+extern td_err_e td_thr_tsd (const td_thrhandle_t *__th,
+                           const thread_key_t __tk, void **__data);
+
+
+/* Suspend execution of thread TH.  */
+extern td_err_e td_thr_dbsuspend (const td_thrhandle_t *__th);
+
+/* Resume execution of thread TH.  */
+extern td_err_e td_thr_dbresume (const td_thrhandle_t *__th);
+
+#endif /* thread_db.h */
diff --git a/nptl_db/thread_dbP.h b/nptl_db/thread_dbP.h
new file mode 100644 (file)
index 0000000..4407143
--- /dev/null
@@ -0,0 +1,98 @@
+/* Private header for thread debug library.  */
+#ifndef _THREAD_DBP_H
+#define _THREAD_DBP_H  1
+
+#include <stdbool.h>
+#include <string.h>
+#include <unistd.h>
+#include "proc_service.h"
+#include "thread_db.h"
+#include "../nptl/pthreadP.h"
+#include <list.h>
+
+
+/* Indeces for the symbol names.  */
+enum
+  {
+    SYM_PTHREAD_THREADS_EVENTS = 0,
+    SYM_PTHREAD_LAST_EVENT,
+    SYM_PTHREAD_NTHREADS,
+    SYM_PTHREAD_STACK_USED,
+    SYM_PTHREAD_STACK_USER,
+    SYM_PTHREAD_KEYS,
+    SYM_PTHREAD_KEYS_MAX,
+    SYM_PTHREAD_SIZEOF_DESCR,
+    SYM_PTHREAD_CREATE_EVENT,
+    SYM_PTHREAD_DEATH_EVENT,
+    SYM_PTHREAD_VERSION,
+    SYM_NUM_MESSAGES
+  };
+
+
+/* Comment out the following for less verbose output.  */
+#ifndef NDEBUG
+# define LOG(c) if (__td_debug) __libc_write (2, c "\n", strlen (c "\n"))
+extern int __td_debug;
+#else
+# define LOG(c)
+#endif
+
+
+/* Handle for a process.  This type is opaque.  */
+struct td_thragent
+{
+  /* Delivered by the debugger and we have to pass it back in the
+     proc callbacks.  */
+  struct ps_prochandle *ph;
+
+  /* Some cached information.  */
+
+  /* Lists of running threads.  */
+  psaddr_t stack_used;
+  psaddr_t stack_user;
+
+  /* Address of the `pthread_keys' array.  */
+  struct pthread_key_struct *keys;
+
+  /* Maximum number of thread-local data keys.  */
+  int pthread_keys_max;
+
+  /* Size of 2nd level array for thread-local data keys.  */
+  int pthread_key_2ndlevel_size;
+
+  /* Sizeof struct _pthread_descr_struct.  */
+  int sizeof_descr;
+
+  /* Pointer to the `__pthread_threads_events' variable in the target.  */
+  psaddr_t pthread_threads_eventsp;
+
+  /* Pointer to the `__pthread_last_event' variable in the target.  */
+  psaddr_t pthread_last_event;
+
+  /* List head the queue agent structures.  */
+  list_t list;
+};
+
+
+/* List of all known descriptors.  */
+extern list_t __td_agent_list;
+
+
+/* Function used to test for correct thread agent pointer.  */
+static inline bool
+ta_ok (const td_thragent_t *ta)
+{
+  list_t *runp;
+
+  list_for_each (runp, &__td_agent_list)
+    if (list_entry (runp, td_thragent_t, list) == ta)
+      return true;
+
+  return false;
+}
+
+
+/* Internal wrapper around ps_pglobal_lookup.  */
+extern int td_lookup (struct ps_prochandle *ps, int idx, psaddr_t *sym_addr);
+
+#endif /* thread_dbP.h */
This page took 0.817093 seconds and 5 git commands to generate.