summaryrefslogtreecommitdiff
path: root/libpthread
diff options
context:
space:
mode:
authorEric Andersen <andersen@codepoet.org>2003-02-27 18:13:05 +0000
committerEric Andersen <andersen@codepoet.org>2003-02-27 18:13:05 +0000
commit187dd78d7bd1c03fcf16e54a30314512d38e1a4a (patch)
tree9780638e5286b40da74a128c9f540a9ea720862f /libpthread
parentd4d6e2c50565da18253cd0d6f3332484142b6587 (diff)
Major update for pthreads, based in large part on improvements
from glibc 2.3. This should make threads much more efficient. -Erik
Diffstat (limited to 'libpthread')
-rw-r--r--libpthread/Makefile4
-rw-r--r--libpthread/linuxthreads/condvar.c308
-rw-r--r--libpthread/linuxthreads/internals.h37
-rw-r--r--libpthread/linuxthreads/join.c18
-rw-r--r--libpthread/linuxthreads/manager.c100
-rw-r--r--libpthread/linuxthreads/mutex.c216
-rw-r--r--libpthread/linuxthreads/pthread.c416
-rw-r--r--libpthread/linuxthreads/restart.h26
-rw-r--r--libpthread/linuxthreads/semaphore.c159
-rw-r--r--libpthread/linuxthreads/semaphore.h36
-rw-r--r--libpthread/linuxthreads/signals.c3
-rw-r--r--libpthread/linuxthreads/spinlock.c616
-rw-r--r--libpthread/linuxthreads/spinlock.h132
-rw-r--r--libpthread/linuxthreads/sysdeps/alpha/pt-machine.h45
-rw-r--r--libpthread/linuxthreads/sysdeps/alpha/stackinfo.h28
-rw-r--r--libpthread/linuxthreads/sysdeps/arm/pt-machine.h19
-rw-r--r--libpthread/linuxthreads/sysdeps/arm/sigcontextinfo.h75
-rw-r--r--libpthread/linuxthreads/sysdeps/arm/stackinfo.h28
-rw-r--r--libpthread/linuxthreads/sysdeps/cris/pt-machine.h20
-rw-r--r--libpthread/linuxthreads/sysdeps/cris/stackinfo.h28
-rw-r--r--libpthread/linuxthreads/sysdeps/i386/i686/pt-machine.h38
-rw-r--r--libpthread/linuxthreads/sysdeps/i386/pt-machine.h27
-rw-r--r--libpthread/linuxthreads/sysdeps/i386/sigcontextinfo.h45
-rw-r--r--libpthread/linuxthreads/sysdeps/i386/stackinfo.h28
-rw-r--r--libpthread/linuxthreads/sysdeps/i386/tls.h183
-rw-r--r--libpthread/linuxthreads/sysdeps/i386/useldt.h213
-rw-r--r--libpthread/linuxthreads/sysdeps/m68k/pt-machine.h27
-rw-r--r--libpthread/linuxthreads/sysdeps/m68k/stackinfo.h28
-rw-r--r--libpthread/linuxthreads/sysdeps/mips/pt-machine.h111
-rw-r--r--libpthread/linuxthreads/sysdeps/mips/stackinfo.h28
-rw-r--r--libpthread/linuxthreads/sysdeps/powerpc/pt-machine.h82
-rw-r--r--libpthread/linuxthreads/sysdeps/powerpc/stackinfo.h28
-rw-r--r--libpthread/linuxthreads/sysdeps/pthread/bits/libc-lock.h327
-rw-r--r--libpthread/linuxthreads/sysdeps/pthread/bits/libc-tsd.h35
-rw-r--r--libpthread/linuxthreads/sysdeps/pthread/tls.h81
-rw-r--r--libpthread/linuxthreads/sysdeps/sh/pt-machine.h33
-rw-r--r--libpthread/linuxthreads/sysdeps/sh/stackinfo.h28
-rw-r--r--libpthread/linuxthreads/sysdeps/sh/tls.h115
-rw-r--r--libpthread/linuxthreads/sysdeps/sparc/stackinfo.h28
-rw-r--r--libpthread/linuxthreads_db/Banner1
-rw-r--r--libpthread/linuxthreads_db/ChangeLog190
-rw-r--r--libpthread/linuxthreads_db/Makefile27
-rw-r--r--libpthread/linuxthreads_db/Versions6
-rw-r--r--libpthread/linuxthreads_db/proc_service.h16
-rw-r--r--libpthread/linuxthreads_db/td_init.c4
-rw-r--r--libpthread/linuxthreads_db/td_log.c6
-rw-r--r--libpthread/linuxthreads_db/td_symbol_list.c40
-rw-r--r--libpthread/linuxthreads_db/td_ta_clear_event.c4
-rw-r--r--libpthread/linuxthreads_db/td_ta_delete.c4
-rw-r--r--libpthread/linuxthreads_db/td_ta_enable_stats.c4
-rw-r--r--libpthread/linuxthreads_db/td_ta_event_addr.c2
-rw-r--r--libpthread/linuxthreads_db/td_ta_event_getmsg.c5
-rw-r--r--libpthread/linuxthreads_db/td_ta_get_nthreads.c2
-rw-r--r--libpthread/linuxthreads_db/td_ta_get_ph.c4
-rw-r--r--libpthread/linuxthreads_db/td_ta_get_stats.c4
-rw-r--r--libpthread/linuxthreads_db/td_ta_map_id2thr.c19
-rw-r--r--libpthread/linuxthreads_db/td_ta_map_lwp2thr.c16
-rw-r--r--libpthread/linuxthreads_db/td_ta_new.c18
-rw-r--r--libpthread/linuxthreads_db/td_ta_reset_stats.c4
-rw-r--r--libpthread/linuxthreads_db/td_ta_set_event.c4
-rw-r--r--libpthread/linuxthreads_db/td_ta_setconcurrency.c4
-rw-r--r--libpthread/linuxthreads_db/td_ta_thr_iter.c36
-rw-r--r--libpthread/linuxthreads_db/td_ta_tsd_iter.c5
-rw-r--r--libpthread/linuxthreads_db/td_thr_clear_event.c9
-rw-r--r--libpthread/linuxthreads_db/td_thr_dbresume.c4
-rw-r--r--libpthread/linuxthreads_db/td_thr_dbsuspend.c4
-rw-r--r--libpthread/linuxthreads_db/td_thr_event_enable.c22
-rw-r--r--libpthread/linuxthreads_db/td_thr_event_getmsg.c9
-rw-r--r--libpthread/linuxthreads_db/td_thr_get_info.c21
-rw-r--r--libpthread/linuxthreads_db/td_thr_getfpregs.c8
-rw-r--r--libpthread/linuxthreads_db/td_thr_getgregs.c9
-rw-r--r--libpthread/linuxthreads_db/td_thr_getxregs.c4
-rw-r--r--libpthread/linuxthreads_db/td_thr_getxregsize.c4
-rw-r--r--libpthread/linuxthreads_db/td_thr_set_event.c9
-rw-r--r--libpthread/linuxthreads_db/td_thr_setfpregs.c9
-rw-r--r--libpthread/linuxthreads_db/td_thr_setgregs.c9
-rw-r--r--libpthread/linuxthreads_db/td_thr_setprio.c4
-rw-r--r--libpthread/linuxthreads_db/td_thr_setsigpending.c4
-rw-r--r--libpthread/linuxthreads_db/td_thr_setxregs.c4
-rw-r--r--libpthread/linuxthreads_db/td_thr_sigsetmask.c4
-rw-r--r--libpthread/linuxthreads_db/td_thr_tls_get_addr.c70
-rw-r--r--libpthread/linuxthreads_db/td_thr_tsd.c12
-rw-r--r--libpthread/linuxthreads_db/td_thr_validate.c21
-rw-r--r--libpthread/linuxthreads_db/thread_db.h37
-rw-r--r--libpthread/linuxthreads_db/thread_dbP.h5
85 files changed, 3613 insertions, 893 deletions
diff --git a/libpthread/Makefile b/libpthread/Makefile
index 567ceb983..89d039246 100644
--- a/libpthread/Makefile
+++ b/libpthread/Makefile
@@ -25,7 +25,7 @@ LIBPTHREAD_SHARED=libpthread.so
LIBPTHREAD_SHARED_FULLNAME=libpthread-$(MAJOR_VERSION).$(MINOR_VERSION).$(SUBLEVEL).so
LIBTHREAD_DB=libthread_db.a
-LIBTHREAD_DB_SHARED=libthread_db.so
+LIBTHREAD_DB_SHARED=libthread_db.so.1
LIBTHREAD_DB_SHARED_FULLNAME=libthread_db-$(MAJOR_VERSION).$(MINOR_VERSION).$(SUBLEVEL).so
DIRS=
@@ -101,8 +101,6 @@ shared: all
install -m 644 $(LIBTHREAD_DB_SHARED_FULLNAME) $(TOPDIR)lib; \
(cd $(TOPDIR)lib && ln -sf $(LIBTHREAD_DB_SHARED_FULLNAME) \
$(LIBTHREAD_DB_SHARED)); \
- (cd $(TOPDIR)lib && ln -sf $(LIBTHREAD_DB_SHARED_FULLNAME) \
- $(LIBTHREAD_DB_SHARED).$(MAJOR_VERSION)); \
fi;
tags:
diff --git a/libpthread/linuxthreads/condvar.c b/libpthread/linuxthreads/condvar.c
index 8bc114e3c..f9c46a331 100644
--- a/libpthread/linuxthreads/condvar.c
+++ b/libpthread/linuxthreads/condvar.c
@@ -25,22 +25,6 @@
#include "queue.h"
#include "restart.h"
-static int pthread_cond_timedwait_relative_old(pthread_cond_t *,
- pthread_mutex_t *, const struct timespec *);
-
-static int pthread_cond_timedwait_relative_new(pthread_cond_t *,
- pthread_mutex_t *, const struct timespec *);
-
-static int (*pthread_cond_tw_rel)(pthread_cond_t *, pthread_mutex_t *,
- const struct timespec *) = pthread_cond_timedwait_relative_old;
-
-/* initialize this module */
-void __pthread_init_condvar(int rt_sig_available)
-{
- if (rt_sig_available)
- pthread_cond_tw_rel = pthread_cond_timedwait_relative_new;
-}
-
int pthread_cond_init(pthread_cond_t *cond,
const pthread_condattr_t *cond_attr)
{
@@ -76,12 +60,20 @@ int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
volatile pthread_descr self = thread_self();
pthread_extricate_if extr;
int already_canceled = 0;
+ int spurious_wakeup_count;
+
+ /* Check whether the mutex is locked and owned by this thread. */
+ if (mutex->__m_kind != PTHREAD_MUTEX_TIMED_NP
+ && mutex->__m_kind != PTHREAD_MUTEX_ADAPTIVE_NP
+ && mutex->__m_owner != self)
+ return EINVAL;
/* Set up extrication interface */
extr.pu_object = cond;
extr.pu_extricate_func = cond_extricate_func;
/* Register extrication interface */
+ THREAD_SETMEM(self, p_condvar_avail, 0);
__pthread_set_own_extricate_if(self, &extr);
/* Atomically enqueue thread for waiting, but only if it is not
@@ -106,7 +98,21 @@ int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
pthread_mutex_unlock(mutex);
- suspend(self);
+ spurious_wakeup_count = 0;
+ while (1)
+ {
+ suspend(self);
+ if (THREAD_GETMEM(self, p_condvar_avail) == 0
+ && (THREAD_GETMEM(self, p_woken_by_cancel) == 0
+ || THREAD_GETMEM(self, p_cancelstate) != PTHREAD_CANCEL_ENABLE))
+ {
+ /* Count resumes that don't belong to us. */
+ spurious_wakeup_count++;
+ continue;
+ }
+ break;
+ }
+
__pthread_set_own_extricate_if(self, 0);
/* Check for cancellation again, to provide correct cancellation
@@ -119,31 +125,36 @@ int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
pthread_exit(PTHREAD_CANCELED);
}
+ /* Put back any resumes we caught that don't belong to us. */
+ while (spurious_wakeup_count--)
+ restart(self);
+
pthread_mutex_lock(mutex);
return 0;
}
-/* The following function is used on kernels that don't have rt signals.
- SIGUSR1 is used as the restart signal. The different code is needed
- because that ordinary signal does not queue. */
-
static int
-pthread_cond_timedwait_relative_old(pthread_cond_t *cond,
+pthread_cond_timedwait_relative(pthread_cond_t *cond,
pthread_mutex_t *mutex,
const struct timespec * abstime)
{
volatile pthread_descr self = thread_self();
- sigset_t unblock, initial_mask;
int already_canceled = 0;
- int was_signalled = 0;
- sigjmp_buf jmpbuf;
pthread_extricate_if extr;
+ int spurious_wakeup_count;
+
+ /* Check whether the mutex is locked and owned by this thread. */
+ if (mutex->__m_kind != PTHREAD_MUTEX_TIMED_NP
+ && mutex->__m_kind != PTHREAD_MUTEX_ADAPTIVE_NP
+ && mutex->__m_owner != self)
+ return EINVAL;
/* Set up extrication interface */
extr.pu_object = cond;
extr.pu_extricate_func = cond_extricate_func;
/* Register extrication interface */
+ THREAD_SETMEM(self, p_condvar_avail, 0);
__pthread_set_own_extricate_if(self, &extr);
/* Enqueue to wait on the condition and check for cancellation. */
@@ -162,202 +173,40 @@ pthread_cond_timedwait_relative_old(pthread_cond_t *cond,
pthread_mutex_unlock(mutex);
- if (atomic_decrement(&self->p_resume_count) == 0) {
- /* Set up a longjmp handler for the restart signal, unblock
- the signal and sleep. */
-
- if (sigsetjmp(jmpbuf, 1) == 0) {
- THREAD_SETMEM(self, p_signal_jmp, &jmpbuf);
- THREAD_SETMEM(self, p_signal, 0);
- /* Unblock the restart signal */
- sigemptyset(&unblock);
- sigaddset(&unblock, __pthread_sig_restart);
- sigprocmask(SIG_UNBLOCK, &unblock, &initial_mask);
-
- while (1) {
- struct timeval now;
- struct timespec reltime;
-
- /* Compute a time offset relative to now. */
- gettimeofday (&now, NULL);
- reltime.tv_nsec = abstime->tv_nsec - now.tv_usec * 1000;
- reltime.tv_sec = abstime->tv_sec - now.tv_sec;
- if (reltime.tv_nsec < 0) {
- reltime.tv_nsec += 1000000000;
- reltime.tv_sec -= 1;
- }
-
- /* Sleep for the required duration. If woken by a signal, resume waiting
- as required by Single Unix Specification. */
- if (reltime.tv_sec < 0 || __libc_nanosleep(&reltime, NULL) == 0)
- break;
- }
-
- /* Block the restart signal again */
- sigprocmask(SIG_SETMASK, &initial_mask, NULL);
- was_signalled = 0;
- } else {
- was_signalled = 1;
- }
- THREAD_SETMEM(self, p_signal_jmp, NULL);
- }
-
- /* Now was_signalled is true if we exited the above code
- due to the delivery of a restart signal. In that case,
- we know we have been dequeued and resumed and that the
- resume count is balanced. Otherwise, there are some
- cases to consider. First, try to bump up the resume count
- back to zero. If it goes to 1, it means restart() was
- invoked on this thread. The signal must be consumed
- and the count bumped down and everything is cool.
- Otherwise, no restart was delivered yet, so we remove
- the thread from the queue. If this succeeds, it's a clear
- case of timeout. If we fail to remove from the queue, then we
- must wait for a restart. */
-
- if (!was_signalled) {
- if (atomic_increment(&self->p_resume_count) != -1) {
- __pthread_wait_for_restart_signal(self);
- atomic_decrement(&self->p_resume_count); /* should be zero now! */
- } else {
- int was_on_queue;
- __pthread_lock(&cond->__c_lock, self);
- was_on_queue = remove_from_queue(&cond->__c_waiting, self);
- __pthread_unlock(&cond->__c_lock);
-
- if (was_on_queue) {
- __pthread_set_own_extricate_if(self, 0);
- pthread_mutex_lock(mutex);
- return ETIMEDOUT;
- }
-
- suspend(self);
- }
- }
-
- __pthread_set_own_extricate_if(self, 0);
-
- /* The remaining logic is the same as in other cancellable waits,
- such as pthread_join sem_wait or pthread_cond wait. */
-
- if (THREAD_GETMEM(self, p_woken_by_cancel)
- && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) {
- THREAD_SETMEM(self, p_woken_by_cancel, 0);
- pthread_mutex_lock(mutex);
- pthread_exit(PTHREAD_CANCELED);
- }
-
- pthread_mutex_lock(mutex);
- return 0;
-}
-
-/* The following function is used on new (late 2.1 and 2.2 and higher) kernels
- that have rt signals which queue. */
-
-static int
-pthread_cond_timedwait_relative_new(pthread_cond_t *cond,
- pthread_mutex_t *mutex,
- const struct timespec * abstime)
-{
- volatile pthread_descr self = thread_self();
- sigset_t unblock, initial_mask;
- int already_canceled = 0;
- int was_signalled = 0;
- sigjmp_buf jmpbuf;
- pthread_extricate_if extr;
-
- /* Set up extrication interface */
- extr.pu_object = cond;
- extr.pu_extricate_func = cond_extricate_func;
-
- /* Register extrication interface */
- __pthread_set_own_extricate_if(self, &extr);
-
- /* Enqueue to wait on the condition and check for cancellation. */
- __pthread_lock(&cond->__c_lock, self);
- if (!(THREAD_GETMEM(self, p_canceled)
- && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE))
- enqueue(&cond->__c_waiting, self);
- else
- already_canceled = 1;
- __pthread_unlock(&cond->__c_lock);
+ spurious_wakeup_count = 0;
+ while (1)
+ {
+ if (!timedsuspend(self, abstime)) {
+ int was_on_queue;
- if (already_canceled) {
- __pthread_set_own_extricate_if(self, 0);
- pthread_exit(PTHREAD_CANCELED);
- }
+ /* __pthread_lock will queue back any spurious restarts that
+ may happen to it. */
- pthread_mutex_unlock(mutex);
+ __pthread_lock(&cond->__c_lock, self);
+ was_on_queue = remove_from_queue(&cond->__c_waiting, self);
+ __pthread_unlock(&cond->__c_lock);
- /* Set up a longjmp handler for the restart signal, unblock
- the signal and sleep. */
-
- if (sigsetjmp(jmpbuf, 1) == 0) {
- THREAD_SETMEM(self, p_signal_jmp, &jmpbuf);
- THREAD_SETMEM(self, p_signal, 0);
- /* Unblock the restart signal */
- sigemptyset(&unblock);
- sigaddset(&unblock, __pthread_sig_restart);
- sigprocmask(SIG_UNBLOCK, &unblock, &initial_mask);
-
- while (1) {
- struct timeval now;
- struct timespec reltime;
-
- /* Compute a time offset relative to now. */
- gettimeofday (&now, NULL);
- reltime.tv_nsec = abstime->tv_nsec - now.tv_usec * 1000;
- reltime.tv_sec = abstime->tv_sec - now.tv_sec;
- if (reltime.tv_nsec < 0) {
- reltime.tv_nsec += 1000000000;
- reltime.tv_sec -= 1;
+ if (was_on_queue) {
+ __pthread_set_own_extricate_if(self, 0);
+ pthread_mutex_lock(mutex);
+ return ETIMEDOUT;
}
- /* Sleep for the required duration. If woken by a signal,
- resume waiting as required by Single Unix Specification. */
- if (reltime.tv_sec < 0 || __libc_nanosleep(&reltime, NULL) == 0)
- break;
+ /* Eat the outstanding restart() from the signaller */
+ suspend(self);
}
- /* Block the restart signal again */
- sigprocmask(SIG_SETMASK, &initial_mask, NULL);
- was_signalled = 0;
- } else {
- was_signalled = 1;
- }
- THREAD_SETMEM(self, p_signal_jmp, NULL);
-
- /* Now was_signalled is true if we exited the above code
- due to the delivery of a restart signal. In that case,
- everything is cool. We have been removed from the queue
- by the other thread, and consumed its signal.
-
- Otherwise we this thread woke up spontaneously, or due to a signal other
- than restart. The next thing to do is to try to remove the thread
- from the queue. This may fail due to a race against another thread