diff options
352 files changed, 29447 insertions, 0 deletions
diff --git a/nptl/ANNOUNCE b/nptl/ANNOUNCE new file mode 100644 index 0000000000..b63c657b85 --- /dev/null +++ b/nptl/ANNOUNCE @@ -0,0 +1,92 @@ +Now that the Linux kernel is once again able to run all the tests we +have and since glibc 2.3 was released it was time for a new code drop. +I've uploaded the second code drop for the Native POSIX Thread +Library: + + ftp://people.redhat.com/drepper/nptl/nptl-0.2.tar.bz2 + +You need + +- the latest of Linus' kernel from BitKeeper (or 2.5.41 when it + is released); + +- glibc 2.3 + +- the very latest in tools such as + + + gcc either from the current development branch or the gcc 3.2 + from Red Hat Linux 8; + + + binutils preferrably from CVS, from H.J. Lu's latest release for + Linux, or from RHL 8. + + +Compiling glibc should proceed smoothly. But there are a number of +tests which fail, mostly because some functionality is missing in +glibc. Ignore those errors. It is only important that all tests in +nptl/ are passing. Run + + make subdirs=nptl check + +to run all thread tests. + + +This version features several improvements: + +- all APIs are now implemented; + +- fork handling has been improved; stacks in the child are freed; + atfork handlers are removed if they were registered from a module + which gets unloaded. + +- pthread_tryjoin_np and pthread_timedjoin_np are implemented + +- TSD handling corrected and optimized. + +- many more tests which also test the underlying kernel implementation. + +- the build infrastructure has been implemented so that the DSO and + archives are built in usable form and with correct named. + +- libthread_db has been implemented. This is the library which is + needed by all program which need to get access to internals of + libpthread (mainly debuggers). + +- the CPU clock functions are implemented + + + +The white paper hasn't yet been updated. It's still available at + + http://people.redhat.com/drepper/nptl-design.pdf + + +This release should be ready for some serious testing. I know it is +hard to compile which I why I'm looking into providing binary RPMs. +They can be used on non-critical systems. I'll only be able to +provide binaries for RHL8 based systems, though, and the kernel still +must be installed separately. + + +The next steps will include: + +- write more tests and fix the bugs which are discovered this way + +- update the white paper + +- write and run more performance tests + +- port to IA-64 + + +Interested parties are once again invited to join the mailing we +created: + + + phil-list@redhat.com + +Go to + + https://listman.redhat.com/mailman/listinfo/phil-list + +to subscribe, unsubscribe, or review the archive. diff --git a/nptl/Banner b/nptl/Banner new file mode 100644 index 0000000000..e5342825c3 --- /dev/null +++ b/nptl/Banner @@ -0,0 +1 @@ +nptl 0.9 by Ulrich Drepper diff --git a/nptl/ChangeLog b/nptl/ChangeLog new file mode 100644 index 0000000000..e34cbcf180 --- /dev/null +++ b/nptl/ChangeLog @@ -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 index 0000000000..782377f0c5 --- /dev/null +++ b/nptl/DESIGN-barrier.txt @@ -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 index 0000000000..303807be6d --- /dev/null +++ b/nptl/DESIGN-condvar.txt @@ -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 index 0000000000..6262a7a5b9 --- /dev/null +++ b/nptl/DESIGN-rwlock.txt @@ -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 index 0000000000..2db2f35ce2 --- /dev/null +++ b/nptl/DESIGN-sem-old.txt @@ -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 index 0000000000..d25a1c281d --- /dev/null +++ b/nptl/DESIGN-sem.txt @@ -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 index 0000000000..61015d27f3 --- /dev/null +++ b/nptl/Makeconfig @@ -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 index 0000000000..e596803ef1 --- /dev/null +++ b/nptl/Makefile @@ -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 index 0000000000..09392b1f88 --- /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 index 0000000000..2ee5da67fe --- /dev/null +++ b/nptl/TODO-kernel @@ -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 index 0000000000..ce11c67295 --- /dev/null +++ b/nptl/Versions @@ -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 index 0000000000..6dc5cfa2ce --- /dev/null +++ b/nptl/alloca_cutoff.c @@ -0,0 +1,36 @@ +/* Determine whether block of given size can be allocated on the stack or not. + Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU 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 index 0000000000..2aaaaeca9c --- /dev/null +++ b/nptl/allocatestack.c @@ -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 index 0000000000..927e0fe5ac --- /dev/null +++ b/nptl/atomic.h @@ -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 index 0000000000..890b26ec4e --- /dev/null +++ b/nptl/cancellation.c @@ -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 index 0000000000..6c7ba6187b --- /dev/null +++ b/nptl/cleanup.c @@ -0,0 +1,63 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with 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 index 0000000000..192fea57c8 --- /dev/null +++ b/nptl/cleanup_defer.c @@ -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 index 0000000000..3eafc93f5b --- /dev/null +++ b/nptl/configure @@ -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 index 0000000000..f3a9620a7b --- /dev/null +++ b/nptl/descr.h @@ -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 index 0000000000..8232d0c7d7 --- /dev/null +++ b/nptl/events.c @@ -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 index 0000000000..a82059f2f1 --- /dev/null +++ b/nptl/flockfile.c @@ -0,0 +1,31 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <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 index 0000000000..29f291d555 --- /dev/null +++ b/nptl/forward.c @@ -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 index 0000000000..9ed010ddfc --- /dev/null +++ b/nptl/ftrylockfile.c @@ -0,0 +1,31 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <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 index 0000000000..cbb3ec690c --- /dev/null +++ b/nptl/funlockfile.c @@ -0,0 +1,31 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <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 index 0000000000..58d97846cf --- /dev/null +++ b/nptl/herrno.c @@ -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 index 0000000000..395ede7033 --- /dev/null +++ b/nptl/init.c @@ -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 index 0000000000..768e6876c4 --- /dev/null +++ b/nptl/old_pthread_atfork.c @@ -0,0 +1,27 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <shlib-compat.h> + +#if SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_3) +# define __pthread_atfork __dyn_pthread_atfork +# include "pthread_atfork.c" +# undef __pthread_atfork +compat_symbol (libpthread, __dyn_pthread_atfork, pthread_atfork, GLIBC_2_0); +#endif diff --git a/nptl/perf.c b/nptl/perf.c new file mode 100644 index 0000000000..e94ccf8a6b --- /dev/null +++ b/nptl/perf.c @@ -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 index 0000000000..09e2c52efd --- /dev/null +++ b/nptl/pt-accept.c @@ -0,0 +1,40 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <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 index 0000000000..3598dbb49f --- /dev/null +++ b/nptl/pt-allocrtsig.c @@ -0,0 +1,50 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <signal.h> + + +/* These are defined in libc. We want to have only one definition + so we "forward" the calls. */ +extern int __libc_current_sigrtmin_private (void); +extern int __libc_current_sigrtmax_private (void); +extern int __libc_allocate_rtsig_private (int high); + + +/* We reserve __SIGRTMIN for use as the cancelation signal. This + signal is used internally. */ +int +__libc_current_sigrtmin (void) +{ + return __libc_current_sigrtmin_private (); +} + + +int +__libc_current_sigrtmax (void) +{ + return __libc_current_sigrtmax_private (); +} + + +int +__libc_allocate_rtsig (int high) +{ + return __libc_allocate_rtsig_private (high); +} diff --git a/nptl/pt-close.c b/nptl/pt-close.c new file mode 100644 index 0000000000..85115c9c23 --- /dev/null +++ b/nptl/pt-close.c @@ -0,0 +1,45 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <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 index 0000000000..105cb6218d --- /dev/null +++ b/nptl/pt-connect.c @@ -0,0 +1,41 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <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 index 0000000000..bdb5e4f561 --- /dev/null +++ b/nptl/pt-creat.c @@ -0,0 +1,45 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <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 index 0000000000..194f6ca52b --- /dev/null +++ b/nptl/pt-fcntl.c @@ -0,0 +1,54 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <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 index 0000000000..6c41912a7b --- /dev/null +++ b/nptl/pt-fsync.c @@ -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 index 0000000000..f333b8dfb0 --- /dev/null +++ b/nptl/pt-longjmp.c @@ -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 index 0000000000..31e3ef700e --- /dev/null +++ b/nptl/pt-lseek.c @@ -0,0 +1,45 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <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 index 0000000000..f9faa16402 --- /dev/null +++ b/nptl/pt-lseek64.c @@ -0,0 +1,40 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <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 index 0000000000..b8bf6bc56c --- /dev/null +++ b/nptl/pt-msgrcv.c @@ -0,0 +1,40 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <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 index 0000000000..4297f9dc4e --- /dev/null +++ b/nptl/pt-msgsnd.c @@ -0,0 +1,46 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <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 index 0000000000..c1d64454ca --- /dev/null +++ b/nptl/pt-msync.c @@ -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 index 0000000000..1d6cbb5170 --- /dev/null +++ b/nptl/pt-nanosleep.c @@ -0,0 +1,45 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <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 index 0000000000..00e06b1956 --- /dev/null +++ b/nptl/pt-open.c @@ -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 index 0000000000..25eec281f4 --- /dev/null +++ b/nptl/pt-open64.c @@ -0,0 +1,54 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <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 index 0000000000..dbc6250789 --- /dev/null +++ b/nptl/pt-pause.c @@ -0,0 +1,40 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <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 index 0000000000..65da7e6434 --- /dev/null +++ b/nptl/pt-poll.c @@ -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 index 0000000000..bcc7e0dc0c --- /dev/null +++ b/nptl/pt-pread.c @@ -0,0 +1,40 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <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 index 0000000000..1cf85f49b1 --- /dev/null +++ b/nptl/pt-pread64.c @@ -0,0 +1,41 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <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 index 0000000000..e935a07ccd --- /dev/null +++ b/nptl/pt-pselect.c @@ -0,0 +1,41 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <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 index 0000000000..28910f60b7 --- /dev/null +++ b/nptl/pt-pwrite.c @@ -0,0 +1,40 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <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 index 0000000000..abe4106182 --- /dev/null +++ b/nptl/pt-pwrite64.c @@ -0,0 +1,41 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <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 index 0000000000..8f31f0ceb4 --- /dev/null +++ b/nptl/pt-read.c @@ -0,0 +1,45 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <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 index 0000000000..9f6e653d4f --- /dev/null +++ b/nptl/pt-readv.c @@ -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 index 0000000000..0b9f7056a3 --- /dev/null +++ b/nptl/pt-recv.c @@ -0,0 +1,40 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <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 index 0000000000..095b0b4b58 --- /dev/null +++ b/nptl/pt-recvfrom.c @@ -0,0 +1,41 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <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 index 0000000000..e5ceaaad0c --- /dev/null +++ b/nptl/pt-recvmsg.c @@ -0,0 +1,40 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <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 index 0000000000..03e10cd08e --- /dev/null +++ b/nptl/pt-select.c @@ -0,0 +1,46 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <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 index 0000000000..90221adc24 --- /dev/null +++ b/nptl/pt-send.c @@ -0,0 +1,41 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <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 index 0000000000..5b4d8b93cc --- /dev/null +++ b/nptl/pt-sendmsg.c @@ -0,0 +1,40 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <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 index 0000000000..6a81e61df2 --- /dev/null +++ b/nptl/pt-sendto.c @@ -0,0 +1,41 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <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 index 0000000000..69157107ae --- /dev/null +++ b/nptl/pt-siglongjmp.c @@ -0,0 +1,32 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <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 index 0000000000..ad78662839 --- /dev/null +++ b/nptl/pt-sigpause.c @@ -0,0 +1,41 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <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 index 0000000000..d345b5dc50 --- /dev/null +++ b/nptl/pt-sigsuspend.c @@ -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 index 0000000000..c2940f397e --- /dev/null +++ b/nptl/pt-sigtimedwait.c @@ -0,0 +1,45 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <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 index 0000000000..efd05ed7d9 --- /dev/null +++ b/nptl/pt-sigwait.c @@ -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 index 0000000000..961293b06c --- /dev/null +++ b/nptl/pt-sigwaitinfo.c @@ -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 index 0000000000..2572c477c8 --- /dev/null +++ b/nptl/pt-system.c @@ -0,0 +1,40 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <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 index 0000000000..65af7b8092 --- /dev/null +++ b/nptl/pt-tcdrain.c @@ -0,0 +1,40 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <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 index 0000000000..951bba6b44 --- /dev/null +++ b/nptl/pt-wait.c @@ -0,0 +1,41 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <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 index 0000000000..977e5d4b77 --- /dev/null +++ b/nptl/pt-waitid.c @@ -0,0 +1,41 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <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 index 0000000000..413328bea9 --- /dev/null +++ b/nptl/pt-waitpid.c @@ -0,0 +1,40 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <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 index 0000000000..190bea90ae --- /dev/null +++ b/nptl/pt-write.c @@ -0,0 +1,45 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <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 index 0000000000..c1dda350aa --- /dev/null +++ b/nptl/pt-writev.c @@ -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 index 0000000000..adca0514a3 --- /dev/null +++ b/nptl/pthreadP.h @@ -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 index 0000000000..00a52fd4cd --- /dev/null +++ b/nptl/pthread_atfork.c @@ -0,0 +1,46 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "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 index 0000000000..088800cd8a --- /dev/null +++ b/nptl/pthread_attr_destroy.c @@ -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 index 0000000000..a1a0549c2e --- /dev/null +++ b/nptl/pthread_attr_getdetachstate.c @@ -0,0 +1,38 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include "pthreadP.h" + + +int +pthread_attr_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 index 0000000000..e1d0ed6243 --- /dev/null +++ b/nptl/pthread_attr_getguardsize.c @@ -0,0 +1,37 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include "pthreadP.h" + + +int +pthread_attr_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 index 0000000000..faba994062 --- /dev/null +++ b/nptl/pthread_attr_getinheritsched.c @@ -0,0 +1,39 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include "pthreadP.h" + + +int +pthread_attr_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 index 0000000000..93961d555c --- /dev/null +++ b/nptl/pthread_attr_getschedparam.c @@ -0,0 +1,39 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include <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 index 0000000000..18293f255a --- /dev/null +++ b/nptl/pthread_attr_getschedpolicy.c @@ -0,0 +1,38 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include "pthreadP.h" + + +int +pthread_attr_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 index 0000000000..1b97ef3b36 --- /dev/null +++ b/nptl/pthread_attr_getscope.c @@ -0,0 +1,39 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include "pthreadP.h" + + +int +pthread_attr_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 index 0000000000..1db135e5cf --- /dev/null +++ b/nptl/pthread_attr_getstack.c @@ -0,0 +1,41 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include "pthreadP.h" + + +int +__pthread_attr_getstack (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 index 0000000000..f483dc82ef --- /dev/null +++ b/nptl/pthread_attr_getstackaddr.c @@ -0,0 +1,49 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <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 index 0000000000..d4ff54f381 --- /dev/null +++ b/nptl/pthread_attr_getstacksize.c @@ -0,0 +1,40 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include "pthreadP.h" + + +int +__pthread_attr_getstacksize (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 index 0000000000..90c8dc2ede --- /dev/null +++ b/nptl/pthread_attr_init.c @@ -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 index 0000000000..3f247cf762 --- /dev/null +++ b/nptl/pthread_attr_setdetachstate.c @@ -0,0 +1,47 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include <errno.h> +#include "pthreadP.h" + + +int +pthread_attr_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 index 0000000000..4c674f4dfb --- /dev/null +++ b/nptl/pthread_attr_setguardsize.c @@ -0,0 +1,40 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include "pthreadP.h" + + +int +pthread_attr_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 index 0000000000..f724396c9a --- /dev/null +++ b/nptl/pthread_attr_setinheritsched.c @@ -0,0 +1,46 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include <errno.h> +#include "pthreadP.h" + + +int +pthread_attr_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 index 0000000000..2ffba99008 --- /dev/null +++ b/nptl/pthread_attr_setschedparam.c @@ -0,0 +1,49 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <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 index 0000000000..65bf155b7b --- /dev/null +++ b/nptl/pthread_attr_setschedpolicy.c @@ -0,0 +1,43 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <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 index 0000000000..1435afbe2c --- /dev/null +++ b/nptl/pthread_attr_setscope.c @@ -0,0 +1,50 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <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 index 0000000000..811ab69791 --- /dev/null +++ b/nptl/pthread_attr_setstack.c @@ -0,0 +1,47 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include <errno.h> +#include <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 index 0000000000..a72511225f --- /dev/null +++ b/nptl/pthread_attr_setstackaddr.c @@ -0,0 +1,43 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <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 index 0000000000..508cc3f70f --- /dev/null +++ b/nptl/pthread_attr_setstacksize.c @@ -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 index 0000000000..492b29485b --- /dev/null +++ b/nptl/pthread_barrier_destroy.c @@ -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 index 0000000000..19e82fa38d --- /dev/null +++ b/nptl/pthread_barrier_init.c @@ -0,0 +1,57 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include "pthreadP.h" +#include <lowlevellock.h> + + +int +pthread_barrier_init (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 index 0000000000..f947daf381 --- /dev/null +++ b/nptl/pthread_barrierattr_destroy.c @@ -0,0 +1,30 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "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 index 0000000000..246c8882ed --- /dev/null +++ b/nptl/pthread_barrierattr_getpshared.c @@ -0,0 +1,31 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" + + +int +pthread_barrierattr_getpshared (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 index 0000000000..a0be9528ba --- /dev/null +++ b/nptl/pthread_barrierattr_init.c @@ -0,0 +1,30 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "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 index 0000000000..b69f23ef14 --- /dev/null +++ b/nptl/pthread_barrierattr_setpshared.c @@ -0,0 +1,40 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include "pthreadP.h" + + +int +pthread_barrierattr_setpshared (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 index 0000000000..1fa20e087c --- /dev/null +++ b/nptl/pthread_cancel.c @@ -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 index 0000000000..0e6f67bc96 --- /dev/null +++ b/nptl/pthread_clock_gettime.c @@ -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 index 0000000000..ef6dc18773 --- /dev/null +++ b/nptl/pthread_clock_settime.c @@ -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 index 0000000000..20cc39f269 --- /dev/null +++ b/nptl/pthread_cond_broadcast.c @@ -0,0 +1,30 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "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 index 0000000000..05299fc7a9 --- /dev/null +++ b/nptl/pthread_cond_destroy.c @@ -0,0 +1,29 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <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 index 0000000000..309fc6a471 --- /dev/null +++ b/nptl/pthread_cond_init.c @@ -0,0 +1,37 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "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 index 0000000000..58573d327f --- /dev/null +++ b/nptl/pthread_cond_signal.c @@ -0,0 +1,30 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "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 index 0000000000..792dbdc49d --- /dev/null +++ b/nptl/pthread_cond_timedwait.c @@ -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 index 0000000000..37c5ffe846 --- /dev/null +++ b/nptl/pthread_cond_wait.c @@ -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 index 0000000000..4bce09dc2c --- /dev/null +++ b/nptl/pthread_condattr_destroy.c @@ -0,0 +1,29 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" + + +int +pthread_condattr_destroy (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 index 0000000000..7b91f14f46 --- /dev/null +++ b/nptl/pthread_condattr_getpshared.c @@ -0,0 +1,31 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" + + +int +pthread_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 index 0000000000..4e8aaf9603 --- /dev/null +++ b/nptl/pthread_condattr_init.c @@ -0,0 +1,31 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <string.h> +#include "pthreadP.h" + + +int +pthread_condattr_init (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 index 0000000000..518c1c791e --- /dev/null +++ b/nptl/pthread_condattr_setpshared.c @@ -0,0 +1,30 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "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 index 0000000000..451a9b3f99 --- /dev/null +++ b/nptl/pthread_create.c @@ -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 index 0000000000..2ba9f4913d --- /dev/null +++ b/nptl/pthread_detach.c @@ -0,0 +1,51 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <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 index 0000000000..f2ef2b4dab --- /dev/null +++ b/nptl/pthread_equal.c @@ -0,0 +1,29 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <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 index 0000000000..5822a2e038 --- /dev/null +++ b/nptl/pthread_exit.c @@ -0,0 +1,31 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <stdlib.h> +#include "pthreadP.h" + + +void +pthread_exit (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 index 0000000000..4e580437cf --- /dev/null +++ b/nptl/pthread_getattr_np.c @@ -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 index 0000000000..52c0c7cbee --- /dev/null +++ b/nptl/pthread_getconcurrency.c @@ -0,0 +1,27 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" + + +int +pthread_getconcurrency (void) +{ + return __concurrency_level; +} diff --git a/nptl/pthread_getschedparam.c b/nptl/pthread_getschedparam.c new file mode 100644 index 0000000000..3e23ffaac8 --- /dev/null +++ b/nptl/pthread_getschedparam.c @@ -0,0 +1,51 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <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 index 0000000000..9e3b69480a --- /dev/null +++ b/nptl/pthread_getspecific.c @@ -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 index 0000000000..a223a7d4a3 --- /dev/null +++ b/nptl/pthread_join.c @@ -0,0 +1,100 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <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 index 0000000000..7a073f2d80 --- /dev/null +++ b/nptl/pthread_key_create.c @@ -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 index 0000000000..a0145f8efa --- /dev/null +++ b/nptl/pthread_key_delete.c @@ -0,0 +1,43 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include "pthreadP.h" +#include <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 index 0000000000..a4464233af --- /dev/null +++ b/nptl/pthread_kill_other_threads.c @@ -0,0 +1,37 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <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 index 0000000000..e3dba3794a --- /dev/null +++ b/nptl/pthread_mutex_destroy.c @@ -0,0 +1,29 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" + + +int +__pthread_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 index 0000000000..3a783d768d --- /dev/null +++ b/nptl/pthread_mutex_init.c @@ -0,0 +1,55 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with 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 index 0000000000..8398003d6d --- /dev/null +++ b/nptl/pthread_mutex_lock.c @@ -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 index 0000000000..a63b2048db --- /dev/null +++ b/nptl/pthread_mutex_timedlock.c @@ -0,0 +1,88 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include "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 index 0000000000..aae506739f --- /dev/null +++ b/nptl/pthread_mutex_trylock.c @@ -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 index 0000000000..be510cb371 --- /dev/null +++ b/nptl/pthread_mutex_unlock.c @@ -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 index 0000000000..eab27d3518 --- /dev/null +++ b/nptl/pthread_mutexattr_destroy.c @@ -0,0 +1,29 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthreadP.h> + + +int +__pthread_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 index 0000000000..1769463d63 --- /dev/null +++ b/nptl/pthread_mutexattr_getpshared.c @@ -0,0 +1,38 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthreadP.h> + + +int +pthread_mutexattr_getpshared (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 index 0000000000..82a938db6a --- /dev/null +++ b/nptl/pthread_mutexattr_gettype.c @@ -0,0 +1,38 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthreadP.h> + + +int +pthread_mutexattr_gettype (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 index 0000000000..3270d5346e --- /dev/null +++ b/nptl/pthread_mutexattr_init.c @@ -0,0 +1,38 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <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 index 0000000000..9bc5c26700 --- /dev/null +++ b/nptl/pthread_mutexattr_setpshared.c @@ -0,0 +1,45 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthreadP.h> + + +int +pthread_mutexattr_setpshared (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 index 0000000000..54021b37c6 --- /dev/null +++ b/nptl/pthread_mutexattr_settype.c @@ -0,0 +1,43 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthreadP.h> + + +int +__pthread_mutexattr_settype (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 index 0000000000..28fd24b558 --- /dev/null +++ b/nptl/pthread_rwlock_destroy.c @@ -0,0 +1,30 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "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 index 0000000000..f664dd8104 --- /dev/null +++ b/nptl/pthread_rwlock_init.c @@ -0,0 +1,51 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" + + +static const struct pthread_rwlockattr default_attr = + { + .lockkind = PTHREAD_RWLOCK_DEFAULT_NP, + .pshared = PTHREAD_PROCESS_PRIVATE + }; + + +int +__pthread_rwlock_init (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 index 0000000000..446af05969 --- /dev/null +++ b/nptl/pthread_rwlock_tryrdlock.c @@ -0,0 +1,50 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include "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 index 0000000000..32fcbba8c5 --- /dev/null +++ b/nptl/pthread_rwlock_trywrlock.c @@ -0,0 +1,43 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include "pthreadP.h" +#include <lowlevellock.h> + + +int +__pthread_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 index 0000000000..4f0c2c4fe5 --- /dev/null +++ b/nptl/pthread_rwlockattr_destroy.c @@ -0,0 +1,30 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "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 index 0000000000..aad9468fdf --- /dev/null +++ b/nptl/pthread_rwlockattr_getkind_np.c @@ -0,0 +1,31 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" + + +int +pthread_rwlockattr_getkind_np (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 index 0000000000..3a776835ae --- /dev/null +++ b/nptl/pthread_rwlockattr_getpshared.c @@ -0,0 +1,31 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" + + +int +pthread_rwlockattr_getpshared (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 index 0000000000..b29953455f --- /dev/null +++ b/nptl/pthread_rwlockattr_init.c @@ -0,0 +1,35 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "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 index 0000000000..0311f1b50a --- /dev/null +++ b/nptl/pthread_rwlockattr_setkind_np.c @@ -0,0 +1,41 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include "pthreadP.h" + + +int +pthread_rwlockattr_setkind_np (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 index 0000000000..9438d29315 --- /dev/null +++ b/nptl/pthread_rwlockattr_setpshared.c @@ -0,0 +1,40 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include "pthreadP.h" + + +int +pthread_rwlockattr_setpshared (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 index 0000000000..ad231cd928 --- /dev/null +++ b/nptl/pthread_self.c @@ -0,0 +1,28 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" +#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 index 0000000000..3f36df8cd6 --- /dev/null +++ b/nptl/pthread_setcancelstate.c @@ -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 index 0000000000..8f84634888 --- /dev/null +++ b/nptl/pthread_setcanceltype.c @@ -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 index 0000000000..f65a174d41 --- /dev/null +++ b/nptl/pthread_setconcurrency.c @@ -0,0 +1,37 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "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 index 0000000000..f662405892 --- /dev/null +++ b/nptl/pthread_setschedparam.c @@ -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 index 0000000000..5af6cae83e --- /dev/null +++ b/nptl/pthread_setspecific.c @@ -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 index 0000000000..e9b17b4939 --- /dev/null +++ b/nptl/pthread_testcancel.c @@ -0,0 +1,28 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <stdlib.h> +#include "pthreadP.h" + + +void +pthread_testcancel (void) +{ + CANCELLATION_P (THREAD_SELF); +} diff --git a/nptl/pthread_timedjoin.c b/nptl/pthread_timedjoin.c new file mode 100644 index 0000000000..d3f4a282a6 --- /dev/null +++ b/nptl/pthread_timedjoin.c @@ -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 index 0000000000..88d2e8bd4e --- /dev/null +++ b/nptl/pthread_tryjoin.c @@ -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 index 0000000000..6c2e3f8867 --- /dev/null +++ b/nptl/res.c @@ -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 index 0000000000..379565f518 --- /dev/null +++ b/nptl/sem_close.c @@ -0,0 +1,29 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <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 index 0000000000..790a80e316 --- /dev/null +++ b/nptl/sem_destroy.c @@ -0,0 +1,34 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <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 index 0000000000..ee976c3fb6 --- /dev/null +++ b/nptl/sem_getvalue.c @@ -0,0 +1,38 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <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 index 0000000000..c8b80ff8c4 --- /dev/null +++ b/nptl/sem_init.c @@ -0,0 +1,51 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <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 index 0000000000..6fc72f7dc6 --- /dev/null +++ b/nptl/sem_open.c @@ -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 index 0000000000..b8e3de17d7 --- /dev/null +++ b/nptl/sem_unlink.c @@ -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 index 0000000000..b8861e5da2 --- /dev/null +++ b/nptl/semaphore.h @@ -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 index 0000000000..0d3f6e53a0 --- /dev/null +++ b/nptl/semaphoreP.h @@ -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 index 0000000000..9493a31978 --- /dev/null +++ b/nptl/shlib-versions @@ -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 index 0000000000..d29a6ee26a --- /dev/null +++ b/nptl/sockperf.c @@ -0,0 +1,594 @@ +#define _GNU_SOURCE +#include <argp.h> +#include <complex.h> +#include <errno.h> +#include <error.h> +#include <fcntl.h> +#include <gd.h> +#include <inttypes.h> +#include <pthread.h> +#include <signal.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> +#include <sys/param.h> +#include <sys/poll.h> +#include <sys/socket.h> +#include <sys/un.h> + + +#define size_x 320 +#define size_y 240 + + +#define PATH "/tmp/s.sockperf" + + +struct thread_param +{ + unsigned int from; + unsigned int to; + unsigned int nserv; +}; + +struct coord +{ + unsigned int x; + unsigned int y; + complex double z; +}; + + +/* We use 64bit values for the times. */ +typedef unsigned long long int hp_timing_t; + + +static unsigned int nclients = 2; +static unsigned int nservers = 2; + +static bool timing; +static int points; + + +static complex double top_left = -0.7 + 0.2i; +static complex double bottom_right = -0.5 - 0.0i; + + +static int colors[256]; +static gdImagePtr image; +static pthread_mutex_t image_lock; + +static int sock; + + +static void * +client (void *arg) +{ + struct thread_param *param = arg; + unsigned int cnt; + unsigned int nserv = param->nserv; + int clisock[nserv]; + struct pollfd servpoll[nserv]; + struct sockaddr_un servaddr; + socklen_t servlen; + struct coord c; + + bool new_coord (void) + { + if (cnt >= param->to) + return false; + + unsigned int row = cnt / size_x; + unsigned int col = cnt % size_x; + + c.x = col; + c.y = row; + c.z = (top_left + + ((col + * (creal (bottom_right) - creal (top_left))) / size_x) + + (_Complex_I * (row * (cimag (bottom_right) - cimag (top_left))) + / size_y)); + + ++cnt; + + return true; + } + + + for (cnt = 0; cnt < nserv; ++cnt) + { + servpoll[cnt].fd = socket (AF_UNIX, SOCK_STREAM, 0); + if (clisock < 0) + { + puts ("cannot create socket in client"); + return NULL; + } + + memset (&servaddr, '\0', sizeof (servaddr)); + servaddr.sun_family = AF_UNIX; + strncpy (servaddr.sun_path, PATH, sizeof (servaddr.sun_path)); + servlen = offsetof (struct sockaddr_un, sun_path) + strlen (PATH) + 1; + + + int err; + while (1) + { + err = TEMP_FAILURE_RETRY (connect (servpoll[cnt].fd, &servaddr, + servlen)); + if (err != -1 || errno != ECONNREFUSED) + break; + + pthread_yield (); + } + + if (err == -1) + { + printf ("cannot connect: %m (%d)\n", errno); + exit (1); + } + + servpoll[cnt].events = POLLOUT; + servpoll[cnt].revents = 0; + } + + cnt = param->from; + + new_coord (); + bool z_valid = true; + + while (1) + { + int i; + int n = poll (servpoll, nserv, -1); + if (n == -1) + { + puts ("poll returned error"); + break; + } + + bool cont = false; + for (i = 0; i < nserv && n > 0; ++i) + if (servpoll[i].revents != 0) + { + if (servpoll[i].revents == POLLIN) + { + unsigned int vals[3]; + if (TEMP_FAILURE_RETRY (read (servpoll[i].fd, &vals, + sizeof (vals))) + != sizeof (vals)) + { + puts ("read error in client"); + return NULL; + } + + pthread_mutex_lock (&image_lock); + + gdImageSetPixel (image, vals[0], vals[1], vals[2]); + ++points; + + pthread_mutex_unlock (&image_lock); + + servpoll[i].events = POLLOUT; + } + else + { + if (servpoll[i].revents != POLLOUT) + printf ("revents: %hd != POLLOUT ???\n", + servpoll[i].revents); + + if (z_valid) + { + if (TEMP_FAILURE_RETRY (write (servpoll[i].fd, &c, + sizeof (c))) != sizeof (c)) + { + puts ("write error in client"); + return NULL; + } + cont = true; + servpoll[i].events = POLLIN; + + z_valid = new_coord (); + if (! z_valid) + /* No more to do. Clear the event fields. */ + for (i = 0; i < nserv; ++i) + if (servpoll[i].events == POLLOUT) + servpoll[i].events = servpoll[i].revents = 0; + } + else + servpoll[i].events = servpoll[i].revents = 0; + } + + --n; + } + else if (servpoll[i].events != 0) + cont = true; + + if (! cont && ! z_valid) + break; + } + + c.x = 0xffffffff; + c.y = 0xffffffff; + for (cnt = 0; cnt < nserv; ++cnt) + { + TEMP_FAILURE_RETRY (write (servpoll[cnt].fd, &c, sizeof (c))); + close (servpoll[cnt].fd); + } + + return NULL; +} + + +static void * +server (void *arg) +{ + struct sockaddr_un cliaddr; + socklen_t clilen; + int clisock = TEMP_FAILURE_RETRY (accept (sock, &cliaddr, &clilen)); + + if (clisock == -1) + { + puts ("accept failed"); + return NULL; + } + + while (1) + { + struct coord c; + + if (TEMP_FAILURE_RETRY (read (clisock, &c, sizeof (c))) != sizeof (c)) + { + printf ("server read failed: %m (%d)\n", errno); + break; + } + + if (c.x == 0xffffffff && c.y == 0xffffffff) + break; + + unsigned int rnds = 0; + complex double z = c.z; + while (cabs (z) < 4.0) + { + z = z * z - 1; + if (++rnds == 255) + break; + } + + unsigned int vals[3] = { c.x, c.y, rnds }; + if (TEMP_FAILURE_RETRY (write (clisock, vals, sizeof (vals))) + != sizeof (vals)) + { + puts ("server write error"); + return NULL; + } + } + + close (clisock); + + return NULL; +} + + +static const char *outfilename = "test.png"; + + +static const struct argp_option options[] = + { + { "clients", 'c', "NUMBER", 0, "Number of client threads" }, + { "servers", 's', "NUMBER", 0, "Number of server threads per client" }, + { "timing", 'T', NULL, 0, + "Measure time from startup to the last thread finishing" }, + { NULL, 0, NULL, 0, NULL } + }; + +/* Prototype for option handler. */ +static error_t parse_opt (int key, char *arg, struct argp_state *state); + +/* Data structure to communicate with argp functions. */ +static struct argp argp = +{ + options, parse_opt +}; + + +int +main (int argc, char *argv[]) +{ + int cnt; + FILE *outfile; + struct sockaddr_un servaddr; + socklen_t servlen; + int remaining; + + /* Parse and process arguments. */ + argp_parse (&argp, argc, argv, 0, &remaining, NULL); + + + pthread_t servth[nservers * nclients]; + pthread_t clntth[nclients]; + struct thread_param clntparam[nclients]; + + + image = gdImageCreate (size_x, size_y); + if (image == NULL) + { + puts ("gdImageCreate failed"); + return 1; + } + + for (cnt = 0; cnt < 255; ++cnt) + colors[cnt] = gdImageColorAllocate (image, 256 - cnt, 256 - cnt, + 256 - cnt); + /* Black. */ + colors[cnt] = gdImageColorAllocate (image, 0, 0, 0); + + + sock = socket (AF_UNIX, SOCK_STREAM, 0); + if (sock < 0) + error (EXIT_FAILURE, errno, "cannot create socket"); + + memset (&servaddr, '\0', sizeof (servaddr)); + servaddr.sun_family = AF_UNIX; + strncpy (servaddr.sun_path, PATH, sizeof (servaddr.sun_path)); + servlen = offsetof (struct sockaddr_un, sun_path) + strlen (PATH) + 1; + + if (bind (sock, &servaddr, servlen) == -1) + error (EXIT_FAILURE, errno, "bind failed"); + + listen (sock, SOMAXCONN); + + pthread_mutex_init (&image_lock, NULL); + + + struct sigaction sa; + sa.sa_handler = SIG_IGN; + sigemptyset (&sa.sa_mask); + sa.sa_flags = 0; + + clockid_t cl; + struct timespec start_time; + if (timing) + { + if (clock_getcpuclockid (0, &cl) != 0 + || clock_gettime (cl, &start_time) != 0) + timing = false; + } + + /* Start the servers. */ + for (cnt = 0; cnt < nservers * nclients; ++cnt) + { + if (pthread_create (&servth[cnt], NULL, server, NULL) != 0) + { + puts ("pthread_create for server failed"); + exit (1); + } + } + + for (cnt = 0; cnt < nclients; ++cnt) + { + clntparam[cnt].from = cnt * (size_x * size_y) / nclients; + clntparam[cnt].to = MIN ((cnt + 1) * (size_x * size_y) / nclients, + size_x * size_y); + clntparam[cnt].nserv = nservers; + + if (pthread_create (&clntth[cnt], NULL, client, &clntparam[cnt]) != 0) + { + puts ("pthread_create for client failed"); + exit (1); + } + } + + + /* Wait for the clients. */ + for (cnt = 0; cnt < nclients; ++cnt) + if (pthread_join (clntth[cnt], NULL) != 0) + { + puts ("client pthread_join failed"); + exit (1); + } + + /* Wait for the servers. */ + for (cnt = 0; cnt < nclients * nservers; ++cnt) + if (pthread_join (servth[cnt], NULL) != 0) + { + puts ("server pthread_join failed"); + exit (1); + } + + + if (timing) + { + struct timespec end_time; + + if (clock_gettime (cl, &end_time) == 0) + { + end_time.tv_sec -= start_time.tv_sec; + end_time.tv_nsec -= start_time.tv_nsec; + if (end_time.tv_nsec < 0) + { + end_time.tv_nsec += 1000000000; + --end_time.tv_sec; + } + + printf ("\nRuntime: %lu.%09lu seconds\n%d points computed\n", + (unsigned long int) end_time.tv_sec, + (unsigned long int) end_time.tv_nsec, + points); + } + } + + + outfile = fopen (outfilename, "w"); + if (outfile == NULL) + error (EXIT_FAILURE, errno, "cannot open output file '%s'", outfilename); + + gdImagePng (image, outfile); + + fclose (outfile); + + unlink (PATH); + + return 0; +} + + +/* Handle program arguments. */ +static error_t +parse_opt (int key, char *arg, struct argp_state *state) +{ + switch (key) + { + case 'c': + nclients = strtoul (arg, NULL, 0); + break; + + case 's': + nservers = strtoul (arg, NULL, 0); + break; + + case 'T': + timing = true; + break; + + default: + return ARGP_ERR_UNKNOWN; + } + + return 0; +} + + +static hp_timing_t +get_clockfreq (void) +{ + /* We read the information from the /proc filesystem. It contains at + least one line like + cpu MHz : 497.840237 + or also + cpu MHz : 497.841 + We search for this line and convert the number in an integer. */ + static hp_timing_t result; + int fd; + + /* If this function was called before, we know the result. */ + if (result != 0) + return result; + + fd = open ("/proc/cpuinfo", O_RDONLY); + if (__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 index 0000000000..9cffca83e6 --- /dev/null +++ b/nptl/sysdeps/generic/lowlevellock.h @@ -0,0 +1,89 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <atomic.h> + + +/* Implement generic mutex. Basic futex syscall support is required: + + lll_futex_wait(futex, value) - call sys_futex with FUTEX_WAIT + and third parameter VALUE + + lll_futex_wake(futex, value) - call sys_futex with FUTEX_WAKE + and third parameter VALUE +*/ + + +/* Mutex lock counter: + bit 31 clear means unlocked; + bit 31 set means locked. + + All code that looks at bit 31 first increases the 'number of + interested threads' usage counter, which is in bits 0-30. + + All negative mutex values indicate that the mutex is still locked. */ + + +static inline void +__generic_mutex_lock (int *mutex) +{ + unsigned int v; + + /* Bit 31 was clear, we got the mutex. (this is the fastpath). */ + if (atomic_bit_test_set (mutex, 31) == 0) + return; + + atomic_increment (mutex); + + while (1) + { + if (atomic_bit_test_set (mutex, 31) == 0) + { + atomic_decrement (mutex); + return; + } + + /* We have to wait now. First make sure the futex value we are + monitoring is truly negative (i.e. locked). */ + v = *mutex; + if (v >= 0) + continue; + + lll_futex_wait (mutex, v); + } +} + + +static inline void +__generic_mutex_unlock (int *mutex) +{ + /* Adding 0x80000000 to the counter results in 0 if and only if + there are not other interested threads - we can return (this is + the fastpath). */ + if (atomic_add_zero (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 index 0000000000..59d9590e6e --- /dev/null +++ b/nptl/sysdeps/generic/pt-raise.c @@ -0,0 +1,30 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <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 index 0000000000..7eb7573265 --- /dev/null +++ b/nptl/sysdeps/i386/i686/bits/atomic.h @@ -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 index 0000000000..881976c4fe --- /dev/null +++ b/nptl/sysdeps/i386/i686/pthread_spin_trylock.S @@ -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 index 0000000000..4025ed8d21 --- /dev/null +++ b/nptl/sysdeps/i386/i686/tls.h @@ -0,0 +1,36 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _TLS_H + +/* Additional definitions for <tls.h> on i686 and up. */ + + +/* Macros to load from and store into segment registers. We can use + the 32-bit instructions. */ +#define TLS_GET_GS() \ + ({ int __seg; __asm ("movl %%gs, %0" : "=q" (__seg)); __seg; }) +#define TLS_SET_GS(val) \ + __asm ("movl %0, %%gs" :: "q" (val)) + + +/* Get the full set of definitions. */ +#include "../tls.h" + +#endif /* tls.h */ diff --git a/nptl/sysdeps/i386/pthread_sigmask.c b/nptl/sysdeps/i386/pthread_sigmask.c new file mode 100644 index 0000000000..2ae9198c02 --- /dev/null +++ b/nptl/sysdeps/i386/pthread_sigmask.c @@ -0,0 +1,34 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <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 index 0000000000..4d0109cf02 --- /dev/null +++ b/nptl/sysdeps/i386/pthread_spin_destroy.c @@ -0,0 +1,29 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" + + +int +pthread_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 index 0000000000..0a47981aa2 --- /dev/null +++ b/nptl/sysdeps/i386/pthread_spin_init.c @@ -0,0 +1,20 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* Not needed. pthread_spin_init is an alias for pthread_spin_unlock. */ diff --git a/nptl/sysdeps/i386/pthread_spin_lock.c b/nptl/sysdeps/i386/pthread_spin_lock.c new file mode 100644 index 0000000000..43a1831131 --- /dev/null +++ b/nptl/sysdeps/i386/pthread_spin_lock.c @@ -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 index 0000000000..d94f1e7b8c --- /dev/null +++ b/nptl/sysdeps/i386/pthread_spin_unlock.S @@ -0,0 +1,32 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + + .globl pthread_spin_unlock + .type pthread_spin_unlock,@function + .align 16 +pthread_spin_unlock: + movl 4(%esp), %eax + movl $1, (%eax) + xorl %eax, %eax + ret + .size pthread_spin_unlock,.-pthread_spin_unlock + + /* The implementation of pthread_spin_init is identical. */ + .globl pthread_spin_init +pthread_spin_init = pthread_spin_unlock diff --git a/nptl/sysdeps/i386/pthreaddef.h b/nptl/sysdeps/i386/pthreaddef.h new file mode 100644 index 0000000000..6efa1b6d82 --- /dev/null +++ b/nptl/sysdeps/i386/pthreaddef.h @@ -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 index 0000000000..244a487bcb --- /dev/null +++ b/nptl/sysdeps/i386/tls.h @@ -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 index 0000000000..fade787877 --- /dev/null +++ b/nptl/sysdeps/pthread/Makefile @@ -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 index 0000000000..4d1f4d876b --- /dev/null +++ b/nptl/sysdeps/pthread/Subdirs @@ -0,0 +1 @@ +nptl_db diff --git a/nptl/sysdeps/pthread/allocalim.h b/nptl/sysdeps/pthread/allocalim.h new file mode 100644 index 0000000000..2d666c0b0a --- /dev/null +++ b/nptl/sysdeps/pthread/allocalim.h @@ -0,0 +1,29 @@ +/* Determine whether block of given size can be allocated on the stack or not. + Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU 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 index 0000000000..0001676a3b --- /dev/null +++ b/nptl/sysdeps/pthread/bits/libc-lock.h @@ -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 index 0000000000..df2bcac291 --- /dev/null +++ b/nptl/sysdeps/pthread/bits/sigthread.h @@ -0,0 +1,38 @@ +/* Signal handling function for threaded programs. + Copyright (C) 1998, 1999, 2000, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU 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 index 0000000000..1d6a4cfa65 --- /dev/null +++ b/nptl/sysdeps/pthread/list.h @@ -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 index 0000000000..6710291b9b --- /dev/null +++ b/nptl/sysdeps/pthread/posix-timer.h @@ -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 index 0000000000..55d9f31562 --- /dev/null +++ b/nptl/sysdeps/pthread/pt-initfini.c @@ -0,0 +1,124 @@ +/* Special .init and .fini section support. Linuxthread version. + Copyright (C) 1995, 1996, 1997, 2000, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it + and/or modify it under the terms of the GNU 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 index 0000000000..d6b0966d40 --- /dev/null +++ b/nptl/sysdeps/pthread/pthread.h @@ -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 index 0000000000..62761f9d7a --- /dev/null +++ b/nptl/sysdeps/pthread/pthread_getcpuclockid.c @@ -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 index 0000000000..9b2cef8645 --- /dev/null +++ b/nptl/sysdeps/pthread/pthread_once.c @@ -0,0 +1,54 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" +#include <lowlevellock.h> + + + +static lll_lock_t once_lock = LLL_LOCK_INITIALIZER; + + +int +__pthread_once (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 index 0000000000..8ec7cf81ee --- /dev/null +++ b/nptl/sysdeps/pthread/pthread_sigmask.c @@ -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 index 0000000000..c3f6f435dd --- /dev/null +++ b/nptl/sysdeps/pthread/sigaction.c @@ -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 index 0000000000..b34f70e8c1 --- /dev/null +++ b/nptl/sysdeps/pthread/timer_create.c @@ -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 index 0000000000..48ba1f2726 --- /dev/null +++ b/nptl/sysdeps/pthread/timer_delete.c @@ -0,0 +1,70 @@ +/* Copyright (C) 2000, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Kaz Kylheku <kaz@ashi.footprints.net>. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <assert.h> +#include <errno.h> +#include <pthread.h> +#include <time.h> + +#include "posix-timer.h" + + +/* Delete timer TIMERID. */ +int +timer_delete (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 index 0000000000..f3e22215b2 --- /dev/null +++ b/nptl/sysdeps/pthread/timer_getoverr.c @@ -0,0 +1,45 @@ +/* Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Kaz Kylheku <kaz@ashi.footprints.net>. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <errno.h> +#include <pthread.h> +#include <time.h> + +#include "posix-timer.h" + + +/* Get expiration overrun for timer TIMERID. */ +int +timer_getoverrun (timerid) + timer_t timerid; +{ + struct timer_node *timer; + int retval = -1; + + pthread_mutex_lock (&__timer_mutex); + + if (! timer_valid (timer = timer_id2ptr (timerid))) + __set_errno (EINVAL); + else + retval = timer->overrun_count; + + pthread_mutex_unlock (&__timer_mutex); + + return retval; +} diff --git a/nptl/sysdeps/pthread/timer_gettime.c b/nptl/sysdeps/pthread/timer_gettime.c new file mode 100644 index 0000000000..99a080311c --- /dev/null +++ b/nptl/sysdeps/pthread/timer_gettime.c @@ -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 index 0000000000..ddd8afe988 --- /dev/null +++ b/nptl/sysdeps/pthread/timer_routines.c @@ -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 index 0000000000..592b5271ba --- /dev/null +++ b/nptl/sysdeps/pthread/timer_settime.c @@ -0,0 +1,137 @@ +/* Copyright (C) 2000, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Kaz Kylheku <kaz@ashi.footprints.net>. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <errno.h> +#include <pthread.h> +#include <time.h> + +#include "posix-timer.h" + + +/* Set timer TIMERID to VALUE, returning old value in OVLAUE. */ +int +timer_settime (timerid, flags, value, ovalue) + timer_t timerid; + int flags; + const struct itimerspec *value; + struct itimerspec *ovalue; +{ + struct timer_node *timer; + struct thread_node *thread = NULL; + struct timespec now; + int have_now = 0, need_wakeup = 0; + int retval = -1; + + timer = timer_id2ptr (timerid); + if (timer == NULL) + { + __set_errno (EINVAL); + goto bail; + } + + if (value->it_interval.tv_nsec < 0 + || value->it_interval.tv_nsec >= 1000000000 + || value->it_value.tv_nsec < 0 + || value->it_value.tv_nsec >= 1000000000) + { + __set_errno (EINVAL); + goto bail; + } + + /* Will need to know current time since this is a relative timer; + might as well make the system call outside of the lock now! */ + + if ((flags & TIMER_ABSTIME) == 0) + { + clock_gettime (timer->clock, &now); + have_now = 1; + } + + pthread_mutex_lock (&__timer_mutex); + timer_addref (timer); + + /* One final check of timer validity; this one is possible only + until we have the mutex, because it accesses the inuse flag. */ + + if (! timer_valid(timer)) + { + __set_errno (EINVAL); + goto unlock_bail; + } + + if (ovalue != NULL) + { + ovalue->it_interval = timer->value.it_interval; + + if (timer->armed) + { + if (! have_now) + { + pthread_mutex_unlock (&__timer_mutex); + clock_gettime (timer->clock, &now); + have_now = 1; + pthread_mutex_lock (&__timer_mutex); + timer_addref (timer); + } + + timespec_sub (&ovalue->it_value, &timer->expirytime, &now); + } + else + { + ovalue->it_value.tv_sec = 0; + ovalue->it_value.tv_nsec = 0; + } + } + + timer->value = *value; + + list_unlink_ip (&timer->links); + timer->armed = 0; + + thread = timer->thread; + + /* A value of { 0, 0 } causes the timer to be stopped. */ + if (value->it_value.tv_sec != 0 + || __builtin_expect (value->it_value.tv_nsec != 0, 1)) + { + if ((flags & TIMER_ABSTIME) != 0) + /* The user specified the expiration time. */ + timer->expirytime = value->it_value; + else + timespec_add (&timer->expirytime, &now, &value->it_value); + + /* Only need to wake up the thread if timer is inserted + at the head of the queue. */ + if (thread != NULL) + need_wakeup = __timer_thread_queue_timer (thread, timer); + timer->armed = 1; + } + + retval = 0; + +unlock_bail: + timer_delref (timer); + pthread_mutex_unlock (&__timer_mutex); + +bail: + if (thread != NULL && need_wakeup) + __timer_thread_wakeup (thread); + + return retval; +} diff --git a/nptl/sysdeps/pthread/tst-timer.c b/nptl/sysdeps/pthread/tst-timer.c new file mode 100644 index 0000000000..7417bcd5f0 --- /dev/null +++ b/nptl/sysdeps/pthread/tst-timer.c @@ -0,0 +1,114 @@ +/* Tests for POSIX timer implementation. + Copyright (C) 2000, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Kaz Kylheku <kaz@ashi.footprints.net>. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <errno.h> +#include <signal.h> +#include <stdio.h> +#include <time.h> +#include <unistd.h> + + +static void +notify_func (union sigval sigval) +{ + puts ("notify_func"); +} + + +static void +signal_func (int sig) +{ + static const char text[] = "signal_func\n"; + signal (sig, signal_func); + write (STDOUT_FILENO, text, sizeof text - 1); +} + +static void +intr_sleep (int sec) +{ + struct timespec ts; + + ts.tv_sec = sec; + ts.tv_nsec = 0; + + while (nanosleep (&ts, &ts) == -1 && errno == EINTR) + ; +} + +#define ZSIGALRM 14 + + +int +main (void) +{ + struct timespec ts; + timer_t timer_sig, timer_thr1, timer_thr2; + int retval; + struct sigevent sigev1 = + { + .sigev_notify = SIGEV_SIGNAL, + .sigev_signo = ZSIGALRM + }; + struct sigevent sigev2; + struct itimerspec itimer1 = { { 0, 200000000 }, { 0, 200000000 } }; + struct itimerspec itimer2 = { { 0, 100000000 }, { 0, 500000000 } }; + struct itimerspec itimer3 = { { 0, 150000000 }, { 0, 300000000 } }; + struct itimerspec old; + + retval = clock_gettime (CLOCK_REALTIME, &ts); + + sigev2.sigev_notify = SIGEV_THREAD; + sigev2.sigev_notify_function = notify_func; + sigev2.sigev_notify_attributes = NULL; + + setvbuf (stdout, 0, _IOLBF, 0); + + printf ("clock_gettime returned %d, timespec = { %ld, %ld }\n", + retval, ts.tv_sec, ts.tv_nsec); + + retval = clock_getres (CLOCK_REALTIME, &ts); + + printf ("clock_getres returned %d, timespec = { %ld, %ld }\n", + retval, ts.tv_sec, ts.tv_nsec); + + timer_create (CLOCK_REALTIME, &sigev1, &timer_sig); + timer_create (CLOCK_REALTIME, &sigev2, &timer_thr1); + timer_create (CLOCK_REALTIME, &sigev2, &timer_thr2); + + timer_settime (timer_thr1, 0, &itimer2, &old); + timer_settime (timer_thr2, 0, &itimer3, &old); + + signal (ZSIGALRM, signal_func); + + timer_settime (timer_sig, 0, &itimer1, &old); + + timer_delete (-1); + + intr_sleep (3); + + timer_delete (timer_sig); + timer_delete (timer_thr1); + + intr_sleep (3); + + timer_delete (timer_thr2); + + return 0; +} diff --git a/nptl/sysdeps/unix/sysv/linux/Implies b/nptl/sysdeps/unix/sysv/linux/Implies new file mode 100644 index 0000000000..f1b3e8939c --- /dev/null +++ b/nptl/sysdeps/unix/sysv/linux/Implies @@ -0,0 +1 @@ +pthread diff --git a/nptl/sysdeps/unix/sysv/linux/Makefile b/nptl/sysdeps/unix/sysv/linux/Makefile new file mode 100644 index 0000000000..efe4ba4e9d --- /dev/null +++ b/nptl/sysdeps/unix/sysv/linux/Makefile @@ -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 index 0000000000..117598c95f --- /dev/null +++ b/nptl/sysdeps/unix/sysv/linux/Versions @@ -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 index 0000000000..5badaea9ec --- /dev/null +++ b/nptl/sysdeps/unix/sysv/linux/allocrtsig.c @@ -0,0 +1,54 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <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 index 0000000000..63de09a1b0 --- /dev/null +++ b/nptl/sysdeps/unix/sysv/linux/bits/local_lim.h @@ -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 index 0000000000..8274f516be --- /dev/null +++ b/nptl/sysdeps/unix/sysv/linux/bits/posix_opt.h @@ -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 index 0000000000..229414dd74 --- /dev/null +++ b/nptl/sysdeps/unix/sysv/linux/configure @@ -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 index 0000000000..ff00261404 --- /dev/null +++ b/nptl/sysdeps/unix/sysv/linux/fork-gen.c @@ -0,0 +1,37 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <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 index 0000000000..c1aa23c5c5 --- /dev/null +++ b/nptl/sysdeps/unix/sysv/linux/fork.c @@ -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 index 0000000000..85722a59eb --- /dev/null +++ b/nptl/sysdeps/unix/sysv/linux/fork.h @@ -0,0 +1,60 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <list.h> +#include <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 index 0000000000..2167bbb988 --- /dev/null +++ b/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h @@ -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 index 0000000000..ab46ac099b --- /dev/null +++ b/nptl/sysdeps/unix/sysv/linux/i386/bits/semaphore.h @@ -0,0 +1,39 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _SEMAPHORE_H +# error "Never use <bits/semaphore.h> directly; include <semaphore.h> instead." +#endif + + +#define __SIZEOF_SEM_T 16 + + +/* Value returned if `sem_open' failed. */ +#define SEM_FAILED ((sem_t *) 0) + +/* Maximum value the semaphore can have. */ +#define SEM_VALUE_MAX ((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 index 0000000000..3196a8c754 --- /dev/null +++ b/nptl/sysdeps/unix/sysv/linux/i386/createthread.c @@ -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 index 0000000000..813e5299a6 --- /dev/null +++ b/nptl/sysdeps/unix/sysv/linux/i386/fork.c @@ -0,0 +1,31 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sched.h> +#include <signal.h> +#include <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 index 0000000000..9e2b9fec8d --- /dev/null +++ b/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevelcond.S @@ -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 index 0000000000..400413d7c2 --- /dev/null +++ b/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S @@ -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 index 0000000000..a48cd88fa8 --- /dev/null +++ b/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevelmutex.S @@ -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 index 0000000000..2dde246d1f --- /dev/null +++ b/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevelrwlock.S @@ -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 index 0000000000..18fb16f6f6 --- /dev/null +++ b/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevelsem.S @@ -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 index 0000000000..a385adc5f9 --- /dev/null +++ b/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_barrier_wait.S @@ -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 index 0000000000..3dc8403a29 --- /dev/null +++ b/nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevelcond.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/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 index 0000000000..e60dea89ef --- /dev/null +++ b/nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevellock.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/lowlevellock.S" diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevelmutex.S b/nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevelmutex.S new file mode 100644 index 0000000000..50481991ff --- /dev/null +++ b/nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevelmutex.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/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 index 0000000000..6f4a8305ee --- /dev/null +++ b/nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevelrwlock.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/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 index 0000000000..cfaa36ac74 --- /dev/null +++ b/nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevelsem.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/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 index 0000000000..6d20b9a95c --- /dev/null +++ b/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_barrier_wait.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/pthread_barrier_wait.S" diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevelcond.S b/nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevelcond.S new file mode 100644 index 0000000000..3dc8403a29 --- /dev/null +++ b/nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevelcond.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/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 index 0000000000..e60dea89ef --- /dev/null +++ b/nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevellock.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/lowlevellock.S" diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevelmutex.S b/nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevelmutex.S new file mode 100644 index 0000000000..50481991ff --- /dev/null +++ b/nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevelmutex.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/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 index 0000000000..6f4a8305ee --- /dev/null +++ b/nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevelrwlock.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/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 index 0000000000..cfaa36ac74 --- /dev/null +++ b/nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevelsem.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/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 index 0000000000..6d20b9a95c --- /dev/null +++ b/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_barrier_wait.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/pthread_barrier_wait.S" diff --git a/nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h b/nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h new file mode 100644 index 0000000000..71babd5c93 --- /dev/null +++ b/nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h @@ -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 index 0000000000..bd5f96402b --- /dev/null +++ b/nptl/sysdeps/unix/sysv/linux/i386/lowlevelsem.h @@ -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 index 0000000000..6994c0d7fa --- /dev/null +++ b/nptl/sysdeps/unix/sysv/linux/i386/pt-vfork.S @@ -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 index 0000000000..747c8ec2d2 --- /dev/null +++ b/nptl/sysdeps/unix/sysv/linux/i386/pthread_once.S @@ -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 index 0000000000..24ead1b5ce --- /dev/null +++ b/nptl/sysdeps/unix/sysv/linux/internaltypes.h @@ -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 index 0000000000..0fd3c9aa58 --- /dev/null +++ b/nptl/sysdeps/unix/sysv/linux/jmp-unwind.c @@ -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 index 0000000000..a1e228ee29 --- /dev/null +++ b/nptl/sysdeps/unix/sysv/linux/pt-fork.c @@ -0,0 +1,28 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <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 index 0000000000..0c68960e5d --- /dev/null +++ b/nptl/sysdeps/unix/sysv/linux/pt-raise.c @@ -0,0 +1,31 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <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 index 0000000000..f5c2377e7e --- /dev/null +++ b/nptl/sysdeps/unix/sysv/linux/pthread_kill.c @@ -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 index 0000000000..5aecffcf0d --- /dev/null +++ b/nptl/sysdeps/unix/sysv/linux/pthread_yield.c @@ -0,0 +1,30 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <sched.h> + + +/* With the 1-on-1 model we implement this function is equivalent to + the 'sched_yield' function. */ +int +pthread_yield (void) +{ + return sched_yield (); +} diff --git a/nptl/sysdeps/unix/sysv/linux/raise.c b/nptl/sysdeps/unix/sysv/linux/raise.c new file mode 100644 index 0000000000..009f32ad30 --- /dev/null +++ b/nptl/sysdeps/unix/sysv/linux/raise.c @@ -0,0 +1,39 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <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 index 0000000000..ef70dde8a2 --- /dev/null +++ b/nptl/sysdeps/unix/sysv/linux/register-atfork.c @@ -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 index 0000000000..470f80d05c --- /dev/null +++ b/nptl/sysdeps/unix/sysv/linux/unregister-atfork.c @@ -0,0 +1,49 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <stdlib.h> +#include "fork.h" + + +void +__unregister_atfork (dso_handle) + void *dso_handle; +{ + /* Get the lock to not conflict with running forks. */ + 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 index 0000000000..25bd3f2f09 --- /dev/null +++ b/nptl/tst-atfork1.c @@ -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 index 0000000000..2859fb4cab --- /dev/null +++ b/nptl/tst-barrier1.c @@ -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 index 0000000000..5b620b7407 --- /dev/null +++ b/nptl/tst-barrier2.c @@ -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 index 0000000000..b5478f8277 --- /dev/null +++ b/nptl/tst-barrier3.c @@ -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 index 0000000000..36ae767db0 --- /dev/null +++ b/nptl/tst-basic1.c @@ -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 index 0000000000..ffb19289b8 --- /dev/null +++ b/nptl/tst-basic2.c @@ -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 index 0000000000..99a8339f0c --- /dev/null +++ b/nptl/tst-cancel1.c @@ -0,0 +1,150 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + + +static pthread_mutex_t m1 = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t m2 = PTHREAD_MUTEX_INITIALIZER; + +static int cntr; + + +static void +cleanup (void *arg) +{ + if (arg != (void *) 42l) + cntr = 42; + else + cntr = 1; +} + + +static void * +tf (void *arg) +{ + int err; + + pthread_cleanup_push (cleanup, (void *) 42l); + + err = pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL); + if (err != 0) + { + printf ("setcanceltype failed: %s\n", strerror (err)); + exit (1); + } + + err = pthread_mutex_unlock (&m2); + if (err != 0) + { + printf ("child: mutex_unlock failed: %s\n", strerror (err)); + exit (1); + } + + err = pthread_mutex_lock (&m1); + if (err != 0) + { + printf ("child: 1st mutex_lock failed: %s\n", strerror (err)); + exit (1); + } + + /* We should never come here. */ + + pthread_cleanup_pop (0); + + return NULL; +} + + +static int +do_test (void) +{ + int err; + pthread_t th; + int result = 0; + void *retval; + + /* Get the mutexes. */ + err = pthread_mutex_lock (&m1); + if (err != 0) + { + printf ("parent: 1st mutex_lock failed: %s\n", strerror (err)); + return 1; + } + err = pthread_mutex_lock (&m2); + if (err != 0) + { + printf ("parent: 2nd mutex_lock failed: %s\n", strerror (err)); + return 1; + } + + err = pthread_create (&th, NULL, tf, NULL); + if (err != 0) + { + printf ("create failed: %s\n", strerror (err)); + return 1; + } + + err = pthread_mutex_lock (&m2); + if (err != 0) + { + printf ("parent: 3rd mutex_lock failed: %s\n", strerror (err)); + return 1; + } + + err = pthread_cancel (th); + if (err != 0) + { + printf ("cancel failed: %s\n", strerror (err)); + return 1; + } + + err = pthread_join (th, &retval); + if (err != 0) + { + printf ("join failed: %s\n", strerror (err)); + return 1; + } + + if (retval != PTHREAD_CANCELED) + { + printf ("wrong return value: %p\n", retval); + result = 1; + } + + if (cntr == 42) + { + puts ("cleanup handler called with wrong argument"); + result = 1; + } + else if (cntr != 1) + { + puts ("cleanup handling not called"); + result = 1; + } + + return result; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/nptl/tst-cancel2.c b/nptl/tst-cancel2.c new file mode 100644 index 0000000000..6d80f8ae5e --- /dev/null +++ b/nptl/tst-cancel2.c @@ -0,0 +1,100 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <unistd.h> + + +static int fd[2]; + + +static void * +tf (void *arg) +{ + /* The buffer size must be larger than the pipe size so that the + write blocks. */ + char buf[100000]; + + if (write (fd[1], buf, sizeof (buf)) == sizeof (buf)) + { + puts ("write succeeded"); + return (void *) 1l; + } + + return (void *) 42l; +} + + +static int +do_test (void) +{ + pthread_t th; + void *r; + struct sigaction sa; + + sa.sa_handler = SIG_IGN; + sigemptyset (&sa.sa_mask); + sa.sa_flags = 0; + + if (sigaction (SIGPIPE, &sa, NULL) != 0) + { + puts ("sigaction failed"); + return 1; + } + + if (pipe (fd) != 0) + { + puts ("pipe failed"); + return 1; + } + + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + return 1; + } + + if (pthread_cancel (th) != 0) + { + puts ("cancel failed"); + return 1; + } + + /* This will cause the write in the child to return. */ + close (fd[0]); + + if (pthread_join (th, &r) != 0) + { + puts ("join failed"); + return 1; + } + + if (r != PTHREAD_CANCELED) + { + printf ("result is wrong: expected %p, got %p\n", PTHREAD_CANCELED, r); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/nptl/tst-cancel3.c b/nptl/tst-cancel3.c new file mode 100644 index 0000000000..86c482bcc1 --- /dev/null +++ b/nptl/tst-cancel3.c @@ -0,0 +1,98 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <unistd.h> + + +static int fd[2]; + + +static void * +tf (void *arg) +{ + char buf[100]; + + if (read (fd[0], buf, sizeof (buf)) == sizeof (buf)) + { + puts ("read succeeded"); + return (void *) 1l; + } + + return NULL; +} + + +static int +do_test (void) +{ + pthread_t th; + void *r; + struct sigaction sa; + + sa.sa_handler = SIG_IGN; + sigemptyset (&sa.sa_mask); + sa.sa_flags = 0; + + if (sigaction (SIGPIPE, &sa, NULL) != 0) + { + puts ("sigaction failed"); + return 1; + } + + if (pipe (fd) != 0) + { + puts ("pipe failed"); + return 1; + } + + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + return 1; + } + + if (pthread_cancel (th) != 0) + { + puts ("cancel failed"); + return 1; + } + + /* This will cause the read in the child to return. */ + close (fd[0]); + + if (pthread_join (th, &r) != 0) + { + puts ("join failed"); + return 1; + } + + if (r != PTHREAD_CANCELED) + { + puts ("result is wrong"); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/nptl/tst-cancel4.c b/nptl/tst-cancel4.c new file mode 100644 index 0000000000..371f2f7f26 --- /dev/null +++ b/nptl/tst-cancel4.c @@ -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 index 0000000000..46085c2b7c --- /dev/null +++ b/nptl/tst-cond1.c @@ -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 index 0000000000..d1f3d0fd38 --- /dev/null +++ b/nptl/tst-cond2.c @@ -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 index 0000000000..cb9eb85585 --- /dev/null +++ b/nptl/tst-cond3.c @@ -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 index 0000000000..ffc83c7668 --- /dev/null +++ b/nptl/tst-cond4.c @@ -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 index 0000000000..efa207b5dc --- /dev/null +++ b/nptl/tst-cond5.c @@ -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 index 0000000000..63c54705db --- /dev/null +++ b/nptl/tst-cond6.c @@ -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 index 0000000000..0448a059d1 --- /dev/null +++ b/nptl/tst-exec1.c @@ -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 index 0000000000..0fa80eff5e --- /dev/null +++ b/nptl/tst-exec2.c @@ -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 index 0000000000..eb9c721244 --- /dev/null +++ b/nptl/tst-exec3.c @@ -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 index 0000000000..5113f2dd2d --- /dev/null +++ b/nptl/tst-exit1.c @@ -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 index 0000000000..ed2472d3a0 --- /dev/null +++ b/nptl/tst-flock1.c @@ -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 index 0000000000..52d02dc9bb --- /dev/null +++ b/nptl/tst-flock2.c @@ -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 index 0000000000..56ffe50d9e --- /dev/null +++ b/nptl/tst-fork1.c @@ -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 index 0000000000..95a78ba0b5 --- /dev/null +++ b/nptl/tst-join1.c @@ -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 index 0000000000..2cfab8b0e8 --- /dev/null +++ b/nptl/tst-join2.c @@ -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 index 0000000000..df1135fb5b --- /dev/null +++ b/nptl/tst-join3.c @@ -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 index 0000000000..dfbe58417a --- /dev/null +++ b/nptl/tst-key1.c @@ -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 index 0000000000..c5493322c5 --- /dev/null +++ b/nptl/tst-key2.c @@ -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 index 0000000000..73cb7417ad --- /dev/null +++ b/nptl/tst-key3.c @@ -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 index 0000000000..50b5ccaf0e --- /dev/null +++ b/nptl/tst-mutex1.c @@ -0,0 +1,57 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <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 index 0000000000..21948a9f5b --- /dev/null +++ b/nptl/tst-mutex2.c @@ -0,0 +1,100 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <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 index 0000000000..c6c75ca0aa --- /dev/null +++ b/nptl/tst-mutex3.c @@ -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 index 0000000000..5e71d9fbf6 --- /dev/null +++ b/nptl/tst-mutex4.c @@ -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 index 0000000000..cfa8d31568 --- /dev/null +++ b/nptl/tst-mutex5.c @@ -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 index 0000000000..f066c62edc --- /dev/null +++ b/nptl/tst-mutex6.c @@ -0,0 +1,55 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with 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 index 0000000000..9ee8ece939 --- /dev/null +++ b/nptl/tst-mutex7.c @@ -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 index 0000000000..87ed51c821 --- /dev/null +++ b/nptl/tst-once1.c @@ -0,0 +1,51 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <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 index 0000000000..3fbc4a975d --- /dev/null +++ b/nptl/tst-once2.c @@ -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 index 0000000000..c97e0e60f4 --- /dev/null +++ b/nptl/tst-rwlock1.c @@ -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 index 0000000000..6f38682b85 --- /dev/null +++ b/nptl/tst-rwlock2.c @@ -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 index 0000000000..c1cac876d6 --- /dev/null +++ b/nptl/tst-rwlock3.c @@ -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 index 0000000000..2bf54167b6 --- /dev/null +++ b/nptl/tst-rwlock4.c @@ -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 index 0000000000..a04eb2670e --- /dev/null +++ b/nptl/tst-rwlock5.c @@ -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 index 0000000000..f0a96e8965 --- /dev/null +++ b/nptl/tst-rwlock6.c @@ -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 index 0000000000..41e5af3ba8 --- /dev/null +++ b/nptl/tst-rwlock7.c @@ -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 index 0000000000..32d59eb361 --- /dev/null +++ b/nptl/tst-sem1.c @@ -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 index 0000000000..026939ef9b --- /dev/null +++ b/nptl/tst-sem2.c @@ -0,0 +1,54 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <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 index 0000000000..7d3f68f019 --- /dev/null +++ b/nptl/tst-sem3.c @@ -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 index 0000000000..ccffbdd779 --- /dev/null +++ b/nptl/tst-sem4.c @@ -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 index 0000000000..d76c265bf8 --- /dev/null +++ b/nptl/tst-sem5.c @@ -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 index 0000000000..e7480f547a --- /dev/null +++ b/nptl/tst-signal1.c @@ -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 index 0000000000..1c0a4118bd --- /dev/null +++ b/nptl/tst-signal2.c @@ -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 index 0000000000..3de2887545 --- /dev/null +++ b/nptl/tst-signal3.c @@ -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 index 0000000000..259b4b4d6a --- /dev/null +++ b/nptl/tst-spin1.c @@ -0,0 +1,57 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <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 index 0000000000..ff7421ae47 --- /dev/null +++ b/nptl/tst-spin2.c @@ -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 index 0000000000..4437740327 --- /dev/null +++ b/nptl/tst-spin3.c @@ -0,0 +1,55 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with 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 index 0000000000..471e6753e5 --- /dev/null +++ b/nptl/tst-stack1.c @@ -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 index 0000000000..51b2d0cb20 --- /dev/null +++ b/nptl/tst-tsd1.c @@ -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 index 0000000000..66a1128e91 --- /dev/null +++ b/nptl/tst-tsd2.c @@ -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 index 0000000000..4494ce88c7 --- /dev/null +++ b/nptl/tst-unload.c @@ -0,0 +1,45 @@ +/* Tests for non-unloading of libpthread. + Copyright (C) 2000, 2002 Free Software Foundation, Inc. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2000. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU 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 index 0000000000..4812cd2af9 --- /dev/null +++ b/nptl_db/Makefile @@ -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 index 0000000000..4ca8042c12 --- /dev/null +++ b/nptl_db/Versions @@ -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 index 0000000000..9963c3aecd --- /dev/null +++ b/nptl_db/proc_service.h @@ -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 index 0000000000..592f7fa284 --- /dev/null +++ b/nptl_db/shlib-versions @@ -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 index 0000000000..946ff7244e --- /dev/null +++ b/nptl_db/td_init.c @@ -0,0 +1,32 @@ +/* Initialization function of thread debugger support library. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + +int __td_debug; + + +td_err_e +td_init (void) +{ + /* XXX We have to figure out what has to be done. */ + LOG ("td_init"); + return TD_OK; +} diff --git a/nptl_db/td_log.c b/nptl_db/td_log.c new file mode 100644 index 0000000000..52212a0e9f --- /dev/null +++ b/nptl_db/td_log.c @@ -0,0 +1,32 @@ +/* Noop, left for historical reasons. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_log (void) +{ + /* This interface is deprecated in the Sun interface. We provide it + for compatibility but don't do anything ourself. We might in + future do some logging if this seems reasonable. */ + LOG ("td_log"); + return TD_OK; +} diff --git a/nptl_db/td_symbol_list.c b/nptl_db/td_symbol_list.c new file mode 100644 index 0000000000..1be7001d85 --- /dev/null +++ b/nptl_db/td_symbol_list.c @@ -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 index 0000000000..611281fbaa --- /dev/null +++ b/nptl_db/td_ta_clear_event.c @@ -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 index 0000000000..57b90e57f2 --- /dev/null +++ b/nptl_db/td_ta_delete.c @@ -0,0 +1,42 @@ +/* Detach to target process. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <stdlib.h> + +#include "thread_dbP.h" + + +td_err_e +td_ta_delete (td_thragent_t *ta) +{ + LOG ("td_ta_delete"); + + /* Safety check. Note that the test will also fail for TA == NULL. */ + if (!ta_ok (ta)) + return TD_BADTA; + + /* Remove the handle from the list. */ + list_del (&ta->list); + + /* The handle was allocated in `td_ta_new'. */ + free (ta); + + return TD_OK; +} diff --git a/nptl_db/td_ta_enable_stats.c b/nptl_db/td_ta_enable_stats.c new file mode 100644 index 0000000000..ec7014ad2d --- /dev/null +++ b/nptl_db/td_ta_enable_stats.c @@ -0,0 +1,35 @@ +/* Enable collection of statistics for process. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_ta_enable_stats (const td_thragent_t *ta, int enable) +{ + /* XXX We have to figure out what has to be done. */ + LOG ("td_ta_enable_stats"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + return TD_OK; +} diff --git a/nptl_db/td_ta_event_addr.c b/nptl_db/td_ta_event_addr.c new file mode 100644 index 0000000000..906835dc73 --- /dev/null +++ b/nptl_db/td_ta_event_addr.c @@ -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 index 0000000000..4e3245d07b --- /dev/null +++ b/nptl_db/td_ta_event_getmsg.c @@ -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 index 0000000000..cfe93d1b19 --- /dev/null +++ b/nptl_db/td_ta_get_nthreads.c @@ -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 index 0000000000..04e01fb73f --- /dev/null +++ b/nptl_db/td_ta_get_ph.c @@ -0,0 +1,36 @@ +/* Get external process handle. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_ta_get_ph (const td_thragent_t *ta, struct ps_prochandle **ph) +{ + LOG ("td_ta_get_ph"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + *ph = ta->ph; + + return TD_OK; +} diff --git a/nptl_db/td_ta_get_stats.c b/nptl_db/td_ta_get_stats.c new file mode 100644 index 0000000000..d5d879c3ee --- /dev/null +++ b/nptl_db/td_ta_get_stats.c @@ -0,0 +1,35 @@ +/* Retrieve statistics for process. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_ta_get_stats (const td_thragent_t *ta, td_ta_stats_t *statsp) +{ + /* XXX We have to figure out what has to be done. */ + LOG ("td_ta_get_stats"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + return TD_OK; +} diff --git a/nptl_db/td_ta_map_id2thr.c b/nptl_db/td_ta_map_id2thr.c new file mode 100644 index 0000000000..189a671713 --- /dev/null +++ b/nptl_db/td_ta_map_id2thr.c @@ -0,0 +1,38 @@ +/* Map thread ID to thread handle. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_ta_map_id2thr (const td_thragent_t *ta, pthread_t pt, td_thrhandle_t *th) +{ + LOG ("td_ta_map_id2thr"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + /* Create the `td_thrhandle_t' object. */ + th->th_ta_p = (td_thragent_t *) ta; + th->th_unique = (psaddr_t) pt; + + return TD_OK; +} diff --git a/nptl_db/td_ta_map_lwp2thr.c b/nptl_db/td_ta_map_lwp2thr.c new file mode 100644 index 0000000000..326b9ee92a --- /dev/null +++ b/nptl_db/td_ta_map_lwp2thr.c @@ -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 index 0000000000..de564edfd8 --- /dev/null +++ b/nptl_db/td_ta_new.c @@ -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 index 0000000000..ea59d2cdaf --- /dev/null +++ b/nptl_db/td_ta_reset_stats.c @@ -0,0 +1,35 @@ +/* Reset statistics. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_ta_reset_stats (const td_thragent_t *ta) +{ + /* XXX We have to figure out what has to be done. */ + LOG ("td_ta_reset_stats"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + return TD_OK; +} diff --git a/nptl_db/td_ta_set_event.c b/nptl_db/td_ta_set_event.c new file mode 100644 index 0000000000..5e2cca795d --- /dev/null +++ b/nptl_db/td_ta_set_event.c @@ -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 index 0000000000..8552ffbe01 --- /dev/null +++ b/nptl_db/td_ta_setconcurrency.c @@ -0,0 +1,35 @@ +/* Set suggested concurrency level for process. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_ta_setconcurrency (const td_thragent_t *ta, int level) +{ + /* This is something LinuxThreads does not need to support. */ + LOG ("td_ta_setconcurrency"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + return TD_NOCAPAB; +} diff --git a/nptl_db/td_ta_thr_iter.c b/nptl_db/td_ta_thr_iter.c new file mode 100644 index 0000000000..ca1c82df6b --- /dev/null +++ b/nptl_db/td_ta_thr_iter.c @@ -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 index 0000000000..cbc2f37c51 --- /dev/null +++ b/nptl_db/td_ta_tsd_iter.c @@ -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 index 0000000000..e729b52706 --- /dev/null +++ b/nptl_db/td_thr_clear_event.c @@ -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 index 0000000000..3fd7943779 --- /dev/null +++ b/nptl_db/td_thr_dbresume.c @@ -0,0 +1,30 @@ +/* Resume execution of given thread. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_thr_dbresume (const td_thrhandle_t *th) +{ + /* XXX We have to figure out what has to be done. */ + LOG ("td_thr_dbresume"); + return TD_NOCAPAB; +} diff --git a/nptl_db/td_thr_dbsuspend.c b/nptl_db/td_thr_dbsuspend.c new file mode 100644 index 0000000000..6ef82ad34f --- /dev/null +++ b/nptl_db/td_thr_dbsuspend.c @@ -0,0 +1,30 @@ +/* Suspend execution of given thread. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_thr_dbsuspend (const td_thrhandle_t *th) +{ + /* XXX We have to figure out what has to be done. */ + LOG ("td_thr_dbsuspend"); + return TD_NOCAPAB; +} diff --git a/nptl_db/td_thr_event_enable.c b/nptl_db/td_thr_event_enable.c new file mode 100644 index 0000000000..e822453e63 --- /dev/null +++ b/nptl_db/td_thr_event_enable.c @@ -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 index 0000000000..ffd0baadc5 --- /dev/null +++ b/nptl_db/td_thr_event_getmsg.c @@ -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 index 0000000000..0686649d54 --- /dev/null +++ b/nptl_db/td_thr_get_info.c @@ -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 index 0000000000..360e1d2f29 --- /dev/null +++ b/nptl_db/td_thr_getfpregs.c @@ -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 index 0000000000..2485e5d6e2 --- /dev/null +++ b/nptl_db/td_thr_getgregs.c @@ -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 index 0000000000..3c77ab6be8 --- /dev/null +++ b/nptl_db/td_thr_getxregs.c @@ -0,0 +1,30 @@ +/* Get a thread's extra state register set. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_thr_getxregs (const td_thrhandle_t *th, void *xregs) +{ + /* XXX This might be platform specific. */ + LOG ("td_thr_getxregs"); + return TD_NOXREGS; +} diff --git a/nptl_db/td_thr_getxregsize.c b/nptl_db/td_thr_getxregsize.c new file mode 100644 index 0000000000..1704e4b0a4 --- /dev/null +++ b/nptl_db/td_thr_getxregsize.c @@ -0,0 +1,30 @@ +/* Get the size of the extra state register set for this architecture. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_thr_getxregsize (const td_thrhandle_t *th, int *sizep) +{ + /* XXX This might be platform specific. */ + LOG ("td_thr_getxregsize"); + return TD_NOXREGS; +} diff --git a/nptl_db/td_thr_set_event.c b/nptl_db/td_thr_set_event.c new file mode 100644 index 0000000000..656728c438 --- /dev/null +++ b/nptl_db/td_thr_set_event.c @@ -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 index 0000000000..e1ec9be66e --- /dev/null +++ b/nptl_db/td_thr_setfpregs.c @@ -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 index 0000000000..d46e32a11e --- /dev/null +++ b/nptl_db/td_thr_setgregs.c @@ -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 index 0000000000..6032b0ed48 --- /dev/null +++ b/nptl_db/td_thr_setprio.c @@ -0,0 +1,30 @@ +/* Set a thread's priority. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_thr_setprio (const td_thrhandle_t *th, int prio) +{ + /* XXX We have to figure out what has to be done. */ + LOG ("td_thr_setprio"); + return TD_OK; +} diff --git a/nptl_db/td_thr_setsigpending.c b/nptl_db/td_thr_setsigpending.c new file mode 100644 index 0000000000..e2c9d7ad26 --- /dev/null +++ b/nptl_db/td_thr_setsigpending.c @@ -0,0 +1,31 @@ +/* Raise a signal for a thread. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_thr_setsigpending (const td_thrhandle_t *th, unsigned char n, + const sigset_t *ss) +{ + /* XXX We have to figure out what has to be done. */ + LOG ("td_thr_setsigpending"); + return TD_OK; +} diff --git a/nptl_db/td_thr_setxregs.c b/nptl_db/td_thr_setxregs.c new file mode 100644 index 0000000000..f48877c78e --- /dev/null +++ b/nptl_db/td_thr_setxregs.c @@ -0,0 +1,30 @@ +/* Set a thread's extra state register set. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_thr_setxregs (const td_thrhandle_t *ta, const void *addr) +{ + /* XXX This might have to be platform specific. */ + LOG ("td_thr_setxregs"); + return TD_NOXREGS; +} diff --git a/nptl_db/td_thr_sigsetmask.c b/nptl_db/td_thr_sigsetmask.c new file mode 100644 index 0000000000..3a68aecd39 --- /dev/null +++ b/nptl_db/td_thr_sigsetmask.c @@ -0,0 +1,30 @@ +/* Set a thread's signal mask. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_thr_sigsetmask (const td_thrhandle_t *th, const sigset_t *ss) +{ + /* XXX We have to figure out what has to be done. */ + LOG ("td_thr_sigsetmask"); + return TD_OK; +} diff --git a/nptl_db/td_thr_tls_get_addr.c b/nptl_db/td_thr_tls_get_addr.c new file mode 100644 index 0000000000..5bbdc50c3f --- /dev/null +++ b/nptl_db/td_thr_tls_get_addr.c @@ -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 index 0000000000..d1a54537ff --- /dev/null +++ b/nptl_db/td_thr_tsd.c @@ -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 index 0000000000..76cbad31cf --- /dev/null +++ b/nptl_db/td_thr_validate.c @@ -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 index 0000000000..acb0607662 --- /dev/null +++ b/nptl_db/thread_db.h @@ -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 index 0000000000..4407143af0 --- /dev/null +++ b/nptl_db/thread_dbP.h @@ -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 */ |