diff options
author | Eric Andersen <andersen@codepoet.org> | 2003-02-27 18:13:05 +0000 |
---|---|---|
committer | Eric Andersen <andersen@codepoet.org> | 2003-02-27 18:13:05 +0000 |
commit | 187dd78d7bd1c03fcf16e54a30314512d38e1a4a (patch) | |
tree | 9780638e5286b40da74a128c9f540a9ea720862f | |
parent | d4d6e2c50565da18253cd0d6f3332484142b6587 (diff) |
Major update for pthreads, based in large part on improvements
from glibc 2.3. This should make threads much more efficient.
-Erik
88 files changed, 3644 insertions, 917 deletions
diff --git a/include/semaphore.h b/include/semaphore.h index 84742233b..9c283c864 100644 --- a/include/semaphore.h +++ b/include/semaphore.h @@ -17,6 +17,10 @@ #include <features.h> #include <sys/types.h> +#ifdef __USE_XOPEN2K +# define __need_timespec +# include <time.h> +#endif #ifndef _PTHREAD_DESCR_DEFINED /* Thread descriptors. Needed for `sem_t' definition. */ @@ -27,11 +31,7 @@ typedef struct _pthread_descr_struct *_pthread_descr; /* System specific semaphore definition. */ typedef struct { - struct - { - long int status; - int spinlock; - } __sem_lock; + struct _pthread_fastlock __sem_lock; int __sem_value; _pthread_descr __sem_waiting; } sem_t; @@ -49,31 +49,39 @@ __BEGIN_DECLS /* Initialize semaphore object SEM to VALUE. If PSHARED then share it with other processes. */ -extern int sem_init __P ((sem_t *__sem, int __pshared, unsigned int __value)); +extern int sem_init (sem_t *__sem, int __pshared, unsigned int __value) __THROW; /* Free resources associated with semaphore object SEM. */ -extern int sem_destroy __P ((sem_t *__sem)); +extern int sem_destroy (sem_t *__sem) __THROW; /* Open a named semaphore NAME with open flaot OFLAG. */ -extern sem_t *sem_open __P ((__const char *__name, int __oflag, ...)); +extern sem_t *sem_open (__const char *__name, int __oflag, ...) __THROW; /* Close descriptor for named semaphore SEM. */ -extern int sem_close __P ((sem_t *__sem)); +extern int sem_close (sem_t *__sem) __THROW; /* Remove named semaphore NAME. */ -extern int sem_unlink __P ((__const char *__name)); +extern int sem_unlink (__const char *__name) __THROW; /* Wait for SEM being posted. */ -extern int sem_wait __P ((sem_t *__sem)); +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 __P ((sem_t *__sem)); +extern int sem_trywait (sem_t *__sem) __THROW; /* Post SEM. */ -extern int sem_post __P ((sem_t *__sem)); +extern int sem_post (sem_t *__sem) __THROW; /* Get current value of SEM and store it in *SVAL. */ -extern int sem_getvalue __P ((sem_t *__sem, int *__sval)); +extern int sem_getvalue (sem_t *__restrict __sem, int *__restrict __sval) + __THROW; __END_DECLS diff --git a/libc/sysdeps/linux/common/bits/initspin.h b/libc/sysdeps/linux/common/bits/initspin.h index 257fed3c5..a19ec077e 100644 --- a/libc/sysdeps/linux/common/bits/initspin.h +++ b/libc/sysdeps/linux/common/bits/initspin.h @@ -3,16 +3,16 @@ This file is part of the 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 + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that 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. + Lesser General Public License for more details. - You should have received a copy of the GNU Library General Public + 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. */ @@ -20,8 +20,9 @@ /* Initial value of a spinlock. Most platforms should use zero, unless they only implement a "test and clear" operation instead of the usual "test and set". */ -#define __ATOMIC_LOCK_INIT 0 +#define __LT_SPINLOCK_INIT 0 /* Macros for lock initializers, using the above definition. */ -#define __LOCK_INITIALIZER { 0, 0 } -#define __ATOMIC_INITIALIZER { 0, 0 } +#define __LOCK_INITIALIZER { 0, __LT_SPINLOCK_INIT } +#define __ALT_LOCK_INITIALIZER { 0, __LT_SPINLOCK_INIT } +#define __ATOMIC_INITIALIZER { 0, __LT_SPINLOCK_INIT } diff --git a/libc/sysdeps/linux/common/bits/pthreadtypes.h b/libc/sysdeps/linux/common/bits/pthreadtypes.h index 441734c9d..3ee5c4813 100644 --- a/libc/sysdeps/linux/common/bits/pthreadtypes.h +++ b/libc/sysdeps/linux/common/bits/pthreadtypes.h @@ -22,13 +22,11 @@ #define __need_schedparam #include <bits/sched.h> -typedef int __atomic_lock_t; - /* Fast locks (not abstract because mutexes and conditions aren't abstract). */ struct _pthread_fastlock { long int __status; /* "Free" or "taken" or head of waiting list */ - __atomic_lock_t __spinlock; /* Used by compare_and_swap emulation. Also, + int __spinlock; /* Used by compare_and_swap emulation. Also, adaptive SMP lock stores spin count here. */ }; 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 |